spring源碼解析-ApplicationContext解析


ApplicationContext和BeanFactory一樣都是bean的容器,而BeanFactory是一切Bean容器的父類,ApplicationContext繼承於BeanFactory(繼承之BeanFactory的子類)
ApplicationContext包含了BeanFactory的所有功能,並且擴展了其他功能。先從ApplicationContext的案例入手,代碼如下:
ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
ctx.getBean("myBean");

 可以看出ApplicationContext和BeanFactory的用法基本一樣,初始化之后就可以直接獲取Bean了,那么我們就先從ApplicationContext的初始化入手,也就是先從ClassPathXmlApplicationContext的構造函數入手,代碼如下:

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }
 1 public ClassPathXmlApplicationContext(
 2             String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
 3             throws BeansException {
 4 
 5         //調用父類的構造函數
 6         super(parent);
 7         //設置配置xml
 8         setConfigLocations(configLocations);
 9         //ApplicationContext初始化
10         if (refresh) {
11             refresh();
12         }
13     }

 

初始化配置xml可以傳入數組形式,設置方法setConfigLocations代碼如下:
 1 public void setConfigLocations(@Nullable String... locations) {
 2         if (locations != null) {
 3             Assert.noNullElements(locations, "Config locations must not be null");
 4             this.configLocations = new String[locations.length];
 5             for (int i = 0; i < locations.length; i++) {
 6                 this.configLocations[i] = resolvePath(locations[i]).trim();
 7             }
 8         }
 9         else {
10             this.configLocations = null;
11         }
12     }

 主要用於解析配置的xml信息,將xml路徑信息賦值給configLocations,設置了配置信息之后就需要對ApplicationContext進行初始化操作了,也就是最后一步的refresh方法了,代碼如下:

 1 @Override
 2     public void refresh() throws BeansException, IllegalStateException {
 3         synchronized (this.startupShutdownMonitor) {
 4             // Prepare this context for refreshing.
 5             //准備刷新
 6             prepareRefresh();
 7 
 8             // Tell the subclass to refresh the internal bean factory.
 9             //初始化BeanFactory,並進行XML文件讀取
10             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
11 
12             // Prepare the bean factory for use in this context.
13             //對BeanFactory進行各種功能擴展
14             prepareBeanFactory(beanFactory);
15 
16             try {
17                 // Allows post-processing of the bean factory in context subclasses.
18                 //子類覆蓋方法做額外對處理
19                 postProcessBeanFactory(beanFactory);
20 
21                 // Invoke factory processors registered as beans in the context.
22                 //激活各種BeanFactory處理器
23                 invokeBeanFactoryPostProcessors(beanFactory);
24 
25                 // Register bean processors that intercept bean creation.
26                 //注冊攔截Bean創建對Bean處理器,這里只是注冊,真正調用是在getBean對時候
27                 registerBeanPostProcessors(beanFactory);
28 
29                 // Initialize message source for this context.
30                 //為上下文初始化Message
31                 initMessageSource();
32 
33                 // Initialize event multicaster for this context.
34                 //初始化應用消息廣播器
35                 initApplicationEventMulticaster();
36 
37                 // Initialize other special beans in specific context subclasses.
38                 //留給子類來初始化其他對Bean
39                 onRefresh();
40 
41                 // Check for listener beans and register them.
42                 //在所有注冊對bean中尋找Lestener bean,注冊到消息廣播器中
43                 registerListeners();
44 
45                 // Instantiate all remaining (non-lazy-init) singletons.
46                 //初始化剩下對單例bean
47                 finishBeanFactoryInitialization(beanFactory);
48 
49                 // Last step: publish corresponding event.
50                 //完成刷新過程,通知生命周期處理器刷新過程,同時發出ContextRefreshEvent通知別人
51                 finishRefresh();
52             }
53 
54             catch (BeansException ex) {
55                 if (logger.isWarnEnabled()) {
56                     logger.warn("Exception encountered during context initialization - " +
57                             "cancelling refresh attempt: " + ex);
58                 }
59 
60                 // Destroy already created singletons to avoid dangling resources.
61                 destroyBeans();
62 
63                 // Reset 'active' flag.
64                 cancelRefresh(ex);
65 
66                 // Propagate exception to caller.
67                 throw ex;
68             }
69 
70             finally {
71                 // Reset common introspection caches in Spring's core, since we
72                 // might not ever need metadata for singleton beans anymore...
73                 resetCommonCaches();
74             }
75         }
76     }
77 }

 

主要過程為:
1.初始化前對准備工作,對系統屬性或者環境變量的驗證
2.初始化BeanFactory,並進行xml文件讀取,相當於復用了BeanFactory的配置文件讀取解析過程,相當於進行了一次BeanFactory的初始化,剩下的都是對BeanFactory的擴展了
3.對BeanFactory進行功能填充(如@Autowired @Qualifier注解對支持等)
4. 子類覆蓋父類方法做額外的處理(postProcessBeanFactory方法是空函數,方便子類進行擴展)
5.激活各種BeanFactory處理器
6.注冊攔截bean創建的bean處理器
7.剩下的可以看代碼中的注解
 
接下來再細看,初始化前的准備驗證直接跳過,直接看如何初始化BeanFactory的,
1 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
2         refreshBeanFactory();
3         return getBeanFactory();
4     }

第一步初始化BeanFactory,進行xml配置讀取解析

第二步返回BeanFactory

 1 @Override
 2     protected final void refreshBeanFactory() throws BeansException {
 3         if (hasBeanFactory()) {
 4             destroyBeans();
 5             closeBeanFactory();
 6         }
 7         try {
 8             DefaultListableBeanFactory beanFactory = createBeanFactory();
 9             beanFactory.setSerializationId(getId());
10             customizeBeanFactory(beanFactory);
11             loadBeanDefinitions(beanFactory);
12             synchronized (this.beanFactoryMonitor) {
13                 this.beanFactory = beanFactory;
14             }
15         }
16         catch (IOException ex) {
17             throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
18         }
19     }

 

大致過程如下:
1.創建DefaultListableBeanFactory對象,BeanFactory的初始化實際也是創建了這個對象
2.指定序列號ID
3.定制BeanFactory
4.加載BeanDefinition
5.使用全局變量記錄BeanFactory實例
 
這里的第三步的customizeBeanFactory方法是對BeanFactory的擴展,添加了@Qualifier和@Autowired的支持
loadBeanDefinitions方法是加載BeanDefinition,首先是加載Xml,使用XmlBeanDefinitionReader的loadBeanDefinitions方法進行配置文件的加載注冊和BeanFactory的邏輯一樣
 
在BeanFactory初始化之后就是對BeanFactory的擴展,也就是prepareBeanFactory方法及之后的內容
 
 1 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
 2         // Tell the internal bean factory to use the context's class loader etc.
 3         beanFactory.setBeanClassLoader(getClassLoader());
 4         beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
 5         beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
 6 
 7         // Configure the bean factory with context callbacks.
 8         beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
 9         beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
10         beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
11         beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
12         beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
13         beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
14         beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
15 
16         // BeanFactory interface not registered as resolvable type in a plain factory.
17         // MessageSource registered (and found for autowiring) as a bean.
18         beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
19         beanFactory.registerResolvableDependency(ResourceLoader.class, this);
20         beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
21         beanFactory.registerResolvableDependency(ApplicationContext.class, this);
22 
23         // Register early post-processor for detecting inner beans as ApplicationListeners.
24         beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
25 
26         // Detect a LoadTimeWeaver and prepare for weaving, if found.
27         if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
28             beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
29             // Set a temporary ClassLoader for type matching.
30             beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
31         }
32 
33         // Register default environment beans.
34         if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
35             beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
36         }
37         if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
38             beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
39         }
40         if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
41             beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
42         }
43     }

 方法主要內容是:

1.增加對SPEL語言的支持(如#{XXX.xxx}設置屬性)

2.增加對屬性編輯器的支持

3.設置依賴功能可忽略的接口

4.注冊一些固定依賴的屬性

5.增加AspectJ的支持

6.將相關環境變量及屬性注冊以單例模式注冊

 
接下來再看下初始化非延遲加載單例的bean
 1 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
 2         // Initialize conversion service for this context.
 3         if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
 4                 beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
 5             beanFactory.setConversionService(
 6                     beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
 7         }
 8 
 9         // Register a default embedded value resolver if no bean post-processor
10         // (such as a PropertyPlaceholderConfigurer bean) registered any before:
11         // at this point, primarily for resolution in annotation attribute values.
12         if (!beanFactory.hasEmbeddedValueResolver()) {
13             beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
14         }
15 
16         // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
17         String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
18         for (String weaverAwareName : weaverAwareNames) {
19             getBean(weaverAwareName);
20         }
21 
22         // Stop using the temporary ClassLoader for type matching.
23         beanFactory.setTempClassLoader(null);
24 
25         // Allow for caching all bean definition metadata, not expecting further changes.
26         beanFactory.freezeConfiguration();
27 
28         // Instantiate all remaining (non-lazy-init) singletons.
29         beanFactory.preInstantiateSingletons();
30     }

 這里的26行的freezeConfiguration方法是對bean定義的凍結,也就是說bean注冊之后就不可改了,而ApplicationContext默認說會將所有的單例bean提前進行初始化的,也就是方法preInstantiateSingletons方法

 1 @Override
 2     public void preInstantiateSingletons() throws BeansException {
 3         if (logger.isTraceEnabled()) {
 4             logger.trace("Pre-instantiating singletons in " + this);
 5         }
 6 
 7         // Iterate over a copy to allow for init methods which in turn register new bean definitions.
 8         // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
 9         List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
10 
11         // Trigger initialization of all non-lazy singleton beans...
12         for (String beanName : beanNames) {
13             RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
14             if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
15                 if (isFactoryBean(beanName)) {
16                     Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
17                     if (bean instanceof FactoryBean) {
18                         final FactoryBean<?> factory = (FactoryBean<?>) bean;
19                         boolean isEagerInit;
20                         if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
21                             isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
22                                             ((SmartFactoryBean<?>) factory)::isEagerInit,
23                                     getAccessControlContext());
24                         }
25                         else {
26                             isEagerInit = (factory instanceof SmartFactoryBean &&
27                                     ((SmartFactoryBean<?>) factory).isEagerInit());
28                         }
29                         if (isEagerInit) {
30                             getBean(beanName);
31                         }
32                     }
33                 }
34                 else {
35                     getBean(beanName);
36                 }
37             }
38         }
39 
40         // Trigger post-initialization callback for all applicable beans...
41         for (String beanName : beanNames) {
42             Object singletonInstance = getSingleton(beanName);
43             if (singletonInstance instanceof SmartInitializingSingleton) {
44                 final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
45                 if (System.getSecurityManager() != null) {
46                     AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
47                         smartSingleton.afterSingletonsInstantiated();
48                         return null;
49                     }, getAccessControlContext());
50                 }
51                 else {
52                     smartSingleton.afterSingletonsInstantiated();
53                 }
54             }
55         }
56     }

 

 

高頻面試題:ApplicationContext和BeanFactory的區別?
1.BeanFactory是容器所有容器接口的父類,提供了最基本的bean相關的功能,而ApplicationContext是繼承之BeanFactory,在BeanFactory的基礎上擴展了更多的功能
2.ApplicationContext的初始化過程就包含了BeanFactory的初始化過程,如何額外擴展,
3.BeanFactory中的bean是在獲取的時候才初始化,而ApplicationContext是初始化的時候就初始化所有的單例bean(好處是在啟動的時候就可以檢查到不合法的bean)
4.ApplicationContext增加了SPEL語言的支持(#{xx.xx}等配置)、 消息發送、響應機制(ApplicationEventPublisher)、支持了@Qualiiar和@Autowired等注解
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM