一、SpringApplication類初始化過程
SpringBoot項目的main函數
常規的這個主類如下圖所示,我們一般會這樣去寫。
在這個類中需要關注的是:
- @SpringBootApplication
- SpringApplication.run()
關於 @SpringBootApplication 注解,在后面分析SpringBoot自動裝配的章節會展開去分析。
本章節中我們需要關注的就是 SpringApplication.run() 方法。
查看run()方法的實現,如下面代碼所示,我們發現其首先是創建了 SpringApplication 的實例,然后調用了 SpringApplication 的run()方法,那本章我們關注的就是 SpringApplication 創建實例的過程。
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); }
SpringApplication() 構造方法
繼續查看源碼, SpringApplication 實例化過程,首先是進入構造方法,最終回來到兩個參數的構造方法。
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.addConversionService = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = new HashSet(); this.isCustomEnvironment = false; this.lazyInitialization = false; this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); //推斷應用類型,后面會根據類型初始化對應的環境。常用的一般都是servlet環境 this.webApplicationType = WebApplicationType.deduceFromClasspath(); //初始化classpath下 META-INF/spring.factories中已配置的ApplicationContextInitializer this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); //初始化classpath下所有已配置的 ApplicationListener this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); //根據調用棧,推斷出 main 方法的類名 this.mainApplicationClass = this.deduceMainApplicationClass(); }
WebApplicationType.deduceFromClasspath();該方法推斷應用的類型。 SERVLET REACTIVE NONE
public enum WebApplicationType { NONE, SERVLET, REACTIVE; // 常量值 private static final String[] SERVLET_INDICATOR_CLASSES = new String[]{"javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext"}; private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet"; private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler"; private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer"; private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext"; private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext"; private WebApplicationType() { } /** * 判斷 應用的類型 * NONE: 應用程序不是web應用,也不應該用web服務器去啟動 * SERVLET: 應用程序應作為基於servlet的web應用程序運行,並應啟動嵌入式servlet web(tomcat)服務器。 * REACTIVE: 應用程序應作為 reactive web應用程序運行,並應啟動嵌入式 reactive web服務器。 * @return */ static WebApplicationType deduceFromClasspath() { //classpath下必須存在org.springframework.web.reactive.DispatcherHandler if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) { return REACTIVE; } else { String[] var0 = SERVLET_INDICATOR_CLASSES; int var1 = var0.length; for(int var2 = 0; var2 < var1; ++var2) { String className = var0[var2]; if (!ClassUtils.isPresent(className, (ClassLoader)null)) { return NONE; } } //classpath環境下存在javax.servlet.Servlet或者org.springframework.web.context.ConfigurableWebApplicationContext return SERVLET; } } static WebApplicationType deduceFromApplicationContext(Class<?> applicationContextClass) { if (isAssignable("org.springframework.web.context.WebApplicationContext", applicationContextClass)) { return SERVLET; } else { return isAssignable("org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext", applicationContextClass) ? REACTIVE : NONE; } } private static boolean isAssignable(String target, Class<?> type) { try { return ClassUtils.resolveClassName(target, (ClassLoader)null).isAssignableFrom(type); } catch (Throwable var3) { return false; } } }
返回類型是WebApplicationType的枚舉類型, WebApplicationType 有三個枚舉,三個枚舉的解釋如下:
- WebApplicationType.REACTIVE classpath下存在org.springframework.web.reactive.DispatcherHandler
- WebApplicationType.SERVLET classpath下存在javax.servlet.Servlet或者org.springframework.web.context.ConfigurableWebApplicationContext
- WebApplicationType.NONE 不滿足以上條件。
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
初始化classpath下 META-INF/spring.factories中已配置的ApplicationContextInitializer。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) { return this.getSpringFactoriesInstances(type, new Class[0]); } /** * 通過指定的classloader 從META-INF/spring.factories獲取指定的Spring的工廠實例 * @param type * @param parameterTypes * @param args * @param <T> * @return */ private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = this.getClassLoader(); //通過指定的classLoader從 META-INF/spring.factories 的資源文件中, //讀取 key 為 type.getName() 的 value Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); //創建Spring工廠實例 List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); //對Spring工廠實例排序(org.springframework.core.annotation.Order注解指定的順序) AnnotationAwareOrderComparator.sort(instances); return instances; }
看看 getSpringFactoriesInstances 都干了什么,看源碼,有一個方法很重要 loadFactoryNames() 這個方法很重要,它是spring-core中提供的從META-INF/spring.factories中獲取指定的類(key)的同一入口方法。
在這里,獲取的是key為 org.springframework.context.ApplicationContextInitializer 的類。
ApplicationContextInitializer 是Spring框架的類, 這個類的主要目的就是在ConfigurableApplicationContext調用refresh()方法之前,回調這個類的initialize方法。通過ConfigurableApplicationContext 的實例獲取容器的環境Environment,從而實現對配置文件的修改完善等工作。
setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
初始化classpath下 META-INF/spring.factories中已配置的 ApplicationListener。
ApplicationListener 的加載過程和上面的 ApplicationContextInitializer 類的加載過程是一樣的。不多說了,至於 ApplicationListener 是spring的事件監聽器,典型的觀察者模式,通過 ApplicationEvent 類和 ApplicationListener 接口,可以實現對spring容器全生命周期的監聽,當然也可以自定義監聽事件。
二、SpringApplication的run方法
run方法的源碼
/** * 運行spring應用,並刷新一個新的 ApplicationContext(Spring的上下文) * ConfigurableApplicationContext 是 ApplicationContext 接口的子接口。在 ApplicationContext * 基礎上增加了配置上下文的工具。 ConfigurableApplicationContext是容器的高級接口 */ public ConfigurableApplicationContext run(String... args) { //記錄程序運行時間 StopWatch stopWatch = new StopWatch(); stopWatch.start(); // ConfigurableApplicationContext Spring 的上下文 ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); //從META-INF/spring.factories中獲取監聽器 //1、獲取並啟動監聽器 SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //2、構造應用上下文環境 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); //處理需要忽略的Bean this.configureIgnoreBeanInfo(environment); //打印banner Banner printedBanner = this.printBanner(environment); //3、初始化應用上下文 context = this.createApplicationContext(); //實例化SpringBootExceptionReporter.class,用來支持報告關於啟動的錯誤 exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); //4、刷新應用上下文前的准備階段 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); //5、刷新應用上下文 this.refreshContext(context); //刷新應用上下文后的擴展接口 this.afterRefresh(context, applicationArguments); //時間記錄停止 stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } //發布容器啟動完成事件 listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }
具體的每一行代碼的含義請看注釋,我們在這先總結一下啟動過程中的重要步驟:
第一步:獲取並啟動監聽器 第二步:構造應用上下文環境 第三步:初始化應用上下文 第四步:刷新應用上下文前的准備階段 第五步:刷新應用上下文 第六步:刷新應用上下文后的擴展接口
OK,下面SpringBoot的啟動流程分析,我們就根據這6大步驟進行詳細解讀。最重要的是第四,五步。我們會着重的分析。
第一步:獲取並啟動監聽器
事件機制在Spring是很重要的一部分內容,通過事件機制我們可以監聽Spring容器中正在發生的一些事件,同樣也可以自定義監聽事件。Spring的事件為Bean和Bean之間的消息傳遞提供支持。當一個對象處理完某種任務后,通知另外的對象進行某些處理,常用的場景有進行某些操作后發送通知,消息、郵件等情況。
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class}; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); }
在這里面是不是看到一個熟悉的方法:getSpringFactoriesInstances(),可以看下下面的注釋,前面我們已經詳細介紹過該方法是怎么一步步的獲取到META-INF/spring.factories中的指定的key的value,獲取到以后怎么實例化類的。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = this.getClassLoader(); //通過指定的classLoader從 META-INF/spring.factories 的資源文件中, //讀取 key 為 type.getName() 的 value Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); //創建Spring工廠實例 List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); //對Spring工廠實例排序(org.springframework.core.annotation.Order注解指定的順序) AnnotationAwareOrderComparator.sort(instances); return instances; }
回到run方法,debug這個代碼 SpringApplicationRunListeners listeners = getRunListeners(args); 獲取的是EventPublishingRunListener監聽器:
EventPublishingRunListener監聽器是Spring容器的啟動監聽器。
listeners.starting(); 開啟了監聽事件。
第二步:構造應用上下文環境
應用上下文環境包括什么呢?包括計算機的環境,Java環境,Spring的運行環境,Spring項目的配置(在SpringBoot中就是那個熟悉的application.properties/yml)等等。
首先看一下prepareEnvironment()方法。
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { //創建並配置相應的環境 ConfigurableEnvironment environment = this.getOrCreateEnvironment(); //根據用戶配置,配置 environment系統環境 this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach((Environment)environment); // 啟動相應的監聽器,其中一個重要的監聽器 ConfigFileApplicationListener 就是加載項目配置文件的監聽器。 listeners.environmentPrepared((ConfigurableEnvironment)environment); this.bindToSpringApplication((ConfigurableEnvironment)environment); if (!this.isCustomEnvironment) { environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass()); } ConfigurationPropertySources.attach((Environment)environment); return (ConfigurableEnvironment)environment; }
看上面的注釋,方法中主要完成的工作,首先是創建並按照相應的應用類型配置相應的環境,然后根據用戶的配置,配置系統環境,然后啟動監聽器,並加載系統配置文件。
ConfigurableEnvironment environment = getOrCreateEnvironment();
private ConfigurableEnvironment getOrCreateEnvironment() { if (this.environment != null) { return this.environment; } else { switch(this.webApplicationType) { case SERVLET: //如果應用類型是 SERVLET 則實例化 StandardServletEnvironment return new StandardServletEnvironment(); case REACTIVE: return new StandardReactiveWebEnvironment(); default: return new StandardEnvironment(); } } }
通過代碼可以看到根據不同的應用類型初始化不同的系統環境實例。前面咱們已經說過應用類型是怎么判斷的了,這里就不在贅述了。
從上面的繼承關系可以看出,StandardServletEnvironment是StandardEnvironment的子類。當是web項目的時候,環境上會多一些關於web環境的配置。
configureEnvironment(environment, applicationArguments.getSourceArgs());
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { if (this.addConversionService) { ConversionService conversionService = ApplicationConversionService.getSharedInstance(); environment.setConversionService((ConfigurableConversionService)conversionService); } // 將main 函數的args封裝成 SimpleCommandLinePropertySource 加入環境中。 this.configurePropertySources(environment, args); // 激活相應的配置文件 this.configureProfiles(environment, args); }
在configurePropertySources(environment, args);中將args封裝成了SimpleCommandLinePropertySource並加入到了environment中。
configureProfiles(environment, args);根據啟動參數激活了相應的配置文件。
listeners.environmentPrepared(environment);
進入到方法一路跟下去就到了SimpleApplicationEventMulticaster類的multicastEvent()方法。
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event); Executor executor = this.getTaskExecutor(); Iterator var5 = this.getApplicationListeners(event, type).iterator(); while(var5.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var5.next(); if (executor != null) { executor.execute(() -> { this.invokeListener(listener, event); }); } else { this.invokeListener(listener, event); } } }
查看getApplicationListeners(event, type)執行結果,發現一個重要的監聽器ConfigFileApplicationListener。
先看看這個類的注釋:
/** * {@link EnvironmentPostProcessor} that configures the context environment by loading * properties from well known file locations. By default properties will be loaded from * 'application.properties' and/or 'application.yml' files in the following locations: * <ul> * <li>classpath:</li> * <li>file:./</li> * <li>classpath:config/</li> * <li>file:./config/:</li> * </ul> * <p> * Alternative search locations and names can be specified using * {@link #setSearchLocations(String)} and {@link #setSearchNames(String)}. * <p> * Additional files will also be loaded based on active profiles. For example if a 'web' * profile is active 'application-web.properties' and 'application-web.yml' will be * considered. * <p> * The 'spring.config.name' property can be used to specify an alternative name to load * and the 'spring.config.location' property can be used to specify alternative search * locations or specific files. * <p> * 從默認的位置加載配置文件,並將其加入 上下文的 environment變量中 */
這個監聽器默認的從注釋中<ul>標簽所示的幾個位置加載配置文件,並將其加入 上下文的 environment變量中。當然也可以通過配置指定。
第三步:初始化應用上下文
在SpringBoot工程中,應用類型分為三種,如下代碼所示。
public enum WebApplicationType { /** * 應用程序不是web應用,也不應該用web服務器去啟動 */ NONE, /** * 應用程序應作為基於servlet的web應用程序運行,並應啟動嵌入式servlet web(tomcat)服務器。 */ SERVLET, /** * 應用程序應作為 reactive web應用程序運行,並應啟動嵌入式 reactive web服務器。 */ REACTIVE }
對應三種應用類型,SpringBoot項目有三種對應的應用上下文,我們以web工程為例,即其上下文為AnnotationConfigServletWebServerApplicationContext。
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch(this.webApplicationType) { case SERVLET: contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext"); break; case REACTIVE: contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext"); break; default: contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext"); } } catch (ClassNotFoundException var3) { throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3); } } return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass); }
我們先看一下AnnotationConfigServletWebServerApplicationContext的設計。
應用上下文可以理解成IoC容器的高級表現形式,應用上下文確實是在IoC容器的基礎上豐富了一些高級功能。
應用上下文對IoC容器是持有的關系。它的一個屬性beanFactory就是IoC容器(DefaultListableBeanFactory)。所以它們之間是持有,和擴展的關系。
接下來看GenericApplicationContext類
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { private final DefaultListableBeanFactory beanFactory; ... public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); } ... }
beanFactory正是在AnnotationConfigServletWebServerApplicationContext實現的接口GenericApplicationContext中定義的。在上面createApplicationContext()方法中的, BeanUtils.instantiateClass(contextClass) 這個方法中,不但初始化了AnnotationConfigServletWebServerApplicationContext類,也就是我們的上下文context,同樣也觸發了GenericApplicationContext類的構造函數,從而IoC容器也創建了。仔細看他的構造函數,有沒有發現一個很熟悉的類DefaultListableBeanFactory,沒錯,DefaultListableBeanFactory就是IoC容器真實面目了。在后面的refresh()方法分析中,DefaultListableBeanFactory是無處不在的存在感。
第四步 刷新應用上下文前的准備階段
prepareContext()方法
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { //設置容器環境 context.setEnvironment(environment); //執行容器后置處理 this.postProcessApplicationContext(context); //執行容器中的 ApplicationContextInitializer 包括spring.factories和通過三種方式自定義的 this.applyInitializers(context); //向各個監聽器發送容器已經准備好的事件 listeners.contextPrepared(context); if (this.logStartupInfo) { this.logStartupInfo(context.getParent() == null); this.logStartupProfileInfo(context); } ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); //將main函數中的args參數封裝成單例Bean,注冊進容器 beanFactory.registerSingleton("springApplicationArguments", applicationArguments); //將 printedBanner 也封裝成單例,注冊進容器 if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } Set<Object> sources = this.getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); //加載我們的啟動類,將啟動類注入容器 this.load(context, sources.toArray(new Object[0])); //發布容器已加載事件 listeners.contextLoaded(context); }
首先看這行 Set<Object> sources = getAllSources(); 在getAllSources()中拿到了我們的啟動類。
我們重點講解這行 load(context, sources.toArray(new Object[0]));
跟進load()方法,看源碼:
protected void load(ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } //創建 BeanDefinitionLoader BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.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(); }
1、getBeanDefinitionRegistry()
繼續看getBeanDefinitionRegistry()方法的源碼
private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) { if (context instanceof BeanDefinitionRegistry) { return (BeanDefinitionRegistry)context; } else if (context instanceof AbstractApplicationContext) { return (BeanDefinitionRegistry)((AbstractApplicationContext)context).getBeanFactory(); } else { throw new IllegalStateException("Could not locate BeanDefinitionRegistry"); } }
這里將我們前文創建的上下文強轉為BeanDefinitionRegistry,是不是很熟悉。BeanDefinitionRegistry定義了很重要的方法registerBeanDefinition(),該方法將BeanDefinition注冊進DefaultListableBeanFactory容器的beanDefinitionMap中。
2、createBeanDefinitionLoader()
繼續看createBeanDefinitionLoader()方法,最終進入了BeanDefinitionLoader類的構造方法,如下
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定義讀取器 比如:@Configuration @Bean @Component @Controller @Service等等 this.annotatedReader = new AnnotatedBeanDefinitionReader(registry); //XML形式的Bean定義讀取器 this.xmlReader = new XmlBeanDefinitionReader(registry); if (this.isGroovyPresent()) { this.groovyReader = new GroovyBeanDefinitionReader(registry); } //類路徑掃描器 this.scanner = new ClassPathBeanDefinitionScanner(registry); //掃描器添加排除過濾器 this.scanner.addExcludeFilter(new BeanDefinitionLoader.ClassExcludeFilter(sources)); }
前面的文章,我們說過,IoC容器的初始化分為三個步驟,上面三個屬性在,BeanDefinition的Resource定位,和BeanDefinition的注冊中起到了很重要的作用。
3、loader.load();
跟進load()方法
private int load(Object source) { Assert.notNull(source, "Source must not be null"); if (source instanceof Class) { // 從Class加載 return this.load((Class)source); } else if (source instanceof Resource) { // 從Resource加載 return this.load((Resource)source); } else if (source instanceof Package) { // 從Package加載 return this.load((Package)source); } else if (source instanceof CharSequence) { // 從 CharSequence 加載 return this.load((CharSequence)source); } else { throw new IllegalArgumentException("Invalid source type " + source.getClass()); } }
當前我們的主類會按Class加載。
繼續跟進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); } if (this.isEligible(source)) { //將 啟動類的 BeanDefinition注冊進 beanDefinitionMap this.annotatedReader.register(new Class[]{source}); return 1; } else { return 0; } }
isComponent(source)判斷主類是不是存在@Component注解,主類@SpringBootApplication是一個組合注解,包含@Component。
this.annotatedReader.register(source);跟進register()方法,最終進到AnnotatedBeanDefinitionReader類的doRegisterBean()方法。
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name, @Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier, @Nullable BeanDefinitionCustomizer[] customizers) { //將指定的類 封裝為AnnotatedGenericBeanDefinition AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); if (!this.conditionEvaluator.shouldSkip(abd.getMetadata())) { abd.setInstanceSupplier(supplier); // 獲取該類的 scope 屬性 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); String beanName = name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry); AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); int var10; int var11; if (qualifiers != null) { Class[] var9 = qualifiers; var10 = qualifiers.length; for(var11 = 0; var11 < var10; ++var11) { Class<? extends Annotation> qualifier = var9[var11]; if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } if (customizers != null) { BeanDefinitionCustomizer[] var13 = customizers; var10 = customizers.length; for(var11 = 0; var11 < var10; ++var11) { BeanDefinitionCustomizer customizer = var13[var11]; customizer.customize(abd); } } BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); // 將該BeanDefinition注冊到IoC容器的beanDefinitionMap中 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); } }
在該方法中將主類封裝成AnnotatedGenericBeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);方法將BeanDefinition注冊進beanDefinitionMap
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // 注冊別名 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { String[] var4 = aliases; int var5 = aliases.length; for(int var6 = 0; var6 < var5; ++var6) { String alias = var4[var6]; registry.registerAlias(beanName, alias); } } }
繼續跟進registerBeanDefinition()方法。
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { // 最后一次校驗了 // 對bean的Overrides進行校驗,還不知道會在哪處理這些overrides ((AbstractBeanDefinition)beanDefinition).validate(); } catch (BeanDefinitionValidationException var8) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var8); } } // 判斷是否存在重復名字的bean,之后看允不允許override // 以前使用synchronized實現互斥訪問,現在采用ConcurrentHashMap BeanDefinition existingDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName); if (existingDefinition != null) { //如果該類不允許 Overriding 直接拋出異常 if (!this.isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } if (existingDefinition.getRole() < beanDefinition.getRole()) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(existingDefinition)) { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (this.logger.isTraceEnabled()) { this.logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } //注冊進beanDefinitionMap this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (this.hasBeanCreationStarted()) { synchronized(this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; this.removeManualSingletonName(beanName); } } else { //如果仍處於啟動注冊階段,注冊進beanDefinitionMap this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition == null && !this.containsSingleton(beanName)) { if (this.isConfigurationFrozen()) { this.clearByTypeCache(); } } else { this.resetBeanDefinition(beanName); } }
最終來到DefaultListableBeanFactory類的registerBeanDefinition()方法,DefaultListableBeanFactory類還熟悉嗎?DefaultListableBeanFactory是IoC容器的具體產品。
仔細看這個方法registerBeanDefinition(),首先會檢查是否已經存在,如果存在並且不允許被覆蓋則直接拋出異常。不存在的話就直接注冊進beanDefinitionMap中。
第五步 刷新應用上下文(IoC容器的初始化過程)
IoC容器的初始化過程,主要分下面三步:
- BeanDefinition的Resource定位
- BeanDefinition的載入
- 向IoC容器注冊BeanDefinition
從run方法的,refreshContext()方法一路跟下去,最終來到AbstractApplicationContext類的refresh()方法。
public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShutdownMonitor) { //刷新上下文環境 this.prepareRefresh(); //這里是在子類中啟動 refreshBeanFactory() 的地方 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); //准備bean工廠,以便在此上下文中使用 this.prepareBeanFactory(beanFactory); try { //設置 beanFactory 的后置處理 this.postProcessBeanFactory(beanFactory); //調用 BeanFactory 的后處理器,這些處理器是在Bean 定義中向容器注冊的 this.invokeBeanFactoryPostProcessors(beanFactory); //注冊Bean的后處理器,在Bean創建過程中調用 this.registerBeanPostProcessors(beanFactory); //對上下文中的消息源進行初始化 this.initMessageSource(); //初始化上下文中的事件機制 this.initApplicationEventMulticaster(); //初始化其他特殊的Bean this.onRefresh(); //檢查監聽Bean並且將這些監聽Bean向容器注冊 this.registerListeners(); //實例化所有的(non-lazy-init)單件 this.finishBeanFactoryInitialization(beanFactory); //發布容器事件,結束Refresh過程 this.finishRefresh(); } catch (BeansException var9) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } this.destroyBeans(); this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } } }
從以上代碼中我們可以看到,refresh()方法中所作的工作也挺多,我們沒辦法面面俱到,主要根據IoC容器的初始化步驟和IoC依賴注入的過程進行分析,圍繞以上兩個過程,我們主要介紹重要的方法。
obtainFreshBeanFactory();
在啟動流程的第三步:初始化應用上下文。中我們創建了應用的上下文,並觸發了GenericApplicationContext類的構造方法如下所示,創建了beanFactory,也就是創建了DefaultListableBeanFactory類。
public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); }
關於obtainFreshBeanFactory()方法,其實就是拿到我們之前創建的beanFactory。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //刷新BeanFactory this.refreshBeanFactory(); //獲取beanFactory return this.getBeanFactory(); }
從上面代碼可知,在該方法中主要做了三個工作,刷新beanFactory,獲取beanFactory,返回beanFactory。
首先看一下refreshBeanFactory()方法,跟下去來到GenericApplicationContext類的refreshBeanFactory()發現也沒做什么。
protected final void refreshBeanFactory() throws IllegalStateException { if (!this.refreshed.compareAndSet(false, true)) { throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); } else { this.beanFactory.setSerializationId(this.getId()); } }
AbstractApplicationContext類有兩個子類實現了refreshBeanFactory(),但是在前面第三步初始化上下文的時候,實例化了GenericApplicationContext類,所以沒有進入AbstractRefreshableApplicationContext中的refreshBeanFactory()方法。
this.refreshed.compareAndSet(false, true) ,這行代碼在這里表示:GenericApplicationContext只允許刷新一次 。這行代碼,很重要,不是在Spring中很重要,而是這行代碼本身。首先看一下this.refreshed屬性:
private final AtomicBoolean refreshed = new AtomicBoolean();
java J.U.C並發包中很重要的一個原子類AtomicBoolean。通過該類的compareAndSet()方法可以實現一段代碼絕對只實現一次的功能。
prepareBeanFactory(beanFactory);
從字面意思上可以看出准備BeanFactory。
看代碼,具體看看做了哪些准備工作。這個方法不是重點,看注釋吧。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 配置類加載器:默認使用當前上下文的類加載器 beanFactory.setBeanClassLoader(this.getClassLoader()); // 配置EL表達式:在Bean初始化完成,填充屬性的時候會用到 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 添加屬性編輯器 PropertyEditor beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment())); // 添加Bean的后置處理器 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 忽略裝配以下指定的類 beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // 將以下類注冊到 beanFactory(DefaultListableBeanFactory) 的resolvableDependencies屬性中 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // 將早期后處理器注冊為application監聽器,用於檢測內部bean beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // 如果當前BeanFactory包含loadTimeWeaver Bean,說明存在類加載期織入AspectJ, // 則把當前BeanFactory交給類加載期BeanPostProcessor實現類LoadTimeWeaverAwareProcessor來處理, // 從而實現類加載期織入AspectJ的目的。 if (beanFactory.containsBean("loadTimeWeaver")) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // 將當前環境變量(environment) 注冊為單例bean if (!beanFactory.containsLocalBean("environment")) { beanFactory.registerSingleton("environment", this.getEnvironment()); } // 將當前系統配置(systemProperties) 注冊為單例Bean if (!beanFactory.containsLocalBean("systemProperties")) { beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties()); } // 將當前系統環境 (systemEnvironment) 注冊為單例Bean if (!beanFactory.containsLocalBean("systemEnvironment")) { beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment()); } }
postProcessBeanFactory(beanFactory);
postProcessBeanFactory()方法向上下文中添加了一系列的Bean的后置處理器。后置處理器工作的時機是在所有的beanDenifition加載完成之后,bean實例化之前執行。簡單來說Bean的后置處理器可以修改BeanDefinition的屬性信息。
invokeBeanFactoryPostProcessors(beanFactory);(重點)
上面說過,IoC容器的初始化過程包括三個步驟,在invokeBeanFactoryPostProcessors()方法中完成了IoC容器初始化過程的三個步驟。
第一步:Resource定位
在SpringBoot中,我們都知道他的包掃描是從主類所在的包開始掃描的,prepareContext()方法中,會先將主類解析成BeanDefinition,然后在refresh()方法的invokeBeanFactoryPostProcessors()方法中解析主類的BeanDefinition獲取basePackage的路徑。這樣就完成了定位的過程。其次SpringBoot的各種starter是通過SPI擴展機制實現的自動裝配,SpringBoot的自動裝配同樣也是在invokeBeanFactoryPostProcessors()方法中實現的。還有一種情況,在SpringBoot中有很多的@EnableXXX注解,細心點進去看的應該就知道其底層是@Import注解,在invokeBeanFactoryPostProcessors()方法中也實現了對該注解指定的配置類的定位加載。
常規的在SpringBoot中有三種實現定位,第一個是主類所在包的,第二個是SPI擴展機制實現的自動裝配(比如各種starter),第三種就是@Import注解指定的類。
第二步:BeanDefinition的載入
第一步中說了三種Resource的定位情況,定位后緊接着就是BeanDefinition的分別載入。所謂的載入就是通過上面的定位得到的basePackage,SpringBoot會將該路徑拼接成:classpath*:org/springframework/boot/demo/**/*.class這樣的形式,然后一個叫做PathMatchingResourcePatternResolver的類會將該路徑下所有的.class文件都加載進來,然后遍歷判斷是不是有@Component注解,如果有的話,就是我們要裝載的BeanDefinition。大致過程就是這樣的了。
注:@Configuration,@Controller,@Service等注解底層都是@Component注解,只不過包裝了一層罷了。
第三個過程:注冊BeanDefinition
這個過程通過調用上文提到的BeanDefinitionRegister接口的實現來完成。這個注冊過程把載入過程中解析得到的BeanDefinition向IoC容器進行注冊。通過上文的分析,我們可以看到,在IoC容器中將BeanDefinition注入到一個ConcurrentHashMap中,IoC容器就是通過這個HashMap來持有這些BeanDefinition數據的。比如DefaultListableBeanFactory 中的beanDefinitionMap屬性。
OK,總結完了,接下來我們通過代碼看看具體是怎么實現的。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); ... } // PostProcessorRegistrationDelegate類 public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { ... invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); ... } // PostProcessorRegistrationDelegate類 private static void invokeBeanDefinitionRegistryPostProcessors( Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) { for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) { postProcessor.postProcessBeanDefinitionRegistry(registry); } } // ConfigurationClassPostProcessor類 @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { ... processConfigBeanDefinitions(registry); } // ConfigurationClassPostProcessor類 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { ... do { parser.parse(candidates); parser.validate(); ... } ... }
一路跟蹤調用棧,來到ConfigurationClassParser類的parse()方法。
public void parse(Set<BeanDefinitionHolder> configCandidates) { Iterator var2 = configCandidates.iterator(); while(var2.hasNext()) { BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next(); BeanDefinition bd = holder.getBeanDefinition(); try { // 如果是SpringBoot項目進來的,bd其實就是前面主類封裝成的 AnnotatedGenericBeanDefinition(AnnotatedBeanDefinition接口的實現類) if (bd instanceof AnnotatedBeanDefinition) { this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) { this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName()); } else { this.parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException var6) { throw var6; } catch (Throwable var7) { throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7); } } // 加載默認的配置---》(對springboot項目來說這里就是自動裝配的入口了) this.deferredImportSelectorHandler.process(); }
看上面的注釋,在前面的prepareContext()方法中,我們詳細介紹了我們的主類是如何一步步的封裝成AnnotatedGenericBeanDefinition,並注冊進IoC容器的beanDefinitionMap中的。
繼續沿着parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());方法跟下去
// ConfigurationClassParser類 protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException { processConfigurationClass(new ConfigurationClass(metadata, beanName)); } // ConfigurationClassParser類 protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { ... // Recursively process the configuration class and its superclass hierarchy. //遞歸地處理配置類及其父類層次結構。 SourceClass sourceClass = asSourceClass(configClass); do { //遞歸處理Bean,如果有父類,遞歸處理,直到頂層父類 sourceClass = doProcessConfigurationClass(configClass, sourceClass); } while (sourceClass != null); this.configurationClasses.put(configClass, configClass); } // ConfigurationClassParser類 protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { // Recursively process any member (nested) classes first //首先遞歸處理內部類,(SpringBoot項目的主類一般沒有內部類) processMemberClasses(configClass, sourceClass); // Process any @PropertySource annotations // 針對 @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.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // Process any @ComponentScan annotations // 根據 @ComponentScan 注解,掃描項目中的Bean(SpringBoot 啟動類上有該注解) 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 // 立即執行掃描,(SpringBoot項目為什么是從主類所在的包掃描,這就是關鍵了) 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(); } // 檢查是否是ConfigurationClass(是否有configuration/component兩個注解),如果是,遞歸查找該類相關聯的配置類。 // 所謂相關的配置類,比如@Configuration中的@Bean定義的bean。或者在有@Component注解的類上繼續存在@Import注解。 if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } // Process any @Import annotations //遞歸處理 @Import 注解(SpringBoot項目中經常用的各種@Enable*** 注解基本都是封裝的@Import) 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; }
看doProcessConfigurationClass()方法。(SpringBoot的包掃描的入口方法,重點哦)
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(... 獲取主類上的@PropertySource注解(關於該注解是怎么用的請自行百度),解析該注解並將該注解指定的properties配置文件中的值存儲到Spring的 Environment中,Environment接口提供方法去讀取配置文件中的值,參數是properties文件中定義的key值。
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); 解析主類上的@ComponentScan注解,呃,怎么說呢,42行后面的代碼將會解析該注解並進行包掃描。
processImports(configClass, sourceClass, getImports(sourceClass), true); 解析主類上的@Import注解,並加載該注解指定的配置類。
提示:在spring中好多注解都是一層一層封裝的,比如@EnableXXX,是對@Import注解的二次封裝。@SpringBootApplication注解=@ComponentScan+@EnableAutoConfiguration+@Import+@Configuration+@Component。@Controller,@Service等等是對@Component的二次封裝。
Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); 進入該方法
// ComponentScanAnnotationParser類 public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) { ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); ... // 根據 declaringClass (如果是SpringBoot項目,則參數為主類的全路徑名) if (basePackages.isEmpty()) { basePackages.add(ClassUtils.getPackageName(declaringClass)); } ... // 根據basePackages掃描類 return scanner.doScan(StringUtils.toStringArray(basePackages)); }
發現有兩行重要的代碼。
到這里呢IoC容器初始化三個步驟的第一步,Resource定位就完成了,成功定位到了主類所在的包。
接着往下看 return scanner.doScan(StringUtils.toStringArray(basePackages)); Spring是如何進行類掃描的。進入doScan()方法。
// ComponentScanAnnotationParser類 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) { // 從指定的包中掃描需要裝載的Bean 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 注冊進 IoC容器(beanDefinitionMap) registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }
這個方法中有兩個比較重要的方法,Set<BeanDefinition> candidates = findCandidateComponents(basePackage); 從basePackage中掃描類並解析成BeanDefinition,拿到所有符合條件的類后在 registerBeanDefinition(definitionHolder, this.registry); 將該類注冊進IoC容器。也就是說在這個方法中完成了IoC容器初始化過程的第二三步,BeanDefinition的載入,和BeanDefinition的注冊。
findCandidateComponents(basePackage);
// ClassPathScanningCandidateComponentProvider類 public Set<BeanDefinition> findCandidateComponents(String basePackage) { ... else { return scanCandidateComponents(basePackage); } } // ClassPathScanningCandidateComponentProvider類 private Set<BeanDefinition> scanCandidateComponents(String basePackage) { Set<BeanDefinition> candidates = new LinkedHashSet<>(); try { //拼接掃描路徑,比如:classpath*:org/springframework/boot/demo/**/*.class String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + '/' + this.resourcePattern; //從 packageSearchPath 路徑中掃描所有的類 Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath); boolean traceEnabled = logger.isTraceEnabled(); boolean debugEnabled = logger.isDebugEnabled(); for (Resource resource : resources) { if (traceEnabled) { logger.trace("Scanning " + resource); } if (resource.isReadable()) { try { MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource); // //判斷該類是不是 @Component 注解標注的類,並且不是需要排除掉的類 if (isCandidateComponent(metadataReader)) { //將該類封裝成 ScannedGenericBeanDefinition(BeanDefinition接口的實現類)類 ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader); sbd.setResource(resource); sbd.setSource(resource); if (isCandidateComponent(sbd)) { if (debugEnabled) { logger.debug("Identified candidate component class: " + resource); } candidates.add(sbd); } else { if (debugEnabled) { logger.debug("Ignored because not a concrete top-level class: " + resource); } } } else { if (traceEnabled) { logger.trace("Ignored because not matching any filter: " + resource); } } } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to read candidate component class: " + resource, ex); } } else { if (traceEnabled) { logger.trace("Ignored because not readable: " + resource); } } } } catch (IOException ex) { throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex); } return candidates; }
將basePackage拼接成classpath*:org/springframework/boot/demo/**/*.class,在getResources(packageSearchPath);方法中掃描到了該路徑下的所有的類。然后遍歷這些Resources,在isCandidateComponent(metadataReader)方法中判斷該類是不是 @Component 注解標注的類,並且不是需要排除掉的類。ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);將掃描到的類,解析成ScannedGenericBeanDefinition,該類是BeanDefinition接口的實現類。OK,IoC容器的BeanDefinition載入到這里就結束了。
registerBeanDefinition(definitionHolder, this.registry);
查看registerBeanDefinition()方法。是不是有點眼熟,在前面介紹prepareContext()方法時,我們詳細介紹了主類的BeanDefinition是怎么一步一步的注冊進DefaultListableBeanFactory的beanDefinitionMap中的。在此呢我們就省略1w字吧。完成了BeanDefinition的注冊,就完成了IoC容器的初始化過程。此時,在使用的IoC容器DefaultListableFactory中已經建立了整個Bean的配置信息,而這些BeanDefinition已經可以被容器使用了。他們都在BeanbefinitionMap里被檢索和使用。容器的作用就是對這些信息進行處理和維護。這些信息是容器簡歷依賴反轉的基礎。
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) { BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry); }
OK,到這里IoC容器的初始化過程的三個步驟就梳理完了。當然這只是針對SpringBoot的包掃描的定位方式的BeanDefinition的定位,加載,和注冊過程。前面我們說過,還有兩種方式@Import和SPI擴展實現的starter的自動裝配。
@Import注解的解析過程
相信不說大家也應該知道了,各種@EnableXXX注解,很大一部分都是對@Import的二次封裝(其實也是為了解耦,比如當@Import導入的類發生變化時,我們的業務系統也不需要改任何代碼)。
我們又要回到上文中的ConfigurationClassParser類的doProcessConfigurationClass方法的processImports(configClass, sourceClass, getImports(sourceClass), true);
processImports(configClass, sourceClass, getImports(sourceClass), true);中configClass和sourceClass參數都是主類相對應的。
首先看getImports(sourceClass);
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException { Set<SourceClass> imports = new LinkedHashSet<>(); Set<SourceClass> visited = new LinkedHashSet<>(); collectImports(sourceClass, imports, visited); return imports; }
三、SpringBoot自動裝配原理實現
通過分析refresh()方法中的invokeBeanFactoryPostProcessors()方法,分析了IoC容器的初始化過程,這一節從代碼上如下所示,接上一節ConfigurationClassParser類中的parse()方法,接着分析SpringBoot的自動裝配原理。
public void parse(Set<BeanDefinitionHolder> configCandidates) { Iterator var2 = configCandidates.iterator(); while(var2.hasNext()) { BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next(); BeanDefinition bd = holder.getBeanDefinition(); try { // 如果是SpringBoot項目進來的,bd其實就是前面主類封裝成的 AnnotatedGenericBeanDefinition(AnnotatedBeanDefinition接口的實現類) if (bd instanceof AnnotatedBeanDefinition) { this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) { this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName()); } else { this.parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException var6) { throw var6; } catch (Throwable var7) { throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7); } } // 加載默認的配置---》(對springboot項目來說這里就是自動裝配的入口了) this.deferredImportSelectorHandler.process(); }
@SpringBootApplication注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { ... }
接着看@EnableAutoConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ... }
OK,看到@Import(AutoConfigurationImportSelector.class)導入了一個重要的類AutoConfigurationImportSelector。
AutoConfigurationImportSelector
//自動裝配 public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } } protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!this.isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } else { AnnotationAttributes attributes = this.getAttributes(annotationMetadata); //獲取所有的自動配置類(META-INF/spring.factories中配置的key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的類) List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes); configurations = this.removeDuplicates(configurations); //需要排除的自動裝配類(springboot的主類上 @SpringBootApplication(exclude = {com.demo.starter.config.DemoConfig.class})指定的排除的自動裝配類) Set<String> exclusions = this.getExclusions(annotationMetadata, attributes); this.checkExcludedClasses(configurations, exclusions); //將需要排除的類從 configurations remove掉 configurations.removeAll(exclusions); configurations = this.getConfigurationClassFilter().filter(configurations); this.fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions); } }
至於怎么從章節一中提到的ConfigurationClassParser類中的parse()===>deferredImportSelectorHandler.process();==>AutoConfigurationImportSelector#selectImports(),篇幅有限不做過多介紹。
我們來看一下getCandidateConfigurations()方法是怎么拿到這些自動配置類的。
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; }
是不是又看到一個十分熟悉的方法loadFactoryNames(),沒錯,其實我們在分析SpringBoot啟動流程的的時候,就已經分析了,SpringBoot是如何從META-INF/spring.factories中加載指定key的value的。
繼續看Set<String> exclusions = getExclusions(annotationMetadata, attributes);方法,該方法是排除主類上@SpringBootApplication注解上排除的自動裝配的類。
configurations = this.getConfigurationClassFilter().filter(configurations);該行代碼將會過濾掉不需要裝配的類。過濾的邏輯有很多,比如我們常用的@ConditionXXX注解。如下所示:
@ConditionalOnBean:容器中有指定的Bean
@ConditionalOnClass:當類路徑下有指定的類
@ConditionalOnExpression:基於SpEL表達式作為判斷條件
@ConditionalOnJava:基於JVM版本作為判斷條件
@ConditionalOnJndi:在JNDI存在的條件下查找指定的位置
@ConditionalOnMissingBean:當容器中沒有指定Bean的情況下
@ConditionalOnMissingClass:當類路徑下沒有指定的類
@ConditionalOnNotWebApplication:當前項目不是Web項目
@ConditionalOnProperty:配置文件中指定的屬性是否有指定的值
@ConditionalOnResource:類路徑下是否有指定的資源
@ConditionalOnSingleCandidate:當指定Bean在容器中只有一個,或者雖然有多個但是指定首選Bean
@ConditionalOnWebApplication:當前項目是Web項目的條件下
四、IOC容器依賴注入
前面在refresh()-->invokeBeanFactoryPostProcessors(beanFactory);方法中已經完成了IoC容器的初始化並已經載入了我們定義的Bean的信息(BeanDefinition),現在我們開始分析依賴注入的原理。首先需要說明的是依賴注入在用戶第一次向IoC容器索要Bean時觸發,當然也有例外,我們可以在BeanDefinition中中通過控制lazy-init屬性來讓容器完成對Bean的預實例化。這個預實例化實際上也是一個依賴注入的過程,但它是在初始化過程中完成的。
getBean()的過程
// AbstractApplicationContext類 @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... try { ... // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); ... } ... } } // AbstractApplicationContext類 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { ... // Instantiate all remaining (non-lazy-init) singletons. // 實例化所有剩余的(non-lazy-init)單例。 beanFactory.preInstantiateSingletons(); } // DefaultListableBeanFactory類 @Override public void preInstantiateSingletons() throws BeansException { ... // Iterate over a copy to allow for init methods which in turn register new bean definitions. // While this may not be part of the regular factory bootstrap, it does otherwise work fine. List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... 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 { // 這里就是觸發依賴注入的地方 getBean(beanName); } } } ... }
跟蹤其調用棧,看到getBean(beanName);方法,我們再梳理一下getBean()方法,前面總結過該方法在IoC容器的頂層接口BeanFactory中定義,然后在IoC容器的具體產品DefaultListableBeanFactory類的基類AbstractBeanFactory實現了getBean()方法。接着看代碼。
// AbstractBeanFactory類 @Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } @Override public <T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } @Override public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false); } public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException { return doGetBean(name, requiredType, args, false); }
從上面代碼可知大致可分為兩種獲取Bean的參數,一種是按名獲取,一種是按類獲取。但是最終都進入到了doGetBean()方法。
// AbstractBeanFactory類 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // bean獲取過程:先獲取bean名字 // 會把帶有&前綴的去掉,或者去aliasMap中找這個是不是別名,最終確定bean的id是什么 final String beanName = transformedBeanName(name); Object bean; // 1.檢查緩存中或者實例工廠中是否有對應的實例 // 因為在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候為了避免循環依賴 // Spring在創建bean的時候不會等bean創建完成就會將bean的ObjectFactory提早曝光 // 也就是將ObjectFactory加入到緩存中,一旦下一個要創建的bean需要依賴上個bean則直接使用ObjectFactory // 2.spring 默認是單例的,如果能獲取到直接返回,提高效率。 // Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } } // 用於檢測bean的正確性,同時如果獲取的是FactoryBean的話還需要調用getObject()方法獲取最終的那個bean實例 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // Fail if we're already creating this bean instance: // We're assumably within a circular reference. if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // Check if bean definition exists in this factory. //這里對IoC容器中的BeanDefinition是否存在進行檢查,檢查是否能在當前的BeanFactory中取得需要的Bean。 // 如果當前的工廠中取不到,則到雙親BeanFactory中去取。如果當前的雙親工廠取不到,那就順着雙親BeanFactory // 鏈一直向上查找。 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { // 遞歸調用父bean的doGetBean查找 return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup, args); } else { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } } if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { //這里根據Bean的名字取得BeanDefinition final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. //獲取當前Bean的所有依賴Bean,這里會觸發getBean的遞歸調用。知道取到一個沒有任何依賴的Bean為止。 String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'", ex); } } } // 這里通過createBean方法創建singleton Bean的實例 這里還有一個回調函數 // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { // 最后在getSingleton中又會調用這個方法 // TODO createBean的入口 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); } // 這里是創建prototype bean的地方 else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, () -> { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // Check if required type matches the type of the actual bean instance. //這里對創建的Bean進行類型檢查,如果沒有問題,就返回這個新創建的Bean,這個Bean已經是包含了依賴關系的Bean if (requiredType != null && !requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }
這個就是依賴注入的入口了,依賴注入是在容器的BeanDefinition數據已經建立好的前提下進行的。“程序=數據+算法”,很經典的一句話,前面我們詳細介紹了BeanDefinition的注冊過程,BeanDefinition就是數據。如上面代碼所示,doGetBean()方法不涉及復雜的算法,但是這個過程也不是很簡單,因為我們都知道,對於IoC容器的使用,Spring提供了很多的配置參數,每一個配置參數實際上就代表了一個IoC容器的實現特征,這些特征很多都需要在依賴注入的過程或者對Bean進行生命周期管理的過程中完成。雖然我們可以簡單的將IoC容器描述成一個ConcurrentHashMap,ConcurrentHashMap只是它的數據結構而不是IoC容器的全部。
Object sharedInstance = getSingleton(beanName);如注釋所說,首先回去找在容器中是不是已經存在該單例。
// DefaultSingletonBeanRegistry類 protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 由於scope是singleton,所以先從緩存中取單例對象的實例,如果取到直接返回,沒有取到加載bean Object singletonObject = this.singletonObjects.get(beanName); // 當想要獲取的bean沒有被加載,並且也沒有正在被創建的時候,主動去加載bean if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 鎖住單例緩存區加載bean synchronized (this.singletonObjects) { // singletonObjects ,earlySingletonObjects ,singletonFactories是一個單例實例的三種存在狀態 // 再去earlySingletonObjects中去找 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // 去singletonFactories中去找對象的實例 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
在DefaultSingletonBeanRegistry類中的singletonObjects屬性就是存singleton bean的地方。
如果getSingleton()為 null繼續往下看,會在當前的BeanFactory中獲取BeanDefinition,也就是這行方法代碼:final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);在這行代碼拿到BeanDefinition后,首先判斷是不是singleton Bean,如果是的話,開始執行創建Bean,正是return createBean(beanName, mbd, args);這行代碼。如果是原型(Prototype)Bean我們就不分析了。原型bean每次執行getBean()都會創建一個實例。接下來我們看createBean()方法。
createBean()的過程
首先看一下create bean的過程
Bean實例的創建 為Bean實例設置屬性(屬性注入,其實就是依賴注入真正發生的地方) 調用Bean的初始化方法
前面說了getBean()是依賴注入的起點,之后會調用createBean(),下面通過createBean()代碼來了解這個過程。在這個過程中,Bean對象會根據BeanDefinition定義的要求生成。
// AbstractAutowireCapableBeanFactory類 @Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { ... try { // 驗證以及准備override的方法 mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", ex); } try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. // createBean之前調用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法 // 默認不做任何處理所以會返回null // 但是如果我們重寫了這兩個方法,那么bean的創建過程就結束了,這里就為以后的annotation自動注入提供了鈎子 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } }catch (Throwable ex) { throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", ex); } try { // 實際執行createBean的是doCreateBean()方法 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isDebugEnabled()) { logger.debug("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()方法。
// AbstractAutowireCapableBeanFactory類 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // BeanWrapper是用來持有創建出來的Bean對象 // Instantiate the bean. BeanWrapper instanceWrapper = null; // 如果是單例,先把緩存中的同名Bean清除 if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } // 這里是創建Bean的地方,由createBeanInstance完成。 // TODO 完成Bean初始化過程的第一步:創建實例 if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } } // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. // 是否自動解決循環引用 // 當bean條件為: 單例&&允許循環引用&&正在創建中這樣的話提早暴露一個ObjectFactory boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } // 把ObjectFactory放進singletonFactories中 // 這里在其他bean在創建的時候會先去singletonFactories中查找有沒有beanName到ObjectFactory的映射 // 如果有ObjectFactory就調用它的getObject方法獲取實例 // 但是在這里就可以對一個bean進行保證,代理等等AOP就可以在getEarlyBeanReference這里實現 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { // TODO 完成Bean初始化過程的第二步:為Bean的實例設置屬性 // Bean依賴注入發生的地方 // 對bean進行屬性填充,如果存在依賴於其他的bean的屬性,則會遞歸的調用初始化依賴的bean populateBean(beanName, mbd, instanceWrapper); // TODO 完成Bean初始化過程的第三步:調用Bean的初始化方法(init-method) // 調用初始化方法,比如init-method方法指定的方法 exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } // Register bean as disposable. try { // 注冊銷毀方法,比如:可以在配置bean的時候指定destory-method方法 registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
結合上面的代碼,我們再來看一下創建Bean的三個步驟,是不是有點豁然開朗的感覺。別着急繼續往下看。
Bean實例的創建,instanceWrapper = createBeanInstance(beanName, mbd, args);
為Bean實例設置屬性,populateBean(beanName, mbd, instanceWrapper);
調用Bean的初始化方法,exposedObject = initializeBean(beanName, exposedObject, mbd);
createBeanInstance():Bean實例的創建
// AbstractAutowireCapableBeanFactory類 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // Make sure bean class is actually resolved at this point. // 確認需要創建的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); } // 當有工廠方法的時候使用工廠方法初始化Bean,就是配置的時候指定FactoryMethod屬性,類似注解中的@Bean把方法的返回值作為Bean 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) { // 如果有有參數的構造函數,構造函數自動注入 // 這里spring會花費大量的精力去進行參數的匹配 return autowireConstructor(beanName, mbd, null, null); } else { // 如果沒有有參構造函數,使用默認構造函數構造 return instantiateBean(beanName, mbd); } } // Need to determine the constructor... // 使用構造函數進行實例化 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // No special handling: simply use no-arg constructor. // 使用默認的構造函數對Bean進行實例化 return instantiateBean(beanName, mbd); }
我們可以看到在instantiateBean()方法中生成了Bean所包含的Java對象,這個對象的生成有很多種不同的方式,可以通過工廠方法生成,也可以通過容器的autowire特性生成,這些生成方式都是由BeanDefinition決定的。對於上面我們的WebController和WebService兩個類是通過最后一行,使用默認的構造函數進行Bean的實例化。
接着看instantiateBean()方法。
// AbstractAutowireCapableBeanFactory類 protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) { // 使用默認的實例化策略對Bean進行實例化,默認的實例化策略是CglibSubclassingInstantiationStrategy, // 也就是常說的CGLIB來對Bean進行實例化。PS:面試官常問的字節碼增強 try { Object beanInstance; final BeanFactory parent = this; if (System.getSecurityManager() != null) { beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, parent), getAccessControlContext()); } else { // getInstantiationStrategy()會返回CglibSubclassingInstantiationStrategy類的實例 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); } }
這里使用CGLIB進行Bean的實例化。CGLIB是一個常用的字節碼生成器的類庫,其提供了一系列的API來提供生成和轉換Java字節碼的功能。在Spring AOP中同樣也是使用的CGLIB對Java的字節碼進行增強。在IoC容器中,使用SimpleInstantiationStrategy類。這個類是Spring用來生成Bean對象的默認類,它提供了兩種實例化Java對象的方法,一種是通過BeanUtils,它使用的是JVM的反射功能,一種是通過CGLIB來生成。
getInstantiationStrategy()方法獲取到CglibSubclassingInstantiationStrategy實例,instantiate()是CglibSubclassingInstantiationStrategy類的父類SimpleInstantiationStrategy實現的。
// SimpleInstantiationStrategy類 @Override public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. // 如果BeanFactory重寫了Bean內的方法,則使用CGLIB,否則使用BeanUtils if (!bd.hasMethodOverrides()) { // 如果bean沒有需要動態替換的方法就直接反射進行創建實例 Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) { constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; if (constructorToUse == null) { 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); } } } // 通過BeanUtils進行實例化,這個BeanUtils的實例化通過Constructor類實例化Bean // 在BeanUtils中可以看到具體的調用ctor.newInstances(args) return BeanUtils.instantiateClass(constructorToUse); } else { // Must generate CGLIB subclass. // TODO 使用CGLIB實例化對象 return instantiateWithMethodInjection(bd, beanName, owner); } }
在SpringBoot中我們一般采用@Autowire的方式進行依賴注入,很少采用像SpringMVC那種在xml中使用<lookup-method>或者<replaced-method>等標簽的方式對注入的屬性進行override,所以在上面的代碼中if(!bd.hasMethodOverrides())中的判斷為true,會采用BeanUtils的實例化方式。
populateBean();屬性設置(依賴注入)
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { if (bw == null) { if (mbd.hasPropertyValues()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); } else { // Skip property population phase for null instance. return; } } // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the // state of the bean before properties are set. This can be used, for example, // to support styles of field injection. boolean continueWithPropertyPopulation = true; // 調用InstantiationAwareBeanPostProcessor Bean的后置處理器,在Bean注入屬性前改變BeanDefinition的信息 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; } } } } if (!continueWithPropertyPopulation) { return; } // 這里取得在BeanDefinition中設置的property值,這些property來自對BeanDefinition的解析 // 用於在配置文件中通過<property>配置的屬性並且顯示在配置文件中配置了autowireMode屬性 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. // 這里對autowire注入的處理,autowire by name if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. // 這里對autowire注入的處理, autowire by type // private List<Test> tests; if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); if (hasInstAwareBpps || needsDepCheck) { if (pvs == null) { pvs = mbd.getPropertyValues(); } PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; // TODO @Autowire @Resource @Value @Inject 等注解的依賴注入過程 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } } if (needsDepCheck) { checkDependencies(beanName, mbd, filteredPds, pvs); } } if (pvs != null) { // 注入配置文件中<property>配置的屬性 applyPropertyValues(beanName, mbd, bw, pvs); } }
上面方法中的applyPropertyValues()方法基本都是用於SpringMVC中采用xml配置Bean的方法。我們主要看的是pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);這行代碼,這行代碼是真正執行采用@Autowire @Value 等注解的依賴注入過程。
接着往下看
// AutowiredAnnotationBeanPostProcessor類 @Override public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException { // 遍歷,獲取@Autowire,@Resource,@Value,@Inject等具備注入功能的注解 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try { // 屬性注入 metadata.inject(bean, beanName, pvs); } catch (BeanCreationException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); } return pvs; }
AutowiredAnnotationBeanPostProcessor類實現了postProcessPropertyValues()方法。findAutowiringMetadata(beanName, bean.getClass(), pvs);方法會尋找在當前類中的被@Autowire,@Value等具備注入功能的注解的屬性。
metadata.inject(bean, beanName, pvs);方法開始執行注入的邏輯。
// AutowiredAnnotationBeanPostProcessor類 @Override protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { // 需要注入的字段 Field field = (Field) this.member; // 需要注入的屬性值 Object value; if (this.cached) { value = resolvedCachedArgument(beanName, this.cachedFieldValue); } else { // @Autowired(required = false),當在該注解中設置為false的時候,如果有直接注入,沒有跳過,不會報錯。 DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set<String> autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory != null, "No BeanFactory available"); TypeConverter typeConverter = beanFactory.getTypeConverter(); try { // 通過BeanFactory 解決依賴關系 // 比如在webController中注入了webService,這個會去BeanFactory中去獲取webService,也就是getBean()的邏輯。 // 如果存在直接返回,不存在再執行createBean()邏輯。 // 如果在webService中依然依賴,依然會去遞歸。 // 這里是一個復雜的遞歸邏輯。 value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } synchronized (this) { if (!this.cached) { if (value != null || this.required) { this.cachedFieldValue = desc; registerDependentBeans(beanName, autowiredBeanNames); if (autowiredBeanNames.size() == 1) { String autowiredBeanName = autowiredBeanNames.iterator().next(); if (beanFactory.containsBean(autowiredBeanName) && beanFactory.isTypeMatch(autowiredBeanName, field.getType())) { this.cachedFieldValue = new ShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); } } } else { this.cachedFieldValue = null; } this.cached = true; } } } if (value != null) { ReflectionUtils.makeAccessible(field); field.set(bean, value); } }
看這行代碼:value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);注意beanFactory依舊是我們熟悉的IoC容器的具體產品,也就是實現類DefaultListableBeanFactory。見到就說一遍,方便大家記住它,很重要。
在resolveDependency()方法中經過一頓操作,最終又會來到上面的getBean()方法。以上就是依賴注入的整個過程。
initializeBean():調用Bean的初始化方法
設置Bean的初始化方法有兩種方法,一種是在xml或者@Bean指定init-method方法。另一種是讓bean實現InitializingBean接口重寫afterPropertiesSet()方法。
// AbstractAutowireCapableBeanFactory類 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else { //在調用Bean的初始化方法之前,調用一系列的aware接口實現,把相關的BeanName,BeanClassLoader,以及BeanFactory注入到Bean中去。 invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { // 這些都是鈎子方法,在反復的調用,給Spring帶來了極大的可拓展性 // 初始化之前調用BeanPostProcessor wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { // 調用指定的init-method方法 invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || !mbd.isSynthetic()) { // 這些都是鈎子方法,在反復的調用,給Spring帶來了極大的可拓展性 // 初始化之后調用BeanPostProcessor wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
在調用Bean的初始化方法之前,調用一系列的aware接口實現,把相關的BeanName,BeanClassLoader,以及BeanFactory注入到Bean中去。接着會執行invokeInitMethods()方法。
// AbstractAutowireCapableBeanFactory類 protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { // 除了使用init-method指定的初始化方法,還可以讓bean實現InitializingBean接口重寫afterPropertiesSet()方法 boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> { ((InitializingBean) bean).afterPropertiesSet(); return null; }, getAccessControlContext()); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { // 執行afterPropertiesSet()方法進行初始化 ((InitializingBean) bean).afterPropertiesSet(); } } // 先執行afterPropertiesSet()方法,再進行init-method if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); } } }
可見該方法中首先判斷Bean是否配置了init-method方法,如果有,那么通過invokeCustomInitMethod()方法來直接調用。其中在invokeCustomInitMethod()方法中是通過JDK的反射機制得到method對象,然后調用的init-method。最終完成Bean的初始化。
備注:因為篇幅太長,所以里面的一些代碼可能會因為版本關系導致代碼不完全一樣,但是處理邏輯基本是一樣的。
轉自:
https://www.cnblogs.com/hello-shf/category/1456313.html