容器功能的扩展
ApplicationContext用于扩展BeanFactory中现有的功能。究竟多出了哪些功能,进一步探索。写法上:
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));

ApplicationContext bf = new ClassPahtApplicationContext("beanFactoryTest.xml");
还是以ClassPahtApplicationContext作为切入点:
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

ClassPahtApplicationContext可以对数据进行解析并进行加载,而对于解析及功能实现都是在refresh()中实现

setConfigLocations(String... locations):设置配置路径
用于解析给定的路径数组,如果数组中包含特殊符号如$(var),那么resolvePath中会搜索匹配的变量并替换

refresh();扩展功能
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();
}
}
}
1_ prepareRefresh()初始化的准备工作,例如对系统属性或者环境变量进行准备及验证。
2_ obtainFreshBeanFactory 初始化BeanFactory,并进行XML文件读取
ClassPathXmlApplicationContext包含着BeanFactory所提供的一切特征,在这一步中将会复用BeanFactory中的配置文件读取解析及其它功能,这一步之后,ClassPathXmlApplicationContext实际上就包含了BeanFactory所提供的功能,也就是可以进行Bean的提取等基础操作了
3_ prepareBeanFactory() 对BeanFactory进行各种功能填充
@Qualifier与@Autowired正式在这一步骤中提供的支持
4_ postProcessBeanFactory() 子类覆盖方法做额外处理
postProcessBeanFactory是一个空函数,需要自己重写子类,覆盖方法来方便在业务上进行扩展
5_ invokeBeanFactoryPostProcessors(beanFactory) 激活各种BeanFactory处理器
6_ registerBeanPostProcessors(beanFactory) 注册拦截bean创建的bean处理器,这里只是注册,真正的调用在getBean的时候。
7_ initMessageSource() 为上下文初始化Message源,即对不同语言的消息体进行国际化处理。
8_ initApplicationEventMulticaster() 初始化应用消息广播器,并犯法如“applicationEventMuliticaster”bean中。
9_ onRefresh()留个子类初始化其他的bean
10_ registerListeners() 在所有注册的bean中查找listener bean,注册到消息广播器中
11_ finishBeanFactoryInitialization(beanFactory) 初始化剩下的单实例(非惰性的)。
12_ finishRefresh()完成刷新功能,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人。

1__ prepareRefrsh 主要做些准备工作,例如对系统属性和环境变量的初始化及验证
里边两个主要的方法initPropertySources(),validateRequiredProperties()。
initPropertySources,用户根据自己的需要重写initPropertySources()方法,并在方法进行个性化的属性处理及设置
validateRequiredProperties,对属性验证。如:工程需要某个设置(VAR)从系统环境变量中获取,如果用户没配这个变量,那么系统不能工作。这一要求在spring就可以自定义一个类集成ClassPathXmlApplicationContext,在initPropertySources()里用getEnviroment().setRequiredProperties("VAR")设置这个属性,那么在验证的就是验证这个属性,没有就会报错。当然也要在使用的时候替换掉原有的ClassPathXmlApplicationContext:ApplicationContext bf = new MyApplicationPathApplicationContext("test.xml");
2__ obtainFreshBeanFactory
加载BeanFactory,经过这个函数后,ApplicationContext就有了BeanFactory的全部功能。这个方法里的步骤:
1.创建DefaultListableBeanFactory
前面用的BeanFactory bf = new XmlBeanFactory("text.xml")中的XmlBeanFactory继承自DefaultListenBeanFactory,并提供了XmlBeanDefinitionReader属性,也就是说DefaultListenBeanFactory是容器的基础。必须首先实例化。
2.是定序列化ID
3.定制BeanFactory
customizeBeanFactory(beanFactory)
4.加载BeanDefinition
5.使用全局变量记录BeanFactory类实例。因为DefaultListenBeanFactory类型的变量beanFacotory是函数内的局部变量,所有要用全局变量来记录解析结果。
3_ customizeBeanFactory(beanFactory)
这里已经开始了对BeanFactory的扩展,在基本容器的基础上,增加了是否允许覆盖是否允许扩展的设置并提供了@Qualifier和@Autowired的支持。允许覆盖允许扩展只是判断了是否为空,为空就进行设置,但是在此之前哪个地方来设置它并没有看见,还是在子类的customizeBeanFactory覆盖方法中进行设置。接下来就是加载BeanDefinition,需要XmlBeanDefinitionReader来读取xml,这里首先初始化它,调用loadBeanDefinitions方法,和前面说的Beanfactory的加载一模一样。
这里还有很多细节。(书的135页)
3__ prepareBeanFactory() 功能扩展
1增加SPEL语言的支持
2增加属性注册编辑器
spring在DI的时候类似于Date这种属性无法识别,会报错,可以有两种方法解决
1:使用自定义属性编辑器
2:注册spring自带的属性编辑器CustomDateEditor
3添加ApplicationContextAwareProcessor处理器
对于beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this))的主要目的就是注册个BeanPostProcessor。真正的逻辑还在ApplicationContextAwareProcessor中。ApplicationContextAwareProcessor实现BeanPostProcessor接口。之前在bean实例化的时候,也就是spring激活bean的init-method的前后,会调用BeanPostProcessor的postProcessBeforeInitialization方法和postProcessAfterInitialization方法,同样对于ApplicationContextAwareProcessor我们也看这两个方法。
postProcessAfterInitialization方法没有做过多逻辑处理
postProcessBeforeInitialization方法,其中主要的逻辑是调用了invokeAwareInterfaces,从这个方法代码中能看出主要是实现这些Aware接口在被初始化的后,可以获得一些对应的资源。
4.设置忽略依赖。将ApplicationContextAwareProcessor注册后,invokeAwareInterfaces方法中间接调用的Aware已经不是普通的bean了,需要在spring做bean的依赖注入的时候忽略他们。
5.注册依赖。当注册了依赖解析后,例如当注册了对BeanFactory.Class的解析依赖后,当bean的属性注入的时候,一旦检测属性为BeanFactory类型便会将实例beanFactory注入进去。
4_ postProcessBeanFactory BeanFactory的后处理
11_ finishBeanFactoryInitialization(beanFactory)
完成BeanFactory的初始化工作,其中包括ConversionService的设置、配置冻结以及非延迟加载的bean的初始化工作。
1.ConversionService的设置。之前说过用自定义类型转化器可以从String转Date,spring中还提供了另外一种转换方式:使用Converter。
2.冻结配置。冻结所有的bean定义说明注册的bean定义将不能被修改或进行任何进一步处理。
3.初始化非延迟加载。ApplicationContext实现的默认方式就是在启动的时候将所有的单例bean提前实例化,通常只是好事,因为这样在配置的中的错误能马上就发现。这个实例化的过程是在finishBeanFactoryInitialization中完成的。
12_ finishRefresh
在spring中还提供了Lifecycle接口,包好start/stop方法,实现此接口后Spring会保证在启动的时候调用其start方法开始生命周期,并在关闭的时候调用stop方法接受生命周期,通常用来配置后台程序,在启动后一直运行(如对MQ进行轮询)。
1.initLifecycleProcessor:当ApplicationContext启动或停止时,会通过LifecycleProcessor来与所有的bean的周期做状态更新,而在使用前需要初始化
2.onRefresh:启动所有实现了Lifecycle接口的bean
3.publishEvent:当完成ApplicationContext初始化的时候,要通过Spring中的时间发布机制来发出ContextRefreshEvent事件,保证对应的监听器可以进一步的逻辑处理。

spring源码深度解析-2功能扩展的更多相关文章

  1. spring源码深度解析— IOC 之 容器的基本实现

    概述 上一篇我们搭建完Spring源码阅读环境,spring源码深度解析—Spring的整体架构和环境搭建 这篇我们开始真正的阅读Spring的源码,分析spring的源码之前我们先来简单回顾下spr ...

  2. Spring源码深度解析之Spring MVC

    Spring源码深度解析之Spring MVC Spring框架提供了构建Web应用程序的全功能MVC模块.通过策略接口,Spring框架是高度可配置的,而且支持多种视图技术,例如JavaServer ...

  3. Spring源码深度解析之事务

    Spring源码深度解析之事务 目录 一.JDBC方式下的事务使用示例 (1)创建数据表结构 (2)创建对应数据表的PO (3)创建表和实体之间的映射 (4)创建数据操作接口 (5)创建数据操作接口实 ...

  4. spring源码深度解析— IOC 之 默认标签解析(上)

    概述 接前两篇文章  spring源码深度解析—Spring的整体架构和环境搭建  和  spring源码深度解析— IOC 之 容器的基本实现 本文主要研究Spring标签的解析,Spring的标签 ...

  5. spring源码深度解析— IOC 之 默认标签解析(下)

    在spring源码深度解析— IOC 之 默认标签解析(上)中我们已经完成了从xml配置文件到BeanDefinition的转换,转换后的实例是GenericBeanDefinition的实例.本文主 ...

  6. spring源码深度解析— IOC 之 开启 bean 的加载

    概述 前面我们已经分析了spring对于xml配置文件的解析,将分析的信息组装成 BeanDefinition,并将其保存注册到相应的 BeanDefinitionRegistry 中.至此,Spri ...

  7. Spring源码深度解析之数据库连接JDBC

    Spring源码深度解析之数据库连接JDBC JDBC(Java Data Base Connectivity,Java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供 ...

  8. Spring源码深度解析系列-----------org.springframework.aop-3.0.6.RELEASE

    Spring源码深度解析系列-----------org.springframework.aop-3.0.6.RELEASE

  9. spring源码深度解析—Spring的整体架构和环境搭建

    概述 Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用.Spring是于2003 年兴起的一个轻量级的Java 开发框 ...

随机推荐

  1. 翻译之basename()

    NAME top basename, dirname - parse pathname components SYNOPSIS top #include <libgen.h> char * ...

  2. MSSQL删除字段时出现 服务器: 消息 5074,级别 16,状态 1,行 1 的解决办法

    有的朋友在做用户维护字段的界面时,肯定发现一个问题,当用脚本:ALTER TABLE 表名 DROP COLUMN 字段名进行删除字段的操作时,会出现“服务器: 消息 5074,级别 16,状态 1, ...

  3. jquery简单插件到复杂插件(3)--顶部导航固定

    那个效果很多,比如hao123的头部 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" ...

  4. Hashtable与ConcurrentHashMap区别

    Hashtable与ConcurrentHashMap区别 ConcurrentHashMap融合了hashtable和hashmap二者的优势. hashtable是做了同步的,是线性安全的,(2) ...

  5. linux定时任务crontab

    今天在执行mysql定时任务语句时候问了很多大拿,都建议我不要随便在生产环境下写定时任务这样的语句,有的说会有延时,那样的话就不准了,有的说在.系统时间和本地时间不一致怎么办?后来就建议我用linux ...

  6. C#读写本地ini

    //读写INI public class GF_INI { [DllImport("kernel32")] private static extern long WritePriv ...

  7. 建立exception包,编写TestException.java程序,主方法中有以下代码,确定其中可能出现的异常,进行捕获处理。

    package exception; public class TestException { public static void main(String[] args) { for(int i=0 ...

  8. 关于group by 两个或以上条件的分析

    关于group by 两个或以上条件的分析     原文地址:http://uule.iteye.com/blog/1569262 博客分类: 数据库   首先group by 的简单说明: grou ...

  9. Shifting List Item Values From One List To Another In Oracle Forms

    Suppose you have two T-List items in form and you want  to shift element values from one list to ano ...

  10. Creating Excel File in Oracle Forms

    Below is the example to create an excel file in Oracle Forms.Pass the Sql query string to the below ...