基于自定义注解的方式使用Spring AOP

以前在xml中配置spring aop,切点用一个表达式定义,在大多数场景中,我们不想包名或方法名遵循统一的规则,要实现灵活的定义切点,比如自定义一个注解,标注在那个方法上,就切那个方法。下面的内容刚好符合上面的场景,当然只是基本的代码模板,你可以根据你的业务需求进行更复杂的封装,这里只是提取出通用的代码。

定义PointcutAdvisor实现

这里一般都是继承AbstractPointcutAdvisor类,需要子类提供Pointcut和Advice实例

public class MyAnnotaionAdvisor extends AbstractPointcutAdvisor{
    private Advice advice;
    private Pointcut pointcut;
    
    //传入你自定义注解和MethodInterceptor实现
    public MyAnnotaionAdvisor (Class annotationType,MethodInterceptor interceptor){
      this.advice = interceptor;
      this.pointcut = buildPointcut(annotationType);
    }

    @Override
    public Pointcut getPointcut() {
        Assert.notNull(this.pointcut, "'pointcut' must not be null");
        return this.pointcut;
    }

    @Override
    public Advice getAdvice() {
        Assert.notNull(this.advice, "'advice' must not be null");
        return this.advice;
    }    

    private Pointcut buildPointcut(Class annotationType) {
        Assert.notNull(annotationType, "'annotationTypes' must not be null");
        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);
    }
}

定义Advice 实现

Advice接口有多种方式,如BeforeAdvice,AfterAdvice,Interceptor,一般实现MethodInterceptor接口

//你也可以继承或实现你的业务类
public class MyInterceptor implements MethodInterceptor {
    
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        //获取目标类
        Class targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
        //获取指定方法
        Method specificMethod = ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
        //获取真正执行的方法,可能存在桥接方法
        final Method userDeclaredMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

        //获取方法上注解
        Async async = AnnotatedElementUtils.findMergedAnnotation(userDeclaredMethod, Async.class);
        if (async == null) {
            async = AnnotatedElementUtils.findMergedAnnotation(userDeclaredMethod.getDeclaringClass(), Async.class);
        }

        //获取返回类型
        Class returnType = invocation.getMethod().getReturnType();
        //返回类型判断
        if (User.class.isAssignableFrom(returnType)) {

            return null;
        }

        //执行具体业务逻辑
        
        return invocation.proceed();
    }

}

配置Advisor

  //在配置类或文件中创建该Bean
  public class MyAnnotationBeanPostProcessor extends AbstractAdvisingBeanPostProcessor implements BeanFactoryAware {
     private MethodInterceptor  interceptor;
     private  Class annotation;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        setBeforeExistingAdvisors(true);
        StatAnnotationAdvisor advisor = new StatAnnotationAdvisor(this.annotation,this.interceptor);
        advisor.setBeanFactory(beanFactory);
        this.advisor = advisor;
    }
    //省略getter/setter方法
}

以上只是针对单个注解的AOP实现,那对于多个注解,每个注解都有不同的处理逻辑,怎么实现?这里使用的是Spring aop,如果希望在CGLIB中灵活配置,怎么实现?不着急,后面慢慢写。

你可能感兴趣的:(基于自定义注解的方式使用Spring AOP)