假设开发了一个中间件,比如是一个缓存系统,这个中间件要配置一个IP地址,还要配置一个Factory,从这个Factory里得到一个client,如:
<bean name="cacheFactory" class="com.test.cache.Factory"> <property name="address" value="192.168.1.100"/> </bean> <bean name="cacheClient" factory-bean="cacheFactory" factory-method="getClient" />
然后这个中间件有三个集群(clusterA, clusterB, clusterC),分别给不同的业务使用,那就这时会有很多的配置的麻烦。
如果两个不同的业务都使用了这个cache,然后它们的jar包又再被第三个业务引用,那么它们都import了一个cache service的配置,那么就有可能出现后面的Bean定义被前面的覆盖了。而spring默认不处理这种Bean重复定义的问题。
spring profile,,@AutoWried,@Qualifier, PropertyPlaceholderConfigurer,PropertyOverrideConfigurer。
profile,PropertyPlaceholderConfigurer等的相关,不一一介绍了。如果有不明白的,可以到spring的文档里参考下。
简要列举下是如何解决上面的问题的。
<beans profile="dev"> <bean id="cacheClusterAFactory" class="com.test.cache.CacheFactory"> <property name="address" value="${cache.address.clusterA:127.0.0.1}"/> </bean> <bean name="cacheClusterAClient" factory-bean="cacheClusterAFactory" factory-method="getClient" /> </beans> <beans profile="test"> <bean id="cacheClusterAFactory" class="com.test.cache.CacheFactory"> <property name="address" value="${cache.address.clusterA:192.168.1.101}"/> </bean> <bean name="cacheClusterAClient" factory-bean="cacheClusterAFactory" factory-method="getClient" /> </beans> <beans profile="product"> <bean id="cacheClusterAFactory" class="com.test.cache.CacheFactory"> <property name="address" value="${cache.address.clusterA:10.10.1.10}"/> </bean> <bean name="cacheClusterAClient" factory-bean="cacheClusterAFactory" factory-method="getClient" /> </beans>
里面定义了三个profile:dev,test,product。这三个profile分别对应开发,测试,线上三种环境。
而在具体bean的配置上,用了一些”${}”这样的占位符,另外还为它们配置了默认值。
PropertyPlaceholderConfigurer,PropertyOverrideConfigurer可以配置默认值,估计这功能比较少人知道 。
这样就解决了不同环境,还要有默认配置的问题。
假定使用者要用到clusterA和clusterB这两个集群,那么可以这样配置:
<context:property-placeholder location="classpath:env.properties" /> <import resource="cacheConfigDefault/spring-cacheClusterA.xml" /> <import resource="cacheConfigDefault/spring-cacheClusterB.xml" />
import了缓存中间件的默认配置,然后还用placeholder加载了一个env.properties的环境变量文件。
那么对于spring-cacheClusterA.xml和spring-cacheClusterB.xml里的address这个属性,如果没有在env.properties里有配置,则会使用默认配置。
如果想要修改,如修改cacheClusterA的配置,则可以在env.properties里加下:
#if comment this, will use the default value cache.address.clusterA=testClusterAAddress
那么clusterA使用的就是用户的配置,而不是所依赖的jar包的默认配置了。
再多详细的代码和配置,可以到这里找到演示的代码:
https://github.com/hengyunabc/spring-config
调试spring placeholder时,或者线上查看placeholder到底有没有工作时,可以把spring的log级别调为TRACE,这样就可以看到很多有用的信息了。