Java注解使用案例总结
一、java注解说明和自定义
1.1官网解释
Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的。Java 注解是从 Java5 开始添加到 Java 的。
通俗理解注解像是一个标记,可以标记在类、属性、方法等,通过反射机制动态获取标记的值,然后通过自定义注解处理器,实现自己的业务逻辑。
1.2注解分类
此处列举java7的常用注解,java8以后有新的内置注解。
1.2.1内置普通注解
作用于普通类和接口的注解
注解 | 说明 |
---|---|
@Deprecated | 主要标记过去的方法和类。如果使用标记的方法,会报编译警告 |
@Override | 检查该方法是否是重写方法 |
@SuppressWarnings | 忽视编译器的编译警告 |
1.2.2内置元注解
作用与自定义注解(Annotation)时使用,相当于自定注解时使用的注解。
注解 | 说明 |
---|---|
@Documented | 表示自定义注解是否通过javadoc生成到文档中 |
@Inherited | 它所标注的Annotation具有继承性,标记此注解类的子类也具有父类的注解。 |
@Retention | 用来说明该注解类的生命周期。结合枚举RetentionPolicy控制生命阶段。源码(java)、字节码(class)、运行(JVM) |
@Target | 用来声明注解的使用范围。集合ElementType属性控制使用范围是方法、类、字段等 |
1.2.3自定义注解
a) 注解基本语法
自定义注解语法和接口类似,通过@interface表示
// 不添加@Target。默认全部
@Target(ElementType.TYPE)
// 不添加@Retention。默认为RetentionPolicy.CLASS
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation{
String value() default "";
}
b) 注解范围和生命周期
@Target结合ElementType控制注解的使用范围,比如只能标记方法或者只能标记类。
java8以后有新增,此处列举java7常用属性。
package java.lang.annotation;
public enum ElementType {
TYPE, /**类、接口(包括批注类型)、枚举 */
FIELD, /** 字段声明 */
METHOD, /** 方法声明 */
PARAMETER,/** 形参数声明 */
CONSTRUCTOR, /** 构造函数声明 */
LOCAL_VARIABLE, /** 局部变量声明 */
ANNOTATION_TYPE, /** 注释类型声明 */
PACKAGE,/** 包声明 */
}
@Retention结合RetentionPolicy控制注解的生命阶段
package java.lang.annotation;
public enum RetentionPolicy {
/**
* 源码阶段。java源码存在,经过编译器处理,编译成class后丢弃
*/
SOURCE,
/**
* 字节码阶段。java源码和编译成class时存在,JVM在运行时不保留注释。这是默认行为
*/
CLASS,
/**
* 运行阶段。。java源码和编译成class时存在,并且在运行时由JVM保留,因此可以反射地读取它们
*/
RUNTIME
}
二、自定义注解使用案例
前面初步说明注解的定义,此处说明注解的使用,主要通过java反射操作。
RetentionPolicy生命周期说明
可以通过反编译工具查看注解源码编译后的对应的class文件
级别 | 编译后 | 运行期 | 说明 |
---|---|---|---|
SOURCE | 不存在 | NULL | 源码编译后,字节码文件中不存在注解代码 |
CLASS | 存在 | NULL | 字节码文件存在注解代码,运行期间无法通过反射无法获取对象 |
RUNTIME | 存在 | 注解对象 | 字节码文件存在注解代码,运行期间无法可以通过反射获取注解对象 |
2.1注解在运行期调用的案例
定义注解并标记生命周期和范围,通过自定义处理器解决业务问题。
案例中注解生命周期使用RetentionPolicy.RUNTIME,所以可以通过反射动态获取注解的值。
package com.cs.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 模拟SpringMVC中的Controller注解
*/
// 指定在类、接口头部标记,如果其他地方编译报错
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
/**
* 请求模块路径
*/
String value() ;
}
package com.cs.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 模拟SpringMVC中的RequestMapping注解
*/
// 指定在方法头部标记,如果其他地方编译报错
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
/**
* 请求api路径
*/
String value();
/**
* 请求方式
*/
String[] method() default {};
}
package com.cs.spring;
import com.cs.spring.annotation.Controller;
import com.cs.spring.annotation.RequestMapping;
/**
* 模拟api接口
*/
@Controller("/user")
class UserRest {
@RequestMapping(value = "/addUser", method = {"POST", "GET"})
public void addUser() {
System.out.println("addUser");
}
}
public class Test {
public static void main(String[] args) throws NoSuchMethodException {
Controller controller = UserRest.class.getAnnotation(Controller.class);
System.out.println("Controller注解 value=" + controller.value());
RequestMapping requestMapping = UserRest.class.getMethod("addUser").getAnnotation(RequestMapping.class);
System.out.println("RequestMapping注解 value=" + requestMapping.value() + " method=" + requestMapping.method()[0]);
}
}
运行结果
2.2注解在编译器调用的案例
java6 以后提供了编译期处理注解的方式,通过继承AbstractProcessor(注解处理器)类实现。
lombok采用的就是此方式
TODO