Spring Boot 注解—基本知识

注:该部分内容包含注解基本知识的讲解,如果对学习过java注解的同学可以直接跳过注解讲解部分,直接查看下一小节Spring Boot 注解—常用注解即可,如果对Spring Boot或者Spring MVC也比较熟悉的同学可以跳过该节。

注解

我对注解的理解是,注解就是一种标记,通过这个标记我们可以获取一定的关联信息。

为什么要学习注解

在这里主要是现有的框架中存在大量的注解,我们需要知道主键的基本概念以及使用方法,能够更加理解这些框架,另一方面,学习注解,我们可以开发自定义注解使得代码更加简洁清晰。

注解的分类

1、按照声明周期

源码注解(仅在.java文件中存在,经过编译就不存在了)
编译时注解(在编译时起作用,即在.class文件中也仍然存在)
运行时注解(在运行阶段起作用,有时会影响程序的运行逻辑)

2、按照来源

JDK自带的注解
第三方框架注解
自定义注解

3、元注解(对注解进行注解的注解)

注解的语法

我们首先看一下@SpringBootApplication注解,这是SpringBoot HelloWorld程序中的主类的主键,我们看一下他的源码

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
        @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    //...
}

我们通过该主键就可以帮我们自动配置好SpringBoot应用程序,通过包名我们可以看到@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan这三个注解也是属于Spring自己的注解,所以@SpringBootApplication注解是一个组合注解,去除这些组合信息,以及不必要的代码,我们再来看一下该注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface SpringBootApplication {
    //...
}

这就是一个注解的基本框架,首先我们知道,定义一个主键的关键字是@interface,另外我们还看到有@Target、@Retention、@Documented、@Inherited四个注解就是标注在注解上的注解即元注解,下面我们对这四个注解进行详细的讲解:
@Target:注解的作用目标,即作用域
可以看到它的取值是一个枚举类型,我们看一下该枚举源码:

public enum ElementType {
    /**Class, interface (including annotation type), or enum declaration*/
    /** 类,接口   重要*/
    TYPE,
    
    /** Field declaration (includes enum constants) */
    /** 字段声明  重要*/
    FIELD,

    /** Method declaration */
     /** 方法声明  重要*/
    METHOD,

    /** Formal parameter declaration */
    /** 参数声明  重要*/
    PARAMETER,

    /** Constructor declaration */
    /** 构造函数声明  重要*/
    CONSTRUCTOR,

    /** Local variable declaration */
    /** 构局部变量声明*/
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    /** 注解类型声明*/
    ANNOTATION_TYPE,

    /** Package declaration*/
    /** 包声明*/
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

注解的作用域可以来自这些值

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

通过查看@Target的源码可以知道,其取值是一个ElementType[]数组所以,其值也可以是ElementType中的组合例如

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
  //...
}

Spring中的@Bean注解的作用域就是可以是在方法声明中或者注解类型声明中。
@Retention:表示注解的声明周期,即可以是源码阶段、编译时、运行时,我们可以看一下RetentionPolicy枚举的源码

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler. 
     * 源码阶段
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     * 编译时阶段
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     * 运行时阶段
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

@Documented:标识在生成javadoc文档时包含该注解信息
@Inherited:标识允许子类继承
注解的成员:注解的成员以无参无异常的方法进行声明,可以指定默认值,成员的类型包括基本数据类型以及String、Class、Annotation、Enumeration

注解的使用

@<注解名>(<成员1>=<成员1值>,<成员2>=<成员2值>,...)

注解解析

注解解析主要是利用反射进行解析的下面我们看一个简单的例子

package com.example.demo.annotation;

import java.lang.annotation.*;
/**
 * 描述:@Description用来对类或者方法进行注释说明的注解
 */
@Target({ElementType.TYPE,ElementType.METHOD})//作用域:类、方法
@Retention(RetentionPolicy.RUNTIME)//生命周期  运行时
@Inherited//允许继承
@Documented//生成javadoc描述符
public @interface Description {
    String value();
}
package com.example.demo.annotation;

/**
 * 描述:普通类,用来使用@Description注解
 */
@Description("用户类")
public class User {

    private String username;

    private String password;

    @Description("用户名")
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
    @Description("密码")
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
package com.example.demo.annotation;

import java.lang.reflect.Method;

/**
 * 描述:解析注解
 */
public class ParseAnnotation {

    public static void main(String[] args) throws ClassNotFoundException {
        //利用反射获取类信息
        Class c=Class.forName("com.example.demo.annotation.User");
        //判断是否为@Description注解标注的类
        boolean isDescriptionAnnotationClass=c.isAnnotationPresent(Description.class);
        if(isDescriptionAnnotationClass){
            //如果是获取注解信息
            Description description= (Description) c.getAnnotation(Description.class);
            //输出
            System.out.println(description.value());
        }
        //利用反射获取所有方法信息
        Method [] ms=c.getMethods();
        for (Method m:ms){
            //判断是否为@Description注解标注的方法
            boolean isDescriptionAnnotationMethod=m.isAnnotationPresent(Description.class);
            if(isDescriptionAnnotationMethod){
                //如果是获取注解信息
                Description description= (Description) m.getAnnotation(Description.class);
                //输出
                System.out.println(description.value());
            }
        }
    }
}

运行结果:


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

推荐阅读更多精彩内容