1.注解与注释对比
注释:
给人看的提示信息,人看了提示信息了解程序的内容
java中注释的格式:// /**/ /** */
注解:
sun在jdk5.0开始提供的新特性
给程序看的提示信息,程序看后可以根据有无注解及注解上属性的不同配置执行不同的逻辑。
java中的注解的格式:@AnnoName(key=value,...)
注解在开发中,可以作为轻量化配置来使用,比起使用xml作为配置文件,更加的轻便易用,在java开发中大量的使用
2.jdk内置注解
@Override
- 声明重写父类方法的注解,要求编译器帮我们检查是否成功的覆盖,如果没有成功覆盖父类方法,编译器将会进行报错提示。
@Deprecated
- 声明方法被过时,不再建议使用,要求编译器在编译的过程中对于这样的方法的调用提出警告,提示方法过时。
@SuppressWarnings
- 压制警告,提示编译器,在编译的过程中对指定类型的警告不再提示自定义注解开发
3.自定义注解开发
3.1开发一个注解类
开发一个注解类的过程,非常类似于开发一个接口,只不过需要通过@interface关键字来声明
3.2使用元注解修饰注解的声明
所谓的元注解是用来修饰注解声明的注解,可以控制被修饰的注解的特性。
@Target
- 用来声明被修饰的注解可以用在什么位置。
- 可以在@Target的属性中设置ElementType类型的数组来指定可以使用的位置。
- 如果不用此元注解修饰,默认注解可以用在任意位置。
ElementType中的值:
CONSTRUCTOR:构造器
FIELD:成员属性
METHOD:成员方法
LOCAL_VARIABLE:局部变量
PACKAGE:包的声明
PARAMETER:方法的参数
TYPE:类
泛型:TYPE_PARAMETER
@Retention
- 用来声明被修饰的注解会被保留到什么阶段。
- 可以在该注解的属性中通过RetentionPolicy类型的值来指定注解被保留到何时。
RetentionPolicy.SOURCE
- 此注解将会被保留到源码阶段,.java中,在编译过程中被删除。
- 这种类型的注解通常是给编译器看的。
这个阶段的注解:如@Override,它的存在帮你确定了你的方法是重写方法,如果没有这个注解,如果方法名称单词写错,一般也不会报错,会导致无法发现方法并未被重写,而是自己新写的一个方法。导致后期出错。
RetentionPolicy.CLASS
- 此注解将会被保留在源码阶段 和 编译阶段 ,.java和.class中,在类加载的过程中被删除。
- 这种类型的注解通常是给类加载器看的。
RetentionPolicy.RUNTIME
- 此注解将会被保留在源码阶段 、编译阶段 和 运行阶段,.java .class和内存中的字节码中都会存在。
- 这种类型的注解通常用来在运行阶段进行反射,控制程序运行过程。
它们的保留阶段如下图
**只有RUNTIME级别的注解才可以通过反射技术进行反射。
@Documented
- 用来声明被修饰注解是否要被文档提取工具提取到文档中。
- 默认不提取。
@Inherited
- 被修饰的注解是否具有继承性
- 默认没有继承性
3.3为注解增加属性
注解类中还可以声明属性。
- 为注解类声明属性的过程非常类似于为接口定义方法。
- 但要求,注解中的所有的属性必须是public的,可以显式声明,也可以不声明,不声明默认就是public的。
- 注解中的属性只能是八种基本数据类型 String类型 Class类型 枚举类型 其他注解类型 及 以上类型的一维数组。
- 注解中声明的属性,需要在使用注解时为其赋值, 赋值的方式就是使用注解时在注解后跟一对小括号, 在其中 通过 属性名=属性值 的方式 指定属性的值
- 也可以在声明注解时 在注解的属性后 通过default关键字 声明属性的默认值 声明过默认值的属性 可以在使用注解时 不赋值 则默认采用默认值 也可以手动赋值 覆盖默认值
- 如果属性是 一维数组类型 而 在传入的数组中 只有一个值 则包括数组的大括号可以省略
- 如果注解的属性 只有一个需要赋值 且该属性的名称叫做value 则在使用注解时 value= 可以不写
开发的步骤可以归纳为:
1.先写一个类:用@interface声明
2.通过元注解修饰自定义注解的声明,来指定自定义注解的特性(元注解:java提供的用来修饰注解定义的注解)
3. 设置@Retention,让注解保留到什么阶段,如果不设置就只保留在源码阶段,源码阶段如果经过编译就会丢失该注解,编译好的.class文件就不会有该注解
4.给自定义好的注解添加属性(不是必须的),类似于接口中定义方法
代码实现:
类的声明用class,接口的声明用interface,注解的声明用@interface
如下声明一个注解,声明完成就能使用,只是不会有任何作用
public @interface PrivAnno {
}
声明后通过元注解@Target 限定只能将该注解用在方法上,用在其他地方会报错
@Target(ElementType.METHOD)
既可以用在类上,也可以用在方法上,可以按照如下设置
@Target({ElementType.METHOD,ElementType.TYPE})
设置@Retention,让注解保留到什么阶段运行阶段
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PrivAnno {
}
给注解添加属性,属性的注意事项,参照上面所述
如果添加了属性,在使用是就必须为这些属性赋值
//定义属性
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PrivAnno {
public String name();
Role[] value();
}
//在使用时给注解赋值,不赋值编译不能通过
@PrivAnno(name="张三",value={Role.USER, Role.ADMIN})
@Override
public void queryUser() {
System.out.println("查询用户..");
}
如果只有一个属性,那么在赋值是,可以将该属性省略,直接给值即可
//只有一个属性value
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PrivAnno {
Role[] value();
}
//赋值时可以不写value,直接给值
@PrivAnno({Role.USER, Role.ADMIN})
@Override
public void queryUser() {
System.out.println("查询用户..");
}
如果该属性为数组属性且该数组的值只有一个,那么可以省略大括号
//定义注解属性
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PrivAnno {
Role[] value();
String[] addr();
}
//数组只有一个值,赋值方法一
@PrivAnno(value = {Role.USER, Role.ADMIN},addr={"北京"})
@Override
public void queryUser() {
System.out.println("查询用户..");
}
//数组只有一个值,赋值方法二,等价于方法一
@PrivAnno(value = {Role.USER, Role.ADMIN},addr="北京")
@Override
public void queryUser() {
System.out.println("查询用户..");
}
注解中定义了属性,可以设置属性的默认值,这样在使用时如果不赋值,那么就是默认值,如果给了值,就会覆盖默认值
//注解中设置默认值
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PrivAnno {
Role[] value();
String name() default "张三";
}
//使用注解时,如果不赋值,那么就是默认值
@PrivAnno(value = {Role.USER, Role.ADMIN})
@Override
public void queryUser() {
System.out.println("查询用户..");
}
注解@Qualifier 默认值是空串,所以在使用时需要指定id,否则就的不到对应的bean
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {
String value() default "";
}
4.使用场景
在权限控制时,可以定义管理员,用户,游客等,通过注解赋值,给不同的方法赋予不同的权限
步骤如下:
通过aop来实现权限控制
- 通过自定义注解声明业务方法是否需要权限控制
- 通过权限注解上的属性声明需要什么样的权限
- 通过切面拦截业务方法,根据是否需要权限、是否具有权限,控制目标方法的执行