共计 3489 个字符,预计需要花费 9 分钟才能阅读完成。
1. 注解是什么
首先,咱们先来康康注解在百度百科上的解释
而在 Java 中,简略艰深的讲,就是一个 标签 ,对 类、办法、变量 的一个解释阐明,在早些年,咱们通常应用 xml 去对咱们的代码进行加强的解释,然而 格局繁冗,代码可读性差,保护起来很艰难 ,在 Java SE 5.0 当前,注解的呈现为这种状况失去了改善,越来越多的开源我的项目开始应用注解,摈弃了 xml。
xml 就像一段代码的补充解释和阐明,是一段 独自 的文档,比方咱们 Spring 我的项目中应用 xml 配置 Bean 的作用域,而注解是写在代码旁边,对代码进行标记和进行进一步的解释。
- xml 配置 Bean
<bean name="user" class="shanhe.show.User" scope="prototype"
</bean>
- 注解配置 Bean
@Bean
public class User{}
2. 注解该怎么用
咱们应用注解的办法十分的简略,能够别离这样去用
类
@Data
public class User{}
办法
@Override
public String print(){}
变量
@Notnull
private String id;
参数
String getIdByName(@Param("name") String name);
其应用的简略和不便其实也是咱们抉择应用的注解的最大起因:)
3. 自定义注解
要想真正的了解注解的实现原理,首先咱们要学会本人去实现一个自定义的注解,当咱们失去一个本人的注解之后,置信能够对注解的了解有更为粗浅的意识。
自定义注解之前,咱们先来意识几个 定义注解的注解——元注解 。@Target
@Retention
@Docuemented
Inherited
通过这四个元注解,咱们就能够去自定义一个咱们想要的注解,首先来别离解释一下,这四个元注解在构建自定义注解的时候起到的作用 @Target
正如它的名字那样,它是用于限定这个自定义注解可能利用的 Java 元素,在这个注解中保护着一个枚举类:
public enum ElementType {
/** 类,接口(包含注解类型)或枚举的申明 */
TYPE,
/** 属性的申明 */
FIELD,
/** 办法的申明 */
METHOD,
/** 办法形式参数申明 */
PARAMETER,
/** 构造方法的申明 */
CONSTRUCTOR,
/** 局部变量申明 */
LOCAL_VARIABLE,
/** 注解类型申明 */
ANNOTATION_TYPE,
/** 包的申明 */
PACKAGE
}
其应用的办法如下
@Target(value = {ElementType.TYPE,ElementType.METHOD})
public @interface AnnotionDemo {String value();
}
@Retention
注解是对自定义注解的生命周期进行限定,分为了源文件、编译期、运行期这三类,同样的,它也有一个好搭档——枚举类去保护这三个阶段。
public enum RetentionPolicy {
/**
* 注解将被编译器疏忽掉
*/
SOURCE,
/**
* 注解将被编译器记录在 class 文件中,但在运行时不会被虚拟机保留,这是一个默认的行为
*/
CLASS,
/**
* 注解将被编译器记录在 class 文件中,而且在运行时会被虚拟机保留,因而它们能通过反射被读取到
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
咱们理论开发中应用自定义注解的时候,最常应用的还是 RUNTIME
类型,咱们能够通过另外一个神器——反射去获取到咱们自定义注解的相干内容,从而对这些不同的内容进行不同的判断,前面我的项目实战局部,会举例说明理论应用的办法
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotionDemo {String value();
}
@Document
注解相对来说就比较简单了,它只是用来指定自定义注解是否跟随着它被应用的 Java 文件一起生成到 JavaDoc 中,就目前来看,这个元注解对于咱们的作用并不是很大。@Inherited
的应用则是有条件限度,只有当 ElementType
为TYPE
的时候才会失效,而它的作用就是将父类的作用域裁减到子类中,是子类能够去继承本来处于父类上的注解。
所以综上所述,咱们就能够使用元注解去自定义出一个属于咱们本人的注解:
@Document
@Inherited
@Target(value = {ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotionDemo {String value();
}
4. 注解实现原理
首先,在 Java 的文档中,我找到了这样的一句话:
The direct superinterface of every annotation type is java.lang.annotation.Annotation
意思就说,咱们不论是自定义的注解也好,JDK 中原生的注解也好,都是继承自Annotation
这个接口的,也就是说咱们下面自定义的注解通过了编译器编译后,大略是这个样子的
@Document
@Inherited
@Target(value = {ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public interface AnnotionDemo extends Annotation {String value();
}
那么咱们是应用注解的时候,怎么去给注解中的 value
赋值呢?
咱们应用该注解后,通过反编译后的代码,咱们能够找到(这里就不贴出反编译后的代码了,节约空间,大家晓得怎么回事就好~)在堆内存中有一个代理对象,大略长上面这样
public final class com.sun.proxy.$Proxy1 extends java.lang.reflect.Proxy implements java.lang.annotation.Annotation
而后在这个代理类中去实现了对 value
的赋值,而执行这一系列动作的是一个叫做 AnnotationInvocationHandler
的货色,它实现了在运行期间生成动静代理对象的操作,整体的流程大略是这样的
5. 在我的项目中咱们如何去应用注解?
上面,咱们通过一个理论利用的一个小???? 去看一下
咱们在应用零碎的时候,通常会有 权限的管制 ,在我的项目中,咱们会在 gateway 中去设置过滤器,通过过滤申请之中的 token,获取对应的用户信息,从而拿到用户的权限,实现对权限的管制,然而有一些接口是处于非登录状态(即没有 token 的时候)也须要去拜访的,而这些接口并非固定变化无穷的,这个时候,咱们就须要一个 标记 ,也就是注解去注明,哪些接口的拜访是无需进行权限的,相当于颁发了一个绿牌,能够跳过权限的管制。
自定义 @Pass
注解
/**
* 既能够作用于办法上,也能够作用于类上,作用于类上时,该类下的所有接口均可跳过
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Pass {boolean required() default true;
}
解决形式
// 如果不是映射到办法间接通过
if (!(object instanceof HandlerMethod)) {return true;}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
// 查看是否有 pass 正文,有则跳过认证
if (method.isAnnotationPresent(Pass.class)) {Pass pass = method.getAnnotation(Pass.class);
if (pass.required()) {return true;}
}
在拦截器中获取 Method 办法,通过反射去获取注解中的值,这样就能够跳过过滤间接去拜访接口啦,具体 应用办法 如下:
@Pass
@GetMapping("hello")
public String hello(){return "hello";}
置信我聪慧的读者肯定能够触类旁通,应用注解去奇妙的实现更多的性能,本次注解的相干内容就到此为止了~
如果你有学到,请给我点赞 + 关注,原创不易,且看且珍惜。