許多文章都是分析的 xml 配置,可是如今 Spring Boot 開發多基於註解。本文從註解
的角度分析 Spring IOC 容器源碼。java
版本:git
文章部份內容參考自:https://www.javadoop.com/post/spring-iocgithub
BeanDefinition 接口定義了一個包含屬性、構造器參數、其餘具體信息的 bean 實例。web
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { // ConfigurableBeanFactory 中只有 2 種:singleton 和 prototype。 // request, session 等是基於 Web 的擴展 String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; // 不重要 int ROLE_APPLICATION = 0; int ROLE_SUPPORT = 1; int ROLE_INFRASTRUCTURE = 2; // 設置父 Bean 的信息(繼承父 Bean 的配置信息) void setParentName(@Nullable String parentName); @Nullable String getParentName(); // 設置 Bean 的類名稱,要經過反射來生成實例 void setBeanClassName(@Nullable String beanClassName); // 返回當前 Bean 的 class name String getBeanClassName(); void setScope(@Nullable String scope); @Nullable String getScope(); // 是否延遲初始化 void setLazyInit(boolean lazyInit); boolean isLazyInit(); // 設置該 Bean 依賴的全部的 Bean,並不是 @Autowire 標記的 void setDependsOn(@Nullable String... dependsOn); @Nullable String[] getDependsOn(); // 設置該 Bean 是否能夠注入到其餘 Bean 中,只對根據類型注入有效, // 若是根據名稱注入,即便這邊設置了 false,也是能夠的 void setAutowireCandidate(boolean autowireCandidate); boolean isAutowireCandidate(); // 同一接口的多個實現,若是不指定名字,Spring 會優先選擇設置 primary 爲 true 的 bean void setPrimary(boolean primary); boolean isPrimary(); // 若是該 Bean 採用工廠方法生成,指定工廠名稱;不然用反射生成 void setFactoryBeanName(@Nullable String factoryBeanName); @Nullable String getFactoryBeanName(); // 指定工廠類中的 工廠方法名稱 void setFactoryMethodName(@Nullable String factoryMethodName); @Nullable String getFactoryMethodName(); // 返回該 bean 的構造器參數 ConstructorArgumentValues getConstructorArgumentValues(); default boolean hasConstructorArgumentValues() { return !getConstructorArgumentValues().isEmpty(); } // Bean 中的屬性值,返回的實例在 bean factory post-processing 期間會被更改 MutablePropertyValues getPropertyValues(); default boolean hasPropertyValues() { return !getPropertyValues().isEmpty(); } void setInitMethodName(@Nullable String initMethodName); @Nullable String getInitMethodName(); void setDestroyMethodName(@Nullable String destroyMethodName); @Nullable String getDestroyMethodName(); void setRole(int role); int getRole(); void setDescription(@Nullable String description); @Nullable String getDescription(); // Read-only attributes boolean isSingleton(); boolean isPrototype(); boolean isAbstract(); @Nullable String getResourceDescription(); @Nullable BeanDefinition getOriginatingBeanDefinition(); }
AnnotationConfigUtils#processCommonDefinitionAnnotations(...)面試
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) { AnnotationAttributes lazy = attributesFor(metadata, Lazy.class); if (lazy != null) { abd.setLazyInit(lazy.getBoolean("value")); } else if (abd.getMetadata() != metadata) { lazy = attributesFor(abd.getMetadata(), Lazy.class); if (lazy != null) { abd.setLazyInit(lazy.getBoolean("value")); } } if (metadata.isAnnotated(Primary.class.getName())) { abd.setPrimary(true); } AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class); if (dependsOn != null) { abd.setDependsOn(dependsOn.getStringArray("value")); } AnnotationAttributes role = attributesFor(metadata, Role.class); if (role != null) { abd.setRole(role.getNumber("value").intValue()); } AnnotationAttributes description = attributesFor(metadata, Description.class); if (description != null) { abd.setDescription(description.getString("value")); } }
能夠看到,processCommonDefinitionAnnotations 方法會根據註解來填充 AnnotatedBeanDefinition,這些註解有:spring
向上查看調用,發現會在 ConfigurationClassBeanDefinitionReader#registerBeanDefinitionForImportedConfigurationClass 將其註冊爲一個 bean definition。緩存
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) { AnnotationMetadata metadata = configClass.getMetadata(); AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata); ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef); configBeanDef.setScope(scopeMetadata.getScopeName()); String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry); // 1. 經過註解填充 configBeanDef AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata); BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); // 2. 將 bean definition 註冊到 registry 中 this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition()); configClass.setBeanName(configBeanName); if (logger.isTraceEnabled()) { logger.trace("Registered bean definition for imported class '" + configBeanName + "'"); } }
最終會被 AbstractApplicationContext#refresh 的 invokeBeanFactoryPostProcessors(beanFactory) 方法調用。session
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } ... } }
BeanFactory 是生產 bean 的工廠,它負責生產和管理各個 bean 實例。從下圖能夠看到,ApplicationContext 也是一個 BeanFactory。若是說 BeanFactory 是 Spring 的心臟,那麼 ApplicationContext 就是完整的身軀。多線程
ApplicationContext 是應用程序運行時提供配置信息的通用接口。ApplicationContext 在程序運行時是不可更改的,可是實現類能夠從新再入配置信息。app
ApplicationContext 的實現類有不少,好比 AnnotationConfigApplicationContext, AnnotationConfigWebApplicationContext, ClassPathXmlApplicationContext, FileSystemXmlApplicationContext, XmlWebApplicationContext 等。咱們上面分析的就是 AnnotationConfigApplicationContext,其採用註解的方式提供配置信息,這樣咱們就不用寫 XML 配置文件了,很是簡潔。
本文使用 Spring Boot 開發,其啓動的代碼是:
@SpringBootApplication @EnableScheduling @EnableAspectJAutoProxy public class AppApplication { public static void main(String[] args) { SpringApplication.run(AppApplication.class, args); } }
核心的點是這一句:
SpringApplication.run(AppApplication.class, args);
SpringApplication 的代碼就不分析了,明確本次看源碼的目的是分析容器源碼
,Spring Boot 的啓動過程和其餘信息都忽略了,由於 Spring 代碼實在是龐雜。分析上面的 run 方法,最終會追蹤到 SpringApplication#run(...) 方法。
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } listeners.started(context); callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
跟 context 相關的,是下面這 3 句代碼:
prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments);
refreshContext 方法就是刷新給定的 context:
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(); }
會發現最終調用到了 AbstractApplicationContext#refresh 方法。註釋參考自:https://www.javadoop.com/post/spring-ioc
@Override public void refresh() throws BeansException, IllegalStateException { // 來個鎖,否則 refresh() 還沒結束,你又來個啓動或銷燬容器的操做,那不就亂套了嘛 synchronized (this.startupShutdownMonitor) { // 準備工做,記錄下容器的啓動時間、標記「已啓動」狀態、處理配置文件中的佔位符 prepareRefresh(); // 這步比較關鍵,這步完成後,配置文件就會解析成一個個 Bean 定義,註冊到 BeanFactory 中, // 固然,這裏說的 Bean 尚未初始化,只是配置信息都提取出來了, // 註冊也只是將這些信息都保存到了註冊中心(說到底核心是一個 beanName-> beanDefinition 的 map) ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 設置 BeanFactory 的類加載器,添加幾個 BeanPostProcessor,手動註冊幾個特殊的 bean prepareBeanFactory(beanFactory); try { // 【這裏須要知道 BeanFactoryPostProcessor 這個知識點,Bean 若是實現了此接口, // 那麼在容器初始化之後,Spring 會負責調用裏面的 postProcessBeanFactory 方法。】 // 這裏是提供給子類的擴展點,到這裏的時候,全部的 Bean 都加載、註冊完成了,可是都尚未初始化 // 具體的子類能夠在這步的時候添加一些特殊的 BeanFactoryPostProcessor 的實現類或作點什麼事 postProcessBeanFactory(beanFactory); // 調用 BeanFactoryPostProcessor 各個實現類的 postProcessBeanFactory(factory) 方法 invokeBeanFactoryPostProcessors(beanFactory); // 註冊 BeanPostProcessor 的實現類,注意看和 BeanFactoryPostProcessor 的區別 // 此接口兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization // 兩個方法分別在 Bean 初始化以前和初始化以後獲得執行。注意,到這裏 Bean 還沒初始化 registerBeanPostProcessors(beanFactory); // 初始化當前 ApplicationContext 的 MessageSource,國際化這裏就不展開說了,否則沒完沒了了 initMessageSource(); // 初始化當前 ApplicationContext 的事件廣播器,這裏也不展開了 initApplicationEventMulticaster(); // 從方法名就能夠知道,典型的模板方法(鉤子方法), // 具體的子類能夠在這裏初始化一些特殊的 Bean(在初始化 singleton beans 以前) onRefresh(); // 註冊事件監聽器,監聽器須要實現 ApplicationListener 接口。這也不是咱們的重點,過 registerListeners(); // 重點,重點,重點 // 初始化全部的 singleton beans //(lazy-init 的除外) finishBeanFactoryInitialization(beanFactory); // 最後,廣播事件,ApplicationContext 初始化完成 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. // 銷燬已經初始化的 singleton 的 Beans,以避免有些 bean 會一直佔用資源 destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
核心流程就是 try 代碼塊裏的內容,咱們應該瞭解總體原理,本篇文章並不能逐行逐句分析。若是那樣作,徹底就變成一部字典了……
bean 加載的調用函數:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 提取對應 bean 的名字 final String beanName = transformedBeanName(name); Object bean; // 1. 重要,重要,重要! // 建立單例 bean 避免循環依賴,嘗試從緩存中獲取 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); } else { // 存在循環依賴 if (isPrototypeCurrentlyInCreation(beanName)) { // 原型模式直接拋出異常(循環依賴僅能在單例模式下解決) throw new BeanCurrentlyInCreationException(beanName); } // Check if bean definition exists in this factory. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { 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 if (requiredType != null) { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } // 若是不是僅僅作類型檢查,則是建立 bean,須要作記錄 if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { // 獲取 RootBeanDefinition,若是指定 beanName 是子 bean 的話,須要合併父類屬性 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); // 若存在依賴,須要遞歸實例化依賴的 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); } } } // 建立 bean 實例 // Singleton 模式的建立 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); } // Prototype 模式的建立 else if (mbd.isPrototype()) { 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; } } // 檢測 requiredType 是否爲 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.isTraceEnabled()) { logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; }
能夠看到 bean 的加載是至關複雜的。加載的步驟大體以下:
前面提到了 BeanFactory,這裏又來了個 FactoryBean …… 聽說 Spring 提供了 70 多個 FactoryBean 的實現,可見其在 Spring 框架中的地位。它們隱藏了實例化複雜 bean 的細節,給上層應用帶來便捷。
public interface FactoryBean<T> { // 返回 FactoryBean 建立的 bean 實例,若是 isSingleton() 返回 true,則該實例會放到 Spring 容器的單例緩存池中 @Nullable T getObject() throws Exception; // 返回 FactoryBean 建立的 bean 類型 @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } }
循環依賴就是循環引用
,兩個或多個 bean 相互之間持有對方。那麼 Spring 是如何解決循環依賴的?
在 Spring 中循環依賴一共有 3 種狀況:
其中構造器循環依賴是沒法解決的,由於一個 bean 建立時首先要通過構造器,可是構造器相互依賴,就至關於 Java 中多線程死鎖。
setter 注入形成的依賴是經過 Spring 容器提早暴露剛完成構造器注入但未完成其餘步驟(如 setter 注入)的 bean 來完成的,並且只能解決單例做用域的 bean 循環依賴
。經過提早暴露一個單例工廠方法,從而使其餘 bean 能引用到該 bean,代碼以下:
@Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }
其中 earlySingletonObjects 的定義爲:
/** Cache of early singleton objects: bean name to bean instance. */ private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
對於 prototype 做用域的 bean,Spring 容器沒法完成依賴注入,由於 Spring 容器不緩存 prototype 做用域的 bean。
面試的話,Spring 的核心就在這裏了,不過只要記住大致流程就行。
coding 筆記、點滴記錄,之後的文章也會同步到公衆號(Coding Insight)中,但願你們關注_
代碼和思惟導圖在 GitHub 項目中,歡迎你們 star!