Springboot动态配置AOP切点详解
作者:澄风
前言
Springboot 可以定义注解切点去拦截注解修饰的类方法以及execution (xxxx)切点去拦截具体的类方法。默认情况下我们都会使用注解@PointCut去定义切点,然后定义切面拦截切点。
但有些场景需要我们在配置文件(.properties/yml)中配置 execution 灵活的去修改需要拦截的切点。这样我们可以将一些公共的拦截增强放到 jar 包推送到仓库中共享。
通用不可动态配置的做法
@Aspect @Component public class TransactionConfig { private static final String C_POINT_CUT = "execution(public * com.allens.export.service.*.*(..))"; @Pointcut(C_POINT_CUT) public void pointCut () {}; //@Pointcut("execution(public * com.allens.export.service.*.*(..))") //public void pointCut () {}; @Before("pointCut()") public void before(JoinPoint joinPoint) { System.out.println("----------------"); } @Around("pointCut()") public Object process (ProceedingJoinPoint joinPoint) throws Throwable { return joinPoint.proceed(); } @After("pointCut()") public void after(JoinPoint joinPoint) { } }
可以看到我们可以将切点写成static final 传入到注解中,但我们并不能传变量到切点中。解下来就要讲重点部分,如何动态配置切点。其实我们可以猜到,AOP原理就是使用Java动态代理或CGlib进行增强代理。我们使用注解@PointCut定义切点其实也是需要代码去解析然后增强。我们其实也可以直接写代码去增强我们的类,手动定义切点,手动定义切面等等。
动态配置切点
AspectJExpressionPointcut 提供表达式匹配类和方法。
public class GreetingDynamicPointcut extends AspectJExpressionPointcut { }
MethodInterceptor 提供拦截方法的能力,我们可以借助它实现注解@Around功能
@Slf4j public class GreetingInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { try { log.info("调用前..."); return methodInvocation.proceed(); } catch (Exception e) { log.error("error", e); throw e; } finally { log.info("调用后..."); } } }
GreetingAdvice 这个类继承了 GreetingInterceptor 可以实现@Around环绕功能,继承了 AfterReturningAdvice 实现了 @After 方法调用后拦截功能,继承了 MethodBeforeAdvice 实现了方法调用前的拦截功能。
@Slf4j public class GreetingAdvice extends GreetingInterceptor implements MethodBeforeAdvice, AfterReturningAdvice, AdvisorAdapter { @Override public void before(Method method, Object[] args, Object target) throws Throwable { // 输出切点 System.out.println("Pointcut:" + target.getClass().getName() + "." + method.getName()); if (args.length > 0) { String clientName = (String) args[0]; System.out.println("How are you " + clientName + " ?"); } } @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println(returnValue); } @Override public boolean supportsAdvice(Advice advice) { return true; } @Override public MethodInterceptor getInterceptor(Advisor advisor) { return null; } }
配置
@Configuration public class WebmvcConfig { @Bean public Pointcut customPointCut() { GreetingDynamicPointcut greetingDynamicPointcut = new GreetingDynamicPointcut(); // ① greetingDynamicPointcut.setExpression("execution(public * com.allens.test.controller..*(..)) || execution(public * com.allens.test.service..*(..))"); return greetingDynamicPointcut; } @Bean GreetingBeforeAdvice getAdvice () { return new GreetingBeforeAdvice(); } // ② @Bean DefaultPointcutAdvisor defaultPointcutAdvisor () { DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor(); defaultPointcutAdvisor.setPointcut(customPointCut()); defaultPointcutAdvisor.setAdvice(getAdvice()); return defaultPointcutAdvisor; } }
① 我们实现动态配置只需要把这里的execution 字符串替换成自己从配置文件中获取的配置即可。
② 自定义切面,可以灵活配置切点和切面。
到此这篇关于Springboot动态配置AOP切点详解的文章就介绍到这了,更多相关Springboot配置AOP切点内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!