• 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源码后的理解。

  • 相关阅读:
    supersockets扩展服务器配置
    SuperSocket根据条件获取 Session
    SuperSocket获取所有连接上的 Session
    淘宝天猫店铺微信公众平台建设指南
    微信浏览器内置JavaScript 对象:WeixinJSBridge
    微信公众平台开发(41)一键关注微信公众平台账号
    微信公众平台开发(39)支付宝手机网站支付
    如何重启一个控制台程序
    微信公众平台自定义菜单接口开发(1)
    Unicode编码解码在线转换工具
  • 原文地址:https://www.cnblogs.com/bokers/p/14903062.html
Copyright © 2020-2023  润新知