JAVA 注解概念及应用
注解的定义
定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
注解在JDK1.5版本被引用,其作为代码的描述或注释,并不直接影响代码运行效果。可以通过反射机制提取注解并进行业务处理。
一、自定义注解
1、注解的定义
@Documented (1)
@Target(ElementType.METHOD) (2)
@Retention(RetentionPolicy.SOURCE) (3)
@Inherited (4)
public @interface DemoAnnotation { (5)
String[] value() default {}; (6)
}
(1) @Documented 表明这个注解应该被 javadoc工具记
(2) @Target 说明了该注解所修饰的对象范围,范围标识如下所示:
类型 | 范围 |
---|---|
ElementType.TYPE | 类、接口(包括注释类型)或枚举声明 |
ElementType.FIELD | 字段声明(包括枚举常量) |
ElementType.METHOD | 方法声明 |
ElementType.PARAMETER | 正式的参数声明 |
ElementType.CONSTRUCTOR | 构造函数声明 |
ElementType.LOCAL_VARIABLE | 局部变量声明 |
ElementType.ANNOTATION_TYPE | 注释类型声明,作为注解的注解 |
ElementType.PACKAGE | 包装声明 |
ElementType.TYPE_PARAMETER | 类型参数声明 (since1.8) |
ElementType.TYPE_USE | 类型的使用 (since1.8) |
(3) @Retention 用来标注注解的声明周期,其可选参数如下:
类型 | 含义 |
---|---|
RetentionPolicy.SOURCE | 只保留在源文件中 |
RetentionPolicy.CLASS | 保留在class文件中,在加载到JVM虚拟机时丢弃 |
RetentionPolicy.RUNTIME | 注解保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解。 |
(4) @Inherited 允许子注解继承该注解
(5) @interface 注解定义标识
(6) String[] value() default {}; 表示注解的参数,可以通过 调用该注解的,对应方法获得设置在注解上的信息
((DemoAnnotation) annotation).value()
以上语法可以获得 DemoAnnotation注解的value属性值
注意:在使用注解对目标进行注释时,当有且仅有value属性需要使用时,可以直接在注释的参数中填写内容,无效使用KEY=VALUE
模式。
2、代码添加注解
根据注解修饰对象的范围,在允许的范围内添加注解
如:
@Override
public int insert(User user) {
userMapper.insert(user);
return user.getId();
}
示例中的 @Override 注解为JDK内置注解,用于源码阶段的方法覆盖,其功能为覆盖接口中的 insert(User user) 方法。
3、注解的业务处理
针对 @Retention
为 RetentionPolicy.RUNTIME
的注解,提供注解处理器功能,以实现特定业务逻辑
首先,可以通过Class对象的 isAnnotationPresent()
方法判断他是否应用了某个注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
然后,通过Class对象的 getAnnotation()
或 getAnnotations()
方法获取 Annotation
对象或对象数组
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
public Annotation[] getAnnotations() {}
以下为注解处理器示例代码
首先,定义一个注解
package org.items.annotation;
/**
* @author tysite
* Date Created 2019/5/30
*/
import java.lang.annotation.*;
@Documented
@Target(value={ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface DemoAnnotation {
String value() default "demo";
String color() default "Red";
}
然后,将注解注释到含有main方法的类中
package org.items.annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author tysite
* Date Created 2019/5/30
*/
@DemoAnnotation(value = "猪", color = "黑")
public class AnnotationTest {
public static void main(String[] args) {
//验证注解是否存在
if (AnnotationTest.class.isAnnotationPresent(DemoAnnotation.class)) {
DemoAnnotation annotation = AnnotationTest.class.getAnnotation(DemoAnnotation.class);
System.out.println("类 [AnnotationTest] 的 注解是 =>\t" + annotation.color() + " " + annotation.value());
} else {
System.out.println("类 [AnnotationTest] 无 DemoAnnotation 注解");
}
try {
//获取指定属性
Field field = AnnotationTest.class.getDeclaredField("demo");
//解决私有成员变量获取限制问题
field.setAccessible(true);
if (field.isAnnotationPresent(DemoAnnotation.class)){
DemoAnnotation demoAnnotation = field.getAnnotation(DemoAnnotation.class);
System.out.println("成员变量 [demo] 的 注解是 =>\t" + demoAnnotation.color()+" "+demoAnnotation.value());
} else {
System.out.println("成员变量 [demo] 无DemoAnnotation注解");
}
Method method = AnnotationTest.class.getDeclaredMethod("showAnnotation");
if (method.isAnnotationPresent(DemoAnnotation.class)) {
DemoAnnotation methodAnnotation = method.getAnnotation(DemoAnnotation.class);
System.out.println("私有方法 [showAnnotation] 的 注解是 =>\t" + methodAnnotation.color()+" "+methodAnnotation.value());
} else {
System.out.println("私有方法 [showAnnotation] 无DemoAnnotation注解");
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
}
}
@DemoAnnotation(value = "兔", color = "白")
String demo;
@DemoAnnotation(value = "猫", color = "橘")
private void showAnnotation() {}
}
最后,执行该main方法,显示注解结果
类 [AnnotationTest] 的 注解是 => 黑 猪
成员变量 [demo] 的 注解是 => 白 兔
私有方法 [showAnnotation] 的 注解是 => 橘 猫
二、常用注解
1、JDK提供的注解
注解名称 | 注解功能 |
---|---|
@Override | 用于重写父类的方法 或 实现接口类的方法时,标记方法覆盖关系 |
@Deprecated | 标记被注释目标 (类、方法、属性等) 已弃用,不建议继续使用 |
@suppressWarnings | 编译时忽略被注释目标的警告 |
@FunctionalInterface | (jdk1.8更新) 表示:用来指定某个接口必须是函数式接口,否则就会编译出错。 |
2、SpringBoot 提供的常用注解
注解名称 | 注解功能 |
---|---|
@EnableAutoConfiguration | 可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。参考文献:SpringBoot之@EnableAutoConfiguration注解 |
@ComponentScan | 组件扫描注解,用于自动发现和装配Bean。相当于配置文件的<context:component-scan> |
@Configuration | Spring Java配置注解,其作用相当于一个xml配置文件 |
@ConfigurationProperties | 配置属性前缀设置注解 |
@SpringBootApplication | 该注解为 @EnableAutoConfiguration、@Configuration、@ComponentScan的集合,应用于SpringBoot项目的启动类 |
@Bean | 该注解标注相当于XML中配置的Bean |
@Value | SpringBoot 配置文件属性赋值注解,可以是常量、application.propreties属性或表达式 |
@Repository | 用于标注数据访问组件的注解 |
@Service | Service层组件注解 |
@Component | 泛指组件注解,不进行具体分类,建议对可分类的组件不要使用该注解,而应该使用诸如@Service这种具有分类含义的注解。 |
@Autowired | @Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。 |
@Qualifier | 当有多个同一类型的Bean时,可以用@Qualifier(“name”)来指定。与@Autowired配合使用 |
@Controller | 控制器类定义注解 |
@RequestMapping | 请求处理注解, 用于设定接收请求的类型、URL路径、请求参数等 |
@ResponseBody | 该注解标注表示方法返回数据写入到 HTTP Response body 中,并以json结构返回数据 |
@RestController | 该注解为@Controller 和 @ResponseBody的整合注解 |
@ExceptionHandler | 异常处理注解,当该注解标注方法时,如遇到注解value标记的注解抛出,则以被注释方法进行处理 |
注意:springboot还提供了很多其他的注解,不在此进行一一列举,此处仅列举出相对常用的注解
三、Spring 的 @AliasFor 说明
该注解用于实现Spring框架中,注解别名设定,以便注解的灵活应用,具体细节请参考以下文章
https://blog.youkuaiyun.com/wolfcode_cn/article/details/80654730
如有错误,欢迎大家斧正