栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

applicationcontext的实现类(spring中applicationcontext作用域)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

applicationcontext的实现类(spring中applicationcontext作用域)

Spring源码系列 - ApplicationContext容器的功能扩展

前言一. ApplicationContext容器

1.1 拓展功能refresh1.2 环境准备

案例1 1.3 加载BeanFactory1.4 功能的拓展(BeanFactory的属性填充)

1.4.1 SpEL语言支持1.4.2 增加属性注册编辑器

(1) 使用自定义属性编辑器(2) 利用Spring自带的CustomDateEditor编辑器 1.4.3 添加ApplicationContextAwareProcessor处理器 1.5 BeanFactory的后处理

1.5.1 Spring中BeanFactoryPostProcessor的应用1.5.2 自定义BeanFactoryPostProcessor1.5.3 激活处理器原理1.5.4 注册BeanPostProcessor1.5.5 初始化消息资源1.5.6 初始化消息广播器 1.6 初始化非延迟加载单例1.7 完成上下文的刷新工作 二. 总结

前言

在我Spring源码系列的前几篇文章中,看过的读者可能会发现,对于Spring的容器,我一直用的是BeanFactory。而本文将讲解Spring的另一个常用的容器ApplicationContext。ApplicationContext拥有BeanFactory的全部功能,同时扩展类许多的功能。两种都是用来加载Bean的一种容器。

例如,BeanFactory加载XML:(该用法过时了)

XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("user.xml"));

ApplicationContext加载XML:

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("user.xml");
一. ApplicationContext容器

我们从上述的案例代码出发,来看下源码:

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
	this(new String[] {configLocation}, true, null);
}
↓↓↓↓↓↓
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
	// 1.父类构造
	super(parent);
	// 2.设置配置文件的路径
	setConfigLocations(configLocations);
	if (refresh) {
		// 3.核心功能
		refresh();
	}
}
1.1 拓展功能refresh

ApplicationContext的拓展功能,必定是在解析到对应的配置文件的基础上进行的,而上述构造函数中,我们看到的方法只有refresh()函数了,这里面包含了ApplicationContext容器中几乎所有的功能。我们来分析下其源码:

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
		// 1.刷新上下文环境,做一些准备工作,如对系统属性或者环境变量进行验证
		prepareRefresh();
		// 2.初始化BeanFactory,进行XML读取。此步骤结束后,ApplicationContext就拥有了BeanFactory的功能。
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		// 3.对BeanFactory进行填充,对 @Qualifier 和 @Autowired 注解进行支持
		prepareBeanFactory(beanFactory);
		try {
			// 4.处理子类覆盖方法
			postProcessBeanFactory(beanFactory);
			StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
			// 5.激活各种BeanFactory处理器
			invokeBeanFactoryPostProcessors(beanFactory);
			// 6.注册 [拦截bean的创建过程] 的处理器
			registerBeanPostProcessors(beanFactory);
			beanPostProcess.end();
			// 7.为上下文初始化Message,国际化处理
			initMessageSource();
			// 8.初始化应用消息广播器
			initApplicationEventMulticaster();
			// 9.让子类来初始化其他的bean
			onRefresh();
			// 10.在已经注册的bean中寻找监听器,并注册到消息广播器中
			registerListeners();
			// 11.初始化非惰性单例bean
			finishBeanFactoryInitialization(beanFactory);
			// 12.完成刷新过程
			finishRefresh();
		}
		catch (BeansException ex) {
			// ...
			// 若失败了,则销毁该bean,并且重置刷新状态
			destroyBeans();
			cancelRefresh(ex);
			throw ex;
		}
		finally {
			resetCommonCaches();
			contextRefresh.end();
		}
	}
}

此时,我们就根据上面的标注来进行解析。

1.2 环境准备

此时我们关注第一步prepareRefresh();看看它做了什么事情:

protected void prepareRefresh() {
	// ...省略
	// 1.让子类去覆盖,一般初始化完成后,内容交给第二步来校验
	initPropertySources();
	// 2.验证需要的属性文件是否都已经加载到环境中了
	getEnvironment().validateRequiredProperties();
	// ...省略
}

这里我将大部分不重要的代码给省略了,留下了俩核心方法:

initPropertySources()validateRequiredProperties()

遗憾的是,点开initPropertySources方法,发现源码是空的:

protected void initPropertySources() {
	// For subclasses: do nothing by default.
}

那么这个环境准备的函数,里面的操作又是空的,那到底有啥用呢?

案例1

项目结构如下:(Spring源码中测试的话,建议在context包下,自己测试的话,记得引以下spring-context包)

自定义的容器MyApplicationContext,需要继承ClassPathXmlApplicationContext:

public class MyApplicationContext extends ClassPathXmlApplicationContext {
	public MyApplicationContext(String... configLocations) throws BeansException {
		super(configLocations);
	}

	protected void initPropertySources() {
		getEnvironment().setRequiredProperties("ljj");
	}
}

User类:

public class User {
	private String name;
	private String address;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}
}

Test类:

public class Test {
	@org.junit.jupiter.api.Test
	void test(){
		MyApplicationContext context = new MyApplicationContext("test.xml");
		User user = (User) context.getBean("user");
		System.out.println(user.getName());
	}
}

test.xml文件:




	
		
	

测试如下:

那么如何让程序成功跑通嘞?我们增加个环境配置参数:

随便填什么,主要是ljj的参数名称就行,我填了ljj="真棒",再跑一次程序,结果如下:

此时我们就知道initPropertySources和validateRequiredProperties方法的作用了,就是用来校验我们自己配置的环境变量的。

1.3 加载BeanFactory

紧接着,我们里看下拓展功能里的第二步,初始化BeanFactory操作。

ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
↓↓↓↓↓
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		// 1.初始化BeanFactory,进行XML读取
		refreshBeanFactory();
		// 2.返回BeanFactory实体类对象
		return getBeanFactory();
	}
}

我们来看下第一步refreshBeanFactory()方法。首先其是AbstractApplicationContext类中的一个抽象方法,并没有具体的实现,因此该方法最终会委派给子类AbstractRefreshableApplicationContext来完成:

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
	@Override
	protected final void refreshBeanFactory() throws BeansException {
		// 1.若已经存在BeanFactory实例,则销毁,重新生成一个
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			// 2.创建DefaultListableBeanFactory实例
			// 注意,我们的案例中,XmlBeanFactory是DefaultListableBeanFactory的一个子类。
			// 因此DefaultListableBeanFactory可以说是容器的基础了。
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			// 3.序列化指定的id,若有必要,将从该id进行反序列化得到一个BeanFactory对象
			beanFactory.setSerializationId(getId());
			// 4.定制BeanFactory,设置相关的属性。例如:是否允许覆盖同名称的不同定义的对象、循环依赖、@Autowired、@Qualifier注解等
			customizeBeanFactory(beanFactory);
			// 5.初始化documentReader,进行XML的读取和解析
			loadBeanDefinitions(beanFactory);
			// 6.将完成好的BeanFactory赋值
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
}

其中我们先来重点看下第四步:定制BeanFactory:

customizeBeanFactory(beanFactory);
↓↓↓↓↓↓
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
	// allowBeanDefinitionOverriding:是否允许覆盖同名称的不同定义的对象
	// 若其部位null,则设置对应的属性
	if (this.allowBeanDefinitionOverriding != null) {
		beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	// allowCircularReferences:是否允许bean之间存在循环依赖
	if (this.allowCircularReferences != null) {
		beanFactory.setAllowCircularReferences(this.allowCircularReferences);
	}
}

同样,在这里没有做任何具体的实现,只是单单的进行赋值罢了,那么这段代码又有什么作用呢?同理,和案例1同样,该方法若希望真正发挥作用,同样需要我们自定义一个子类去完成,例如:

public class MyApplicationContext extends ClassPathXmlApplicationContext {
	public MyApplicationContext(String... configLocations) throws BeansException {
		super(configLocations);
	}

	protected void initPropertySources() {
		getEnvironment().setRequiredProperties("ljj");
	}
	// 设置不允许覆盖名称的不同定义的对象以及不允许发生循环依赖
	protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		super.setAllowBeanDefinitionOverriding(false);
		super.setAllowCircularReferences(false);
	}
}

紧接着,在定制完自己的Spring容器后(重写customizeBeanFactory方法),来看下第五步:加载BeanDefinition做了什么事情。同样loadBeanDefinitions方法,也是AbstractApplicationContext类中的一个抽象方法,并没有具体的实现,因此该方法最终会委派给子类AbstractXmlApplicationContext去完成:

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
	// 1.为指定的BeanFactory创建一个XmlBeanDefinitionReader
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

	// 2.对XmlBeanDefinitionReader进行环境变量的设置。
	beanDefinitionReader.setEnvironment(this.getEnvironment());
	beanDefinitionReader.setResourceLoader(this);
	beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

	// 3.允许对BeanDefinitionReader进行覆盖
	initBeanDefinitionReader(beanDefinitionReader);
	// 4.BeanDefinition的加载
	loadBeanDefinitions(beanDefinitionReader);
}

对于最后一步loadBeanDefinitions,本文不再详细展开,有需要则开启传送门:Spring源码系列:容器的基本实现

那么在这里对1.3节做个总结,ApplicationContext容器对BeanFactory的加载阶段做了什么事情,很简单,两步:

    进行功能的拓展,用户可自定义属性,是否允许覆盖名称的不同定义的对象以及bean之间发生发生循环依赖。加载BeanDefinition。(做和BeanFactory一样的事情)
1.4 功能的拓展(BeanFactory的属性填充)

从1.3小节我们可以知道,完成BeanFactory的加载之后,此时ApplicationContext容器已经完成了对配置的解析和BeanDefinition的加载。已经可以正常地去获取Bean了。那么此时,也是时候对容器的功能进行拓展了。我们来看下第三步prepareBeanFactory(beanFactory);

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// 1.设置BeanFactory的类加载器为当前context的类加载器
	beanFactory.setBeanClassLoader(getClassLoader());
	// 2.设置BeanFactory的表达式语言处理器。
	if (!shouldIgnoreSpel) {
		beanFactory.setBeanexpressionResolver(new StandardBeanexpressionResolver(beanFactory.getBeanClassLoader()));
	}
	// 3.为BeanFactory增加一个propertyEditor,用于对bean属性的管理
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// 4.配置BeanPostProcessor以及几个忽略自动装配的接口
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

	// 5.设置几个自动装配的特殊规则
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// 注册监听器类型的bean
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// 6.增加对AspectJ的支持。(AOP)
	if (!NativeDetector.inNativeImage() && 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()));
	}

	// 注册默认的系统bean
	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());
	}
	if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
		beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
	}
}

做的事情分为这么几种:

    增加对SpEL语言的支持。增加对属性编辑器的支持。增加一些内置类,以及设置依赖注入可以忽略的接口。注册一些固定依赖的属性以及系统相关的bean。增加AspectJ的支持。
1.4.1 SpEL语言支持

Spring表达式的全称为:Spring expression Language,缩写SpEL。用于在运行时构建复杂的表达式、存取对象图属性、对象方法调用等。可以用来配置bean的定义。其使用#{...}作为定界符。

我们先来看下案例:
User类:

public class User {
	private String name;
	private String path;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}
}

Test类:

public class Test {
	@org.junit.jupiter.api.Test
	void test(){
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spel/test.xml");
		User user = (User) context.getBean("user");
		System.out.println(user.getName());
		System.out.println(user.getPath());
	}
}

test.xml文件:我们通过表达式动态地为 userBean 注入 osName(操作系统名)与 classPath(类路径)属性。




	

结果如下:

1.4.2 增加属性注册编辑器

背景:Spring进行属性注入的时候,注入int、String这类属性,是可以正常注入的,但是像Date类型就无法被识别,例如:

我们在上述的案例基础上修改下:
test.xml:


	

User类:

public class User {
	private Date date;
	public Date getDate() {
		return date;
	}
	public void setDate(Date date) {
		this.date = date;
	}
}

Test类:

@org.junit.jupiter.api.Test
void test(){
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spel/test.xml");
	User user = (User) context.getBean("user");
	System.out.println(user.getDate());
}

运行结果如下:

针对这种情况,Spring提供了两种解决方法:

(1) 使用自定义属性编辑器

这种方式,需要我们编写自定义的属性编辑器,继承PropertyEditorSupport类,重写其setAsText方法。案例如下:

DatePropertyEditor类:

import java.beans.PropertyEditorSupport;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DatePropertyEditor extends PropertyEditorSupport {
	@Override
	public void setAsText(String text) throws IllegalArgumentException {
		System.out.println("自定义解析Date,解析前:" + text);
		try {
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
			Date date = dateFormat.parse(text);
			this.setValue(date);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

test.xml文件增加bean配置:在customEditors属性中注入自定义的属性编辑器。(注意:该属性的类型是个Map,因此用了Map标签,同时entry的key应该指的是Date类型,意思是一旦遇到了该类型的属性,就会调用自定义的DatePropertyEditor进行解析)


	
		
			
		
	

结果如下:

(2) 利用Spring自带的CustomDateEditor编辑器

案例如下:

创建DateEditorRegister类,同时实现PropertyEditorRegistrar接口:

import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;

import java.text.SimpleDateFormat;
import java.util.Date;

public class DateEditorRegister implements PropertyEditorRegistrar {
	@Override
	public void registerCustomEditors(PropertyEditorRegistry registry) {
		registry.registerCustomEditor(Date.class,
				new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
	}
}

test.xml文件更改如下:改为注入propertyEditorRegistrars属性


	
		
			
		
	

结果依旧如上图所示,这里就不展开了。

1.4.3 添加ApplicationContextAwareProcessor处理器

这里我们关注第四步代码块:

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

这行代码的作用就是注册一个BeanPostProcessor,它有啥作用呢?

在调用bean的initMethod方法前后分别调用postProcessBeforeInitialization和postProcessAfterInitialization方法,那么我们来看下ApplicationContextAwareProcessor处理器做了什么:

class ApplicationContextAwareProcessor implements BeanPostProcessor {
	// postProcessAfterInitialization方法没有重写,就默认的什么都不干返回bean,这里就不说了
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		// 这里的类型都是上文希望忽略的依赖接口,调用了ignoreDependencyInterface方法。
		// 如果不是这几种bean,直接返回
		if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
				bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
				bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
				bean instanceof ApplicationStartupAware)) {
			return bean;
		}

		AccessControlContext acc = null;
		if (System.getSecurityManager() != null) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}
		if (acc != null) {
			AccessController.doPrivileged((PrivilegedAction) () -> {
				// 核心调用
				invokeAwareInterfaces(bean);
				return null;
			}, acc);
		}else {
			// 核心调用
			invokeAwareInterfaces(bean);
		}

		return bean;
	}
	private void invokeAwareInterfaces(Object bean) {
		// 这里就是对各种类型的bean,添加各种资源属性而已
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationStartupAware) {
			((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}
}
 

提问:为何要设置忽略依赖,即调用ignoreDependencyInterface方法?

答:Spring将ApplicationContextAwareProcessor注册后,在invokeAwareInterfaces方法调用的Aware类已经不是普通的bean。例如EnvironmentAware类,那么需要在Spring做bean的依赖注入的时候忽略他们。他们不适用于一般bean的依赖注入。有另外的逻辑做处理。

总结下,添加ApplicationContextAwareProcessor处理器的作用也就是:让一些实现了Aware接口的bean,在初始化的时候能够获得对应的资源。

例如某bean实现了EnvironmentAware接口,那么就会执行这段代码,添加当前容器的系统环境相关属性:

if (bean instanceof EnvironmentAware) {
	((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}

关于对AspectJ的支持,将在后续文章中讲解。

1.5 BeanFactory的后处理

这一环节,我们将跳出prepareBeanFactory()代码,回到refresh()代码,同时定位到第五步,激活各种BeanFactory处理器:

invokeBeanFactoryPostProcessors(beanFactory);

首先,我们来了解下BeanFactoryPostProcessor是干啥用的。一般用来在实例化一个bean之前,读取相关元数据并进行修改操作。 Spring中就已经有对BeanFactoryPostProcessor的一个应用:PropertyPlaceholderConfigurer类。

1.5.1 Spring中BeanFactoryPostProcessor的应用

User类:

public class User {
	private String address;

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}
}

Test类:

@org.junit.jupiter.api.Test
void test(){
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
	User user = (User) context.getBean("user");
	System.out.println(user.getAddress());
}

然后在resources下创建目录config,并创建文件bean.properties:

message=Hello World

text.xml文件如下:




	
		
			
				config/bean.properties
			
		
	

	
		
		
	

程序运行结果如下:

从结果而言,我们能看出PropertyPlaceholderConfigurer类的作用,也就是指定了配置文件的地址。我们来看下这个类的层次结构:

可见其间接地继承了BeanFactoryPostProcessor接口,而当Spring加载了任何实现了该接口的bean后,都会在bean工厂载入所有bean之后,调用postProcessBeanFactory方法。

我们来看下PropertyResourceConfigurer类中对postProcessBeanFactory方法的重写:

public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
		implements BeanFactoryPostProcessor, PriorityOrdered {
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		try {
			// 合并配置
			Properties mergedProps = mergeProperties();
			// 转换配置
			convertProperties(mergedProps);
			// 将配置信息载入到BeanFactory工厂里,也是因此,
			// BeanFactory在实例化前能得到配置信息,而正确的解析我们XML配置文件中的变量引用
			processProperties(beanFactory, mergedProps);
		}
		// ..catch
	}
}
1.5.2 自定义BeanFactoryPostProcessor

自定义MyPostProcessor类,做一个敏感词屏蔽器。用于替换一些敏感的值,实现BeanFactoryPostProcessor接口:

package test;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionVisitor;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.util.StringValueResolver;

import java.util.HashSet;
import java.util.Set;

public class MyPostProcessor implements BeanFactoryPostProcessor {
	private Set obscenties;

	public MyPostProcessor() {
		obscenties = new HashSet<>();
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		String[] definitionNames = beanFactory.getBeanDefinitionNames();
		for (String beanName : definitionNames) {
			BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
			StringValueResolver valueResolver = new StringValueResolver() {
				@Override
				public String resolveStringValue(String strVal) {
					if (isObscene(strVal)) {
						return "******";
					}
					return strVal;
				}
			};
			BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
			visitor.visitBeanDefinition(bd);
		}
	}
	// 判断当前值是否在敏感集合中,若在,则替换为******
	public boolean isObscene(Object value) {
		String str = value.toString().toUpperCase();
		return this.obscenties.contains(str);
	}

	public void setObscenties(Set obscenties) {
		this.obscenties.clear();
		for (String obscenty : obscenties) {
			this.obscenties.add(obscenty.toUpperCase());
		}
	}
}

text.xml文件:




	
		
			
				123456
			
		
	

	
		
		
		
	

Test类:

@org.junit.jupiter.api.Test
void test(){
	ConfigurableListableBeanFactory bf = new XmlBeanFactory(new ClassPathResource("test.xml"));
	BeanFactoryPostProcessor mybd = (BeanFactoryPostProcessor) bf.getBean("mybd");
	mybd.postProcessBeanFactory(bf);

	User user = (User) bf.getBean("user");
	System.out.println(user.getAddress());
	System.out.println(user.getPhone());
}

@org.junit.jupiter.api.Test
void test2(){
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
	User user = (User) context.getBean("user");
	System.out.println(user.getAddress());
	System.out.println(user.getPhone());
}

结果如下,可见Spring自动将123456这个敏感词给屏蔽掉了。

至于我为什么写俩test呢,首先他们两个的效果是等价的。本篇文章主要围绕着容器ApplicationContext来展开的,那么从代码的比较上来看,我们可以发现,若是BeanFactory容器,我们需要自己手动调用postProcessBeanFactory方法,而ApplicationContext容器则自动调用了,这也是两个容器的一个区别。

1.5.3 激活处理器原理

这里我们回到invokeBeanFactoryPostProcessors(beanFactory)这行代码,来看下它的处理流程:

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List beanFactoryPostProcessors) {
	Set processedBeans = new HashSet<>();
	// 针对BeanDefinitionRegistry进行处理
	if (beanFactory instanceof BeanDefinitionRegistry) {
		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
		// 用于存放常规的 BeanFactoryPostProcessor
		List regularPostProcessors = new ArrayList<>();
		// 存放 BeanDefinitionRegistryPostProcessor
		List registryProcessors = new ArrayList<>();
		// 处理硬编码注册的后处理器(通过参数传进来的)
		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
				// 因为对于BeanDefinitionRegistryPostProcessor类型,其在 BeanFactoryPostProcessor 的基础上还有自定义的方法
				BeanDefinitionRegistryPostProcessor registryProcessor =
						(BeanDefinitionRegistryPostProcessor) postProcessor;
				// 这里则进行调用
				registryProcessor.postProcessBeanDefinitionRegistry(registry);
				// 添加到registryProcessor中,为的是最后执行postProcessBeanFactory方法
				registryProcessors.add(registryProcessor);
			} else {
				// 记录常规的 BeanFactoryPostProcessor
				regularPostProcessors.add(postProcessor);
			}
		}
		// 用于保存本次要执行的BeanDefinitionRegistryPostProcessor
		List currentRegistryProcessors = new ArrayList<>();
		// 3.调用所有实现PriorityOrdered接口的BeanDefinitionRegistryPostProcessor实现类
		// 找出所有实现BeanDefinitionRegistryPostProcessor接口的Bean的beanName
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			// 校验是否实现了PriorityOrdered接口
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				// 将要被执行的加入processedBeans,避免后续重复执行
				processedBeans.add(ppName);
			}
		}
		// 排序、执行、情况
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
		currentRegistryProcessors.clear();

		// 调用了所有实现了Ordered接口的 BeanDefinitionRegistryPostProcessor 实现类
		postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
		for (String ppName : postProcessorNames) {
			if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
				processedBeans.add(ppName);
			}
		}
		sortPostProcessors(currentRegistryProcessors, beanFactory);
		registryProcessors.addAll(currentRegistryProcessors);
		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
		currentRegistryProcessors.clear();

		// 调用剩下的 BeanDefinitionRegistryPostProcessor 实现类
		boolean reiterate = true;
		while (reiterate) {
			reiterate = false;
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
					reiterate = true;
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();
		}
		invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
	} else {
		invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
	}
	// 此时,入参中的处理器和容器中的BeanDefinitionRegistryPostProcessor已经被处理完毕
	// 接下来开始处理容器中所有的 BeanFactoryPostProcessor
	String[] postProcessorNames =
			beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

	// 对处理器进行分类、具有优先级的、排过序的、无序的
	List priorityOrderedPostProcessors = new ArrayList<>();
	List orderedPostProcessorNames = new ArrayList<>();
	List nonOrderedPostProcessorNames = new ArrayList<>();
	for (String ppName : postProcessorNames) {
		if (processedBeans.contains(ppName)) {
			// skip - already processed in first phase above
		} else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
		} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		} else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// 优先调用 有优先级顺序 的处理器
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

	// 其次调用 排过序 的处理器
	List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
	for (String postProcessorName : orderedPostProcessorNames) {
		orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

	// 最后调用 剩下 的处理器
	List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
	for (String postProcessorName : nonOrderedPostProcessorNames) {
		nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
	}
	invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

	// 清除元数据缓存
	beanFactory.clearmetadataCache();
}

代码有点冗长,这里做个宏观的总结,方便理解:

首先,我们将处理器分为两大类:

BeanFactoryPostProcessor,本文简称BF处理器。主要执行postProcessBeanFactory方法。BeanDefinitionRegistryPostProcessor,本文简称R处理器。主要执行postProcessBeanDefinitionRegistry方法。

其次,先处理入参中的beanFactoryPostProcessors对象,进行分类。处理入参中的BeanFactoryPostProcessor和容器中的BeanDefinitionRegistryPostProcessor对象:

调用实现了PriorityOrdered接口的R处理器(具有优先级)。(包括校验操作)调用实现了Ordered接口的R处理器(排过序)。调用普通的R处理器。调用入参中普通的BF处理器。

然后开始处理容器中所有的BF处理器,进行分类。

调用实现了PriorityOrdered接口的BF处理器(具有优先级)。(包括校验操作)调用实现了Ordered接口的BF处理器(排过序)。调用普通的BF处理器。

这里做个小区分哈,BF处理器和R处理器,都属于Spring的后置处理器,R处理器优先于BF处理器执行。 可以实现它们以达到动态注册bean定义,动态修改bean定义,以及动态修改bean。 而他们的作用也恰恰可以当做上述那一大段代码的总结。

紧接着,我们来看下registerBeanPostProcessors(beanFactory)这行代码是干什么用的。

1.5.4 注册BeanPostProcessor

首先,希望小伙伴们将BeanPostProcessor和上述的BF处理器R处理器进行区分。

R处理器继承了B处理器,两者都是基于bean factory来调整上下文的bean的属性值的。他们并不会使用bean实例。BeanPostProcessor则允许动态修改应用程序上下文的bean,这时候bean已经实例化成功。 他的执行顺序也在最后。

我们先来看下一个简单地案例:

自定义一个后处理器,实现InstantiationAwareBeanPostProcessor接口

public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
	@Override
	public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
		System.out.println("**************Hello World***************");
		return null;
	}
}

同时在xml文件中添加bean的配置:


结果如下:

知道了BeanPostProcessor的一个使用之后,我们来回到代码本身,我们来看下源码:

// 注册 [拦截bean的创建过程] 的处理器
registerBeanPostProcessors(beanFactory);
↓↓↓↓↓↓
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
	PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
↓↓↓↓↓↓
public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
	// 1.查找 BeanPostProcessor 类型的 Bean 的名称集合
	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
	
	int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
	beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

	// 2.四个集合 区分实现不同接口的 BeanPostProcessors
	List priorityOrderedPostProcessors = new ArrayList<>();
	List internalPostProcessors = new ArrayList<>();
	List orderedPostProcessorNames = new ArrayList<>();
	List nonOrderedPostProcessorNames = new ArrayList<>();
	for (String ppName : postProcessorNames) {
		if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			priorityOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		} else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
			orderedPostProcessorNames.add(ppName);
		} else {
			nonOrderedPostProcessorNames.add(ppName);
		}
	}

	// 3.注册实现了PriorityOrdered接口的 BeanPostProcessors
	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

	// 4.注册实现了 Ordered 接口的 BeanPostProcessors
	List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
	for (String ppName : orderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		orderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	sortPostProcessors(orderedPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, orderedPostProcessors);

	// 5.注册其余常规的 BeanPostProcessors
	List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
	for (String ppName : nonOrderedPostProcessorNames) {
		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
		nonOrderedPostProcessors.add(pp);
		if (pp instanceof MergedBeanDefinitionPostProcessor) {
			internalPostProcessors.add(pp);
		}
	}
	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

	// 6.最后,注册所有 MergedBeanDefinitionPostProcessor 类型的 BeanPostProcessors
	sortPostProcessors(internalPostProcessors, beanFactory);
	registerBeanPostProcessors(beanFactory, internalPostProcessors);

	// 7.添加ApplicationListenerDetector探测器
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

总的来看。也就是对不同类型的BeanPostProcessor进行分类,然后分别注册。似乎和1.5.3 节没什么区别。但是还是要做好区分。

1.5.3 节对于BF处理器和R处理器,会调用了后处理逻辑。而BeanPostProcessor的注册环节,仅仅是将其注册到BeanFactory中,并没有真正的执行!真正的执行实在bean实例化的时候发生的! 1.5.5 初始化消息资源

背景:我们的应用程序需要支持多语言。即 i18n国际化问题。

国际化信息也称为本地化信息,一般需要两个条件才可以确定一个特定类型的本地化信息:

语言类型。国家/地区的类型。

Java则通过java.util.Locale来标识一个本地化对象,例如:

Locale locale = new Locale("zh", "CN");

同时util包下提供了几个支持本地化的格式化操作类:NumberFormat、MessageFormat等。Spring中的国际化资源操作也就是在这些类的基础上进行封装。我们先来看下MessageFormat类的使用:

@org.junit.jupiter.api.Test
void messageFormatTest() {
	String pattern1 = "{0},你好!你于{1}在银行存入{2}元";
	String pattern2 = "At {1,time,short} On{1,date,long} {0} paid {2,number,currency}";
	Object[] params = {"LJJ", new GregorianCalendar().getTime(), 1.0E3};
	
	String s = MessageFormat.format(pattern1, params);
	System.out.println(s);

	MessageFormat mf = new MessageFormat(pattern2, Locale.US);
	String s2 = mf.format(params);
	System.out.println(s2);
}

结果如下:

Spring中则定义了访问国际化信息的MessageSource接口。我们来看下refresh()源码中的第七步:为上下文初始化Message,国际化处理。

initMessageSource();

protected void initMessageSource() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	// bean的名称额必须是messageSource
	if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
		this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
		// Make MessageSource aware of parent MessageSource.
		if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
			HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
			if (hms.getParentMessageSource() == null) {
				// // 如果已经注册的父上下文没有消息源,则只能将父上下文设置为父消息源
				hms.setParentMessageSource(getInternalParentMessageSource());
			}
		}
		if (logger.isTraceEnabled()) {
			logger.trace("Using MessageSource [" + this.messageSource + "]");
		}
	}
	else {
		// 若用户没有定义配置文件,那么使用临时的 DelegatingMessageSource 作为调用 getMessage方法的返回
		DelegatingMessageSource dms = new DelegatingMessageSource();
		dms.setParentMessageSource(getInternalParentMessageSource());
		this.messageSource = dms;
		beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
		if (logger.isTraceEnabled()) {
			logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
		}
	}
}

这段代码很简单:

    将实现了MessageSource接口的bean存放在ApplicationContext的成员变量中。先看是否有此配置,如果有就实例化。否则就创建一个DelegatingMessageSource实例的bean。

那源码中出现的HierarchicalMessageSource类是干啥的呢?它是MessageSource接口的一个扩展接口。而其有个重要的实现类为ResourceBundleMessageSource类,我们来看下其使用:

1.创建国际化配置文件:

2.创建一个名字为message的文件:选中左侧的英语,然后点下→按钮

此时会自动生成两种文件:

test.xml配置文件如下:


	
	
		
			test/message
		
	

Test类:

@org.junit.jupiter.api.Test
void messageFormatTest2() {
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test.xml");
	String str1 = context.getMessage("test", null, Locale.ENGLISH);
	String str2 = context.getMessage("test", null, Locale.CHINA);

	System.out.println(str1);
	System.out.println(str2);
}

结果如下:

将这个小案例和上述源码结合起来看也就是:

    若我们配置了国际化资源文件,并且存在实现了MessageSource接口的bean。那么ApplicationContext会将其整合到容器里面。那么此时我们调用getMessage()方法,也就是调用对应子类的实现而已。
1.5.6 初始化消息广播器

首先我们来看下Spring中监听器的使用:

1.定义监听事件:

public class MyEvent extends ApplicationEvent {
	public String msg;

	public MyEvent(Object source) {
		super(source);
	}

	public MyEvent(Object source, String msg) {
		super(source);
		this.msg = msg;
	}

	public void print() {
		System.out.println(msg);
	}
}

2.定义监听器:

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class MyListener implements ApplicationListener {
	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof MyEvent) {
			MyEvent myEvent = (MyEvent) event;
			((MyEvent) event).print();
		}
	}
}

3.test.xml文件:




	

4.Test方法:

@org.junit.jupiter.api.Test
void test() {
	ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("listener/test.xml");
	MyEvent myEvent = new MyEvent("hello", "你好,上海");
	context.publishEvent(myEvent);
}

结果如下:

我们发现,程序运行的时候,Spring会将发出的MyEvent事件转给我们自定义的监听器MyListener处理(观察者模式)。

1.6 初始化非延迟加载单例

这一环节我们主要围绕finishBeanFactoryInitialization这个方法来展开。其主要做完成BeanFactory的初始化工作,其中包括conversionService的设置、配置冻结和非延迟加载单例的初始化工作:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// 1.初始化此上下文的转换服务,完成conversionService的设置
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}
	// 如果beanFactory之前没有注册嵌入值解析器,则注册默认的嵌入值解析器:主要用于注解属性值的解析。
	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}
	// 初始化LoadTimeWeaverAware Bean实例对象
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}
	// Stop using the temporary ClassLoader for type matching.
	beanFactory.setTempClassLoader(null);
	// 2.冻结所有的bean定义,说明此时注册的bean定义 将不能够被修改。此时马上要创建bean实例对象了
	beanFactory.freezeConfiguration();
	// 3.初始化剩下的单例bean
	beanFactory.preInstantiateSingletons();
}

先来看下第一步,我们来熟悉下ConversionService是干什么的:

@org.junit.jupiter.api.Test
void test3() {
	DefaultConversionService conversionService = new DefaultConversionService();
	double d = conversionService.convert("1.2", double.class);
	System.out.println(d); 

	int i = conversionService.convert("2", int.class);
	System.out.println(i);
	Byte b = conversionService.convert("0x10", Byte.class);
	System.out.println(Integer.toBinaryString(b));

}

结果如下:

第二步冻结所有的bean定义,无非就是将beanDefinitionNames集合转化为String数组,本身没什么好探索的。我们直接来看第三步,非延迟bean 的加载。

懒加载:用的时候才加载构造,不用的时候不加载。非懒加载(非延迟):容器启动的时候立刻创建对象。

接下来看下preInstantiateSingletons的源码:

@Override
public void preInstantiateSingletons() throws BeansException {
	if (logger.isTraceEnabled()) {
		logger.trace("Pre-instantiating singletons in " + this);
	}

	// 1.将所有BeanDefinition的名字创建一个集合
	List beanNames = new ArrayList<>(this.beanDefinitionNames);
	// 2.触发所有 非延迟加载单例bean的初始化
	for (String beanName : beanNames) {
		// 3.合并父类BeanDefinition
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// 4.条件判断:抽象、单例、非懒加载
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			// 是否实现了FactoryBean接口
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				// 类型转换
				if (bean instanceof FactoryBean) {
					FactoryBean factory = (FactoryBean) bean;
					// 判断该FactoryBean是否希望立即初始化
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(
								(PrivilegedAction) ((SmartFactoryBean) factory)::isEagerInit,
								getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			}
			else {
				getBean(beanName);
			}
		}
	}

	// 遍历beanNames,触发所有SmartInitializingSingleton的后初始化回调
	// 当所有单例 bean 都初始化完成以后,会执行afterSingletonsInstantiated()方法
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		// 判断singletonInstance是否实现了SmartInitializingSingleton接口
		if (singletonInstance instanceof SmartInitializingSingleton) {
			StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
					.tag("beanName", beanName);
			SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			}
			else {
				smartSingleton.afterSingletonsInstantiated();
			}
			smartInitialize.end();
		}
	}
}
 

总结下本方法主要做了这么几件事:

    准备转换器ConversionService。其作用也就是bean的一个属性解析。然后在初始化bean之前,把这些bean冻结起来,不让他们被修改。然后对于那些希望在容器启动阶段就创建的bean(非延迟),调用getBean()方法创建。(其详细过程:Spring源码系列:Bean的加载)
1.7 完成上下文的刷新工作

终于来到了refresh()方法的最后一步:finishRefresh

protected void finishRefresh() {
	// 1.清理缓存
	clearResourceCaches();
	// 2.为此上下文初始化生命周期处理器,它有啥作用呢?
	// ApplicationContext容器在启动或者停止的时候,需要LifecycleProcessor来和所有的bean的生命周期做状态更新
	initLifecycleProcessor();
	// 3.将刷新完毕事件传播到生命周期处理器。启动所有实现了Lifecycle接口的bean
	getLifecycleProcessor().onRefresh();
	// 4.推送上下文刷新完毕事件到相应的监听器
	publishEvent(new ContextRefreshedEvent(this));
	if (!NativeDetector.inNativeImage()) {
		LiveBeansView.registerApplicationContext(this);
	}
}
二. 总结

ApplicationContext容器在传统的BeanFactory容器上扩展了很多功能,而这些功能的扩展都靠refresh()方法的调用,而该方法又拓展了这么几个主要的功能:

1.环境准备。

比如我们可以校验该程序是否在特定的环境变量下运行的。

2.加载BeanFactory。

进行功能的拓展,用户可自定义属性,是否允许覆盖名称的不同定义的对象以及bean之间发生发生循环依赖。加载BeanDefinition。(做和BeanFactory一样的事情)

3.填充BeanFactory,增加一些功能支持:

增加对SpEL语言的支持。增加对属性编辑器的支持。(例如支持String类型的属性转Date)让一些实现了Aware接口的bean,在初始化的时候能够获得对应的资源,如添加当前容器的系统环境相关属性增加AspectJ的支持

4.BeanFactory的后处理:

按顺序调用BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry()。BeanFactoryPostProcessor.postProcessBeanFactory()。 可以实现它们以达到动态注册bean定义,动态修改bean定义,以及动态修改bean。激活BeanPostProcessor处理器。初始化各种实现了MessageSource接口的子类。完成消息和资源的初始化。例如国际化i18n配置。初始化消息广播器。

5.初始化非延迟加载单例:

准备转换器ConversionService。其作用也就是bean的一个属性解析。然后在初始化bean之前,把这些bean冻结起来,不让他们被修改。然后对于那些希望在容器启动阶段就创建的bean(非延迟),调用getBean()方法创建。(其详细过程:Spring源码系列:Bean的加载)

6.完成上下文的刷新工作。


最后,我们可以看出来,ApplicationContext和BeanFactory的一个优缺点比较:

功能的丰富程度上,ApplicationContext拓展的功能更多,使用率也更高。

但是功能多了,启动过程复杂了,那么ApplicationContext的启动速度必然要比BeanFactory要慢。

下一篇文章准备学习下Spring-AOP,也正好弥补本文当中ApplicationContext容器对AspectJ功能支持 这一环节源码的讲解。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号