Spring中Bean多种实现切换方案

Spring中Bean多种实现切换方案

原创  2013年09月14日 21:11:23

 

一个公共工程中的Spring配置文件,可能会被多个工程引用。因为每个工程可能只需要公共工程中的一部分Bean,所以这些工程的Spring容器启动时,需要区分开哪些Bean要创建出来。另一种场景是:想通过Properties文件中的配置开关,就将Spring配置文件中Bean的实现切换成另一套。

 

方法一:Qulifier区分Bean

1.1应用实例

以Apache开源框架Jetspeed中的一段配置为例:page-manager.xml

===============================================================================

[html]  view plain  copy
  1. <bean name="xmlPageManager"class="org.apache.jetspeed.page.psml.CastorXmlPageManager"init-method="init" destroy-method="destroy">  
  2.   <meta key="j2:cat" value="xmlPageManager orpageSerializer" />  
  3.   <constructor-arg index="0">  
  4.     <ref bean="IdGenerator"/>  
  5.   </constructor-arg>  
  6.   <constructor-arg index="1">  
  7.     <refbeanrefbean="xmlDocumentHandlerFactory" />  
  8.   </constructor-arg>  
  9.   ……  
  10. </bean>  
  11.   
  12. <bean id="dbPageManager"class="org.apache.jetspeed.page.impl.DatabasePageManager"init-method="init" destroy-method="destroy">  
  13.   <meta key="j2:cat" value="dbPageManager orpageSerializer" />  
  14.   <!-- OJB configuration file resourcepath -->  
  15.   <constructor-arg index="0">  
  16.    <value>JETSPEED-INF/ojb/page-manager-repository.xml</value>  
  17.   </constructor-arg>  
  18.   <!-- fragment id generator -->  
  19.   <constructor-arg index="1">  
  20.     <ref bean="IdGenerator"/>  
  21.   </constructor-arg>  
  22.   ……  
  23. </bean>  
 

1.2 Bean过滤器

JetspeedBeanDefinitionFilter在Spring容器解析每个Bean定义时,会取出上面Bean配置中j2:cat对应的值,例如dbPageManageror pageSerializer。然后将这部分作为正则表达式与当前的Key(从配置文件中读出)进行匹配。只有匹配上的Bean,才会被Spring容器创建出来。

 

JetspeedBeanDefinitionFilter

===============================================================================

[java]  view plain  copy
  1. public boolean match(BeanDefinition bd)  
  2. {  
  3.     String beanCategoriesExpression = (String)bd.getAttribute(CATEGORY_META_KEY);  
  4.     boolean matched = true;  
  5.     if (beanCategoriesExpression != null)  
  6.     {  
  7.         matched = ((matcher != null)&& matcher.match(beanCategoriesExpression));  
  8.     }  
  9.     return matched;  
  10.   
  11.   
  12. public void registerDynamicAlias(BeanDefinitionRegistry registry, String beanName,BeanDefinition bd)  
  13. {  
  14.     String aliases =(String)bd.getAttribute(ALIAS_META_KEY);  
  15.     if (aliases != null)  
  16.     {  
  17.         StringTokenizer st = newStringTokenizer(aliases, " ,");  
  18.         while (st.hasMoreTokens())  
  19.         {  
  20.             String alias = st.nextToken();  
  21.             if (!alias.equals(beanName))  
  22.             {  
  23.                 registry.registerAlias(beanName, alias);  
  24.             }  
  25.         }  
  26.     }  
  27. }  

===============================================================================

match()方法中的CATEGORY_META_KEY的值就是j2:cat,matcher类中保存的就是当前的Key,并负责将当前Key与每个Bean的进行正则表达式匹配。

registerDynamicAlias的作用是:在Bean匹配成功后,定制的Spring容器会调用此方法为Bean注册别名。详见下面1.3中的源码。


1.3定制Spring容器

定制一个Spring容器,重写registerBeanDefinition()方法,在Spring注册Bean时进行拦截。

===============================================================================

[java]  view plain  copy
  1. public class FilteringXmlWebApplicationContextextends XmlWebApplicationContext  
  2. {  
  3.     private JetspeedBeanDefinitionFilterfilter;  
  4.      
  5.     publicFilteringXmlWebApplicationContext(JetspeedBeanDefinitionFilter filter, String[]configLocations, Properties initProperties, ServletContext servletContext)  
  6.     {  
  7.         this(filter, configLocations,initProperties, servletContext, null);  
  8.     }  
  9.      
  10.     publicFilteringXmlWebApplicationContext(JetspeedBeanDefinitionFilter filter, String[]configLocations, Properties initProperties, ServletContext servletContext,ApplicationContext parent)  
  11.     {  
  12.         super();  
  13.         if (parent != null)  
  14.         {  
  15.             this.setParent(parent);  
  16.         }  
  17.         if (initProperties != null)  
  18.         {  
  19.             PropertyPlaceholderConfigurer ppc =new PropertyPlaceholderConfigurer();  
  20.            ppc.setIgnoreUnresolvablePlaceholders(true);  
  21.            ppc.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_FALLBACK);  
  22.             ppc.setProperties(initProperties);  
  23.             addBeanFactoryPostProcessor(ppc);  
  24.         }  
  25.         setConfigLocations(configLocations);  
  26.         setServletContext(servletContext);  
  27.         this.filter = filter;  
  28.     }  
  29.      
  30.     protected DefaultListableBeanFactorycreateBeanFactory()  
  31.     {  
  32.         return new FilteringListableBeanFactory(filter,getInternalParentBeanFactory());  
  33.     }  
  34. }  
  35.    
  36. public classFilteringListableBeanFactory extends DefaultListableBeanFactory  
  37. {  
  38.     private JetspeedBeanDefinitionFilterfilter;  
  39.      
  40.     public FilteringListableBeanFactory(JetspeedBeanDefinitionFilterfilter, BeanFactory parentBeanFactory)  
  41.     {  
  42.         super(parentBeanFactory);  
  43.         this.filter = filter;  
  44.         if (this.filter == null)  
  45.         {  
  46.             this.filter = newJetspeedBeanDefinitionFilter();  
  47.         }  
  48.         this.filter.init();  
  49.     }  
  50.    
  51.     /** 
  52.      * Override of the registerBeanDefinitionmethod to optionally filter out a BeanDefinition and 
  53.      * if requested dynamically register anbean alias 
  54.      */  
  55.     public void registerBeanDefinition(StringbeanName, BeanDefinition bd)  
  56.             throws BeanDefinitionStoreException  
  57.     {  
  58.         if (filter.match(bd))  
  59.         {  
  60.            super.registerBeanDefinition(beanName, bd);  
  61.             if (filter != null)  
  62.             {  
  63.                 filter.registerDynamicAlias(this, beanName, bd);  
  64.             }  
  65.         }  
  66.     }  
  67. }  


1.4为Bean起别名

使用BeanReferenceFactoryBean工厂Bean,将上面配置的两个Bean(xmlPageManager和dbPageManager)包装起来。将Key配成各自的,实现通过配置当前Key来切换两种实现。别名都配成一个,这样引用他们的Bean就直接引用这个别名就行了。例如下面的PageLayoutComponent。

 

page-manager.xml

===============================================================================

[html]  view plain  copy
  1. <bean class="org.springframework.beans.factory.config.BeanReferenceFactoryBean">  
  2.     <meta key="j2:cat"value="xmlPageManager" />  
  3.     <meta key="j2:alias"value="org.apache.jetspeed.page.PageManager" />  
  4.     <propertynamepropertyname="targetBeanName" value="xmlPageManager" />  
  5.   </bean>  
  6.    
  7.   <bean class="org.springframework.beans.factory.config.BeanReferenceFactoryBean">  
  8.     <meta key="j2:cat"value="dbPageManager" />  
  9.     <meta key="j2:alias"value="org.apache.jetspeed.page.PageManager" />  
  10.     <propertynamepropertyname="targetBeanName" value="dbPageManager" />  
  11.   </bean>  
  12.    
  13.   <bean id="org.apache.jetspeed.layout.PageLayoutComponent"  
  14.     class="org.apache.jetspeed.layout.impl.PageLayoutComponentImpl">  
  15.     <meta key="j2:cat"value="default" />  
  16.     <constructor-arg index="0">  
  17.       <refbeanrefbean="org.apache.jetspeed.page.PageManager" />  
  18.     </constructor-arg>  
  19.     <constructor-arg index="1">  
  20.       <value>jetspeed-layouts::VelocityOneColumn</value>  
  21.     </constructor-arg>  
  22.   </bean>   
 

方法二:使用注解区分Bean

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值