spring源码初步学习-容器的功能扩展(ApplicationContext)

时间:2021-11-10 17:20:05

第三部分:容器功能的扩展

ApplicationContext和BeanFactory两者都是用于加载Bean的,但是相比之下,ApplicationContext提供了更多的扩展功能。

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {

super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

其中setConfigLocations(configLocations)用于设置配置路径;

reffesh()函数包含了几乎ApplicationContext中提供的全部功能。


一 扩展功能概览——refresh():

reffesh()函数包含了几乎ApplicationContext中提供的全部功能。

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {

//1 初始化前的准备工作
<strong>prepareRefresh();</strong>

//2 初始化beanFactory,并进行XML文件读取
ConfigurableListableBeanFactory beanFactory = <strong>obtainFreshBeanFactory()</strong>;

//3 对beanFactory进行各种功能填充
<strong>prepareBeanFactory(beanFactory);</strong>

try {
//4 子类覆盖方法做额外的处理
<strong>postProcessBeanFactory(beanFactory);</strong>

// 激活各种beanFactory处理器
<strong>invokeBeanFactoryPostProcessors(beanFactory);</strong>

// 注册拦截bean创建的Bean处理器,这里只是注册,真正调用是在getBean时候
<strong>registerBeanPostProcessors(beanFactory);</strong>

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

// Initialize event multicaster for this context.
//初始化应用消息广播器,并放入“applicationEventMulticaster”bean中
<strong> initApplicationEventMulticaster();</strong>

//留给子类来初始化其他bean
onRefresh();

// 在所有注册的bean中查找Listener bean,注册到消息广播器中
<strong>registerListeners();</strong>

// 初始化剩下的单实例
<strong>finishBeanFactoryInitialization(beanFactory);</strong>

// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
finishRefresh();
}

catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}
}
1 初始化前的准备工作,例如对系统属性或者环境变量进行准备及验证

2 初始化BeanFactory,并进行XML文件读取

这一步骤会复用BeanFactory中的 配置文件读取解析 及其他功能。这一步骤之后,ClassPathXmlApplicationContext实际上已经包含了BeanFactory所提供的功能

3 对BeanFactory进行各种功能填充

在这一步增加对@Qualifier和@Autowired注解的支持

4 提供一个空的函数postProcessBeanFactory()来方便程序猿在业务上做进一步扩展


二 加载BeanFactory——obtainFreshBeanFactory()

        // 1.初始化BeanFactory,并进行XML文件读取,将得到的BeanFactory记录在当前实体的属性中
<strong>refreshBeanFactory();</strong>
// 2.返回当前实体的beanFactory属性
<strong>ConfigurableListableBeanFactory beanFactory = <strong>getBeanFactory();</strong>
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}</span>

protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}</span>
1 创建DefaultListableBeanFactory

DefaultListableBeanFactory beanFactory = createBeanFactory();

XmlBeanFactory继承自DefaultListableBeanFactory,并提供了XmlBeanDefinitionReader类型的reader属性。

也就是说DefaultListableBeanFactory是容器的基础,必须首先要实例化。

2 定制BeanFactory:

customizeBeanFactory(beanFactory);

设置相关属性(包括设置@Autowired和@Qualifier注解解析器QualifierAnnotationAutowireCandidateResolver等)

在创建bean时,如果采用autowireByType方式注入,Spring在这里使用了QualifierAnnotationAutowireCandidateResolver,设置了这个解析器后Spring就可以支持注解方式的注入了

3 加载BeanDefinition

loadBeanDefinitions(beanFactory);

使用XmlBeanDefinitionReader的loadBeanDefinitions方法进行配置文件的加载及注册,这完全就是BeanFactory的套路。

因为在XmlBeanDefinitionReader中已经将之前初始化的DefaultListableBeanFactory注册进去了,所以XmlBeanDefinitionReader所读取的BeanDefinitionHolder都会注册到DefaultListableBeanFactory中。

即经过此步骤,类型DefaultListableBeanFactory的变量beanFactory已经包含了所有解析好的配置。

4 使用全局变量记录BeanFactory类实例

this.beanFactory = beanFactory;


三 功能扩展——prepareBeanFactory(beanFactory)

在进入prepareBeanFactory(beanFactory)前,Spring已经完成了对配置的解析,而ApplicationContext在功能上的扩展也由此展开

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {

// 设置beanFactory的classLoader为当前context的classLoader
beanFactory.setBeanClassLoader(getClassLoader());

// 设置beanFactory的表达式语言处理器
 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());

// 为beanFactory增加一个默认的propertyEditor,它主要是对bean的属性等设置管理的一个工具
 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

// 添加beanPostProcessor
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

// 设置几个忽略自动装配的接口
 beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

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

// 增加对AspectJ的支持
if (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());
}
}

1 添加ApplicationContextAwareProcessor:beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

Spring激活bean的init-method的前后,会调用BeanPostProcessor的postProcessBeforeInitialization方法和postProcessAfterInitialization方法

ApplicationContextAwareProcessor的postProcessBeforeInitialization方法的逻辑中,完成了对实现各种Aware接口的bean在初始化之后注入对应资源的功能。


四 BeanFactory的后处理

1 激活注册的BeanFactoryPostProcessor:invokeBeanFactoryPostProcessors(beanFactory);

BeanFactoryPostProcessor接口跟BeanPostProcessor类似,可以对bean的定义(配置元数据)进行处理。也就是说,Spring Ioc容器允许BeanFactoryPostProcessor在容器实际实例化任何其他的bean之前读取配置元数据,并有可能修改它。

如果你在容器中定义一个BeanFactoryPostProcessor,它仅仅对此容器中的bean进行后置处理。

当Spring加载任何实现了BeanFactoryPostProcessor接口的bean的配置时,都会在bean工厂载入所有bean的配置之后执行postProcessbeanFactory方法。


2 注册BeanPostProcessor:registerBeanPostProcessors(beanFactory);**

Spring中大部分的功能都是通过后处理器的方式进行扩展的,这是Spring框架的一个特性。

但是在BeanFactory中其实并没有实现后处理器的自动注册,所以在调用的时候如果没有进行手动注册其实是不能使用的。

但是在ApplicationContext中却添加了自动注册功能。


3 初始化消息资源:initMessageSource();


4 初始化ApplicationEventMulticaster:initApplicationEventMulticaster();**

如果用户自定义了事件广播器,那么使用用户自定义的事件广播器;否则使用默认的ApplicationEventMulticaster

作为广播器,一定是用于存放监听器并在合适的时候调用监听器。

当产生Spring事件的时候,会默认使用SimpleApplicationEventMulticaster的multicastEvent来广播事件;遍历所有监听器,并使用监听器中的onApplicationEvent方法来进行监听器的处理。



五 初始化非延迟加载单例——finishBeanFactoryInitialization(beanFactory);

完成BeanFactory的初始化工作,其中包括

1 ConversionService的设置**

2 配置冻结

冻结所有bean定义,说明注册的bean定义将不被修改或进行任何进一步的处理

3 非延迟加载的bean的初始化工作

ApplicationContext实现的默认行为就是在启动时将所有单例bean提前进行实例化。

提前实例化意味着,作为初始化的一部分,ApplicationContext实例会创建并配置所有的单例bean。


六 finishRefresh

在Spring中还提供了Lifecycle接口,Lifecycle中包含start/stop方法。

实现此接口后Spring会保证在启动的时候调用其start方法开始生命周期,并在Spring关闭的时候调用stop方法来结束生命周期。

protected void finishRefresh() {
// Initialize lifecycle processor for this context.
initLifecycleProcessor();

// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();

// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));

// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}

1 初始化LifecycleProcessor

2 启动所有实现了Lifecycle接口的bean

3 当晚餐ApplicationContext初始化的时候,要通过Spring中的事件发布机制来发出ContextRefreshEvent事件,以保证对应的监听器可以做进一步的逻辑处理



补充 Spring功能使用示例

1 PropertyEditor的使用

在Spring DI注入的时候可以把普通属性注入进来,但是像Date类型就无法被识别。即如果一个Bean的属性是Date类型时,但在XML中配置的却是String类型的,这时会抛出异常。

此时可以使用自定义属性编辑器来解决

示例:

实体类UserManager


public class UserManager {

private Date dataValue;

public Date getDataValue() {
return dataValue;
}

public void setDataValue(Date dataValue) {
this.dataValue = dataValue;
}

@Override
public String toString() {
return "UserManager [dataValue=" + dataValue + "]";
}

}

自定义的属性编辑器DatePropertyEditor

public class DatePropertyEditor extends PropertyEditorSupport {
private String format = "YYYYMMdd";

public void setFormat(String format) {
this.format = format;
}

@Override
public void setAsText(String text) throws IllegalArgumentException {
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
Date d = sdf.parse(text);
this.setValue(d);
} catch (ParseException e) {
e.printStackTrace();
}
}

}

配置文件

    <!-- 测试propertyEditor -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean class="com.zhangyiwen.website03.base_exercise.spring.property_editor.DatePropertyEditor"></bean>
</entry>
</map>
</property>
</bean>
<bean id="userManager" class="com.zhangyiwen.website03.base_exercise.spring.property_editor.UserManager">
<property name="dataValue" value="20150404"></property>
</bean>

测试代码

UserManager manager = (UserManager) ctx.getBean("userManager");
System.out.println(manager.toString());

运行结果

UserManager [dataValue=Sun Dec 28 00:00:00 CST 2014]



2 Converter的使用

之前我们使用自定义类型转换器PropertyEditor将配置文件中的String转换为Date。

Spring中还提供了另一种转换方式,使用Converter.

具体使用方法另外查吧




3 BeanFactoryPostProcessor的使用

BeanFactoryPostProcessor和BeanPostProcessor,这两个接口,都是Spring初始化bean时对外暴露的扩展点。

public interface BeanFactoryPostProcessor {

void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}
BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息


例子:

配置文件

    <!-- 测试BeanFactoryPostProcessor -->
<bean id="myJavaBean" class="com.zhangyiwen.website03.base_exercise.spring.bean_factory_post_processor.MyJavaBean">
<property name="desc" value="测试一下啦" />
<property name="remark" value="这是备注信息啦啦啦" />
</bean>
<bean id="myBeanFactoryPostProcessor" class="com.zhangyiwen.website03.base_exercise.spring.bean_factory_post_processor.MyBeanFactoryPostProcessor" />

java类

public class MyJavaBean {

private String desc;

private String remark;

}

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out
.println("调用MyBeanFactoryPostProcessor的postProcessBeanFactory");
BeanDefinition bd = beanFactory.getBeanDefinition("myJavaBean");
System.out.println("属性值============"
+ bd.getPropertyValues().toString());
MutablePropertyValues pv = bd.getPropertyValues();
if (pv.contains("remark")) {
pv.addPropertyValue("remark", "把备注信息修改一下");
}
bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
}
}

测试代码

ApplicationContext ctx = new ClassPathXmlApplicationContext(
            "test/beanFactoryTest.xml");
MyJavaBean bean = (MyJavaBean) ctx.getBean("myJavaBean");
System.out.println(bean.getDesc() + "," + bean.getRemark());

测试结果

调用MyBeanFactoryPostProcessor的postProcessBeanFactory
属性值============PropertyValues: length=2; bean property 'desc'; bean property 'remark'
init
测试一下啦,把备注信息修改一下

spring源码初步学习-容器的功能扩展(ApplicationContext)


4 BeanPostProcessor的使用


BeanPostProcessor,可以在spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些自己的处理逻辑。

这里说的初始化方法,指的是下面两种:

1)bean实现了InitializingBean接口,对应的方法为afterPropertiesSet

2)在bean定义的时候,通过init-method设置的方法

BeanPostProcessor是在spring容器加载了bean的定义文件并且实例化bean之后执行的。BeanPostProcessor的执行顺序是在BeanFactoryPostProcessor之后。

spring中,有内置的一些BeanPostProcessor实现类,例如:

  • org.springframework.context.annotation.CommonAnnotationBeanPostProcessor:支持@Resource注解的注入
  • org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor:支持@Required注解的注入
  • org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor:支持@Autowired注解的注入
  • org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor:支持@PersistenceUnit和@PersistenceContext注解的注入
  • org.springframework.context.support.ApplicationContextAwareProcessor:用来为bean注入ApplicationContext等容器对象

以上这些注解类的BeanPostProcessor,在spring配置文件中,可以通过这样的配置 <context:component-scan base-package="*.*" /> ,自动进行注册。(spring通过ComponentScanBeanDefinitionParser类来解析该标签


例子:

配置文件

    <!-- 测试BeanPostProcessor -->
<bean id="myJavaBean2" class="com.zhangyiwen.website03.base_exercise.spring.bean_post_processor.MyJavaBean2" init-method="initMethod">
<property name="desc" value="原始的描述信息" />
<property name="remark" value="原始的备注信息" />
</bean>
<bean id="myBeanPostProcessor" class="com.zhangyiwen.website03.base_exercise.spring.bean_post_processor.MyBeanPostProcessor" />

java代码

public class MyJavaBean2 implements InitializingBean {
private String desc;
private String remark;

public MyJavaBean2() {
System.out.println("MyJavaBean的构造函数被执行啦");
}

public String getDesc() {
return desc;
}

public void setDesc(String desc) {
System.out.println("调用setDesc方法");
this.desc = desc;
}

public String getRemark() {
return remark;
}

public void setRemark(String remark) {
System.out.println("调用setRemark方法");
this.remark = remark;
}

@Override
public void afterPropertiesSet() throws Exception {
System.out.println("调用afterPropertiesSet方法");
this.desc = "在初始化方法中修改之后的描述信息";
}

public void initMethod() {
System.out.println("调用initMethod方法");
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("[描述:").append(desc);
builder.append(", 备注:").append(remark).append("]");
return builder.toString();
}
}

public class MyBeanPostProcessor implements BeanPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("BeanPostProcessor,对象" + beanName + "调用初始化方法之前的数据: "
+ bean.toString());
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("BeanPostProcessor,对象" + beanName + "调用初始化方法之后的数据:"
+ bean.toString());
return bean;
}

}

测试代码

MyJavaBean2 bean = (MyJavaBean2) ctx.getBean("myJavaBean2");
System.out.println("===============下面输出结果============");
System.out.println("描述:" + bean.getDesc());
System.out.println("备注:" + bean.getRemark());

测试结果

调用MyBeanFactoryPostProcessor的postProcessBeanFactory
属性值============PropertyValues: length=2; bean property 'desc'; bean property 'remark'
MyJavaBean的构造函数被执行啦
调用setDesc方法
调用setRemark方法
BeanPostProcessor,对象myJavaBean2调用初始化方法之前的数据: [描述:原始的描述信息, 备注:原始的备注信息]
调用afterPropertiesSet方法
调用initMethod方法
BeanPostProcessor,对象myJavaBean2调用初始化方法之后的数据:[描述:在初始化方法中修改之后的描述信息, 备注:原始的备注信息]
===============下面输出结果============
描述:在初始化方法中修改之后的描述信息
备注:原始的备注信息

从上面的结果可以看出,BeanFactoryPostProcessor在bean实例化之前执行,之后实例化bean(调用构造函数,并调用set方法注入属性值),然后在调用两个初始化方法前后,执行了BeanPostProcessor。初始化方法的执行顺序是,先执行afterPropertiesSet,再执行init-method。


5 Event和Listener的使用


event和listener是观察者模式的典型应用,可以在比较关心的事件结束后进行及时处理。

Spring会在event事件发生时,将发出的event事件转给相应的EventListener进行进一步处理


例子:

配置文件

<!-- 测试event和Listener -->
<bean id="testListener" class="com.zhangyiwen.website03.base_exercise.spring.event.TestListener" />

java代码

public class TestEvent extends ApplicationEvent {

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

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

private static final long serialVersionUID = 1L;

public String msg;

public void print() {
System.out.println("event message is " + msg);
}

}

public class TestListener implements ApplicationListener<ApplicationEvent> {

@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof TestEvent) {
TestEvent testEvent = (TestEvent) event;
testEvent.print();
}
}

}

测试代码

ApplicationContext ctx = new ClassPathXmlApplicationContext(
            "test/beanFactoryTest.xml");
TestEvent event = new TestEvent("hello", "msg。。。");
ctx.publishEvent(event);

测试结果

event message is msg。。。