和spring cloud/boot 學習如何管理本身的組件

案例,java

功能:web

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

 

當組建啓動時,須要創建以下資源:spring

1, 和kafka創建若干條鏈接bootstrap

2, 啓動一個線程池app

3, 啓動上報一個緩衝區ide

 

問題以下:

 

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

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

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

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工程) 管理版本

 

 

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

歡迎關注下,謝謝

相關文章
相關標籤/搜索