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

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

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
测试一下啦,把备注信息修改一下



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。。。
















  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值