Java注解小总结

背景

最近想做Spring Boot的总结,众所周知,Spring有不少自己的注解,Spring Boot更甚,它的口号是做到零配置,目的也是为了避免配置零散到多个地方的场景。那么如果想要深入了解Spring Boot的话势必要知道它读取到注解后做哪些处理,这些后面会总结。这篇文章算是前提吧。顺势而为。

什么是注解

官方定义如下:

注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注解对于代码的运行效果没有直接影响

注解有许多用处,主要如下:
- 提供信息给编译器: 编译器可以利用注解来探测错误和警告信息
- 编译阶段时的处理: 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。
- 运行时的处理: 某些注解可以在程序运行的时候接受代码的提取


有些小伙伴可能一看到元数据就已经有些懵了,这里先简单介绍一下元数据:元数据即描述数据的数据。比如说我们描述windows系统里面的一个文件,它是由很多属性定义的,像大小、编码、权限等等,这些就叫做它的元数据。如果想更深入理解可以看下wiki,说的实在是太太太详细了。

回到主题,对于官方定义我觉得可以一句话一句话的理解,参照我定义中标出的关键语句。

  • 元数据

    根据我上面元数据粗浅的解释,我们得出注解也是用来定义或者描述某个东西的。

  • 提供数据

    元数据可以定义并提供一些我们想要传达的数据。

  • 解释程序代码

    程序代码就是被定义或者描述的那个主体。

  • 并非是所解释的代码本身的一部分

    这句话其实跟上面的解释是同样的意思,我们可以想一想我们还有其他解释程序代码的方式比如说注释,这样就很容易理解它们并不是代码的一部分这个含义。

  • 对于代码的运行效果没有直接影响

    我猜测大家大部分对这句话抱有怀疑。会想“不是这样吧,只有我类上标明@service后才能被Spring扫描到呀,怎么就说对代码没有影响了?”。其实换句话说可能大家就能更好的理解了,注解自身不会对代码产生任何影响,但是我们可以读取注解及其提供的数据来编写代码来对系统造成影响。还是上面的例子,@service本身没有什么作用,但是Spring框架中有部分代码会依据它加载实例,所以我们看结果是它产生了影响。

最后三句话是简单说了一下注解可应用的主要场景,分别对应了不同的三个周期,周期的问题下面篇幅说明。

注解的定义

定义注解其实很简单,就跟定义一个类或者接口区别不是很大,只是把class | interface换为@interface

同时定义注解我们还需要引入另一个概念,就是元注解

元注解

大家估计现在看名字就能猜出元注解的作用了,就是修饰描述注解的注解。

元注解有以下五种。

@Retention

Retention翻译过来是保留的意思。它描述的就是被修饰注解的生命周期。

它的取值如下,这里我们可以跟上一节里面它的主要用途来对应着看:

  • RetentionPolicy.SOURCE

    被修饰注解只能在源码阶段保留,不会进入编译器进行的编译期。

  • RetentionPolicy.CLASS

    被修饰注解只能保留到编译期,不会加载到JVM。

  • RetentionPolicy.RUNTIME

    注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

@Documented

其作用是能够将注解中的元素包含到 Javadoc 中去。

@Target

其作用是指定被修饰注解可用到哪些地方。

取值如下:

  • ElementType.ANNOTATION_TYPE

    可以给一个注解进行注解

  • ElementType.CONSTRUCTOR

    可以给构造方法进行注解

  • ElementType.FIELD

    可以给属性进行注解

  • ElementType.LOCAL_VARIABLE

    可以给局部变量进行注解

  • ElementType.METHOD

    可以给方法进行注解

  • ElementType.PACKAGE

    可以给一个包进行注解

  • ElementType.PARAMETER

    可以给一个方法内的参数进行注解

  • ElementType.TYPE

    可以给一个类型进行注解,比如类、接口、枚举

@Inherited

继承的意思。如果超类被某个注解修饰,而这个注解被@Inherited修饰,那么继承超类的子类默认也被这个注解修饰。

@Repeatable

其为Java 1.8版本新引入元注解。场景可以举例说明,比如各个公司都有职位设置,而且也有兼职的这种制度,如果我们定义一个注解为@Role,属性是职位那么可能就有@Role("manager")或者@Role("developer"),而我们修饰的那个人可能就是一个做开发的经理。

代码举例如下:

@interface Roles {
    Role[]  value();
}


@Repeatable(Roles.class)
@interface Role{
    String value() default "";
}


@Role("manager")
@Role("developer")
public class SuperMan{

}

注解的属性

在注解的定义中我们知道注解是可以提供数据的,而这个方式就是定义属性。

这个属性的定义跟我们正常的认知不太一样,它采用的是定义无参无方法体类似定义方法的方式来定义的。其中方法名就是属性的名字,而返回值就是属性的类型。

而且可以通过default关键字来定义默认值。

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

    public int id() default -1;

    public String msg() default "hello world";

}

如上所示,我们定义了一个名为MyAnnotation的注解,它包含两个属性且都有默认值。

可以这样使用:

@MyAnnotation(id=1, msg="msg")
public class MyClass() {}

//因为注解中有默认值,所以我们也可以不自定义属性值
@MyAnnotation()
public class MyClass() {}

//因为有些注解可能只有一个value属性,那直接引号就可以
@OnlyValue("bye")
public class MyClass() {}

//有些注解一个属性都没有,那就完全可以不带括号
@NoAttribute
public class MyClass() {}

如何获取注解

我们知道注解的生命周期主要有三种,而我们大部分用的都是Runtime。不同周期获取注解的方式是不一样的,我们这版先主要讨论Runtime期间的获取,其他的以后再扩充。

而运行期间进行获取的方式主要是反射(有没有其他方式没有研究过,如果知道其他的方式大家可以留言补充)。作为开发人员的明显看代码更形象。如下所示:

@MyAnnotation(msg="hello")
public class Test {
    
    @Check(value="hi")
    int a;

    @Perform
    public void testMethod(){}

    @SuppressWarnings("deprecation")
    public void test1(){
        Hero hero = new Hero();
        hero.say();
        hero.speak();
    }

    public static void main(String[] args) {
        boolean hasAnnotation = Test.class.isAnnotationPresent(MyAnnotation.class);
        if ( hasAnnotation ) {
            MyAnnotation testAnnotation = Test.class.getAnnotation(MyAnnotation.class);
            //获取类的注解
            System.out.println("id:"+testAnnotation.id());
            System.out.println("msg:"+testAnnotation.msg());
        }
        try {
            Field a = Test.class.getDeclaredField("a");
            a.setAccessible(true);
            //获取一个成员变量上的注解
            Check check = a.getAnnotation(Check.class);

            if ( check != null ) {
                System.out.println("check value:"+check.value());
            }
            
            Method testMethod = Test.class.getDeclaredMethod("testMethod");
            if ( testMethod != null ) {
                // 获取方法中的注解
                Annotation[] ans = testMethod.getAnnotations();
                for( int i = 0;i < ans.length;i++) {
                    System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
                }
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.out.println(e.getMessage());
        } 
    }
}

参考资料

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,873评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,483评论 1 306
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,525评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,595评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,018评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,958评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,118评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,873评论 0 208
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,643评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,813评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,293评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,615评论 3 262
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,306评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,170评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,968评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,107评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,894评论 2 278

推荐阅读更多精彩内容