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. 代码实现
- 定义注解
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnno {
Class<?>[] value() default {};
}
- 定义切点
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;
}
}
- 定义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将会加强方法。