前言


  很久没有写博客了,也是两个原因:一是自己觉得一直在班门弄斧,其实自己没什么技术可言;二是很多朋友的问题实际上可以自行解决,我经常觉得不该我来过问,或者是有时候我认为技术还得靠自己钻研,我一两句话不能让各位醍醐灌顶……

  不过还是偶尔做一下记录,免得博客界渐渐就把我淡忘了。

  这篇博客主要给大家讲一下Spring中如何批量修改Bean的定义。

应用场景

  我之前遇到一个很有意思的问题:我需要批量重定义特定类型的由Spring容器托管的Bean。具体体现在,我有很多控制器类(Controller)和校验器类(Validator),我希望他们都是多例(Prototype)的,而Spring默认创建实例是单例(Singleton)的。有朋友可能要问:为什么不自己在Bean定义时加参数呢@Scope("prototype")?我的回答很简单:懒……。因为我的Bean声明是这样的:

  

  

  那么我就没法很精确得去设置控制器和校验器的类实例为多例,因为我这里很笼统。

  接下来我们详解怎样使用代码实现设置特定Bean定义的修改。

ApplicationListener-ContextRefreshedEvent

  我们可以监听一个Spring的ApplicationContext的事件来让Spring的Bean容器配置完成后通知我们来处理一下。

<bean id="beanDefineConfigue" class="com.xx.yy.zz.BeanDefineConfigue"></bean>
 public class BeanDefineConfigue implements ApplicationListener<ContextRefreshedEvent> {

     @Override
public void onApplicationEvent(ContextRefreshedEvent event) { }
}

  ContextRefreshedEvent是“Event raised when an ApplicationContext gets initialized or refreshed.(当ApplicationContext初始化完成或刷新完成后产生的事件)”

  当然,我们可以在onApplicationEvent函数内“搞事儿”了!

BeanFactory-BeanDefinition-registerBeanDefinition

 public void onApplicationEvent(ContextRefreshedEvent event) {
ConfigurableApplicationContext context = (ConfigurableApplicationContext) event.getApplicationContext();
DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getBeanFactory();
// 控制器
String[] controllers = factory.getBeanNamesForAnnotation(Controller.class);
if(controllers != null) {
for(String controllerBeanName : controllers) {
BeanDefinition beanDefine = factory.getBeanDefinition(controllerBeanName);
String scope = beanDefine.getScope();
if(scope == null || !scope.equals(ConfigurableBeanFactory.SCOPE_PROTOTYPE)) {
beanDefine.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
factory.registerBeanDefinition(controllerBeanName, beanDefine);
}
}
}
// 校验器
Object[] validators = factory.getBeanNamesForType(Validator.class);
if(validators != null) {
for(Object _validatorBeanName : validators) {
String validatorBeanName = String.valueOf(_validatorBeanName);
BeanDefinition beanDefine = factory.getBeanDefinition(validatorBeanName);
String scope = beanDefine.getScope();
if(scope == null || !scope.equals(ConfigurableBeanFactory.SCOPE_PROTOTYPE)) {
beanDefine.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
factory.registerBeanDefinition(validatorBeanName, beanDefine);
}
}
}
}

  可以看到,核心代码其实很少,也很容易懂!我针对控制器类和校验器类的所有Bean定义(使用getBeanNamesForType函数可以获取给定类型及其子类型的所有Bean定义;上文对Controller类型的检测是使用了Spring的@Controller,这是因为我个人的业务需求不一样,大家注意,beanfactory中的各种方法大家查看API灵活使用),检测到它们scope不为prototype时强制重设!

说在结尾


  我一直跟很多向我咨询Spring运用的朋友们说起:先把Spring看成一个Hashtable,它存了很多键值,就是Bean定义(包括Bean关系等等);其次是Spring不会凭空产生,更不会凭空为你托管对象,我们使用Spring的方式最终都是{new XXYYZZApplicationContext().getBean(XXYYZZ)},你在web.xml中定义的ContextLoaderListener,或者是其他中间件(Struts等)。

  “万事万物都有其源头。”所以,如果观看此篇博文的朋友进行单元测试时发现自动注入等功能未实现,请看看你是否为Spring容器创建了对象。

联系我,一起交流


欢迎您移步我们的交流群,无聊的时候大家一起打发时间:

或者通过QQ与我联系:

(最后编辑时间2015-12-31 16:22:53)

Spring进阶教程之在ApplicationContext初始化完成后重定义Bean的更多相关文章

  1. Spring 系列教程之 bean 的加载

    Spring 系列教程之 bean 的加载 经过前面的分析,我们终于结束了对 XML 配置文件的解析,接下来将会面临更大的挑战,就是对 bean 加载的探索.bean 加载的功能实现远比 bean 的 ...

  2. Spring Security教程之Jsp标签(八)

    目录 1.1     authorize 1.2     authentication 1.3     accesscontrollist Spring Security也有对Jsp标签的支持的标签库 ...

  3. Spring Security教程之Jsp标签(四)

    目录 1.1     authorize 1.2     authentication 1.3     accesscontrollist Spring Security也有对Jsp标签的支持的标签库 ...

  4. 迅为4412开发板Linux驱动教程之GPIO的初始化

    视频下载地址:http://pan.baidu.com/s/1c06oiti GPIO的初始化 • 在内核源码目录下使用命令“ls drivers/gpio/*.o”,可以看到“gpio-exynos ...

  5. Spring Security教程之session管理(十一)

    1.1     检测session超时 1.2     concurrency-control 1.3     session 固定攻击保护 Spring Security通过http元素下的子元素s ...

  6. Spring Security教程之session管理

    1.1     检测session超时 1.2     concurrency-control 1.3     session 固定攻击保护 Spring Security通过http元素下的子元素s ...

  7. Vue 进阶教程之:详解 v-model

    分享 Vue 官网教程上关于 v-model 的讲解不是十分的详细,写这篇文章的目的就是详细的剖析一下, 并介绍 Vue 2.2 v-model改进的地方,然后穿插的再说点 Vue 的小知识. 在 V ...

  8. 《STM32CubeMX配置STM32H743XI工程》第一讲《初始化UART,重定义printf函数,点亮一个LED灯》

    1.打开STM32CubeMX软件->新建一个工程(软件自行到ST官网下载安装) 2.输入对应的芯片型号(本次基于野火STM32H743XI Pro 开发板)点击Start Project生成项 ...

  9. SpringBoot 源码解析 (三)----- Spring Boot 精髓:启动时初始化数据

    在我们用 springboot 搭建项目的时候,有时候会碰到在项目启动时初始化一些操作的需求 ,针对这种需求 spring boot为我们提供了以下几种方案供我们选择: ApplicationRunn ...

随机推荐

  1. 从“程序员转行卖烧饼”想到IT人创业

    我的一个朋友最近总在跟我念叨着“我不想做开发了,整天累死累活写程序,也攒不下几个钱.我想辞职搞点啥!” 我问他:“你想搞点啥?”. 他说:“搞啥都比做开发强,做个网站赚广告费,接私活……实在不行我去卖 ...

  2. 【Leetcode】【Medium】Set Matrix Zeroes

    Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place. 解题思路: ...

  3. 写给自己看的Linux运维基础(三) - Mono

    如果使用ubuntu,可使用apg-get安装完mono,xsp,mod_mono,我的yum源并没有找到mono可安装,网上也没找到CentOS的源,最后选择下载编译安装. Stackoverflo ...

  4. [安卓] 5、SeekBar拖动条

    越来越发现这些控件用法大同小异了,这里注意几个函数:seekBar.setSecondaryProgress(0);设置初始进度为0,总共为0~99,对其监听用setOnSeekBarChangeLi ...

  5. 我的cookie读写

    前后台必须一致, 后台: public static void SetCookie(string cookieName, string value, int expiresDays){    var ...

  6. Openstack Murano(kilo)二次开发之添加Volume

    Openstack Murano(kilo)二次开发之添加Volume 欢迎转载,转载请注明出处:http://www.cnblogs.com/fmnisme/p/openstack_murano_a ...

  7. C# 两行代码实现 延迟加载的单例模式(线程安全)

    关键代码第4,5行. 很简单的原理不解释:readonly + Lazy(.Net 4.0 + 的新特性) public class LazySingleton { //Lazy singleton ...

  8. Null 与 “” 的区别

    说明:很多人有时候对于 null 和 "" 不是很清楚,结合其他人的文章,今天做下解释. String str1 = null; str引用为空 String str2 = &qu ...

  9. 上海SAP代理商 电子行业ERP系统 SAP金牌代理商达策

    上海SAP代理商 电子行业ERP系统 SAP金牌代理商达策上海达策为电子行业企业提供了多样的ERP信息化管理系统.基于多营运中心的管理架构体系,构造了以供应链.生产管理.财务一体化为核心,协同HR.B ...

  10. linux 下查找大于100M的文件(转)

    命令行如下 find . -type f -size +1000000k Linux系统下查找大文件或目录的技巧 当硬盘空间不够时,我们就很关心哪些目录或文件比较大,看看能否干掉一些了,怎么才能知道呢 ...