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. linux - 文件拆分

    核心: split 例如,把一个文件以10万行为单位拆分文件, 并且以perfix作为前缀,3位数数字,从000开始递增 split -l 100000 filename.txt -d -a 3 pe ...

  2. 兼容IE7、IE8、IE9的input type="number"插件

    IE11版本好像才兼容input type="number",但是现在Win7版本操作系统下,很多人的IE版本都是IE7/8/9,所以为了体验就自己写了一个小插件,支持设置最大值. ...

  3. 用Git发布版本笔记

    1.首先,如果是发布的Develop分支,先从master建立HotFix分支,提交到git并指定关联关系 (git branch --set-upstream-to=D..) 2.对H分支进行功能完 ...

  4. curl: (60) SSL certificate problem: unable to get local issuer certificate 错误

    今天同事做微信管理的项目,请求接口返回如下错误SSL certificate problem: unable to get local issuer certificate. 此问题的出现是由于没有配 ...

  5. php 输出缓冲 Output Control

    关于php的输出缓冲,首先要说明的是什么是缓冲(buffer),比如我们通过记事本在编辑文件的时候,并不是我们输入了内容,系统就会立刻向磁盘中写入数据.只有我们在保存文件后,系统才会向磁盘写入数据.而 ...

  6. mysql优化概述2

    一.索引的概念 利用关键字,就是记录的部分数据(某个字段,某些字段,某个字段的一部份),建立与记录位置的对应关系,就是索引.索引的关键字一定是排序的. 二.索引的类型 mysql支持四种索引: 1.主 ...

  7. MongoDB 3.0 Release Notes

    MongoDB 3.0支持WiredTiger存储引擎,提供可插拔存储引擎API,新增SCRAM-SHA-1认证机制,改进explain功能. 可插拔存储引擎API 允许第三方为MongoDB开发存储 ...

  8. 在Jmeter中用JAVA获取Rolling Date

    Rolling Date_Weekly import java.util.*; import java.text.SimpleDateFormat; import java.text.DateForm ...

  9. msys2 git status显示中文文件名问题

    git config [--global] core.quotepath off https://stackoverflow.com/questions/5854967/git-msysgit-acc ...

  10. 2018.07.12 atcoder Choosing Points(数学分析好题)

    传送门 一句话题意:给出n,d1,d2" role="presentation" style="position: relative;">n,d ...