注:该部分内容包含注解基本知识的讲解,如果对学习过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
网友评论