和spring cloud/boot 學習如何管理自己的組件


案例,

功能:

需要寫一個往kafka上報數據的組建。

 

當組建啟動時,需要建立如下資源:

1, 和kafka建立若干條連接

2, 啟動一個線程池

3, 啟動上報一個緩沖區

 

問題如下:

 

1, 如何在spring工程中引入該組件,並注入到spring容器中

2, 如間接被引用到此JAR包(如 引用的工程有引用到此組建JAR),或只是想用到里面數據類型,並不打算用功能時,如何避免資源會隨着引入而自行啟動造成資源浪費

3, 組建的配置如何統一管理問題

4, 如何管理眾多JAR包依賴,如, 此組建開發要用到kafka的0.11.0.2,有天需要升級到1.0.0

 

這些問題其實在spring cloud中都有比較好的解決方案,如 zuul, 后面也是仿造zuul的解決

 

一, 如何使該組建被spring工程引入

 

SPI方式,

如 zuul 的通過

\META-INF\spring.factories 

進行引入 ,指定引導目錄

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration,\
org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration

 

 

故 組建也定義如下

\META-INF\spring.factories 

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.zhenai.security.report.SecurityAutoConfiguration

在SecurityAutoConfiguration中,根據需要對bean進行初始化,和相關資源的啟動。如 啟動連接,啟動本地線程池等。

但這里的問題是,只要引入了這個JAR包(包括間接引入該JAR包),那么所有工程都會平白無故的去連kafka,去啟動一些無用的線程池

 

二, 如何屏蔽間接被引用到此JAR包的工程啟動相關資源

 

解決這個問題,spring cloud和spring boot還稍有不同,先看spring cloud.

 

Marker方式

spring cloud標簽模式

先看zuul是怎么做的, 如要在工程里啟動ZUUL,一般會在main類里加入@EnableZuulProxy 標簽,如下:

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class Application {
...  ....
}

需要引入@EnableZuulProxy 標簽

@EnableZuulProxy的源碼如下 :

@EnableCircuitBreaker
@EnableDiscoveryClient
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyMarkerConfiguration.class)
public @interface EnableZuulProxy {
}

看到 @Import(ZuulProxyMarkerConfiguration.class), ZuulProxyMarkerConfiguration只做了一件事,引入一個maker標簽

如下:

@Configuration
public class ZuulProxyMarkerConfiguration {
    @Bean
    public Marker zuulProxyMarkerBean() {
        return new Marker();
    }

    class Marker {
    }
}

這個Maker對象用作是否啟動啟用該配置,從而控制了資源是否啟動,如 ZuulServerAutoConfiguration

@Configuration
@EnableConfigurationProperties({ ZuulProperties.class })
@ConditionalOnClass(ZuulServlet.class)
@ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class)
// Make sure to get the ServerProperties from the same place as a normal web app would
@Import(ServerPropertiesAutoConfiguration.class)
public class ZuulServerAutoConfiguration {
...  ...
}

根據是否有Marker進行相關類的注入,是否啟動。

故:

此處,案例中的組件也選用了這種方式,如

@EnableZASecurityReport 標簽

當需要啟動時,在main類里加入標簽即可,如

@EnableZASecurityReport
public class Application {

...  ....

}

后續kafka的連接類,線程池,緩沖區等是否分配都可以根據相關標識進行管理,如spi入口類SecurityAutoConfiguration :

@Configuration
@EnableConfigurationProperties({ SecurityReportProperties.class })
@ConditionalOnBean(SecurityProxyMarkerConfiguration.Marker.class)
public class SecurityAutoConfiguration {
...  ... 
}

這樣,如果在main啟動類中,只要未加入@EnableZASecurityReport,那么即使引入了組件的JAR包,相關資源也不會被啟動。

starter方式

還有一種方式,即,spring boot用的比較多的start方式

spring boot的所有配置都在spring-boot-autoconfigure/META-INF/spring.factories里,通過@ConditionalOnBean特定類是否引入來判斷是否啟動資源。

如: spring-boot-starter-data-redis

首先通過spring.factories,引入Redis的引導類

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\

如:

RedisAutoConfiguration

@Configuration
@ConditionalOnClass({ RedisOperations.class })
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
 ... ...
}

當工程需要用到Redis時,通過Maven引入相關類

<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-redis</artifactId>  
</dependency>

spring-boot-starter-data-redis, 其實是一個空項目,有個spring.provides,通過它引入redis相關的JAR包,然后使@ConditionalOnClass生效,從而完成對Redis的JAR環境的初始化。

 

三, 配置如何統一管理問題

一個組件(JAR包)出來后,配置會比較多,比如該項目涉及到kafka配置,線程池配置等一大堆,傳統方式是去寫個相關說明文檔,一堆配置項會讓使用起來很是麻煩。

 

1, 約定優於配置

在spring cloud/boot中,最讓人好用的就是 約定優於配置。記住約定,少寫配置

如在zuul中, 只需要配置幾個必須項,其它都是約定項

如,約定配置文件即application.yml( 或 bootstrap.yml):

zuul:
 debug:
  routes:
    ZHENAI-CLIENT:
      path: /test/**

簡單配置下routes就可以啟動,如果要找到zuul的配置的約定值,可以直接尋找總配置類ZuulProperties,

ZuulProperties里,包含了所有配置項,並通過配置對象的方式進行模塊話的划分如:

ZuulRoute相關,Host相關,HystrixSemaphore相關等

(也是一種默認約定)

故,

在組件中,也可以模仿簡化下配置。 此組件核心功能就是上報,比配項目應該只是kafka的地址,要啟用,只需要

report.kafkaConfig.servers=X.X.X.X:9092

即可,若要詳細配置,和約定值,用一個統一配置文件管 ReportProperties.java

里面注明約定配置的值

 

2,運用spring的自動裝配功能

運用@ConfigurationProperties標簽進行自動裝配。這個所有基本功能不細說。

詳細可查看ZuulProperties里。

好處在於:

1, 可以實現動態配置,如 配置 map,list,甚至enums等

2,如果配合spring cloud config,可以實現動態熱更新

 

四,統一管理JAR包的依賴

參考spring cloud/boot 里,JAR文件統一在spring-boot-dependencies的項目里單獨管理,而版本間的兼容,依靠了開源項目http://platform.spring.io/platform/ 來做管理,故很少存在版本沖突。

作為自研的組件,最好依賴到的第三方jar都由spring boot去同理管理版本號,而需要用到的其它jar,可用建立個dependencies項目單獨管理起來,不再自己工程能寫版本號,方便統一升級維護。

 

 

總結下:

1,  如何給spring /spring boot 項目提供組件會比較好

用SPI方式,方便平滑引用

2,如何避免不需要用到組件的項目誤引用JAR后,自動啟動組件相關資源

1, 提供@EnableXXX標簽模式,注入一個marker標簽,在啟動時通過@ConditionalOnBean來判斷

2,starter方式,配置與類分開,@ConditionalOnBean來判斷,同時引用時才啟動會

3,組件的配置如何統一管理

1, 約定大於配置,簡化配置。 為每個組件統一一個組件的XXXProperties.java,並提供約定值

2,自動裝配模式

4, 如何統一管理JAR包,防止JAR版本沖突等

交給spring boot統一管理,其它版本號統一在父工程(或加入dependencies工程) 管理版本

 

 

加個廣告,新的一年,打算把公眾號維護起來,質量做起來。

歡迎關注下,謝謝


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM