Apollo 1 融合 Spring 的三個入口
前言
Spring 作為 Java 世界非官方標準框架,任何一個中間件想要得到良好的發展,必須完美支持 Spring 的各種特性,即:無縫融入 Spring。
Apollo 作為分布式配置中心,服務於 Java 應用程序,Java 應用程序可以通過 Apollo 提供的 Client 獲取遠程配置信息。而如何將這個 Client 高度融合到用戶的應用程序中呢?
這就需要針對 Spring 提供給我們的接口進行擴展。
在之前的文章中,已經大致聊過 Spring 的一些擴展接口:深入理解Spring 之 Spring 進階開發必知必會 之 Spring 擴展接口。
而想融入 Spring,首先得找到入口,然後才能註冊相關的類進行自己系統的初始化。
第一種入口:XML
XML 是傳統 Java 項目的配置文件,特別是 Spring MVC 項目。雖然現在都是使用的自動化配置,但仍然有一些遺留項目使用 XML,因此,支持 XML 是大部分中間件的必須工作。
支持 XML 需要準守 Spring 的幾個約定:
- 繼承
NamespaceHandlerSupport
抽象類,重寫 init 方法,調用 registerBeanDefinitionParser 方法,並傳入自己繼承的AbstractSingleBeanDefinitionParser
子類用於解析標簽,重寫他的 getBeanClass 方法,返回一個 Bean,用於註冊相關的 Bean。 - classpath 下創建 META-INF 目錄,創建
spring.handlers
文件,將 xml 配置中的 URL 指向NamespaceHandlerSupport
。 - META-INF 目錄下,創建
apollo-1.0.0.xsd
xsd 文件,用於解釋自定義標簽。 - META-INF 目錄下,繼續創建
spring.schemas
文件,將 xml 配置中的 xsd URL 指向 xsd 文件。
如果你的 xml 配置中,引用了 apollo 的標簽,Spring 將會根據 xml 中的 URL 找到 spring.handlers
中的 NamespaceHandlerSupport
第二種入口:@Import 註解
相對於基於XML的配置,基於Java的配置是目前比較流行的方式。
@Import 註解的使用方式:
定義一個自己的啟動註解。並標註 @import 註解, 其實就是 xml 中的 import 標簽,在該註解中,可以配置一個類,這個類就會註冊進 Spring 的容器,成為 Bean,你就可以在這個 bean 裏做文章。
在 apollo 中,使用方式如下:@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(ApolloConfigRegistrar.class) public @interface EnableApolloConfig { String[] value() default {ConfigConsts.NAMESPACE_APPLICATION}; int order() default Ordered.LOWEST_PRECEDENCE; }
從上面可以看出
ApolloConfigRegistrar
類是 apollo 註冊進的 bean。這個 bean 用於處理 @EnableApolloConfig 註解,同時註冊 apollo 關鍵 Bean 到 Spring 容器中。用戶只需在 Spring 系統中的某個類上,標註 @EnableApolloConfig ,就可以通過 Spring 的方式(自動更新,註解等)使用 apollo 功能。
第三種入口:SpringBoot Starter
目前最流行的框架就是 Spring Boot ,兼容 SpringBoot 是一個大趨勢。
Spring Boot 提供 spring-boot-autoconfigure
讓第三方框架兼容 Boot,稱之為 starter。
創建一個 starter 需要遵守幾個約定:
- maven 引入
spring-boot-autoconfigure
artifact. - 創建一個類,實現
ApplicationContextInitializer
接口,重寫 initialize 方法,該方法在容器初始化的時候調用。 - META-INF 創建
spring.factories
文件,Boot 啟動時會自動掃描這個文件。需要在這個文件中寫入一個步驟 2 創建的類,類似org.springframework.context.ApplicationContextInitializer=\com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer
。這個類的作用是提前(容器初始化前)加載關鍵配置到 Spring 環境。 在
spring.factories
文件中,還需要讓 boot 的EnableAutoConfiguration
自動配置類指向一個自定義類。這是 SpringBoot starter 的關鍵,例如:org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.ctrip.framework.apollo.spring.boot.ApolloAutoConfiguration
。ApolloAutoConfiguration 就會加入的 apollo 的配置 bean 中。你可以在這個配置 bean 中,創建一個關鍵 bean ,用於處理系統相關的初始化類。例如 apollo 的方式:@Configuration @ConditionalOnProperty(PropertySourcesConstants.APOLLO_BOOTSTRAP_ENABLED) @ConditionalOnMissingBean(PropertySourcesProcessor.class)// 當Spring Context中不存在該Bean時 public class ApolloAutoConfiguration { @Bean public ConfigPropertySourcesProcessor configPropertySourcesProcessor() { return new ConfigPropertySourcesProcessor(); } }
在 apollo 中,
ConfigPropertySourcesProcessor
就是用來註冊系統關鍵 bean 的。
總結
本文重點介紹了 3 種入口:
- XML 方式,通過在 getBeanClass 方法返回系統關鍵 Bean。
- @Import 註解,通過在註解中定義 Bean,然後在該 Bean 中處理。
- SpringBoot Starter 方式,通過
spring.factories
文件中定義自動配置類,可以註冊系統關鍵 bean。
在以後的開發中,如果想融入 Spring,就可以通過這 3 種方式自行處理。
Apollo 1 融合 Spring 的三個入口