java注解的实现原理(如何自定义注解)
Annotation是Java重要的组成部分,从J2SE 5.0时代就已经存在了。在我们的代码中,我们随处可以看到许多注解,例如@Autowired、@Override、@Service。这些注解我们可能非常熟悉,但是注解的作用、工作原理、工作方式以及我们如何自定义注解,我们可能并不熟悉。这篇文章我们就探索一下这些知识点。
1、什么是注解
注解是一种特殊的元数据,元数据是关于数据的数据,所以,注解就是代码的元数据。我们看下面这个例子:
我们用@Override注解toString()方法,说明我们要重写toString()方法。这里,即使我们不用@Override注解,这个方法任然可以正常执行。那注解的好处是什么呢?@Override告诉编译器,子类要重写这个方法,需要按照自己定义的格式输出内容,也就是覆盖了父类的方法,如果父类中没有这个方法,编译器就会报错。
所以,注解是一种特殊的Java构造器,它可以用于装饰类,方法,字段,参数,变量,构造函数或包。
2、为什么要使用注解
在注释之前(甚至之后),XML被广泛用于元数据。但是随着项目中代码量的增大,XML维护变得越来越麻烦。开发人员希望元数据与代码是紧密耦合,而XML与代码之间的耦合非常松散(在某些情况下,几乎是分开的)。
关于使用注解还是基于XML进行标记一直是一个具有争议的话题,对于开发人员来说,记住以下两个原则即可:
1、假设您要设置一些应用程序范围内的常量。在这种情况下,XML是一个更好的选择,因为它与任何特定的代码段都不相关。
2、如果要将某个方法作为服务公开,则注解将是一个更好的选择,因为它需要与该方法紧密结合。
另一个重要因素是,注解定义了在代码中定义元数据的标准方式。在注解之前,开发人员使用自己的方式定义元数据,这造成元数据定义混乱。但要注解是标准化的东西,更容易维护。
现在,大多数框架都将XML和注解结合使用,以充分利用两者的积极方面。
3、注解的工作方式
注解仅仅是元数据,不包括任何业务逻辑。那它的使用者是谁呢?像@Override这种注解,JVM是它的使用者,它在字节码级别工作。如果我们自己编写了一个注解,那我们就要去实现它的消费者,否则,我们自定义的注解是没有任何作用的。
4、编写自定义注解
在编写自定义注解的时候,我们首先需要搞清楚几个默认的注解,这几个注解仅仅作用与另一个注解之上。
@Documented
@Documented注解表明这个注解要被javadoc记录。注解默认状态下是不被javadoc记录的。
@Retention
@Documented注解表明该注解保留到那个阶段,主要有三个值:
SOURCE —— 这种注解保留在源代码级别,编译时就会被忽略
CLASS —— 这种注解编译时被保留,在class文件中存在,但JVM将会忽略
RUNTIME —— 这种注解将被JVM保留,利用反射机制可以获取并使用。
@Target
@Target注解表明该注解作用的范围。包括package、method、field、构造方法、成员变量、枚举值等属性。
@Inherited
@Inherited注解表明该注解是否影响子类。如果定义的注解上使用了@Inherited标记,则使用该注解的某个父类,它的子类默认继承所有的属性
现在我们定义自己的一个注解@CronScheduled
CronScheduled注解上用了三个默认的注解,@interface表明这是一个注解(注意不是接口)。同时我们定义了cron和desc两个属性。这就是一个完整的注解,我们再看怎么使用它。
我们假设一个业务场景:我们的业务中很多个定时任务,这些定时任务我们手动实现了线程池维护并调度这些方法。那在线程池中我们怎么获取那些方法是定时任务呢?这就是自定义注解的作用。我们在synCreative的方法上使用了我们自定义的注解,目的就是让调度的线程池可以发现它。具体的实现看下面代码:
我们循环遍历所有的定时任务方法,并获取方法上的注解,如果方法上有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的配置。
原文地址:https://tangjiusheng.cn/it/498.html