Spring進階教程之在ApplicationContext初始化完成後重定義Bean

來源:互聯網
上載者:User

標籤:

之前遇到一個很有意思的問題:我需要批量重定義特定類型的由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     @Override4     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容器建立了對象。

Spring進階教程之在ApplicationContext初始化完成後重定義Bean

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.