Spring后处理器

Spring框架提供了很好的扩张性,除了可以与各种第三方框架良好整合外,其IoC容器也允许开发者进行扩展,这种扩展甚至无须实现BeanFactory或ApplicationContext接口,而是允许通过两个后处理器对IoC容器进行扩展。

Spring提供了两种常用的后处理器:

 > Bean后处理器:这种后处理器会对容器中的Bean进行后处理,对Bean功能进行额外加强。

 > 容器后处理器:这种后处理器对IoC容器进行后处理,用于增强容器功能。


一、Bean后处理器

Bean后处理器是一种特殊的Bean,这种特殊Bean并不对外提供服务,它甚至可以无须id 属性,它主要负责对容器中的其他Bean执行后处理,例如为容器中的目标Bean生成代理等。

Bean后处理器必须实现BeanPostProcessor接口,该接口有两个方法:Object postProcessBeforeInitialization(Object bean,String name) 和Object postProcessAfterInitialization(Object bean,String name) 。


package PostProcessor;

//Bean后处理器

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
		// TODO Auto-generated method stub
		System.out.println("Bean后处理器在初始化之前对"+beanName+"进行增强处理...");	
		return bean;
	}
	
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName)
			throws BeansException {
		// TODO Auto-generated method stub
		
		System.out.println("Bean后处理器在初始化之后对"+beanName+"进行增强处理..");
		//如果该Bean是Chinese类的实例
		if(bean instanceof Chinese){
			//修改其name属性值
			Chinese c = (Chinese)bean;
			c.setName("Struts 2 ");
		}
		return bean;
	}
}

package PostProcessor;

import org.springframework.beans.factory.InitializingBean;

import DependencyInjection.Axe;
import DependencyInjection.Person;

public class Chinese implements Person ,InitializingBean		//依赖关系注入之后的行为
{

	private Axe axe;
	private String name;
	
	public Chinese(){
		System.out.println("Spring实例化主调bean:Chinese实例...");
	}
	
	public void setAxe(Axe axe) {
		this.axe = axe;
	}
	
	public void setName(String name) {
		System.out.println("Spring执行依赖注入.");
		this.name = name;
	}

	@Override
	public void useAxe() {
		// TODO Auto-generated method stub
		System.out.println(name+axe.chop());
	}
	
	//生命周期
	//测试用初始化方法	方法名与init-method属性对应,配置该方法只是普通方法,无代码污染
	public void begin(){
		System.out.println("正在执行初始化方法begin..");
	}
	//实现InitializingBean接口必须实现的方法
	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("正在执行初始化方法afterPropertiesSet..");
	}
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://www.springframework.org/schema/beans"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">

	<bean id="steelAxe" class="DependencyInjection.SteelAxe"/>
	<bean id="chinese" class="PostProcessor.Chinese" init-method="begin">
		<property name="axe" ref="steelAxe"/>
		<property name="name" value="依赖注入的值"/>
	</bean>
	
	<!-- Bean后处理器	可以无需指定id属性 -->
 	<bean id="beanPostProcessor" class="PostProcessor.MyBeanPostProcessor"/>
</beans>

package PostProcessor;

import org.springframework.core.io.ClassPathResource;
import org.springframework.beans.factory.xml.XmlBeanFactory;

import DependencyInjection.Person;

public class Test {

	public static void main(String[] args) throws Exception {

		//CLASSPATH路径下的xml文件创建Resource对象
		ClassPathResource isr = new ClassPathResource("bean.xml");
		//以Resource对象作为参数,创建BeanFactory的实例
		XmlBeanFactory factory = new XmlBeanFactory(isr);
		//获取Bean后处理器实例
		MyBeanPostProcessor prr = factory.getBean("beanPostProcessor",MyBeanPostProcessor.class);
		//注册BeanPostProcessor实例
		factory.addBeanPostProcessor(prr);
		Person p = factory.getBean("chinese",Person.class);
		p.useAxe();
	}
}
如果使用BeanFactory作为Spring容器,则必须手动注册Bean后处理器,因此程序中先获取Bean后处理器实例,然后手动注册——这就是在配置文件中指定Bean后处理器id 属性的原因,使用BeanFactory的addBeanPostProcessor即可注册Bean后处理器。

如果采用ApplicationContext作为Spring容器,则无须手动注册Bean后处理器。ApplicationContext可自动检测到容器中的Bean后处理器,自动注册。Bean后处理器会在Bean实例创建时自动启动,采用下面代码,效果也完全一样。

package PostProcessor;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import DependencyInjection.Person;

public class Test {

	public static void main(String[] args) throws Exception {
		
		ApplicationContext ctx =
				new ClassPathXmlApplicationContext("bean.xml");
		
		Person p = ctx.getBean("chinese",Person.class);
		p.useAxe();	
	}
}



由上面执行过程可以看出,Bean后处理器两个方法的回调时机如下:

...→ 注入依赖关系 → 回调postProcessBeforeInitialization 进行后处理 → 调用 afterPropertiesSet → 调用init-method 方法 → 回调PostProcessAfterInitialization 进行后处理 →...


实际中Bean后处理器完成的工作更加实际,例如生成Proxy。Spring框架本身提供了大量的Bean后处理器,下面是两个常用的后处理器:

 > BeanNameAutoProxyCreator:根据Bean实例的name属性,创建Bean实例的代理。

 > DefaultAdvisorAutoProxyCreator:根据提供的Advisor,对容器中所有的Bean实例创建代理。


二、容器后处理器

容器后处理器负责处理容器本身,必须实现BeanFactoryPostProcessor接口,该接口须实现一个方法:postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)。


package PostProcessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
			throws BeansException {
		// TODO Auto-generated method stub
		
		System.out.println("程序对Spring所做的beanFactory的初始化没有改变。。");
		System.out.println("Spring容器是:"+beanFactory);
	}

}


	<!-- 容器后处理器	 -->
 	<bean id="beanFactoryPostProcessor" class="PostProcessor.MyBeanFactoryPostProcessor"/>
将容器后处理器作为普通Bean部署在容器中,如果使用ApplicationContext作为容器,容器会自动调用BeanFactoryPostProcessor来处理Spring容器。但如果使用BeanFactory作为Spring容器,则必须手动调用容器后处理器来处理Spring容器。

package PostProcessor;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import DependencyInjection.Person;

public class Test {

	public static void main(String[] args) throws Exception {

		ApplicationContext ctx =
				new ClassPathXmlApplicationContext("beanPP.xml");
		
		Person p = ctx.getBean("chinese",Person.class);
		p.useAxe();		
	}
}



Spring没有提供ApplicationContextPostProcessor。对于ApplicationContext容器,一样使用BeanFactoryPostProcessor作为容器后处理器。

实现BeanFactoryPostProcessor接口的容器后处理器不仅可对BeanFactory执行后处理,也可以对ApplicationContext容器执行后处理。容器后处理器还可用来注册额外的属性编辑器。

Spring已提供如下几个常用的容器后处理器:

 > PropertyPlaceholderConfigurer:属性占位符配置器。

 > PropertyOverrideConfigurer:重写占位符配置器。

 > CustomAutowireConfigurer:自定义自动装配的配置器。

 > CustomScopeConfigurer:自定义作用域的配置器。


1、属性占位符配置器

Spring提供了PropertyPlaceholderConfigurer,它是一个容器后处理器,负责读取Properties属性文件里的属性值,并将这些属性值设置成Spring配置文件的元数据。

通过使用PropertyPlaceholderConfigurer后处理器,可以将Spring配置文件中的部分元数据放在属性文件中设置,这种配置方式有其优势:可以将部分相似的配置(比如说数据库的URL、用户名和密码)放在特定的属性文件中,如果只需要修改这部分配置,则无须修改Spring配置文件,修改属性文件即可。


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://www.springframework.org/schema/beans"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">

 	<!-- 属性占位符配置器	 PropertyPlaceholderConfigurer是一个容器后处理器,它会读取
 		属性文件信息,并将这些信息设置成Spring配置文件的元数据 -->
 	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
 		<property name="locations">
 			<list>
 				<value>dbconn.properties</value>
 				<!-- 如果有多个属性文件,依次在下面列出来 -->
 				<!-- <value>**.properties</value>-->
 			</list>
 		</property>
 	</bean>
 	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
 		<property name="driverClass" value="${jbdc.driverClassName}"/>
 		<property name="jbdcUrl" value="${jbdc.url}"/>
 		<property name="user" value="${jbdc.username}"/>
 		<property name="password" value="${jbdc.password}"/>
 	</bean>
</beans>
dbconn.properties:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/**
jdbc.username=**
jdbc.password=**

对于采用基于XML Schema 的配置文件而言,如果导入了context Schema,则可采用如下方式来配置该属性占位符

 	<context:property-placeholder location="classpath:dbconn.properties" -->

2、重写占位符配置器

PropertyOverrideConfigurer是Spring提供的另一个容器后处理器,这个后处理器的作用比上面那个容器后处理器的功能更加强大:PropertyOverrideConfigurer的属性文件指定的信息可以直接覆盖Spring配置文件中的元数据。即:PropertyOverrideConfigurer允许XML配置文件中有默认的配置信息。


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://www.springframework.org/schema/beans"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">

 	<!-- PropertyOverrideConfigurer 它会读取属性文件信息,并用这些信息设置覆盖Spring配置文件中的元数据 -->
 	<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
 		<property name="locations">
 			<list>
 				<value>dbconn.properties</value>
 				<!-- 如果有多个属性文件,依次在下面列出来 -->
 			</list>
 		</property>
 	</bean>
 	<!-- 定义数据源Bean,使用C3P0数据源实现,
 		配置该Bean时没有指定任何信息,但properties文件里的信息将会直接覆盖该Bean的属性值 -->
 	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"/> 	
</beans>

属性文件里每条属性的格式必须是:beanName.property=value

dbconn.properties:
dataSource.driverClassName=com.sql.jdbc.Driver
dataSource.jdbcUrl=jdbc://localhost:3306/**
dataSource.username=**
dataSource.password=**

对于采用基于XML Schema 的配置文件而言,如果导入了context Schema,则可采用如下方式来配置重写占位符

<context:property-override location="classpath:dbconn.properties"/>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值