天天看點

spring boot @SpringBootApplication @EnableAutoConfiguration 的工作原理

在spring boot中@SpringBootApplication、@EnableAutoConfiguration是最常見Annotation,且最為重要,是以本文将展開對此的解讀。@SpringBootApplication在spring架構中的處理尤為複雜,然後能将它的來龍去脈(加載機制)講清楚的文章非常少。說實話你要完全了解及解讀它,需要對spring 3.x的源碼有一定程度了解,主要是它在原有的基礎上拓展了一些新概念,如若不按本文的思路,稍有不慎就會陷入代碼的海洋裡不能自拔。

目錄

1. SpringApplication

1.1 SpringFactoriesLoader

1.2 ApplicationListener

1.3 ApplicationContextInitializer

1.4 SpringApplication.run

1.5 SpringApplicationRunListeners和SpringApplicationRunListener

2. AbstractApplicationContext.refresh

2.1 BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor和BeanPostProcessor

2.2 ConfigurationClassPostProcessor

2.4 AnnotationConfigServletWebServerApplicationContext

2.5 ConfigurationClassParser

3. EnableAutoConfiguration

3.1 ImportSelector

@SpringBootApplication(scanBasePackages = {"com.example"})
public class WebApp {
    public static void main(String[] args) {
        SpringApplication.run(WebApp.class, args);
    }
}
           

首問:@SpringBootApplication是如何被解析并加載到spring ioc中的?

1. SpringApplication

在之前的文章“容器啟動原理揭秘”中提到過,最終通過 JarLauncher.launch 運作的目标是 WebApp.main 方法,之後就沒有再深入的講。首先進入視野的攔路虎就是SpringApplication,可以了解為它相當于spring的外觀模式,集各功能于一身,它也給使用者提供了鍊式文法支援-Builder模式(SpringApplicationBuilder().sources(Parent.class).child(Application.class)..run(args))。

public class SpringApplication {
    //入口
    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
    }
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        return (new SpringApplication(primarySources)).run(args);
    }
    public SpringApplication(Class... primarySources) {
        this((ResourceLoader)null, primarySources);
    }
    public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
        this.sources = new LinkedHashSet();
        this.bannerMode = Mode.CONSOLE;
        this.logStartupInfo = true;
        this.addCommandLineProperties = true;
        this.headless = true;
        this.registerShutdownHook = true;
        this.additionalProfiles = new HashSet();
        this.isCustomEnvironment = false;
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
        // 判斷web類型為reactive、none、servlet(隻要可以加載Servlet或ConfigurableWebApplicationContext),目前為servlet
        this.webApplicationType = this.deduceWebApplicationType();
        //從SpringFactoriesLoader中加載ApplicationContextInitializer類,并執行個體化
        this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //從SpringFactoriesLoader中加載ApplicationListener類,并執行個體化
        this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
        //這個是很重要的屬性:WebApp 
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }
}
           

你可能會問:SpringFactoriesLoader是什麼鬼?ApplicationContextInitializer和ApplicationListener又是什麼東西?

1.1 SpringFactoriesLoader

SpringFactoriesLoader 在spring boot中非常重要,它是spring對SPI的實作版本,主要是從jar中META-INF/spring.factories讀取拓展配置資訊。在spring boot架構中有兩個核心的 jar,它内置的 spring.factories 非常重要(使用者一般很少關注),而一般功能進行拓展也基于此:

spring-boot-2.0.5.RELEASE.jar/META-INF/spring.factories

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers

# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
           

spring-boot-autoconfigure-2.0.5.RELEASE.jar/META-INF/spring.factories

# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener

# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnClassCondition

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
           

SpringFactoriesLoader 源碼其實也不複雜,這裡不再贅述。

public abstract class SpringFactoriesLoader {
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    private static final Map<ClassLoader, MultiValueMap<String, String>> cache = new ConcurrentReferenceHashMap();
    public static <T> List<T> loadFactories(Class<T> factoryClass, @Nullable ClassLoader classLoader) {
        Assert.notNull(factoryClass, "'factoryClass' must not be null");
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }

        List<String> factoryNames = loadFactoryNames(factoryClass, classLoaderToUse);
        if (logger.isTraceEnabled()) {
            logger.trace("Loaded [" + factoryClass.getName() + "] names: " + factoryNames);
        }

        List<T> result = new ArrayList(factoryNames.size());
        Iterator var5 = factoryNames.iterator();

        while(var5.hasNext()) {
            String factoryName = (String)var5.next();
            result.add(instantiateFactory(factoryName, factoryClass, classLoaderToUse));
        }

        AnnotationAwareOrderComparator.sort(result);
        return result;
    }
}
           

1.2 ApplicationListener

ApplicationListener 就是Spring的事件監聽器,最重要的方法就是 onApplicationEvent,而事件源就是spring的廣播元件(SimpleApplicationEventMulticaster),所有監聽器通過 SpringFactoriesLoader 擷取。

spring boot @SpringBootApplication @EnableAutoConfiguration 的工作原理
//事件監聽器
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E var1);
}
//廣播事件
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
    public void multicastEvent(ApplicationEvent event) {
        this.multicastEvent(event, this.resolveDefaultEventType(event));
    }
    //添加監聽器
    public void addApplicationListener(ApplicationListener<?> listener) {
        Object var2 = this.retrievalMutex;
        synchronized(this.retrievalMutex) {
            Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
            if (singletonTarget instanceof ApplicationListener) {
                this.defaultRetriever.applicationListeners.remove(singletonTarget);
            }

            this.defaultRetriever.applicationListeners.add(listener);
            this.retrieverCache.clear();
        }
    }
}
//較重要的監聽器實作類
public class BackgroundPreinitializer implements ApplicationListener<SpringApplicationEvent> {
    public void onApplicationEvent(SpringApplicationEvent event) {
        //如果是首次觸發ApplicationStartingEvent時執行
        if (event instanceof ApplicationStartingEvent && preinitializationStarted.compareAndSet(false, true)) {
            this.performPreinitialization();
        }

        if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) && preinitializationStarted.get()) {
            try {
                preinitializationComplete.await();
            } catch (InterruptedException var3) {
                Thread.currentThread().interrupt();
            }
        }
    }
    private void performPreinitialization() {
        try {
            Thread thread = new Thread(new Runnable() {
                public void run() {
                    this.runSafely(new BackgroundPreinitializer.ConversionServiceInitializer());
                    this.runSafely(new BackgroundPreinitializer.ValidationInitializer());
                    this.runSafely(new BackgroundPreinitializer.MessageConverterInitializer());
                    this.runSafely(new BackgroundPreinitializer.MBeanFactoryInitializer());
                    this.runSafely(new BackgroundPreinitializer.JacksonInitializer());
                    this.runSafely(new BackgroundPreinitializer.CharsetInitializer());
                    BackgroundPreinitializer.preinitializationComplete.countDown();
                }
                public void runSafely(Runnable runnable) {
                    try {
                        runnable.run();
                    } catch (Throwable var3) {
                        ;
                    }

                }
            }, "background-preinit");
            thread.start();
        } catch (Exception var2) {
            preinitializationComplete.countDown();
        }
    }
}
           

題外話,BackgroundPreinitializer 把耗時的操作采用這種模式(事件+多線程)來實作,足以可見spring的設計功底。

1.3 ApplicationContextInitializer

ApplicationContextInitializer 是 ConfigurableApplicationContext(繼承自ApplicationContext) 執行個體後的上下文初始化元件,它主要可以向 applicationContext 注入一些新的bean、修改 applicationContext 基本資訊等,核心方法是 initialize,所有實作類通過 SpringFactoriesLoader 擷取。

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
    void initialize(C var1);
}
           

spring提供的實作非常多,比如:ContextIdApplicationContextInitializer,它實作applicationContext.setId(contextId.getId())。

spring boot @SpringBootApplication @EnableAutoConfiguration 的工作原理

1.4 SpringApplication.run

其實 SpringApplication.run 整體還不算特别複雜,關鍵的方法有 prepareContext ,refreshContext會比較繞。當然這裡面有一個出現的頻率非常高的對象 SpringApplicationRunListeners (讀源碼就是這樣,要解決痛點),那它是幹什麼的?繼續向下看吧!

public class SpringApplication {
    //真正的入口
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
        this.configureHeadlessProperty();
        //下面專門解釋
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
        //觸發ApplicationStartingEvent
        listeners.starting();

        Collection exceptionReporters;
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //擷取配置對象
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
            //向environment添加新配置
            this.configureIgnoreBeanInfo(environment);
            //列印spring boot的Banner
            Banner printedBanner = this.printBanner(environment);
            //根據webApplicationType類型擷取applicationContext,目前為AnnotationConfigServletWebServerApplicationContext
            context = this.createApplicationContext();
            //異常彙總報告
            exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
            //向applicationContext中填充資訊(environment、調用ApplicationContextInitializer、注入新bean)
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            //重新整理application
            this.refreshContext(context);
            //無任何實作
            this.afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                //列印日志
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
            //觸發ApplicationStartedEvent
            listeners.started(context);
            //調用ioc中所有ApplicationRunner.run和CommandLineRunner.run
            this.callRunners(context, applicationArguments);
        } catch (Throwable var10) {
            this.handleRunFailure(context, var10, exceptionReporters, listeners);
            throw new IllegalStateException(var10);
        }
        try {
            //觸發ApplicationReadyEvent
            listeners.running(context);
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
            throw new IllegalStateException(var9);
        }
    }
    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
        ConfigurableEnvironment environment = this.getOrCreateEnvironment();  
        this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
        //觸發ApplicationEnvironmentPreparedEvent
        listeners.environmentPrepared((ConfigurableEnvironment)environment);
        this.bindToSpringApplication((ConfigurableEnvironment)environment);
        if (!this.isCustomEnvironment) {
            //根據webApplicationType類型擷取配置對象(環境資訊、profile),目前為StandardServletEnvironment
            environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
        }

        ConfigurationPropertySources.attach((Environment)environment);
        return (ConfigurableEnvironment)environment;
    }
    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        //注入beanNameGenerator、設定ResourceLoader
        this.postProcessApplicationContext(context);
        //調用所有的初始化元件(ApplicationContextInitializer)
        this.applyInitializers(context);
        //無任何實作
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            //列印getApplicationLog()資訊
            this.logStartupInfo(context.getParent() == null);
            // 列印Profile資訊
            this.logStartupProfileInfo(context);
        }
        //ioc容器儲存應用程式啟動參數(String[] args)資訊
        context.getBeanFactory().registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            //ioc容器儲存Banner資訊
            context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
        }
        
        Set<Object> sources = this.getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        //把啟動類(WebApp )注入到Ioc容器中,調用BeanDefinitionLoader.load
        this.load(context, sources.toArray(new Object[0]));
        //觸發ApplicationPreparedEvent
        listeners.contextLoaded(context);
    }
    private void refreshContext(ConfigurableApplicationContext context) {
        //調用AbstractApplicationContext.refresh(後面專門講)
        this.refresh(context);
        //添加鈎子函數
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
                ;
            }
        }
    }
}
class BeanDefinitionLoader {
    //prepareContext方法中this.load最終會執行到這裡
    private int load(Class<?> source) {
        if (this.isGroovyPresent() && BeanDefinitionLoader.GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            BeanDefinitionLoader.GroovyBeanDefinitionSource loader = (BeanDefinitionLoader.GroovyBeanDefinitionSource)BeanUtils.instantiateClass(source, BeanDefinitionLoader.GroovyBeanDefinitionSource.class);
            this.load(loader);
        }
        //WebApp類符合條件
        if (this.isComponent(source)) {
            this.annotatedReader.register(new Class[]{source});
            return 1;
        } else {
            return 0;
        }
    }
}
           

到這裡你感覺是結束了!

但這好像并沒看到spring是如何處理 SpringBootApplication、EnableAutoConfiguration 相關的邏輯啊?

如果你真正調試,你會發現一個這樣現象:

  • 未執行refreshContext方法前,applicationContext (Ioc容器)好像注入的的bean非常少,其中一個就是WebApp對象
  • 執行refreshContext之後,applicationContext (Ioc容器)裡什麼都有了,的确是 SpringBootApplication、EnableAutoConfiguration 生效了

是的,這發現很重要!!至少知道 refreshContext (就是 AbstractApplicationContext.refresh)是突破口!!

1.5 SpringApplicationRunListeners和SpringApplicationRunListener

SpringApplicationRunListeners 管理着 applicationContext  初始化、執行個體化、啟動運作的各個階段,它最重要的職責就是通過事件驅動與外界的聯系。SpringApplicationRunListener是通過 SpringFactoriesLoader 擷取的,它定義了applicationContext  的各個階段及其實作(EventPublishingRunListener ),EventPublishingRunListener的特點是事件驅動,它通過事件廣播元件SimpleApplicationEventMulticaster與外界交換。

class SpringApplicationRunListeners {
    SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log;
        //通過SpringApplicationRunListener
        this.listeners = new ArrayList(listeners);
    }
    public void starting() {
        Iterator var1 = this.listeners.iterator();
        //調用所有的SpringApplicationRunListener.starting
        while(var1.hasNext()) {
            SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
            listener.starting();
        }
    }
    public void started(ConfigurableApplicationContext context) {
        Iterator var2 = this.listeners.iterator();
        while(var2.hasNext()) {
            SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
            listener.started(context);
        }
    }
}
//SpringApplicationRunListener是通過SpringFactoriesLoader擷取的
private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
    return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
//applicationContext的各個階段
public interface SpringApplicationRunListener {
    void starting();//啟動中
    void environmentPrepared(ConfigurableEnvironment environment);//環境變量初始化
    void contextPrepared(ConfigurableApplicationContext context);//上下文準備
    void contextLoaded(ConfigurableApplicationContext context);
    void started(ConfigurableApplicationContext context);
    void running(ConfigurableApplicationContext context);
    void failed(ConfigurableApplicationContext context, Throwable exception);//失敗
}
//支援事件驅動的SpringApplicationRunListener的實作
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        //事件廣播元件
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        Iterator var3 = application.getListeners().iterator();

        while(var3.hasNext()) {
            ApplicationListener<?> listener = (ApplicationListener)var3.next();
            this.initialMulticaster.addApplicationListener(listener);
        }

    }
    public void starting() {
        //發事件
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }
    public void environmentPrepared(ConfigurableEnvironment environment) {
        this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
    }
    public void contextLoaded(ConfigurableApplicationContext context) {
        ApplicationListener listener;
        for(Iterator var2 = this.application.getListeners().iterator(); var2.hasNext(); context.addApplicationListener(listener)) {
            listener = (ApplicationListener)var2.next();
            if (listener instanceof ApplicationContextAware) {
                ((ApplicationContextAware)listener).setApplicationContext(context);
            }
        }
        //發事件
        this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
    }
    public void started(ConfigurableApplicationContext context) {
        //發事件
        context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
    }
}
           

2. AbstractApplicationContext.refresh

AbstractApplicationContext.refresh 是非常複雜的,為避免知識點無限延伸,和本文主題相關性不大的東西不展開探讨。

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {    
    public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            //設定this.startupDate、this.closed=true,this.active=true,initPropertySources()、validateRequiredProperties()
            this.prepareRefresh();
            /**通知子類重新整理内部的bean factory,主要分為兩步:
             * refreshBeanFactory(進行真正的配置加載,xml是在這一步解析的,讀取注冊的regular bean)
             * 擷取beanFactory
             */
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            /**配置beanFactory标準的上下文特性,非常複雜
             * set:classLoader
             * set:StandardBeanExpressionResolver (spring EL)
             * addBeanPostProcessor:ApplicationContextAwareProcessor(BeanPostProcessor提供set各種aware)
             * addBeanPostProcessor:ApplicationListenerDetector(ApplicationListener處理)
             * ignoreDependencyInterface、registerResolvableDependency
             */
            this.prepareBeanFactory(beanFactory);

            try {
                //在子類中,允許對beanFactory進行後期處理
                this.postProcessBeanFactory(beanFactory);
                //執行BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor,後面專門講            
                this.invokeBeanFactoryPostProcessors(beanFactory);
                /**添加執行個體化的後置處理器,并對所有的進行排序
                 * BeanPostProcessorChecker
                 * ApplicationListenerDetector
                **/               
                this.registerBeanPostProcessors(beanFactory);
                //初始化國際化服務
                this.initMessageSource();
                //建立事件廣播器
                this.initApplicationEventMulticaster();
                //在子類中實作
                this.onRefresh();
                /**注冊一部分給出的事件監聽器,
                 * addApplicationListenerBean:隻添加監聽器的名字(留待bean執行個體化完成後再注冊)
                **/
                this.registerListeners();
                //單例模式的bean的執行個體化、成員變量注入、初始化等工作都在此完成
                this.finishBeanFactoryInitialization(beanFactory);
                /**applicationContext重新整理完成後的處理
                 * initLifecycleProcessor()
                 * this.getLifecycleProcessor().onRefresh
                 * this.publishEvent(new ContextRefreshedEvent(this));
                **/
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }
                //重新整理失敗後的處理,主要是将一些儲存環境資訊的集合做清理
                this.destroyBeans();
                //applicationContext是否已經激活的标志,設定為false
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }
}
           

這裡有一點基本上可以确認了:refresh調用方法invokeBeanFactoryPostProcessors(beanFactory)

其實這裡有一個疑問:regular bean是什麼?BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor有什麼差別及聯系?

2.1 BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor和BeanPostProcessor

ConfigurationClassPostProcessor(其實是個BeanDefinitionRegistryPostProcessor,之前的文章講過)今天的主角,處理spring-boot中的SpringBootApplication ,

//AbstractApplicationContext.invokeBeanFactoryPostProcessors的入口
final class PostProcessorRegistrationDelegate {
	//裡面處理很複雜,但英文注釋已經足夠了解很多的情況了
	public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the bean factory post-processors apply to them!
			// Separate between BeanDefinitionRegistryPostProcessors that implement
			// PriorityOrdered, Ordered, and the rest.
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				currentRegistryProcessors.clear();
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
				// skip - already processed in first phase above
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		beanFactory.clearMetadataCache();
	}
}
           

2.2 ConfigurationClassPostProcessor

前面講過ConfigurationClassPostProcessor實是個BeanDefinitionRegistryPostProcessor。還是看源碼吧,其實不需要所有的地方都懂,有注釋的地方看懂就能了解今天的真相。

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		int factoryId = System.identityHashCode(beanFactory);
		if (this.factoriesPostProcessed.contains(factoryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + beanFactory);
		}
		this.factoriesPostProcessed.add(factoryId);
		if (!this.registriesPostProcessed.contains(factoryId)) {
			// BeanDefinitionRegistryPostProcessor hook apparently not supported...
			// Simply call processConfigurationClasses lazily at this point then.
			//看這裡啊,英文解釋很明确,處理Configuration類
			processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
		}
		enhanceConfigurationClasses(beanFactory);
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}
	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();
		//從ioc中找到有spring注解的bean
		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// Return immediately if no @Configuration classes were found
		if (configCandidates.isEmpty()) {
			return;
		}
		...
		// Parse each @Configuration class
		// ConfigurationClassParser 後面具體講
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			parser.parse(candidates);
			parser.validate();
		...
	}
}
           

那新的問題來了:

  • ConfigurationClassPostProcessor是什麼時候注入到spring ioc中的呢?
  • ConfigurationClassParser又是什麼呢?

2.4 AnnotationConfigServletWebServerApplicationContext

在上面我們講過SpringApplication.createApplicationContext(),最終得到的是AnnotationConfigServletWebServerApplicationContext,看源碼吧

public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
    public AnnotationConfigServletWebServerApplicationContext() {
        this.annotatedClasses = new LinkedHashSet();
        //reader 這個對象很關鍵
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
}
public class AnnotatedBeanDefinitionReader {
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
		this(registry, getOrCreateEnvironment(registry));
	}
	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		//它注入了一些BeanFactoryPostProcessor
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}
}
public class AnnotationConfigUtils {
	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		if (beanFactory != null) {
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			}
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			}
		}

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			//看這裡,就是spring boot注解處理類
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			//Autowired注解處理類
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			//Required注解處理類
			RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
		if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition();
			try {
				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
						AnnotationConfigUtils.class.getClassLoader()));
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
			}
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}

		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}

		return beanDefs;
	}
}
           

2.5 ConfigurationClassParser

ConfigurationClassParser是spring boot真正的配置類解析器,當然入口方法是parse。

class ConfigurationClassParser {
	public void parse(Set<BeanDefinitionHolder> configCandidates) {
		this.deferredImportSelectors = new LinkedList<>();
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				if (bd instanceof AnnotatedBeanDefinition) {
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}
		processDeferredImportSelectors();
	}
	//ImportSelector後續專門講
	private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
		if (importCandidates.isEmpty()) {
			return;
		}
		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
			this.importStack.push(configClass);
			try {
				for (SourceClass candidate : importCandidates) {
					//對ImportSelector的處理
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						//執行個體化selector
						ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
						//							
						ParserStrategyUtils.invokeAwareMethods(
								selector, this.environment, this.resourceLoader, this.registry);
						if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
							//如果為延遲導入處理則加入集合當中
							this.deferredImportSelectors.add(
									new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
						}
						else {
   							//根據ImportSelector方法的傳回值來進行遞歸操作
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
					}
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
						ParserStrategyUtils.invokeAwareMethods(
								registrar, this.environment, this.resourceLoader, this.registry);
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					else {
						// 如果目前的類既不是ImportSelector也不是ImportBeanDefinitionRegistar就進行@Configuration的解析處理
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						processConfigurationClass(candidate.asConfigClass(configClass));
					}
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to process import candidates for configuration class [" +
						configClass.getMetadata().getClassName() + "]", ex);
			}
			finally {
				this.importStack.pop();
			}
		}
	}
	//處理spring各種注解類
	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {
		// Process any @PropertySource annotations
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}
		// Process any @ComponentScan annotations
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}
		// Process any @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), true);
		// Process any @ImportResource annotations
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}
		// Process individual @Bean methods
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		processInterfaces(configClass, sourceClass);
		// Process superclass, if any
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}
		// No superclass -> processing is complete
		return null;
	}
}
           

那最剩下最後一個問題:ImportSelector又是什麼呢?

3. EnableAutoConfiguration

個人感覺@EnableAutoConfiguration這個Annotation最為重要,是以放在最後來解讀,大家是否還記得Spring架構提供的各種名字為@Enable開頭的Annotation定義?比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和做事方式其實一脈相承、

簡單概括一下就是,借助@Import的支援,收集和注冊特定場景相關的bean定義。

  • @EnableScheduling是通過@Import将Spring排程架構相關的bean定義都加載到IoC容器。
  • @EnableMBeanExport是通過@Import将JMX相關的bean定義加載到IoC容器。

而@EnableAutoConfiguration也是借助@Import的幫助,将所有符合自動配置條件的bean定義加載到IoC容器,僅此而已!

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    Registrar() {
    }
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
    }
    public Set<Object> determineImports(AnnotationMetadata metadata) {
        return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
    }
}
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return NO_IMPORTS;
        } else {
            AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.filter(configurations, autoConfigurationMetadata);
            //觸發AutoConfigurationImportEvent
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return StringUtils.toStringArray(configurations);
        }
    }
   //從spring.factories中EnableAutoConfiguration擷取所有
   protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
        Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
        return configurations;
    }
}
           

AutoConfigurationPackage它其實是注冊了一個Bean的定義。new PackageImport(metadata).getPackageName(),它其實傳回了目前主程式類的同級以及子級 的包元件。這也就是為什麼,我們要把WebApp放在項目的最進階中。

3.1 ImportSelector

之前講過ImportSelector被ConfigurationClassParser調用,AutoConfigurationImportSelector 繼承了 DeferredImportSelector 繼承了 ImportSelector,有一個重要的方法為:selectImports。就像一隻“八爪魚”一樣,勾起spring-boot的強大配置庫。

spring boot @SpringBootApplication @EnableAutoConfiguration 的工作原理

總結,SpringBootApplication注解是通過一個BeanDefinitionRegistryPostProcessor實作解析,在createApplicationContext()時被執行個體化并注入到Ioc中,在AbstractApplicationContext.refresh被調用PostProcessor。

spring boot @SpringBootApplication @EnableAutoConfiguration 的工作原理

繼續閱讀