zoukankan      html  css  js  c++  java
  • Spring之BeanPostProcessor(后置处理器)介绍

      为了弄清楚Spring框架,我们需要分别弄清楚相关核心接口的作用,本文来介绍下BeanPostProcessor接口

    BeanPostProcessor

      该接口我们也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。接口的源码如下

    public interface BeanPostProcessor {
    
    	/**
    	 * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
    	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
    	 * or a custom init-method). The bean will already be populated with property values.
    	 * The returned bean instance may be a wrapper around the original.
    	 * @param bean the new bean instance
    	 * @param beanName the name of the bean
    	 * @return the bean instance to use, either the original or a wrapped one;
    	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
    	 * @throws org.springframework.beans.BeansException in case of errors
    	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
    	 */
    	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    
    	/**
    	 * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
    	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
    	 * or a custom init-method). The bean will already be populated with property values.
    	 * The returned bean instance may be a wrapper around the original.
    	 * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
    	 * instance and the objects created by the FactoryBean (as of Spring 2.0). The
    	 * post-processor can decide whether to apply to either the FactoryBean or created
    	 * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
    	 * <p>This callback will also be invoked after a short-circuiting triggered by a
    	 * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
    	 * in contrast to all other BeanPostProcessor callbacks.
    	 * @param bean the new bean instance
    	 * @param beanName the name of the bean
    	 * @return the bean instance to use, either the original or a wrapped one;
    	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
    	 * @throws org.springframework.beans.BeansException in case of errors
    	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
    	 * @see org.springframework.beans.factory.FactoryBean
    	 */
    	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
    
    }
    
    方法 说明
    postProcessBeforeInitialization 实例化、依赖注入完毕,
    在调用显示的初始化之前完成一些定制的初始化任务
    postProcessAfterInitialization 实例化、依赖注入、初始化完毕时执行

    一、自定义后置处理器演示

    1.自定义处理器

    package com.dpb.processor;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    /**
     * 自定义BeanPostProcessor实现类
     * BeanPostProcessor接口的作用是:
     * 	 我们可以通过该接口中的方法在bean实例化、配置以及其他初始化方法前后添加一些我们自己的逻辑
     * @author dengp
     *
     */
    public class MyBeanPostProcessor implements BeanPostProcessor{
    
    	/**
    	 * 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
    	 * 注意:方法返回值不能为null
    	 * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
    	 * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
    	 */
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("before--实例化的bean对象:"+bean+"	"+beanName);
    		// 可以根据beanName不同执行不同的处理操作
    		return bean;
    	}
    
    	/**
    	 * 实例化、依赖注入、初始化完毕时执行 
    	 * 注意:方法返回值不能为null
    	 * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
    	 * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
    	 */
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("after...实例化的bean对象:"+bean+"	"+beanName);
    		// 可以根据beanName不同执行不同的处理操作
    		return bean;
    	}
    
    }
    

    注意:接口中两个方法不能返回null,如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象,因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中

    2.Pojo类

    public class User {
    
    	private int id;
    	
    	private String name;
    	
    	private String beanName;
    	
    	public User(){
    		System.out.println("User 被实例化");
    	}
    
    	public int getId() {
    		return id;
    	}
    
    	public void setId(int id) {
    		this.id = id;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		System.out.println("设置:"+name);
    		this.name = name;
    	}
    
    	public String getBeanName() {
    		return beanName;
    	}
    
    	public void setBeanName(String beanName) {
    		this.beanName = beanName;
    	}
    	/**
    	 * 自定义的初始化方法
    	 */
    	public void start(){
    		System.out.println("User 中自定义的初始化方法");
    	}
    }
    

    3.配置文件注册

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    	<bean class="com.dpb.pojo.User" id="user" init-method="start">
    		<property name="name" value="波波烤鸭" />
    	</bean>
    	
    	<!-- 注册处理器 -->
    	<bean class="com.dpb.processor.MyBeanPostProcessor"></bean>
    </beans>
    

    4.测试

    	@Test
    public void test() {
    	ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    	User user = ac.getBean(User.class);
    	System.out.println(user);
    }
    

    输出结果

    User 被实例化
    设置:波波烤鸭
    before--实例化的bean对象:com.dpb.pojo.User@65e2dbf3	user
    User 中自定义的初始化方法
    after...实例化的bean对象:com.dpb.pojo.User@65e2dbf3	user
    com.dpb.pojo.User@65e2dbf3
    

      通过输出语句我们也能看到postProcessBeforeInitialization方法的输出语句是在Bean实例化及属性注入后执行的,且在自定义的初始化方法之前执行(通过init-method指定)。而postProcessAfterInitialization方法是在自定义初始化方法执行之后执行的。

    注意!!!

    1. BeanFactory和ApplicationContext两个容器对待bean的后置处理器稍微有些不同。ApplicationContext容器会自动检测Spring配置文件中那些bean所对应的Java类实现了BeanPostProcessor接口,并自动把它们注册为后置处理器。在创建bean过程中调用它们,所以部署一个后置处理器跟普通的bean没有什么太大区别。
    2. BeanFactory容器注册bean后置处理器时必须通过代码显示的注册,在IoC容器继承体系中的ConfigurableBeanFactory接口中定义了注册方法
    /**
     * Add a new BeanPostProcessor that will get applied to beans created
     * by this factory. To be invoked during factory configuration.
     * <p>Note: Post-processors submitted here will be applied in the order of
     * registration; any ordering semantics expressed through implementing the
     * {@link org.springframework.core.Ordered} interface will be ignored. Note
     * that autodetected post-processors (e.g. as beans in an ApplicationContext)
     * will always be applied after programmatically registered ones.
     * @param beanPostProcessor the post-processor to register
     */
    void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
    

    测试代码如下

    @Test
    public void test2() {
    	//ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    	XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
    	// 显示添加后置处理器
    	bf.addBeanPostProcessor(bf.getBean(MyBeanPostProcessor.class));
    	User user = bf.getBean(User.class);
    	System.out.println(user);
    }
    

    二、多个后置处理器

      我们可以在Spring配置文件中添加多个BeanPostProcessor(后置处理器)接口实现类,在默认情况下Spring容器会根据后置处理器的定义顺序来依次调用。

    public class MyBeanPostProcessor implements BeanPostProcessor{
    
    	/**
    	 * 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
    	 * 注意:方法返回值不能为null
    	 * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
    	 * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
    	 */
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("A before--实例化的bean对象:"+bean+"	"+beanName);
    		// 可以根据beanName不同执行不同的处理操作
    		return bean;
    	}
    
    	/**
    	 * 实例化、依赖注入、初始化完毕时执行 
    	 * 注意:方法返回值不能为null
    	 * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
    	 * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
    	 */
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("A after...实例化的bean对象:"+bean+"	"+beanName);
    		// 可以根据beanName不同执行不同的处理操作
    		return bean;
    	}
    }
    
    public class MyBeanPostProcessor2 implements BeanPostProcessor{
    
    	/**
    	 * 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
    	 * 注意:方法返回值不能为null
    	 * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
    	 * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
    	 */
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("B before--实例化的bean对象:"+bean+"	"+beanName);
    		// 可以根据beanName不同执行不同的处理操作
    		return bean;
    	}
    
    	/**
    	 * 实例化、依赖注入、初始化完毕时执行 
    	 * 注意:方法返回值不能为null
    	 * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
    	 * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
    	 */
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("B after...实例化的bean对象:"+bean+"	"+beanName);
    		// 可以根据beanName不同执行不同的处理操作
    		return bean;
    	}
    }
    

    配置文件注册

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    	<bean class="com.dpb.pojo.User" id="user" init-method="start">
    		<property name="name" value="波波烤鸭" />
    	</bean>
    	
    	<!-- 注册处理器 -->
    	<bean class="com.dpb.processor.MyBeanPostProcessor"/>
    	<bean class="com.dpb.processor.MyBeanPostProcessor2"/>
    </beans>
    

    测试结果

    User 被实例化
    设置:波波烤鸭
    A before--实例化的bean对象:com.dpb.pojo.User@7fac631b	user
    B before--实例化的bean对象:com.dpb.pojo.User@7fac631b	user
    User 中自定义的初始化方法
    A after...实例化的bean对象:com.dpb.pojo.User@7fac631b	user
    B after...实例化的bean对象:com.dpb.pojo.User@7fac631b	user
    com.dpb.pojo.User@7fac631b
    

    三、显示指定顺序

      在Spring机制中可以指定后置处理器调用顺序,通过让BeanPostProcessor接口实现类实现Ordered接口getOrder方法,该方法返回一整数,默认值为 0,优先级最高,值越大优先级越低

    public class MyBeanPostProcessor implements BeanPostProcessor,Ordered{
    
    	/**
    	 * 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
    	 * 注意:方法返回值不能为null
    	 * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
    	 * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
    	 */
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("A before--实例化的bean对象:"+bean+"	"+beanName);
    		// 可以根据beanName不同执行不同的处理操作
    		return bean;
    	}
    
    	/**
    	 * 实例化、依赖注入、初始化完毕时执行 
    	 * 注意:方法返回值不能为null
    	 * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
    	 * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
    	 */
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("A after...实例化的bean对象:"+bean+"	"+beanName);
    		// 可以根据beanName不同执行不同的处理操作
    		return bean;
    	}
    
    	@Override
    	public int getOrder() {
    		// TODO Auto-generated method stub
    		return 10;
    	}
    }
    
    public class MyBeanPostProcessor2 implements BeanPostProcessor,Ordered{
    
    	/**
    	 * 实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务
    	 * 注意:方法返回值不能为null
    	 * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
    	 * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
    	 */
    	@Override
    	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("B before--实例化的bean对象:"+bean+"	"+beanName);
    		// 可以根据beanName不同执行不同的处理操作
    		return bean;
    	}
    
    	/**
    	 * 实例化、依赖注入、初始化完毕时执行 
    	 * 注意:方法返回值不能为null
    	 * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
    	 * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
    	 */
    	@Override
    	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    		System.out.println("B after...实例化的bean对象:"+bean+"	"+beanName);
    		// 可以根据beanName不同执行不同的处理操作
    		return bean;
    	}
    
    	@Override
    	public int getOrder() {
    		// TODO Auto-generated method stub
    		return 2;
    	}
    }
    

    测试输出结果

    User 被实例化
    设置:波波烤鸭
    B before--实例化的bean对象:com.dpb.pojo.User@7fac631b	user
    A before--实例化的bean对象:com.dpb.pojo.User@7fac631b	user
    User 中自定义的初始化方法
    B after...实例化的bean对象:com.dpb.pojo.User@7fac631b	user
    A after...实例化的bean对象:com.dpb.pojo.User@7fac631b	user
    com.dpb.pojo.User@7fac631b
    

    数值越大的优先级越低,所以A的输出就在后面了。

    ~好了通过本文详细大家对于BeanPostProcessor接口的作用应该比较清楚了。

  • 相关阅读:
    HttpWatch 有火狐版本?
    JQgrid的最新API
    jqgrid
    JSON的学习网站
    array创建数组
    Numpy安装及测试
    SQLite3删除数据_7
    SQLite3修改数据_6
    SQLite3查询一条数据_5
    SQLite3查询所有数据_4
  • 原文地址:https://www.cnblogs.com/dengpengbo/p/10464892.html
Copyright © 2011-2022 走看看