Spring-Cloud-Zuul MySQL 实现动态路由以及手动刷新

介绍

实现zuul的动态路由可通过两种方式

  1. 基于配置中心实现配置文件动态刷新
  2. 基于数据库存储配置文件,发布RoutesRefreshedEvent事件,触发SimpleRouteLocator重新加载配置

代码参考:https://github.com/iyezhou/zuul-gateway-demo

实现步骤

数据库初始化

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE `zuul_route` (
`id` varchar(50) NOT NULL,
`path` varchar(255) NOT NULL,
`service_id` varchar(50) DEFAULT NULL,
`url` varchar(255) DEFAULT NULL,
`strip_prefix` tinyint(1) DEFAULT '1',
`retryable` tinyint(1) DEFAULT '0',
`enabled` tinyint(1) NOT NULL DEFAULT '1',
`description` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `zuul_route`(`id`,`path`,`service_id`,`url`,`strip_prefix`,`retryable`,`enabled`,`description`) values ('pppp','/client/**',NULL,'http://localhost:7070',1,0,1,'url');

配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server:
port: 8080
eureka:
client:
serviceUrl:
defaultZone: http://127.0.0.1:8000/eureka/ #注册中心地址
registry-fetch-interval-seconds: 15 #客户端拉取服务端的频率
spring:
application:
name: zuul
datasource:
url: jdbc:mysql://rm-bp1e5s5co.mysql.rds.aliyuncs.com:3306/zuul?useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.jdbc.Driver
username: rook
password: Hou5
ribbon:
eureka:
enabled: true

数据库访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ZuulRouteEntity {

private String id;

private String path;

private String serviceId;

private String url;

private boolean stripPrefix = true;

private Boolean retryable;

private Boolean enabled;

private String description;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
public class PropertiesDao {

@Autowired
private JdbcTemplate jdbcTemplate;

private final static String SQL = "SELECT * FROM zuul_route WHERE enabled = TRUE";

public Map<String, ZuulRoute> getProperties() {
Map<String, ZuulRoute> routes = new LinkedHashMap<>();
List<ZuulRouteEntity> list = jdbcTemplate.query(SQL, new BeanPropertyRowMapper<>(ZuulRouteEntity.class));
list.forEach(entity -> {
if (StringUtils.isEmpty(entity.getPath())) {
return;
}
ZuulRoute zuulRoute = new ZuulRoute();
BeanUtils.copyProperties(entity, zuulRoute);
routes.put(zuulRoute.getPath(), zuulRoute);
});
return routes;
}
}

重写理由配置加载方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
import org.springframework.util.StringUtils;

import java.util.LinkedHashMap;
import java.util.Map;

public class DynamicZuulRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

@Autowired
private ZuulProperties properties;

@Autowired
private PropertiesDao propertiesDao;

public DynamicZuulRouteLocator(String servletPath, ZuulProperties properties) {
super(servletPath, properties);
this.properties = properties;
}

@Override
public void refresh() {
doRefresh();
}

@Override
protected Map<String, ZuulRoute> locateRoutes() {
LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();
routesMap.putAll(super.locateRoutes());
routesMap.putAll(propertiesDao.getProperties());
LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
routesMap.forEach((key, value) -> {
String path = key;
if (!path.startsWith("/")) {
path = "/" + path;
}
if (StringUtils.hasText(this.properties.getPrefix())) {
path = this.properties.getPrefix() + path;
if (!path.startsWith("/")) {
path = "/" + path;
}
}
values.put(path, value);
});
return values;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
public class DynamicZuulConfig {

@Autowired
private ZuulProperties zuulProperties;

@Autowired
private ServerProperties serverProperties;

@Bean
public DynamicZuulRouteLocator routeLocator() {
DynamicZuulRouteLocator routeLocator = new DynamicZuulRouteLocator(
serverProperties.getServlet().getContextPath(), zuulProperties);
return routeLocator;
}
}

刷新接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RestController
public class RefreshController {
@Autowired
private ApplicationEventPublisher publisher;
@Autowired
private RouteLocator routeLocator;
@Autowired
private ZuulHandlerMapping zuulHandlerMapping;

@GetMapping("refreshRoute")
public String refreshRoute() {
RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(routeLocator);
publisher.publishEvent(routesRefreshedEvent);
return "refresh success";
}

@GetMapping("watchRoute")
public Object watchNowRoute() {
//可以用debug模式看里面具体是什么
return zuulHandlerMapping.getHandlerMap();
}
}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2021 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :