千千梦丶琪 发表于 2023-1-10 01:10:37

Spring IOC官方文档学习笔记(八)之容器扩展点

1.通过BeanPostProcessor来自定义bean
(1) BeanPostProcessor用于在容器完成了对bean的实例化,配置及初始化后来实现一些自定义逻辑,它是用于操纵由容器创建的每个bean实例的,即在容器实例化了一个bean后以及该bean的初始化回调(如InitializingBean.afterPropertiesSet()等)被执行之前,会将这个bean交由BeanPostProcessor来进行处理。通过BeanPostProcessor,我们可以对bean实例进行任何操作,包括忽略掉初始化回调等,BeanPostProcessor通常用来检查回调接口,或用来生成某个bean的代理对象,因此一些Spring AOP的基础类就被实现为BeanPostProcessor实例,以提供代理对象,如下是简单使用BeanPostProcessor的一个例子
//让ExampleA实现3个初始化回调
public class ExampleA implements InitializingBean {

    private String name;

    public ExampleA() {
      System.out.println("ExampleA的构造方法被调用");
      System.out.println("----------------------------------------");
    }

    //这个方法只用于IOC的属性注入
    public void setName(String name) {
      System.out.println("IOC对ExampleA的name属性进行注入,值为:" + name);
      System.out.println("----------------------------------------");
      this.name = name;
    }
   
    //这个方法用于我们自己手动注入
    public void setNameInOtherWay(String name) {
      this.name = name;
    }

    public String getName() {
      return name;
    }

    @Override
    public String toString() {
      return "ExampleA{" +
                "name='" + name + '\'' +
                '}';
    }

    @PostConstruct
    public void postConstruct() {
      System.out.println("正在执行初始化回调PostConstruct,此时的ExampleA为:" + this);
      this.setNameInOtherWay("zzz2");
      System.out.println("执行完毕,此时的ExampleA为:" + this);
      System.out.println("----------------------------------------");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
      System.out.println("正在执行初始化回调InitializingBean.afterPropertiesSet,此时的ExampleA为:" + this);
      this.setNameInOtherWay("zzz3");
      System.out.println("执行完毕,此时的ExampleA为:" + this);
      System.out.println("----------------------------------------");
    }

    public void init() {
      System.out.println("正在执行初始化回调init-method,此时的ExampleA为:" + this);
      this.setNameInOtherWay("zzz4");
      System.out.println("执行完毕,此时的ExampleA为:" + this);
      System.out.println("----------------------------------------");
    }
}

//实现BeanPostProcessor,自定义后置处理器来操纵bean实例(注意:需要把我们的自定义处理器注入到容器中),它主要提供了2个方法
public class Processor implements BeanPostProcessor {

    /**
   * 该方法作用于bean实例创建配置好后,初始化回调执行前,来自定义一些逻辑
   * @param bean 实例化并配置好后的bean
   * @param beanNamebean的名称
   * @return自定义操作完成后的bean
   * @throws BeansException
   */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("正在执行postProcessBeforeInitialization,此时的ExampleA为:" + bean);
      ((ExampleA) bean).setNameInOtherWay("zzz1");
      System.out.println("执行完毕,此时的ExampleA为:" + bean);
      System.out.println("----------------------------------------");
      return bean;
    }
   
    /**
   * 该方法作用于初始化回调执行后
   */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("正在执行postProcessAfterInitialization,此时的ExampleA为:" + bean);
      ((ExampleA) bean).setNameInOtherWay("zzz5");
      System.out.println("执行完毕,此时的ExampleA为:" + bean);
      System.out.println("----------------------------------------");
      return bean;
    }
}


<beans ....>

   
    <context:annotation-config></context:annotation-config>
   
    <bean id="exampleA"init-method="init">
      <property name="name" value="zzz"></property>
    </bean>
   
   
    <bean id="processor" ></bean>
</beans>

//启动容器后,打印结果为
ExampleA的构造方法被调用
----------------------------------------
IOC对ExampleA的name属性进行注入,值为:zzz
----------------------------------------
正在执行postProcessBeforeInitialization,此时的ExampleA为:ExampleA{name='zzz'}
执行完毕,此时的ExampleA为:ExampleA{name='zzz1'}
----------------------------------------
正在执行初始化回调PostConstruct,此时的ExampleA为:ExampleA{name='zzz1'}
执行完毕,此时的ExampleA为:ExampleA{name='zzz2'}
----------------------------------------
正在执行初始化回调InitializingBean.afterPropertiesSet,此时的ExampleA为:ExampleA{name='zzz2'}
执行完毕,此时的ExampleA为:ExampleA{name='zzz3'}
----------------------------------------
正在执行初始化回调init-method,此时的ExampleA为:ExampleA{name='zzz3'}
执行完毕,此时的ExampleA为:ExampleA{name='zzz4'}
----------------------------------------
正在执行postProcessAfterInitialization,此时的ExampleA为:ExampleA{name='zzz4'}
执行完毕,此时的ExampleA为:ExampleA{name='zzz5'}
----------------------------------------综上可见,添加了BeanPostProcessor后,bean的初始化流程为:执行bean的构造函数 -> IOC进行属性注入 -> BeanPostProcessor.postProcessBeforeInitialization -> 三大初始化回调 -> BeanPostProcessor.postProcessAfterInitialization
(2) 我们可以向容器中注入多个自定义BeanPostProcessor,并通过实现Ordered接口来控制这些BeanPostProcessor的执行顺序,如下所示
public class ExampleA { }

//让该自定义后置处理器实现Ordered接口,指定它在所有自定义后置处理器中的执行顺序
public class Processor0 implements BeanPostProcessor, Ordered {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("Order值为0的postProcessBeforeInitialization执行...");
      return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("Order值为0的postProcessAfterInitialization执行...");
      return bean;
    }

    @Override
    public int getOrder() {
      return 0;
    }
}

public class Processor1 implements BeanPostProcessor, Ordered {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("Order值为1的postProcessBeforeInitialization执行...");
      return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("Order值为1的postProcessAfterInitialization执行...");
      return bean;
    }

    @Override
    public int getOrder() {
      return 1;
    }
}


<beans ....>
    <bean id="exampleA" ></bean>
    <bean id="processor0" ></bean>
    <bean id="processor1" ></bean>
</beans>

//启动容器,输出如下
Order值为0的postProcessBeforeInitialization执行...
Order值为1的postProcessBeforeInitialization执行...
Order值为0的postProcessAfterInitialization执行...
Order值为1的postProcessAfterInitialization执行...由上可见,getOrder返回值越小,自定义的后置处理器就越先执行
(3) 在一个容器中注入了一个BeanPostProcessor,那么该BeanPostProcessor仅对该容器中的bean进行后置处理,例如,即父容器中的BeanPostProcessor不会作用于子容器中的bean
(4) BeanPostProcessor作用于bean实例化并配置好了之后,换句话说,在BeanPostProcessor起作用时,bean实例已经存在了,因此,如果我们想要修改bean的配置元数据(即BeanDefinition,此时的bean还未被创建),则需要实现BeanFactoryPostProcessor接口,它与BeanPostProcessor类似,只不过作用时机不同
未完待续...

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: Spring IOC官方文档学习笔记(八)之容器扩展点