1. 程式人生 > >spring學習(三)ConfigurableApplicationContext的refresh方法

spring學習(三)ConfigurableApplicationContext的refresh方法

spring在載入bean的時候,執行的主要方法就是ConfigurableApplicationContext的refresh方法。這個方法在實現類AbstractApplicationContext裡做了處理,這裡就簡單說明一下這個處理方法,下圖是我簡單畫的類關係圖


這個是類AbstractApplicationContext實現的程式碼,以下對每個執行進行說明

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}
		}
	}

一、prepareRefresh

此方法主要記錄一下開始初始化的時候或active的標記,並對一些properties進行初始化

initPropertySources();//子類實現

getEnvironment().validateRequiredProperties();//如果沒有設定Environment取預設的實現StandardEnvironment

二、ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory()
	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

此方法全部由子類實現,

在AbstractRefreshApplicationContext實現了refreshBeanFactory方法,此方法最主要的就是loadBeanDefinitions(beanFactory),由子類去實現load所有的beanDefinition,下一次將具體說明這個方法

@Override
	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
//建立一個預設的BeanFactory。使用了DefaultListableBeanFactory
protected DefaultListableBeanFactory createBeanFactory() {
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}

	@Override
	public final ConfigurableListableBeanFactory getBeanFactory() {
		synchronized (this.beanFactoryMonitor) {
			if (this.beanFactory == null) {
				throw new IllegalStateException("BeanFactory not initialized or already closed - " +
						"call 'refresh' before accessing beans via the ApplicationContext");
			}
			return this.beanFactory;
		}
	}

三、prepareBeanFactory(beanFactory);

預處理beanFactory容器,配置一些beanFactory的classLoader和post-processor等

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// Register default environment beans.
		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());
		}
	}

四、postProcessBeanFactory(beanFactory);

此方法由子類執行beanFactory 之前的操作

五、invokeBeanFactoryPostProcessors(beanFactory);

用於執行BeanFactoryPostProcessors中的postProcessBeanFactory,beanFactoryPostProcessor是優先於BeanPostProcessor執行

先執行BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry。再執行BeanFactoryPostProcessor.postProcessBeanFactory


小例子,此時在載入spring容器時,會打印出當前的Singlecount,注。此時還沒有載入指定的業務bean.除非呼叫getBean(beanName),否則要等到後一步才載入執行

public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

	@Override
	public void postProcessBeanFactory(
			ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println(" signleton count :" + beanFactory.getSingletonCount());
	}

}

mybatis與spring整合時,就是配置了一個BeanDefinitionRegistryPostProcessor。並在postProcessBeanDefinitionRegistry這個方法裡進行查詢mybatis所有配置的mapper

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 
       <property name="basePackage" value="com.dld.app.shop"/>
       <property name="sqlSessionFactory" ref="sqlSessionFactoryShop"></property>
    </bean>
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    if (this.processPropertyPlaceHolders) {
      processPropertyPlaceHolders();
    }

    ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
    scanner.setAddToConfig(this.addToConfig);
    scanner.setAnnotationClass(this.annotationClass);
    scanner.setMarkerInterface(this.markerInterface);
    scanner.setSqlSessionFactory(this.sqlSessionFactory);
    scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
    scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
    scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
    scanner.setResourceLoader(this.applicationContext);
    scanner.setBeanNameGenerator(this.nameGenerator);
    scanner.registerFilters();
    scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }



六、registerBeanPostProcessors(beanFactory);

註冊beanPostProcessor,注意要和beanFactoryPostProcessor區分開,beanFactoryPostProcessor是執行。此時的這裡只是註冊beanPostProcessor,beanFactoryPostProcessor優先於beanPostProcessor執行

beanPostProcessor的流程與beanFactoryPostProcessor執行流程類似。

1、先查詢所有BeanPostProcessor型別的bean

2、註冊屬於PriorityOrdered的beanPostProcessor

3、註冊屬於Ordered型別的beanPostProcessor

4、註冊剩餘的beanPostProcessor

5、增加一個繼承了ApplicationListener的beanPostProcessor檢查ApplicationListenerDetector

public class TestBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
		System.out.println("before beanName [" + beanName + "] bean class [" + bean.getClass() + "]");
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
		System.out.println("after beanName [" + beanName + "] bean class [" + bean.getClass() + "]");
		return bean;
	}

}


七、initMessageSource();

初始化一個messageSource類

1、判斷beanFactory是否有name=messageSource的MessageSource

2、生成一個預設的MessageSource  DelegatingMessageSource並註冊到beanFactory中

八、initApplicationEventMulticaster();

初始化ApplicationEvent類

1、判斷beanFactory是否有name =applicationEventMulticaster的ApplicationEventMulticaster

2、生成預設的SimpleApplicationEventMulticaster 並註冊到beanFactory中

九、onRefresh();

此方法由子類實現

十、registerListeners();

載入所以ApplicationListener並註冊到ApplicationEventMulticaster中

十一、finishBeanFactoryInitialization(beanFactory);

處理beanFactory初始化結束的操作

其中

beanFactory.preInstantiateSingletons();

開始例項化所有未例項化的bean

十二、finishRefresh()

protected void finishRefresh() {
		// Initialize lifecycle processor for this context.
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		getLifecycleProcessor().onRefresh();

		// Publish the final event.
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}

1、生成一個LifecycleProcessor.預設為DefaultLifecycleProcessor

2、執行LiftcycleProcessor的onfresh方法,執行所有屬於Lifecycle的bean

3、推送ApplicationEvent

相關推薦

spring學習ConfigurableApplicationContext的refresh方法

spring在載入bean的時候,執行的主要方法就是ConfigurableApplicationContext的refresh方法。這個方法在實現類AbstractApplicationContext裡做了處理,這裡就簡單說明一下這個處理方法,下圖是我簡單畫的類關係圖

Spring學習| Spring AOP

文章目錄 1. 什麼是 AOP ? 2. 為什麼需要使用 AOP ? 3. AOP 術語 4. 在 Spring 中使用 Aspect 註解方式進行切面程式設計 4.1 在 Spring 中啟用 AspectJ 註解支援 4.2

Spring 學習——Spring 中的 Bean 配置

配置形式:基於 XML 檔案的方式;基於註解的方式 Bean 的配置方式:通過全類名(反射)、通過工廠方法(靜態工廠方法 & 例項工廠方法)、FactoryBean IOC 容器 BeanFactory & ApplicationContext 概述 依賴注入

Spring學習

(一)Spring基於AspectJ的註解的AOP開發 (1)建立專案 引入jar包 編寫目標類,切面類,在Spring中進行bean配置 (2)在配置檔案中開啟註解的AOP開發 (3)切面類AOP配置 注意要在類上打Aspect註解 前置通知 後置通知

Spring學習IOC控制反轉與DI依賴注入

IOC(Inversion of Control,控制反轉)是spring的核心,貫穿始終。 所謂IOC,對於spring框架來說,就是由spring來負責控制物件的生命週期和物件間的關係: 傳統開發

Spring極簡學習例項化Bean的方法有兩種

其實例項化一個Bean並沒有那麼複雜,不就是將new Bean()的過程放到Spring這裡來實現了嗎? 其實的確如此,當然了,之前的設計模式中的例項化Bean的方式Spring也得支援支援吧。 一、最直觀例項化(反射模式) xml配置 <bean id="car1

Spring Boot學習

src pack art tin pre size -s script jar Spring boot實戰 —— Hello Word 1、創建maven項目 2、pom.xml文件 <?xml version="1.0" encoding="UTF-8"?>

Spring MVC學習

新建一個web project專案 嚴重: Context initialization failed org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML docum

SpringBoot學習--構建RESTFUL API並用spring-data-jpa進行儲存&&使用IDEA反向生成帶註釋的例項

構造User物件(/domain),如果有資料庫的表可以直接使用IDEA反向生成例項的類。過程如下: 開啟IDEA:View-ToolWindows-Database。新增資料來源,選擇資料庫型別,輸入資料庫的ip。如果不是預設Windows登陸資料庫,則取消勾選然後填入使用者名稱,密碼。

SSH框架學習——struts整合spring

SSH框架學習(三)——struts整合spring 建立包結構 struts整合spring 建立提交頁面 編寫domain 編寫dao 編寫service 編寫action 配置applicationCo

Spring學習:面向切面的Spring

介紹 如果要重用功能的話,最常見的面向物件技術是繼承或者委託。但是,如果在整個應用中都使用相同的基類,繼承往往會導致一個脆弱的物件體系;而使用委託可能需要對委託物件進行復雜的呼叫。 切面提供了取代繼承和委託的另一種可選方案,而且在很多場景下更清晰簡潔。在使用切面

Spring Cloud學習Feign簡單使用

  前面瞭解瞭如何通過RestTemplate+Ribbon去消費服務,這裡講述如何通過Feign去消費服務。   Feign是一個宣告式的偽Http客戶端,它使得寫Http客戶端變得更簡單。使用Feign,只需要建立一個介面並註解。它具有可插拔的註解特性,可

Spring 學習——通過工廠方法靜態工廠方法 & 例項工廠方法配置 bean

  通過呼叫靜態工廠方法建立 Bean •呼叫靜態工廠方法建立 Bean是將物件建立的過程封裝到靜態方法中. 當客戶端需要物件時, 只需要簡單地呼叫靜態方法, 而不同關心建立物件的細節. •要宣告通過靜態方法建立的 Bean, 需要在 Bean 的 class 屬性裡指定擁有該

spring深入學習IOC 之 載入 Bean

先看一段熟悉的程式碼: ClassPathResource resource = new ClassPathResource("bean.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanF

SpringBoot學習,兩種啟動方式-以main方法啟動和在tomcat裡啟動

        sprigboot既可以直接通過main方法啟動,也可以在tomcat裡啟動,在main方法裡啟動很簡單,直接run啟動類的main方法就可以了。         在tomcat裡啟動

laravel框架學習win下php artisan tinker 測試資料時,無法執行報錯的解決方法

問題描述: 複製該路徑,在資源管理器的位址列中開啟,會看到 如下: Temp 往往是系統或者其他軟體生成的快取檔案或目錄 需要返回到上一級目錄Temp中,全選資料夾,刪除,提示不允許刪除的話,

Spring Boot 構建企業級部落格學習

ide外掛的安裝配置、專案執行 安裝、配置ide 常用外掛安裝、配置 匯入專案到ide 啟動gradle的方式 eclipse環境配置 jdk配置 在eslipse中window-preferences-java裡配置jdk 安裝gradle

Spring Cloud微學習Eureka應用——服務間通訊

微服務可以在“自己的程式”中執行,並通過“輕量級裝置與HTTP型API進行溝通”。這裡的溝通就是本節要說的服務間通訊。即各個微服務註冊到Eureka服務註冊中心,這些微服務之間的通訊 建立服務提供者 啟動上一節 Eureka入門——叢集的服務內容

小菜學習設計模式—工廠方法Factory Method模式

前言 設計模式目錄: 本篇目錄:   其實大家都知道,在工廠方法(Factory Method)模式之前有個簡單工廠模式,也就是靜態工廠方法(Static Factory Method)模式,在簡單工廠模式之前有個我們都熟悉的三層架構模式,那我們就上到下一層一層的來了解下。 三層架構   三

Spring Boot學習:定時任務

一、簡介 專案中經常會遇到使用定時任務的情況,那麼SpringBoot如何實現這種需求呢,還是簡潔到要命。 二、環境準備 eclipse + maven + Spring Boot 三、程式碼示例 pom.xml檔案不用特殊引入依賴包,保持一般初始化就可以,如下