欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

apollo與springboot集成實(shí)現(xiàn)動(dòng)態(tài)刷新配置的教程詳解

 更新時(shí)間:2020年06月07日 10:53:26   作者:Linyb極客之路  
這篇文章主要介紹了apollo與springboot集成實(shí)現(xiàn)動(dòng)態(tài)刷新配置,本文分步驟給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

分布式apollo簡(jiǎn)介

Apollo(阿波羅)是攜程框架部門研發(fā)的開源配置管理中心,能夠集中化管理應(yīng)用不同環(huán)境、不同集群的配置,配置修改后能夠?qū)崟r(shí)推送到應(yīng)用端,并且具備規(guī)范的權(quán)限、流程治理等特性。

本文主要介紹如何使用apollo與springboot實(shí)現(xiàn)動(dòng)態(tài)刷新配置,如果之前不了解apollo可以查看如下文檔

https://github.com/ctripcorp/apollo

學(xué)習(xí)了解一下apollo,再來查看本文

正文

apollo與spring實(shí)現(xiàn)動(dòng)態(tài)刷新配置本文主要演示2種刷新,一種基于普通字段刷新、一種基于bean上使用了@ConfigurationProperties刷新

1、普通字段刷新

a、pom.xml配置

 <dependency>
  <groupId>com.ctrip.framework.apollo</groupId>
  <artifactId>apollo-client</artifactId>
  <version>1.6.0</version>
 </dependency>

b、客戶端配置AppId,Apollo Meta Server

此配置有多種方法,本示例直接在application.yml配置,配置內(nèi)容如下

app:
  id: ${spring.application.name}
apollo:
  meta: http://192.168.88.128:8080,http://192.168.88.129:8080
  bootstrap:
    enabled: true
    eagerLoad:
      enabled: true

c、項(xiàng)目中啟動(dòng)類上加上@EnableApolloConfig注解,形如下

@SpringBootApplication
@EnableApolloConfig(value = {"application","user.properties","product.properties","order.properties"})
public class ApolloApplication {

	public static void main(String[] args) {

		SpringApplication.run(ApolloApplication.class, args);
	}

}

@EnableApolloConfig不一定要加在啟動(dòng)類上,加在被spring管理的類上即可

d、在需刷新的字段上配置@Value注解,形如

 @Value("${hello}")
 private String hello;

通過以上三步就可以實(shí)現(xiàn)普通字段的動(dòng)態(tài)刷新

2.bean使用@ConfigurationProperties動(dòng)態(tài)刷新

bean使用@ConfigurationProperties注解目前還不支持自動(dòng)刷新,得編寫一定的代碼實(shí)現(xiàn)刷新。目前官方提供2種刷新方案

  • 基于RefreshScope實(shí)現(xiàn)刷新
  • 基于EnvironmentChangeEvent實(shí)現(xiàn)刷新
  • 本文再提供一種,當(dāng)bean上如果使用了@ConditionalOnProperty如何實(shí)現(xiàn)刷新

a、基于RefreshScope實(shí)現(xiàn)刷新

1、pom.xml要額外引入

 <dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-context</artifactId>
  <version>2.0.3.RELEASE</version>
 </dependency>

2、bean上使用@RefreshScope注解

@Component
@ConfigurationProperties(prefix = "product")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@RefreshScope
public class Product {

 private Long id;

 private String productName;

 private BigDecimal price;

}

3、利用RefreshScope搭配@ApolloConfigChangeListener監(jiān)聽實(shí)現(xiàn)bean的動(dòng)態(tài)刷新,其代碼實(shí)現(xiàn)如下

@ApolloConfigChangeListener(value="product.properties",interestedKeyPrefixes = {"product."})
 private void refresh(ConfigChangeEvent changeEvent){

 refreshScope.refresh("product");

 PrintChangeKeyUtils.printChange(changeEvent);
 }

b、基于EnvironmentChangeEvent實(shí)現(xiàn)刷新

利用spring的事件驅(qū)動(dòng)配合@ApolloConfigChangeListener監(jiān)聽實(shí)現(xiàn)bean的動(dòng)態(tài)刷新,其代碼如下

@Component
@Slf4j
public class UserPropertiesRefresh implements ApplicationContextAware {

 private ApplicationContext applicationContext;

 @ApolloConfigChangeListener(value="user.properties",interestedKeyPrefixes = {"user."})
 private void refresh(ConfigChangeEvent changeEvent){
 applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));

 PrintChangeKeyUtils.printChange(changeEvent);
 }

 @Override
 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
 this.applicationContext = applicationContext;
 }
}

c、當(dāng)bean上有@ConditionalOnProperty如何實(shí)現(xiàn)刷新

當(dāng)bean上有@ConditionalOnProperty注解時(shí),上述的兩種方案可以說失效了,因?yàn)锧ConditionalOnProperty是一個(gè)條件注解,當(dāng)不滿足條件注解時(shí),bean是沒法注冊(cè)到spring容器中的。如果我們要實(shí)現(xiàn)此種情況的下的動(dòng)態(tài)刷新,我們就得自己手動(dòng)注冊(cè)或者銷毀bean了。其實(shí)現(xiàn)流程如下

1、當(dāng)滿足條件注解時(shí),則手動(dòng)創(chuàng)建bean,然后配合@ApolloConfigChangeListener監(jiān)聽該bean的屬性變化。當(dāng)該bean屬性有變化時(shí),手動(dòng)把屬性注入bean。同時(shí)刷新依賴該bean的其他bean

2、當(dāng)不滿足條件注解時(shí),則手動(dòng)從spring容器中移除bean,同時(shí)刷新依賴該bean的其他bean

其刷新核心代碼如下

public class OrderPropertiesRefresh implements ApplicationContextAware {

 private ApplicationContext applicationContext;

 @ApolloConfig(value = "order.properties")
 private Config config;

 @ApolloConfigChangeListener(value="order.properties",interestedKeyPrefixes = {"order."},interestedKeys = {"model.isShowOrder"})
 private void refresh(ConfigChangeEvent changeEvent){
 for (String basePackage : listBasePackages()) {
  Set<Class> conditionalClasses = ClassScannerUtils.scan(basePackage, ConditionalOnProperty.class);
  if(!CollectionUtils.isEmpty(conditionalClasses)){
  for (Class conditionalClass : conditionalClasses) {
   ConditionalOnProperty conditionalOnProperty = (ConditionalOnProperty) conditionalClass.getAnnotation(ConditionalOnProperty.class);
   String[] conditionalOnPropertyKeys = conditionalOnProperty.name();
   String beanChangeCondition = this.getChangeKey(changeEvent,conditionalOnPropertyKeys);
   String conditionalOnPropertyValue = conditionalOnProperty.havingValue();
   boolean isChangeBean = this.changeBean(conditionalClass, beanChangeCondition, conditionalOnPropertyValue);
   if(!isChangeBean){
   // 更新相應(yīng)的bean的屬性值,主要是存在@ConfigurationProperties注解的bean
   applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
   }
  }
  }
 }

 PrintChangeKeyUtils.printChange(changeEvent);
 printAllBeans();
 }

 /**
 * 根據(jù)條件對(duì)bean進(jìn)行注冊(cè)或者移除
 * @param conditionalClass
 * @param beanChangeCondition bean發(fā)生改變的條件
 * @param conditionalOnPropertyValue
 */
 private boolean changeBean(Class conditionalClass, String beanChangeCondition, String conditionalOnPropertyValue) {
 boolean isNeedRegisterBeanIfKeyChange = this.isNeedRegisterBeanIfKeyChange(beanChangeCondition,conditionalOnPropertyValue);
 boolean isNeedRemoveBeanIfKeyChange = this.isNeedRemoveBeanIfKeyChange(beanChangeCondition,conditionalOnPropertyValue);
 String beanName = StringUtils.uncapitalize(conditionalClass.getSimpleName());
 if(isNeedRegisterBeanIfKeyChange){
  boolean isAlreadyRegisterBean = this.isExistBean(beanName);
  if(!isAlreadyRegisterBean){
  this.registerBean(beanName,conditionalClass);
  return true;
  }
 }else if(isNeedRemoveBeanIfKeyChange){
  this.unregisterBean(beanName);
  return true;
 }
 return false;
 }

 /**
 * bean注冊(cè)
 * @param beanName
 * @param beanClass
 */
 public void registerBean(String beanName,Class beanClass) {
 log.info("registerBean->beanName:{},beanClass:{}",beanName,beanClass);
 BeanDefinitionBuilder beanDefinitionBurinilder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
 BeanDefinition beanDefinition = beanDefinitionBurinilder.getBeanDefinition();
 setBeanField(beanClass, beanDefinition);
 getBeanDefinitionRegistry().registerBeanDefinition(beanName,beanDefinition);

 }

 /**
 * 設(shè)置bean字段值
 * @param beanClass
 * @param beanDefinition
 */
 private void setBeanField(Class beanClass, BeanDefinition beanDefinition) {
 ConfigurationProperties configurationProperties = (ConfigurationProperties) beanClass.getAnnotation(ConfigurationProperties.class);
 if(ObjectUtils.isNotEmpty(configurationProperties)){
  String prefix = configurationProperties.prefix();
  for (String propertyName : config.getPropertyNames()) {
  String fieldPrefix = prefix + ".";
  if(propertyName.startsWith(fieldPrefix)){
   String fieldName = propertyName.substring(fieldPrefix.length());
   String fieldVal = config.getProperty(propertyName,null);
   log.info("setBeanField-->fieldName:{},fieldVal:{}",fieldName,fieldVal);
   beanDefinition.getPropertyValues().add(fieldName,fieldVal);
  }
  }
 }
 }

 /**
 * bean移除
 * @param beanName
 */
 public void unregisterBean(String beanName){
 log.info("unregisterBean->beanName:{}",beanName);
 getBeanDefinitionRegistry().removeBeanDefinition(beanName);
 }

 public <T> T getBean(String name) {
 return (T) applicationContext.getBean(name);
 }

 public <T> T getBean(Class<T> clz) {
 return (T) applicationContext.getBean(clz);
 }

 public boolean isExistBean(String beanName){
 return applicationContext.containsBean(beanName);
 }

 public boolean isExistBean(Class clz){
 try {
  Object bean = applicationContext.getBean(clz);
  return true;
 } catch (BeansException e) {
  // log.error(e.getMessage(),e);
 }
 return false;
 }

 private boolean isNeedRegisterBeanIfKeyChange(String changeKey,String conditionalOnPropertyValue){
 if(StringUtils.isEmpty(changeKey)){
  return false;
 }
 String apolloConfigValue = config.getProperty(changeKey,null);
 return conditionalOnPropertyValue.equals(apolloConfigValue);
 }

 private boolean isNeedRemoveBeanIfKeyChange(String changeKey,String conditionalOnPropertyValue){
 if(!StringUtils.isEmpty(changeKey)){
  String apolloConfigValue = config.getProperty(changeKey,null);
  return !conditionalOnPropertyValue.equals(apolloConfigValue);
 }

 return false;

 }

 private boolean isChangeKey(ConfigChangeEvent changeEvent,String conditionalOnPropertyKey){
 Set<String> changeKeys = changeEvent.changedKeys();
 if(!CollectionUtils.isEmpty(changeKeys) && changeKeys.contains(conditionalOnPropertyKey)){
  return true;
 }
 return false;
 }

 private String getChangeKey(ConfigChangeEvent changeEvent, String[] conditionalOnPropertyKeys){
 if(ArrayUtils.isEmpty(conditionalOnPropertyKeys)){
  return null;
 }
 String changeKey = null;
 for (String conditionalOnPropertyKey : conditionalOnPropertyKeys) {
  if(isChangeKey(changeEvent,conditionalOnPropertyKey)){
  changeKey = conditionalOnPropertyKey;
  break;
  }
 }

 return changeKey;
 }

 private BeanDefinitionRegistry getBeanDefinitionRegistry(){
 ConfigurableApplicationContext configurableContext = (ConfigurableApplicationContext) applicationContext;
 BeanDefinitionRegistry beanDefinitionRegistry = (DefaultListableBeanFactory) configurableContext.getBeanFactory();
 return beanDefinitionRegistry;
 }

 private List<String> listBasePackages(){
 ConfigurableApplicationContext configurableContext = (ConfigurableApplicationContext) applicationContext;
 return AutoConfigurationPackages.get(configurableContext.getBeanFactory());
 }

 @Override
 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
 this.applicationContext = applicationContext;
 }

 public void printAllBeans() {
 String[] beans = applicationContext.getBeanDefinitionNames();
 Arrays.sort(beans);
 for (String beanName : beans) {
  Class<?> beanType = applicationContext.getType(beanName);
  System.out.println(beanType);
 }
 }
}

如果條件注解的值也是配置在apollo上,可能會(huì)出現(xiàn)依賴條件注解的bean的其他bean,在項(xiàng)目拉取apollo配置時(shí),就已經(jīng)注入spring容器中,此時(shí)就算條件注解滿足條件,則引用該條件注解bean的其他bean,也會(huì)拿不到條件注解bean。此時(shí)有2種方法解決,一種是在依賴條件注解bean的其他bean注入之前,先手動(dòng)注冊(cè)條件注解bean到spring容器中,其核心代碼如下

@Component
@Slf4j
public class RefreshBeanFactory implements BeanFactoryPostProcessor {

 @Override
 public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
 Config config = ConfigService.getConfig("order.properties");
 List<String> basePackages = AutoConfigurationPackages.get(configurableListableBeanFactory);
 for (String basePackage : basePackages) {
  Set<Class> conditionalClasses = ClassScannerUtils.scan(basePackage, ConditionalOnProperty.class);
  if(!CollectionUtils.isEmpty(conditionalClasses)){
  for (Class conditionalClass : conditionalClasses) {
   ConditionalOnProperty conditionalOnProperty = (ConditionalOnProperty) conditionalClass.getAnnotation(ConditionalOnProperty.class);
   String[] conditionalOnPropertyKeys = conditionalOnProperty.name();
   String beanConditionKey = this.getConditionalOnPropertyKey(config,conditionalOnPropertyKeys);
   String conditionalOnPropertyValue = conditionalOnProperty.havingValue();
   this.registerBeanIfMatchCondition((DefaultListableBeanFactory)configurableListableBeanFactory,config,conditionalClass,beanConditionKey,conditionalOnPropertyValue);
  }
  }
 }

 }

 private void registerBeanIfMatchCondition(DefaultListableBeanFactory beanFactory,Config config,Class conditionalClass, String beanConditionKey, String conditionalOnPropertyValue) {
 boolean isNeedRegisterBean = this.isNeedRegisterBean(config,beanConditionKey,conditionalOnPropertyValue);
 String beanName = StringUtils.uncapitalize(conditionalClass.getSimpleName());
 if(isNeedRegisterBean){
  this.registerBean(config,beanFactory,beanName,conditionalClass);

 }

 }

 public void registerBean(Config config,DefaultListableBeanFactory beanFactory, String beanName, Class beanClass) {
 log.info("registerBean->beanName:{},beanClass:{}",beanName,beanClass);
 BeanDefinitionBuilder beanDefinitionBurinilder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
 BeanDefinition beanDefinition = beanDefinitionBurinilder.getBeanDefinition();
 setBeanField(config,beanClass, beanDefinition);
 beanFactory.registerBeanDefinition(beanName,beanDefinition);

 }

 private void setBeanField(Config config,Class beanClass, BeanDefinition beanDefinition) {
 ConfigurationProperties configurationProperties = (ConfigurationProperties) beanClass.getAnnotation(ConfigurationProperties.class);
 if(ObjectUtils.isNotEmpty(configurationProperties)){
  String prefix = configurationProperties.prefix();
  for (String propertyName : config.getPropertyNames()) {
  String fieldPrefix = prefix + ".";
  if(propertyName.startsWith(fieldPrefix)){
   String fieldName = propertyName.substring(fieldPrefix.length());
   String fieldVal = config.getProperty(propertyName,null);
   log.info("setBeanField-->fieldName:{},fieldVal:{}",fieldName,fieldVal);
   beanDefinition.getPropertyValues().add(fieldName,fieldVal);
  }
  }
 }
 }

 public boolean isNeedRegisterBean(Config config,String beanConditionKey,String conditionalOnPropertyValue){
 if(StringUtils.isEmpty(beanConditionKey)){
  return false;
 }
 String apolloConfigValue = config.getProperty(beanConditionKey,null);
 return conditionalOnPropertyValue.equals(apolloConfigValue);
 }

 private String getConditionalOnPropertyKey(Config config, String[] conditionalOnPropertyKeys){
 if(ArrayUtils.isEmpty(conditionalOnPropertyKeys)){
  return null;
 }
 String changeKey = null;
 for (String conditionalOnPropertyKey : conditionalOnPropertyKeys) {
  if(isConditionalOnPropertyKey(config,conditionalOnPropertyKey)){
  changeKey = conditionalOnPropertyKey;
  break;
  }
 }

 return changeKey;
 }
 private boolean isConditionalOnPropertyKey(Config config,String conditionalOnPropertyKey){
 Set<String> propertyNames = config.getPropertyNames();
 if(!CollectionUtils.isEmpty(propertyNames) && propertyNames.contains(conditionalOnPropertyKey)){
  return true;
 }
 return false;
 }
}

其次利用懶加載的思想,在使用條件注解bean時(shí),使用形如下方法

Order order = (Order) 
SpringContextUtils.getBean("order");

總結(jié)

本文主要介紹了常用的動(dòng)態(tài)刷新,但本文的代碼示例實(shí)現(xiàn)的功能不局限于此,本文的代碼還實(shí)現(xiàn)如何通過自定義注解與apollo整合來實(shí)現(xiàn)一些業(yè)務(wù)操作,同時(shí)也實(shí)現(xiàn)了基于hystrix注解與apollo整合,實(shí)現(xiàn)基于線程隔離的動(dòng)態(tài)熔斷,感興趣的朋友可以復(fù)制文末鏈接到瀏覽器,進(jìn)行查看

apollo基本上是能滿足我們?nèi)粘5臉I(yè)務(wù)開發(fā)要求,但是對(duì)于一些需求,比如動(dòng)態(tài)刷新線上數(shù)據(jù)庫資源啥,我們還是得做一定的量的改造,好在攜程也提供了apollo-use-cases,在里面可以找到常用的使用場(chǎng)景以及示例代碼,其鏈接如下

https://github.com/ctripcorp/apollo-use-cases

感興趣的朋友,可以查看下。

demo鏈接

https://github.com/lyb-geek/springboot-learning/tree/master/springboot-apollo

到此這篇關(guān)于apollo與springboot集成實(shí)現(xiàn)動(dòng)態(tài)刷新配置的文章就介紹到這了,更多相關(guān)apollo與springboot集成動(dòng)態(tài)刷新配置內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java并發(fā)學(xué)習(xí)-CountDownLatch實(shí)現(xiàn)原理全面講解

    java并發(fā)學(xué)習(xí)-CountDownLatch實(shí)現(xiàn)原理全面講解

    這篇文章主要介紹了java并發(fā)學(xué)習(xí)-CountDownLatch實(shí)現(xiàn)原理全面講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java中的注解、元注解詳細(xì)解析

    Java中的注解、元注解詳細(xì)解析

    這篇文章主要介紹了Java中的注解、元注解詳細(xì)解析,注解也叫元數(shù)據(jù),與類、接口、枚舉是在同一個(gè)層次,它可以聲明在包、類、字段、方法、局部變量、方法參數(shù)等的前面,用來對(duì)這些元素進(jìn)行說明,注釋,需要的朋友可以參考下
    2023-11-11
  • Mybatis中連接查詢和嵌套查詢實(shí)例代碼

    Mybatis中連接查詢和嵌套查詢實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于Mybatis中連接查詢和嵌套查詢的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Java可重入鎖的實(shí)現(xiàn)原理與應(yīng)用場(chǎng)景

    Java可重入鎖的實(shí)現(xiàn)原理與應(yīng)用場(chǎng)景

    今天小編就為大家分享一篇關(guān)于Java可重入鎖的實(shí)現(xiàn)原理與應(yīng)用場(chǎng)景,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • SpringMVC圖片文件跨服務(wù)器上傳

    SpringMVC圖片文件跨服務(wù)器上傳

    這篇文章主要為大家詳細(xì)介紹了SpringMVC圖片文件跨服務(wù)器上傳,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • Java中關(guān)于isEmpty方法、null以及““的區(qū)別

    Java中關(guān)于isEmpty方法、null以及““的區(qū)別

    這篇文章主要介紹了Java中關(guān)于isEmpty方法、null以及““的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 盤點(diǎn)Java中延時(shí)任務(wù)的多種實(shí)現(xiàn)方式

    盤點(diǎn)Java中延時(shí)任務(wù)的多種實(shí)現(xiàn)方式

    當(dāng)需要一個(gè)定時(shí)發(fā)布系統(tǒng)通告的功能,如何實(shí)現(xiàn)??當(dāng)支付超時(shí),訂單自動(dòng)取消,如何實(shí)現(xiàn)?其實(shí)這些問題本質(zhì)都是延時(shí)任務(wù)的實(shí)現(xiàn),本文為大家盤點(diǎn)了多種常見的延時(shí)任務(wù)實(shí)現(xiàn)方法,希望對(duì)大家有所幫助
    2022-12-12
  • Java迭代器遍歷list的方法及代碼分析

    Java迭代器遍歷list的方法及代碼分析

    在本篇內(nèi)容里系小編給大家分享的是一篇關(guān)于Java迭代器遍歷list的方法總結(jié)內(nèi)容,有需要的朋友們可以參考學(xué)習(xí)下。
    2022-11-11
  • Java基礎(chǔ)之引用相關(guān)知識(shí)總結(jié)

    Java基礎(chǔ)之引用相關(guān)知識(shí)總結(jié)

    今天聊聊Java的引用,大多數(shù)時(shí)候我們說引用都是強(qiáng)引用,只有在對(duì)象不使用的情況下才會(huì)釋放內(nèi)存,其實(shí)Java 內(nèi)存有四種不同的引用.一起看看吧,,需要的朋友可以參考下
    2021-05-05
  • 面試題:Java 實(shí)現(xiàn)查找旋轉(zhuǎn)數(shù)組的最小數(shù)字

    面試題:Java 實(shí)現(xiàn)查找旋轉(zhuǎn)數(shù)組的最小數(shù)字

    這篇文章主要介紹了Java 實(shí)現(xiàn)查找旋轉(zhuǎn)數(shù)組的最小數(shù)字,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-07-07

最新評(píng)論