Merge branch 'develop'

# Conflicts:
#	changelog.md
#	sop-admin/sop-admin-server/pom.xml
#	sop-common/pom.xml
#	sop-common/sop-gateway-common/pom.xml
#	sop-common/sop-registry-api/pom.xml
#	sop-common/sop-service-common/pom.xml
#	sop-example/sop-auth/pom.xml
#	sop-example/sop-book/sop-book-web/pom.xml
#	sop-example/sop-easyopen/pom.xml
#	sop-example/sop-springmvc/pom.xml
#	sop-example/sop-story/sop-story-web/pom.xml
#	sop-gateway/pom.xml
#	sop-website/website-server/pom.xml
This commit is contained in:
tanghc
2019-08-07 15:15:54 +08:00
108 changed files with 2065 additions and 293 deletions

View File

@@ -1,6 +1,5 @@
package com.gitee.sop.gateway.config;
import com.gitee.sop.gateway.manager.ManagerInitializer;
import com.gitee.sop.gatewaycommon.gateway.configuration.AlipayGatewayConfiguration;
@@ -20,9 +19,6 @@ import com.gitee.sop.gatewaycommon.gateway.configuration.AlipayGatewayConfigurat
//@Configuration
public class GatewayConfig extends AlipayGatewayConfiguration {
static {
new ManagerInitializer();
}
}
/**

View File

@@ -6,8 +6,10 @@ package com.gitee.sop.gateway.config;
* 注意:下面两个只能使用一个
*/
import com.gitee.sop.gateway.manager.ManagerInitializer;
import com.gitee.sop.gateway.loadbalancer.SopPropertiesFactory;
import com.gitee.sop.gatewaycommon.zuul.configuration.AlipayZuulConfiguration;
import org.springframework.cloud.netflix.ribbon.PropertiesFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
@@ -17,8 +19,9 @@ import org.springframework.context.annotation.Configuration;
@Configuration
public class ZuulConfig extends AlipayZuulConfiguration {
static {
new ManagerInitializer();
@Bean
PropertiesFactory propertiesFactory() {
return new SopPropertiesFactory();
}
}

View File

@@ -0,0 +1,42 @@
package com.gitee.sop.gateway.entity;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
/**
* 表名config_gray
* 备注:服务灰度配置
*
* @author tanghc
*/
@Table(name = "config_gray")
@Data
public class ConfigGray {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
/** 数据库字段id */
private Long id;
/** 数据库字段service_id */
private String serviceId;
/** 用户key多个用引文逗号隔开, 数据库字段user_key_content */
private String userKeyContent;
/** 需要灰度的接口goods.get1.0=1.2,多个用英文逗号隔开, 数据库字段name_version_content */
private String nameVersionContent;
/** 数据库字段gmt_create */
private Date gmtCreate;
/** 数据库字段gmt_modified */
private Date gmtModified;
}

View File

@@ -0,0 +1,41 @@
package com.gitee.sop.gateway.entity;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
/**
* 表名config_gray_instance
*
* @author tanghc
*/
@Table(name = "config_gray_instance")
@Data
public class ConfigGrayInstance {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
/** 数据库字段id */
private Long id;
/** instance_id, 数据库字段instance_id */
private String instanceId;
/** service_id, 数据库字段service_id */
private String serviceId;
/** 0禁用1启用, 数据库字段status */
private Byte status;
/** 数据库字段gmt_create */
private Date gmtCreate;
/** 数据库字段gmt_modified */
private Date gmtModified;
}

View File

@@ -0,0 +1,77 @@
package com.gitee.sop.gateway.loadbalancer;
import com.gitee.sop.gateway.manager.DbEnvGrayManager;
import com.gitee.sop.gatewaycommon.bean.SpringContext;
import com.gitee.sop.gatewaycommon.param.Param;
import com.gitee.sop.gatewaycommon.zuul.loadbalancer.BaseServerChooser;
import com.netflix.loadbalancer.Server;
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
import org.springframework.core.env.Environment;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* 预发布、灰度环境选择参考自https://segmentfault.com/a/1190000017412946
*
* @author tanghc
*/
public class EnvironmentServerChooser extends BaseServerChooser {
private static final String MEDATA_KEY_ENV = "env";
private static final String ENV_PRE_VALUE = "pre";
private static final String ENV_GRAY_VALUE = "gray";
/**
* 预发布机器域名
*/
private static final String PRE_DOMAIN = "localhost";
@Override
protected boolean isPreServer(Server server) {
String env = getEnvValue(server);
return ENV_PRE_VALUE.equals(env);
}
@Override
protected boolean isGrayServer(Server server) {
String env = getEnvValue(server);
return ENV_GRAY_VALUE.equals(env);
}
private String getEnvValue(Server server) {
// eureka存储的metadata
Map<String, String> metadata = ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata();
return metadata.get(MEDATA_KEY_ENV);
}
/**
* 通过判断hostname来确定是否是预发布请求可修改此方法实现自己想要的
*
* @param request request
* @return 返回true可以进入到预发环境
*/
@Override
protected boolean canVisitPre(Server server, HttpServletRequest request) {
String serverName = request.getServerName();
String domain = SpringContext.getBean(Environment.class).getProperty("pre.domain", PRE_DOMAIN);
return domain.equals(serverName);
}
/**
* 是否是灰度用户,可修改此方法实现自己想要的
*
* @param param 接口参数
* @param userKeyManager userKey管理
* @param server 服务器实例
* @param request request
* @return true
*/
protected boolean isGrayUser(Param param, DbEnvGrayManager userKeyManager, Server server, HttpServletRequest request) {
String instanceId = server.getMetaInfo().getInstanceId();
// 这里的灰度用户为appKey包含此appKey则为灰度用户允许访问
String appKey = param.fetchAppKey();
return userKeyManager.containsKey(instanceId, appKey);
}
}

View File

@@ -0,0 +1,39 @@
package com.gitee.sop.gateway.loadbalancer;
import com.netflix.loadbalancer.IRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.ribbon.PropertiesFactory;
import org.springframework.core.env.Environment;
/**
* 自定义PropertiesFactory用来动态添加LoadBalance规则
* @author tanghc
*/
public class SopPropertiesFactory extends PropertiesFactory {
/**
* 可在配置文件中设置<code>zuul.custom-rule-classname=com.xx.ClassName</code>指定负载均衡规则类
* 默认使用com.gitee.sop.gateway.loadbalancer.PreEnvironmentServerChooser
*/
private static final String PROPERTIES_KEY = "zuul.custom-rule-classname";
private static final String CUSTOM_RULE_CLASSNAME = EnvironmentServerChooser.class.getName();
@Autowired
private Environment environment;
/**
* 配置文件配置:<serviceId>.ribbon.NFLoadBalancerRuleClassName=com.gitee.sop.gateway.loadbalancer.EnvironmentServerChooser
* @param clazz
* @param name serviceId
* @return 返回class全限定名
*/
@Override
public String getClassName(Class clazz, String name) {
if (clazz == IRule.class) {
return this.environment.getProperty(PROPERTIES_KEY, CUSTOM_RULE_CLASSNAME);
} else {
return super.getClassName(clazz, name);
}
}
}

View File

@@ -0,0 +1,126 @@
package com.gitee.sop.gateway.manager;
import com.alibaba.fastjson.JSON;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.sop.gateway.entity.ConfigGray;
import com.gitee.sop.gateway.entity.ConfigGrayInstance;
import com.gitee.sop.gateway.mapper.ConfigGrayInstanceMapper;
import com.gitee.sop.gateway.mapper.ConfigGrayMapper;
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
import com.gitee.sop.gatewaycommon.bean.ServiceGrayDefinition;
import com.gitee.sop.gatewaycommon.manager.DefaultEnvGrayManager;
import com.gitee.sop.gatewaycommon.manager.ZookeeperContext;
import com.gitee.sop.gatewaycommon.zuul.loadbalancer.ServiceGrayConfig;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 存放用户key这里放在本机内容如果灰度发布保存的用户id数量偏多可放在redis中
*
* @author tanghc
*/
@Slf4j
@Service
public class DbEnvGrayManager extends DefaultEnvGrayManager {
private static final int STATUS_ENABLE = 1;
private static final Function<String[], String> FUNCTION_KEY = arr -> arr[0];
private static final Function<String[], String> FUNCTION_VALUE = arr -> arr[1];
@Autowired
private Environment environment;
@Autowired
private ConfigGrayMapper configGrayMapper;
@Autowired
private ConfigGrayInstanceMapper configGrayInstanceMapper;
@Override
public void load() {
List<ConfigGray> list = configGrayMapper.list(new Query());
for (ConfigGray configGray : list) {
this.setServiceGrayConfig(configGray);
}
Query query = new Query();
query.eq("status", STATUS_ENABLE);
List<ConfigGrayInstance> grayInstanceList = configGrayInstanceMapper.list(query);
for (ConfigGrayInstance configGrayInstance : grayInstanceList) {
this.openGray(configGrayInstance.getInstanceId(), configGrayInstance.getServiceId());
}
}
/**
* 设置用户key
*
* @param configGray 灰度配置
*/
public void setServiceGrayConfig(ConfigGray configGray) {
if (configGray == null) {
return;
}
String userKeyData = configGray.getUserKeyContent();
String nameVersionContent = configGray.getNameVersionContent();
String[] userKeys = StringUtils.split(userKeyData, ',');
String[] nameVersionList = StringUtils.split(nameVersionContent, ',');
log.info("灰度配置userKeys.length:{}, nameVersionList:{}", userKeys.length, Arrays.toString(nameVersionList));
Set<String> userKeySet = Stream.of(userKeys)
.collect(Collectors.toCollection(Sets::newConcurrentHashSet));
Map<String, String> grayNameVersionMap = Stream.of(nameVersionList)
.map(nameVersion -> StringUtils.split(nameVersion, '='))
.collect(Collectors.toConcurrentMap(FUNCTION_KEY, FUNCTION_VALUE));
ServiceGrayConfig serviceGrayConfig = new ServiceGrayConfig();
serviceGrayConfig.setServiceId(configGray.getServiceId());
serviceGrayConfig.setUserKeys(userKeySet);
serviceGrayConfig.setGrayNameVersion(grayNameVersionMap);
this.saveServiceGrayConfig(serviceGrayConfig);
}
@PostConstruct
protected void after() throws Exception {
ZookeeperContext.setEnvironment(environment);
String isvChannelPath = ZookeeperContext.getServiceGrayChannelPath();
ZookeeperContext.listenPath(isvChannelPath, nodeCache -> {
String nodeData = new String(nodeCache.getCurrentData().getData());
ChannelMsg channelMsg = JSON.parseObject(nodeData, ChannelMsg.class);
String data = channelMsg.getData();
ServiceGrayDefinition userKeyDefinition = JSON.parseObject(data, ServiceGrayDefinition.class);
String serviceId = userKeyDefinition.getServiceId();
switch (channelMsg.getOperation()) {
case "set":
ConfigGray configGray = configGrayMapper.getByColumn("service_id", serviceId);
this.setServiceGrayConfig(configGray);
break;
case "open":
openGray(userKeyDefinition.getInstanceId(), serviceId);
break;
case "close":
closeGray(userKeyDefinition.getInstanceId());
break;
default:
}
});
}
}

View File

@@ -9,6 +9,7 @@ import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.List;
@@ -19,6 +20,7 @@ import java.util.List;
* @author tanghc
*/
@Slf4j
@Service
public class DbIPBlacklistManager extends DefaultIPBlacklistManager {
@Autowired
@@ -54,7 +56,6 @@ public class DbIPBlacklistManager extends DefaultIPBlacklistManager {
remove(ip);
break;
default:
log.error("IP黑名单错误的消息指令nodeData{}", nodeData);
}
});
}

View File

@@ -3,6 +3,7 @@ package com.gitee.sop.gateway.manager;
import com.alibaba.fastjson.JSON;
import com.gitee.sop.gateway.entity.IsvDetailDTO;
import com.gitee.sop.gateway.mapper.IsvInfoMapper;
import com.gitee.sop.gatewaycommon.bean.ApiConfig;
import com.gitee.sop.gatewaycommon.bean.ChannelMsg;
import com.gitee.sop.gatewaycommon.bean.IsvDefinition;
import com.gitee.sop.gatewaycommon.manager.ZookeeperContext;
@@ -11,6 +12,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.List;
@@ -19,6 +21,7 @@ import java.util.List;
* @author tanghc
*/
@Slf4j
@Service
public class DbIsvManager extends CacheIsvManager {
@Autowired
@@ -41,6 +44,7 @@ public class DbIsvManager extends CacheIsvManager {
@PostConstruct
protected void after() throws Exception {
ApiConfig.getInstance().setIsvManager(this);
ZookeeperContext.setEnvironment(environment);
String isvChannelPath = ZookeeperContext.getIsvInfoChannelPath();
ZookeeperContext.listenPath(isvChannelPath, nodeCache -> {
@@ -57,7 +61,6 @@ public class DbIsvManager extends CacheIsvManager {
remove(isvDefinition.getAppKey());
break;
default:
log.error("ISV信息错误的消息指令nodeData{}", nodeData);
}
});

View File

@@ -17,6 +17,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
@@ -35,6 +36,7 @@ import static java.util.stream.Collectors.toList;
* @author tanghc
*/
@Slf4j
@Service
public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManager {
@Autowired
@@ -150,6 +152,8 @@ public class DbIsvRoutePermissionManager extends DefaultIsvRoutePermissionManage
log.info("删除ISV路由权限信息isvRoutePermission:{}", isvRoutePermission);
remove(isvRoutePermission.getAppKey());
break;
default:
}
});
}

View File

@@ -11,6 +11,7 @@ import com.gitee.sop.gatewaycommon.util.MyBeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
@@ -19,6 +20,7 @@ import javax.annotation.PostConstruct;
* @author tanghc
*/
@Slf4j
@Service
public class DbLimitConfigManager extends DefaultLimitConfigManager {
@Autowired
@@ -61,7 +63,6 @@ public class DbLimitConfigManager extends DefaultLimitConfigManager {
update(configLimitDto);
break;
default:
log.error("限流配置信息错误的消息指令nodeData{}", nodeData);
}
});
}

View File

@@ -14,6 +14,7 @@ import com.gitee.sop.gatewaycommon.manager.ZookeeperContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Collection;
@@ -22,6 +23,7 @@ import java.util.Collection;
* @author tanghc
*/
@Slf4j
@Service
public class DbRouteConfigManager extends DefaultRouteConfigManager {
@Autowired
@@ -85,7 +87,6 @@ public class DbRouteConfigManager extends DefaultRouteConfigManager {
update(routeConfig);
break;
default:
log.error("路由配置信息错误的消息指令nodeData{}", nodeData);
}
});
}

View File

@@ -14,5 +14,6 @@ public class ManagerInitializer {
apiConfig.setRouteConfigManager(new DbRouteConfigManager());
apiConfig.setLimitConfigManager(new DbLimitConfigManager());
apiConfig.setIpBlacklistManager(new DbIPBlacklistManager());
apiConfig.setUserKeyManager(new DbEnvGrayManager());
}
}

View File

@@ -0,0 +1,11 @@
package com.gitee.sop.gateway.mapper;
import com.gitee.fastmybatis.core.mapper.CrudMapper;
import com.gitee.sop.gateway.entity.ConfigGrayInstance;
/**
* @author tanghc
*/
public interface ConfigGrayInstanceMapper extends CrudMapper<ConfigGrayInstance, Long> {
}

View File

@@ -0,0 +1,11 @@
package com.gitee.sop.gateway.mapper;
import com.gitee.fastmybatis.core.mapper.CrudMapper;
import com.gitee.sop.gateway.entity.ConfigGray;
/**
* @author tanghc
*/
public interface ConfigGrayMapper extends CrudMapper<ConfigGray, Long> {
}

View File

@@ -12,6 +12,9 @@ eureka.url=http://localhost:1111/eureka/
zookeeper.url=localhost:2181
# zipkin服务监控地址没有开启不用改
zipkin.url=http://127.0.0.1:9411/
# 预发布网关域名
pre.domain=localhost
# ------- 需要改的配置end -------
# 入口地址,不用改,默认是/zuul