java注解的实现原理(如何自定义注解)

 分类:IT知识时间:2022-07-14 07:30:16点击:

Annotation是Java重要的组成部分,从J2SE 5.0时代就已经存在了。在我们的代码中,我们随处可以看到许多注解,例如@Autowired、@Override、@Service。这些注解我们可能非常熟悉,但是注解的作用、工作原理、工作方式以及我们如何自定义注解,我们可能并不熟悉。这篇文章我们就探索一下这些知识点。

1、什么是注解

注解是一种特殊的元数据,元数据是关于数据的数据,所以,注解就是代码的元数据。我们看下面这个例子:

Java注解的工作原理及如何自定义注解


我们用@Override注解toString()方法,说明我们要重写toString()方法。这里,即使我们不用@Override注解,这个方法任然可以正常执行。那注解的好处是什么呢?@Override告诉编译器,子类要重写这个方法,需要按照自己定义的格式输出内容,也就是覆盖了父类的方法,如果父类中没有这个方法,编译器就会报错。

所以,注解是一种特殊的Java构造器,它可以用于装饰类,方法,字段,参数,变量,构造函数或包。

2、为什么要使用注解

在注释之前(甚至之后),XML被广泛用于元数据。但是随着项目中代码量的增大,XML维护变得越来越麻烦。开发人员希望元数据与代码是紧密耦合,而XML与代码之间的耦合非常松散(在某些情况下,几乎是分开的)。

关于使用注解还是基于XML进行标记一直是一个具有争议的话题,对于开发人员来说,记住以下两个原则即可:

  • 1、假设您要设置一些应用程序范围内的常量。在这种情况下,XML是一个更好的选择,因为它与任何特定的代码段都不相关。

  • 2、如果要将某个方法作为服务公开,则注解将是一个更好的选择,因为它需要与该方法紧密结合。

另一个重要因素是,注解定义了在代码中定义元数据的标准方式。在注解之前,开发人员使用自己的方式定义元数据,这造成元数据定义混乱。但要注解是标准化的东西,更容易维护。

现在,大多数框架都将XML和注解结合使用,以充分利用两者的积极方面。

3、注解的工作方式

注解仅仅是元数据,不包括任何业务逻辑。那它的使用者是谁呢?像@Override这种注解,JVM是它的使用者,它在字节码级别工作。如果我们自己编写了一个注解,那我们就要去实现它的消费者,否则,我们自定义的注解是没有任何作用的。

4、编写自定义注解

在编写自定义注解的时候,我们首先需要搞清楚几个默认的注解,这几个注解仅仅作用与另一个注解之上。

  • @Documented

Java注解的工作原理及如何自定义注解


@Documented注解表明这个注解要被javadoc记录。注解默认状态下是不被javadoc记录的。

  •  @Retention

@Documented注解表明该注解保留到那个阶段,主要有三个值:

Java注解的工作原理及如何自定义注解


SOURCE —— 这种注解保留在源代码级别,编译时就会被忽略

CLASS —— 这种注解编译时被保留,在class文件中存在,但JVM将会忽略

RUNTIME —— 这种注解将被JVM保留,利用反射机制可以获取并使用。

  • @Target

Java注解的工作原理及如何自定义注解


@Target注解表明该注解作用的范围。包括package、method、field、构造方法、成员变量、枚举值等属性。

  • @Inherited

@Inherited注解表明该注解是否影响子类。如果定义的注解上使用了@Inherited标记,则使用该注解的某个父类,它的子类默认继承所有的属性

现在我们定义自己的一个注解@CronScheduled

Java注解的工作原理及如何自定义注解


CronScheduled注解上用了三个默认的注解,@interface表明这是一个注解(注意不是接口)。同时我们定义了cron和desc两个属性。这就是一个完整的注解,我们再看怎么使用它。

Java注解的工作原理及如何自定义注解


我们假设一个业务场景:我们的业务中很多个定时任务,这些定时任务我们手动实现了线程池维护并调度这些方法。那在线程池中我们怎么获取那些方法是定时任务呢?这就是自定义注解的作用。我们在synCreative的方法上使用了我们自定义的注解,目的就是让调度的线程池可以发现它。具体的实现看下面代码:

Java注解的工作原理及如何自定义注解


我们循环遍历所有的定时任务方法,并获取方法上的注解,如果方法上有CronScheduled的注解,说明该方法就是定时任务的方法,同时,获取注解上的cron属性值,设定执行任务的周期。

至此,我们就完成了一个自定义的注解。

5、注解用例

注释功能非常强大,Spring和Hibernate之类的框架将注解广泛用于日志记录和验证,在Servlet规范3.0中,引入了许多注解,尤其是与Servlet安全性相关的注释。让我们看看一些常见的注解。

  • HandlesTypes 用于声明传递给的应用程序类的数组ServletContainerInitializer。

  • HttpConstraint 被使用来代表应用于所有HTTP协议方法的安全限制

  • HttpMethodConstraint 特定的安全约束可以应用于不同的请求类型

  • MultipartConfig 声明它的Servlet希望使用multipart / form-data MIME类型进行请求。

  • ServletSecurity 在Servlet实现类上声明此注解,以对HTTP协议请求强制实施安全性约束。

  • WebFilter 用于声明Servlet过滤器的注解。

  • WebInitParam 用于在WebFilter或WebServlet上声明初始化参数。

  • WebListener 在给定的Web应用程序上下文中用于声明各种事件的侦听器。

  • WebServlet 用于声明Servlet的配置。


除注明外的文章,均为来源:老汤博客,转载请保留本文地址!
原文地址: