引伸: 其實一開始不想寫這篇文章的 , 奈何發現市面上的文章大部分都是隻知其一;不知其二 . 索性整理一篇文章方便之後閱讀查閱
此次就不一開始就長篇大論了 , 先說一個問題 ,爲啥咱們要研究spring 中bean的初始化順序java
spring 框架是個啥? -> 本質上是一個IOC框架,解決依賴問題的玩意 , 依賴問題的核心承載點是啥? 是對象javabean , 因此若是把這一塊搞明白了,其實整個spring框架已經差很少搞透徹了.spring
其實扒開spring的外衣 , 其實最核心的東西是BeanFactory , spring本身能找到的全部的java bean 全在裏面 , 這個就是整個spring的數據中心緩存
若是讓我說spring最大的成就是什麼 , 我認爲spring最大的成就就是實現整個容器中java對象邏輯的託管功能 , 也就是我認爲的IOC
這個是spring整個java對象管理運行的開端,我稱它爲始祖種子類注意永遠記住spring是一個龐大臃腫功能強大的java框架 , 因此ApplicationContext的實現類特多,挑幾個重點來講多線程
這兩個類都有繼承自AbstractApplication 全部的spring對象初始化的時候都會調用這個通用的類 , 整個bean初始化,容器加載相關的邏輯都是在這裏面的
我認爲整個IOC過程當中最應該關注的就是這兩個問題 1. bean何時初始化的? 怎麼初始化的? 2. bean之間的依賴關係是何時? 是怎麼解決的? 3. 特殊狀態的javabean好比lookup和lazy是如何作的
spring中bean的初始化的過程 , 我認爲分爲以下的幾個過程app
這裏梳理一下他們的過程
這一步中 ClassPathXMLApplicationContext和 AnnotationConfigApplicationContext的操做是不一樣的
ClassPathApplicationContext 在spring中屬於元老了 , 他的着一塊的支持是在AbstractApplicationContext中的refresh()方法(下面會給出源碼)中實現的
最核心的邏輯是在ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();這一行中框架
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); return getBeanFactory(); }
這裏其實知道結論就行了 ,沒有必要追究細節 , 這裏spring將會經過spring的xml文件生成一系列的javabean的包裝bean -> BeanDefinition ,
而後放入默認生成的DefaultListableBeanFactory之中, 注意在spring中 全部的java bean在解析的過程當中都會變成 BeanDefinition(有些特殊的單例不是用BeanDefinition封裝的)ide
這個須要重點關注一下 , 這個context和classPathXmLApplicationContext有必定的區別 , 他是繼承自GenericApplicationContext , GenericApplicationContext是新一代spring使用註解進行bean配置的核心Context首先注意下這個ApplicationContext的構造方法函數
AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 都是初始化用來將使用class或者basePackages名稱加載的BeanDefinition註冊進GenericApplicationContext的工具類工具
//將指定的java bean的配置類對象 public AnnotationConfigApplicationContext(Class<?>... componentClasses) { this(); register(componentClasses); refresh(); } //將制定的包下全部的配置類對象 public AnnotationConfigApplicationContext(String... basePackages) { this(); scan(basePackages); refresh(); } //初始化註冊BeanDefinition所須要的加載器 -> 這兩個方法很重要的 , 初始化了不少process好比AutowiredAnnotationBeanPostProcessor和 // CommonAnnotationBeanPostProcessor用來處理@Autowrite註解等等 public AnnotationConfigApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
最核心的方法AbstractAplication的refresh()方法 , 這個方法完成了整個spring聲明週期的初始化
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 準備,記錄容器的啓動時間startupDate, 標記容器爲激活,初始化上下文環境如文件路徑信息,驗證必填屬性是否填寫 prepareRefresh(); // 獲取新的beanFactory,銷燬原有beanFactory、爲每一個bean生成BeanDefinition等 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 初始化beanfactory的各類屬性 prepareBeanFactory(beanFactory); try { // 模板方法,此時,全部的beanDefinition已經加載,可是尚未實例化。 //容許在子類中對beanFactory進行擴展處理。好比添加ware相關接口自動裝配設置,添加後置處理器等,是子類擴展prepareBeanFactory(beanFactory)的方法 postProcessBeanFactory(beanFactory); // 實例化並調用全部註冊的beanFactory後置處理器(實現接口BeanFactoryPostProcessor的bean,在beanFactory標準初始化以後執行) invokeBeanFactoryPostProcessors(beanFactory); // 實例化和註冊beanFactory中擴展了BeanPostProcessor的bean //例如: // AutowiredAnnotationBeanPostProcessor(處理被@Autowired註解修飾的bean並注入) // RequiredAnnotationBeanPostProcessor(處理被@Required註解修飾的方法) // CommonAnnotationBeanPostProcessor(處理@PreDestroy、@PostConstruct、@Resource等多個註解的做用)等。 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // 模板方法,在容器刷新的時候能夠自定義邏輯,不一樣的Spring容器作不一樣的事情。 onRefresh(); // 註冊監聽器,廣播early application events registerListeners(); // 實例化全部剩餘的(非懶加載)單例 // 好比invokeBeanFactoryPostProcessors方法中根據各類註解解析出來的類,在這個時候都會被初始化。 // 實例化的過程各類BeanPostProcessor開始起做用。 finishBeanFactoryInitialization(beanFactory); // refresh作完以後須要作的其餘事情。 // 清除上下文資源緩存(如掃描中的ASM元數據) // 初始化上下文的生命週期處理器,並刷新(找出Spring容器中實現了Lifecycle接口的bean並執行start()方法)。 // 發佈ContextRefreshedEvent事件告知對應的ApplicationListener進行響應的操做 finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); } } }
咱們只要注意這個方法 finishBeanFactoryInitialization() spring全部非內置的單例 javabean都是在這裏初始化的 , 主要是下面的這一行
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { ... // Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons(); }
這行作了beanFactory中全部單例 javabean初始化和依賴處理的, 進入看一下post
@Override public void preInstantiateSingletons() throws BeansException { .... // 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方法來盡心初始化的-> 而這個方法一樣也是咱們每次使用ApplicationContext獲取對象的時候所須要調用的類這個getBean方法很是長,其實本質上就是嘗試獲取一個javabean,內部實現了bean的建立,依賴管理等等的邏輯,貼一個單例模式的核心代碼吧
@SuppressWarnings("unchecked") protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { .... // Create bean instance. if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } .... }
外層的getSingleton 方法天然就是獲取單例而其中的會掉就是當單例不存在的時候,進行建立的邏輯,進入一下這個createBean
這裏代碼依然不少可是這個類最終依賴得了doCreateBean方法,因此直接看doCreateBean方法裏有啥,可是這裏執行了一個前置處理邏輯(postProcessBeforeInstantiation)方法來超前處理bean初始化
try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. 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 { Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; }
接下來就是重點了doCreateBean方法,解決了循環引用問題和實現提前曝光的邏輯都是在這裏
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { ...... // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); 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 { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
這裏有幾個重點
- 咱們的javabean屬性注入是在 populateBean方法中實現的,他的內部邏輯是使用了遞歸來循環的填衝屬性. 這裏也處理了構造函數等等依賴關係.
這裏要插一句AutoWriterAnnotionBeanPostProcessor
AutoWriterAnnotionBeanPostProcessor , 在這裏有一個特殊的處理邏輯能夠借鑑一下
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // Quick check on the concurrent map first, with minimal locking. InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { synchronized (this.injectionMetadataCache) { metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) { if (metadata != null) { metadata.clear(pvs); } metadata = buildAutowiringMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); } } } return metadata; }
AutoWriterAnnotionBeanPostProcessor 將須要的屬性,使用反射並將反射緩存了一下(injectionMetadataCache) , 來加快性能
- 依賴關係處理
其實看上面doCreate的邏輯有一個earlySingletonExposure變量, spring在執行到這裏的時候將會自動的將這個尚未進行初始化的類(也就是當bean爲單例 && 容器配置容許循環依賴 && bean正在建立)的時候,將會在BeanFactory中設置第三級緩存, key是當前的bean的名稱,value是一個工廠方法 , 很簡單就是返回當前的類
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } return exposedObject; }
ps: spring 如何解決循環引用的?
這個能夠看一下spring的getBean的邏輯 , 其中有一段這樣的代碼
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; }
若是第一層緩存沒有找到,就從早起類裏找若是早期類裏尚未,就使用工廠方法獲取
聊一下這三層緩存都幹了啥
第一層: 全部的初始化完成的單例bean
早期的bean: 被循環引用觸發了,而且尚未初始化完成的bean
第三層: 正在被初始化的bean
如何解決循環引用就很簡單了 , 若是A依賴了B 而且B依賴了A , 當A初始化了B的時候, B初始化時將會從第三層引用中獲取當前的提前曝光的類,從而實現瞭解決循環引用,而且spring的實現,還實現了多線程模式下也能夠進行循環應用的邏輯還沒完,整個生命週期尚未完全搞懂