springcloud?gateway高級功能之集成apollo后動態(tài)刷新路由方式
springcloud gateway集成apollo后動態(tài)刷新路由
springcloud集成apollo后動態(tài)刷新路由配置
官網(wǎng)給的demo如下
import com.ctrip.framework.apollo.enums.PropertyChangeType;
import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
/**
* @author ksewen
* @date 2019/5/175:24 PM
*/
@Configuration
public class GatewayPropertiesRefresher implements ApplicationContextAware,ApplicationEventPublisherAware {
private static final Logger logger = LoggerFactory.getLogger(GatewayPropertiesRefresher.class);
private static final String ID_PATTERN = "spring\\.cloud\\.gateway\\.routes\\[\\d+\\]\\.id";
private static final String DEFAULT_FILTER_PATTERN = "spring\\.cloud\\.gateway\\.default-filters\\[\\d+\\]\\.name";
private ApplicationContext applicationContext;
private ApplicationEventPublisher publisher;
@Autowired
private GatewayProperties gatewayProperties;
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
@ApolloConfigChangeListener(interestedKeyPrefixes = "spring.cloud.gateway.",value="recommend-facade.yml")
public void onChange(ConfigChangeEvent changeEvent) {
refreshGatewayProperties(changeEvent);
}
/***
* 刷新org.springframework.cloud.gateway.config.PropertiesRouteDefinitionLocator中定義的routes
*
* @param changeEvent
* @return void
* @author ksewen
* @date 2019/5/21 2:13 PM
*/
private void refreshGatewayProperties(ConfigChangeEvent changeEvent) {
logger.info("Refreshing GatewayProperties!");
preDestroyGatewayProperties(changeEvent);
this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
refreshGatewayRouteDefinition();
logger.info("GatewayProperties refreshed!");
}
/***
* GatewayProperties沒有@PreDestroy和destroy方法
* org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder#rebind(java.lang.String)中destroyBean時不會銷毀當前對象
* 如果把spring.cloud.gateway.前綴的配置項全部刪除(例如需要動態(tài)刪除最后一個路由的場景),initializeBean時也無法創(chuàng)建新的bean,則return當前bean
* 若仍保留有spring.cloud.gateway.routes[n]或spring.cloud.gateway.default-filters[n]等配置,initializeBean時會注入新的屬性替換已有的bean
* 這個方法提供了類似@PreDestroy的操作,根據(jù)配置文件的實際情況把org.springframework.cloud.gateway.config.GatewayProperties#routes
* 和org.springframework.cloud.gateway.config.GatewayProperties#defaultFilters兩個集合清空
*
* @param
* @return void
* @author ksewen
* @date 2019/5/21 2:13 PM
*/
private synchronized void preDestroyGatewayProperties(ConfigChangeEvent changeEvent) {
logger.info("Pre Destroy GatewayProperties!");
final boolean needClearRoutes = this.checkNeedClear(changeEvent, ID_PATTERN, this.gatewayProperties.getRoutes().size());
if (needClearRoutes) {
this.gatewayProperties.setRoutes(new ArrayList<>());
}
final boolean needClearDefaultFilters = this.checkNeedClear(changeEvent, DEFAULT_FILTER_PATTERN, this.gatewayProperties.getDefaultFilters().size());
if (needClearDefaultFilters) {
this.gatewayProperties.setRoutes(new ArrayList<>());
}
logger.info("Pre Destroy GatewayProperties finished!");
}
private void refreshGatewayRouteDefinition() {
logger.info("Refreshing Gateway RouteDefinition!");
this.publisher.publishEvent(new RefreshRoutesEvent(this));
logger.info("Gateway RouteDefinition refreshed!");
}
/***
* 根據(jù)changeEvent和定義的pattern匹配key,如果所有對應(yīng)PropertyChangeType為DELETED則需要清空GatewayProperties里相關(guān)集合
*
* @param changeEvent
* @param pattern
* @param existSize
* @return boolean
* @author ksewen
* @date 2019/5/23 2:18 PM
*/
private boolean checkNeedClear(ConfigChangeEvent changeEvent, String pattern, int existSize) {
return changeEvent.changedKeys().stream().filter(key -> key.matches(pattern))
.filter(key -> {
ConfigChange change = changeEvent.getChange(key);
return PropertyChangeType.DELETED.equals(change.getChangeType());
}).count() == existSize;
}
}這里有個坑
如果是沒有用到默認的application.properties,這里我們就需要填寫namespace了
如下,
需要配置value=“使用的namespace”
@ApolloConfigChangeListener(interestedKeyPrefixes = "spring.cloud.gateway.",value="xxxx.yml")
public void onChange(ConfigChangeEvent changeEvent) {
refreshGatewayProperties(changeEvent);
}springcloud集成apollo的注意事項
apollo的集成注意事項
1、建立本地緩存目錄(這里的本地指的是java應(yīng)用程序所在的pc):/opt/data
本地緩存路徑默認位于以下路徑,所以請確保/opt/data或C:\opt\data\目錄存在,且應(yīng)用有讀寫權(quán)限。
- Mac/Linux: /opt/data/{appId}/config-cache
- Windows: C:\opt\data{appId}\config-cache
2、要在本地目錄下設(shè)置連接apollo環(huán)境變量。
在下面的目錄下面,建立一個server.properties文件
- Mac/Linux: /opt/settings
- Windows: C:\opt\settings
文件內(nèi)容如下:(DEV是SpringColoud 要連接的 apollo 配置 )
env=DEV

3、如果使用 apollo 自帶的 eureka 。
那么發(fā)布到 apollo 的yml文件需要指定配置(eureka注意不能省略)
eureka.client.service-url.defaultZone http://【apollo所在的ip】:8080/eureka
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
JavaSwing GridLayout 網(wǎng)格布局的實現(xiàn)代碼
這篇文章主要介紹了JavaSwing GridLayout 網(wǎng)格布局的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-12-12
Java實現(xiàn)富文本轉(zhuǎn)markdown
這篇文章主要為大家詳細介紹了如何通過Java實現(xiàn)富文本轉(zhuǎn)markdown功能,文中的示例代碼講解詳細,具有一定的借鑒價值,有需要的小伙伴可以參考下2023-12-12
java實現(xiàn)消息隊列的兩種方式(小結(jié))
本文主要介紹了兩種java實現(xiàn)消息隊列的方式,利用Spring消息模板發(fā)送消息和Apache ActiveMQ官方實例發(fā)送消息,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-12-12
SpringBoot文件上傳控制及Java 獲取和判斷文件頭信息
這篇文章主要介紹了SpringBoot文件上傳控制的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-12-12
Spring Batch讀取txt文件并寫入數(shù)據(jù)庫的方法教程
這篇文章主要給大家介紹了Spring Batch讀取txt文件并寫入數(shù)據(jù)庫的方法,SpringBatch 是一個輕量級、全面的批處理框架。這里我們用它來實現(xiàn)文件的讀取并將讀取的結(jié)果作處理,處理之后再寫入數(shù)據(jù)庫中的功能。需要的朋友可以參考借鑒,下面來一起看看吧。2017-04-04
Apache Shrio安全框架實現(xiàn)原理及實例詳解
這篇文章主要介紹了Apache Shrio安全框架實現(xiàn)原理及實例詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-04-04

