Commit d184ff1f by liyuan

网关代码提交

parent 85515b43
package com.byit.gateway; package com.byit.gateway;
import com.byit.rpc.remoting.provider.annotation.RpcService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
...@@ -15,6 +16,7 @@ import org.springframework.cloud.netflix.zuul.EnableZuulProxy; ...@@ -15,6 +16,7 @@ import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
* modified By * modified By
**/ **/
@EnableZuulProxy @EnableZuulProxy
@RpcService
@SpringBootApplication @SpringBootApplication
@Slf4j @Slf4j
public class GatewayApplication { public class GatewayApplication {
......
package com.byit.gateway.config;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter4;
import com.byit.gateway.interceptors.PerformanceInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.List;
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
private final Logger logger = LoggerFactory.getLogger(WebMvcConfiguration.class);
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new FastJsonHttpMessageConverter4());
}
/*
可以做登录拦截,访问权限拦截等
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
logger.info("添加拦截器");
registry.addInterceptor(new PerformanceInterceptor());
}
}
package com.byit.gateway.config;
import com.byit.gateway.zuul.ZuulRouteDatabaseLocator;
import com.byit.gateway.zuul.refresh.AutoRefreshRouteJob;
import com.byit.gateway.zuul.refresh.RefreshRouteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
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;
import javax.sql.DataSource;
/**
* @author liyuan
* create date on 2019-11-13 16:40
* description:
* <p></p>
* modified By
**/
@Configuration
public class ZuulConfig {
@Autowired
private DataSource dataSource;
@Autowired
private ZuulProperties zuulProperties;
@Autowired
private ServerProperties server;
@Bean
@ConditionalOnMissingBean(JdbcTemplate.class)
public JdbcTemplate jdbcTemplate(){
return new JdbcTemplate(dataSource);
}
@Bean
@ConditionalOnBean(JdbcTemplate.class)
@ConditionalOnMissingBean(ZuulRouteDatabaseLocator.class)
public ZuulRouteDatabaseLocator zuulRouteDatabaseLocator(){
ZuulProperties zuulProperties = new ZuulProperties();
return new ZuulRouteDatabaseLocator(server.getServletPrefix(), zuulProperties);
}
@Bean
public RefreshRouteService refreshRouteService(){
return new RefreshRouteService();
}
@Bean
public AutoRefreshRouteJob autoRefreshRouteJob(){
return new AutoRefreshRouteJob();
}
}
...@@ -39,7 +39,7 @@ public class ZuulRegistryConfig { ...@@ -39,7 +39,7 @@ public class ZuulRegistryConfig {
put(RegistryServiceRegistry.ENV, env); put(RegistryServiceRegistry.ENV, env);
}}); }});
log.info(">>>>>>>>>>>>>>> 向注册中心注册config初始化完成"); log.info(">>>>>>>>>>>>>>> byit-myth-gateway 向注册中心注册config初始化完成");
return providerFactory; return providerFactory;
} }
......
package com.byit.gateway.filters;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
* @author liyuan
* create date on 2019-11-14 14:34
* description:
* <p>
* 登陆过滤器
* </p>
* modified By
**/
@Component
@Slf4j
public class LoginFilter extends ZuulFilter {
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString()));
Object a = request.getParameter("a");
if(a != null) {
log.warn("param a is empty");
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
return false;
}
log.info("param a is : " + a);
return true;
}
}
package com.byit.gateway.interceptors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 过滤器
* 可以多写几个哦
*/
public class PerformanceInterceptor extends HandlerInterceptorAdapter {
private final Logger log = LoggerFactory.getLogger(PerformanceInterceptor.class);
private final String key = "timekey";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.setAttribute(key, System.currentTimeMillis());
request.setAttribute("basePath", "http://" + request.getServerName() + ":" + request.getServerPort() + "/");
return super.preHandle(request, response, handler);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info(request.getRequestURI() + " handle time millis : " + (System.currentTimeMillis() - (long) request.getAttribute(key)));
super.afterCompletion(request, response, handler, ex);
}
}
package com.byit.gateway.zuul;
import com.alibaba.fastjson.JSONArray;
import com.byit.rpc.remoting.invoker.route.LoadBalance;
import com.byit.rpc.remoting.invoker.route.RpcLoadBalance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties.ZuulRoute;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
/**
* @author liyuan
*/
public class ZuulRouteDatabaseLocator extends ZuulRouteLocator {
public final static Logger logger = LoggerFactory.getLogger(ZuulRouteDatabaseLocator.class);
@Autowired
private JdbcTemplate jdbcTemplate;
/**
* biz针对的是项目
*/
@Value("${myth-rpc.registry.biz}")
private String biz;
@Value("${gateway.load.balance}")
private String gatewayLoadBalance;
private List<ZuulRouteEntity> locateRouteList;
private RpcLoadBalance rpcLoadBalance;
public ZuulRouteDatabaseLocator(String servletPath, ZuulProperties properties) {
super(servletPath, properties);
}
@Override
public Map<String, ZuulRoute> loadLocateRoute() {
locateRouteList = new ArrayList<>();
try {
String sql = "select * from myth_registry where status = 0 and locate('.',`key`) = 0 and biz = '" + biz + "'";
List<Map<String, Object>> locateRouteMapList = jdbcTemplate.queryForList(sql);
logger.info(locateRouteMapList.toString());
if (!CollectionUtils.isEmpty(locateRouteMapList)) {
for (Map<String, Object> locateRouteMap : locateRouteMapList) {
ZuulRouteEntity zuulRouteEntity = new ZuulRouteEntity();
String serviceId = locateRouteMap.get("key").toString();
String addressStr = locateRouteMap.get("data").toString();
String address = this.loadBalance(serviceId, addressStr);
StringBuilder url = new StringBuilder();
url.append("http://");
url.append(address);
url.append("/");
url.append(serviceId);
//路由id匹配成服务id,表示一个服务对应一个路由
zuulRouteEntity.setId(serviceId);
zuulRouteEntity.setServiceId(serviceId);
zuulRouteEntity.setPath("/" + serviceId + "/**");
zuulRouteEntity.setUrl(url.toString());
zuulRouteEntity.setEnable(true);
zuulRouteEntity.setStripPrefix(true);
locateRouteList.add(zuulRouteEntity);
}
}
} catch (DataAccessException e) {
logger.error("load zuul route from db exception", e);
}
return handle(locateRouteList);
}
/*@Override
public List<IZuulRouteRule> getRules(Route route) {
if (CollectionUtils.isEmpty(locateRouteList)) {
return null;
}
for (ZuulRouteEntity item : locateRouteList) {
if (item.getId().equals(route.getId())) {
return item.getRuleList();
}
}
return null;
}*/
/**
* 网关负载均衡
* @param serviceId 服务id
* @param addressStr 服务地址(jsonArray字符串)
* @return 负载后得到的地址
*/
private String loadBalance(String serviceId, String addressStr) {
JSONArray addressJsonArray = JSONArray.parseArray(addressStr);
TreeSet<String> addressSet = new TreeSet<>();
for (Object addressObj : addressJsonArray) {
addressSet.add(addressObj.toString());
}
//默认为轮询
rpcLoadBalance = LoadBalance.match(gatewayLoadBalance,LoadBalance.ROUND).rpcInvokerRouter;
return rpcLoadBalance.route(serviceId,addressSet);
}
}
\ No newline at end of file
package com.byit.gateway.zuul;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
public class ZuulRouteEntity implements Serializable {
/**
*
*/
private static final long serialVersionUID = -8909855285961467412L;
/**
* The ID of the route (the same as its map key by default).
*/
private String id;
/**
* The path (pattern) for the route, e.g. /foo/**.
*/
private String path;
/**
* The service ID (if any) to map to this route. You can specify a
* physical URL or a service, but not both.
*/
private String serviceId;
/**
* A full physical URL to map to the route. An alternative is to use a
* service ID and service discovery to find the physical address.
*/
private String url;
/**
* Flag to determine whether the prefix for this route (the path, minus
* pattern patcher) should be stripped before forwarding.
*/
private boolean stripPrefix;
/**
* Flag to indicate that this route should be retryable (if supported).
* Generally retry requires a service ID and ribbon.
*/
private boolean retryable;
/**
* List of sensitive headers that are not passed to downstream requests.
* Defaults to a "safe" set of headers that commonly contain user
* credentials. It's OK to remove those from the list if the downstream
* service is part of the same system as the proxy, so they are sharing
* authentication data. If using a physical URL outside your own domain,
* then generally it would be a bad idea to leak user credentials.
*/
private Set<String> sensitiveHeadersSet = new LinkedHashSet<>();
/**
* 字符串格式,与sensitiveHeaders对应,多个用逗号隔开
*/
private String sensitiveHeaders;
private boolean customSensitiveHeaders;
/**
* 是否可用
*/
private boolean enable;
/**
* 路由器名称
*/
private String routerName;
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 isRetryable() {
return retryable;
}
public void setRetryable(boolean retryable) {
this.retryable = retryable;
}
public Set<String> getSensitiveHeadersSet() {
return sensitiveHeadersSet;
}
public void setSensitiveHeadersSet(Set<String> sensitiveHeadersSet) {
this.sensitiveHeadersSet = sensitiveHeadersSet;
StringBuilder sb = new StringBuilder("");
if (!CollectionUtils.isEmpty(sensitiveHeadersSet)) {
for (String item : sensitiveHeadersSet) {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(item);
}
}
this.sensitiveHeaders = sb.toString();
}
public String getSensitiveHeaders() {
return sensitiveHeaders;
}
public void setSensitiveHeaders(String sensitiveHeaders) {
this.sensitiveHeaders = sensitiveHeaders;
if (!StringUtils.isEmpty(sensitiveHeaders)) {
this.sensitiveHeadersSet = new LinkedHashSet<>(Arrays.asList(sensitiveHeaders.split(",")));
} else {
this.sensitiveHeadersSet = new LinkedHashSet<String>();
}
}
public boolean isCustomSensitiveHeaders() {
return customSensitiveHeaders;
}
public void setCustomSensitiveHeaders(boolean customSensitiveHeaders) {
this.customSensitiveHeaders = customSensitiveHeaders;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
public String getRouterName() {
return routerName;
}
public void setRouterName(String routerName) {
this.routerName = routerName;
}
}
package com.byit.gateway.zuul;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author liyuan
* 路由探测器
*/
public abstract class ZuulRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
private final static Logger logger = LoggerFactory.getLogger(ZuulRouteLocator.class);
private ZuulProperties properties;
public ZuulRouteLocator(String servletPath, ZuulProperties properties) {
super(servletPath, properties);
this.properties = properties;
logger.info("servletPath:{}", servletPath);
}
@Override
public void refresh() {
doRefresh();
}
@Override
protected Map<String, ZuulRoute> locateRoutes() {
LinkedHashMap<String, ZuulRoute> routesMap = new LinkedHashMap<>();
// 从application.properties中加载路由信息
Map<String, ZuulRoute> locateRoutesMap = loadLocateRoute();
if (!CollectionUtils.isEmpty(locateRoutesMap)) {
routesMap.putAll(locateRoutesMap);
}
// 优化一下配置
LinkedHashMap<String, ZuulRoute> values = new LinkedHashMap<>();
for (Map.Entry<String, 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 abstract Map<String, ZuulRoute> loadLocateRoute();
@Override
public int getOrder() {
return -1;
}
/**
* 复制查询出来的数据的属性
*/
public Map<String, ZuulRoute> handle(List<ZuulRouteEntity> locateRouteList){
if(CollectionUtils.isEmpty(locateRouteList)){
return null;
}
Map<String, ZuulRoute> routes = new LinkedHashMap<>();
for (ZuulRouteEntity locateRoute : locateRouteList) {
if (StringUtils.isEmpty(locateRoute.getPath())
|| !locateRoute.isEnable()
|| (StringUtils.isEmpty(locateRoute.getUrl()) && StringUtils.isEmpty(locateRoute.getServiceId()))) {
continue;
}
ZuulRoute zuulRoute = new ZuulRoute();
try {
//zuulRoute.setCustomSensitiveHeaders(locateRoute.isCustomSensitiveHeaders());
//zuulRoute.setSensitiveHeaders(locateRoute.getSensitiveHeadersSet());
//zuulRoute.setId(locateRoute.getId());
// zuulRoute.setLocation("");
zuulRoute.setId(locateRoute.getId());
zuulRoute.setPath(locateRoute.getPath());
//是否需要重试
zuulRoute.setRetryable(false);
zuulRoute.setServiceId(locateRoute.getServiceId());
//是否去掉前缀
zuulRoute.setStripPrefix(true);
zuulRoute.setUrl(locateRoute.getUrl());
logger.info("add zuul route: " + JSON.toJSONString(zuulRoute));
} catch (Exception e) {
logger.error("=============load zuul route info from db with error==============", e);
}
routes.put(zuulRoute.getPath(), zuulRoute);
}
return routes;
}
}
package com.byit.gateway.zuul.refresh;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.Resource;
public class AutoRefreshRouteJob {
private final Logger logger = LoggerFactory.getLogger(AutoRefreshRouteJob.class);
@Resource
private RefreshRouteService refreshRouteService;
@Scheduled(cron = "${spring.zuul.route.refreshCron:0/30 * * * * ?}")
public void run() {
logger.info("refresh zuul route config");
refreshRouteService.refreshRoute();
}
}
package com.byit.gateway.zuul.refresh;
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;
/**
* @author liyuan
* 更新路由
*/
public class RefreshRouteService {
@Autowired
private ApplicationEventPublisher publisher;
@Autowired
private RouteLocator routeLocator;
public void refreshRoute() {
RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(routeLocator);
publisher.publishEvent(routesRefreshedEvent);
}
}
\ No newline at end of file
zuul.ignored-services=*
logging.level.org.springframework=INFO #路由规则参考byit-myth-rpc中的LoadBalance枚举类中的类型 默认是轮询
logging.level.com.byit.gateway=DEBUG gateway.load.balance=ROUND
# myth-rpc
myth-rpc.remoting.port=7080
myth-rpc.registry.address=http://localhost:8080/myth-register
myth-rpc.registry.env=dev
myth-rpc.registry.biz=${spring.application.name}
spring.zuul.route.refreshCron:0/10 * * * * ?
# Druid
logging.level.druid.sql=ERROR
logging.level.druid.sql.DataSource=ERROR
logging.level.druid.sql.Connection=ERROR
logging.level.druid.sql.Statement=DEBUG
logging.level.druid.sql.ResultSet=ERROR
#datasource #datasource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.driver-class-name=com.mysql.jdbc.Driver
...@@ -25,3 +12,16 @@ spring.datasource.password=123456 ...@@ -25,3 +12,16 @@ spring.datasource.password=123456
spring.datasource.hikari.idle-timeout=60000 spring.datasource.hikari.idle-timeout=60000
spring.datasource.hikari.maximum-pool-size=5 spring.datasource.hikari.maximum-pool-size=5
spring.datasource.hikari.minimum-idle=1 spring.datasource.hikari.minimum-idle=1
logging.config=classpath:logback.xml
logging.level.org.springframework=INFO
logging.level.com.byit.gateway=DEBUG
# myth-rpc
myth-rpc.remoting.port=8082
myth-rpc.registry.address=http://localhost:8080/myth-register
myth-rpc.registry.env=liyuan
myth-rpc.registry.biz=byit-myth-job
spring.zuul.route.refreshCron:0/10 * * * * ?
zuul.ignored-services=*
#路由规则参考byit-myth-rpc中的LoadBalance枚举类中的类型 默认是轮询
gateway.load.balance=ROUND
logging.config=classpath:logback.xml
logging.level.org.springframework=INFO
logging.level.com.byit.gateway=DEBUG
#datasource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://10.0.10.118:3306/myth-registry?useUnicode=true&useSSL=true&characterEncoding=utf-8&mysqlEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=false&autoReconnect=true&failOverReadOnly=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.hikari.idle-timeout=60000
spring.datasource.hikari.maximum-pool-size=5
spring.datasource.hikari.minimum-idle=1
# myth-rpc
myth-rpc.remoting.port=8082
myth-rpc.registry.address=http://localhost:8080/myth-register
myth-rpc.registry.env=pre
myth-rpc.registry.biz=byit-myth-job
spring.zuul.route.refreshCron:0/10 * * * * ?
zuul.ignored-services=*
#路由规则参考byit-myth-rpc中的LoadBalance枚举类中的类型 默认是轮询
gateway.load.balance=ROUND
logging.config=classpath:logback.xml
logging.level.org.springframework=INFO
logging.level.com.byit.gateway=DEBUG
# myth-rpc
myth-rpc.remoting.port=8082
myth-rpc.registry.address=http://localhost:8080/myth-register
myth-rpc.registry.env=test
myth-rpc.registry.biz=byit-myth-job
spring.zuul.route.refreshCron:0/10 * * * * ?
# Druid
#logging.level.druid.sql=ERROR
#logging.level.druid.sql.DataSource=ERROR
#logging.level.druid.sql.Connection=ERROR
#logging.level.druid.sql.Statement=DEBUG
#logging.level.druid.sql.ResultSet=ERROR
#datasource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://10.0.10.118:3306/myth-registry?useUnicode=true&useSSL=true&characterEncoding=utf-8&mysqlEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=false&autoReconnect=true&failOverReadOnly=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.hikari.idle-timeout=60000
spring.datasource.hikari.maximum-pool-size=5
spring.datasource.hikari.minimum-idle=1
...@@ -2,5 +2,4 @@ ...@@ -2,5 +2,4 @@
server.port=8081 server.port=8081
spring.profiles.active=dev spring.profiles.active=dev
spring.application.name=byit-myth-gateway spring.application.name=byit-myth-gateway
zuul.ignored-services="*"
logging.config=classpath:logback.xml
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment