Replace AotApplicationContextInitializer with Framework version

This commit is contained in:
Phillip Webb 2022-09-29 16:37:26 -07:00
parent 7eb8abbda8
commit 7a5b61fd19
4 changed files with 7 additions and 266 deletions

View File

@ -24,7 +24,6 @@ import java.util.List;
import java.util.function.Consumer;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.AotApplicationContextInitializer;
import org.springframework.boot.ApplicationContextFactory;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
@ -44,6 +43,7 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.aot.AotApplicationContextInitializer;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.SpringVersion;
@ -494,7 +494,7 @@ public class SpringBootContextLoader extends AbstractContextLoader implements Ao
ContextLoaderHook.this.configurer.accept(application);
if (ContextLoaderHook.this.mode == Mode.AOT_RUNTIME) {
application.addInitializers(
AotApplicationContextInitializer.of(ContextLoaderHook.this.initializer));
(AotApplicationContextInitializer<?>) ContextLoaderHook.this.initializer::initialize);
}
}

View File

@ -1,152 +0,0 @@
/*
* Copyright 2012-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.boot;
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.core.log.LogMessage;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* A {@link ApplicationContextInitializer} wrapper used to initialize a
* {@link ConfigurableApplicationContext} using artifacts that were generated
* ahead-of-time.
*
* @param <C> the application context type
* @author Phillip Webb
* @since 3.0.0
*/
public abstract sealed class AotApplicationContextInitializer<C extends ConfigurableApplicationContext>
implements ApplicationContextInitializer<C> {
private static final Log logger = LogFactory.getLog(AotApplicationContextInitializer.class);
@Override
public final void initialize(C applicationContext) {
logger.debug(LogMessage.format("Initializing ApplicationContext using AOT initializer '%s'", getName()));
aotInitialize(applicationContext);
}
abstract void aotInitialize(C applicationContext);
abstract String getName();
static <C extends ConfigurableApplicationContext> AotApplicationContextInitializer<C> forMainApplicationClass(
Class<?> mainApplicationClass) {
String initializerClassName = mainApplicationClass.getName() + "__ApplicationContextInitializer";
return new ReflectionDelegatingAotApplicationContextInitializer<>(initializerClassName);
}
/**
* Create a new {@link AotApplicationContextInitializer} by delegating to an existing
* initializer instance.
* @param <C> the application context type
* @param initializer the initializer to delegate to
* @return a new {@link AotApplicationContextInitializer} instance
*/
public static <C extends ConfigurableApplicationContext> AotApplicationContextInitializer<C> of(
ApplicationContextInitializer<C> initializer) {
Assert.notNull(initializer, "Initializer must not be null");
return new InstanceDelegatingAotApplicationContextInitializer<>(initializer.getClass().getName(), initializer);
}
/**
* Create a new {@link AotApplicationContextInitializer} by delegating to an existing
* initializer instance.
* @param <C> the application context type
* @param initializer the initializer to delegate to
* @param name the name of the initializer
* @return a new {@link AotApplicationContextInitializer} instance
*/
public static <C extends ConfigurableApplicationContext> AotApplicationContextInitializer<C> of(String name,
ApplicationContextInitializer<C> initializer) {
Assert.notNull(name, "Name must not be null");
Assert.notNull(initializer, "Initializer must not be null");
return new InstanceDelegatingAotApplicationContextInitializer<>(name, initializer);
}
/**
* {@link AotApplicationContextInitializer} that delegates to an initializer created
* via reflection.
*
* @param <C> the application context type
*/
static final class ReflectionDelegatingAotApplicationContextInitializer<C extends ConfigurableApplicationContext>
extends AotApplicationContextInitializer<C> {
private final String initializerClassName;
ReflectionDelegatingAotApplicationContextInitializer(String initializerClassName) {
this.initializerClassName = initializerClassName;
}
@Override
void aotInitialize(C applicationContext) {
ApplicationContextInitializer<C> initializer = createInitializer(applicationContext.getClassLoader());
initializer.initialize(applicationContext);
}
@SuppressWarnings("unchecked")
private ApplicationContextInitializer<C> createInitializer(ClassLoader classLoader) {
Class<?> initializerClass = ClassUtils.resolveClassName(this.initializerClassName, classLoader);
Assert.isAssignable(ApplicationContextInitializer.class, initializerClass);
return (ApplicationContextInitializer<C>) BeanUtils.instantiateClass(initializerClass);
}
@Override
String getName() {
return this.initializerClassName;
}
}
/**
* {@link AotApplicationContextInitializer} that delegates to an existing initializer
* instance.
*
* @param <C> the application context type
*/
static final class InstanceDelegatingAotApplicationContextInitializer<C extends ConfigurableApplicationContext>
extends AotApplicationContextInitializer<C> {
private final String name;
private final ApplicationContextInitializer<C> initializer;
InstanceDelegatingAotApplicationContextInitializer(String name, ApplicationContextInitializer<C> initializer) {
this.name = name;
this.initializer = initializer;
}
@Override
void aotInitialize(C applicationContext) {
this.initializer.initialize(applicationContext);
}
@Override
String getName() {
return this.name;
}
}
}

View File

@ -67,6 +67,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.aot.AotApplicationContextInitializer;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.GenericTypeResolver;
@ -85,7 +86,6 @@ import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.io.support.SpringFactoriesLoader.ArgumentResolver;
import org.springframework.core.log.LogMessage;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@ -416,19 +416,11 @@ public class SpringApplication {
private void addAotGeneratedInitializerIfNecessary(List<ApplicationContextInitializer<?>> initializers) {
if (AotDetector.useGeneratedArtifacts()) {
List<AotApplicationContextInitializer<?>> aotInitializers = new ArrayList<>();
for (ApplicationContextInitializer<?> candidate : initializers) {
if (candidate instanceof AotApplicationContextInitializer<?> aotInitializer) {
aotInitializers.add(aotInitializer);
}
}
List<ApplicationContextInitializer<?>> aotInitializers = new ArrayList<>(
initializers.stream().filter(AotApplicationContextInitializer.class::isInstance).toList());
if (aotInitializers.isEmpty()) {
AotApplicationContextInitializer<?> aotInitializer = AotApplicationContextInitializer
.forMainApplicationClass(this.mainApplicationClass);
aotInitializers.add(aotInitializer);
}
for (AotApplicationContextInitializer<?> aotInitializer : aotInitializers) {
logger.debug(LogMessage.format("Using AOT generated initializer: %s", aotInitializer.getName()));
String initializerClassName = this.mainApplicationClass.getName() + "__ApplicationContextInitializer";
aotInitializers.add(AotApplicationContextInitializer.forInitializerClasses(initializerClassName));
}
initializers.removeAll(aotInitializers);
initializers.addAll(0, aotInitializers);

View File

@ -1,99 +0,0 @@
/*
* Copyright 2012-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.boot;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
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 Phillip Webb
*/
class AotApplicationContextInitializerTests {
@Test
void forMainApplicationClassUsesReflection() {
AotApplicationContextInitializer<ConfigurableApplicationContext> initializer = AotApplicationContextInitializer
.forMainApplicationClass(ExampleMain.class);
GenericApplicationContext applicationContext = new GenericApplicationContext();
initializer.initialize(applicationContext);
assertThat(initializer.getName()).isEqualTo(ExampleMain__ApplicationContextInitializer.class.getName());
assertThat(applicationContext.getId()).isEqualTo("ExampleMain");
}
@Test
void ofWhenInitializerIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> AotApplicationContextInitializer.of(null))
.withMessage("Initializer must not be null");
}
@Test
void ofWithNameWhenInitializerIsNullThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> AotApplicationContextInitializer.of("test", null))
.withMessage("Initializer must not be null");
}
@Test
void ofWithNameWhenNameIsNullThrowsException() {
assertThatIllegalArgumentException()
.isThrownBy(() -> AotApplicationContextInitializer.of(null, new CustomApplicationContextInitializer()))
.withMessage("Name must not be null");
}
@Test
void ofUsesDelegation() {
AotApplicationContextInitializer<ConfigurableApplicationContext> initializer = AotApplicationContextInitializer
.of(new CustomApplicationContextInitializer());
GenericApplicationContext applicationContext = new GenericApplicationContext();
initializer.initialize(applicationContext);
assertThat(initializer.getName()).isEqualTo(CustomApplicationContextInitializer.class.getName());
assertThat(applicationContext.getId()).isEqualTo("Custom");
}
static class ExampleMain {
}
static class ExampleMain__ApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.setId("ExampleMain");
}
}
static class CustomApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.setId("Custom");
}
}
}