SpringBoot2.x下“后置处理器”完成AOP代理实战—注解版日志打印

Spring完成AOP代理有两种途径,一种依赖AbstractAutoProxyCreator来完成自动代理(例如事务就是依赖其子类完成代理)。另一种是依赖AbstractAdvisingBeanPostProcessor来完成代理(例如@Async就是依赖其子类完成代理)。

使用AbstractAutoProxyCreator完成AOP代理,只需要将Advisor注册到Spring容器中。而AbstractAdvisingBeanPostProcessor需要使用其子类来完成AOP代理。

1. AbstractAdvisingBeanPostProcessor子类

image.png

Spring使用模板方法模式,只是将个性化的功能留给子类来实现,那么我们先点击MethodValidationPostProcessor类,看下它实现了父类什么方法。

image.png

那么MethodValidationPostProcessor做了什么?便完成了对方法校验的AOP代理???

public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor
        implements InitializingBean {
    //在初始化时,创建了一个Advisor并赋予给父类
    //(AbstractAdvisingBeanProcessor)的advisor属性。
    @Override
    public void afterPropertiesSet() {
        Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
        this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));
    }
    protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
        return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
    }
}

只是在后置处理器定义了一个Advisor,并将其赋予给父类的属性,Spring便可以使用该Advisor对Bean进行代理。

没错,就是这么简单!!!

3. 注解版日志打印实战

@Target({ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyLogAnno {

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

}

定义后置后置处理器(声明advisor),在项目启动的时会对类进行AOP代理。

@Slf4j
@Component
public class MyLogAnnoBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor
        implements InitializingBean {

    private Class<? extends Annotation> myLogAnnoType = MyLogAnno.class;


    @Override
    public void afterPropertiesSet() throws Exception {
        //对带有myLogAnno注解的方法进行拦截
        Pointcut pointcut =AnnotationMatchingPointcut.forMethodAnnotation(myLogAnnoType);
        this.advisor = new DefaultPointcutAdvisor(pointcut,
                (MethodBeforeAdvice) (method, args, target) -> {
                    //打印日志
                    log.info("调用方法:[{}]", method);
                    log.info("方法参数:[{}]", JSON.toJSONString(args));
                    log.info("target类:[{}]", target);
                });
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。