本篇文章是針對上篇文章啓動原理的補充,主要介紹Spring IOC容器初始化中刷新應用上下文操做。java
查看源碼發現refreshContext(context) --> refresh(context) --> ApplicationContext.refresh()
因此咱們這裏詳細說一下這個refresh()方法。
代碼以下:web
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //第一步:容器刷新前的準備,設置上下文狀態,獲取屬性,驗證必要的屬性等 prepareRefresh(); //第二步:獲取新的beanFactory,銷燬原有beanFactory、爲每一個bean生成BeanDefinition等,注意此處是獲取新的,銷燬舊的,這就是刷新的意義(Spring容器裏經過BeanDefinition對象來表示Bean,BeanDefinition描述了Bean的配置信息。) ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //第三步:配置標準的beanFactory,設置ClassLoader,設置SpEL表達式解析器等 prepareBeanFactory(beanFactory); try { //第四步:在全部的beanDenifition加載完成以後,bean實例化以前執行。好比在beanfactory加載完成全部的bean後,想修改其中某個bean的定義,或者對beanFactory作一些其餘的配置,就能夠在子類中對beanFactory進行後置處理。 postProcessBeanFactory(beanFactory); //第五步:實例化並調用全部註冊的beanFactory後置處理器(實現接口BeanFactoryPostProcessor的bean) invokeBeanFactoryPostProcessors(beanFactory); //第六步:實例化和註冊beanFactory中擴展了BeanPostProcessor的bean。 //例如: AutowiredAnnotationBeanPostProcessor(處理被@Autowired註解修飾的bean並注入) //RequiredAnnotationBeanPostProcessor(處理被@Required註解修飾的方法) //CommonAnnotationBeanPostProcessor(處理@PreDestroy、@PostConstruct、@Resource等多個註解的做用)等。 registerBeanPostProcessors(beanFactory); //第七步:初始化國際化工具類MessageSource initMessageSource(); //第八步:初始化應用事件廣播器。這是觀察者模式的典型應用。咱們知道觀察者模式由主題Subject和Observer組成。廣播器至關於主題Subject,其包含多個監聽器。當主題發生變化時會通知全部的監聽器。初始化應用消息廣播器,並放入"ApplicationEventMulticaster" Bean中 initApplicationEventMulticaster(); //第九步:這個方法在AnnotationApplicationContex上下文中沒有實現,留給子類來初始化其餘的Bean,是個模板方法,在容器刷新的時候能夠自定義邏輯(子類本身去實現邏輯),不一樣的Spring容器作不一樣的事情 onRefresh(); //第十步:註冊監聽器,而且廣播early application events,也就是早期的事件 registerListeners(); //第十一步:初始化剩下的單例(非懶加載的單例類)(並invoke BeanPostProcessors) //實例化全部剩餘的(非懶加載)單例Bean。(也就是咱們本身定義的那些Bean) //好比invokeBeanFactoryPostProcessors方法中根據各類註解解析出來的類,在這個時候都會被初始化,掃描的@Bean之類的, //實例化的過程各類BeanPostProcessor開始起做用 finishBeanFactoryInitialization(beanFactory); //第十二步:完成刷新過程,通知生命週期處理器lifecycleProcessor完成刷新過程,同時發出ContextRefreshEvent通知別人 //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); } //若是刷新失敗那麼就會將已經建立好的單例Bean銷燬掉 destroyBeans(); //重置context的活動狀態 告知是失敗的 cancelRefresh(ex); //拋出異常 throw ex; } finally { // 失敗與否,都會重置Spring內核的緩存。由於可能再也不須要metadata給單例Bean了。 resetCommonCaches(); } } }
protected void prepareRefresh() { //記錄容器啓動時間,而後設立對應的標誌位 this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); // 打印info日誌:開始刷新當前容器了 if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // 這是擴展方法,由子類去實現,能夠在驗證以前爲系統屬性設置一些值能夠在子類中實現此方法 // 由於咱們這邊是AnnotationConfigApplicationContext,能夠看到無論父類仍是本身,都什麼都沒作,因此此處先忽略 initPropertySources(); //屬性文件驗證,確保須要的文件都已經放入環境中 getEnvironment().validateRequiredProperties(); //初始化容器,用於裝載早期的一些事件 this.earlyApplicationEvents = new LinkedHashSet<>(); }
obtainFreshBeanFactory()方法會解析全部Spring配置文件(一般咱們會放在 resources 目錄下),將全部 Spring 配置文件中的 bean 定義封裝成 BeanDefinition,加載到 BeanFactory中。常見的,若是解析到<context:component-scan base-package="" /> 註解時,會掃描 base-package 指定的目錄,將該目錄下使用指定註解(@Controller、@Service、@Component、@Repository)的 bean 定義也一樣封裝成 BeanDefinition,加載到 BeanFactory 中。spring
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { //初始化BeanFactory refreshBeanFactory(); //返回初始化以後的BeanFactory ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
protected final void refreshBeanFactory() throws BeansException { //判斷是否已經存在BeanFactory,存在則銷燬全部Beans,而且關閉BeanFactory if (hasBeanFactory()) { //銷燬全部的bean destroyBeans(); //關閉並銷燬BeanFactory closeBeanFactory(); } try { //建立具體的beanFactory,這裏建立的是DefaultListableBeanFactory,最重要的beanFactory spring註冊及加載bean就靠它 DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); //定製BeanFactory,包括是否容許覆蓋同名稱的不一樣定義的對象以及循環依賴 customizeBeanFactory(beanFactory); //這個就是最重要的了,加載全部的Bean配置信息(屬於模版方法,由子類去實現加載的方式) loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { //allowBeanDefinitionOverriding屬性是指是否允對一個名字相同但definition不一樣進行從新註冊,默認是true。 if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } //allowCircularReferences屬性是指是否容許Bean之間循環引用,默認是true. if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } }
實現loadBeanDefinitions()的子類有多種,如AbstractXmlApplicationContext類提供了基於XML的加載實現,AnnotationConfigWebApplicationContext類提供了在webapp的場景下基於註解配置的加載實現,XmlWebApplicationContext類提供了在webapp場景下基於xml配置的加載實現,XmlPortletApplicationContext提供了在portalet下基於xml配置的加載實現,GroovyWebApplicationContext類提供了基於groovy腳本配置的加載實現。apache
下面以AnnotationConfigWebApplicationContext#loadBeanDefinitions()方法爲例看下代碼。數組
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) { //初始化這個腳手架 其實就是直接new出實例 AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory); ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory); // 生成Bean的名稱的生成器,若是本身沒有setBeanNameGenerator(能夠自定義),這裏目前爲null BeanNameGenerator beanNameGenerator = getBeanNameGenerator(); if (beanNameGenerator != null) { reader.setBeanNameGenerator(beanNameGenerator); scanner.setBeanNameGenerator(beanNameGenerator); //若咱們註冊了beanName生成器,那麼就會註冊進容器裏面 beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator); } //這是給reader和scanner註冊scope的解析器 此處爲null ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver(); if (scopeMetadataResolver != null) { reader.setScopeMetadataResolver(scopeMetadataResolver); scanner.setScopeMetadataResolver(scopeMetadataResolver); } //咱們能夠本身指定annotatedClasses 配置文件,同時也能夠交給下面掃描 if (!this.annotatedClasses.isEmpty()) { // 這裏會把全部的配置文件輸出=======info日誌 請注意觀察控制檯 if (logger.isDebugEnabled()) { logger.debug("Registering annotated classes: [" + StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]"); } // 如果指明的Bean,就交給reader去處理 reader.register(ClassUtils.toClassArray(this.annotatedClasses)); } // 也能夠是包掃描的方式,掃描配置文件的Bean if (!this.basePackages.isEmpty()) { if (logger.isDebugEnabled()) { logger.debug("Scanning base packages: [" + StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]"); } scanner.scan(StringUtils.toStringArray(this.basePackages)); } // 此處的意思是,也能夠以全類名的形式註冊。好比能夠調用setConfigLocations設置(這在xml配置中使用較多) 能夠是全類名,也能夠是包路徑 String[] configLocations = getConfigLocations(); if (configLocations != null) { for (String configLocation : configLocations) { try { Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader()); if (logger.isTraceEnabled()) { logger.trace("Registering [" + configLocation + "]"); } reader.register(clazz); } catch (ClassNotFoundException ex) { if (logger.isTraceEnabled()) { logger.trace("Could not load class for config location [" + configLocation + "] - trying package scan. " + ex); } int count = scanner.scan(configLocation); // 發現不是全類名,那就看成包掃描 if (count == 0 && logger.isDebugEnabled()) { logger.debug("No annotated classes found for specified class/package [" + configLocation + "]"); } } } } }
該方法主要是解析咱們項目配置的 application.xml、xxx.xml 定義的import、bean、resource、profile、、、、、。或掃描註解 將其屬性封裝到BeanDefinition 對象中。緩存
上面提到的 「加載到 BeanFactory 中」 的內容主要指的是添加到如下3個緩存:
beanDefinitionNames緩存:全部被加載到 BeanFactory 中的 bean 的 beanName 集合。
beanDefinitionMap緩存:全部被加載到 BeanFactory 中的 bean 的 beanName 和 BeanDefinition 映射( Map<String, BeanDefinition>,beanName--key和beanDefinition--value)。
aliasMap緩存:全部被加載到 BeanFactory 中的 bean 的 beanName 和別名映射。tomcat
如今BeanFactory已經建立完成了,而且Config配置文件的Bean定義已經註冊完成了(備註:其它單例Bean是尚未解析的),下面的步驟大都把BeanFactory傳進去了,都是基於此Bean工廠的操做。session
至此,spring已經完成了對配置的解析,開始ApplicationContext功能上的擴展。app
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { //設置beanFactory的classLoader爲當前context的classLoader beanFactory.setBeanClassLoader(getClassLoader()); //設置EL表達式解析器(Bean初始化完成後填充屬性時會用到) beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); //設置屬性註冊解析器PropertyEditor 這個主要是對bean的屬性等設置管理的一個工具 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // 將當前的ApplicationContext對象交給ApplicationContextAwareProcessor類來處理,從而在Aware接口實現類中的注入applicationContext等等 // 添加了一個處理aware相關接口的beanPostProcessor擴展,主要是使用beanPostProcessor的postProcessBeforeInitialization()前置處理方法實現aware相關接口的功能 // 相似的還有下面的ResourceLoaderAware、ServletContextAware等等等等 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); //設置幾個忽略自動裝配的接口( 默認只有BeanFactoryAware被忽略,因此其它的須要自行設置) 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的類,就註冊beanFactory // 若是是ResourceLoader、ApplicationEventPublisher、ApplicationContext等等就注入當前對象this(applicationContext對象) // 此處registerResolvableDependency()方法注意:它會把他們加入到DefaultListableBeanFactory的resolvableDependencies字段裏面緩存這,供後面處理依賴注入的時候使用 DefaultListableBeanFactory#resolveDependency處理依賴關係 // 這也是爲何咱們能夠經過依賴注入的方式,直接注入這幾個對象好比ApplicationContext能夠直接依賴注入 // 可是須要注意的是:這些Bean,Spring的IOC容器裏實際上是沒有的。beanFactory.getBeanDefinitionNames()和beanFactory.getSingletonNames()都是找不到他們的,因此特別須要理解這一點 // 至於容器中沒有,可是咱們仍是能夠@Autowired直接注入的有哪些,請看下圖 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // 註冊這個Bean的後置處理器:在Bean初始化後檢查是否實現了ApplicationListener接口 // 是則加入當前的applicationContext的applicationListeners列表 這樣後面廣播事件也就方便了 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // 檢查容器中是否包含名稱爲loadTimeWeaver的bean,其實是增長Aspectj的支持 // AspectJ採用編譯期織入、類加載期織入兩種方式進行切面的織入 // 類加載期織入簡稱爲LTW(Load Time Weaving),經過特殊的類加載器來代理JVM默認的類加 if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { // 添加BEAN後置處理器:LoadTimeWeaverAwareProcessor // 在BEAN初始化以前檢查BEAN是否實現了LoadTimeWeaverAware接口, // 若是是,則進行加載時織入,即靜態代理。 beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // 注入一些系統環境的bean,好比environment、systemProperties、SystemEnvironment等 if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
附:IOC容器中沒有Bean,可是咱們仍是能夠依賴注入的Bean以下(resolvableDependencies):webapp
主要擴展: 1. 增長對SPEL語言的支持; 2. 增長對屬性編輯器的支持,這些PropertyEditors在這裏只是註冊,使用的時候是將bean包裝成BeanWrapper,包裝後的BeanWrapper的就包含了全部的這些PropertyEditors,以便後期給bean設置屬性的時候使用; 3. 增長對一些內置類(實際上就是前置處理器),好比Aware接口的信息注入; 4. 設置依賴功能可忽略的接口; 5. 註冊一些固定的bean,這些都是特殊的依賴解析,好比當註冊了BeanFactory.class的依賴解析以後,當bean的屬性注入的時候,一旦檢測到屬性爲BeanFactory類型便會將beanFactory的實例注入進去; 6. 增長對AspectJ的支持; 7. 將相關環境變量及屬性以單例模式註冊。
到這裏beanFactory都準備好了,子類能夠本身去實現本身的邏輯。因此postProcessBeanFactory這個模版方法用於子類對beanFactory進行後置處理。好比一些web的ApplicationContext,就實現了本身的邏輯,作一些本身的web相關的事情。此處咱們看下AbstractRefreshableWebApplicationContext#postProcessBeanFactory方法:
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { //註冊ServletContextAwareProcessor 這樣任意Bean均可以很方便的獲取到ServletContext了 同時忽略另外兩個,由於ServletContextAwareProcessor 都把事情都作了 beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig)); beanFactory.ignoreDependencyInterface(ServletContextAware.class); beanFactory.ignoreDependencyInterface(ServletConfigAware.class); //註冊web環境,包括request、session、golableSession、application WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext); //註冊servletContext、contextParamters、contextAttributes 、servletConfig單例bean WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig); }
invokeBeanFactoryPostProcessors執行BeanFactory後置處理器,前提是你已經在容器中註冊過此處理器了。這個接口跟BeanPostProcessor相似,能夠對bean的定義(配置元數據)進行處理,做用範圍是容器級的,只對本身的容器的bean進行處理。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // 1.getBeanFactoryPostProcessors(): 拿到當前應用上下文beanFactoryPostProcessors變量中的值 // 2.invokeBeanFactoryPostProcessors: 實例化並調用全部已註冊的BeanFactoryPostProcessor PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // 這裏就是定製:若是loadTimeWeaver這個Bean存在,那麼就會配置上運行時織入的處理器LoadTimeWeaverAwareProcessor if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } }
拿到當前應用上下文 beanFactoryPostProcessors 變量中的值.
public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() { return this.beanFactoryPostProcessors; }
它不是返回Spring容器裏面的Processors,而是你本身的註冊的(你本身手動set的),也就是說咱們本身手動調用set方法添加進去,就可以執行。並不須要本身配置@Bean或者在xml裏配置,那麼重點就在於PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors:
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { // 這個doc說明很清楚:無論怎麼樣,先執行BeanDefinitionRegistryPostProcessors // 須要注意的是BeanDefinitionRegistryPostProcessors 爲 BeanFactoryPostProcessor 的子接口 它新增了方法:void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) // BeanFactoryPostProcessor 的方法爲;void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; // 因此BeanDefinitionRegistryPostProcessors,咱們介入並改變Bean的一些定義信息 Set<String> processedBeans = new HashSet<>(); // 1.判斷beanFactory是否爲BeanDefinitionRegistry,beanFactory爲DefaultListableBeanFactory, // 而DefaultListableBeanFactory實現了BeanDefinitionRegistry接口,所以這邊爲true //1.只有此beanFactory是BeanDefinitionRegistry 才能執行BeanDefinitionRegistryPostProcessor,才能修改Bean的定義 (beanFactory爲DefaultListableBeanFactory,而DefaultListableBeanFactory實現了BeanDefinitionRegistry接口,所以這邊爲true) if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; // 用於存放普通的BeanFactoryPostProcessor List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>(); // 用於存放BeanDefinitionRegistryPostProcessor List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>(); 都是LinkedList,因此執行順序和set進去的順序是保持同樣的 // 2.首先處理入參中的beanFactoryPostProcessors // 遍歷全部的beanFactoryPostProcessors, 將BeanDefinitionRegistryPostProcessor和普通BeanFactoryPostProcessor區分開 for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) { if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { // 2.1 若是是BeanDefinitionRegistryPostProcessor BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; // 2.1.1 直接執行BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法 registryProcessor.postProcessBeanDefinitionRegistry(registry); // 2.1.2 添加到registryProcessors(用於最後執行postProcessBeanFactory方法) registryProcessors.add(registryProcessor); } else { // 2.2 不然,只是普通的BeanFactoryPostProcessor // 2.2.1 添加到regularPostProcessors(用於最後執行postProcessBeanFactory方法)regularPostProcessors.add(postProcessor); } } // 用於保存本次要執行的BeanDefinitionRegistryPostProcessor List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>(); // 3.調用全部實現PriorityOrdered接口的BeanDefinitionRegistryPostProcessor實現類 // 3.1 找出全部實現BeanDefinitionRegistryPostProcessor接口的Bean的beanName String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); // 3.2 遍歷postProcessorNames for (String ppName : postProcessorNames) { // 3.3 校驗是否實現了PriorityOrdered接口 if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // 3.4 獲取ppName對應的bean實例, 添加到currentRegistryProcessors中, // beanFactory.getBean: 這邊getBean方法會觸發建立ppName對應的bean對象, 目前暫不深刻解析currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); // 3.5 將要被執行的加入processedBeans,避免後續重複執行 processedBeans.add(ppName); } } // 3.6 進行排序(根據是否實現PriorityOrdered、Ordered接口和order值來排序) sortPostProcessors(currentRegistryProcessors, beanFactory); // 3.7 添加到registryProcessors(用於最後執行postProcessBeanFactory方法) registryProcessors.addAll(currentRegistryProcessors); // 3.8 遍歷currentRegistryProcessors, 執行postProcessBeanDefinitionRegistry方法invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); // 3.9 執行完畢後, 清空currentRegistryProcessors currentRegistryProcessors.clear(); // 4.調用全部實現了Ordered接口的BeanDefinitionRegistryPostProcessor實現類(過程跟上面的步驟3基本同樣) // 4.1 找出全部實現BeanDefinitionRegistryPostProcessor接口的類, 這邊重複查找是由於執行完上面的BeanDefinitionRegistryPostProcessor, // 可能會新增了其餘的BeanDefinitionRegistryPostProcessor, 所以須要從新查找 postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 校驗是否實現了Ordered接口,而且還未執行過 if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); // 4.2 遍歷currentRegistryProcessors, 執行postProcessBeanDefinitionRegistry方法invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); // 5.最後, 調用全部剩下的BeanDefinitionRegistryPostProcessors boolean reiterate = true; while (reiterate) { reiterate = false; // 5.1 找出全部實現BeanDefinitionRegistryPostProcessor接口的類 postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { // 5.2 跳過已經執行過的 if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); // 5.3 若是有BeanDefinitionRegistryPostProcessor被執行, 則有可能會產生新的BeanDefinitionRegistryPostProcessor, // 所以這邊將reiterate賦值爲true, 表明須要再循環查找一次 reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); // 5.4 遍歷currentRegistryProcessors, 執行postProcessBeanDefinitionRegistry方法invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); } // 6.調用全部BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法(BeanDefinitionRegistryPostProcessor繼承自BeanFactoryPostProcessor) invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); // 7.最後, 調用入參beanFactoryPostProcessors中的普通BeanFactoryPostProcessor的postProcessBeanFactory方法 invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); } else { // Invoke factory processors registered with the context instance. invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory); } // 到這裏 , 入參beanFactoryPostProcessors和容器中的全部BeanDefinitionRegistryPostProcessor已經所有處理完畢, // 下面開始處理容器中的全部BeanFactoryPostProcessor // 8.找出全部實現BeanFactoryPostProcessor接口的類 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); // 用於存放實現了PriorityOrdered接口的BeanFactoryPostProcessor List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>(); // 用於存放實現了Ordered接口的BeanFactoryPostProcessor的beanName List<String> orderedPostProcessorNames = new ArrayList<>(); // 用於存放普通BeanFactoryPostProcessor的beanName List<String> nonOrderedPostProcessorNames = new ArrayList<>(); // 8.1 遍歷postProcessorNames, 將BeanFactoryPostProcessor按實現PriorityOrdered、實現Ordered接口、普通三種區分開 for (String ppName : postProcessorNames) { // 8.2 跳過已經執行過的 if (processedBeans.contains(ppName)) { // skip - already processed in first phase above } else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { // 8.3 添加實現了PriorityOrdered接口的BeanFactoryPostProcessor priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { // 8.4 添加實現了Ordered接口的BeanFactoryPostProcessor的beanName orderedPostProcessorNames.add(ppName); } else { // 8.5 添加剩下的普通BeanFactoryPostProcessor的beanName nonOrderedPostProcessorNames.add(ppName); } } // 9.調用全部實現PriorityOrdered接口的BeanFactoryPostProcessor // 9.1 對priorityOrderedPostProcessors排序 sortPostProcessors(priorityOrderedPostProcessors, beanFactory); // 9.2 遍歷priorityOrderedPostProcessors, 執行postProcessBeanFactory方法 invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // 10.調用全部實現Ordered接口的BeanFactoryPostProcessor List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(); for (String postProcessorName : orderedPostProcessorNames) { // 10.1 獲取postProcessorName對應的bean實例, 添加到orderedPostProcessors, 準備執行 orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } // 10.2 對orderedPostProcessors排序 sortPostProcessors(orderedPostProcessors, beanFactory); // 10.3 遍歷orderedPostProcessors, 執行postProcessBeanFactory方法 invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // 11.調用全部剩下的BeanFactoryPostProcessor List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(); for (String postProcessorName : nonOrderedPostProcessorNames) { // 11.1 獲取postProcessorName對應的bean實例, 添加到nonOrderedPostProcessors, 準備執行 nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } // 11.2 遍歷nonOrderedPostProcessors, 執行postProcessBeanFactory方法 invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); / 12.清除元數據緩存(mergedBeanDefinitions、allBeanNamesByType、singletonBeanNamesByType), // 由於後處理器可能已經修改了原始元數據,例如, 替換值中的佔位符... beanFactory.clearMetadataCache(); }
invokeBeanFactoryPostProcessors(beanFactory)這一步主要作了:
到這裏Bean工廠徹底準備好了,而且也註冊好了全部的Bean的定義信息(此時Bean還並無建立)。也完成了對配置文件的解析,能夠說Spring IOC容器的大部分準備工做已經完成了,接下來就是對Bean的一些初始化、操做
略。。。
略。。。
略。。。
在接觸SpringBoot以前咱們的web項目都是須要部署到web服務容器上,如tomcat、weblogic、JBoss等,而後啓動web容器真正運行咱們的系統。
SpringBoot給咱們帶來了一個全新的開發體驗,咱們能夠把web程序打成jar包,直接啓動,這得益於SpringBoot內置了容器,能夠直接啓動,本文將以Tomcat爲例,來看看SpringBoot是如何啓動Tomcat的,同時也將展開學習下Tomcat的源碼,瞭解Tomcat的設計。
啓動Tomcat是在「刷新上下文」操做中;Tomcat的啓動主要是初始化2個核心組件,鏈接器(Connector)和容器(Container),一個Tomcat實例就是一個Server,一個Server包含多個Service,也就是多個應用程序,每一個Service包含多個鏈接器(Connetor)和一個容器(Container),而容器下又有多個子容器,按照父子關係分別爲:Engine,Host,Context,Wrapper,其中除了Engine外,其他的容器都是能夠有多個。
在onReFresh建立內置tomcat,在finishRefresh啓動tomcat
tomcat的編碼有點意思 咱們獲取任何一個容器的時候,在他內部都會包含獲取其父容器的方法
onRefresh()方法是調用其子類的實現,根據咱們上文的分析,咱們這裏的子類是ServletWebServerApplicationContext。
//類:ServletWebServerApplicationContext protected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } } private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); //若是webServer 和servletContext 都爲空 if (webServer == null && servletContext == null) { //經過spring去加載ServletWebServerFactory ServletWebServerFactory factory = getWebServerFactory(); //建立webServer,這邊getSelfInitializer裏面就是咱們spring容器 this.webServer = factory.getWebServer(getSelfInitializer()); } else if (servletContext != null) { try { //若是servletContext 不爲空,調用ServletContextInitializer數組去啓動該容器, //即給改servletContext配置servlet,filters,listeners context-params 和attribute getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } //把咱們建立好的額webServer好servletcontext, // 更新到ConfigurableWebEnvironment中 // 前提是自己ConfigurableWebEnvironment就有這兩個屬性 initPropertySources(); }
到這裏,createWebServer()就是啓動web服務,可是尚未真正啓動Tomcat,既然webServer是經過ServletWebServerFactory來獲取的,咱們就來看看這個工廠的真面目。
根據上圖咱們發現,工廠類是一個接口,各個具體服務的實現是由各個子類來實現的,因此咱們就去看看TomcatServletWebServerFactory.getWebServer()的實現。
建立webServer的過程,initializers就是spring的容器 @Override public WebServer getWebServer(ServletContextInitializer... initializers) { //建立tomcat Tomcat tomcat = new Tomcat(); //建立一個臨時目錄個給當前webServer,並註冊了一個鉤子在程序退出的時候刪除文件夾 File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat"); //設置tomcat的baseDir,baseDir是給臨時文件使用的, //應該是第一個被調用的方法,若是該方法沒被調用, // 咱們默認調用系統屬性system properties - catalina.base, catalina.home //或者[user.dir]/tomcat.$PORT tomcat.setBaseDir(baseDir.getAbsolutePath()); //根據protocol(默認是Http11NioProtocol)建立connector, // 這邊的邏輯是先看下是不是http協議,而後再看看是不是AJP協議, // 若是都不是直接塞入協議的名字,而後下一步根據協議的名字調用class.forName獲得協議類, // 而後經過org.apache.catalina.STRICT_SERVLET_COMPLIANCE屬性設置整個tomcat的編碼是ISO_8859_1仍是UTF-8 Connector connector = new Connector(this.protocol); //給第一個service添加connector,這其中會初始化server(StandardServer)(server會初始化baseDir,設置初始化監聽關閉端口爲-1,這樣就不會被從端口關閉,建立標準的service(StandardServer))而後綁定二者 addConnector:尋找現有的connector數組,將connector添加進去並把connector和service互相綁定,而後啓動該connector tomcat.getService().addConnector(connector); //設置咱們自定義的端口號,添加server,bindOnInit屬性,添加咱們的協議,添加urlEncoding,設置ssl,compression customizeConnector(connector); //tomcat自己設置connector tomcat.setConnector(connector); //關閉自動部署 tomcat.getHost().setAutoDeploy(false); //設置backgroundProcessorDelay機制,若是backgroundProcessorDelay爲正值,那麼子容器的一些任務會有後臺線程幫忙處理,爲負值,則由當前容器一併處理。這些任務都是週期性的好比例如從新加載等。 爲engine配置上Valve,設置container configureEngine(tomcat.getEngine()); //給這個service添加額外的connector,從這能夠看出connector和service的關係是多對一 container和service是1對1 for (Connector additionalConnector : this.additionalTomcatConnectors) { tomcat.getService().addConnector(additionalConnector); } //準備一個context給engine,這裏咱們設置TomcatEmbeddedContext,這個是spring本身寫的,而後配置好 這個context的一些屬性 prepareContext(tomcat.getHost(), initializers); //啓動tomcat(即tomcat的容器被啓動,可是connector沒有啓動) return getTomcatWebServer(tomcat); }
根據上面的代碼,咱們發現其主要作了兩件事情,第一件事就是把Connnctor(咱們稱之爲鏈接器)對象添加到Tomcat中,第二件事就是configureEngine,這鏈接器咱們勉強能理解(不理解後面會述說),那這個Engine是什麼呢?咱們查看tomcat.getEngine()的源碼:
public Engine getEngine() { Service service = getServer().findServices()[0]; if (service.getContainer() != null) { return service.getContainer(); } Engine engine = new StandardEngine(); engine.setName( "Tomcat" ); engine.setDefaultHost(hostname); engine.setRealm(createDefaultRealm()); service.setContainer(engine); return engine; }
根據上面的源碼,咱們發現,原來這個Engine是容器,咱們繼續跟蹤源碼,找到Container接口。
上圖中,咱們看到了4個子接口,分別是Engine,Host,Context,Wrapper。咱們從繼承關係上能夠知道他們都是容器,Engine是最高級別的容器,其子容器是Host,Host的子容器是Context,Wrapper是Context的子容器,因此這4個容器的關係就是父子關係,也就是Engine>Host>Context>Wrapper。咱們再看看Tomcat類的源碼:
//部分源碼,其他部分省略。 public class Tomcat { //設置鏈接器 public void setConnector(Connector connector) { Service service = getService(); boolean found = false; for (Connector serviceConnector : service.findConnectors()) { if (connector == serviceConnector) { found = true; } } if (!found) { service.addConnector(connector); } } //獲取service public Service getService() { return getServer().findServices()[0]; } //設置Host容器 public void setHost(Host host) { Engine engine = getEngine(); boolean found = false; for (Container engineHost : engine.findChildren()) { if (engineHost == host) { found = true; } } if (!found) { engine.addChild(host); } } //獲取Engine容器 public Engine getEngine() { Service service = getServer().findServices()[0]; if (service.getContainer() != null) { return service.getContainer(); } Engine engine = new StandardEngine(); engine.setName( "Tomcat" ); engine.setDefaultHost(hostname); engine.setRealm(createDefaultRealm()); service.setContainer(engine); return engine; } //獲取server public Server getServer() { if (server != null) { return server; } System.setProperty("catalina.useNaming", "false"); server = new StandardServer(); initBaseDir(); // Set configuration source ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(new File(basedir), null)); server.setPort( -1 ); Service service = new StandardService(); service.setName("Tomcat"); server.addService(service); return server; } //添加Context容器 public Context addContext(Host host, String contextPath, String contextName, String dir) { silence(host, contextName); Context ctx = createContext(host, contextPath); ctx.setName(contextName); ctx.setPath(contextPath); ctx.setDocBase(dir); ctx.addLifecycleListener(new FixContextListener()); if (host == null) { getHost().addChild(ctx); } else { host.addChild(ctx); } //添加Wrapper容器 public static Wrapper addServlet(Context ctx, String servletName, Servlet servlet) { // will do class for name and set init params Wrapper sw = new ExistingStandardWrapper(servlet); sw.setName(servletName); ctx.addChild(sw); return sw; } }
閱讀Tomcat的getServer()咱們能夠知道,Tomcat的最頂層是Server,Server就是Tomcat的實例,一個Tomcat一個Server;經過getEngine()咱們能夠了解到Server下面是Service,並且是多個,一個Service表明咱們部署的一個應用,並且咱們還能夠知道,Engine容器,一個service只有一個;根據父子關係,咱們看setHost()源碼能夠知道,host容器有多個;同理,咱們發現addContext()源碼下,Context也是多個;addServlet()代表Wrapper容器也是多個,並且這段代碼也暗示了,其實Wrapper和Servlet是一層意思。另外咱們根據setConnector源碼能夠知道,鏈接器(Connector)是設置在service下的,並且是能夠設置多個鏈接器(Connector)。
根據上面分析,咱們能夠小結下:Tomcat主要包含了2個核心組件,鏈接器(Connector)和容器(Container),用圖表示以下:
一個Tomcat是一個Server,一個Server下有多個service,也就是咱們部署的多個應用,一個應用下有多個鏈接器(Connector)和一個容器(Container),容器下有多個子容器,關係用圖表示以下:
Engine下有多個Host子容器,Host下有多個Context子容器,Context下有多個Wrapper子容器。
在全部註冊的Bean中查找Listenter bean,註冊到消息廣播器中。
protected void registerListeners() { // 首先註冊靜態註冊的監聽器(代碼註冊的) for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // 獲取容器中全部配置的listener並註冊 String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // 對earlyApplicationEvents這些事件進行廣播,實際上就是遍歷全部的listener,找到能夠處理event的listener處理 Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
初始化剩下的非惰性單例,若是某個單例依賴了惰性的單例,那麼這個惰性的單例也會被初始化,這個很好理解吧。
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // 初始化ConversionService,跟PropertyEditor相似 if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } //則註冊默認的嵌入值解析器 //例如PropertyPlaceholderConfigurer bean)以前註冊過: //主要用於註解屬性值的解析。 if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } //單例bean初始化以前首先初始化LoadTimeWeaverAware,以支持aop,AspectJ String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } // Stop using the temporary ClassLoader for type matching. beanFactory.setTempClassLoader(null); //凍結bean定義(BeanDefinition),表示全部的bean定義進不被修改或進行進一步處理 beanFactory.freezeConfiguration(); //初始化非惰性單例,實際上就是遍歷全部的beanName,而後一一調用getBean() beanFactory.preInstantiateSingletons(); }
protected void finishRefresh() { //清除上下文級別(context-level)的資源緩存,好比由scanning產生的ASM元數據 clearResourceCaches(); //初始化LifecycleProcessor initLifecycleProcessor(); //使用LifecycleProcessor來啓動Lifecycle子類 getLifecycleProcessor().onRefresh(); //上下文刷新完成,發佈事件 publishEvent(new ContextRefreshedEvent(this)); // Participate in LiveBeansView MBean, if active. LiveBeansView.registerApplicationContext(this); }
初始化LifecycleProcessor的時候,跟初始化MessageResource同樣,沒有自定義的就是用默認的DefaultLifecycleProcessor。
getLifecycleProcessor().onRefresh()會使用咱們註冊的LyfecycleProcessor來啓動咱們註冊的SmartLifeCycle的子類。看一下代碼吧。
//默認的DefaultLifecycleProcessor.java public void onRefresh() { startBeans(true); this.running = true; }
private void startBeans(boolean autoStartupOnly) { //獲取全部的LifeCycle類型的bean Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans(); Map<Integer, LifecycleGroup> phases = new HashMap<>(); lifecycleBeans.forEach((beanName, bean) -> { //默認的DefaultLifecycleProcessor只會啓動SmartLifecycle的,或者非自動啓動的類型 //SmartLifecycle繼承了Phases接口 if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) { int phase = getPhase(bean); LifecycleGroup group = phases.get(phase); if (group == null) { group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly); //添加到須要啓動的集合中 phases.put(phase, group); } group.add(beanName, bean); } }); //啓動須要啓動的這些LifeCycle if (!phases.isEmpty()) { List<Integer> keys = new ArrayList<>(phases.keySet()); Collections.sort(keys); for (Integer key : keys) { phases.get(key).start(); } } }
這一步主要完成如下操做:
Spring刷新應用上下文操做簡要劃分爲12步操做流程:
1.準備刷新--->2.獲取刷新bean工廠--->3.準備bean工廠--->4.前處理bean工廠--->
5.調用bean工廠前處理器--->6.註冊bean前處理器--->7.初始化消息源--->8.初始化應用事件發佈器--->
9.刷新--->10.註冊監聽器--->11.完成bean工廠初始化--->12.完成刷新.