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

方法一:Qulifier区分Bean

1.1应用实例

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

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

  <bean name="xmlPageManager"class="org.apache.jetspeed.page.psml.CastorXmlPageManager"init-method="init" destroy-method="destroy">
<meta key="j2:cat" value="xmlPageManager orpageSerializer" />
<constructor-arg index="0">
<ref bean="IdGenerator"/>
</constructor-arg>
<constructor-arg index="1">
<refbean="xmlDocumentHandlerFactory" />
</constructor-arg>
……
</bean> <bean id="dbPageManager"class="org.apache.jetspeed.page.impl.DatabasePageManager"init-method="init" destroy-method="destroy">
<meta key="j2:cat" value="dbPageManager orpageSerializer" />
<!-- OJB configuration file resourcepath -->
<constructor-arg index="0">
<value>JETSPEED-INF/ojb/page-manager-repository.xml</value>
</constructor-arg>
<!-- fragment id generator -->
<constructor-arg index="1">
<ref bean="IdGenerator"/>
</constructor-arg>
……
</bean>

1.2 Bean过滤器

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

JetspeedBeanDefinitionFilter

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

    public boolean match(BeanDefinition bd)
{
String beanCategoriesExpression = (String)bd.getAttribute(CATEGORY_META_KEY);
boolean matched = true;
if (beanCategoriesExpression != null)
{
matched = ((matcher != null)&& matcher.match(beanCategoriesExpression));
}
return matched;
} public void registerDynamicAlias(BeanDefinitionRegistry registry, String beanName,BeanDefinition bd)
{
String aliases =(String)bd.getAttribute(ALIAS_META_KEY);
if (aliases != null)
{
StringTokenizer st = newStringTokenizer(aliases, " ,");
while (st.hasMoreTokens())
{
String alias = st.nextToken();
if (!alias.equals(beanName))
{
registry.registerAlias(beanName, alias);
}
}
}
}

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

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

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

1.3定制Spring容器

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

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

public class FilteringXmlWebApplicationContextextends XmlWebApplicationContext
{
private JetspeedBeanDefinitionFilterfilter; publicFilteringXmlWebApplicationContext(JetspeedBeanDefinitionFilter filter, String[]configLocations, Properties initProperties, ServletContext servletContext)
{
this(filter, configLocations,initProperties, servletContext, null);
} publicFilteringXmlWebApplicationContext(JetspeedBeanDefinitionFilter filter, String[]configLocations, Properties initProperties, ServletContext servletContext,ApplicationContext parent)
{
super();
if (parent != null)
{
this.setParent(parent);
}
if (initProperties != null)
{
PropertyPlaceholderConfigurer ppc =new PropertyPlaceholderConfigurer();
ppc.setIgnoreUnresolvablePlaceholders(true);
ppc.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_FALLBACK);
ppc.setProperties(initProperties);
addBeanFactoryPostProcessor(ppc);
}
setConfigLocations(configLocations);
setServletContext(servletContext);
this.filter = filter;
} protected DefaultListableBeanFactorycreateBeanFactory()
{
return new FilteringListableBeanFactory(filter,getInternalParentBeanFactory());
}
} public classFilteringListableBeanFactory extends DefaultListableBeanFactory
{
private JetspeedBeanDefinitionFilterfilter; public FilteringListableBeanFactory(JetspeedBeanDefinitionFilterfilter, BeanFactory parentBeanFactory)
{
super(parentBeanFactory);
this.filter = filter;
if (this.filter == null)
{
this.filter = newJetspeedBeanDefinitionFilter();
}
this.filter.init();
} /**
* Override of the registerBeanDefinitionmethod to optionally filter out a BeanDefinition and
* if requested dynamically register anbean alias
*/
public void registerBeanDefinition(StringbeanName, BeanDefinition bd)
throws BeanDefinitionStoreException
{
if (filter.match(bd))
{
super.registerBeanDefinition(beanName, bd);
if (filter != null)
{
filter.registerDynamicAlias(this, beanName, bd);
}
}
}
}

1.4为Bean起别名

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

page-manager.xml

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

<bean class="org.springframework.beans.factory.config.BeanReferenceFactoryBean">
<meta key="j2:cat"value="xmlPageManager" />
<meta key="j2:alias"value="org.apache.jetspeed.page.PageManager" />
<propertyname="targetBeanName" value="xmlPageManager" />
</bean> <bean class="org.springframework.beans.factory.config.BeanReferenceFactoryBean">
<meta key="j2:cat"value="dbPageManager" />
<meta key="j2:alias"value="org.apache.jetspeed.page.PageManager" />
<propertyname="targetBeanName" value="dbPageManager" />
</bean> <bean id="org.apache.jetspeed.layout.PageLayoutComponent"
class="org.apache.jetspeed.layout.impl.PageLayoutComponentImpl">
<meta key="j2:cat"value="default" />
<constructor-arg index="0">
<refbean="org.apache.jetspeed.page.PageManager" />
</constructor-arg>
<constructor-arg index="1">
<value>jetspeed-layouts::VelocityOneColumn</value>
</constructor-arg>
</bean>

方法二:使用注解区分Bean

(未完 待续)

Spring中Bean多种实现切换方案的更多相关文章

  1. Spring入门(五):Spring中bean的作用域

    1. Spring中bean的多种作用域 在默认情况下,Spring应用上下文中所有的bean都是以单例(singleton)的形式创建的,即不管给定的一个bean被注入到其他bean多少次,每次所注 ...

  2. Spring中bean的管理

    Spring 中常见的容器 我们知道spring容器就是spring中bean的驻留场所.spring容器并不是只有一个.spring自带了多个容器实现,可以归为两种不同的类型:bean工厂和应用上下 ...

  3. Spring中Bean的作用域、生命周期

                                   Bean的作用域.生命周期 Bean的作用域 Spring 3中为Bean定义了5中作用域,分别为singleton(单例).protot ...

  4. Spring中Bean的实例化

                                    Spring中Bean的实例化 在介绍Bean的三种实例化的方式之前,我们首先需要介绍一下什么是Bean,以及Bean的配置方式. 如果 ...

  5. Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别

    Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...

  6. (转)Spring中Bean的命名问题(id和name区别)及ref和idref之间的区别

    Spring中Bean的命名 1.每个Bean可以有一个id属性,并可以根据该id在IoC容器中查找该Bean,该id属性值必须在IoC容器中唯一: 2.可以不指定id属性,只指定全限定类名,如: & ...

  7. JAVA面试题:Spring中bean的生命周期

    Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...

  8. Spring中Bean的命名问题及ref和idref之间的区别

    一直在用Spring,其实对其了解甚少,刚去了解了一下Spring中Bean的命名问题以及ref和idref之间的区别,略作记录,以备后查. Spring中Bean的命名 1.每个Bean可以有一个i ...

  9. 深入理解Spring中bean的生命周期

    [Spring中bean的生命周期] bean的生命周期 1.以ApplocationContext上下文单例模式装配bean为例,深入探讨bean的生命周期: (1).生命周期图: (2).具体事例 ...

随机推荐

  1. C++ 实参和形参

    形参:在函数没有调用的时候,函数的形参并不占据实际的内存空间,也没有实质的值,--正如字面意思那样,"形式"参数,只是一个"形式. 实参:当函数被调用的时候,系统会为形式 ...

  2. SSD:TensorFlow中的单次多重检测器

    SSD:TensorFlow中的单次多重检测器 SSD Notebook 包含 SSD TensorFlow 的最小示例. 很快,就检测出了两个主要步骤:在图像上运行SSD网络,并使用通用算法(top ...

  3. 网易互联网&网易游戏产品经理面试经验

    网易是分网易游戏和网易互联网的,本人都参加了校园招聘面试,最后均拿到了产品经理的offer. 网易是分网易游戏和网易互联网的,先说网易互联网吧,当时是去杭州总部进行面试,我觉得这是我面的最难的面试了. ...

  4. urllib,request 设置代理

     通常防止爬虫被反主要有以下几个策略: 1.动态设置User-Agent(随机切换User-Agent,模拟不同用户的浏览器信息) 2.使用IP地址池:VPN和代理IP,现在大部分网站都是根据IP来b ...

  5. 值得珍藏的HTTP协议详解

    转自:http://www.cnblogs.com/li0803/archive/2008/11/03/1324746.html 引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式 ...

  6. ERP中的地区管理

    地区管理 地区管理主要实现地区数据的添加.编辑.查看.启用.禁用等功能,另外还包含地区选择控件封装. 业务功能点: 地区数据查看:地区列表树状展现,列表增加省.市.区.县.乡图标. 地区选择控件:选择 ...

  7. C语言多维数组的指针传递

    在C语言中为了节省空间,提高运行速度经常使用指针来完成数组的传递. 对于一维数组而言可以直接传递首地址 而对于二维数组必须在传递时声明是二维数组的指针,并且调用时也要经过一些运算 首先是定义形参: 函 ...

  8. CRM客户关系管理系统(四)

    kingadmin设计开发 4.4.根据list_display配置生成数据列表 (1)kingadmin/views.py (2)kingadmin/templates/kingadmin/tabl ...

  9. Android开发艺术探索第五章——理解RemoteViews

    Android开发艺术探索第五章--理解RemoteViews 这门课的重心在于RemoteViews,RemoteViews可以理解为一种远程的View,其实他和远程的Service是一样的,Rem ...

  10. Antlr v4入门教程和实例

    1 重逢ANTLR 最早知道ANTLR是当年学习Apache Derby数据库源码时,在看到SQL解析那一层时,第一次看到编译原理在实际项目中的应用,惊叹之余也只能望而却步.之前也根据网上一些资料尝试 ...