Spring 學習記錄8 初識XmlWebApplicationContext(2)

主題

接上文Spring 學習記錄7 初識XmlWebApplicationContexthtml

 

refresh方法

refresh方法是定義在父類AbstractApplicationContext中的.它內部會調用不少方法.有一些是在子類中實現的.算是模板方法的設計模式吧.主要做用就是初始化wac加載各類bean等做用.web

 1 @Override
 2     public void refresh() throws BeansException, IllegalStateException {
 3         synchronized (this.startupShutdownMonitor) {
 4             // Prepare this context for refreshing.
 5             // 記錄開始wac開始初始化的時間,設置激活標記,servlet的相關param設置到env(以前作過1次),校驗env中必須的props
 6             prepareRefresh();
 7 
 8             // Tell the subclass to refresh the internal bean factory.
 9             // 刷新初始化BF並獲取它,將舊的BF裏的bean刪掉,新建1個BF,加載XML配置文件
10             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
11 
12             // Prepare the bean factory for use in this context.
13             prepareBeanFactory(beanFactory);
14 
15             try {
16                 // Allows post-processing of the bean factory in context subclasses.
17                 postProcessBeanFactory(beanFactory);
18 
19                 // Invoke factory processors registered as beans in the context.
20                 invokeBeanFactoryPostProcessors(beanFactory);
21 
22                 // Register bean processors that intercept bean creation.
23                 registerBeanPostProcessors(beanFactory);
24 
25                 // Initialize message source for this context.
26                 initMessageSource();
27 
28                 // Initialize event multicaster for this context.
29                 initApplicationEventMulticaster();
30 
31                 // Initialize other special beans in specific context subclasses.
32                 onRefresh();
33 
34                 // Check for listener beans and register them.
35                 registerListeners();
36 
37                 // Instantiate all remaining (non-lazy-init) singletons.
38                 finishBeanFactoryInitialization(beanFactory);
39 
40                 // Last step: publish corresponding event.
41                 finishRefresh();
42             } catch (BeansException ex) {
43                 logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
44 
45                 // Destroy already created singletons to avoid dangling resources.
46                 destroyBeans();
47 
48                 // Reset 'active' flag.
49                 cancelRefresh(ex);
50 
51                 // Propagate exception to caller.
52                 throw ex;
53             }
54         }
55     }
View Code

 

prepareRefresh方法

第一個被調用的方法就是它設計模式

主要做用:session

記錄開始wac開始初始化的時間,設置激活標記,servlet的相關param設置到env(以前作過1次),校驗env中必須的propsapp

 1     /**
 2      * Prepare this context for refreshing, setting its startup date and
 3      * active flag as well as performing any initialization of property sources.
 4      * 記錄開始wac開始初始化的時間,設置激活標記,servlet的相關param設置到env(以前作過1次),校驗env中必須的props
 5      */
 6     protected void prepareRefresh() {
 7         this.startupDate = System.currentTimeMillis();
 8         this.active.set(true);
 9 
10         if (logger.isInfoEnabled()) {
11             logger.info("Refreshing " + this);
12         }
13 
14         // Initialize any placeholder property sources in the context environment
15         // 講servlet的config和context裏的params賦值給env..以前已經作過一次了,這個wac可能會由servlet初始化,這樣的話ServletConfig就不會爲空
16         initPropertySources();
17 
18         // Validate that all properties marked as required are resolvable
19         // see ConfigurablePropertyResolver#setRequiredProperties
20         // 在env中有一些properties是必須的,校驗這些props.沒有就拋出異常
21         getEnvironment().validateRequiredProperties();
22     }

L16..這個方法作了什麼直接看註釋吧..ide

 1     /**
 2      * {@inheritDoc}
 3      * <p>Replace {@code Servlet}-related property sources.
 4      */
 5     @Override
 6     protected void initPropertySources() {
 7         ConfigurableEnvironment env = getEnvironment();
 8         if (env instanceof ConfigurableWebEnvironment) {
 9             ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);
10         }
11     }

就是拿servletContext和servletConfig去填充env....和以前作的同樣....若是是listener初始化的話這裏servletConfig確定是空的.函數

 

L21 對env裏的必須的屬性進行校驗.若是這些屬性不存在的話就報錯.(可是我源碼裏搜索了一下並無找到調用設置必須屬性的地方...不知道怎麼使用才能標記屬性爲必須....)post

 

obtainFreshBeanFactory方法

主要做用:學習

刷新初始化BF並獲取它,將舊的BF裏的bean刪掉,新建1個BF,加載XML配置文件ui

 1     /**
 2      * Tell the subclass to refresh the internal bean factory.
 3      * 刷新初始化BF並獲取它,將舊的BF裏的bean刪掉,新建1個BF,加載XML配置文件
 4      *
 5      * @return the fresh BeanFactory instance
 6      * @see #refreshBeanFactory()
 7      * @see #getBeanFactory()
 8      */
 9     protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
10         refreshBeanFactory(); // 刷新BF
11         ConfigurableListableBeanFactory beanFactory = getBeanFactory();
12         if (logger.isDebugEnabled()) {
13             logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
14         }
15         return beanFactory;
16     }

L10 refreshBeanFactory(); 

 1     /**
 2      * This implementation performs an actual refresh of this context's underlying
 3      * bean factory, shutting down the previous bean factory (if any) and
 4      * initializing a fresh bean factory for the next phase of the context's lifecycle.
 5      */
 6     @Override
 7     protected final void refreshBeanFactory() throws BeansException {
 8         if (hasBeanFactory()) {
 9             destroyBeans(); // 刪除全部單例bean
10             closeBeanFactory(); // wac中的BF成員域=null.
11         }
12         try {
13             DefaultListableBeanFactory beanFactory = createBeanFactory(); // 建立1個新的DefaultListableBeanFactory
14             beanFactory.setSerializationId(getId()); // 設置ID
15             customizeBeanFactory(beanFactory); // wac 中的屬性 allowBeanDefinitionOverriding allowCircularReferences 覆蓋BF
16             loadBeanDefinitions(beanFactory); // 加載BeanDefinitions.
17             synchronized (this.beanFactoryMonitor) {
18                 this.beanFactory = beanFactory;
19             }
20         } catch (IOException ex) {
21             throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
22         }
23     }
View Code

主要做用就是先把以前的beanfactory裏建立的bean都銷燬,而後銷燬beanfactory.

而後新建1個DefaultListableBeanFactory,並配置一些經過wac配置的屬性.

再加載一下bean的配置.在這裏由於wac是XmlWebApplicationContext,因此bean的配置確定是寫在XML裏的了.

最後把bf對象設置到wac的成員域上.

 

L11獲得以前設置的新的BF並在L15返回...

 

prepareBeanFactory方法

主要做用:

1.設置BF解析bean配置須要用到的一些對象好比env. 2.註冊一些BeanPostProcessor好比ApplicationContextAwareProcessor去設置Aware須要的對象 3.忽略一些特定class注入的對象,設置一些特定class注入的對象爲指定值 4.將一些env中的properties map當作bean註冊到BF中

 1 /**
 2      * Configure the factory's standard context characteristics,
 3      * such as the context's ClassLoader and post-processors.
 4      *
 5      * @param beanFactory the BeanFactory to configure
 6      */
 7     protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 8         // Tell the internal bean factory to use the context's class loader etc.
 9         // BF須要解析屬性或者轉化須要用到env和其餘相關的類.從wac中設置進去
10         beanFactory.setBeanClassLoader(getClassLoader());
11         beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
12         beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
13 
14         // Configure the bean factory with context callbacks.
15         // 由於bean是在BF中建立的,因此若是他們須要用到wac的callback好比ApplicationEventPublisherAware的方法或者ApplicationContextAware,
16         // 那就須要再BF生成bean的時候注入applicationcontext或者它的相關類.好比env
17         beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
18         beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
19         beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
20         beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
21         beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
22         beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
23 
24         // BeanFactory interface not registered as resolvable type in a plain factory.
25         // MessageSource registered (and found for autowiring) as a bean.
26         // 若是要注入如下類型的bean,直接使用這些對象
27         beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
28         beanFactory.registerResolvableDependency(ResourceLoader.class, this);
29         beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
30         beanFactory.registerResolvableDependency(ApplicationContext.class, this);
31 
32         // Detect a LoadTimeWeaver and prepare for weaving, if found.
33         if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
34             beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
35             // Set a temporary ClassLoader for type matching.
36             beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
37         }
38 
39         // Register default environment beans.
40         // 將一些properties當作bean放到BF中
41         if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
42             beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
43         }
44         if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
45             beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
46         }
47         if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
48             beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
49         }
50     }

第一個代碼塊就是設置一些BF解析bean須要用到的對象.好比env.

第二個代碼塊就是add了一些XXXAwareProcess.好比applicationContextAware...BF在建立這個bean之後會調用ApplicationContextAwareProcessor的回調函數去注入applicationContext.

而後忽略了一些接口,他們不會被注入實現類.

第三個代碼塊配置了一些接口的注入的實現類.

第四個代碼又注入了一個BeanPostProcessor,這個彷佛和AOP有關係.沒研究過.

第五個代碼塊就是把env中的一些props當作bean註冊到BF中去.

 

postProcessBeanFactory方法

又是1個模板方法.能夠對BF進行一些加工定製.

在web環境下有重寫過.

主要做用:

1.設置一個BeanPostProcess爲ServletContextAware的實現類注入servlet相關對象
2.在BF中增長requetsScope等Scope
3.把servletContext,Config,ServletInitParams,ServletAttribute當作Bean註冊到BF中
 1     /**
 2      * Register request/session scopes, a {@link ServletContextAwareProcessor}, etc.
 3      * 1.設置一個BeanPostProcess爲ServletContextAware的實現類注入servlet相關對象
 4      * 2.在BF中增長requetsScope等Scope
 5      * 3.把servletContext,Config,ServletInitParams,ServletAttribute當作Bean註冊到BF中
 6      *
 7      */
 8     @Override
 9     protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
10         // 設置一個BeanPostProcess爲ServletContextAware的實現類注入servlet相關對象
11         beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
12         beanFactory.ignoreDependencyInterface(ServletContextAware.class);
13         beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
14 
15         // 在BF中增長requetsScope等Scope
16         WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
17         // 把servletContext,Config,ServletInitParams,ServletAttribute當作Bean註冊到BF中
18         WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
19     }

 

invokeBeanFactoryPostProcessors方法

初始化並調用配置的BeanFactoryPostProcessor..具體比較複雜.等後續更多學習之後再分享.

 

registerBeanPostProcessors方法

基本同invokeBeanFactoryPostProcessors方法,這是這裏不會調用BeanPostProcess只是向BF裏註冊而已.具體比較複雜.等後續更多學習之後再分享.

相關文章
相關標籤/搜索