Spring源码之容器的功能拓展-ApplicationContext

时间:2021-06-19 19:31:28   收藏:0   阅读:0

PS * 本文代码基本为伪代码,注释为个人理解,水平有限,如有谬误,感谢指正。

关于spring的容器,除了BeanFactory以及它的默认实现类XmlBeanFactory之外。
Spring还提供了 ApplicationContext ,
它用于对 BeanFactory的拓展。

本文入口:

    ApplicationContext bf = new ClassPathXmlApplicationContext("bean.xml"");

核心代码:

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			
			prepareRefresh();//解析预备 刷新上下文环境  例如对系统属性或者环境变量进行校验和准备
			
			
			//  初始化 beanFactory 并读取xml  配置文件 , 此函数过后即拥有了 BeanFactory的全部功能
			//  向下转型 实际持有 它的子类: DefaultListableBeanFactory 类型的对象
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			
			
			//  ****####  DefaultListableBeanFactory  <-  beanFactory 
			//  功能拓展 
			//  beanFactory 初始化 <功能填充>  复用 BeanFactory 中的 配置文件读取、解析 以及其他功能  
			prepareBeanFactory(beanFactory);
			
			try {
				
				postProcessBeanFactory(beanFactory);//  钩子函数,由子类实现  后处理器 
				
				
				//  激活各种 BeanFactory 处理器 
				//  postProcessor  后处理器  
				//  ** 激活 ** 注册的 各种  BeanFactoryPostProcessor 
				//  **激活**  且  **注册**
				invokeBeanFactoryPostProcessors(beanFactory);
				
				
				//  ** 注册 **   BeanPostProcessors ,用于拦截 Bean 的创建 
				//  《后处理器》,仅仅注册,在getBean方法调用时才会实际触发   《不激活》
				//  因为仅仅注册,所以不需要考虑 硬编码方式的后处理器 
				//  对于硬编码方式的后处理器  仅仅在 getBean时被调用 
				registerBeanPostProcessors(beanFactory);
				// 注册最终调用 AbstractBeanFactory.addBeanPostProcessor()
				//  AbstractBeanFactory <==  AbstractAutowireCapableBeanFactory <==  DefaultListableBeanFactory
				
				
				
				//  为上下文初始化message 源 ,即不同语言的消息体(国际化处理)
				initMessageSource();
				
				//  初始化 应用消息  广播器,并放入  "applicationEventMulticaster" bean 中 
				initApplicationEventMulticaster();
				
				//  留个子类来初始化其它的 bean  《钩子函数》
				onRefresh();
				
				//  在所有注册的bean中,查找 Listener-bean ,  注册到消息广播器中
				registerListeners();
				
				//  初始化 非延迟加载单例  
				finishBeanFactoryInitialization(beanFactory);
				
				//  完成刷新过程,通知生命周期处理器  lifecycleProcessor 刷新过程 
				//  发出  ContextRefreshEvent 通知别人 
				finishRefresh();
			}
			catch (BeansException ex) {
				destroyBeans();
				cancelRefresh(ex);
				throw ex;
			}
			finally {
				resetCommonCaches();
			}
		}
	}

一、解析预备 刷新上下文环境 例如对系统属性或者环境变量进行校验和准备

protected void prepareRefresh() {

		//  子类实现该函数,并设置需要校验的 内容
		initPropertySources();//  钩子函数  初始化上下文环境中的任何占位符属性资源
		
		//  验证需要的属性文件是否已经 放入环境中  《《《 initPropertySources 是否完成工作 ??
		getEnvironment().validateRequiredProperties();
	}

二、初始化 BeanFactory 并进行 Xml 配置文件的读取

@Override
	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {//  已有,不再重复该逻辑
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());//  为了序列化指定ID 

			//  定制 beanFactory 包括是否允许覆盖同名称不同定义的对象、循环依赖  
			//  设置 @AutoWired 和 @Qualifier 的注解解析器 QualifierAnnotationAutowireCandidateResolver 
			customizeBeanFactory(beanFactory);
			//  初始化 DocumentReader 并进行 xml 读取、解析
			loadBeanDefinitions(beanFactory);//  类 AbstractXmlApplicationContext 提供实现 
			this.beanFactory = beanFactory;//  记录到全局变量
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

三、对BeanFactory 各种功能填充

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {

  1. 定制 BeanFactory 设置 beanFactory 的类加载器 为当前的 context的 类加载器

  2. 增加对SpEL 语言的支持

  1. 增加 属性注册编辑器

例如在 XML 配置中定义

<property name="currentDate">
    <value>2021-05-03</value>
</property>
<property name="name">
    <value>张二狗</value>
</property>

在 bean 中定义:

private Date currentDate; 
private String name;

当spring 进行注入的时候,可以把普通属性name注入进来,但是却不能识别bean中定义的Date类型currentDate;
有两种解决方法:

a. 使用自定义属性编辑器即可,需要继承 类: Property|EditorSupport 并重写 setAsText() 方法;

b. 使用spring 自带的属性编辑器:CustomDateEditor,

设置属性注册编辑器 AbstractBeanFactory.addPropertyEditorRegistrar();

  1. 增加 ApplicationContextAwareProcessor 处理器,该后处理器用于对 容器的补充/增强,而非普通bean的后处理器

在init-method的前后,将调用该处理器的postProcessBeforeInitialization()方法 和postProcessAfterInitialization()方法;

  1. 设置 忽略依赖

当 Spring 将ApplicationContextAwareProcessor 注册后,在 invokeAwareInterfaces() 方法中 间接调用的Aware 类已经不是普通的 bean 了,
如:ResourceLoaderAware,所以需要在spring进行bean的依赖注入的时候忽略掉它们。

  1. 注册依赖

同样spring 也提供了 注册依赖的功能

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

当解析到对类型 BeanFactory.class 的依赖时,会直接将它的实例 beanFactory 注入。

四、激活以及注册各种 BeanFactoryPostProcessor 后处理器

PostProcessorRegistrationDelegate
        .invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

五、注册后处理器 BeanPostProcessor

后续环节

后续环节还包括:

由于逻辑并不复杂,不再记录。

-- 本文仅为个人学习spring源码后的理解。

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!