关于java:面试官注解五问你怕了吗

6次阅读

共计 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的应用则是有条件限度,只有当 ElementTypeTYPE的时候才会失效,而它的作用就是将父类的作用域裁减到子类中,是子类能够去继承本来处于父类上的注解。
所以综上所述,咱们就能够使用元注解去自定义出一个属于咱们本人的注解:

@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";}

置信我聪慧的读者肯定能够触类旁通,应用注解去奇妙的实现更多的性能,本次注解的相干内容就到此为止了~

如果你有学到,请给我点赞 + 关注,原创不易,且看且珍惜。

正文完
 0