spring之扩展点

上篇文章。介绍了spring中bean的生命周期,而且在文章末尾提到,spring使用BeanPostProcessor接口来处理生命周期的回调。我们能够在初始化函数(init())中定制化一些逻辑。上述BeanPostProcessor就是spring扩展点(extension points)。Spring及其灵活,普通情况下我们并不须要去继承ApplicationContext 去扩展功能。仅仅须要使用spring提供的扩展接口,就能够刻spring无缝集成。

Spring主要提供了两类扩展点BeanPostProcessor和BeanFactoryPostProcessor。

前者是操作bean的实例,后者使对bean的元数据定义进行扩展。

BeanPostProcessor

接口说明

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 ;
        
   }

以上两个方法的參数列表中各自是spring容器创建的对象和beanName,返回值是经过定制化的对象。

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 { }


然后採用在採用JDK动态代理的机制创建代理前,我们须要一个自己定义的InvocationHandler。它对仅对上述注解标识的方法进行事务处理。其代码和凝视例如以下:

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;
   }
 
}
 

最后我们须要上述的BeanPostProcessor生效。为此我们在xml配置文件里添加例如以下代码:

<bean class="com.test.MyCustomPostProcessor"/>

然后測试代码例如以下,和之前一样採用main方法模拟:

 UserService userService0 = context.getBean("user0", UserService.class);
      System.out.println(userService0.getUser());

程序执行结果,从下面程序执行结果能够看出我们提出的两点:

1.                 BeanPostProcessor的两个回调一个在依赖注入和初始化函数运行前运行,一个在初始化函数运行后运行。

2.                 我们模拟AOP事务处理的代码成功运行。实际上Spring中AOP自己主动代理就是使用BeanPostProcessor实现的。



BeanFactoryPostProcessor

接口说明

这是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;
   }

实现该接口。能够在spring的bean创建之前,改动bean的定义属性。

也就是说。Spring同意BeanFactoryPostProcessor在容器实例化不论什么其他bean之前读取配置元数据,并能够依据须要进行改动,比如能够把bean的scope从singleton改为prototype,也能够把property的值给改动掉。能够同一时候配置多个BeanFactoryPostProcessor,并通过设置'order'属性或实现order接口来控制各个BeanFactoryPostProcessor的运行次序。这些和BeanPostProcessor非常类似,而且其启用方式和容器相关性也与之中的一个致。

注意:BeanFactoryPostProcessor是在spring容器载入了bean的定义文件之后,在bean实例化之前运行的。接口方法的入參是ConfigurrableListableBeanFactory。使用该參数。能够获取到相关bean的定义信息:

 BeanDefinition obj = arg0.getBeanDefinition("sumBean");

Spring内置实现了非常多的BeanFactoryPostProcessor实现。比如:

经常使用的有:

  • org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
  • org.springframework.beans.factory.config.PropertyOverrideConfigurer
  • org.springframework.beans.factory.config.CustomEditorConfigurer:用来注冊自己定义的属性编辑器。


一个演示样例

这个演示样例我们来演示下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", "这是新添加的測试值");
   }
  
}
最后在配置文件里注冊它:

<bean class="com.test.MyCostumFactoryProcessor"/>

结束语

Spring扩展点在Spring核心中是非常重要的概念,spring本身就内置了非常多实现。假设我们须要扩展Spring的功能。他们是非常好的方式。而且它们能够像插件一样非常好的工作。本篇演示完整代码见底下评论。

posted on 2017-04-20 17:07  ljbguanli  阅读(325)  评论(0编辑  收藏  举报