Spring进阶教程之在ApplicationContext初始化完成后重定义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>
1 public class BeanDefineConfigue implements ApplicationListener<ContextRefreshedEvent> {
2     
3     @Override
4     public void onApplicationEvent(ContextRefreshedEvent event) {
5         
6     }
7 }

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

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

BeanFactory-BeanDefinition-registerBeanDefinition

 1 public void onApplicationEvent(ContextRefreshedEvent event) {
 2         ConfigurableApplicationContext context = (ConfigurableApplicationContext) event.getApplicationContext();
 3         DefaultListableBeanFactory factory = (DefaultListableBeanFactory) context.getBeanFactory();
 4         // 控制器
 5         String[] controllers = factory.getBeanNamesForAnnotation(Controller.class);
 6         if(controllers != null) {
 7             for(String controllerBeanName : controllers) {
 8                 BeanDefinition beanDefine = factory.getBeanDefinition(controllerBeanName);
 9                 String scope = beanDefine.getScope();
10                 if(scope == null || !scope.equals(ConfigurableBeanFactory.SCOPE_PROTOTYPE)) {
11                     beanDefine.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
12                     factory.registerBeanDefinition(controllerBeanName, beanDefine);
13                 }
14             }
15         }
16         // 校验器
17         Object[] validators = factory.getBeanNamesForType(Validator.class);
18         if(validators != null) {
19             for(Object _validatorBeanName : validators) {
20                 String validatorBeanName = String.valueOf(_validatorBeanName);
21                 BeanDefinition beanDefine = factory.getBeanDefinition(validatorBeanName);
22                 String scope = beanDefine.getScope();
23                 if(scope == null || !scope.equals(ConfigurableBeanFactory.SCOPE_PROTOTYPE)) {
24                     beanDefine.setScope(ConfigurableBeanFactory.SCOPE_PROTOTYPE);
25                     factory.registerBeanDefinition(validatorBeanName, beanDefine);
26                 }
27             }
28         }
29     }

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

说在结尾


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

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

优质内容筛选与推荐>>
1、配置阿里云maven中央库
2、C# +DirectX基础编程
3、Cocos2d-x中的坐标系
4、Day_02
5、C#框架类


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn