我们在使用AOP时通常都是直接使用@Before、@After、@Around、@AfterThrowing、@AfterReturning等注解来拦截方法的,其实Spring还有另外一种方式来实现AOP,那就是创建Advisor
。
Advisor(顾问)的组成:Advisor内部包含了PointCut(切点)和Advice(通知),PointCut表名要匹配哪些类的哪些方法,Advice表明要植入的代码。
其实我们编写的@Before等注解最终还是会被解析为Advis
注解 | 实现类 |
---|---|
@Around | AspectJAroundAdvice |
@Before | AspectJMethodBeforeAdvice |
@After | AspectJAfterAdvice |
@AfterReturing | AspectJAfterReturingAdvice |
@AfterThrowing | AspectJAfterThrowingAdvice |
1. 编写PointCut
PointCut表明我们需要代理哪些类的哪些方法。
/**
* 切点:包含了 MethodMatcher(方法匹配器)
*/
public class LogPrintPointCut implements Pointcut {
/**
* 指明要拦截哪些类
*/
@Override
public ClassFilter getClassFilter() {
return new ClassFilter() {
@Override
public boolean matches(Class<?> clazz) {
//拦截所有类
return true;
}
};
}
/**
* 指明要拦截哪些方法
*/
@Override
public MethodMatcher getMethodMatcher() {
return new MethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
//拦截加了LogPrint注解的所有方法
return Objects.nonNull(method.getAnnotation(LogPrint.class));
}
//后面2个方法不会用到,返回false即可
@Override
public boolean isRuntime() {
return false;
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
return false;
}
};
}
}
2. 编写Advice
Advice标明要执行的操作
/**
* 自定义环绕通知
*/
@Slf4j
public class LogPrintAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
//执行方法
Object proceed = invocation.proceed();
Map<String,Object> parameterMap = new HashMap<>();
List<Parameter> parameterList = Arrays.asList(invocation.getMethod().getParameters());
for (int i = 0; i < parameterList.size(); i++) {
parameterMap.put(parameterList.get(i).getName(),invocation.getArguments()[i]);
}
log.info("环绕通知-{}执行成功,参数{},返回值{}",invocation.getMethod().getName(), JSONUtil.toJsonStr(parameterMap),proceed);
return proceed;
}
}
3. 注入Advisor
往Spring容器内放入Advisor,Spring即可生成代理类
/**
* Advisor(顾问) 包含了Advice(通知)和PointCut(切点)
*/
@Component
public class MyAdvisor implements PointcutAdvisor {
@Override
public Pointcut getPointcut() {
return new LogPrintPointCut();
}
@Override
public Advice getAdvice() {
return new LogPrintAdvice();
}
}