1. SQL 同步最新
2. 优化 trace 相关的逻辑
This commit is contained in:
parent
e65488265d
commit
6f6e8777e7
@ -56,7 +56,8 @@
|
||||
| | MySQL 监控 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈 |
|
||||
| | Redis 监控 |监控 Redis 数据库的使用情况,使用的 Redis Key 管理 |
|
||||
| 🚀 |Java 监控 | 基于 Spring Boot Admin 实现 Java 应用的监控 |
|
||||
| 🚀 | 链路追踪 | 基于 SkyWalking 实现性能监控,特别是链路的追踪 |
|
||||
| 🚀 | 链路追踪 | 接入 SkyWalking 组件,实现链路追踪 |
|
||||
| 🚀 | 日志中心 | 接入 SkyWalking 组件,实现日志中心 |
|
||||
| 🚀 | 分布式锁 | 基于 Redis 实现分布式锁,满足并发场景 |
|
||||
| 🚀 | 幂等组件 | 基于 Redis 实现幂等组件,解决重复请求问题 |
|
||||
| 🚀 | 服务保障 | 基于 Resilience4j 实现服务的稳定性,包括限流、熔断等功能 |
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,8 +1,9 @@
|
||||
package cn.iocoder.dashboard.framework.tracer.core.aop;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.dashboard.framework.tracer.core.annotation.BizTrace;
|
||||
import cn.iocoder.dashboard.util.sping.SpElUtil;
|
||||
import cn.iocoder.dashboard.util.sping.SpringExpressionUtils;
|
||||
import io.opentracing.Span;
|
||||
import io.opentracing.Tracer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -11,6 +12,9 @@ import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* {@link BizTrace} 切面,记录业务链路
|
||||
@ -55,8 +59,9 @@ public class BizTraceAspect {
|
||||
|
||||
private void setBizTag(Span span, ProceedingJoinPoint joinPoint, BizTrace trace) {
|
||||
try {
|
||||
span.setTag(BizTrace.TYPE_TAG, StrUtil.toString(SpElUtil.analysisSpEl(trace.type(), joinPoint)));
|
||||
span.setTag(BizTrace.ID_TAG, StrUtil.toString(SpElUtil.analysisSpEl(trace.id(), joinPoint)));
|
||||
Map<String, Object> result = SpringExpressionUtils.parseExpressions(joinPoint, asList(trace.type(), trace.id()));
|
||||
span.setTag(BizTrace.TYPE_TAG, MapUtil.getStr(result, trace.type()));
|
||||
span.setTag(BizTrace.ID_TAG, MapUtil.getStr(result, trace.id()));
|
||||
} catch (Exception ex) {
|
||||
log.error("[setBizTag][解析 bizType 与 bizId 发生异常]", ex);
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class ToolTestDemoController {
|
||||
@ApiImplicitParam(name = "ids", value = "编号列表", required = true, dataTypeClass = List.class)
|
||||
@PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
|
||||
// @RateLimiter(name = "backendA")
|
||||
@BizTrace(id = "1", type = "'user'")
|
||||
@BizTrace(id = "#ids", type = "'user'")
|
||||
public CommonResult<List<ToolTestDemoRespVO>> getTestDemoList(@RequestParam("ids") Collection<Long> ids) {
|
||||
List<ToolTestDemoDO> list = testDemoService.getTestDemoList(ids);
|
||||
return success(ToolTestDemoConvert.INSTANCE.convertList(list));
|
||||
|
@ -1,70 +0,0 @@
|
||||
package cn.iocoder.dashboard.util.sping;
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* SpEl解析类
|
||||
*
|
||||
* @author mashu
|
||||
*/
|
||||
public class SpElUtil {
|
||||
|
||||
private static SpelExpressionParser parser = new SpelExpressionParser();
|
||||
private static DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
|
||||
|
||||
private SpElUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析切面SpEL
|
||||
*
|
||||
* @param spElString 表达式
|
||||
* @param joinPoint 切面点
|
||||
* @return 执行界面
|
||||
*/
|
||||
public static Object analysisSpEl(String spElString, ProceedingJoinPoint joinPoint) {
|
||||
// 通过joinPoint获取被注解方法
|
||||
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
// 使用spring的DefaultParameterNameDiscoverer获取方法形参名数组
|
||||
String[] paramNames = nameDiscoverer.getParameterNames(method);
|
||||
// 解析过后的Spring表达式对象
|
||||
Expression expression = parser.parseExpression(spElString);
|
||||
// spring的表达式上下文对象
|
||||
EvaluationContext context = new StandardEvaluationContext();
|
||||
// 通过joinPoint获取被注解方法的形参
|
||||
Object[] args = joinPoint.getArgs();
|
||||
// 给上下文赋值
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
context.setVariable(paramNames[i], args[i]);
|
||||
}
|
||||
return expression.getValue(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量解析切面SpEL
|
||||
*
|
||||
* @param spElStrings 表达式
|
||||
* @param joinPoint 切面点
|
||||
* @return 执行界面
|
||||
*/
|
||||
public static Map<String, Object> analysisSpEls(List<String> spElStrings, ProceedingJoinPoint joinPoint) {
|
||||
if (null == spElStrings) {
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> resultMap = new HashMap<>(spElStrings.size());
|
||||
spElStrings.forEach(expression -> resultMap.put(expression, analysisSpEl(expression, joinPoint)));
|
||||
return resultMap;
|
||||
}
|
||||
}
|
@ -1,46 +1,46 @@
|
||||
package cn.iocoder.dashboard.util;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import org.springframework.aop.framework.AdvisedSupport;
|
||||
import org.springframework.aop.framework.AopProxy;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
|
||||
/**
|
||||
* Spring AOP 工具类
|
||||
*
|
||||
* 参考波克尔 http://www.bubuko.com/infodetail-3471885.html 实现
|
||||
*/
|
||||
public class AopTargetUtils {
|
||||
|
||||
/**
|
||||
* 获取代理的目标对象
|
||||
*
|
||||
* @param proxy 代理对象
|
||||
* @return 目标对象
|
||||
*/
|
||||
public static Object getTarget(Object proxy) throws Exception {
|
||||
// 不是代理对象
|
||||
if (!AopUtils.isAopProxy(proxy)) {
|
||||
return proxy;
|
||||
}
|
||||
// Jdk 代理
|
||||
if (AopUtils.isJdkDynamicProxy(proxy)) {
|
||||
return getJdkDynamicProxyTargetObject(proxy);
|
||||
}
|
||||
// Cglib 代理
|
||||
return getCglibProxyTargetObject(proxy);
|
||||
}
|
||||
|
||||
private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
|
||||
Object dynamicAdvisedInterceptor = BeanUtil.getFieldValue(proxy, "CGLIB$CALLBACK_0");
|
||||
AdvisedSupport advisedSupport = (AdvisedSupport) BeanUtil.getFieldValue(dynamicAdvisedInterceptor, "advised");
|
||||
return advisedSupport.getTargetSource().getTarget();
|
||||
}
|
||||
|
||||
private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
|
||||
AopProxy aopProxy = (AopProxy) BeanUtil.getFieldValue(proxy, "h");
|
||||
AdvisedSupport advisedSupport = (AdvisedSupport) BeanUtil.getFieldValue(aopProxy, "advised");
|
||||
return advisedSupport.getTargetSource().getTarget();
|
||||
}
|
||||
|
||||
}
|
||||
package cn.iocoder.dashboard.util.sping;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import org.springframework.aop.framework.AdvisedSupport;
|
||||
import org.springframework.aop.framework.AopProxy;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
|
||||
/**
|
||||
* Spring AOP 工具类
|
||||
*
|
||||
* 参考波克尔 http://www.bubuko.com/infodetail-3471885.html 实现
|
||||
*/
|
||||
public class SpringAopUtils {
|
||||
|
||||
/**
|
||||
* 获取代理的目标对象
|
||||
*
|
||||
* @param proxy 代理对象
|
||||
* @return 目标对象
|
||||
*/
|
||||
public static Object getTarget(Object proxy) throws Exception {
|
||||
// 不是代理对象
|
||||
if (!AopUtils.isAopProxy(proxy)) {
|
||||
return proxy;
|
||||
}
|
||||
// Jdk 代理
|
||||
if (AopUtils.isJdkDynamicProxy(proxy)) {
|
||||
return getJdkDynamicProxyTargetObject(proxy);
|
||||
}
|
||||
// Cglib 代理
|
||||
return getCglibProxyTargetObject(proxy);
|
||||
}
|
||||
|
||||
private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
|
||||
Object dynamicAdvisedInterceptor = BeanUtil.getFieldValue(proxy, "CGLIB$CALLBACK_0");
|
||||
AdvisedSupport advisedSupport = (AdvisedSupport) BeanUtil.getFieldValue(dynamicAdvisedInterceptor, "advised");
|
||||
return advisedSupport.getTargetSource().getTarget();
|
||||
}
|
||||
|
||||
private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
|
||||
AopProxy aopProxy = (AopProxy) BeanUtil.getFieldValue(proxy, "h");
|
||||
AdvisedSupport advisedSupport = (AdvisedSupport) BeanUtil.getFieldValue(aopProxy, "advised");
|
||||
return advisedSupport.getTargetSource().getTarget();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package cn.iocoder.dashboard.util.sping;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Spring EL 表达式的工具类
|
||||
*
|
||||
* @author mashu
|
||||
*/
|
||||
public class SpringExpressionUtils {
|
||||
|
||||
private static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
|
||||
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
|
||||
|
||||
private SpringExpressionUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 从切面中,单个解析 EL 表达式的结果
|
||||
*
|
||||
* @param joinPoint 切面点
|
||||
* @param expressionString EL 表达式数组
|
||||
* @return 执行界面
|
||||
*/
|
||||
public static Object parseExpression(ProceedingJoinPoint joinPoint, String expressionString) {
|
||||
Map<String, Object> result = parseExpressions(joinPoint, Collections.singletonList(expressionString));
|
||||
return result.get(expressionString);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从切面中,批量解析 EL 表达式的结果
|
||||
*
|
||||
* @param joinPoint 切面点
|
||||
* @param expressionStrings EL 表达式数组
|
||||
* @return 结果,key 为表达式,value 为对应值
|
||||
*/
|
||||
public static Map<String, Object> parseExpressions(ProceedingJoinPoint joinPoint, List<String> expressionStrings) {
|
||||
// 如果为空,则不进行解析
|
||||
if (CollUtil.isEmpty(expressionStrings)) {
|
||||
return MapUtil.newHashMap();
|
||||
}
|
||||
|
||||
// 第一步,构建解析的上下文 EvaluationContext
|
||||
// 通过 joinPoint 获取被注解方法
|
||||
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = methodSignature.getMethod();
|
||||
// 使用 spring 的 ParameterNameDiscoverer 获取方法形参名数组
|
||||
String[] paramNames = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
|
||||
// Spring 的表达式上下文对象
|
||||
EvaluationContext context = new StandardEvaluationContext();
|
||||
// 给上下文赋值
|
||||
if (ArrayUtil.isNotEmpty(paramNames)) {
|
||||
Object[] args = joinPoint.getArgs();
|
||||
for (int i = 0; i < paramNames.length; i++) {
|
||||
context.setVariable(paramNames[i], args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 第二步,逐个参数解析
|
||||
Map<String, Object> result = MapUtil.newHashMap(expressionStrings.size(), true);
|
||||
expressionStrings.forEach(key -> {
|
||||
Object value = EXPRESSION_PARSER.parseExpression(key).getValue(context);
|
||||
result.put(key, value);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysMenuMapper;
|
||||
import cn.iocoder.dashboard.modules.system.enums.permission.MenuTypeEnum;
|
||||
import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysMenuProducer;
|
||||
import cn.iocoder.dashboard.modules.system.service.permission.impl.SysMenuServiceImpl;
|
||||
import cn.iocoder.dashboard.util.AopTargetUtils;
|
||||
import cn.iocoder.dashboard.util.sping.SpringAopUtils;
|
||||
import cn.iocoder.dashboard.util.RandomUtils;
|
||||
import cn.iocoder.dashboard.util.object.ObjectUtils;
|
||||
import com.google.common.collect.Multimap;
|
||||
@ -57,7 +57,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest {
|
||||
sysMenuService.initLocalCache();
|
||||
|
||||
// 获取代理对象
|
||||
SysMenuServiceImpl target = (SysMenuServiceImpl) AopTargetUtils.getTarget(sysMenuService);
|
||||
SysMenuServiceImpl target = (SysMenuServiceImpl) SpringAopUtils.getTarget(sysMenuService);
|
||||
|
||||
Map<Long, SysMenuDO> menuCache =
|
||||
(Map<Long, SysMenuDO>) BeanUtil.getFieldValue(target, "menuCache");
|
||||
@ -227,7 +227,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest {
|
||||
public void testListMenusFromCache_success() throws Exception {
|
||||
Map<Long, SysMenuDO> mockCacheMap = new HashMap<>();
|
||||
//获取代理对象
|
||||
SysMenuServiceImpl target = (SysMenuServiceImpl) AopTargetUtils.getTarget(sysMenuService);
|
||||
SysMenuServiceImpl target = (SysMenuServiceImpl) SpringAopUtils.getTarget(sysMenuService);
|
||||
BeanUtil.setFieldValue(target, "menuCache", mockCacheMap);
|
||||
|
||||
Map<Long, SysMenuDO> idMenuMap = new HashMap<>();
|
||||
@ -256,7 +256,7 @@ public class SysMenuServiceTest extends BaseDbUnitTest {
|
||||
public void testListMenusFromCache2_success() throws Exception {
|
||||
Map<Long, SysMenuDO> mockCacheMap = new HashMap<>();
|
||||
//获取代理对象
|
||||
SysMenuServiceImpl target = (SysMenuServiceImpl) AopTargetUtils.getTarget(sysMenuService);
|
||||
SysMenuServiceImpl target = (SysMenuServiceImpl) SpringAopUtils.getTarget(sysMenuService);
|
||||
BeanUtil.setFieldValue(target, "menuCache", mockCacheMap);
|
||||
|
||||
Map<Long, SysMenuDO> idMenuMap = new HashMap<>();
|
||||
|
@ -13,14 +13,8 @@ import cn.iocoder.dashboard.modules.system.dal.mysql.permission.SysRoleMapper;
|
||||
import cn.iocoder.dashboard.modules.system.enums.permission.SysRoleTypeEnum;
|
||||
import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysRoleProducer;
|
||||
import cn.iocoder.dashboard.modules.system.service.permission.impl.SysRoleServiceImpl;
|
||||
import cn.iocoder.dashboard.util.AopTargetUtils;
|
||||
import cn.iocoder.dashboard.util.AssertUtils;
|
||||
import cn.iocoder.dashboard.util.RandomUtils;
|
||||
import cn.iocoder.dashboard.util.object.ObjectUtils;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import cn.iocoder.dashboard.util.sping.SpringAopUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@ -63,7 +57,7 @@ public class SysRoleServiceTest extends BaseDbUnitTest {
|
||||
|
||||
//断言
|
||||
//获取代理对象
|
||||
SysRoleServiceImpl target = (SysRoleServiceImpl) AopTargetUtils.getTarget(sysRoleService);
|
||||
SysRoleServiceImpl target = (SysRoleServiceImpl) SpringAopUtils.getTarget(sysRoleService);
|
||||
|
||||
Map<Long, SysRoleDO> roleCache = (Map<Long, SysRoleDO>) BeanUtil.getFieldValue(target, "roleCache");
|
||||
assertPojoEquals(roleDO1, roleCache.get(roleDO1.getId()));
|
||||
|
Loading…
Reference in New Issue
Block a user