转自: http://blog.csdn.net/kkdelta/article/details/5488430

Spring在解析完配置文件后,会调用一些callback方法,使用Spring的开发者可以通过提供这些callback方法达到对Spring Container的扩展.
1.   通过实现BeanPostProcessor来完成对某些Bean的一些定制, BeanPostProcessor定义了两个方法, postProcessBeforeInitialization(Object bean, String beanName)和postProcessAfterInitialization(Object bean, String beanName)。 postProcessBeforeInitialization会在Spring对bean初始化完成之后 , 依赖注册(对property指定的成员变量完成了赋值)已经完成 , 但是Container还没有调用申明的initialization方法(如afterPropertiesSet, init-method)之前被调用.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" />

注意这里实现BeanPostProcessor的类是针对Ioc容器里其他的bean调用这两个方法,不是针对BeanPostProcessor自身和其他BeanPostProcessor调用这两个方法, 如果在配置文件里就只有BeanPostProcessor本身, 没有其他的bean, 如只有<beanclass="com.test.spring.extent.MyBeanPostProcessor"/>配置,postProcessBeforeInitialization和postProcessAfterInitialization这两个方法是不会被调用的.BeanPostProcessor会在普通bean被初始化之前先被容器初始化.

调用代码:

Intf intfBean = (Intf) ctx.getBean("IntfBean");

System.out.println(intfBean.testFunc());

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

 

2. 通过实现BeanFactoryPostProcessor接口来操作配置文件,对配置的元数据进行特制。 Spring IoC容器允许BeanFactoryPostProcessor在容器实际实例化任何其它的bean之前读取配置元数据,并有可能修改它。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方法,不用在代码里主动的去调用.

Spring Container的扩展点的更多相关文章

  1. Spring中的扩展点

    Spring作为一个常用的IOC框架,在设计上预留了很多的扩展点,很多第三方开源框架,包括Spring自身也是基于这些扩展点实现的,这很好的体现了对修改关闭.对扩展开放的原则.总的来说Spring的扩 ...

  2. spring源码-扩展点

    /** * @Author quan * @Date 2020/11/13 * 扩展原理 * BeanPostProcessor bean后置处理器,bean创建对象初始化前后进行拦截工作 * * * ...

  3. Spring扩展点-v5.3.9

    Spring 扩展点 **本人博客网站 **IT小神 www.itxiaoshen.com 官网地址****:https://spring.io/projects/spring-framework T ...

  4. Spring系列14:IoC容器的扩展点

    Spring系列14:IoC容器的扩展点 回顾 知识需要成体系地学习,本系列文章前后有关联,建议按照顺序阅读.上一篇我们详细介绍了Spring Bean的生命周期和丰富的扩展点,没有阅读的强烈建议先阅 ...

  5. 三万字盘点Spring/Boot的那些常用扩展点

    大家好,我是三友. Spring对于每个Java后端程序员来说肯定不陌生,日常开发和面试必备的.本文就来盘点Spring/SpringBoot常见的扩展点,同时也来看看常见的开源框架是如何基于这些扩展 ...

  6. Spring Boot 中如何使用 Dubbo Activate 扩展点

    摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 公司的核心竞争力在于创新 – <启示录> 』 继续上一篇:< Spri ...

  7. Spring源码系列 — BeanDefinition扩展点

    前言 前文介绍了Spring Bean的生命周期,也算是XML IOC系列的完结.但是Spring的博大精深,还有很多盲点需要摸索.整合前面的系列文章,从Resource到BeanDefinition ...

  8. Spring扩展点之Aware接口族

    引言 Spring中提供了各种Aware接口,方便从上下文中获取当前的运行环境,比较常见的几个子接口有:BeanFactoryAware,BeanNameAware,ApplicationContex ...

  9. spring mvc 提供的几个常用的扩展点

    转载 :http://blog.csdn.net/gufachongyang02/article/details/43836105 这是spring3 mvc的核心流程图:   SpirngMVC的第 ...

随机推荐

  1. Arcengine 二次开发得到点shapefile的坐标

    做二次开发的时候,想要得到Point shapfile的坐标和相应的属性,也就是Point 的(x,y)和某个属性,在网上查了一些资料,做总结如下 首先,你要确定自己要操作的图层,一般来说,得到当前操 ...

  2. Spark Streaming源码分析 – DStream

    A Discretized Stream (DStream), the basic abstraction in Spark Streaming, is a continuous sequence o ...

  3. Macbook pro 13" compile Apollo 2.5

    STEPS: 0. Install Homebrew 1.  Install 'Docker for Mac 18.03+',配置CPUs (n个CPUs,Bazel开n个线程编译), Memory ...

  4. vue下登录页背景图上下空白处自适应等高

    遇到需求,登录页面需要顶部和底部上下等高,并且随着浏览器自适应上下高度. 解决方法: vue界面的data中先定义 data() { return { windowHeight: "&quo ...

  5. 并发编程 - 线程 - 1.线程queue/2.线程池进程池/3.异步调用与回调机制

    1.线程queue :会有锁 q=queue.Queue(3) q.get() q.put() 先进先出 队列后进先出 堆栈优先级队列 """先进先出 队列"& ...

  6. 剑指Offer——二叉树的深度

    题目描述: 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 分析: 二叉树的深度等于其左子树的深度和右子树的深度两个中最大的深 ...

  7. Python并行编程(四):线程同步之RLock

    1.基本概念 如果想让只有拿到锁的线程才能释放该锁,那么应该使用RLock()对象.当需要在类外面保证线程安全,又要在类内使用同样方法的时候RLock()就很使用. RLock叫做Reentrant ...

  8. git学习------>如何修改git已提交的记录中的Author和Email?

    一.背景 最近搭建好GitLab后,准备陆陆续续的将之前在SVN仓库中保存的代码迁移到GitLab上,昨天顺利将三个Android组件的代码迁移到GitLab后,其他同事发现迁移是成功了,但是pull ...

  9. Sping-Spring JDBC框架

    JDBC框架概述 在使用普通的JDBC数据库时,就会很麻烦的写不必要的代码来处理异常,打开和关闭数据库连接等.但Spring JDBC框架负责所有的底层细节,从开始打开连接,准备和执行SQL语句,处理 ...

  10. docker部署oracle

    oracle部署 创建oracle用户 [root@stpass-15 ~]# useradd oracle[root@stpass-15 oracle]# cd oracle [root@stpas ...