diff --git a/spring-web/src/main/java/org/springframework/web/context/support/AnnotationConfigGenericWebApplicationContext.java b/spring-web/src/main/java/org/springframework/web/context/support/AnnotationConfigGenericWebApplicationContext.java new file mode 100644 index 000000000000..aa77d8ab54fc --- /dev/null +++ b/spring-web/src/main/java/org/springframework/web/context/support/AnnotationConfigGenericWebApplicationContext.java @@ -0,0 +1,168 @@ +package org.springframework.web.context.support; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.function.Supplier; + +import javax.annotation.Nonnull; + +import org.springframework.beans.factory.config.BeanDefinitionCustomizer; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; +import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.AnnotationConfigRegistry; +import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.context.annotation.AnnotationScopeMetadataResolver; +import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; +import org.springframework.context.annotation.ScopeMetadataResolver; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.web.context.support.GenericWebApplicationContext; + +/** + * A copy of Spring-boot 2.1.8 {@link AnnotationConfigServletWebServerApplicationContext}, + * except that it does not use its own WebServer (other super class). + *
+ * Also See {@link AnnotationConfigApplicationContext} (Same as this but uses + * GenericApplicationContext instead of GenericWebApplicationContext) + *
+ * In contrast to {@link org.springframework.web.context.support.AnnotationConfigWebApplicationContext}, + * this class uses the GenericWebApplicationContext, which allows registering beans using a Supplier + * {@link #registerBean(Class, Supplier, BeanDefinitionCustomizer...)} + *
+ * See javadoc of superclass {@link GenericWebApplicationContext} for more information.
+ *
+ * @author Elias Lerch
+ * @see #register
+ * @see #scan
+ */
+public class AnnotationConfigGenericWebApplicationContext extends GenericWebApplicationContext implements AnnotationConfigRegistry {
+
+ private final AnnotatedBeanDefinitionReader reader;
+ private final ClassPathBeanDefinitionScanner scanner;
+ private final Set
+ * Delegates given environment to underlying {@link AnnotatedBeanDefinitionReader} and
+ * {@link ClassPathBeanDefinitionScanner} members.
+ */
+ @Override
+ public void setEnvironment(@Nonnull ConfigurableEnvironment environment) {
+ super.setEnvironment(environment);
+ this.reader.setEnvironment(environment);
+ this.scanner.setEnvironment(environment);
+ }
+
+ /**
+ * Provide a custom {@link BeanNameGenerator} for use with
+ * {@link AnnotatedBeanDefinitionReader} and/or
+ * {@link ClassPathBeanDefinitionScanner}, if any.
+ *
+ * Default is
+ * {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}.
+ *
+ * Any call to this method must occur prior to calls to {@link #register(Class...)}
+ * and/or {@link #scan(String...)}.
+ * @param beanNameGenerator the bean name generator
+ * @see AnnotatedBeanDefinitionReader#setBeanNameGenerator
+ * @see ClassPathBeanDefinitionScanner#setBeanNameGenerator
+ */
+ public void setBeanNameGenerator(BeanNameGenerator beanNameGenerator) {
+ this.reader.setBeanNameGenerator(beanNameGenerator);
+ this.scanner.setBeanNameGenerator(beanNameGenerator);
+ this.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
+ beanNameGenerator);
+ }
+
+ /**
+ * Set the {@link ScopeMetadataResolver} to use for detected bean classes.
+ *
+ * The default is an {@link AnnotationScopeMetadataResolver}.
+ *
+ * Any call to this method must occur prior to calls to {@link #register(Class...)}
+ * and/or {@link #scan(String...)}.
+ * @param scopeMetadataResolver the scope metadata resolver
+ */
+ public void setScopeMetadataResolver(ScopeMetadataResolver scopeMetadataResolver) {
+ this.reader.setScopeMetadataResolver(scopeMetadataResolver);
+ this.scanner.setScopeMetadataResolver(scopeMetadataResolver);
+ }
+
+ /**
+ * Register one or more annotated classes to be processed. Note that
+ * {@link #refresh()} must be called in order for the context to fully process the new
+ * class.
+ *
+ * Calls to {@code #register} are idempotent; adding the same annotated class more
+ * than once has no additional effect.
+ * @param annotatedClasses one or more annotated classes, e.g. {@code @Configuration}
+ * classes
+ * @see #scan(String...)
+ * @see #refresh()
+ */
+ @Override
+ public final void register(Class>... annotatedClasses) {
+ Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
+ this.annotatedClasses.addAll(Arrays.asList(annotatedClasses));
+ }
+
+ /**
+ * Perform a scan within the specified base packages. Note that {@link #refresh()}
+ * must be called in order for the context to fully process the new class.
+ * @param basePackages the packages to check for annotated classes
+ * @see #register(Class...)
+ * @see #refresh()
+ */
+ @Override
+ public final void scan(String... basePackages) {
+ Assert.notEmpty(basePackages, "At least one base package must be specified");
+ this.basePackages = basePackages;
+ }
+
+ @Override
+ protected void prepareRefresh() {
+ this.scanner.clearCache();
+ super.prepareRefresh();
+ }
+
+ @Override
+ protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
+ super.postProcessBeanFactory(beanFactory);
+ if (this.basePackages != null && this.basePackages.length > 0) {
+ this.scanner.scan(this.basePackages);
+ }
+ if (!this.annotatedClasses.isEmpty()) {
+ this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
+ }
+ }
+}