以前在xml中配置spring aop,切点用一个表达式定义,在大多数场景中,我们不想包名或方法名遵循统一的规则,要实现灵活的定义切点,比如自定义一个注解,标注在那个方法上,就切那个方法。下面的内容刚好符合上面的场景,当然只是基本的代码模板,你可以根据你的业务需求进行更复杂的封装,这里只是提取出通用的代码。
定义PointcutAdvisor实现
这里一般都是继承AbstractPointcutAdvisor类,需要子类提供Pointcut和Advice实例
public class MyAnnotaionAdvisor extends AbstractPointcutAdvisor{
private Advice advice;
private Pointcut pointcut;
//传入你自定义注解和MethodInterceptor实现
public MyAnnotaionAdvisor (Class<? extends Annotation> 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<? extends Annotation> 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<? extends Annotation> 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中灵活配置,怎么实现?不着急,后面慢慢写。