java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > springcloud gateway集成apollo后动态刷新路由

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\目录存在,且应用有读写权限。

2、要在本地目录下设置连接apollo环境变量。

在下面的目录下面,建立一个server.properties文件

文件内容如下:(DEV是SpringColoud 要连接的 apollo 配置 )

env=DEV

3、如果使用 apollo 自带的 eureka 。

那么发布到 apollo 的yml文件需要指定配置(eureka注意不能省略)

eureka.client.service-url.defaultZone	http://【apollo所在的ip】:8080/eureka

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文