zoukankan      html  css  js  c++  java
  • JAVA基础5--注解的实现原理

    一、注解简介

    注解也叫元数据,是JDK1.5版本开始引入的一个特性,用于对代码进行标记说明,可以对包、类、接口、字段、方法参数、局部变量等进行注解修饰

    1.1、注解的类型

    1、JDK注解和框架注解:JDK本身提供了很多注解比如@Resource、@PostConstruct等;另外常用的框架也提供了很多注解,比如Spring的@Autowired,@Service等等,这些注解使用时会自动被JDK或框架进行识别解析;

    2、元注解:元注解用于修饰注解的,如@Retention(标明注解被保留的阶段)、@Target(标明注解使用的范围)、@Inherited(标明注解可继承)、@Documented(标明是否生成javadoc文档)

    3、自定义注解:用户可以根据自行需求自定义注解

    1.2、元注解

    @Retention:定义注解的生命周期,默认是CLASS,取值范围如下:

    SOURCE 在编译阶段被抛弃,通常用于编译时使用,比如@Override注解
    CLASS 在编译阶段会被写入字节码,当类加载的时候会被丢弃
    RUNTIME 不会被丢弃,运行期间也可以使用,所以通过反射机制就可以读取该注解的信息,通常自定义注解都会采用RUNTIME类型

    @Target:定义注解可以修饰的目标,默认是可以修饰任意目标,取值范围如下

    TYPE 用于描述类、接口或enum声明,如@Service、@Component等
    FIELD 用于描述属性,比如@JSONField等
    METHOD 用于描述方法,比如@Override
    PARAMETER 用于描述方法参数,比如Mybatis框架中的@Param
    CONSTRUCTOR 用于描述构造函数
    LOCAL_VARIABLE 用于描述局部变量
    ANNOTATION_TYPE 用于描述注解类型,比如@Target本身,@Retention,@Document注解等
    PACKAGE 用于描述包名
    TYPE_PARAMETER 用于描述参数类型
    TYPE_USE 表示该注解能使用在使用类型的任意语句中

    @Inherited:定义注解是否继承给子类

    当@Inherited注解修饰了一个注解,那么如果这个注解修饰了一个类,那么这个类的子类也会继承该注解

    @Documented:定义注解是否将注解信息加到Java文档中

    1.3、注解的组成

    注解通常有几个部分组成,包括修饰该注解的元注解,注解名称和注解方法,当然也可以将注解仅当作标记作用,没有任何方法也行,比如@Override注解就没有任何方法,仅当作标记使用

    二、注解的使用

    通常我们Web服务提供接口需要用户登录之后才可以访问,此时如果每个接口都判断下用户是否登录就会冗余很多的代码,所以需要在执行接口方法之前有一层验证用户登录的逻辑,可以通过过滤器,拦截器等方式实现,此时就可以配合注解来实现,在需要进行登录验证的方法上添加一个自定义的注解,然后每个添加了注解的方法就需要验证登录,没有注解的方法就不需要登录,实现方式如下:

    自定义注解@Logined

    @Documented
    @Target(ElementType.METHOD) /** 修饰方法*/
    @Retention(RetentionPolicy.RUNTIME)/** 生命周期为运行期间*/
    public @interface Logined {
    
        /** 定义方法,如果没有登录的情况下是否直接抛异常*/
        boolean exception() default false;
    }

    定义了注解之后就可以直接使用,但是想要使注解的效果生效,就需要有一套获取注解并处理业务的逻辑,此时就离不开Java的反射机制,需要通过反射机制获取到修饰在方法、类、属性上的注解来进行判断是否加了注解。

    另外在使用Spring框架时,可以配置AOP来配合使用自定义注解,比如以下案例就是用来处理@Logined注解的逻辑:

    @Aspect
    @Component
    public class LoginAspect {
    
        @Around("@annotation(com.test.annotation.Logined)")
        public Object doBefore(ProceedingJoinPoint jp) throws Throwable {
            if (MessageConfig.LOCAL.get() == null) {
                System.out.println("请求用户为空,返回401:" + jp.getSignature().getName());
                return Result.returnUnauthorized();
            }
            return jp.proceed();
        }
    }

    三、注解的实现原理

    注解本身没有任何逻辑,只能起到标记的作用,实现的逻辑完全取决于处理注解的逻辑,而处理注解就需要先找到注解,此时就离不开Java的反射机制,主要是通过Constructor、Class、Method、Field等反射相关类的getAnnotation(Class annotationClass)方法获取对应的注解,如果能获取到注解那么就表示被注解修饰了,案例如下:

     1 /** 1.查找类上的注解 */
     2         Annotation classAnnotation = cla.getAnnotation(Logined.class);
     3         if(classAnnotation != null){
     4             System.out.println("类被@Logined注解修饰");
     5         }
     6 
     7         /** 2.查找方法上的注解 */
     8         Method[] methods = cla.getMethods();
     9         for (Method method : methods){
    10             if(method.getAnnotation(Logined.class) != null){
    11                 System.out.println("方法:" + method.getName() + "被注解@Logined" + "修饰");
    12             }
    13         }
    14 
    15         /** 3.查找属性上的注解 */
    16         Field[] fields = cla.getFields();
    17         for (Field field : fields){
    18             if(field.getAnnotation(Logined.class) != null){
    19                 System.out.println("属性:" + field + "被注解@Logined" + "修饰");
    20             }
    21         }
    22 
    23         /** 4.查找构造函数上的注解 */
    24         Constructor constructor = cla.getConstructor(String.class);
    25         if(constructor.getAnnotation(Logined.class)!=null){
    26             System.out.println("构造器被@Logined注解修饰");
    27         }
  • 相关阅读:
    Spring @ContextConfiguration注解
    【Spring】Junit加载Spring容器作单元测试(整理)
    RestTemplate使用教程
    Linux下Maven私服Nexus3.x环境构建操作记录
    Maven 的 classifier 的作用
    Maven 教程(22)— Maven中 plugins 和 pluginManagement
    IOC给程序带来的好处
    Java NIO原理图文分析及代码实现
    Hadoop的RPC机制源码分析
    Flume之核心架构深入解析
  • 原文地址:https://www.cnblogs.com/jackion5/p/14700195.html
Copyright © 2011-2022 走看看