zoukankan      html  css  js  c++  java
  • Spring源码之容器的功能拓展-ApplicationContext

    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();
    			}
    		}
    	}
    

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

    • 定义钩子函数:initPropertySources() 当需要校验时由子类实现该方法<模板方法模式>
    • 通过 getEnvironment().validateRequiredProperties() 校验
    protected void prepareRefresh() {
    
    		//  子类实现该函数,并设置需要校验的 内容
    		initPropertySources();//  钩子函数  初始化上下文环境中的任何占位符属性资源
    		
    		//  验证需要的属性文件是否已经 放入环境中  《《《 initPropertySources 是否完成工作 ??
    		getEnvironment().validateRequiredProperties();
    	}
    

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

    • 已知的是ApplicationContext 是对BeanFactory的 拓展,经过这一步之后,ApplicationContext 将拥有 BeanFactory 的全部功能;

    • AbstractRefreshableApplicationContext 中 实现的方法 refreshBeanFactory() 会产生一个默认的 DefaultListableBeanFactory 对象,

    • 并加载类的 xml 配置 ,最终 ApplicationContext 将持有该 DefaultListableBeanFactory 对象;因此说它拥有 BeanFactory 的所有功能。

    @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 语言的支持

    • 注册表达式语言SpEL解析器/处理器, 它主要是在依赖解析注入bean的时候、完成bean的初始化和属性获取后的属性填充的时候调用。

    • 例如解析: #{bean.filed}
      loadBean[ BeanFactory.getBean(beanName); ] 过程中的属性注入注入环节:applyPropertyValues,
      会调用方法 BeanDefinitionValueResolver.resolveValueIfNecessary() 解析上述定义的参数

    1. 增加 属性注册编辑器
    • 添加默认的propertyEditor,它主要是:对bean的属性等设置进行管理,的一个工具

    例如在 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();

    • spring自带属性编辑器,使用案例详见: AbstractBeanFactory.initBeanWrapper() -> registerCustomEditors();
      -> ResourceEditorRegistrar.registerCustomEditor() 注册常用的 属性编辑器
    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());
    
    • 后处理器的作用范围是容器级的,仅仅对当前容器中的 bean 生效;

    • 需要激活 以及 注册(提取并调用)

    • 还需要考虑 各种后处理器是否 实现了排序接口

    • BeanFactoryPostProcessor 可以对 bean 定义的元数据进行处理,
      可以说Spring 容器 允许 BeanFactoryPostProcessor , 在实际实例化任意bean之前读取配置的元数据并进行处理。

    • 可以分为xml 文件配置的 BeanFactoryPostProcessor 后处理器 和 硬编码类型的 BeanFactoryPostProcessor 后处理器。

    五、注册后处理器 BeanPostProcessor

    • 仅仅对 BeanPostProcessor 类型的后处理器进行注册,实际调用发生在 getBean(beanName); 实例化bean的时候

    • 类似对 BeanFactoryPostProcessor 的处理,区别是 BeanPostProcessor 由于只需要注册不需要激活,所以它只处理配置文件中配置的 BeanPostProcessor ,而不处理硬编码类型的 BeanPostProcessor

    后续环节

    后续环节还包括:

    • 为上下文初始化message 源 ,即不同语言的消息体(国际化处理)

    • 初始化 应用消息 广播器,并放入 "applicationEventMulticaster" bean 中

    • 在所有注册的bean中,查找 Listener-bean , 注册到消息广播器中

    • 初始化 非延迟加载单例

    • 完成刷新过程,通知生命周期处理器 lifecycleProcessor 刷新过程

      。。。。 等等

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

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

  • 相关阅读:
    【乱侃】How do they look them ?
    【softeware】Messy code,some bug of Youdao notebook in EN win7
    【随谈】designing the login page of our project
    【web】Ad in security code, making good use of resource
    SQL数据库内存设置篇
    关系数据库的查询优化策略
    利用SQL未公开的存储过程实现分页
    sql语句总结
    sql中使用cmd命令注销登录用户
    SQLServer 分页存储过程
  • 原文地址:https://www.cnblogs.com/bokers/p/14903062.html
Copyright © 2011-2022 走看看