前言


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

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

  这篇博客主要给大家讲一下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. 鸟瞰Nodejs

    一,基础. 1,Node的包管理器:npm; 安装node环境时会自动安装. 本地模式获取一个包:npm install [package_name] 此时包被安装到当前木的node_modules子 ...

  2. 《JavaScript高级程序设计》学习笔记12篇

    写在前面: 这12篇博文不是给人看的,而是用来查的,忘记了什么基础知识,点开页面Ctrl + F关键字就好了 P.S.如果在对应分类里没有找到,麻烦告诉我,以便尽快添上.当然,我也会时不时地添点遗漏的 ...

  3. Sqoop2 环境搭建

    原文地址:http://www.cnblogs.com/luogankun/p/4209017.html 正在准备做Spark SQL external data source与关系型数据库交互的部分 ...

  4. 手机H5 web调试利器——WEINRE (WEb INspector REmote)

    手机H5 web调试利器--WEINRE (WEb INspector REmote) 调试移动端页面,优先选择使用chrome浏览器调试,如果是hybrid形式的页面,可以使用chrome提供的ch ...

  5. MongoDB与.NET结合使用一(mongodb在windows 2003上的安装)

    mongodb发展至今已经到2.6版本了,自从获得了1亿美元的风投之后,发展速度更是比以前快了很多,前段时间因为要用缓存,也比较了mongodb,大家也都觉得比较适合做无关系化的大数据存储,所以系统统 ...

  6. Qt之Dialog\widget\ mainwindow的区别和布局管理器 & 分裂器的区别

    1.Dialog\widget\ mainwindow的区别 注意mainwindow和widget的区别,mainwindow都工具栏和菜单栏 Dialog and mainwinodws 都是继承 ...

  7. 使用HTML5的File实现base64和图片的互转

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. Activiti 删除key值相同的所有不同版本的流程定义

    package com.mycom.processDefinition; import java.io.File; import java.io.IOException; import java.io ...

  9. 【CUDA学习】共享存储器

    下面简单介绍一些cuda中的共享存储器和全局存储器 共享存储器,shared memory,可以被同一块中的所有线程访问的可读写存储器,生存期是块的生命期. Tesla的每个SM拥有16KB共享存储器 ...

  10. HiveServer2 的jdbc方式创建udf的修改(add jar 最好不要使用),否则会造成异常: java.sql.SQLException: Error while processing statement: null

    自从Hive0.13.0开始,使用HiveServer2 的jdbc方式创建udf的临时函数的方法由: ADD JAR ${HiveUDFJarPath} create TEMPORARY funct ...