点击上方“JavaEdge”,关注公众号
设为“星标”,好文章不错过!
注解可为Java代码提供元数据,框架也会利用注解暴露功能,比如Spring框架中的@Service、@Controller。
框架可通过类或方法等元素上标记的注解了解它们的功能或特性,并以此来启用或执行相应的功能。通过注解而非API调用来配置框架,属于声明式交互,可以简化框架配置,也可和框架解耦。
你也许认为既然类继承后,类的注解也可继承,那么子类重写父类方法后,父类方法上的注解也能作用于子类,那你确定吗?
1 show me code
自定义注解
定义被该注解标记的类Parent,设置value为Class字符串,foo方法也标记了@MyAnnotation注解
子类Child继承Parent父类,并重写父类的foo方法,子类的foo方法和类上都没有@MyAnnotation注解。
通过反射分别获取Parent和Child的类和方法的注解信息,并输出注解的value属性的值(如果注解不存在则输出空字符串):
日志输出
父类的类和方法上的注解都可正确获得,但子类的类和方法却不能。即子类及子类的方法,无法自动继承父类和父类方法上的注解。
2 @Inherited元注解实现注解的继承
日志输出
子类可以获得父类类上的注解;子类的foo虽是重写父类方法,并且注解本身也支持继承,但还是无法获得方法上的注解。
因为@Inherited只能实现类上的注解继承。
3 方法上注解的继承
可通过反射在继承链上找到方法上的注解。但实现很繁琐,还需要考虑桥接方法。
幸好Spring提供了AnnotatedElementUtils类。
3.1 AnnotatedElementUtils工具类
对@Inherited的支持
遵循get语义的方法将遵循Java的@Inherited注解的约定,除了在本地声明的批注(包括自定义组成的注解)优于继承的注解之外。相反,遵循find语义的方法将完全忽略@Inherited的存在,因为find搜索算法手动遍历类型和方法层次结构,从而隐式支持注解继承,而无需@Inherited。
Find V.S Get 语义
此类中的方法使用的搜索算法遵循find或get语义。
Get 语义
仅限于搜索存在于AnnotatedElement上的注解(即在本地声明或继承)或在AnnotatedElement上方的注解层次结构中声明的注释。
Find 语义
更加详尽,提供了获取语义以及对以下内容的支持:
搜索接口(如果带注释的元素是类)
搜索超类(如果带注释的元素是一个类)
解析桥接方法(如果带注释的元素是方法)
如果带注解的元素是方法,则在接口中搜索方法
如果带注解的元素是方法,则在超类中搜索方法
如下俩方法其实也很相像,有何区别呢?
findAllMergedAnnotations
Find 对应SearchStrategy.TYPE_HIERARCHY
其findMergedAnnotation方法可找出父类和接口、父类方法和接口方法上的注解,并可以处理桥接方法,实现一键找到继承链的注解:
getAllMergedAnnotations
Get对应SearchStrategy.INHERITED_ANNOTATIONS:
4 Spring的@Service、@Controller会支持继承吗?
我们假设继承后,RequestMapping对应的在父子类都能找到,处理起来肯定会很麻烦,在加上这几个注解默认都是单例的,所以是不能继承的。其实spring 官方对此也有回应。
参考
https://github.com/spring-projects/spring-framework/issues/8859
目前交流群已有800+人,旨在促进技术交流,可关注公众号添加笔者微信邀请进群
喜欢文章,点个“在看、点赞、分享”素质三连支持一下~