上篇文章,介绍了spring中bean的生命周期,并且在文章末尾提到,spring使用BeanPostProcessor接口来处理生命周期的回调。我们可以在初始化函数(init())中定制化一些逻辑。上述BeanPostProcessor就是spring扩展点(extension points)。Spring及其灵活,一般情况下我们并不需要去继承ApplicationContext 去扩展功能,只需要使用spring提供的扩展接口,就可以刻spring无缝集成。
Spring主要提供了两类扩展点BeanPostProcessor和BeanFactoryPostProcessor。前者是操作bean的实例,后者使对bean的元数据定义进行扩展。
BeanPostProcessor提供对bean实例的操作扩展,在spring容器对bean实例化和设置依赖之后,其回调开始执行。BeanPostProcessor接口定义的两个方法,分别在bean的初始化方法(InitializingBean接口,或者init-method定义)执行的前后执行:
public interface BeanPostProcessor{
/**
* 在bean的初始化方法执行后执行
*/
public Object postProcessAfterInitialization(Object arg0, String arg1)
throws BeansException ;
/**
* 在bean的初始化方法执行前执行
*/
public Object postProcessBeforeInitialization(Object arg0, String arg1)
throws BeansException ;
}
BeanPostProcessor对bean实例进行操作,其在bean被实例化和后开始被执行相关回调。它是与容器相关的,它只对其所在容器中的bean有影响,对其父容器没有影响。
BeanPostProcessor也是一个bean,只不过它对其它bean进行后续的扩展处理。Spring容器可以自动的发现实现这个接口的bean。所以如果我们要使我们自定义的BeanPostProcessor起作用,可以像配置其他bean一样在配置文件中进行配置(当然也可以编码实现,向容器注册一个)。Spring容器对BeanPostProcessor类型的bean专门处理,所有的BeanPostProcessor及其引用的依赖在spring容器启动的时候实例化,作为spring容器启动的一个阶段。
Spring容器中内置很多BeanPostProcessor的实现,如上篇文章中使用JSR注解@PostConstruct,对它的处理就是使用BeanPostProcessor。它的另外一哥较常见的作用是spring-aop动态代理。
另外我们可以定义多个BeanPostProcessor,他们执行的顺序可以通过实现Ordered接口来控制。
这个示例演示有两个点:
1. BeanPostProcessor的在bean的生命周期中执行时机。
2. 模拟实现一个aop的事务处理代理。
这个示例使用的代码基本上还是上篇文章的代码,增加了一个BeanPostProcessor的一个实现类、一个自定义的注解等在UserService的方法上添加事务的功能,其基本结构如下:
首先我们创建一个注解来标识某个方法,说明其需要事务处理,如下所示:
/**
*一个标志的注解,只有被这个注解标识的方法才需要增加事务。
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD})
public @interface MyTransaction {
}
package com.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 自定义代理,JDK动态代理
*
*/
public class MyCustomProxy implements InvocationHandler{
private Object target;
public MyCustomProxy(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (isNeed(method)) {//只有被@MyTransaction注解标识的方法才执行开启事务操作。
beginTransaction(proxy);
}
Object res = method.invoke(target, args);
if (isNeed(method)) {
endTransaction();
}
return res;
}
/**
*模拟开启事务,假如通用点,就很类似AOP中的 Before advice
*/
private void beginTransaction(Object o){
System.out.println("-----开始事务--------");
}
/**
*模拟结束事务,假如通用点,就很类似AOP中的 After advice
*/
private void endTransaction(){
System.out.println("-----结束事务--------");
}
/**
* 这个实现也可以更加的通用,基于不同的对象不同方法不同的规则
*/
private boolean isNeed(Method method){
if (method.getAnnotation(MyTransaction.class) != null) {
return true;
}
return false;
}
}
接下来我们需要在合适的时机创建JDK动态代理,以下代码仅对UserService创建代理,当然这里可以更加通用一些,如对某些包的某些类、被某个注解标识等。下面的代码是自定义的BeanPostProcessor,我们在postProcessAfterInitialization方法中创建代理对象并返回给Spring容器:
package com.test;
import java.lang.reflect.Proxy;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import com.test.service.UserService;
/**
* 注意打印的文字,观察其生命周期
* 这里只对UserService创建代理
*
*/
public class MyCustomPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object arg0, String arg1)
throws BeansException {
if (arg0 instanceof UserService) {//为UserService创建代理,实现事务,如果这里的可以是基于某种规则,如@ASPECTJ的规则
System.out
.println(" i am postProcessAfterInitialization beanname :"
+ arg1 + " BEAN type:" + arg0);
System.out.println("创建代理,实现事务");
//创建代理,这里可以通过一个代理工厂,根据不同的规则采用不同的InvokeHandler
Object res = Proxy.newProxyInstance(getClass().getClassLoader(), arg0.getClass().getInterfaces(), new MyCustomProxy(arg0));
return res;
}
return arg0;
}
@Override
public Object postProcessBeforeInitialization(Object arg0, String arg1)
throws BeansException {
if (arg0 instanceof UserService) {
System.out
.println(" i am postProcessBeforeInitialization beanname :"
+ arg1 + " BEAN type:" + arg0);
}
return arg0;
}
}
然后测试代码如下,和之前一样采用main方法模拟:
UserService userService0 = context.getBean("user0", UserService.class);
System.out.println(userService0.getUser());
1. BeanPostProcessor的两个回调一个在依赖注入和初始化函数执行前执行,一个在初始化函数执行后执行。
2. 我们模拟AOP事务处理的代码成功执行。实际上Spring中AOP自动代理就是使用BeanPostProcessor实现的。
这是Spring容器的另外一个扩展点,和BeanPostProcessor不同的地方在于,它是对beanDefiniton进行操作。
其接口定义如下所示:
public interface BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
注意:BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的。接口方法的入参是ConfigurrableListableBeanFactory,使用该参数,可以获取到相关bean的定义信息:
BeanDefinition obj = arg0.getBeanDefinition("sumBean");
常用的有:
这个示例我们来演示下BeanFactoryPostProcessor的简单用法,我们在UserServiceIml.Java中新增加一个field 名字是testValue(假设这是个String类型的),但是不设置初值,然后我们在BeanFactoryPostProcessor中进行设置。
我们自定义的BeanFactoryPostProcessor如下:
public class MyCostumFactoryProcessor implements BeanFactoryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
throws BeansException {
BeanDefinition obj = arg0.getBeanDefinition("user0");
MutablePropertyValues pv = obj.getPropertyValues();
pv.add("testValue", "这是新增加的测试值");
}
}
最后在配置文件中注册它:
Spring扩展点在Spring核心中是很重要的概念,spring本身就内置了很多实现。如果我们需要扩展Spring的功能,他们是很好的方式。并且它们可以像插件一样很好的工作。本篇演示完整代码见底下评论。