Spring完成AOP代理有兩種途徑,一種依賴
AbstractAutoProxyCreator
來完成自動(dòng)代理(例如事務(wù)就是依賴其子類完成代理)陨溅。另一種是依賴AbstractAdvisingBeanPostProcessor
來完成代理(例如@Async就是依賴其子類完成代理)。
使用AbstractAutoProxyCreator
完成AOP代理埂伦,只需要將Advisor
注冊(cè)到Spring容器中潦牛。而AbstractAdvisingBeanPostProcessor
需要使用其子類來完成AOP代理。
1. AbstractAdvisingBeanPostProcessor子類
Spring使用模板方法模式狠角,只是將個(gè)性化的功能留給子類來實(shí)現(xiàn),那么我們先點(diǎn)擊MethodValidationPostProcessor
類蚪腋,看下它實(shí)現(xiàn)了父類什么方法丰歌。
那么MethodValidationPostProcessor
做了什么?便完成了對(duì)方法校驗(yàn)的AOP代理屉凯?立帖??
public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor
implements InitializingBean {
//在初始化時(shí)悠砚,創(chuàng)建了一個(gè)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());
}
}
只是在后置處理器定義了一個(gè)Advisor,并將其賦予給父類的屬性,Spring便可以使用該Advisor對(duì)Bean進(jìn)行代理绑咱。
沒錯(cuò)绰筛,就是這么簡(jiǎn)單!C枞凇铝噩!
3. 注解版日志打印實(shí)戰(zhàn)
@Target({ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyLogAnno {
Class<?>[] value() default {};
}
定義后置后置處理器(聲明advisor),在項(xiàng)目啟動(dòng)的時(shí)會(huì)對(duì)類進(jìn)行AOP代理窿克。
@Slf4j
@Component
public class MyLogAnnoBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor
implements InitializingBean {
private Class<? extends Annotation> myLogAnnoType = MyLogAnno.class;
@Override
public void afterPropertiesSet() throws Exception {
//對(duì)帶有myLogAnno注解的方法進(jìn)行攔截
Pointcut pointcut =AnnotationMatchingPointcut.forMethodAnnotation(myLogAnnoType);
this.advisor = new DefaultPointcutAdvisor(pointcut,
(MethodBeforeAdvice) (method, args, target) -> {
//打印日志
log.info("調(diào)用方法:[{}]", method);
log.info("方法參數(shù):[{}]", JSON.toJSONString(args));
log.info("target類:[{}]", target);
});
}
}