服务治理-自定义拦截
# 一、需求背景
在服务治理层面,我们通常会想到熔断、降级、限流、切面的操作,并把这些操作集成在中间件里。
但是每个业务系统的多样性,可能还会有一些额外的场景需要被治理。如果已有中间件的功能不能满足了,但是又不想为一个特殊的业务单独去开发一个中间件,这时候就需要给业务留出一个可自定义逻辑的切口,让业务系统可以自定义扩展一些服务功能。
# 二、方案设计
可以通过在中间件里,加入其他方法的自定义注解配置和拦截操作,这样就可以在调用现在方法时先执行用户自定义的配置方法。
- 使用自定义注解和切面技术,拦截和执行新增的扩展方法
- 拦截到扩展方法后,执行扩展方法的业务逻辑
# 三、实现方案
# 1、自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExMethod {
/**
* 方法名
*/
String method() default "";
/**
* 返回信息
*/
String returnJson() default "";
}
# 2、切面实现
@Aspect
@Component
public class ExMethodPoint {
@Pointcut("@annotation(me.xu.method.annotation.ExMethod)")
public void aopPoint() {
}
@Around("aopPoint()")
public Object doRouter(ProceedingJoinPoint point) throws Throwable {
// 获取内容
Method method = getMethod(point);
// 获取注解
ExMethod exMethod = method.getAnnotation(ExMethod.class);
// 获取拦截方法
String methodName = exMethod.method();
// 功能处理
Method methodExt = getClass(point).getMethod(methodName, method.getParameterTypes());
Class<?> returnType = methodExt.getReturnType();
// 判断方法返回类型(这里根据自己业务情况)
if (!"boolean".equals(returnType.getName())) {
throw new RuntimeException("annotation @DoMethodExt set method:" + methodName + " returnType is not boolean");
}
// 拦截判断正常,继续执行(反射)
boolean invoke = (boolean) methodExt.invoke(point.getThis(), point.getArgs());
// 返回结果
return invoke ? point.proceed() : JSON.parseObject(exMethod.returnJson(), method.getReturnType());
}
private Method getMethod(JoinPoint point) throws NoSuchMethodException {
Signature sig = point.getSignature();
MethodSignature methodSignature = (MethodSignature) sig;
return point.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
}
private Class<? extends Object> getClass(JoinPoint point) {
return point.getTarget().getClass();
}
}
# 四、案例测试
# 1、依赖映入
<dependency>
<groupId>me.xu</groupId>
<artifactId>spring-ex-method</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
# 2、控制层调用
@RestController
public class UserController {
private Logger logger = LoggerFactory.getLogger(UserController.class);
/**
* 放行:http://localhost:8081/api/queryUserInfo?userId=aaa
* 拦截:http://localhost:8081/api/queryUserInfo?userId=bbb
*/
@ExMethod(method = "blacklist", returnJson = "{\"code\":\"1111\",\"info\":\"自定义校验方法拦截,不允许访问!\"}")
@RequestMapping(path = "/api/queryUserInfo", method = RequestMethod.GET)
public UserInfo queryUserInfo(@RequestParam String userId) {
logger.info("查询用户信息,userId:{}", userId);
return new UserInfo("wxx:" + userId, 19, "地址");
}
/**
* 自定义黑名单,拦截方法
*/
public boolean blacklist(@RequestParam String userId) {
if ("bbb".equals(userId) || "222".equals(userId)) {
logger.info("拦截自定义黑名单用户 userId:{}", userId);
return false;
}
return true;
}
}
- 进入接口之前,会被自定义注解给拦截住
- 拦截自定义方法后,执行自定义方法逻辑
# 参考
上次更新: 2024/06/29, 15:13:44