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. centos 6.5 ftp服务配置及客户端使用

    一.ftp服务简介 FTP是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”.用于Internet上的控制文件的双向传输.同时,它也是一个应用程序(Ap ...

  2. OC 和 swift 冒泡排序

    swift 版 var numbers = [17, 28, 36, 15, 39] print("排序前\(numbers)") for i in 0..<numbers. ...

  3. Html的Padding,Margin自己理解图

    Html的Padding,Margin自己理解图.

  4. 开发中经典sql总结

    1.说明:显示文章.提交人和最后回复时间 select a.title,a.username,b.adddate ,(select max(adddate) from table where tabl ...

  5. 欲哭无泪的p-value = 0.051 | 做几次重复能得到较低的p-value

    欲哭无泪的p-value = 0.051 | 做几次重复能得到较低的p-value 已有 1469 次阅读 2017-12-15 14:12 |个人分类:RNA-seq|系统分类:科普集锦|关键词:R ...

  6. 洛谷 P2986 [USACO10MAR]伟大的奶牛聚集(树形动规)

    题目描述 Bessie is planning the annual Great Cow Gathering for cows all across the country and, of cours ...

  7. ShowMsg函数

    ShowMsg():显示提示信息,跳转到相应页面 例子: ShowMsg(,);

  8. 前后台交互(打开前端页面,不传递任何数据,发送ajax请求)

    1.打开前端,不传递任何数据 <script src="./jquery.min.js"></script> <script> $(docume ...

  9. 7. Debug on local machine

    Step 1:

  10. 使用JConsole监控HBase内存状态

    使用JConsole或者VisualVM等工具监控HBase状态时,需要修改HBase的配置文件,以解决随机端口问题. 文件名:hbase-env.sh export HBASE_JMX_BASE=& ...