天天看點

适應各種開發,測試,線上,線下環境的Spring配置方式

背景

假設開發了一個中間件,比如是一個緩存系統,這個中間件要配置一個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),分别給不同的業務使用,那就這時會有很多的配置的麻煩。

  • 從使用者的角度出發,應用不喜歡引入一堆的配置,它們隻希望import一個配置檔案,然後在代碼裡用@AutoWried注入一個Bean,就可以使用了。
  • Spring Bean被覆寫的風險。

如果兩個不同的業務都使用了這個cache,然後它們的jar包又再被第三個業務引用,那麼它們都import了一個cache service的配置,那麼就有可能出現後面的Bean定義被前面的覆寫了。而Spring預設不處理這種Bean重複定義的問題。

  • @AutoWried 注入的問題。和上一個問題類似,@AutoWried注入時如果沒有配置@Qualifier,那麼如果某個類有多個Bean執行個體,那麼就有可能出現Bean注入混亂的情況。
  • 線上環境臨時切換。必須要支援線上臨時修改配置。
  • 開發者無需配置。要提供預設值的配置,開發者不用做配置就可以直接在本地和測試環境運作代碼。
  • 靜默釋出新版配置。比如當叢集遷移了,IP位址變換了,應用不用修改代碼和配置,隻需要用Maven重新打包即可。

可以利用的技術

spring profile,,@AutoWried,@Qualifier, PropertyPlaceholderConfigurer,PropertyOverrideConfigurer。

profile,PropertyPlaceholderConfigurer等的相關,不一一介紹了。如果有不明白的,可以到spring的文檔裡參考下。

簡要列舉下是如何解決上面的問題的。

1.在緩存中間件的jar包裡放上三個叢集的預設配置:

2.看下spring-cacheClusterA.xm裡的内容:

<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可以配置預設值,估計這功能比較少人知道 。

這樣就解決了不同環境,還要有預設配置的問題。

3.使用者的使用方法

假定使用者要用到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,這樣就可以看到很多有用的資訊了。