注:SpringBoot版本 2.6.2
SpringBoot的入口是從SpringApplication.run()傳入我們的主啟動類開始
@SpringBootApplication public class LeeSpringbootApplication { public static void main(String[] args) { SpringApplication.run(LeeSpringbootApplication.class, args); } }
run()方法:
1、初始化SrpingApplication物件
2、執行run() 方法(primarySources:主啟動類class)
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
1、初始化SrpingApplication物件
1、設定應用型別,後面會根據型別初始化對應的環境,常用的一般都是servlet環境
2、載入系統中引導器Bootstrapper(從META-INF/spring.factories中載入)
3、初始化classpath下 META-INF/spring.factories 中已配置的ApplicationContextInitalizer
4、初始化classpath下所以已配置的 ApplicationListener
5、根據呼叫棧,設定 main 方法的類名
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { //設定資源載入器為null this.resourceLoader = resourceLoader; //斷言載入資源不能為null Assert.notNull(primarySources, "PrimarySources must not be null"); //將primarySources陣列轉換為list,最後放到LinkedHashSet集合中 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 1.1 推斷應用型別,後面會根據型別初始化對應的環境,常用的一般都是servlet環境 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 1.2 載入系統中引導器Bootstrapper this.bootstrapRegistryInitializers = new ArrayList<>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); // 1.3 初始化classpath下 META-INF/spring.factories 中已配置的ApplicationContextInitalizer setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 1.4 初始化classpath下所以已配置的 ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 1.5 根據呼叫棧,設定 main 方法的類名 this.mainApplicationClass = deduceMainApplicationClass(); }
在執行 getSpringFactoriesInstances(BootstrapRegistryInitializer.class) 中會呼叫 loadSpringFactories() 方法遍歷所有jar包中classpath下 META-INF/spring.factories檔案,並儲存在快取中
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { Map<String, List<String>> result = cache.get(classLoader); if (result != null) { return result; } result = new HashMap<>(); try { Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION); while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryTypeName = ((String) entry.getKey()).trim(); String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) entry.getValue()); for (String factoryImplementationName : factoryImplementationNames) { result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()) .add(factoryImplementationName.trim()); } } } // Replace all lists with unmodifiable lists containing unique elements result.replaceAll((factoryType, implementations) -> implementations.stream().distinct() .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList))); cache.put(classLoader, result); } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } return result; }
2、執行run() 方法
1、獲取並啟動監聽器
2、構造上下文環境
3、初始化應用上下文
4、重新整理應用上下文前的準備階段
5、重新整理上下文
6、重新整理應用上下文後的擴充套件介面
public ConfigurableApplicationContext run(String... args) { //記錄程式執行時間 long startTime = System.nanoTime(); // 建立 DefaultBootstrapContext 的一項 DefaultBootstrapContext bootstrapContext = createBootstrapContext(); // ConfigurableApplicationContext spring的上下文 ConfigurableApplicationContext context = null; configureHeadlessProperty(); // 1、獲取並啟動監聽器 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 2、構造上下文環境 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); // 處理需要忽略的Bean configureIgnoreBeanInfo(environment); // 列印banner (springboot圖示) Banner printedBanner = printBanner(environment); // 3、初始化應用上下文 context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); // 4、重新整理應用上下文前的準備階段 prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); // 5、重新整理上下文 refreshContext(context); // 6、重新整理應用上下文後的擴充套件介面 afterRefresh(context, applicationArguments); // 記錄執行時間 Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup); } listeners.started(context, timeTakenToStartup); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime); listeners.ready(context, timeTakenToReady); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; }
2.1 載入監聽器
載入META-INF/spring.factories 中的 SpringApplicationRunListener,SpringApplicationRunListeners負責在springBoot啟動的不同階段,廣播出不同的訊息,傳遞給ApplicationListener監聽器實現類
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup); }
在 getSpringFactoriesInstances 中載入構建監聽器物件並根據order進行排序
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // Use names and ensure unique to protect against duplicates Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
2.2 構造上下文環境
根據之前標記的應用型別(SERVLET)建立相應的環境,並根據配置檔案,配置相應的系統環境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // Create and configure the environment // 建立並配置相應環境 ConfigurableEnvironment environment = getOrCreateEnvironment(); // 根據使用者配置,配置系統環境 configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); // 啟動監聽器,其中一個重要的監聽器 ConfigFileApplicationListener 載入專案配置檔案的監聽器 listeners.environmentPrepared(bootstrapContext, environment); DefaultPropertiesPropertySource.moveToEnd(environment); Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties."); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = convertEnvironment(environment); } ConfigurationPropertySources.attach(environment); return environment; }
2.3 初始化應用上下文
根據配置的應用型別(SERVLET)建立對應的context (AnnotationConfigServletWebServerApplicationContext) 並在父類 GenericApplicationContext 的構造方法中建立了DefaultListableBeanFactory(ioc容器)
protected ConfigurableApplicationContext createApplicationContext() { return this.applicationContextFactory.create(this.webApplicationType); }
ApplicationContextFactory DEFAULT = (webApplicationType) -> { try { switch (webApplicationType) { case SERVLET: return new AnnotationConfigServletWebServerApplicationContext(); case REACTIVE: return new AnnotationConfigReactiveWebServerApplicationContext(); default: return new AnnotationConfigApplicationContext(); } } catch (Exception ex) { throw new IllegalStateException("Unable create a default ApplicationContext instance, " + "you may need a custom ApplicationContextFactory", ex); } };
2.4 重新整理應用上下文前的準備階段
主要完成應用上下文屬性設定,並且將啟動類生成例項物件儲存到容器中。
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 設定容器環境 context.setEnvironment(environment); // 執行容器後置處理(主要設定轉換器) postProcessApplicationContext(context); // 應用初始化器,執行容器中的 ApplicationContextInitializer 包括spring.factories applyInitializers(context); // 向各個容器中傳送容器已經準備好的事件 listeners.contextPrepared(context); bootstrapContext.close(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 將main函式中的args引數封裝成單例Bean,註冊到容器 beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { // 將printedBanner 封裝成單例Bean 註冊到容器 beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof AbstractAutowireCapableBeanFactory) { ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences); if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory) beanFactory) .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources // 獲取主啟動類 Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); // 載入啟動類,將啟動類註冊到容器 load(context, sources.toArray(new Object[0])); // 釋出容器中已載入的事件 listeners.contextLoaded(context); }
postProcessApplicationContext(context) 設定轉換器
protected void postProcessApplicationContext(ConfigurableApplicationContext context) { if (this.beanNameGenerator != null) { context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator); } if (this.resourceLoader != null) { if (context instanceof GenericApplicationContext) { ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader); } if (context instanceof DefaultResourceLoader) { ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader()); } } if (this.addConversionService) { context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService()); } }
應用ApplicationContextInitializer
protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(), ApplicationContextInitializer.class); Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); initializer.initialize(context); } }
getAllSource() 獲取主啟動類
public Set<Object> getAllSources() { Set<Object> allSources = new LinkedHashSet<>(); if (!CollectionUtils.isEmpty(this.primarySources)) { allSources.addAll(this.primarySources); } if (!CollectionUtils.isEmpty(this.sources)) { allSources.addAll(this.sources); } return Collections.unmodifiableSet(allSources); }
load() 主要將主啟動類生成例項物件儲存在容器中,spring容器在啟動的時候會將類解析成spring內部的BeanDefinition結構,並將BeanDefinition儲存到DefaultListableBeanFactory的map中。
protected void load(ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } // 建立 BeanDefinitionLoader BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources); if (this.beanNameGenerator != null) { loader.setBeanNameGenerator(this.beanNameGenerator); } if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); } if (this.environment != null) { loader.setEnvironment(this.environment); } // 將啟動類生成例項物件儲存到容器中 loader.load(); }
getBeanDefinitionRegistry(context) 將上下文轉換為 BeanDefinitionRegistry 型別
private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) { if (context instanceof BeanDefinitionRegistry) { return (BeanDefinitionRegistry) context; } if (context instanceof AbstractApplicationContext) { return (BeanDefinitionRegistry) ((AbstractApplicationContext) context).getBeanFactory(); } throw new IllegalStateException("Could not locate BeanDefinitionRegistry"); } getBeanDefinitionRegistry
createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources) 建立BeanDefinitionLoader,其中建立一些Bean定義讀取器。
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) { return new BeanDefinitionLoader(registry, sources); } BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) { Assert.notNull(registry, "Registry must not be null"); Assert.notEmpty(sources, "Sources must not be empty"); this.sources = sources; // 建立註解形式的Bean定義讀取器, eg:@Configuration @Bean @Component @Controller等 this.annotatedReader = new AnnotatedBeanDefinitionReader(registry); // 建立xml形式的Bean定義讀取器 this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null); this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null); // 建立類路徑掃描器 this.scanner = new ClassPathBeanDefinitionScanner(registry); // 掃描器新增排除過濾器 this.scanner.addExcludeFilter(new ClassExcludeFilter(sources)); }
loader.load()將啟動類生成例項物件儲存在容器中。
void load() { for (Object source : this.sources) { //source 為啟動類 load(source); } } private void load(Object source) { Assert.notNull(source, "Source must not be null"); if (source instanceof Class<?>) { // 從class中載入 load((Class<?>) source); return; } if (source instanceof Resource) { // 從 Resource 中載入 load((Resource) source); return; } if (source instanceof Package) { // 從 Package 中載入 load((Package) source); return; } if (source instanceof CharSequence) { // 從 CharSequence 中載入 load((CharSequence) source); return; } throw new IllegalArgumentException("Invalid source type " + source.getClass()); } private void load(Class<?> source) { if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) { // Any GroovyLoaders added in beans{} DSL can contribute beans here GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class); ((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans()); } if (isEligible(source)) { // 將啟動類的 BeanDefinition 註冊到 BeanDefinitionMap 中 this.annotatedReader.register(source); } } load()
2.5 重新整理上下文
主要邏輯為AbstractApplicationContext 物件的 refresh() 方法,進行整個容器的重新整理過程,會呼叫spring中的refresh()方法,其中有13個關鍵方法,來完成整個
SpringBoot應用程式的啟動。
private void refreshContext(ConfigurableApplicationContext context) { if (this.registerShutdownHook) { shutdownHook.registerApplicationContext(context); } refresh(context); } protected void refresh(ConfigurableApplicationContext applicationContext) { applicationContext.refresh(); } public final void refresh() throws BeansException, IllegalStateException { try { super.refresh(); } catch (RuntimeException ex) { WebServer webServer = this.webServer; if (webServer != null) { webServer.stop(); } throw ex; } } public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); // Prepare this context for refreshing. //1:準備重新整理上下文環境 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. //2:獲取告訴子類初始化Bean工廠 不同工廠不同實現 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // 對bean工廠進行填充屬性 prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. // 執行beanFactroy後置處理器 postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); // Invoke factory processors registered as beans in the context. // 呼叫我們的bean工廠的後置處理器. 1. 會在此將class掃描成beanDefinition 2.bean工廠的後置處理器呼叫 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 註冊我們bean的後置處理器 registerBeanPostProcessors(beanFactory); beanPostProcess.end(); // Initialize message source for this context. // 初始化國際化資源處理器. initMessageSource(); // Initialize event multicaster for this context. // 建立事件多播器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // 這個方法同樣也是留個子類實現的springboot也是從這個方法進行啟動tomcat的. onRefresh(); // Check for listener beans and register them. //把我們的事件監聽器註冊到多播器上 registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // 例項化我們剩餘的單例項bean. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. // 最後容器重新整理 釋出重新整理事件(Spring cloud也是從這裡啟動的) finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); contextRefresh.end(); } } }
invokeBeanFactoryPostProcessors(beanFactory) 改方法會解析核心啟動類中 @SpringBootApplication實現自動配置
Ioc容器的初始化包括三個步驟,該三個步驟在 invokeBeanFactoryPostProcessors 中完成
1、Resource定位
在SpringBoot中,包掃描是從主類所在包開始掃描,prepareContext()方法中,會將主類解析成BeanDefinition儲存在容器中,然後在refresh()方法的invokeBeanFactoryPostProcessors()方法中解析主類的BeanDefinition獲取basePackage的路徑。這樣就完成了定位的過程。
SpringBoot的各種starter是通過SPI擴充套件機制實現的自動裝配,SpringBoot的自動裝配同樣也是在invokeBeanFactoryPostProcessors()方法中實現的。 在SpringBoot中有很多的@EnableXXX註解,其底層是@Import註解,在invokeBeanFactoryPostProcessors()方法中也實現了對該註解指定的配置類的定位載入。
常規在SpringBoot中有三種定位方法:主類所在的包、SPI擴充套件機制實現的自動裝配、@Import註解指定的類
SPI ,全稱為 Service Provider Interface,是一種服務發現機制。它通過在ClassPath路徑下的META-INF/services資料夾查詢檔案,自動載入檔案裡所定義的類,也可以這樣理解:SPI是“基於介面的程式設計+策略模式+配置檔案”組成實現的動態載入機制。
2、BeanDefinition的載入
SpringBoot會將通過定位得到的basePackage的路徑拼裝成 classpath:com/***/.class 的形式,然後 PathMatchingResourcePatternResolver類會將該路徑下所有的 .class 檔案載入進來,然後進行遍歷判斷是否含有 @Component 註解,如果有就是要裝載的 BeanDefinition。
3、註冊Beanfinition
註冊過程是將載入過程中解析得到的BeanDefinition向IOC容器進行註冊。通過上下文分析,在容器中將BeanDefinition注入到一個ConcurrenHashMap中,IOC容器通過這個map來儲存BeanDefinition資料。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } } // PostProcessorRegistrationDelegate public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { // WARNING: Although it may appear that the body of this method can be easily // refactored to avoid the use of multiple loops and multiple lists, the use // of multiple lists and multiple passes over the names of processors is // intentional. We must ensure that we honor the contracts for PriorityOrdered // and Ordered processors. Specifically, we must NOT cause processors to be // instantiated (via getBean() invocations) or registered in the ApplicationContext // in the wrong order. // // Before submitting a pull request (PR) to change this method, please review the // list of all declined PRs involving changes to PostProcessorRegistrationDelegate // to ensure that your proposal does not result in a breaking change: // https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22 // 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, beanFactory.getApplicationStartup()); 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, beanFactory.getApplicationStartup()); 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, beanFactory.getApplicationStartup()); 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<>(orderedPostProcessorNames.size()); 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<>(nonOrderedPostProcessorNames.size()); 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(); } private static void invokeBeanDefinitionRegistryPostProcessors( Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) { for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) { StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process") .tag("postProcessor", postProcessor::toString); // 解析註解 postProcessor.postProcessBeanDefinitionRegistry(registry); postProcessBeanDefRegistry.end(); } }
實現自動裝配:
invokeBeanFactoryPostProcessors()方法主要是對 ConfigurationClassPostProcessor 類的處理,這是BeanDefinitionRegistryPostProcessor的子類,BeanDefinitionRegistryPostProcessor 是BeanDefinitionRegistryPostProcessor 的子類,呼叫BeanDefinitionRegistryPostProcessor中的postProcessBeanDefinitionRegistry()方法,會解析 @PropertySource @ComponentScans @ComponentScan @Bean @Import等註解
refresh() -> AbstractApplicationContext.invokeBeanFactoryPostProcessors(beanFactory)
-> invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup())
-> postProcessor.postProcessBeanDefinitionRegistry(registry) (ConfigurationClassPostProcessor類下的方法)
-> processConfigBeanDefinitions(registry) -> new ConfigurationClassParser() (解析@Configuration 標註的類)
-> parser.parse(candidates) (解析啟動類上的註解)
-> this.reader.loadBeanDefinitions(configClasses) (生效自動配置類)
// ConfigurationClassPostProcessor public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { int registryId = System.identityHashCode(registry); if (this.registriesPostProcessed.contains(registryId)) { throw new IllegalStateException( "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry); } if (this.factoriesPostProcessed.contains(registryId)) { throw new IllegalStateException( "postProcessBeanFactory already called on this post-processor against " + registry); } this.registriesPostProcessed.add(registryId); processConfigBeanDefinitions(registry); } public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); String[] candidateNames = registry.getBeanDefinitionNames(); for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName); if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) { 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; } // Sort by previously determined @Order value, if applicable configCandidates.sort((bd1, bd2) -> { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return Integer.compare(i1, i2); }); // Detect any custom bean name generation strategy supplied through the enclosing application context SingletonBeanRegistry sbr = null; if (registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry) registry; if (!this.localBeanNameGeneratorSet) { BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton( AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR); if (generator != null) { this.componentScanBeanNameGenerator = generator; this.importBeanNameGenerator = generator; } } } if (this.environment == null) { this.environment = new StandardEnvironment(); } // Parse each @Configuration class 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 { StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse"); //獲取所有bean的全路徑(解析各類註解) parser.parse(candidates); parser.validate(); Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses()); configClasses.removeAll(alreadyParsed); // Read the model and create bean definitions based on its content if (this.reader == null) { this.reader = new ConfigurationClassBeanDefinitionReader( registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry()); } // 使自動配置類生效 this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end(); candidates.clear(); if (registry.getBeanDefinitionCount() > candidateNames.length) { String[] newCandidateNames = registry.getBeanDefinitionNames(); Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames)); Set<String> alreadyParsedClasses = new HashSet<>(); for (ConfigurationClass configurationClass : alreadyParsed) { alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); } for (String candidateName : newCandidateNames) { if (!oldCandidateNames.contains(candidateName)) { BeanDefinition bd = registry.getBeanDefinition(candidateName); if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) { candidates.add(new BeanDefinitionHolder(bd, candidateName)); } } } candidateNames = newCandidateNames; } } while (!candidates.isEmpty()); // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) { sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); } if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) { // Clear cache in externally provided MetadataReaderFactory; this is a no-op // for a shared cache since it'll be cleared by the ApplicationContext. ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); } }
parser.parse(candidates) 從啟動類開始解析各種註解(@PropertySource @ComponentScan @Import @ImportResource @Bean),載入配置類,在processImports(configClass, sourceClass, getImports(sourceClass), filter, true)中對啟動類進行解析,載入其中的@Import註解的類
public void parse(Set<BeanDefinitionHolder> configCandidates) { 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); } } this.deferredImportSelectorHandler.process(); } protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException { processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER); } protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException { if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { return; } ConfigurationClass existingClass = this.configurationClasses.get(configClass); if (existingClass != null) { if (configClass.isImported()) { if (existingClass.isImported()) { existingClass.mergeImportedBy(configClass); } // Otherwise ignore new imported config class; existing non-imported class overrides it. return; } else { // Explicit bean definition found, probably replacing an import. // Let's remove the old one and go with the new one. this.configurationClasses.remove(configClass); this.knownSuperclasses.values().removeIf(configClass::equals); } } // Recursively process the configuration class and its superclass hierarchy. SourceClass sourceClass = asSourceClass(configClass, filter); do { sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter); } while (sourceClass != null); this.configurationClasses.put(configClass, configClass); } protected final SourceClass doProcessConfigurationClass( ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException { if (configClass.getMetadata().isAnnotated(Component.class.getName())) { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass, filter); } // 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.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // Process any @ComponentScan annotations // 對啟動類下的所有 @ComponentScan 進行解析載入,包含(@RestController @Service等) 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), filter, 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; }
通過getImport(sourceClass) 解析啟動類上的註解,獲取到其中被@Import註解的類,即AutoConfigurationPackages、AutoConfigurationImportSelector
啟動類上@SpringBootApplication註解為組合註解
@SpringBootConfiguration:其實質是一個 @Configuration 註解,表明該類是一個配置類
@EnableAutoConfiguration:開啟了自動配置功能
@AutoConfigurationPackage:被該註解標註的類即主配置類,將主配置類所在的包當作base-package
@ComponentScan:直接向容器中注入指定的元件
在解析@Import註解時,會有一個getImports()方法,從啟動類開始遞迴解析註解,把所有包含@Import的註解都解析到,然後再processImport()方法中對@Import註解的類進行分類,此處主要識別的是AutoConfigurationImportSelector 歸屬於ImportSelector的子類,在後續的過程中會呼叫 DeferredImprotSelectorHandler中的process()方法,來完成EnableAutoConfiguration的載入。
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException { Set<SourceClass> imports = new LinkedHashSet<>(); Set<SourceClass> visited = new LinkedHashSet<>(); collectImports(sourceClass, imports, visited); return imports; } private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException { if (visited.add(sourceClass)) { for (SourceClass annotation : sourceClass.getAnnotations()) { String annName = annotation.getMetadata().getClassName(); if (!annName.equals(Import.class.getName())) { collectImports(annotation, imports, visited); } } imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value")); } }
執行this.deferredImportSelectorHandler.process()方法進行實現自動裝配
public void process() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; try { if (deferredImports != null) { DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler(); deferredImports.sort(DEFERRED_IMPORT_COMPARATOR); deferredImports.forEach(handler::register); handler.processGroupImports(); } } finally { this.deferredImportSelectors = new ArrayList<>(); } } // ConfigurationClassParser public void processGroupImports() { for (DeferredImportSelectorGrouping grouping : this.groupings.values()) { Predicate<String> exclusionFilter = grouping.getCandidateFilter(); grouping.getImports().forEach(entry -> { ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata()); try { // 處理配置類上的註解 processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter), Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)), exclusionFilter, false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", ex); } }); } } // DeferredImportSelectorGrouping public Iterable<Group.Entry> getImports() { for (DeferredImportSelectorHolder deferredImport : this.deferredImports) { // 遍歷DeferredImportSelectorHolder物件集合deferredImports,deferrdImports集合裝了各種ImportSelector(AutoConfigurationImportSelect) this.group.process(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getImportSelector()); } // 經過上面處理,然後再進行選擇匯入哪寫配置類 return this.group.selectImports(); } //AutoConfigurationImportSelector public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) { Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName())); // 獲取自動配置類放入 AutoConfigurationEntry 物件中 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(annotationMetadata); // 將封裝了自動配置類的 AutoConfigurationEntry 物件裝進 autoConfigurationEntries 集合 this.autoConfigurationEntries.add(autoConfigurationEntry); // 遍歷剛獲取的自動配置類 for (String importClassName : autoConfigurationEntry.getConfigurations()) { // 將符合條件的自動配置類作為 key,annotationMetadata作為值放進 entries 集合中 this.entries.putIfAbsent(importClassName, annotationMetadata); } } // AutoConfigurationImportSelector public Iterable<Entry> selectImports() { if (this.autoConfigurationEntries.isEmpty()) { return Collections.emptyList(); } .getAutoConfigurationEntry(annotationMetadata); // 得到所有要排除的自動配置類集合 Set<String> allExclusions = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet()); .getAutoConfigurationEntry(annotationMetadata); // 得到經過過濾後所有符合條件的自動配置類集合 Set<String> processedConfigurations = this.autoConfigurationEntries.stream() .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream) .collect(Collectors.toCollection(LinkedHashSet::new)); .getAutoConfigurationEntry(annotationMetadata); // 移除需要排除的自動配置類 processedConfigurations.removeAll(allExclusions); .getAutoConfigurationEntry(annotationMetadata); // 對標註有 @Order註解的自動配置類進行排序 return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream() .map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName)) .collect(Collectors.toList()); } private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, 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) { if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); Predicate<String> selectorFilter = selector.getExclusionFilter(); if (selectorFilter != null) { exclusionFilter = exclusionFilter.or(selectorFilter); } if (selector instanceof DeferredImportSelector) { this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter); processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, 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 = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // 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), exclusionFilter); } } } 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(); } } }
執行 this.reader.loadBeanDefinitions(configClasses) 對自動配置類進行生效,生成Bean物件。
自動裝配原理總結:
1、當啟動SpringBoot應用程式時,會建立 SpringApplication 物件,在物件的構造方法中進行某些引數的初始化工作,最主要的是判斷當前應用程式的型別及初始化器和監聽器,在這個過程中會載入整個應用程式的 META-INF/spring.factories 檔案,將檔案的內容儲存到快取中(Map<ClassLoader, Map<String, List<String>>> cache ),方便後續獲取。
2、SpringApplication物件建立完成後,開始執行run() 方法來完成整個啟動。啟動過程中最主要的是有兩個方法:prepareContext()、refreshContext(),在這兩個方法中完成了自動裝配的核心功能。在其之前的處理邏輯中包含了上下文物件的建立,banner的列印等各個準備工作。
3、在prepareContext()方法中主要完成的是對上下文物件的初始化操作,包含了屬性值的設定(比如環境物件)。在整個過程中load()方法完成將當前啟動類作為一個BeanDefinition註冊到registry中,方便後續在進行BeanFactory呼叫執行時找到對應的主類,來完成對 @SpringBootApplication @EnableAutoConfiguration等註解的解析工作。
4、在refreshContext()方法中會進行整個容器的重新整理過程,會呼叫spring中的refresh()方法。refresh()中有13個關鍵方法,在自動裝配過程中,會呼叫invokeBeanFactoryPostProcessors()方法主要是對 ConfigurationClassPostProcessor 類的處理,這是BeanDefinitionRegistryPostProcessor的子類,BeanDefinitionRegistryPostProcessor 是BeanDefinitionRegistryPostProcessor 的子類,呼叫BeanDefinitionRegistryPostProcessor中的postProcessBeanDefinitionRegistry()方法,會解析@PropertySource @ComponentScans @ComponentScan @Bean @Import等註解。
5、在解析@Import註解時,會有一個getImports()方法,從啟動類開始遞迴解析註解,把所有包含@Import的註解都解析到,然後再processImport()方法中對@Import註解的類進行分類,此處主要識別的是AutoConfigurationImportSelector 歸屬於ImportSelector的子類,在後續的過程中會呼叫 DeferredImprotSelectorHandler中的process()方法,來完成EnableAutoConfiguration的載入。