Initial commit

This commit is contained in:
jackyu66git
2026-03-23 11:52:51 +08:00
commit ea8d889fbe
1114 changed files with 92438 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>oneone-common</artifactId>
<groupId>com.oneone.cloud</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>common-sentinel</artifactId>
<packaging>jar</packaging>
<version>0.0.1</version>
<dependencies>
<dependency>
<groupId>com.oneone.cloud</groupId>
<artifactId>common-core</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--feign 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- LB 扩展 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,45 @@
package com.oneone.common.sentinel;
/*import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;*/
import com.alibaba.cloud.sentinel.feign.SentinelFeignAutoConfiguration;
import com.oneone.common.sentinel.config.DataSourceInitFunc;
import com.oneone.common.sentinel.config.OneoneBlockHandler;
import com.oneone.common.sentinel.originparser.IpRequestOriginParser;
import com.oneone.common.sentinel.sentinelfeign.OneoneSentinelFeign;
import feign.Feign;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@AutoConfigureBefore(SentinelFeignAutoConfiguration.class)
@Configuration
@ConditionalOnProperty(name = "feign.sentinel.enabled")
public class SentinelAutoConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public Feign.Builder feignSentinelBuilder() {
return OneoneSentinelFeign.builder();
}
@Bean
public DataSourceInitFunc dataSourceInitFunc() {
return new DataSourceInitFunc();
}
@Bean
public OneoneBlockHandler oneoneBlockHandler(){
return new OneoneBlockHandler();
}
@Bean
public IpRequestOriginParser ipRequestOriginParser(){
return new IpRequestOriginParser();
}
}
@@ -0,0 +1,136 @@
package com.oneone.common.sentinel.config;
import com.alibaba.cloud.sentinel.SentinelProperties;
import com.alibaba.cloud.sentinel.datasource.config.NacosDataSourceProperties;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.List;
/**
*
* @author mice
* @date 2021/7/7 21:23
* @version 1.0
*/
@Slf4j
public class DataSourceInitFunc implements CommandLineRunner {
@Autowired
private SentinelProperties sentinelProperties;
@Override
public void run(String... args) throws Exception {
sentinelProperties.getDatasource().entrySet().stream().filter(map -> map.getValue().getNacos() != null).forEach(map -> {
NacosDataSourceProperties nacosDataSourceProperties = map.getValue().getNacos();
this.init(nacosDataSourceProperties);
});
}
public void init(NacosDataSourceProperties nacosDataSourceProperties){
switch (nacosDataSourceProperties.getRuleType()){
case FLOW :
flowRule(nacosDataSourceProperties);
break;
case DEGRADE :
degradeRule(nacosDataSourceProperties);
break;
case PARAM_FLOW :
paramFlowRule(nacosDataSourceProperties);
break;
case SYSTEM :
systemRule(nacosDataSourceProperties);
break;
case AUTHORITY :
authorityRule(nacosDataSourceProperties);
break;
/*case GW_FLOW :
gwFlowRule(nacosDataSourceProperties);
break;
case GW_API_GROUP :
gwApiGroup(nacosDataSourceProperties);
break; */
}
}
private void flowRule(NacosDataSourceProperties nacosDataSourceProperties){
ReadableDataSource<String, List<FlowRule>> ruleDataSource = new NacosDataSource<>(
nacosDataSourceProperties.getServerAddr(), nacosDataSourceProperties.getGroupId(), nacosDataSourceProperties.getDataId(),
source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
}));
FlowRuleManager.register2Property(ruleDataSource.getProperty());
log.info("sentinel数据源:规则_{}_加载完毕...",nacosDataSourceProperties.getRuleType());
}
private void degradeRule(NacosDataSourceProperties nacosDataSourceProperties){
ReadableDataSource<String, List<DegradeRule>> ruleDataSource = new NacosDataSource<>(
nacosDataSourceProperties.getServerAddr(), nacosDataSourceProperties.getGroupId(), nacosDataSourceProperties.getDataId(),
source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {
}));
DegradeRuleManager.register2Property(ruleDataSource.getProperty());
log.info("sentinel数据源:规则_{}_加载完毕...",nacosDataSourceProperties.getRuleType());
}
private void paramFlowRule(NacosDataSourceProperties nacosDataSourceProperties){
ReadableDataSource<String, List<ParamFlowRule>> ruleDataSource = new NacosDataSource<>(
nacosDataSourceProperties.getServerAddr(), nacosDataSourceProperties.getGroupId(), nacosDataSourceProperties.getDataId(),
source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {
}));
ParamFlowRuleManager.register2Property(ruleDataSource.getProperty());
log.info("sentinel数据源:规则_{}_加载完毕...",nacosDataSourceProperties.getRuleType());
}
private void systemRule(NacosDataSourceProperties nacosDataSourceProperties){
ReadableDataSource<String, List<SystemRule>> ruleDataSource = new NacosDataSource<>(
nacosDataSourceProperties.getServerAddr(), nacosDataSourceProperties.getGroupId(), nacosDataSourceProperties.getDataId(),
source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>() {
}));
SystemRuleManager.register2Property(ruleDataSource.getProperty());
log.info("sentinel数据源:规则_{}_加载完毕...",nacosDataSourceProperties.getRuleType());
}
private void authorityRule(NacosDataSourceProperties nacosDataSourceProperties){
ReadableDataSource<String, List<AuthorityRule>> ruleDataSource = new NacosDataSource<>(
nacosDataSourceProperties.getServerAddr(), nacosDataSourceProperties.getGroupId(), nacosDataSourceProperties.getDataId(),
source -> JSON.parseObject(source, new TypeReference<List<AuthorityRule>>() {
}));
AuthorityRuleManager.register2Property(ruleDataSource.getProperty());
log.info("sentinel数据源:规则_{}_加载完毕...",nacosDataSourceProperties.getRuleType());
}
/*private void gwFlowRule(NacosDataSourceProperties nacosDataSourceProperties){
ReadableDataSource<String, List<GatewayFlowRule>> ruleDataSource = new NacosDataSource<>(
nacosDataSourceProperties.getServerAddr(), nacosDataSourceProperties.getGroupId(), nacosDataSourceProperties.getDataId(),
source -> JSON.parseObject(source, new TypeReference<List<GatewayFlowRule>>() {
}));
GatewayRuleManager.register2Property(ruleDataSource.getProperty());
log.info("sentinel数据源:规则_{}_加载完毕...",nacosDataSourceProperties.getRuleType());
}
private void gwApiGroup(NacosDataSourceProperties nacosDataSourceProperties){
ReadableDataSource<String, List<ApiDefinition>> ruleDataSource = new NacosDataSource<>(
nacosDataSourceProperties.getServerAddr(), nacosDataSourceProperties.getGroupId(), nacosDataSourceProperties.getDataId(),
source -> JSON.parseObject(source, new TypeReference<List<ApiDefinition>>() {
}));
GatewayApiDefinitionManager.register2Property(ruleDataSource.getProperty());
log.info("sentinel数据源:规则_{}_加载完毕...",nacosDataSourceProperties.getRuleType());
}*/
}
@@ -0,0 +1,41 @@
package com.oneone.common.sentinel.config;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.alibaba.fastjson.JSON;
import com.oneone.common.result.Result;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* @author mice
* @date 2021/7/7 21:24
* @version 1.0
*/
public class OneoneBlockHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
httpServletResponse.setContentType("application/json;charset=UTF-8");
Result result = null;
if (e instanceof FlowException) {
result = Result.failed("-1", "接口被限流了");
} else if (e instanceof DegradeException) {
result = Result.failed("-2", "接口被降级了");
} else if (e instanceof ParamFlowException) {
result = Result.failed("-3", "接口被热点限流了");
} else if (e instanceof AuthorityException) {
result = Result.failed("-4", "接口被授权规则限制访问了");
} else if (e instanceof SystemBlockException) {
result = Result.failed("-5", "接口被系统规则限制了了");
}
httpServletResponse.getWriter().write(JSON.toJSONString(result));
}
}
@@ -0,0 +1,18 @@
package com.oneone.common.sentinel.originparser;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import javax.servlet.http.HttpServletRequest;
/**
*
* @author mice
* @date 2021/7/7 21:25
* @version 1.0
*/
public class IpRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
return httpServletRequest.getRemoteAddr();
}
}
@@ -0,0 +1,47 @@
package com.oneone.common.sentinel.sentinelfeign;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.oneone.common.result.Result;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
*
* @author mice
* @date 2021/7/7 21:25
* @version 1.0
*/
@AllArgsConstructor
@Slf4j
public class FeignFallback<T> implements MethodInterceptor {
private final Class<T> targetType;
private final String targetName;
private final Throwable throwable;
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
log.error("feignFallback:[{},{}] api:[{}] message:[{}]",targetType.getName(),method.getName(),targetName,throwable.getMessage());
Result result = null;
if (throwable instanceof FlowException) {
result = Result.failed("-1", "接口被限流了");
} else if (throwable instanceof DegradeException) {
result = Result.failed("-2", "接口被降级了");
} else if (throwable instanceof ParamFlowException) {
result = Result.failed("-3", "接口被热点限流了");
} else if (throwable instanceof AuthorityException) {
result = Result.failed("-4", "接口被授权规则限制访问了");
} else if (throwable instanceof SystemBlockException) {
result = Result.failed("-5", "接口被系统规则限制了了");
}
return result;
}
}
@@ -0,0 +1,113 @@
package com.oneone.common.sentinel.sentinelfeign;
import com.alibaba.cloud.sentinel.feign.SentinelContractHolder;
import feign.Contract;
import feign.Feign;
import feign.InvocationHandlerFactory;
import feign.Target;
import org.springframework.beans.BeansException;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.FeignContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
/**
* 重写 {@link com.alibaba.cloud.sentinel.feign.SentinelFeign} 支持自动降级注入
*
*/
public final class OneoneSentinelFeign {
private OneoneSentinelFeign() {
}
public static OneoneSentinelFeign.Builder builder() {
return new OneoneSentinelFeign.Builder();
}
public static final class Builder extends Feign.Builder implements ApplicationContextAware {
private Contract contract = new Contract.Default();
private ApplicationContext applicationContext;
private FeignContext feignContext;
@Override
public Feign.Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) {
throw new UnsupportedOperationException();
}
@Override
public OneoneSentinelFeign.Builder contract(Contract contract) {
this.contract = contract;
return this;
}
@Override
public Feign build() {
super.invocationHandlerFactory(new InvocationHandlerFactory() {
@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
// 查找 FeignClient 上的 降级策略
FeignClient feignClient = AnnotationUtils.findAnnotation(target.type(), FeignClient.class);
Class fallback = feignClient.fallback();
Class fallbackFactory = feignClient.fallbackFactory();
String beanName = feignClient.contextId();
if (!StringUtils.hasText(beanName)) {
beanName = feignClient.name();
}
Object fallbackInstance;
FallbackFactory fallbackFactoryInstance;
// check fallback and fallbackFactory properties
if (void.class != fallback) {
fallbackInstance = getFromContext(beanName, "fallback", fallback, target.type());
return new OneoneSentinelInvocationHandler(target, dispatch,
new FallbackFactory.Default(fallbackInstance));
}
if (void.class != fallbackFactory) {
fallbackFactoryInstance = (FallbackFactory) getFromContext(beanName, "fallbackFactory",
fallbackFactory, FallbackFactory.class);
return new OneoneSentinelInvocationHandler(target, dispatch, fallbackFactoryInstance);
}
return new OneoneSentinelInvocationHandler(target, dispatch);
}
private Object getFromContext(String name, String type, Class fallbackType, Class targetType) {
Object fallbackInstance = feignContext.getInstance(name, fallbackType);
if (fallbackInstance == null) {
throw new IllegalStateException(String.format(
"No %s instance of type %s found for feign client %s", type, fallbackType, name));
}
if (!targetType.isAssignableFrom(fallbackType)) {
throw new IllegalStateException(String.format(
"Incompatible %s instance. Fallback/fallbackFactory of type %s is not assignable to %s for feign client %s",
type, fallbackType, targetType, name));
}
return fallbackInstance;
}
});
super.contract(new SentinelContractHolder(contract));
return super.build();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
feignContext = this.applicationContext.getBean(FeignContext.class);
}
}
}
@@ -0,0 +1,174 @@
package com.oneone.common.sentinel.sentinelfeign;
import com.alibaba.cloud.sentinel.feign.SentinelContractHolder;
import com.alibaba.cloud.sentinel.feign.SentinelInvocationHandler;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.oneone.common.result.Result;
import feign.Feign;
import feign.InvocationHandlerFactory;
import feign.MethodMetadata;
import feign.Target;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;
import java.util.Map;
import static feign.Util.checkNotNull;
/**
* 重写 {@link SentinelInvocationHandler} 支持自动降级注入
*/
@Slf4j
public class OneoneSentinelInvocationHandler implements InvocationHandler {
public static final String EQUALS = "equals";
public static final String HASH_CODE = "hashCode";
public static final String TO_STRING = "toString";
private final Target<?> target;
private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;
private FallbackFactory fallbackFactory;
private Map<Method, Method> fallbackMethodMap;
OneoneSentinelInvocationHandler(Target<?> target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch,
FallbackFactory fallbackFactory) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch");
this.fallbackFactory = fallbackFactory;
this.fallbackMethodMap = toFallbackMethod(dispatch);
}
OneoneSentinelInvocationHandler(Target<?> target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
this.target = checkNotNull(target, "target");
this.dispatch = checkNotNull(dispatch, "dispatch");
}
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
if (EQUALS.equals(method.getName())) {
try {
Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
return equals(otherHandler);
}
catch (IllegalArgumentException e) {
return false;
}
}
else if (HASH_CODE.equals(method.getName())) {
return hashCode();
}
else if (TO_STRING.equals(method.getName())) {
return toString();
}
Object result;
InvocationHandlerFactory.MethodHandler methodHandler = this.dispatch.get(method);
// only handle by HardCodedTarget
if (target instanceof Target.HardCodedTarget) {
Target.HardCodedTarget hardCodedTarget = (Target.HardCodedTarget) target;
MethodMetadata methodMetadata = SentinelContractHolder.METADATA_MAP
.get(hardCodedTarget.type().getName() + Feign.configKey(hardCodedTarget.type(), method));
// resource default is HttpMethod:protocol://url
if (methodMetadata == null) {
result = methodHandler.invoke(args);
}
else {
String resourceName = methodMetadata.template().method().toUpperCase() + ":" + hardCodedTarget.url()
+ methodMetadata.template().path();
Entry entry = null;
try {
ContextUtil.enter(resourceName);
entry = SphU.entry(resourceName, EntryType.OUT, 1, args);
result = methodHandler.invoke(args);
}
catch (Throwable ex) {
// fallback handle
if (!BlockException.isBlockException(ex)) {
Tracer.trace(ex);
}
if (fallbackFactory != null) {
try {
Object fallbackResult = fallbackMethodMap.get(method).invoke(fallbackFactory.create(ex),
args);
return fallbackResult;
}
catch (IllegalAccessException e) {
// shouldn't happen as method is public due to being an
// interface
throw new AssertionError(e);
}
catch (InvocationTargetException e) {
throw new AssertionError(e.getCause());
}
}
else {
// 若是Result类型 执行自动降级返回R
if (Result.class == method.getReturnType()) {
log.error("feign 服务间调用异常", ex);
return Result.failed("",ex.getLocalizedMessage());
}
else {
throw ex;
}
}
}
finally {
if (entry != null) {
entry.exit(1, args);
}
ContextUtil.exit();
}
}
}
else {
// other target type using default strategy
result = methodHandler.invoke(args);
}
return result;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof SentinelInvocationHandler) {
OneoneSentinelInvocationHandler other = (OneoneSentinelInvocationHandler) obj;
return target.equals(other.target);
}
return false;
}
@Override
public int hashCode() {
return target.hashCode();
}
@Override
public String toString() {
return target.toString();
}
static Map<Method, Method> toFallbackMethod(Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
Map<Method, Method> result = new LinkedHashMap<>();
for (Method method : dispatch.keySet()) {
method.setAccessible(true);
result.put(method, method);
}
return result;
}
}
@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.oneone.common.sentinel.SentinelAutoConfiguration