- 被@Inherited元注解标注的注解标注在类上的时候,子类可以继承父类上的注解。注解未被@Inherited元注解标注的,该注解标注在类上时,子类不会继承父类上标注的注解。注解标注在接口上,其子类及子接口都不会继承该注解注解标注在类或接口方法上,其子类重写该方法不会继承父类或接口中方法上标记的注解
二、注解标注在父类、接口、父类方法、接口方法上如何通过子类拦截,首先了解下几个核心类根据注解继承的特性,我们再做AOP切面拦截的时候会遇到拦截不到的问题,今天我们就讲解下对这些特殊情况如何解决,对源码不做过渡深入的讲解。
AnnotationMatchingPointcut切点类是用来判定是否需要拦截类、父类、实现接口中方法,其中一共四个构造函数如下:
public AnnotationMatchingPointcut(Class extends Annotation> classAnnotationType) { this(classAnnotationType, false); } public AnnotationMatchingPointcut(Class extends Annotation> classAnnotationType, boolean checkInherited) { this.classFilter = new AnnotationClassFilter(classAnnotationType, checkInherited); this.methodMatcher = MethodMatcher.TRUE; } public AnnotationMatchingPointcut(@Nullable Class extends Annotation> classAnnotationType, @Nullable Class extends Annotation> methodAnnotationType) { this(classAnnotationType, methodAnnotationType, false); } public AnnotationMatchingPointcut(@Nullable Class extends Annotation> classAnnotationType, @Nullable Class extends Annotation> methodAnnotationType, boolean checkInherited) { Assert.isTrue((classAnnotationType != null || methodAnnotationType != null), "Either Class annotation type or Method annotation type needs to be specified (or both)"); if (classAnnotationType != null) { this.classFilter = new AnnotationClassFilter(classAnnotationType, checkInherited); } else { this.classFilter = new AnnotationCandidateClassFilter(methodAnnotationType); } if (methodAnnotationType != null) { this.methodMatcher = new AnnotationMethodMatcher(methodAnnotationType, checkInherited); } else { this.methodMatcher = MethodMatcher.TRUE; } }
以上四个构造函数,支持仅标记在类上注解、仅标记方法上的注解、即指定标记类上且标记在方法上的注解(是否拦截父类及接口上标记的方法)三种构造方式。
通过上述四个构造函数可以构造如下几种切点类型:
注解标注在当前类,只拦截当前类的方法注解标注在当前类的父类上,拦截父类及子类中的方法注解标注在当前类实现的接口上 ,拦截接口方法的实现方法注解标注在当前类的方法上,拦截当前类的方法注解标注在当前类父类或接口的方法上,拦截父类的方法或者当前类实现方法。
通过上述切点可以构造出我们需要的大多数场景,如果需要更灵活的实现还需要结合ComposablePointcut类,此类可以实现类级别标注的交集、并集,方法级别的交集、并集,切点级别的交集并集。
三、切点实现案例@Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public Advisor mybatisLogAdvisor(MybatisProperties properties) { //限定类级别的切点 Pointcut cpc = new AnnotationMatchingPointcut(Mapper.class, properties.isCheckClassInherited()); //限定方法级别的切点 Pointcut mpc = new AnnotationMatchingPointcut(null, Mapper.class, properties.isCheckMethodInherited()); //组合切面(并集),一、ClassFilter只要有一个符合条件就返回true,二、 Pointcut pointcut = new ComposablePointcut(cpc).union(mpc); //mybatis日志拦截切面 MethodInterceptor interceptor = new MybatisMethodInterceptor(); //切面增强类 AnnotationPointcutAdvisor advisor = new AnnotationPointcutAdvisor(interceptor, pointcut); //切面优先级顺序 advisor.setOrder(AopOrderInfo.MYBATIS); return advisor; }
此拦截器可以实现对标注了Mapper方法进行日志拦截,具体实现可以参考GitHub源码
四、上述向上查询父类、父接口及其方法的核心是AnnotatedElementUtils工具类,示例参考如下:
//返回当前类或父类或接口方法上标注的注解对象 targetDataSource = AnnotatedElementUtils.findMergedAnnotation(method, TargetDataSource.class); //返回当前类或父类或接口上标注的注解对象 targetDataSource = AnnotatedElementUtils.findMergedAnnotation(method.getDeclaringClass(), TargetDataSource.class);
GitHub地址:https://github.com/mingyang66/spring-parent
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)