前情提要:在追一个讲spring cloud的课,讲到zuul动态路由的时候,老师只是大概说了说思路,没有具体讲细节,于是我自己搞了一下,实现一个非常简陋的zuul动态路由。大概从凌晨十二点多搞到凌晨三点多的样子,简要记录一下。
zuul是干嘛用的:个人理解就是个类似拦截器+过滤器的作用,设置一个路由表,对不同的请求,将其转发到不同的微服务进行处理。
什么是动态路由:个人理解就是不用重启了,改完路由配置直接生效。
项目结构:
pom文件结构如下:
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wmx</groupId>
<artifactId>api-gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>api-gateway</name>
<description>Demo project for Spring Boot</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- config依赖,动态路由用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<!-- bus自动刷新配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
zuul的配置文件是放在我的github上了,由统一配置中心进行加载,github部分配置如下:
统一配置中心这边就不说了
我这个zuul配置文件,自己定义了一个路由规则,/myProduct/**匹配的所有请求都会被转发到product这个微服务上。ignored-patterns的配置表示排除某些接口,这些被排除的接口不能被外部请求所访问到,会报404。
如何配置zuul动态路由,首先获取配置文件被修改之后新的属性:
@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
//动态路由配置,即自动刷新zuul配置
@ConfigurationProperties("zuul")
@RefreshScope
public ZuulProperties zuulProperties(){
return new ZuulProperties();
}
}
zuul已经封装好了一个对象ZuulProperties,这样每次spring bus配置自动刷新之后,就会把新的配置属性存入这个对象中。
然后将ZuulProperties对象里的属性值读出来,进行路由表的配置:
public class ZuulRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
public ZuulRouteLocator(String servletPath, ZuulProperties properties) {
super(servletPath, properties);
}
//刷新路由
@Override
public void refresh() {
doRefresh();
}
}
这里需要注意一点,我写的是最最简单的动态路由配置,直接调用父类默认的方法就行了。像我参考的那篇博客,他的路由规则是存在数据库里的,这时候就需要自己重新覆盖一个locateRoutes()方法,把路由规则从数据库读出来,配到一个map对象中,有需要的可以参考那一篇。
接下来将ZuulRouteLocator配置成bean,供最后一步用:
@Configuration
public class CustomZuulConfig {
@Autowired
ZuulProperties zuulProperties;
@Bean
public ZuulRouteLocator routeLocator() {
ZuulRouteLocator routeLocator = new ZuulRouteLocator(null, this.zuulProperties);
return routeLocator;
}
}
最后配置路由刷新监听事件,这样就可以把新的路由规则配置生效了:
@Service
public class RefreshRouteService {
@Autowired
ApplicationEventPublisher publisher;
@Autowired
RouteLocator routeLocator;
public void refreshRoute() {
RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(routeLocator);
publisher.publishEvent(routesRefreshedEvent);
}
}
启动eureka,config,zuul和微服务进行测试。
一开始的配置文件中,/**/product/listForOrder的请求都会被拦住,返回404。
修改配置文件,把拦截请求换成另一个,然后用postman发一个/actuator/bus-refresh的POST请求(webhook自动刷新在我这里有问题,还需要再查),注意请求头里要加Content-Type:application/json这个属性,配置文件自动更新之后,zuul的项目就会监听到事件从而自动刷新路由表,新的路由规则就生效了。
具体图我就不截了。。。
参考博客:https://blog.youkuaiyun.com/u013815546/article/details/68944039
感谢大佬