java安全学习之注解
2021.03.30
le31ei
WebSec
 热度
℃
0x01 什么是注解
注解是在java中类、方法、参数前面的一种特殊的注释。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package com.itranswarp.learnjava;
import javax.annotation.PostConstruct;
public class Demo1 {
int n;
@PostConstruct public void Demo1(){ System.out.println("after construct"); }
public Demo1(){ System.out.println("construct"); }
@Override public String toString(){ return "this is demo1"; }
public static void main(String[] args) { Demo1 d = new Demo1(); } }
|
注解共分为三类:
- 编译器使用的注释,如
@Override
,检查该方法是否正确的实现了覆写
- 由工具处理
.class
文件中使用的注解,一般在底层库使用
- 程序运行中能够读取的注解,类似于自定义的注解,加载后存在于jvm中
0x02 定义注解
在java中使用@interface
语法来定义注解,例如Override
的定义:
1 2 3 4
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
|
Override注解不带任何配置参数。@Target
和Retention
表示的是元注解,能够修饰自定义注解的注解
元注解
@Target
表示定义的注解能够被用到哪些位置:
- 类或者接口:
ElementType.TYPE
- 字段:
ElementType.FIELD
- 方法:
ElementType.METHOD
- 构造方法:
ElementType.CONSTRUCTOR
- 方法参数:
ElementType.PARAMETER
可以定义一个注解同时用于方法或者字段上面,如下所示:
1 2 3
| @Target({ElementType.FIELD, ElementType.METHOD}) public @interface Demo2 { }
|
@Retention
定义了注解的生命周期:
- 仅编译器:
RetentionPolicy.SOURCE
- 仅class文件:
RetentionPolicy.CLASS
- 运行期:
RetentionPolicy.RUNTIME
如果@Retention
不存在,则默认为CLASS
,故在自定义注解时,需要写明@Retention(RetentionPolicy.RUNTIME)
。
还有一些其他属性,可查阅相关文档,不再赘述。
注解参数
在定义注解的时候可以定义一些参数,并且能够赋予默认的值,具体如下,原理类似于接口的定义,定义无方法体的方法。
1 2 3 4 5 6 7
| @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Report { int type() default 0; String level() default "info"; String value() default ""; }
|
0x03 处理注解
注解对java代码的运行逻辑没有任何影响,我们编写的RUNTIME
类型的注解才会在代码运行时产生影响。
所有的注解都继承于java.lang.annotation.Annotation
,读取注解需要使用反射API。
判断是否存在注解的API:
1 2 3 4
| Class.isAnnotationPresent(Class) Field.isAnnotationPresent(Class) Method.isAnnotationPresent(Class) Constructor.isAnnotationPresent(Class)
|
例如,创建构造函数的注解
注解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.itranswarp.learnjava;
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;
@Target(ElementType.CONSTRUCTOR) @Retention(RetentionPolicy.RUNTIME) public @interface Construct_Annotation { String descp() default "no description"; }
|
注解使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Demo4 {
@Construct_Annotation public Demo4(){ System.out.println("构造函数"); }
@MethodAnnotation public void hello(){ System.out.println("hello method"); }
public static void main(String[] args) { Demo4 demo4 = new Demo4(); Constructor[] constructors = demo4.getClass().getConstructors(); for (Constructor con: constructors){
if (con.isAnnotationPresent(Construct_Annotation.class)){ System.out.println("构造函数注解找到"); } } } }
|
注解的验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| static void check(Person person) throws IllegalArgumentException, ReflectiveOperationException { for (Field field : person.getClass().getFields()) { Range range = field.getAnnotation(Range.class); if (range != null) { Object value = field.get(person);
if (value instanceof String){ int value_length = ((String) value).length(); System.out.println("当前filed:"+ field.getName()+ "的长度是"+ ((String) value).length()); if (value_length < range.min() || value_length > range.max()){ throw new IllegalArgumentException("Invalid field: " + field.getName()); } } if (value instanceof Integer){ if ((int) value < range.min() || (int) value > range.min()){ throw new IllegalArgumentException("Invalid field: " + field.getName()); } }
} } }
|
注解定义:
1 2 3 4 5 6 7 8 9 10
| @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Range {
int min() default 0;
int max() default 255;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Person {
@Range(min = 1, max = 20) public String name;
@Range(max = 10) public String city;
@Range(min = 1, max = 100) public int age;
public Person(String name, String city, int age) { this.name = name; this.city = city; this.age = age; }
@Override public String toString() { return String.format("{Person: name=%s, city=%s, age=%d}", name, city, age); } }
|
参考文档
- https://www.liaoxuefeng.com/wiki/1252599548343744/1255945389098144
- https://blog.csdn.net/pan_junbiao/article/details/85249614