Spring框架中,最主要的一个特性就是依赖注入(Dependency Injection),在我看来,这个特性离不开回调函数,回调函数作用就是将在外部调用该函数时传的参数值通过函数形参传给回调函数的。而BeanPostProcessor其实它的实现方式也是基于依赖注入的。下面就简要说明一下BeanPostProcessor机制。
1、一个Hello World的BeanPostProcessor风格例子
这个BeanPostProcessor的实现类定义如下:
package com.ev.bean.BeanPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("Bean '" + beanName + "' created : " +bean.toString());
return bean;
}
}
然后再对这个特殊的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"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang.xsd">
<bean id="messenger" class="com.ev.beanrefed.Messager"/>
<!--
当上述的bean被实例化的时候,这个特殊的bean会自动调用,将信息输出到控制台中
-->
<bean class="scripting.InstantiationTracingBeanPostProcessor"/>
</beans>
这个例子展示了BeanPostProcessor人基本使用方法,这个例子中展示了一个自定义的BeanPostProcessor实现,当每个bean创建时,调用toString方法将相关信息打印到控制台中。
最后可以通过 一个主函数初始化id为messenger的bean。
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.ev.beanrefed.Messager;
public final class Boot {
public static void main(final String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
Messenger messenger = (Messenger) ctx.getBean("messenger");
System.out.println(messenger);
}
}
我们可以看到如下的输出结果:
Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961
org.springframework.scripting.groovy.GroovyMessenger@272961
可以看出,InstantiationTracingBeanPostProcessor 中的postProcessAfterInitialization方法被自动调用了,并且它的形参,传进了被实例化的bean的一些信息(实例化对像及bean名称),我觉得这个特性可能会对日志记录有比较大的用处。
2、PropertyPlaceholderConfigurer
小节
还有一个扩展就是PropertyPlaceholderConfigurer
,这个东西也是基于依赖注入的。主要作用是在对某个javaBean赋值时,其值可以从某个资源文件中加载得。这是一个接口,我们可以这样做配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang.xsd">
<!--
下面是对PropertyPlaceholderConfigurer接口的配置
value值是com/ev/beanrefed/jdbc.properties即资源文件的路径
-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
<property name="location" value="com/ev/beanrefed/jdbc.properties"></property>
</bean>
<!--
定义一个id为messenger的bean
在这里${jdbc.username}和${jdbc.password}将会被资源
文件中对应的值所替换
-->
<bean id="messenger" class="com.ev.beanrefed.Messager">
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
</beans>
资源文件内容为:
jdbc.username=AAA
jdbc.password=******
最后我们在函数中实例化messenger
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
Messager messenger = (Messager) ctx.getBean("messenger");
System.out.println(messenger.getPassword());
最后我们可以在控制台中看到打印结果,会发现实例对象messenger 的两个属性成员已经被赋上了资源文件中对应的值了。