目錄java
前面介紹了 Spring 容器的概念,其核心可概括爲兩個類: BeanFactory 和 ApplicationContext,ApplicationContext 繼承自 BeanFactory ,其不只包含 BeanFactory 全部功能,還擴展了容器功能。以後介紹了在 SSM 時期和 SpringBoot 時期如何啓動 ApplicationContext 。在結尾處,咱們指出,ApplicationContext 核心實際上是 refresh 方法,容器一系列功能都在該方法中實現,如:註冊 Bean、注入 Bean 等。緩存
在 refresh 方法中,實現容器核心功能前,先進行了一系列環境準備工做,咱們以 SpringBoot 爲當前運行環境,深刻討論這部份內容。ide
注:本篇文章使用的 SpringBoot 版本爲 2.0.3.RELEASE,其 Spring 版本爲 5.0.7.RELEASEpost
refresh 方法定義在 ConfigurableApplicationContext 接口中,被 AbstractApplicationContext 抽象類實現,該方法由十幾個子方法組成,這些子方法各司其職,但部分子方法被 AbstractApplicationContext 的子類進行擴展,來加強功能。其中,前四個子方法主要進行上下文準備工做。ui
咱們先從 refresh 中的 prepareRefresh 方法開始討論:this
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 初始化上下文環境,就是記錄下容器的啓動時間、活動狀態等 prepareRefresh(); ... } }
該方法被繼承 AbstractApplicationContext 抽象類的子類進行擴展,擴展該方法的子類有:debug
因本次演示的環境是 SpringBoot ,前面咱們講過,SpringBoot 會根據當前 Web 應用類型建立不一樣的上下文對象 ,如 Servlet Web、Reactive Web 等。這裏演示的是 Servlet Web 應用,因此建立的上下文對象是 AnnotationConfigServletWebServerApplicationContext 。該類的 prepareRefresh 方法會被執行:code
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext implements AnnotationConfigRegistry { ... @Override protected void prepareRefresh() { // 清除 Class 的元數據緩存。底層用 Map 保存元數據,執行 Map 的 clear 方法 this.scanner.clearCache(); // 調用父類,也就是 AbstractApplicationContext 的 prepareRefresh 方法 super.prepareRefresh(); } ... }
public abstract class AbstractApplicationContext { ... private long startupDate; private final AtomicBoolean active = new AtomicBoolean(); private final AtomicBoolean closed = new AtomicBoolean(); private Set<ApplicationEvent> earlyApplicationEvents; ... protected void prepareRefresh() { // 記錄此上下文開始時的系統時間(以毫秒爲單位) this.startupDate = System.currentTimeMillis(); // 記錄此上下文是否已關閉,這裏設置爲未關閉 this.closed.set(false); // 記錄此上下文是否處於活動狀態,這裏設置爲活動狀態 this.active.set(true); if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // 這也是交由子類擴展的方法。具體子類爲 GenericWebApplicationContext,主要是初始化屬性源, // 將 ServletContext 和 ServletConfig 屬性配置添加到 Environment 環境上下文中 initPropertySources(); // 校驗 Environment 中那些必備的屬性配置是否存在,不存在則拋異常。 getEnvironment().validateRequiredProperties(); // 建立 ApplicationEvent 事件集合 this.earlyApplicationEvents = new LinkedHashSet<>(); } }
refresh 中的 prepareRefresh 方法執行結束,主要是記錄容器的啓動時間、活動狀態、檢查必備屬性是否存在。其中,關於 Environment 環境配置,在前面 SpringBoot 系列文章中有詳細討論,感興趣的同窗可自行翻閱。對象
接着進入 refresh 中的 obtainFreshBeanFactory 方法blog
public abstract class AbstractApplicationContext { ... public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); ... } } ... protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // 該方法也是由子類擴展,其子類有 AbstractRefreshableApplicationContext 和 GenericApplicationContext, // 因當前是 Servlet Web 應用,因此執行的是 GenericApplicationContext 中的 refreshBeanFactory 方法。 // 該方法主要設置 BeanFactory 的 serializationId 屬性值,也就是序列化id refreshBeanFactory(); // 經過 getBeanFactory 返回 BeanFactory 對象。一樣也是由子類擴展,調用的是 GenericApplicationContext 類中的 getBeanFactory 方法。 // 返回的是 DefaultListableBeanFactory 。 ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } ... }
obtainFreshBeanFactory 方法很簡單,但若是當前是非 Servlet Web 應用,執行的就是 AbstractRefreshableApplicationContext 中的 refreshBeanFactory 方法,那可就複雜多了,這裏就不展開討論。以後,該方法還返回了 BeanFactory 對象,從這也能夠看出 ApplicationContext 底層是以 BeanFactory 爲基礎,逐步擴展 Spring 容器功能。
接着進入 refresh 中的 prepareBeanFactory 方法。prepareBeanFactory 方法主要是對 BeanFactory 作一些配置,包含各類類加載器、須要忽略的依賴以及後置處理器、解析器等,
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... prepareBeanFactory(beanFactory); ... } ... } protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 設置類加載器 beanFactory.setBeanClassLoader(getClassLoader()); // 設置表達式解析器,主要用來解析 EL 表達式; Bean 初始化完成後填充屬性時會用到 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 設置屬性註冊解析器,主要用來解析 Bean 中的各類屬性類型,如 String、int 等 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // 添加一個後置處理器:ApplicationContextAwareProcessor。 // 該後置處理器用於向實現了 Aware 系列接口的 bean 設置相應屬性。 // (後置處理器和 Aware 接口也是比較核心的概念,後面會有文章詳細討論) beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 如下接口,在自動注入時會被忽略,其都是 Aware 系列接口 beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // 當如下特殊的 Bean 需自動注入時,指定其注入的類型 。 // 如:注入 BeanFactory 時,注入的類型對象爲 ConfigurableListableBeanFactory 。 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // 添加 ApplicationListenerDetector 後置處理器。 // 該後置處理器用來檢測那些實現了 ApplicationListener 接口的 bean,並將其添加到應用上下文的事件廣播器上。 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // 判斷容器中是否存在 loadTimeWeaver Bean,若是存在則上下文使用臨時的 ClassLoader 進行類型匹配。 // 集成 AspectJ 時會用到 loadTimeWeaver 對象。 if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { 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()); } }
在 prepareBeanFactory 方法中,主要對 BeanFactory 添加了一系列屬性項,如添加忽略自動注入的接口、添加 BeanPostProcessor 後置處理器、手動註冊部分特殊的 Bean及環境相關的 Bean 。
postProcessBeanFactory 方法是上下文準備的最後一步,主要用來註冊 Web 請求相關的處理器、Bean及配置。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... postProcessBeanFactory(beanFactory); ... } }
該方法也是由子類進行擴展,實現該方法的子類有:
前面也說過,當前是 Servlet Web 應用,因此建立的 ApplicationContext 上下文是 AnnotationConfigServletWebServerApplicationContext,執行該類的 postProcessBeanFactory 方法。
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext implements AnnotationConfigRegistry { private final AnnotatedBeanDefinitionReader reader; private final ClassPathBeanDefinitionScanner scanner; private final Set<Class<?>> annotatedClasses = new LinkedHashSet<>(); private String[] basePackages; ... @Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 先執行父類 ServletWebServerApplicationContext 的 postProcessBeanFactory 方法。 // 跳轉到 1 查看父類實現 super.postProcessBeanFactory(beanFactory); // basePackages 存儲的是類路徑。先判斷是否爲 null,不爲 null 則經過 ClassPathBeanDefinitionScanner 的 scan 方法 // 掃描該路徑下符合條件的 Class,並將 Class 信息包裝成 BeanDefinition 註冊到容器中, // 固然,這裏沒有指定掃描路徑,因此不會進入這個 if。 // (BeanDefinition 概念會在後面章節詳細討論) if (this.basePackages != null && this.basePackages.length > 0) { this.scanner.scan(this.basePackages); } // annotatedClasses 存儲的 Class 集合。先判斷該集合是否爲空,不爲空則經過 // AnnotatedBeanDefinitionReader 的 register 方法將 Class 信息包裝成 BeanDefinition 註冊到容器中, // 這裏一樣沒有設置 Class 集合內容,因此不會進入這個 if。 if (!this.annotatedClasses.isEmpty()) { this.reader.register(ClassUtils.toClassArray(this.annotatedClasses)); } } } 一、 public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext { ... @Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 添加 BeanPostProcessor 後置處理器:WebApplicationContextServletContextAwareProcessor, // 該後置處理器主要是從 ConfigurableWebApplicationContext 上下文中獲取 ServletContext 和 ServletConfig 對象 beanFactory.addBeanPostProcessor(new WebApplicationContextServletContextAwareProcessor(this)); // 添加一個 忽略自動注入的接口 beanFactory.ignoreDependencyInterface(ServletContextAware.class); } ... }
postProcessBeanFactory 方法執行的操做和前面相似,也是添加了後置處理器和忽略自動注入的接口。
ApplicationContext 上下文準備工做基本結束,主要仍是在 BeanFactory 中添加一系列後置處理器、註冊特殊的 Bean 及設置忽略自動注入的接口。其中還提到了 Spring 容器的三個核心部分:Aware 系列接口、BeanPostProcessor 後置處理器、BeanDefinition ,這部分在後面的文章會逐步討論。接下來將對 Spring 容器的核心功能展開討論。
以上就是本章內容,若是文章中有錯誤或者須要補充的請及時提出,本人感激涕零。