最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring核心容器之ApplicationContext上下文啟動準備詳解

 更新時間:2023年11月15日 10:43:27   作者:龍三丶  
這篇文章主要介紹了Spring核心容器之ApplicationContext上下文啟動準備詳解,ApplicationContext 繼承自 BeanFactory ,其不僅包含 BeanFactory 所有功能,還擴展了容器功能,需要的朋友可以參考下

前言

前面介紹了 Spring 容器的概念,其核心可歸納為兩個類: BeanFactory 和 ApplicationContext,ApplicationContext 繼承自 BeanFactory ,其不僅包含 BeanFactory 所有功能,還擴展了容器功能。之后介紹了在 SSM 時期和 SpringBoot 時期如何啟動 ApplicationContext 。在結(jié)尾處,我們指出,ApplicationContext 核心其實是 refresh 方法,容器一系列功能都在該方法中實現(xiàn),如:注冊 Bean、注入 Bean 等。

在 refresh 方法中,實現(xiàn)容器核心功能前,先進行了一系列環(huán)境準備工作,我們以 SpringBoot 為當前運行環(huán)境,深入討論這部分內(nèi)容。

注:本篇文章使用的 SpringBoot 版本為 2.0.3.RELEASE,其 Spring 版本為 5.0.7.RELEASE

正文

refresh 方法定義在 ConfigurableApplicationContext 接口中,被 AbstractApplicationContext 抽象類實現(xiàn),該方法由十幾個子方法組成,這些子方法各司其職,但部分子方法被 AbstractApplicationContext 的子類進行擴展,來增強功能。其中,前四個子方法主要進行上下文準備工作。

第一步:prepareRefresh

我們先從 refresh 中的 prepareRefresh 方法開始討論:

public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 初始化上下文環(huán)境,就是記錄下容器的啟動時間、活動狀態(tài)等
		prepareRefresh();

		...
    }
}

該方法被繼承 AbstractApplicationContext 抽象類的子類進行擴展,擴展該方法的子類有:

image

因本次演示的環(huán)境是 SpringBoot ,前面我們講過,SpringBoot 會根據(jù)當前 Web 應用類型創(chuàng)建不同的上下文對象 ,如 Servlet Web、Reactive Web 等。這里演示的是 Servlet Web 應用,所以創(chuàng)建的上下文對象是 AnnotationConfigServletWebServerApplicationContext 。該類的 prepareRefresh 方法會被執(zhí)行:

public class AnnotationConfigServletWebServerApplicationContext
		extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {

    ...
	
	@Override
	protected void prepareRefresh() {
	
	    // 清除 Class 的元數(shù)據(jù)緩存。底層用 Map 保存元數(shù)據(jù),執(zhí)行 Map 的 clear 方法
		this.scanner.clearCache();
		
		// 調(diào)用父類,也就是 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() {
        
        // 記錄此上下文開始時的系統(tǒng)時間(以毫秒為單位)
    	this.startupDate = System.currentTimeMillis();
    	
    	// 記錄此上下文是否已關(guān)閉,這里設(shè)置為未關(guān)閉
    	this.closed.set(false);
    	
    	// 記錄此上下文是否處于活動狀態(tài),這里設(shè)置為活動狀態(tài)
    	this.active.set(true);
    
    	if (logger.isInfoEnabled()) {
    		logger.info("Refreshing " + this);
    	}
    
    	// 這也是交由子類擴展的方法。具體子類為 GenericWebApplicationContext,主要是初始化屬性源,
    	// 將 ServletContext 和 ServletConfig 屬性配置添加到 Environment 環(huán)境上下文中
    	initPropertySources();
    
    	// 校驗 Environment 中那些必備的屬性配置是否存在,不存在則拋異常。
    	getEnvironment().validateRequiredProperties();
    
    	// 創(chuàng)建 ApplicationEvent 事件集合
    	this.earlyApplicationEvents = new LinkedHashSet<>();
    }

}

refresh 中的 prepareRefresh 方法執(zhí)行結(jié)束,主要是記錄容器的啟動時間、活動狀態(tài)、檢查必備屬性是否存在。

第二步:obtainFreshBeanFactory

接著進入 refresh 中的 obtainFreshBeanFactory 方法

public abstract class AbstractApplicationContext {
    
    ...
    
    public void refresh() throws BeansException, IllegalStateException {
    	synchronized (this.startupShutdownMonitor) {
    		
    		...
            
    		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    		...
    	}
    }
    ...
    
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        // 該方法也是由子類擴展,其子類有 AbstractRefreshableApplicationContext 和 GenericApplicationContext,
        // 因當前是 Servlet Web 應用,所以執(zhí)行的是 GenericApplicationContext 中的 refreshBeanFactory 方法。
        // 該方法主要設(shè)置 BeanFactory 的 serializationId 屬性值,也就是序列化id
    	refreshBeanFactory();
    	
    	// 通過 getBeanFactory 返回 BeanFactory 對象。同樣也是由子類擴展,調(diào)用的是 GenericApplicationContext 類中的 getBeanFactory 方法。
    	// 返回的是 DefaultListableBeanFactory 。
    	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    	if (logger.isDebugEnabled()) {
    		logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    	}
    	return beanFactory;
    }
    
    ...
}

obtainFreshBeanFactory 方法很簡單,但如果當前是非 Servlet Web 應用,執(zhí)行的就是 AbstractRefreshableApplicationContext 中的 refreshBeanFactory 方法,那可就復雜多了,這里就不展開討論。之后,該方法還返回了 BeanFactory 對象,從這也可以看出 ApplicationContext 底層是以 BeanFactory 為基礎(chǔ),逐步擴展 Spring 容器功能。

第三步:prepareBeanFactory

接著進入 refresh 中的 prepareBeanFactory 方法。prepareBeanFactory 方法主要是對 BeanFactory 做一些配置,包含各種類加載器、需要忽略的依賴以及后置處理器、解析器等,

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
			
        ...
        
		prepareBeanFactory(beanFactory);
		...	
    }
    ...
}

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// 設(shè)置類加載器
	beanFactory.setBeanClassLoader(getClassLoader());
	// 設(shè)置表達式解析器,主要用來解析 EL 表達式; Bean 初始化完成后填充屬性時會用到
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	// 設(shè)置屬性注冊解析器,主要用來解析 Bean 中的各種屬性類型,如 String、int 等
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
	// 添加一個后置處理器:ApplicationContextAwareProcessor。
	// 該后置處理器用于向?qū)崿F(xiàn)了 Aware 系列接口的 bean 設(shè)置相應屬性。
	// (后置處理器和 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 后置處理器。
	// 該后置處理器用來檢測那些實現(xiàn)了 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()));
	}

	// 注冊和環(huán)境相關(guān)的 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及環(huán)境相關(guān)的 Bean 。

第四步:postProcessBeanFactory

postProcessBeanFactory 方法是上下文準備的最后一步,主要用來注冊 Web 請求相關(guān)的處理器、Bean及配置。

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        
        ...
        
        postProcessBeanFactory(beanFactory);
        ...   
    }
}

該方法也是由子類進行擴展,實現(xiàn)該方法的子類有:

image

前面也說過,當前是 Servlet Web 應用,所以創(chuàng)建的 ApplicationContext 上下文是 AnnotationConfigServletWebServerApplicationContext,執(zhí)行該類的 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) {
		// 先執(zhí)行父類 ServletWebServerApplicationContext 的 postProcessBeanFactory 方法。
		// 跳轉(zhuǎn)到 1 查看父類實現(xiàn)
		super.postProcessBeanFactory(beanFactory);
		
		// basePackages 存儲的是類路徑。先判斷是否為 null,不為 null 則通過 ClassPathBeanDefinitionScanner 的 scan 方法
		// 掃描該路徑下符合條件的 Class,并將 Class 信息包裝成 BeanDefinition 注冊到容器中,
		// 當然,這里沒有指定掃描路徑,所以不會進入這個 if。
		// (BeanDefinition 概念會在后面章節(jié)詳細討論)
		if (this.basePackages != null && this.basePackages.length > 0) {
			this.scanner.scan(this.basePackages);
		}
		
		// annotatedClasses 存儲的 Class 集合。先判斷該集合是否為空,不為空則通過
		// AnnotatedBeanDefinitionReader 的 register 方法將 Class 信息包裝成 BeanDefinition 注冊到容器中,
		// 這里同樣沒有設(shè)置 Class 集合內(nèi)容,所以不會進入這個 if。
		if (!this.annotatedClasses.isEmpty()) {
			this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
		}
	}	    
}

1、
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 方法執(zhí)行的操作和前面類似,也是添加了后置處理器和忽略自動注入的接口。

總結(jié)

ApplicationContext 上下文準備工作基本結(jié)束,主要還是在 BeanFactory 中添加一系列后置處理器、注冊特殊的 Bean 及設(shè)置忽略自動注入的接口。其中還提到了 Spring 容器的三個核心部分:Aware 系列接口、BeanPostProcessor 后置處理器、BeanDefinition ,這部分在后面的文章會逐步討論。接下來將對 Spring 容器的核心功能展開討論。

到此這篇關(guān)于Spring核心容器之ApplicationContext上下文啟動準備詳解的文章就介紹到這了,更多相關(guān)ApplicationContext上下文啟動準備內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java按字節(jié)截取帶有漢字的字符串的解法(推薦)

    java按字節(jié)截取帶有漢字的字符串的解法(推薦)

    下面小編就為大家?guī)硪黄猨ava按字節(jié)截取帶有漢字的字符串的解法(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09
  • 詳解Java中字符串緩沖區(qū)StringBuffer類的使用

    詳解Java中字符串緩沖區(qū)StringBuffer類的使用

    StringBuffer與String類似,只不過StringBuffer在進行字符串處理時不生成新的對象,下面我們就來詳解Java中字符串緩沖區(qū)StringBuffer類的使用:
    2016-06-06
  • SpringBoot+MyBatis實現(xiàn)動態(tài)字段更新的三種方法

    SpringBoot+MyBatis實現(xiàn)動態(tài)字段更新的三種方法

    字段更新是指在數(shù)據(jù)庫表中修改特定列的值的操作,這種操作可以通過多種方式進行,具體取決于業(yè)務需求和技術(shù)環(huán)境,本文給大家介紹了在Spring Boot和MyBatis中,實現(xiàn)動態(tài)更新不固定字段的三種方法,需要的朋友可以參考下
    2025-04-04
  • 解決MyBatis報錯:There is no getter for property named'Xxx'in'class xxx.xxx.Xxx'

    解決MyBatis報錯:There is no getter for 

    這篇文章主要介紹了解決MyBatis報錯:There is no getter for property named'Xxx'in'class xxx.xxx.Xxx'問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • SpringCloud的Gateway網(wǎng)關(guān)詳解

    SpringCloud的Gateway網(wǎng)關(guān)詳解

    這篇文章主要介紹了SpringCloud的Gateway網(wǎng)關(guān)詳解,Gateway 是 Spring Cloud 官方推出的一個基于 Spring 5、Spring Boot 2 和 Project Reactor 的 API 網(wǎng)關(guān)實現(xiàn),本文將介紹 Spring Cloud Gateway 的基本概念、核心組件以及如何配置和使用它,需要的朋友可以參考下
    2023-09-09
  • mybatis利用association或collection傳遞多參數(shù)子查詢

    mybatis利用association或collection傳遞多參數(shù)子查詢

    今天小編就為大家分享一篇關(guān)于mybatis利用association或collection傳遞多參數(shù)子查詢,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Spring Boot 2.5.0 重新設(shè)計的spring.sql.init 配置有啥用

    Spring Boot 2.5.0 重新設(shè)計的spring.sql.init 配置有啥用

    前幾天Spring Boot 2.5.0發(fā)布了,其中提到了關(guān)于Datasource初始化機制的調(diào)整,有讀者私信想了解這方面做了什么調(diào)整。那么今天就要詳細說說這個重新設(shè)計的配置內(nèi)容,并結(jié)合實際情況說說我的理解和實踐建議
    2021-05-05
  • 基于springBoot配置文件properties和yml中數(shù)組的寫法

    基于springBoot配置文件properties和yml中數(shù)組的寫法

    這篇文章主要介紹了springBoot配置文件properties和yml中數(shù)組的寫法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java為什么使用BlockingQueue解決競態(tài)條件問題面試精講

    java為什么使用BlockingQueue解決競態(tài)條件問題面試精講

    這篇文章主要為大家介紹了java為什么使用BlockingQueue解決競態(tài)條件問題面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • 解決PageHelper的上下文問題導致SQL查詢結(jié)果不正確

    解決PageHelper的上下文問題導致SQL查詢結(jié)果不正確

    主要介紹了PageHelper在使用過程中出現(xiàn)的分頁上下文問題,并分析了可能的原因和解決方案,主要解決方案包括每次分頁查詢后調(diào)用`PageHelper.clearPage()`清理分頁上下文,確保每次查詢前正確調(diào)用`startPage`,以及避免在條件判斷未執(zhí)行SQL時影響后續(xù)查詢
    2024-12-12

最新評論

托克逊县| 宜君县| 乌什县| 宁安市| 巍山| 浪卡子县| 焉耆| 永州市| 吉林省| 兴业县| 汽车| 马山县| 芒康县| 江华| 抚州市| 石景山区| 普洱| 迁安市| 阜阳市| 广昌县| 红安县| 潞西市| 砚山县| 斗六市| 贵阳市| 独山县| 衡东县| 淮滨县| 新昌县| 新干县| 肥乡县| 定结县| 盐边县| 宝应县| 讷河市| 镇雄县| 桐庐县| 临泽县| 新余市| 米脂县| 苍梧县|