@Conditional on properties 用法

需求:如何封裝spring cloud 的不同的注冊(cè)中心,比如eureka, zookeeper,consul。 如何封裝不同的http rpc 客戶端,比如 Ribbon.

實(shí)現(xiàn):

這個(gè)需求其實(shí)很簡(jiǎn)單,下面記錄自己解決問(wèn)題的探索過(guò)程。

如何封裝不同的配置中心呢? 首先我們得了解下spring cloud 的自動(dòng)裝配簡(jiǎn)單常識(shí)。(1). 在maven 或者 gradle 加入相關(guān)的依賴之后,springboot 就會(huì)自動(dòng)的加載相關(guān)的類到classpath,比如eureka,會(huì)自動(dòng)的裝載?EurekaClientAutoConfiguration.class,并生成相關(guān)beans。(2)生成相關(guān)的bean有各種注解,比如@imported,@ComponentScan,@Service,@Compoent,@Repository 等。 @Order 可以控制類的加載順序,@order 越小,越先運(yùn)行

其實(shí)對(duì)于這樣的需求,程序員第一反應(yīng)應(yīng)該都是根據(jù)條件加載,但是我們應(yīng)該如何做呢?@Conditional 有各種, 比如@ConditionalOnClass, @ConditionalOnBean,@ConditionalOnMissingbean,@ConditionalOnProperty, 他們都應(yīng)該去繼承SpringBootCondition,實(shí)現(xiàn)接口Condition。因?yàn)槲覀兿雽懗蒘DK的方式,所以最后能夠通過(guò)配置的方式來(lái)啟動(dòng)不同的bean,實(shí)現(xiàn)SDK 支持多個(gè)配置中心,而且可以支持多種的http rpc 客戶端。因此我選擇了@ConditionalOnProperty的方式來(lái)加載不同的beans。

因此第一步,我打算extends?SpringBootCondition,不是使用@ConditionalOnProperty。重寫了method?getMatchOutcome。因此寫了個(gè)annotation?ConditionOnMyProperties,并需要注解@Conditional。@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME)@Documented@Conditional(OnMyPropertiesCondition.class)public @interface ConditionOnMyProperties {Stringname();},? 然后define?OnMyPropertiesCondition extends?SpringBootCondition

public ConditionOutcomegetMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {

Object propertiesName = metadata.getAnnotationAttributes(ConditionOnMyProperties.class.getName()).get("name");String applicationFrameworkName = context.getEnvironment().getProperty("application.framework.name");

其中application.framework.name 就是 配置的key,應(yīng)用程序可以根據(jù)這個(gè)配置來(lái)切換加載不同的beans。?return new ConditionOutcome(true, "application framework " + applicationFrameworkName +" beans loaded");? 當(dāng)return?ConditionOutcome 是true 的時(shí)候,表示加載這個(gè)beans, 當(dāng)返回false的時(shí)候,不加載這個(gè)beans。 所以我們就可以重寫ConditionOutcomegetMatchOutcome打顯身手。

第二步:?

For eureka,?

@Configuration

@ConditionOnMyProperties(name = HttpClientNameType.SPRINGCLOUD_EUREKA)

@EnableSpringCloudStarter

@EnableAutoConfiguration

public class SpringCloudEurekaConfig {

}

其中@ConditionOnMyProperties(name = HttpClientNameType.SPRINGCLOUD_EUREKA),就可以依據(jù) application 配置的值application.framework.name 來(lái)判斷是否要不要加載。 此外@EnableSpringCloudStarter是我自己寫的annotation,里面加了@EnableDiscoveryClient,?@EnableCircuitBreaker。其中SpringCloudZookeeperConfig 也可以這么配置。但是當(dāng)啟動(dòng)的springboot的時(shí)候,新的問(wèn)題來(lái)了, 你會(huì)發(fā)現(xiàn)eureka的注冊(cè)中心,會(huì)去連zookeeper的注冊(cè)中心。這個(gè)時(shí)候你會(huì)發(fā)現(xiàn) 前面說(shuō)的(1)常識(shí)是多么重要。那肯定是有別的bean自動(dòng)的加載到context中去了, 經(jīng)過(guò)調(diào)試,對(duì)于eureka,需要這樣配置@EnableAutoConfiguration(exclude = {ZookeeperAutoConfiguration.class, RibbonZookeeperAutoConfiguration.class}), 剔除ZookeeperAutoConfiguration 和RibbonZookeeperAutoConfiguration的自動(dòng)注解。另外?需要在OnMyPropertiesCondition class中加入環(huán)境變量System.setProperty("spring.cloud.zookeeper.discovery.enabled", "false"); 對(duì)于zookeeper,就需要加入System.setProperty("eureka.client.enabled", "false"); 這樣問(wèn)題就很容易的解決了,是不是覺得很簡(jiǎn)單? springboot 封裝的東西太多,都不知道里面發(fā)生了啥。

缺點(diǎn):無(wú)關(guān)的class 會(huì)加載到j(luò)vm中,jar 沖突的時(shí)候,可能不好解決。

后面會(huì)繼續(xù)介紹些vertx的心得。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容