diff --git a/spring-context/src/main/java/org/springframework/context/aot/AotApplicationContextInitializer.java b/spring-context/src/main/java/org/springframework/context/aot/AotApplicationContextInitializer.java
new file mode 100644
index 0000000000..798f18dcf1
--- /dev/null
+++ b/spring-context/src/main/java/org/springframework/context/aot/AotApplicationContextInitializer.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2002-2022 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.context.aot;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.BeanInstantiationException;
+import org.springframework.beans.BeanUtils;
+import org.springframework.context.ApplicationContextInitializer;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.log.LogMessage;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Specialized {@link ApplicationContextInitializer} used to initialize a
+ * {@link ConfigurableApplicationContext} using artifacts that were generated
+ * ahead-of-time.
+ *
+ * Instances of this initializer are usually created using
+ * {@link #forInitializerClasses(String...)}, passing in the names of code
+ * generated initializer classes.
+ *
+ * @author Stephane Nicoll
+ * @author Phillip Webb
+ * @since 6.0
+ * @param the application context type
+ */
+@FunctionalInterface
+public interface AotApplicationContextInitializer
+ extends ApplicationContextInitializer {
+
+ /**
+ * Factory method to create a new {@link AotApplicationContextInitializer}
+ * instance that delegates to other initializers loaded from the given set
+ * of class names.
+ * @param the application context type
+ * @param initializerClassNames the class names of the initializers to load
+ * @return a new {@link AotApplicationContextInitializer} instance
+ */
+ static ApplicationContextInitializer forInitializerClasses(
+ String... initializerClassNames) {
+
+ Assert.noNullElements(initializerClassNames, "'initializerClassNames' must not contain null elements");
+ return applicationContext -> initialize(applicationContext, initializerClassNames);
+ }
+
+ private static void initialize(
+ C applicationContext, String... initializerClassNames) {
+ Log logger = LogFactory.getLog(AotApplicationContextInitializer.class);
+ ClassLoader classLoader = applicationContext.getClassLoader();
+ logger.debug("Initializing ApplicationContext with AOT");
+ for (String initializerClassName : initializerClassNames) {
+ logger.trace(LogMessage.format("Applying %s", initializerClassName));
+ instantiateInitializer(classLoader, initializerClassName)
+ .initialize(applicationContext);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ static ApplicationContextInitializer instantiateInitializer(
+ ClassLoader classLoader, String initializerClassName) {
+ try {
+ Class> initializerClass = ClassUtils.resolveClassName(initializerClassName, classLoader);
+ Assert.isAssignable(ApplicationContextInitializer.class, initializerClass);
+ return (ApplicationContextInitializer) BeanUtils.instantiateClass(initializerClass);
+ }
+ catch (BeanInstantiationException ex) {
+ throw new IllegalArgumentException(
+ "Failed to instantiate ApplicationContextInitializer: " + initializerClassName, ex);
+ }
+ }
+
+ /**
+ * Return a new {@link List} containing only {@link AotApplicationContextInitializer} instances.
+ * @param the application context type
+ * @param initializers the source initializers
+ * @return a list of the {@link AotApplicationContextInitializer} instances
+ */
+ @SuppressWarnings("unchecked")
+ public static List> getAotInitializers(
+ Collection extends ApplicationContextInitializer extends C>> initializers) {
+
+ Assert.notNull(initializers, "'initializers' must not be null");
+ List> aotInitializers = new ArrayList<>();
+ for (ApplicationContextInitializer> candidate : initializers) {
+ if (candidate instanceof AotApplicationContextInitializer> aotInitializer) {
+ aotInitializers.add((AotApplicationContextInitializer) aotInitializer);
+ }
+ }
+ return aotInitializers;
+ }
+
+}
diff --git a/spring-context/src/main/java/org/springframework/context/aot/ApplicationContextAotInitializer.java b/spring-context/src/main/java/org/springframework/context/aot/ApplicationContextAotInitializer.java
index efc148ba76..3671aadb27 100644
--- a/spring-context/src/main/java/org/springframework/context/aot/ApplicationContextAotInitializer.java
+++ b/spring-context/src/main/java/org/springframework/context/aot/ApplicationContextAotInitializer.java
@@ -16,25 +16,19 @@
package org.springframework.context.aot;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.lang.Nullable;
-import org.springframework.util.ClassUtils;
/**
* Initializes a {@link ConfigurableApplicationContext} using AOT optimizations.
*
* @author Stephane Nicoll
* @since 6.0
+ * @deprecated in favor of {@link AotApplicationContextInitializer}
*/
+@Deprecated(since = "6.0", forRemoval = true)
public class ApplicationContextAotInitializer {
- private static final Log logger = LogFactory.getLog(ApplicationContextAotInitializer.class);
-
/**
* Initialize the specified application context using the specified
* {@link ApplicationContextInitializer} class names. Each class is
@@ -43,35 +37,7 @@ public class ApplicationContextAotInitializer {
* @param initializerClassNames the application context initializer class names
*/
public void initialize(ConfigurableApplicationContext context, String... initializerClassNames) {
- if (logger.isDebugEnabled()) {
- logger.debug("Initializing ApplicationContext with AOT");
- }
- for (String initializerClassName : initializerClassNames) {
- if (logger.isTraceEnabled()) {
- logger.trace("Applying " + initializerClassName);
- }
- loadInitializer(initializerClassName, context.getClassLoader()).initialize(context);
- }
- }
-
- @SuppressWarnings("unchecked")
- private ApplicationContextInitializer loadInitializer(
- String className, @Nullable ClassLoader classLoader) {
- Object initializer = instantiate(className, classLoader);
- if (!(initializer instanceof ApplicationContextInitializer)) {
- throw new IllegalArgumentException("Not an ApplicationContextInitializer: " + className);
- }
- return (ApplicationContextInitializer) initializer;
- }
-
- private static Object instantiate(String className, @Nullable ClassLoader classLoader) {
- try {
- Class> type = ClassUtils.forName(className, classLoader);
- return BeanUtils.instantiateClass(type);
- }
- catch (Exception ex) {
- throw new IllegalArgumentException("Failed to instantiate ApplicationContextInitializer: " + className, ex);
- }
+ AotApplicationContextInitializer.forInitializerClasses(initializerClassNames).initialize(context);
}
}
diff --git a/spring-context/src/test/java/org/springframework/context/aot/AotApplicationContextInitializerTests.java b/spring-context/src/test/java/org/springframework/context/aot/AotApplicationContextInitializerTests.java
new file mode 100644
index 0000000000..d4b455f401
--- /dev/null
+++ b/spring-context/src/test/java/org/springframework/context/aot/AotApplicationContextInitializerTests.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2002-2022 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.context.aot;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.context.ApplicationContextInitializer;
+import org.springframework.context.support.GenericApplicationContext;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+
+/**
+ * Tests for {@link AotApplicationContextInitializer}.
+ *
+ * @author Stephane Nicoll
+ */
+class AotApplicationContextInitializerTests {
+
+ @Test
+ void initializeInvokesApplicationContextInitializer() {
+ GenericApplicationContext context = new GenericApplicationContext();
+ AotApplicationContextInitializer.forInitializerClasses(
+ TestApplicationContextInitializer.class.getName())
+ .initialize(context);
+ assertThat(context.getBeanDefinitionNames()).containsExactly("test");
+ }
+
+ @Test
+ void initializeInvokesApplicationContextInitializersInOrder() {
+ GenericApplicationContext context = new GenericApplicationContext();
+ AotApplicationContextInitializer.forInitializerClasses(
+ AnotherApplicationContextInitializer.class.getName(),
+ TestApplicationContextInitializer.class.getName())
+ .initialize(context);
+ assertThat(context.getBeanDefinitionNames()).containsExactly("another", "test");
+ }
+
+ @Test
+ void initializeWhenClassIsNotApplicationContextInitializerThrowsException() {
+ GenericApplicationContext context = new GenericApplicationContext();
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> AotApplicationContextInitializer.forInitializerClasses("java.lang.String")
+ .initialize(context))
+ .withMessageContaining("not assignable")
+ .withMessageContaining("ApplicationContextInitializer")
+ .withMessageContaining("java.lang.String");
+ }
+
+ @Test
+ void initializeWhenInitializerHasNoDefaultConstructorThrowsException() {
+ GenericApplicationContext context = new GenericApplicationContext();
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> AotApplicationContextInitializer.forInitializerClasses(
+ ConfigurableApplicationContextInitializer.class.getName()).initialize(context))
+ .withMessageContaining("Failed to instantiate ApplicationContextInitializer: ")
+ .withMessageContaining(ConfigurableApplicationContextInitializer.class.getName());
+ }
+
+ @Test
+ void getAotInitializersReturnsOnlyAotInitializers() {
+ ApplicationContextInitializer l1 = context -> { };
+ ApplicationContextInitializer l2 = context -> { };
+ AotApplicationContextInitializer a1 = context -> { };
+ AotApplicationContextInitializer a2 = l2::initialize;
+ List> initializers = List.of(l1, l2, a1, a2);
+ List> aotInitializers = AotApplicationContextInitializer
+ .getAotInitializers(initializers);
+ assertThat(aotInitializers).containsExactly(a1, a2);
+ }
+
+
+ static class TestApplicationContextInitializer implements ApplicationContextInitializer {
+
+ @Override
+ public void initialize(GenericApplicationContext applicationContext) {
+ applicationContext.registerBeanDefinition("test", new RootBeanDefinition());
+ }
+
+ }
+
+ static class AnotherApplicationContextInitializer implements ApplicationContextInitializer {
+
+ @Override
+ public void initialize(GenericApplicationContext applicationContext) {
+ applicationContext.registerBeanDefinition("another", new RootBeanDefinition());
+ }
+
+ }
+
+ static class ConfigurableApplicationContextInitializer implements ApplicationContextInitializer {
+
+ public ConfigurableApplicationContextInitializer(ClassLoader classLoader) {
+ }
+
+ @Override
+ public void initialize(GenericApplicationContext applicationContext) {
+
+ }
+ }
+
+}
diff --git a/spring-context/src/test/java/org/springframework/context/aot/ApplicationContextAotInitializerTests.java b/spring-context/src/test/java/org/springframework/context/aot/ApplicationContextAotInitializerTests.java
index a3ba5634b6..af0e2de2f8 100644
--- a/spring-context/src/test/java/org/springframework/context/aot/ApplicationContextAotInitializerTests.java
+++ b/spring-context/src/test/java/org/springframework/context/aot/ApplicationContextAotInitializerTests.java
@@ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
*
* @author Stephane Nicoll
*/
+@Deprecated
class ApplicationContextAotInitializerTests {
private final ApplicationContextAotInitializer initializer = new ApplicationContextAotInitializer();
@@ -54,7 +55,8 @@ class ApplicationContextAotInitializerTests {
GenericApplicationContext context = new GenericApplicationContext();
assertThatIllegalArgumentException()
.isThrownBy(() -> initializer.initialize(context, "java.lang.String"))
- .withMessageContaining("Not an ApplicationContextInitializer: ")
+ .withMessageContaining("not assignable")
+ .withMessageContaining("ApplicationContextInitializer")
.withMessageContaining("java.lang.String");
}