Spring 的组合注解功能,网上有很多文章介绍,不过都是介绍其使用方法,鲜有其原理解析。

组合注解并非 Java 的原生能力。就是说,想通过用「注解A」来注解「注解B」,再用「注解B」 来注解 C(类或方法),就能够使 C 同时拥有「注解A」和「注解B」是行不通的。

示例如下:

先定义注解 SuperAnno:

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SuperAnno {
}

再定义注解 SubAnno,并使用 SuperAnno 注解 SubAnno:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@SuperAnno
@SomeAnno
public @interface SubAnno {
}

定义 Test,使用 SubAnno 注解 Test:

@SubAnno
public class Test { }

测试一下,看看我们能不能拿到 Test 的 SuperAnno 注解:

import java.lang.annotation.Annotation;

public class Main {

    public static void main(String[] args) {
// write your code here
Test test = new Test();
Class<?> cl = test.getClass();
Annotation[] annotations = cl.getAnnotations();
for(Annotation annotation: annotations) {
System.out.println(annotation.annotationType());
}
}
}

打印出来的结果为:

interface com.company.SubAnno

唔,SuperAnno 没有出现。

怎么拿到合并的注解呢?

核心的思路就是拿到注解后,递归获取其上的注解,见下例:

import javax.annotation.*;
import java.lang.annotation.*;
import java.util.ArrayList; public class Main { private ArrayList<Annotation> annos = new ArrayList<>(); public static void main(String[] args) {
// write your code here
Test test = new Test();
Class<?> cl = test.getClass();
Main main = new Main();
main.getAnnos(cl);
for(Annotation anno: main.annos) {
System.out.println(anno.annotationType());
}
} private void getAnnos(Class<?> cl) {
Annotation[] annotations = cl.getAnnotations();
for(Annotation annotation: annotations) {
if (annotation.annotationType() != Deprecated.class &&
annotation.annotationType() != SuppressWarnings.class &&
annotation.annotationType() != Override.class &&
annotation.annotationType() != PostConstruct.class &&
annotation.annotationType() != PreDestroy.class &&
annotation.annotationType() != Resource.class &&
annotation.annotationType() != Resources.class &&
annotation.annotationType() != Generated.class &&
annotation.annotationType() != Target.class &&
annotation.annotationType() != Retention.class &&
annotation.annotationType() != Documented.class &&
annotation.annotationType() != Inherited.class
) {
annos.add(annotation);
getAnnos(annotation.annotationType());
}
}
}
}

Spring Boot 2 实践记录之 组合注解原理的更多相关文章

  1. Spring Boot 2 实践记录之 使用 ConfigurationProperties 注解将配置属性匹配至配置类的属性

    在 Spring Boot 2 实践记录之 条件装配 一文中,曾经使用 Condition 类的 ConditionContext 参数获取了配置文件中的配置属性.但那是因为 Spring 提供了将上 ...

  2. Spring Boot 2 实践记录之 MyBatis 集成的启动时警告信息问题

    按笔者 Spring Boot 2 实践记录之 MySQL + MyBatis 配置 中的方式,如果想正确运行,需要在 Mapper 类上添加 @Mapper 注解. 但是加入此注解之后,启动时会出现 ...

  3. Spring Boot 2 实践记录之 封装依赖及尽可能不创建静态方法以避免在 Service 和 Controller 的单元测试中使用 Powermock

    在前面的文章中(Spring Boot 2 实践记录之 Powermock 和 SpringBootTest)提到了使用 Powermock 结合 SpringBootTest.WebMvcTest ...

  4. Spring Boot 2 实践记录之 Powermock 和 SpringBootTest

    由于要代码中使用了 Date 类生成实时时间,单元测试中需要 Mock Date 的构造方法,以预设其行为,这就要使用到 PowerMock 在 Spring Boot 的测试套件中,需要添加 @Ru ...

  5. Spring Boot 2 实践记录之 Redis 及 Session Redis 配置

    先说 Redis 的配置,在一些网上资料中,Spring Boot 的 Redis 除了添加依赖外,还要使用 XML 或 Java 配置文件做些配置,不过经过实践并不需要. 先在 pom 文件中添加 ...

  6. Spring Boot 2 实践记录之 使用 Powermock、Mockito 对 UUID 进行 mock 单元测试

    由于注册时,需要对输入的密码进行加密,使用到了 UUID.sha1.md 等算法.在单元测试时,使用到了 Powermock,记录如下. 先看下加密算法: import org.apache.comm ...

  7. Spring Boot 2 实践记录之 MySQL + MyBatis 配置

    如果不需要连接池,那么只需要简单的在pom文件中,添加mysql依赖: <dependency> <groupId>mysql</groupId> <arti ...

  8. Spring Boot 2 实践记录之 条件装配

    实验项目是想要使用多种数据库访问方式,比如 JPA 和 MyBatis. 项目的 Service 层业务逻辑相同,只是具体实现代码不同,自然是一组接口,两组实现类的架构比较合理. 不过这种模式却有一个 ...

  9. Spring Boot 最核心的 25 个注解,都是干货!

    学习和应用 Spring Boot 有一些时间了,你们对 Spring Boot 注解了解有多少呢?今天栈长我给大家整理了 Spring Boot 最核心的 25 个注解,都是干货! 你所需具备的基础 ...

随机推荐

  1. struts2标签类别

    要在jsp中使用Struts2的标志,先要指明标志的引入.通过jsp的代码的顶部加入以下的代码: <%@taglib prefix="s" uri="/struts ...

  2. Windows内置系统账户:Local system/Network service/Local Service 区别

    LocalSystem 账户  LocalSystem是预设的拥有本机所有权限的本地账户,这个账户跟通常的用户账户没有任何关联,也没有用户名和密码之类的凭证.这个服务账户可以打开注册表的HKEY_LO ...

  3. html节点操作与事件

    <div id='a' style="width: 500px;height: 500px;background-color: grey;"> </div> ...

  4. Python requests 使用心得

    最近在用requests写一些项目,遇见了一些问题,百度了很多,有些都不太好使,最后看了下requestsAPI文档,才明白了很多,最后项目趋于稳定.看来学东西还是API文档比较权威啊~ 问题场景 项 ...

  5. win7安装SQL2005出现29506错误

    解决方法: 假设下载的文件名为SQLServer2005_SSMSEE.msi ,并且放在F盘根目录下, 新建一个文本文件,输入msiexec /i F:\SQLServer2005_SSMSEE.m ...

  6. MariaDB · 版本特性 · MariaDB 的 GTID 介绍

    本文来自阿里的数据库内核月报,写的很详细,主要是关于mariadb开启gtid之后做主从的方法. 原文连接:http://mysql.taobao.org/monthly/2016/02/08/

  7. Alluxio/Tachyon如何发挥lineage的作用?

    在Spark的RDD中引入过lineage这一概念.指的是RDD之间的依赖.而Alluxio则使用lineage来表示文件之间的依赖.在代码层面,指的是fileID之间的依赖. 代码中的注释指出: * ...

  8. HDU 4499.Cannon 搜索

    Cannon Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Subm ...

  9. Vue-cli 配置开发环境让测试服务器监听所有IP

    //config/inex.js // Various Dev Server settingshost: '0.0.0.0', // can be overwritten by process.env ...

  10. SqlServer和MySql允许脏读的实现方式,提高查询效率

    --Sql Server 允许脏读查询sqlselect * from category with(nolock) --MySql 允许脏读查询sql Mysql没有语法糖,需要原生的sqlSET S ...