一、增加注解
增加一个作用于类及方法上的注解,并且参数中可以指明这是对哪个应用的拦截。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ProxyInterceptor {
/**
* 第三方应用唯一标识
*/
AppCode appCode();
二、让拦截器注解在运行时生效,需要增加一个切面
public class ProxyInterceptorAdvisor extends AbstractPointcutAdvisor {
private static final long serialVersionUID = -3969619570449156144L;
private Advice advice;
private Pointcut pointcut;
public ProxyInterceptorAdvisor(Class<? extends Annotation> annotationType, MethodInterceptor interceptor) {
this.pointcut = buildPointcut(annotationType);
this.advice = interceptor;
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public Advice getAdvice() {
return this.advice;
}
private Pointcut buildPointcut(Class<? extends Annotation> annotationType) {
ComposablePointcut result = null;
// 类级别
Pointcut cpc = new AnnotationMatchingPointcut(annotationType, true);
// 方法级别
Pointcut mpc = AnnotationMatchingPointcut.forMethodAnnotation(annotationType);
// 对于类和方法上都可以添加注解的情况
// 类上的注解,最终会将注解绑定到每个方法上
if (result == null) {
result = new ComposablePointcut(cpc);
}
return result.union(mpc);
}
}
三、拦截器的业务处理
此时只要在业务Service上添加了ProxyInterceptor注解就可以被如下逻辑拦截
Component
@Order(Integer.MIN_VALUE)
public class ProxyInterceptorProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor
implements InitializingBean, ApplicationContextAware {
private static final long serialVersionUID = 7370491915785512783L;
@SuppressWarnings("unused")
private ApplicationContext applicationContext;
@Override
public void afterPropertiesSet() throws Exception {
this.advisor = new ProxyInterceptorAdvisor(ProxyInterceptor.class, new ProxyMethodInterceptor());
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
private class ProxyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> proxyClass = invocation.getThis().getClass();
Method method = invocation.getMethod();
ProxyInterceptor typeInterceptor = proxyClass.getAnnotation(ProxyInterceptor.class);
ProxyInterceptor methodInterceptor = method.getAnnotation(ProxyInterceptor.class);
// 优先以方法上的注解为准
ProxyInterceptor interceptor = methodInterceptor != null ? methodInterceptor : typeInterceptor;
AppCode app = interceptor.appCode();
Object result = null;
try {
// 被拦截的是私有方法,则直接执行
if (!Modifier.isPublic(method.getModifiers())) {
return invocation.proceed();
}
String className = proxyClass.getSimpleName();
String methodName = method.getName();
Object args[] = invocation.getArguments();
log.info(app + "=request=" + className + "." + methodName + ",args:"
+ JSON.toJSONString(args));
result = invocation.proceed();
log.info(app + "=response=" + className + "." + methodName + ",result:"
+ JSON.toJSONString(result));
return result;
} catch (ProxyServiceException e) {
e.setApp(app);
log.error("ProxyServiceException:" + JSON.toJSONString(result), e);
throw e;
} catch (Exception e) {
log.error("Exception:" + JSON.toJSONString(result), e);
throw new ProxyServiceException(app, e.getMessage(), e);
}
}
}
}
四、使用拦截器
在类上添加注解,并指明这个类是哪个远程应用提供的服务。
@Service
@ProxyInterceptor(appCode = AppCode.CASE)
public class CaseServiceProxy {
}