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

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 beanName  bean的名称
     * @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;
    }
}

<!-- xml配置文件 -->
<beans ....>

    <!-- 开启注解扫描,否则PostConstruct注解不生效 -->
    <context:annotation-config></context:annotation-config>
    
    <bean id="exampleA" class="cn.example.spring.boke.ExampleA" init-method="init">
        <property name="name" value="zzz"></property>
    </bean>
    
    <!-- 注意仅仅实现接口是不行的,我们必须把自定义后置处理器注册成bean,它才会生效 -->
    <bean id="processor" class="cn.example.spring.boke.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;
    }
}

<!-- xml配置文件 -->
<beans ....>
    <bean id="exampleA" class="cn.example.spring.boke.ExampleA"></bean>
    <bean id="processor0" class="cn.example.spring.boke.Processor0"></bean>
    <bean id="processor1" class="cn.example.spring.boke.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类似,只不过作用时机不同

未完待续…

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » Spring IOC官方文档学习笔记(八)之容器扩展点