静态配置
server.port=8006
spring.application.name=api-gateway
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8001/eureka/
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.service-id=consumer-client-ribbon
在路由器中创建路由信息表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_zuul_route
-- ----------------------------
DROP TABLE IF EXISTS `sys_zuul_route`;
CREATE TABLE `sys_zuul_route` (
`id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`path` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`service_id` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`url` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`retryable` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL,
`enabled` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
定义CustomRouteLocator类
CustomRouteLocator集成SimpleRouteLocator,实现了RefreshableRouteLocator接口
package com.feifei.cloud.config;
import com.feifei.cloud.dto.ZuulRouteVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
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.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.StringUtils;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author xupf@wangreat.com
* @create 2019-06-11 14:18
*/
public class CustomRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private ZuulProperties properties;
private JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public ZuulProperties getProperties() {
return properties;
}
public void setProperties(ZuulProperties properties) {
this.properties = properties;
}
public CustomRouteLocator(String servletPath, ZuulProperties properties) {
super(servletPath, properties);
this.properties = properties;
logger.debug("servletPath:{}" + servletPath);
}
@Override
public void refresh() {
doRefresh();
}
@Override
protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {
LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<String, ZuulProperties.ZuulRoute>();
routesMap.putAll(super.locateRoutes());
routesMap.putAll(locateRoutesDb());
LinkedHashMap<String, ZuulProperties.ZuulRoute> values = new LinkedHashMap<>();
for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : routesMap.entrySet()) {
String path = entry.getKey();
// Prepend with slash if not already present.
if (!path.startsWith("/")) {
path = "/" + path;
}
if (StringUtils.hasText(this.properties.getPrefix())) {
path = this.properties.getPrefix() + path;
if (!path.startsWith("/")) {
path = "/" + path;
}
}
values.put(path, entry.getValue());
}
return values;
}
public Map<String, ZuulProperties.ZuulRoute> locateRoutesDb(){
Map<String, ZuulProperties.ZuulRoute> routes = new LinkedHashMap<>();
List<ZuulRouteVO> results = jdbcTemplate.query("select * from sys_zuul_route where enabled = 'true'", new BeanPropertyRowMapper<>(ZuulRouteVO.class));
for (ZuulRouteVO zuulRouteVO: results) {
ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();
BeanUtils.copyProperties(zuulRouteVO, zuulRoute);
routes.put(zuulRoute.getPath(), zuulRoute);
}
return routes;
}
}
主要的是locateRoutes和locateRoutesFromDB这两个函数,locateRoutes是从SimpleRouteLocator Override过来的,先装载配置文件里面的路由信息,在从数据库里面获取路由信息,最后都是保存在SimpleRoteLocator 的AtomicReference<Map<String, ZuulRoute>> routes属性中,注意routes是类型,它是可以保证线程俺去的。
增加CustomZuulConfig类,主要是为了配置CustomRouteLocator
package com.feifei.cloud.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* @author xupf@wangreat.com
* @create 2019-06-11 14:24
*/
@Configuration
public class CustomZuulConfig {
@Autowired
private ZuulProperties zuulProperties;
@Autowired
private ServerProperties server;
@Autowired
private JdbcTemplate jdbcTemplate;
@Bean
public CustomRouteLocator customRouteLocator(){
CustomRouteLocator customRouteLocator = new CustomRouteLocator(this.server.getServletPrefix(), this.zuulProperties);
customRouteLocator.setJdbcTemplate(jdbcTemplate);
return customRouteLocator;
}
}
CustomerRouteLocator 去数据库获取路由配置信息,需要一个JdbcTemplate Bean。this.zuulProperties 就是配置文件里面的路由配置,应该是网关服务启动时自动就获取过来的
RefreshRouteService类,用于实现数据库路由信息的刷新
package com.feifei.cloud.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.RoutesRefreshedEvent;
import org.springframework.cloud.netflix.zuul.filters.RouteLocator;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
/**
* @author xupf@wangreat.com
* @create 2019-06-12 11:38
*/
@Service
public class RefreshRouteService {
@Autowired
ApplicationEventPublisher publisher;
@Autowired
RouteLocator routeLocator;
public void refreshRoute() {
RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(routeLocator);
publisher.publishEvent(routesRefreshedEvent);
}
}
创建实体类
package com.feifei.cloud.dto;
/**
* @author xupf@wangreat.com
* @create 2019-06-12 11:28
*/
public class ZuulRouteVO {
private String id;
private String path;
private String serviceId;
private String url;
private boolean stripPrefix = true;
private Boolean retryable;
private Boolean enabled;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getServiceId() {
return serviceId;
}
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public boolean isStripPrefix() {
return stripPrefix;
}
public void setStripPrefix(boolean stripPrefix) {
this.stripPrefix = stripPrefix;
}
public Boolean getRetryable() {
return retryable;
}
public void setRetryable(Boolean retryable) {
this.retryable = retryable;
}
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
}