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等注解