springcloud gateway高级功能之集成apollo后动态刷新路由方式
作者:lipengxs
这篇文章主要介绍了springcloud gateway高级功能之集成apollo后动态刷新路由方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
springcloud gateway集成apollo后动态刷新路由
springcloud集成apollo后动态刷新路由配置
官网给的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.前缀的配置项全部删除(例如需要动态删除最后一个路由的场景),initializeBean时也无法创建新的bean,则return当前bean * 若仍保留有spring.cloud.gateway.routes[n]或spring.cloud.gateway.default-filters[n]等配置,initializeBean时会注入新的属性替换已有的bean * 这个方法提供了类似@PreDestroy的操作,根据配置文件的实际情况把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!"); } /*** * 根据changeEvent和定义的pattern匹配key,如果所有对应PropertyChangeType为DELETED则需要清空GatewayProperties里相关集合 * * @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应用程序所在的pc):/opt/data
本地缓存路径默认位于以下路径,所以请确保/opt/data或C:\opt\data\目录存在,且应用有读写权限。
- Mac/Linux: /opt/data/{appId}/config-cache
- Windows: C:\opt\data{appId}\config-cache
2、要在本地目录下设置连接apollo环境变量。
在下面的目录下面,建立一个server.properties文件
- Mac/Linux: /opt/settings
- Windows: C:\opt\settings
文件内容如下:(DEV是SpringColoud 要连接的 apollo 配置 )
env=DEV
3、如果使用 apollo 自带的 eureka 。
那么发布到 apollo 的yml文件需要指定配置(eureka注意不能省略)
eureka.client.service-url.defaultZone http://【apollo所在的ip】:8080/eureka
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。