0
点赞
收藏
分享

微信扫一扫

SpringBoot2.x下“AOP自动代理”实战—注解版日志打印

1. 使用EnableAspectJAutoProxy注解

在启动类上使用。

@EnableAspectJAutoProxy(exposeProxy = true)

引入依赖,当然引入依赖后,默认会使用@EnableAspectJAutoProxy注解。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

该注解的作用就是向Spring容器中注册AnnotationAwareAspectJAutoProxyCreator类。

这个类就是Spring 自动代理真正的实现类(我们常用的事务就是这个类完成自动代理的)。

2. 流程分析

AnnotationAwareAspectJAutoProxyCreator类没有实现isEligibleAdvisorBean方法。默认使用的是父类AbstractAdvisorAutoProxyCreator的方法。

//这方法作用就是判断Advisor是否合格。若合格的话,根据Advisor的Pointcut就可以增强Bean了。
protected boolean isEligibleAdvisorBean(String beanName) {
    return true;
}

那么AnnotationAwareAspectJAutoProxyCreator就会找到Spring容器中所有Advisor Bean

也就是,我们将任一的Advisor注册到Spring容器中,就可以对bean进行AOP自动代理!

3. 代码实现

  1. 定义注解
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnno {

    Class<?>[] value() default {};

}
  1. 定义切点
public class LogAnnoAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {

    //ClassFilter默认为Boolean.TRUE
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        //某些类直接返回false(对类的过滤)
        //1. 判断类上是否存在某注解?
        //2. 解析注解内容,放到缓存中,防止多次解析影响效率
        Class<?> userClass = ProxyUtils.getUserClass(targetClass);
        Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
        //处理桥接方法
        specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
        if (specificMethod != method) {
            return findLogAnnoAttribute(method) || findLogAnnoAttribute(method.getDeclaringClass());
        }
        return findLogAnnoAttribute(specificMethod) || findLogAnnoAttribute(specificMethod.getDeclaringClass());
    }
    public boolean findLogAnnoAttribute(Class<?> targetClass) {
        AnnotationAttributes attributes =
                AnnotatedElementUtils.findMergedAnnotationAttributes(targetClass, LogAnno.class, false, false);
        return attributes != null;
    }

    public boolean findLogAnnoAttribute(Method method) {
        AnnotationAttributes attributes =
                AnnotatedElementUtils.findMergedAnnotationAttributes(method, LogAnno.class, false, false);
        return attributes != null;
    }
}
  1. 定义Advisor并放入Spring容器
public class DefaultAdvisorAutoProxyCreatorConfig {
    //切点可以不加入到Spring容器,直接在defaultPointcutAdvisor()new出来也可以。
    @Bean
    public LogAnnoAttributeSourcePointcut logAnnoAttributeSourcePointcut(){
        return new LogAnnoAttributeSourcePointcut();
    }
    //自定义一个切面
    @Bean("defaultPointcutAdvisor")
    public DefaultPointcutAdvisor defaultPointcutAdvisor(LogAnnoAttributeSourcePointcut logAnnoAttributeSourcePointcut) {
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        //通知
        advisor.setAdvice((MethodBeforeAdvice) (method, args, target) -> {
            System.out.println("前置拦截:" + method.getName());
        });
        advisor.setPointcut(logAnnoAttributeSourcePointcut);
        return advisor;
    }
}

直接将Advisor放到容器,AnnotationAwareAspectJAutoProxyCreator将会加强方法。

举报

相关推荐

0 条评论