Spring框架——后处理器InitializingBean和BeanFactoryPostProcessor

Spring提供了很多切面,用于在项目启动的不同阶段植入代码。

 

BeanPostProcessor :可以在Bean创建之后,在初始化之前、初始化之后,进行一些额外的操作。

InitializingBean:在所有的Bean互相注入和Properties参数设置之后,在初始化函数调用之前,进行一些额外的操作。

BeanFactoryPostProcessor :在所有的Bean初始化之前,进行一些额外的操作,例如:手动注册对象到Spring容器。

 

具有相似功能的切面还有:

ContextLoaderListener:因为本身就是侦听项目启动和关闭的,直接在启动函数中添加后置代码也可以。

 

Bean的后处理

public class Person implements InitializingBean{
    private String name;

    public Person() {
        System.out.println("创建Person实例");
    }

    public void setName(String name) {
        System.out.println("Set方式设值:"+name);
        this.name = name;
    }

    public void init(){
        System.out.println("Person初始化:init执行");
    }

    @Override
    public String toString() {
        return "Person [name=" + name + "]";
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("在Bean后处理之后:afterPropertiesSet执行");
    }
}
/**
 * Bean后处理器
 * @author ChenSS
 * @2016年12月30日
 */
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后处理postProcessBeforeInitialization之后:init之前");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean后处理postProcessAfterInitialization:init之后");
        if (!(bean instanceof Person))
            return bean;
        Person person = (Person) bean;
        person.setName("新名字:xiaohua");
        return person;
    }
}
<?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-3.0.xsd">
    <bean id="xiaoming" class="com.spring.test.Person" init-method="init">
        <property name="name" value="小明" />
    </bean>
    <!-- 后处理器 -->
    <bean id="myBeanPostProcessor" class="com.spring.test.MyBeanPostProcessor" />
</beans>
public class Test {
    public static void main(String[] args) {
        new ClassPathXmlApplicationContext("applicationContext.xml");
    }
}

spring_a

容器后处理器

容器后处理器,是一个大的切面,在每一个Bean创建之后,但是在初始化之前;

 

注意:Spring中XML解析是顺序执行的,如果提前注册了容器后处理器,后处理器对后续Bean无效(不严谨的说法,未做全面测试,但是确实反生过此Bug)。

定义一个最简单的容器后处理器

/**
 * 容器后处理器,实现BeanFactoryPostProcessor接口
 * @author ChenSS
 * @2016年12月30日
 */
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("容器后处理器:postProcessBeanFactory");
        System.out.println(beanFactory.getClass().getName());
    }
}

<?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-3.0.xsd">
    <bean id="xiaoming" class="com.spring.test.ioc.Person" init-method="init">
        <property name="name" value="小明" />
    </bean>
    <!-- 后处理器 -->
    <bean class="com.spring.test.ioc.MyBeanFactoryPostProcessor" />
</beans>

代码本身没什么意义,只是打印一下日志,让大家看一下效果,可见容器的后处理器,是在所有Bean创建之后,但是在初始化之前执行的。

spring_b

附:PropertyPlaceholderConfigurer读取dp.properties配置文件

<?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-3.0.xsd">
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>db.properties</value>
                <!-- <value>other value...</value> -->
            </list>
        </property>
    </bean>
    <bean id="dataSource" class="com.spring.test.ioc.DateBaseProperties">
        <!-- 以下这些值均来自配置文件dp.properties -->
        <property name="driverClass" value="${jdbc.driverClass}" />
        <property name="jdbcUrl" value="${jdbc.url}" />
        <property name="user" value="${jdbc.user}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
</beans>

准备dp.properties文件,这个文件也是放在Src根目录下

jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/testdb
jdbc.user=root
jdbc.password=123456

对应的测试用JavaBean。

public class DateBaseProperties {
    private String driverClass;
    private String jdbcUrl;
    private String user;
    private String password;

    //set、toString方法省略
}

PropertyOverrideConfigurer读取dp.properties配置文件

看着前面的配置文件,总觉得怪怪的,不是在dp.properties配置了一次嘛?为什么还要在XML再配置一次?

Spring框架自带的加载工具类PropertyOverrideConfigurer可以帮我们解决这个问题。

<?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-3.0.xsd">
    <bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
        <property name="locations">
            <list>
                <value>db.properties</value>
                <!-- <value>other value...</value> -->
            </list>
        </property>
    </bean>
    <!-- 这里的代码全删了 -->
    <bean id="dataSource" class="com.spring.test.ioc.DateBaseProperties"/>
</beans>

不过关于db.properties的配置得调整一下,把前面的jdbc改成dataSource,名字和Bean的id对应。

dataSource.driverClass=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/testdb
dataSource.user=root
dataSource.password=123456

上面两个容器后处理器的测试结果如下

这里写图片描述

下面例举了一些我看到的、查到的其他后处理器:

CustomAutowireConfigurer自定义自动装配的配置器
CustomScopeConfigurer自定义作用于的配置器
CustomEditorConfigurer:此类注册一个PropertyEditor实现,该实现用户将配置文件中的字符串值转换为bean需要的类型。
ServletContextPropertyPlaceholderConfigurer:此回调处理器泛化了PropertyPlaceholderConfigurer类。因此,只要bean属性遵照指定命名规范,他就替换bean的属性。除了他的超类,此处理器还将从处理应用程序的servlet上下文参数入口装载值。
PreferencesPlaceholderConfigurer:此回调处理器将JDK1.4Preperences API替换bean属性中的值,此Preperences API标识他将解析来自用户Preperences的值,然后系统Preperences获得值,最后从一个引用文件获得值。

 

afterPropertiesSet

posted on 2016-12-31 02:30  疯狂的妞妞  阅读(846)  评论(0编辑  收藏  举报

导航