啟動流程
圖如下:
以上流程圖源文件(可導入https://www.processon.com):https://github.com/Mysakura/DataFiles
相關Event(org.springframework.boot.context.event.SpringApplicationEvent的子類),這些Event是很好的標志,告訴我們程序執行到哪一步了,如下
ApplicationStartingEvent:在Environment和ApplicationContext可用之前 & 在ApplicationListener注冊之后發布。
ApplicationContextInitializedEvent:在bean定義加載之前 & ApplicationContextInitializers被調用之后 & ApplicationContext開始准備之后發布
ApplicationPreparedEvent:在ApplicationContext完全准備好並且沒有刷新之前發布,此時bean定義即將加載,Environment已經准備好被使用。
ApplicationStartedEvent:在ApplicationContext刷新之后,調用ApplicationRunner和CommandLineRunner之前發布
ApplicationReadyEvent:應用已經准備好接受請求時發布。
第一步,先進入啟動類
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
第二步,執行run方法,實際上執行的是【org.springframework.boot.SpringApplication#run(java.lang.Class<?>[], java.lang.String[])】
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { return run(new Class<?>[] { primarySource }, args); } public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { // 初始化SpringApplication,然后執行run方法 return new SpringApplication(primarySources).run(args); }
1. new SpringApplication【org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)】
public SpringApplication(Class<?>... primarySources) { this(null, primarySources); } // 初始化一些成員變量: public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); // 初始化primarySources this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 判斷當前應用是一個基於Servlet或者reactive的web應用還是一個非web應用 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 初始化一系列ApplicationContextInitializer setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 初始化一系列ApplicationListener,這些是針對SpringBoot事件的監聽器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 配置主要應用啟動類 this.mainApplicationClass = deduceMainApplicationClass(); }
2. run【org.springframework.boot.SpringApplication#run(java.lang.String...)】
public ConfigurableApplicationContext run(String... args) { // 一個計算耗時小工具:A StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); // 獲取監聽器,SpringApplicationRunListener的作用是發布SpringBoot運行期間的事件:B SpringApplicationRunListeners listeners = getRunListeners(args); // 監聽器發布事件:C listeners.starting(); try { // 創建默認應用參數 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 准備環境:D ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 處理要忽略的bean信息 configureIgnoreBeanInfo(environment); // 打印Banner Banner printedBanner = printBanner(environment); // 獲取應用上下文:E context = createApplicationContext(); // 獲取異常報告實例列表 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); // 准備上下文:F prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 刷新上下文:G refreshContext(context); // 留給子類實現,在刷新之后做一下額外的處理 afterRefresh(context, applicationArguments); // 計時器計時完畢 stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } // 發布ApplicationStartedEvent事件:H listeners.started(context); // 調用Runners:I callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { // 發布ApplicationReadyEvent事件:J listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
A:計算耗時小工具(運行如下測試代碼)
StopWatch stopWatch = new StopWatch("Test ABC"); stopWatch.start("Task A"); for (int i = 0; i < 10; i++){ } stopWatch.stop(); stopWatch.start("Task B"); for (int i = 0; i < 5; i++){ } stopWatch.stop(); stopWatch.start("Task C"); for (int i = 0; i < 15; i++){ } stopWatch.stop(); System.out.println(stopWatch.prettyPrint());
輸出:
B: 獲取監聽器*
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; // 返回一個SpringApplicationRunListener的集合包裝類 return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); } private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // 使用Set集合確保name是唯一的;調用SpringFactoriesLoader.loadFactoryNames,使用給定的類加載器加載給定類型工廠實現的完全限定類名 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 根據給的Class、類加載器、完全限定類型列表已經相關參數,根據反射創建實例列表 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; } @SuppressWarnings("unchecked") private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<>(names.size()); for (String name : names) { try { Class<?> instanceClass = ClassUtils.forName(name, classLoader); Assert.isAssignable(type, instanceClass); Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes); T instance = (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex); } } return instances; }
C:發布【ApplicationStartingEvent】事件
public void starting() { this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); }
D:准備環境*
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // 根據webApplicationType,決定創建StandardServletEnvironment還是StandardReactiveWebEnvironment還是StandardEnvironment ConfigurableEnvironment environment = getOrCreateEnvironment(); // 配置屬性文件和激活的環境(spring.profiles.active所配) configureEnvironment(environment, applicationArguments.getSourceArgs()); // 將ConfigurationPropertySource附加到指定環境下 ConfigurationPropertySources.attach(environment); // 發布ApplicationEnvironmentPreparedEvent事件 listeners.environmentPrepared(environment); // 綁定環境到應用 bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }
E:獲取應用上下文
// 根據應用類型創建不同的上下文 protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
F:准備上下文*
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 設置environment context.setEnvironment(environment); // 相關額外的處理 postProcessApplicationContext(context); applyInitializers(context); // 派發ApplicationContextInitializedEvent事件,表示應用正在啟動,上下文正在准備並且一系列Initializer已經調用 listeners.contextPrepared(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); beanFactory.registerSingleton("springApplicationArguments", applicationArguments); if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } 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])); // 監聽上下文,派發ApplicationPreparedEvent事件,表示應用正在啟動,上下文已經准備好刷新了 listeners.contextLoaded(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) { // 設置resourceLoader ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader); } if (context instanceof DefaultResourceLoader) { ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader()); } } if (this.addConversionService) { // 設置ConversionService context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance()); } }
G:刷新上下文(容器的初始化)【org.springframework.context.support.AbstractApplicationContext#refresh】*
private void refreshContext(ConfigurableApplicationContext context) { refresh(context); if (this.registerShutdownHook) { try { context.registerShutdownHook(); } catch (AccessControlException ex) { // Not allowed in some environments. } } } protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); } public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. // 為上下文刷新做准備 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. // 告訴子類刷新內部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. // 允許在上下文子類中對bean工廠進行后續處理 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. // 執行上下文中已注冊的bean工廠后置處理器 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 注冊攔截bean創建過程的后置處理器 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. // 初始化此上下文的消息源 initMessageSource(); // Initialize event multicaster for this context. // 初始化事件派發器 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // 初始化子類實現的其它特殊bean onRefresh(); // Check for listener beans and register them. // 檢查並注冊偵聽器bean registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // 實例化所有剩余的(非延遲初始化)單實例bean finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. // 最后,發布對應的事件 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(); } } }
H:發布ApplicationStartedEvent事件(listeners.started(context);)【org.springframework.boot.context.event.EventPublishingRunListener#started】
public void started(ConfigurableApplicationContext context) { context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context)); }
I:調用Runners
private void callRunners(ApplicationContext context, ApplicationArguments args) { List<Object> runners = new ArrayList<>(); // 獲取所有實現ApplicationRunner接口的子類 runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); // 獲取所有實現CommandLineRunner接口的子類 runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); AnnotationAwareOrderComparator.sort(runners); // 循環遍歷 for (Object runner : new LinkedHashSet<>(runners)) { // 如果是ApplicationRunner的實現類 if (runner instanceof ApplicationRunner) { callRunner((ApplicationRunner) runner, args); } // 如果是CommandLineRunner的實現類 if (runner instanceof CommandLineRunner) { callRunner((CommandLineRunner) runner, args); } } } private void callRunner(ApplicationRunner runner, ApplicationArguments args) { try { (runner).run(args); } catch (Exception ex) { throw new IllegalStateException("Failed to execute ApplicationRunner", ex); } } private void callRunner(CommandLineRunner runner, ApplicationArguments args) { try { (runner).run(args.getSourceArgs()); } catch (Exception ex) { throw new IllegalStateException("Failed to execute CommandLineRunner", ex); } }
那么這兩個類有啥作用呢
首先,SpringBoot並沒有默認的實現類,那么肯定是給我們實現的;然后這個方法的執行時機是在spring容器啟動完畢的時候,那么作用肯定是在容器啟動之后做一些其它自定義的處理。
這兩個接口都只有一個方法,就是run方法。類注解上寫的說明:
當SpringApplication中包含了該接口的實現類,在callRunners的時候調用其中的run方法;可以在同一個應用上下文定義多個bean,也可以通過實現Order接口或者使用@Order注解來排序。
這兩個類的唯一區別就是run方法的參數類型不同:
org.springframework.boot.CommandLineRunner#run(String... args)
org.springframework.boot.ApplicationRunner#run(ApplicationArguments args)
J:發布ApplicationReadyEvent事件(listeners.running(context);)【org.springframework.boot.context.event.EventPublishingRunListener#running】
public void running(ConfigurableApplicationContext context) { context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context)); }
到此一個大概的流程已經走完,而我還想看一下具體的東西。
--------------------------------------------------------------------------------------------------------------------------------------------------------
進一步深入
問題0:我看有好幾個地方都用到了同一個方法:org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // 加載工程名稱列表,通過Set集合保證唯一① Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 根據名稱,創建相關實例② List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); // 排序后返回 AnnotationAwareOrderComparator.sort(instances); return instances; }
來看①
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); } private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { // 查看緩存有么有 MultiValueMap<String, String> result = cache.get(classLoader); if (result != null) { return result; } try { // 獲取spring.factories資源路徑 Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>(); 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(); for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { // key為工廠類型接口名稱,值為一系列子類實現 result.add(factoryTypeName, factoryImplementationName.trim()); } } } // 放入緩存並返回 cache.put(classLoader, result); return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }
具體來看SpringBoot的spring.factories里面的內容:是一系列的組件以及具體的實現列表
通過把這些配置事先讀取並放進緩存,我們就可以隨時根據工廠接口類型獲取對應的子類名稱列表。
再來看②
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<>(names.size()); // 遍歷子類名稱,通過反射進行實例化 for (String name : names) { try { Class<?> instanceClass = ClassUtils.forName(name, classLoader); Assert.isAssignable(type, instanceClass); Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes); T instance = (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex); } } return instances; }
一句話作用:這個方法的作用就是找到spring.factories讀取一系列組件的名稱,通過傳入的Class類型獲取對應的子類名稱列表進行實例化並返回。
問題1:那一系列Initializer都有哪些,有什么作用【setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));】
0:報告常見的錯誤配置警告
1:配置ApplicationContext ID
2:執行環境屬性【context.initializer.classes】指定的初始化器,也就是給用戶一個機會去指定自己實現的ApplicationContextInitializer從而對應用程序做一些初始化工作
3:將RSocketServer實際監聽的端口寫入Environment環境屬性中。這樣屬性local.rsocket.server.port就可以直接通過@Value注入到測試中,或者通過Environment獲取。
4:將WebServer實際監聽的端口寫入Environment環境屬性中。這樣屬性local.server.port就可以直接通過@Value注入到測試中,或者通過Environment獲取。
5:創建一個ConfigurationClassPostProcessor 和 Spring Boot共用的CachingMetadataReaderFactory對象
6:將ConditionEvaluationReport寫入日志。
問題2:那一系列Listeners有哪些,有什么作用【setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));】
0:一旦裝載了上下文,就清空緩存。
1:在其父應用程序上下文關閉時關閉該應用程序上下文
2:如果系統文件編碼與environment里設置的不一致,則停止啟動應用程序。默認情況下么有影響,別手賤亂設置。
3:根據屬性{spring.output.ansi.enabled}的值配置{AnsiOutput}
4:通過讀取已知位置屬性文件里的屬性來配置上下文的environment,默認加載application.properties或者application.yml里的配置。
5:執行配置在context.listener.classes環境變量里的Listener
6:通過在{DEBUG}級別記錄線程上下文類加載器(TCCL)的類路徑來對ApplicationEnvironmentPreparedEvent和ApplicationFailedEvent事件做出反應
7:一個配置{LoggingSystem}的ApplicationListener。如果環境包含{logging.config}屬性,它將用於引導日志系統,否則將使用默認配置。無論如何,如果環境包含{logging.level},那么日志級別將被定制。
8:將liquibase {ServiceLocator}替換成和SpringBoot可執行歸檔一起工作的版本。
9:在耗時任務的后台線程中觸發早期初始化
問題3:SpringApplicationRunListeners listeners = getRunListeners(args);怎么又出來一個listeners?
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; // 可以看出,通過getSpringFactoriesInstances讀取對應的names並實例化返回,然后封裝在SpringApplicationRunListeners return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)); }
在這里實例化的是:
問題4:listeners.starting();是啟動監聽器嗎?
void starting() { // 遍歷內部的listener,執行starting方法 for (SpringApplicationRunListener listener : this.listeners) { listener.starting(); } } // starting方法,實際上是廣播ApplicationStartingEvent事件 public void starting() { this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); }
廣播事件,有哪些收聽者呢?
public void multicastEvent(ApplicationEvent event) { multicastEvent(event, resolveDefaultEventType(event)); } @Override public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); // 典型的觀察者模式 for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { invokeListener(listener, event); } } }
收聽者就是我們之前第一步實例化的listener
問題5:Bean在哪里實例化的
先創建bean定義
- 進入org.springframework.boot.SpringApplication#run(java.lang.String...)
- 進入refreshContext(context);方法
- 最終進入org.springframework.context.support.AbstractApplicationContext#refresh
- 進入invokeBeanFactoryPostProcessors(beanFactory);
- 進入PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
- 進入invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
- 里面是一個循環,進入postProcessor.postProcessBeanDefinitionRegistry(registry);
- 進入processConfigBeanDefinitions(registry);
- 進入parser.parse(candidates);
- 里面是一個遍歷BeanDefinitionHolder的過程,獲取BeanDefinition。根據BeanDefinition實現的接口執行不同的方法,但是最終都進入org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass
- 進入sourceClass = doProcessConfigurationClass(configClass, sourceClass);
到此慢慢接近了真相
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { if (configClass.getMetadata().isAnnotated(Component.class.getName())) { // Recursively process any member (nested) classes first processMemberClasses(configClass, sourceClass); } // 處理@PropertySource標記的類 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"); } } // 處理@ComponentScan標記的類 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) { // 立即執行掃描 A Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // 檢查已掃描的定義集合以獲得更多的配置類,並在需要時進行遞歸解析 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()); } } } } // 處理@Import標記的類 processImports(configClass, sourceClass, getImports(sourceClass), true); // 處理@ImportResource標記的類 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); } } // 處理單個@Bean標記的方法 Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } // 處理接口里的默認方法 processInterfaces(configClass, sourceClass); // 處理父類, 如果有的話 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(); } } // 沒有父類,處理完成 return null; }
我們來看一下掃描過程,進入注釋A的那段代碼:this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
這個方法主要讀取相關的屬性,最后的方法是處理過程。其中一段代碼,判斷basePackages是否為空,如果為空,則默認掃描啟動類所在的包
現在進入最后的doScan方法。
protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>(); for (String basePackage : basePackages) { // 具體掃描包,組裝成BeanDefinition返回 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); for (BeanDefinition candidate : candidates) { ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } if (checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); // 注冊bean定義,也就是注冊到beanFactory里(this.registry的類型是org.springframework.beans.factory.support.DefaultListableBeanFactory) registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }
進入注冊bean的方法(最終進入org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition)
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // 在主名稱下注冊bean定義 String beanName = definitionHolder.getBeanName(); // 具體注冊方法 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // 如果有的話,為bean名稱注冊別名 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
進入具體注冊方法(org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition)
實際上是把bean定義放進了一個Map里面。到此為止,bean定義已經注冊到beanFactory里了。但是這個時候還沒有實例化,僅僅是拿到了bean定義。
實例化
剛才我們走的是invokeBeanFactoryPostProcessors(beanFactory);,現在走 finishBeanFactoryInitialization(beanFactory);
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // 為上下文初始化conversion service if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } // 如果之前沒有任何bean后置處理器(例如PropertyPlaceholderConfigurer bean)注冊,則注冊一個默認的嵌入式值解析器 // 此時,主要用於解析注解屬性值。 if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } // 盡早初始化LoadTimeWeaverAware bean,以便盡早注冊它們的轉換器 String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } // 停止使用臨時類加載器進行類型匹配。 beanFactory.setTempClassLoader(null); // 允許緩存所有的bean定義元數據,不希望有進一步的更改。 beanFactory.freezeConfiguration(); // 實例化所有剩余的(非懶加載)單例。 beanFactory.preInstantiateSingletons(); }
進入最后一行
public void preInstantiateSingletons() throws BeansException { if (logger.isTraceEnabled()) { logger.trace("Pre-instantiating singletons in " + this); } // 遍歷一個副本以允許init方法,而init方法反過來注冊新的bean定義。 // 雖然這可能不是常規的工廠引導的一部分,但它在其他方面也可以正常工作。 List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // 觸發所有非懶加載bean的初始化 for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); if (bean instanceof FactoryBean) { final FactoryBean<?> factory = (FactoryBean<?>) bean; boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } } else { // 實例化bean,實際進入的是org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean方法,里面包含了具體實例化的過程 getBean(beanName); } } } // 為所有適用的bean觸發初始化后回調 for (String beanName : beanNames) { Object singletonInstance = getSingleton(beanName); if (singletonInstance instanceof SmartInitializingSingleton) { final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { smartSingleton.afterSingletonsInstantiated(); return null; }, getAccessControlContext()); } else { smartSingleton.afterSingletonsInstantiated(); } } } }
最后看一下具體實例化的過程【org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean】
// Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
進入createBean【org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])】
try { Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { // A previously detected exception with proper bean creation context already, // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry. throw ex; } catch (Throwable ex) { throw new BeanCreationException( mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex); }
進入doCreateBean【org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean】
// spring把實例化的類都放在了包裝類里 BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; }
進入createBeanInstance【org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance】
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 確保此時bean類已經被解析。 Class<?> beanClass = resolveBeanClass(mbd, beanName); if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); } Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // Shortcut when re-creating the same bean... boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { return autowireConstructor(beanName, mbd, null, null); } else { return instantiateBean(beanName, mbd); } } // 為自動裝配准備的候選構造函數 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // 為默認構造函數准備的首選構造函數 ctors = mbd.getPreferredConstructors(); if (ctors != null) { return autowireConstructor(beanName, mbd, ctors, null); } // 不需要特殊處理:只需使用無參構造函數。 return instantiateBean(beanName, mbd); }
因為本例只有一個Controller,所以運行到了最后一行:
進入instantiateBean【org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#instantiateBean】
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { try { Object beanInstance; final BeanFactory parent = this; if (System.getSecurityManager() != null) { beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, parent), getAccessControlContext()); } else { // 獲取instantiationStrategy策略,並調用instanttiate方法進行實例化 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent); } // 包裝 BeanWrapper bw = new BeanWrapperImpl(beanInstance); initBeanWrapper(bw); return bw; } catch (Throwable ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex); } }
進入instantiate【org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)】
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. if (!bd.hasMethodOverrides()) { Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) { constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; if (constructorToUse == null) { // 獲取Class final Class<?> clazz = bd.getBeanClass(); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { if (System.getSecurityManager() != null) { constructorToUse = AccessController.doPrivileged( (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor); } else { // 獲取已聲明的構造方法 constructorToUse = clazz.getDeclaredConstructor(); } bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } // 通過工具類實例化 return BeanUtils.instantiateClass(constructorToUse); } else { // Must generate CGLIB subclass. return instantiateWithMethodInjection(bd, beanName, owner); } }
最后一步,看下如何實例化的【org.springframework.beans.BeanUtils#instantiateClass(java.lang.reflect.Constructor<T>, java.lang.Object...)】
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException { Assert.notNull(ctor, "Constructor must not be null"); try { // 反射工具類:使構造方法可訪問 ReflectionUtils.makeAccessible(ctor); if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { return KotlinDelegate.instantiateClass(ctor, args); } else { // 獲取參數類型列表 Class<?>[] parameterTypes = ctor.getParameterTypes(); Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters"); Object[] argsWithDefaultValues = new Object[args.length]; for (int i = 0 ; i < args.length; i++) { if (args[i] == null) { Class<?> parameterType = parameterTypes[i]; argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null); } else { argsWithDefaultValues[i] = args[i]; } } // 很熟悉的反射代碼【java.lang.reflect.Constructor#newInstance】 return ctor.newInstance(argsWithDefaultValues); } } catch (InstantiationException ex) { throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex); } catch (IllegalAccessException ex) { throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex); } catch (IllegalArgumentException ex) { throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex); } catch (InvocationTargetException ex) { throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException()); } }
總結:
// 在刷新上下文方法里 org.springframework.context.support.AbstractApplicationContext#refresh // 獲取並注冊bean定義(包含了注解掃描等過程) postProcessBeanFactory(beanFactory); // 實例化所有非懶加載的bean(本質用了反射實現了實例化bean) finishBeanFactoryInitialization(beanFactory);