Merge branch '6.0.x'
This commit is contained in:
		
						commit
						209e02cf29
					
				|  | @ -182,7 +182,7 @@ public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareB | |||
| 	private static String[] safeMerge(@Nullable String[] existingNames, Collection<LifecycleMethod> detectedMethods) { | ||||
| 		Stream<String> detectedNames = detectedMethods.stream().map(LifecycleMethod::getIdentifier); | ||||
| 		Stream<String> mergedNames = (existingNames != null ? | ||||
| 				Stream.concat(Stream.of(existingNames), detectedNames) : detectedNames); | ||||
| 				Stream.concat(detectedNames, Stream.of(existingNames)) : detectedNames); | ||||
| 		return mergedNames.distinct().toArray(String[]::new); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -72,6 +72,7 @@ import org.springframework.util.StringUtils; | |||
|  * | ||||
|  * @author Phillip Webb | ||||
|  * @author Stephane Nicoll | ||||
|  * @author Sam Brannen | ||||
|  * @since 6.0 | ||||
|  */ | ||||
| class BeanDefinitionPropertiesCodeGenerator { | ||||
|  | @ -138,7 +139,25 @@ class BeanDefinitionPropertiesCodeGenerator { | |||
| 	} | ||||
| 
 | ||||
| 	private void addInitDestroyHint(Class<?> beanUserClass, String methodName) { | ||||
| 		Method method = ReflectionUtils.findMethod(beanUserClass, methodName); | ||||
| 		Class<?> methodDeclaringClass = beanUserClass; | ||||
| 
 | ||||
| 		// Parse fully-qualified method name if necessary. | ||||
| 		int indexOfDot = methodName.lastIndexOf('.'); | ||||
| 		if (indexOfDot > 0) { | ||||
| 			String className = methodName.substring(0, indexOfDot); | ||||
| 			methodName = methodName.substring(indexOfDot + 1); | ||||
| 			if (!beanUserClass.getName().equals(className)) { | ||||
| 				try { | ||||
| 					methodDeclaringClass = ClassUtils.forName(className, beanUserClass.getClassLoader()); | ||||
| 				} | ||||
| 				catch (Throwable ex) { | ||||
| 					throw new IllegalStateException("Failed to load Class [" + className + | ||||
| 							"] from ClassLoader [" + beanUserClass.getClassLoader() + "]", ex); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		Method method = ReflectionUtils.findMethod(methodDeclaringClass, methodName); | ||||
| 		if (method != null) { | ||||
| 			this.hints.reflection().registerMethod(method, ExecutableMode.INVOKE); | ||||
| 		} | ||||
|  |  | |||
|  | @ -1842,18 +1842,22 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac | |||
| 	protected void invokeCustomInitMethod(String beanName, Object bean, RootBeanDefinition mbd, String initMethodName) | ||||
| 			throws Throwable { | ||||
| 
 | ||||
| 		Class<?> beanClass = bean.getClass(); | ||||
| 		MethodDescriptor descriptor = MethodDescriptor.create(beanName, beanClass, initMethodName); | ||||
| 		String methodName = descriptor.methodName(); | ||||
| 
 | ||||
| 		Method initMethod = (mbd.isNonPublicAccessAllowed() ? | ||||
| 				BeanUtils.findMethod(bean.getClass(), initMethodName) : | ||||
| 				ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName)); | ||||
| 				BeanUtils.findMethod(descriptor.declaringClass(), methodName) : | ||||
| 				ClassUtils.getMethodIfAvailable(beanClass, methodName)); | ||||
| 
 | ||||
| 		if (initMethod == null) { | ||||
| 			if (mbd.isEnforceInitMethod()) { | ||||
| 				throw new BeanDefinitionValidationException("Could not find an init method named '" + | ||||
| 						initMethodName + "' on bean with name '" + beanName + "'"); | ||||
| 						methodName + "' on bean with name '" + beanName + "'"); | ||||
| 			} | ||||
| 			else { | ||||
| 				if (logger.isTraceEnabled()) { | ||||
| 					logger.trace("No default init method named '" + initMethodName + | ||||
| 					logger.trace("No default init method named '" + methodName + | ||||
| 							"' found on bean with name '" + beanName + "'"); | ||||
| 				} | ||||
| 				// Ignore non-existent default lifecycle methods. | ||||
|  | @ -1862,9 +1866,9 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac | |||
| 		} | ||||
| 
 | ||||
| 		if (logger.isTraceEnabled()) { | ||||
| 			logger.trace("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'"); | ||||
| 			logger.trace("Invoking init method '" + methodName + "' on bean with name '" + beanName + "'"); | ||||
| 		} | ||||
| 		Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod, bean.getClass()); | ||||
| 		Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod, beanClass); | ||||
| 
 | ||||
| 		try { | ||||
| 			ReflectionUtils.makeAccessible(methodToInvoke); | ||||
|  |  | |||
|  | @ -266,12 +266,15 @@ class DisposableBeanAdapter implements DisposableBean, Runnable, Serializable { | |||
| 	private Method determineDestroyMethod(String destroyMethodName) { | ||||
| 		try { | ||||
| 			Class<?> beanClass = this.bean.getClass(); | ||||
| 			Method destroyMethod = findDestroyMethod(beanClass, destroyMethodName); | ||||
| 			MethodDescriptor descriptor = MethodDescriptor.create(this.beanName, beanClass, destroyMethodName); | ||||
| 			String methodName = descriptor.methodName(); | ||||
| 
 | ||||
| 			Method destroyMethod = findDestroyMethod(descriptor.declaringClass(), methodName); | ||||
| 			if (destroyMethod != null) { | ||||
| 				return destroyMethod; | ||||
| 			} | ||||
| 			for (Class<?> beanInterface : beanClass.getInterfaces()) { | ||||
| 				destroyMethod = findDestroyMethod(beanInterface, destroyMethodName); | ||||
| 				destroyMethod = findDestroyMethod(beanInterface, methodName); | ||||
| 				if (destroyMethod != null) { | ||||
| 					return destroyMethod; | ||||
| 				} | ||||
|  |  | |||
|  | @ -0,0 +1,73 @@ | |||
| /* | ||||
|  * Copyright 2002-2023 the original author or authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      https://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package org.springframework.beans.factory.support; | ||||
| 
 | ||||
| import org.springframework.util.ClassUtils; | ||||
| 
 | ||||
| /** | ||||
|  * Descriptor for a {@link java.lang.reflect.Method Method} which holds a | ||||
|  * reference to the method's {@linkplain #declaringClass declaring class}, | ||||
|  * {@linkplain #methodName name}, and {@linkplain #parameterTypes parameter types}. | ||||
|  * | ||||
|  * @param declaringClass the method's declaring class | ||||
|  * @param methodName the name of the method | ||||
|  * @param parameterTypes the types of parameters accepted by the method | ||||
|  * @author Sam Brannen | ||||
|  * @since 6.0.11 | ||||
|  */ | ||||
| record MethodDescriptor(Class<?> declaringClass, String methodName, Class<?>... parameterTypes) { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Create a {@link MethodDescriptor} for the supplied bean class and method name. | ||||
| 	 * <p>The supplied {@code methodName} may be a {@linkplain Method#getName() | ||||
| 	 * simple method name} or a | ||||
| 	 * {@linkplain org.springframework.util.ClassUtils#getQualifiedMethodName(Method) | ||||
| 	 * qualified method name}. | ||||
| 	 * <p>If the method name is fully qualified, this utility will parse the | ||||
| 	 * method name and its declaring class from the qualified method name and then | ||||
| 	 * attempt to load the method's declaring class using the {@link ClassLoader} | ||||
| 	 * of the supplied {@code beanClass}. Otherwise, the returned descriptor will | ||||
| 	 * reference the supplied {@code beanClass} and {@code methodName}. | ||||
| 	 * @param beanName the bean name in the factory (for debugging purposes) | ||||
| 	 * @param beanClass the bean class | ||||
| 	 * @param methodName the name of the method | ||||
| 	 * @return a new {@code MethodDescriptor}; never {@code null} | ||||
| 	 */ | ||||
| 	static MethodDescriptor create(String beanName, Class<?> beanClass, String methodName) { | ||||
| 		try { | ||||
| 			Class<?> declaringClass = beanClass; | ||||
| 			String methodNameToUse = methodName; | ||||
| 
 | ||||
| 			// Parse fully-qualified method name if necessary. | ||||
| 			int indexOfDot = methodName.lastIndexOf('.'); | ||||
| 			if (indexOfDot > 0) { | ||||
| 				String className = methodName.substring(0, indexOfDot); | ||||
| 				methodNameToUse = methodName.substring(indexOfDot + 1); | ||||
| 				if (!beanClass.getName().equals(className)) { | ||||
| 					declaringClass = ClassUtils.forName(className, beanClass.getClassLoader()); | ||||
| 				} | ||||
| 			} | ||||
| 			return new MethodDescriptor(declaringClass, methodNameToUse); | ||||
| 		} | ||||
| 		catch (Exception | LinkageError ex) { | ||||
| 			throw new BeanDefinitionValidationException( | ||||
| 					"Could not create MethodDescriptor for method '%s' on bean with name '%s': %s" | ||||
| 						.formatted(methodName, beanName, ex.getMessage())); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -70,8 +70,8 @@ class InitDestroyAnnotationBeanPostProcessorTests { | |||
| 		beanDefinition.setDestroyMethodNames("customDestroyMethod"); | ||||
| 		processAheadOfTime(beanDefinition); | ||||
| 		RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition(); | ||||
| 		assertThat(mergedBeanDefinition.getInitMethodNames()).containsExactly("customInitMethod", "initMethod"); | ||||
| 		assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly("customDestroyMethod", "destroyMethod"); | ||||
| 		assertThat(mergedBeanDefinition.getInitMethodNames()).containsExactly("initMethod", "customInitMethod"); | ||||
| 		assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly("destroyMethod", "customDestroyMethod"); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
|  | @ -129,16 +129,16 @@ class InitDestroyAnnotationBeanPostProcessorTests { | |||
| 		RootBeanDefinition mergedBeanDefinition = getMergedBeanDefinition(); | ||||
| 		assertSoftly(softly -> { | ||||
| 			softly.assertThat(mergedBeanDefinition.getInitMethodNames()).containsExactly( | ||||
| 					"afterPropertiesSet", | ||||
| 					"customInit", | ||||
| 					CustomAnnotatedPrivateInitDestroyBean.class.getName() + ".privateInit", // fully-qualified private method | ||||
| 					CustomAnnotatedPrivateSameNameInitDestroyBean.class.getName() + ".privateInit" // fully-qualified private method | ||||
| 					CustomAnnotatedPrivateSameNameInitDestroyBean.class.getName() + ".privateInit", // fully-qualified private method | ||||
| 					"afterPropertiesSet", | ||||
| 					"customInit" | ||||
| 				); | ||||
| 			softly.assertThat(mergedBeanDefinition.getDestroyMethodNames()).containsExactly( | ||||
| 					"destroy", | ||||
| 					"customDestroy", | ||||
| 					CustomAnnotatedPrivateSameNameInitDestroyBean.class.getName() + ".privateDestroy", // fully-qualified private method | ||||
| 					CustomAnnotatedPrivateInitDestroyBean.class.getName() + ".privateDestroy" // fully-qualified private method | ||||
| 					CustomAnnotatedPrivateInitDestroyBean.class.getName() + ".privateDestroy", // fully-qualified private method | ||||
| 					"destroy", | ||||
| 					"customDestroy" | ||||
| 				); | ||||
| 		}); | ||||
| 	} | ||||
|  |  | |||
|  | @ -376,6 +376,9 @@ class BeanDefinitionPropertiesCodeGeneratorTests { | |||
| 	@Nested | ||||
| 	class InitDestroyMethodTests { | ||||
| 
 | ||||
| 		private final String privateInitMethod = InitDestroyBean.class.getName() + ".privateInit"; | ||||
| 		private final String privateDestroyMethod = InitDestroyBean.class.getName() + ".privateDestroy"; | ||||
| 
 | ||||
| 		@BeforeEach | ||||
| 		void setTargetType() { | ||||
| 			beanDefinition.setTargetType(InitDestroyBean.class); | ||||
|  | @ -393,11 +396,18 @@ class BeanDefinitionPropertiesCodeGeneratorTests { | |||
| 			assertHasMethodInvokeHints(InitDestroyBean.class, "init"); | ||||
| 		} | ||||
| 
 | ||||
| 		@Test | ||||
| 		void privateInitMethod() { | ||||
| 			beanDefinition.setInitMethodName(privateInitMethod); | ||||
| 			compile((beanDef, compiled) -> assertThat(beanDef.getInitMethodNames()).containsExactly(privateInitMethod)); | ||||
| 			assertHasMethodInvokeHints(InitDestroyBean.class, "privateInit"); | ||||
| 		} | ||||
| 
 | ||||
| 		@Test | ||||
| 		void multipleInitMethods() { | ||||
| 			beanDefinition.setInitMethodNames("init", "init2"); | ||||
| 			compile((beanDef, compiled) -> assertThat(beanDef.getInitMethodNames()).containsExactly("init", "init2")); | ||||
| 			assertHasMethodInvokeHints(InitDestroyBean.class, "init", "init2"); | ||||
| 			beanDefinition.setInitMethodNames("init", privateInitMethod); | ||||
| 			compile((beanDef, compiled) -> assertThat(beanDef.getInitMethodNames()).containsExactly("init", privateInitMethod)); | ||||
| 			assertHasMethodInvokeHints(InitDestroyBean.class, "init", "privateInit"); | ||||
| 		} | ||||
| 
 | ||||
| 		@Test | ||||
|  | @ -412,11 +422,18 @@ class BeanDefinitionPropertiesCodeGeneratorTests { | |||
| 			assertHasMethodInvokeHints(InitDestroyBean.class, "destroy"); | ||||
| 		} | ||||
| 
 | ||||
| 		@Test | ||||
| 		void privateDestroyMethod() { | ||||
| 			beanDefinition.setDestroyMethodName(privateDestroyMethod); | ||||
| 			compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly(privateDestroyMethod)); | ||||
| 			assertHasMethodInvokeHints(InitDestroyBean.class, "privateDestroy"); | ||||
| 		} | ||||
| 
 | ||||
| 		@Test | ||||
| 		void multipleDestroyMethods() { | ||||
| 			beanDefinition.setDestroyMethodNames("destroy", "destroy2"); | ||||
| 			compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("destroy", "destroy2")); | ||||
| 			assertHasMethodInvokeHints(InitDestroyBean.class, "destroy", "destroy2"); | ||||
| 			beanDefinition.setDestroyMethodNames("destroy", privateDestroyMethod); | ||||
| 			compile((beanDef, compiled) -> assertThat(beanDef.getDestroyMethodNames()).containsExactly("destroy", privateDestroyMethod)); | ||||
| 			assertHasMethodInvokeHints(InitDestroyBean.class, "destroy", "privateDestroy"); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
|  | @ -461,13 +478,15 @@ class BeanDefinitionPropertiesCodeGeneratorTests { | |||
| 		void init() { | ||||
| 		} | ||||
| 
 | ||||
| 		void init2() { | ||||
| 		@SuppressWarnings("unused") | ||||
| 		private void privateInit() { | ||||
| 		} | ||||
| 
 | ||||
| 		void destroy() { | ||||
| 		} | ||||
| 
 | ||||
| 		void destroy2() { | ||||
| 		@SuppressWarnings("unused") | ||||
| 		private void privateDestroy() { | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
|  |  | |||
|  | @ -18,18 +18,26 @@ package org.springframework.context.annotation; | |||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.function.BiConsumer; | ||||
| 
 | ||||
| import jakarta.annotation.PostConstruct; | ||||
| import jakarta.annotation.PreDestroy; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import org.springframework.aot.test.generate.TestGenerationContext; | ||||
| import org.springframework.beans.factory.DisposableBean; | ||||
| import org.springframework.beans.factory.InitializingBean; | ||||
| import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor; | ||||
| import org.springframework.beans.factory.support.DefaultListableBeanFactory; | ||||
| import org.springframework.beans.factory.support.RootBeanDefinition; | ||||
| import org.springframework.context.ApplicationContextInitializer; | ||||
| import org.springframework.context.annotation.lifecyclemethods.InitDestroyBean; | ||||
| import org.springframework.context.annotation.lifecyclemethods.PackagePrivateInitDestroyBean; | ||||
| import org.springframework.context.aot.ApplicationContextAotGenerator; | ||||
| import org.springframework.context.support.GenericApplicationContext; | ||||
| import org.springframework.core.test.tools.CompileWithForkedClassLoader; | ||||
| import org.springframework.core.test.tools.Compiled; | ||||
| import org.springframework.core.test.tools.TestCompiler; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| 
 | ||||
|  | @ -156,6 +164,79 @@ class InitDestroyMethodLifecycleTests { | |||
| 			); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * @see org.springframework.context.aot.ApplicationContextAotGeneratorTests#processAheadOfTimeWhenHasMultipleInitDestroyMethods | ||||
| 	 */ | ||||
| 	@Test | ||||
| 	@CompileWithForkedClassLoader | ||||
| 	void jakartaAnnotationsWithCustomSameMethodNamesWithAotProcessingAndAotRuntime() { | ||||
| 		Class<CustomAnnotatedPrivateSameNameInitDestroyBean> beanClass = CustomAnnotatedPrivateSameNameInitDestroyBean.class; | ||||
| 		GenericApplicationContext applicationContext = new GenericApplicationContext(); | ||||
| 
 | ||||
| 		DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory(); | ||||
| 		AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory); | ||||
| 
 | ||||
| 		RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); | ||||
| 		beanDefinition.setInitMethodName("customInit"); | ||||
| 		beanDefinition.setDestroyMethodName("customDestroy"); | ||||
| 		beanFactory.registerBeanDefinition("lifecycleTestBean", beanDefinition); | ||||
| 
 | ||||
| 		testCompiledResult(applicationContext, (initializer, compiled) -> { | ||||
| 			GenericApplicationContext aotApplicationContext = createApplicationContext(initializer); | ||||
| 			CustomAnnotatedPrivateSameNameInitDestroyBean bean = aotApplicationContext.getBean("lifecycleTestBean", beanClass); | ||||
| 
 | ||||
| 			assertThat(bean.initMethods).as("init-methods").containsExactly( | ||||
| 					"afterPropertiesSet", | ||||
| 					"@PostConstruct.privateCustomInit1", | ||||
| 					"@PostConstruct.sameNameCustomInit1", | ||||
| 					"customInit" | ||||
| 				); | ||||
| 
 | ||||
| 			aotApplicationContext.close(); | ||||
| 			assertThat(bean.destroyMethods).as("destroy-methods").containsExactly( | ||||
| 					"destroy", | ||||
| 					"@PreDestroy.sameNameCustomDestroy1", | ||||
| 					"@PreDestroy.privateCustomDestroy1", | ||||
| 					"customDestroy" | ||||
| 				); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	@CompileWithForkedClassLoader | ||||
| 	void jakartaAnnotationsWithPackagePrivateInitDestroyMethodsWithAotProcessingAndAotRuntime() { | ||||
| 		Class<SubPackagePrivateInitDestroyBean> beanClass = SubPackagePrivateInitDestroyBean.class; | ||||
| 		GenericApplicationContext applicationContext = new GenericApplicationContext(); | ||||
| 
 | ||||
| 		DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory(); | ||||
| 		AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory); | ||||
| 
 | ||||
| 		RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); | ||||
| 		beanDefinition.setInitMethodName("initMethod"); | ||||
| 		beanDefinition.setDestroyMethodName("destroyMethod"); | ||||
| 		beanFactory.registerBeanDefinition("lifecycleTestBean", beanDefinition); | ||||
| 
 | ||||
| 		testCompiledResult(applicationContext, (initializer, compiled) -> { | ||||
| 			GenericApplicationContext aotApplicationContext = createApplicationContext(initializer); | ||||
| 			SubPackagePrivateInitDestroyBean bean = aotApplicationContext.getBean("lifecycleTestBean", beanClass); | ||||
| 
 | ||||
| 			assertThat(bean.initMethods).as("init-methods").containsExactly( | ||||
| 					"InitializingBean.afterPropertiesSet", | ||||
| 					"PackagePrivateInitDestroyBean.postConstruct", | ||||
| 					"SubPackagePrivateInitDestroyBean.postConstruct", | ||||
| 					"initMethod" | ||||
| 				); | ||||
| 
 | ||||
| 			aotApplicationContext.close(); | ||||
| 			assertThat(bean.destroyMethods).as("destroy-methods").containsExactly( | ||||
| 					"DisposableBean.destroy", | ||||
| 					"SubPackagePrivateInitDestroyBean.preDestroy", | ||||
| 					"PackagePrivateInitDestroyBean.preDestroy", | ||||
| 					"destroyMethod" | ||||
| 				); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	void allLifecycleMechanismsAtOnce() { | ||||
| 		Class<?> beanClass = AllInOneBean.class; | ||||
|  | @ -188,6 +269,31 @@ class InitDestroyMethodLifecycleTests { | |||
| 		return beanFactory; | ||||
| 	} | ||||
| 
 | ||||
| 	private static GenericApplicationContext createApplicationContext( | ||||
| 			ApplicationContextInitializer<GenericApplicationContext> initializer) { | ||||
| 
 | ||||
| 		GenericApplicationContext context = new GenericApplicationContext(); | ||||
| 		initializer.initialize(context); | ||||
| 		context.refresh(); | ||||
| 		return context; | ||||
| 	} | ||||
| 
 | ||||
| 	@SuppressWarnings("unchecked") | ||||
| 	private static void testCompiledResult(GenericApplicationContext applicationContext, | ||||
| 			BiConsumer<ApplicationContextInitializer<GenericApplicationContext>, Compiled> result) { | ||||
| 
 | ||||
| 		TestCompiler.forSystem().with(processAheadOfTime(applicationContext)).compile(compiled -> | ||||
| 				result.accept(compiled.getInstance(ApplicationContextInitializer.class), compiled)); | ||||
| 	} | ||||
| 
 | ||||
| 	private static TestGenerationContext processAheadOfTime(GenericApplicationContext applicationContext) { | ||||
| 		ApplicationContextAotGenerator generator = new ApplicationContextAotGenerator(); | ||||
| 		TestGenerationContext generationContext = new TestGenerationContext(); | ||||
| 		generator.processAheadOfTime(applicationContext, generationContext); | ||||
| 		generationContext.writeGeneratedContent(); | ||||
| 		return generationContext; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	static class InitializingDisposableWithShadowedMethodsBean extends InitDestroyBean implements | ||||
| 			InitializingBean, DisposableBean { | ||||
|  |  | |||
|  | @ -261,9 +261,9 @@ class ApplicationContextAotGeneratorTests { | |||
| 			GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer); | ||||
| 			assertThat(freshApplicationContext.getBeanDefinitionNames()).containsOnly("initDestroyComponent"); | ||||
| 			InitDestroyComponent bean = freshApplicationContext.getBean(InitDestroyComponent.class); | ||||
| 			assertThat(bean.events).containsExactly("customInit", "init"); | ||||
| 			assertThat(bean.events).containsExactly("init", "customInit"); | ||||
| 			freshApplicationContext.close(); | ||||
| 			assertThat(bean.events).containsExactly("customInit", "init", "customDestroy", "destroy"); | ||||
| 			assertThat(bean.events).containsExactly("init", "customInit", "destroy", "customDestroy"); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue