`

Spring Container的扩展点

 
阅读更多

Spring在解析完配置文件后,会调用一些callback方法,使用Spring的开发者可以通过提供这些callback方法达到Spring Container的扩展.

1,通过实现BeanPostProcessor来完成对Bean的一些'定制',BeanPostProcessor定义了两个方法,postProcessBeforeInitialization(Object bean, String beanName)和postProcessAfterInitialization(Object bean, String beanName).

postProcessBeforeInitialization会在Spring初始化bean之后,在Container调用申明的initialization方法(如afterPropertiesSet)之前被调用,postProcessAfterInitialization会在在Container调用申明的initialization方法(如afterPropertiesSet)之后被调用.如果需要有多个实现BeanPostProcessor的类,可以通过让其实现Ordered接口来控制这些类的callback被调用的顺序.

这种bean的post-processor一般用来检查bean是否实现了某个接口,或者把bean和某个proxy包装起来,Spring的AOP某些框架类就是实现了BeanPostProcessor.

例:


public class MyBeanPostProcessor implements BeanPostProcessor,
InvocationHandler {

private Object proxyobj;
public MyBeanPostProcessor() {

}
public MyBeanPostProcessor(Object obj) {
proxyobj = obj;
}

public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessBeforeInitialization Bean '" + beanName
+ "' created : " + bean.toString());

if (bean instanceof Intf) {

Class cls = bean.getClass();

return Proxy.newProxyInstance(cls.getClassLoader(), cls
.getInterfaces(), new MyBeanPostProcessor(bean));
} else {
return bean;
}

}

public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessAfterInitialization Bean '" + beanName
+ "' created : " + bean.toString());
return bean;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("proxy is " + proxy.getClass().getName());
System.out.println("before calling " + method);

if (args != null) {
for (int i = 0; i < args.length; i++) {
System.out.println(args[i] + "");
}
}

Object o = method.invoke(proxyobj, args);

System.out.println("after calling " + method);

return o;
}
}

public interface Intf {
public String testFunc();
}

public class IntfBean implements Intf {
private String strVal = "default value";
@Override
public String testFunc() {
// TODO Auto-generated method stub
return strVal;
}

}

<bean id="IntfBean" class="com.test.spring.extent.IntfBean" />

<bean class="com.test.spring.extent.MyBeanPostProcessor" />

调用代码:

Intf intfBean = (Intf) ctx.getBean("IntfBean");
System.out.println(intfBean.testFunc());

这样,MyBeanPostProcessor会把实现Intf接口的bean和一个proxy包装起来.

2,通过实现BeanFactoryPostProcessor接口来操作配置文件,对配置的元数据进行'特制'.Spring自身的PropertyPlaceholderConfigurer就实现了

这个接口,通过对XML配置文件中使用占位符,PropertyPlaceholderConfigurer从别的property文件中读取值进行替换.

例子:从ext.properties读取值替换${TEST.PROP1},${TEST.PROP2}.

<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:conf/ext.properties" />
<property name="properties">
<value>TEST.PROP3=inside property</value>
</property>
</bean>
<bean id="PropReplaceBean" class="com.test.spring.extent.PropReplaceBean">
<property name="strVal" value="${TEST.PROP1}" />
<property name="intVal" value="${TEST.PROP2}" />
<property name="insideProp" value="${TEST.PROP3}" />
</bean>

通常比较有用的场景是数据库的url,用户名,密码的配置,还可以用来动态指定某个bean的类名,把XMl文件和property文件分开维护更容易.

<bean id="xxxBean" class="${com.xxx.class}"/>

自定义的BeanFactoryPostProcessor,通过实现Ordered接口可以改变被callback的顺序.callback方法中的ConfigurableListableBeanFactory beanFactory提供了配置文件的元数据.(*碰到一个困惑的问题是: PropertyPlaceholderConfigurer的order是 Integer.MAX_VALUE,却发现它比自己定义的order 为-1的 processor先执行.)

<bean class="com.test.spring.extent.MyBeanFactoryPostProcessor" />


public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
Ordered {

private int order = -1;

public void setOrder(int order) {
this.order = order;
}

public int getOrder() {
return this.order;
}

@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition beanDefinition = beanFactory
.getBeanDefinition("PropReplaceBean");
MutablePropertyValues pvs = beanDefinition.getPropertyValues();

PropertyValue[] pvArray = pvs.getPropertyValues();
for (PropertyValue pv : pvArray) {
System.out.println(pv.getName() + " " + pv.getValue().getClass());

}
}

}

Spring检测到BeanPostProcessor和BeanFactoryPostProcessor后会自动调用它们的callback方法,不用用户显式的去调用.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics