[Java] 理解框架的基础之什么是Annotation

前言


Java中的Annotation笔者相信大家都不陌生,未使用框架的时候,如 @Override @SuppressWarnings 。使用Spring框架的时候 @Controller@Mapping等,可以说Annotation是Java世界中不可或缺的医院,笔者想借本文来简单谈谈对于Annotation的理解。

参考


  1. The Java™ Tutorials - Lesson: Annotations
  2. @Getter and @Setter - lombok offical doc
  3. Annotation - Java8 oracle doc

Annotation(注解)的定义


在讨论开始之前,我们先明确在Java世界里Annotation的定义。

Oracle官方的文档里这样写着

Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate.

“Annotations, 一种元数据,其并是可执行代码本身的一部分,只是提供了一些关于这部分程序的元信息。Annotations并不会对他们标记的代码产生直接影响

可以得知我们使用Annotation并不会直接作用在程序上,这或许难以理解(如Spring的Annotation明明可以改变程序的行为!),笔者换个说法

如果没有外部框架如Spring、Lombok、Mybatis等的时候,Annotation并不会直接作用在程序上。

Annotation并不会直接改变程序行为,但如果程序本身包含了如Spring控制的部分,那么Annotation里提供的信息会令框架等对此信息做出相应的反应,从而导致程序行为改变(被配置)。

Annotation的作用


Annotation一般有如下的作用

  • 为编译器提供信息:Annotations能够为编译器提供检查错误或者禁止警告(Suppress warning)的信息。
  • 编译时:编译时能够为外部工具提供信息,以便生成字节码等。如Lombok为你的Java POJO类生成Getter/Setter,你仅需要使用@Setter、@Getter即可。
  • 运行时:Annotation信息能够在运行时被加载,而被使用。典型的有Spring框架的@Controller等,能在Spring框架扫描的时候知道,“wow,这个类是Controller,我应该留意他” 或是 “wow,这个类的方法要匹配"/user"路径,来这种请求的时候我应该交给这个方法处理。”

[实践] 实现自己的Annotation


笔者将在本节实现两个Annotation,并通过下一节来实验,Annotation的信息是如何被获取和利用的。

1. 在运行时会被加载到内存的Annotation


@Retention(RUNTIME) 表明这个标注的信息会被加载到Java程序运行时的内存里,这也是大部分框架注解使用的。毕竟如果内存里没有这些信息,框架也无从得知应该如何配置自己的行为。

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Documented
@Retention(RUNTIME)
@Target(TYPE)
public @interface MyRunTimeAnnotation {
	String message() default "打印\"Hello Annotation\",如果你看到这个标记。";
}

2. 在运行时不会被加载到内存的Annotation


@Retention(SOURCE) 或是 @Retention(CLASS)是不会导致注解被加载到JVM内存的。SOURCE通常仅用于提示开发者某些信息。如下你可以写@Author注解用于标注代码的作者~

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Documented
@Retention(SOURCE)
@Target(TYPE)
public @interface Author {
	String value();
}

[实践] 运行时获取Annotation的信息


在上面我们设计了两个注解,一个能在运行时被加载,一个不能,那么我们来验证一下究竟是不是如此。

import java.lang.annotation.Annotation;

@MyRunTimeAnnotation()
@Author("虎猫")
public class AnnotatedTestClass {

	public static void main(String[] args) {
		Class<AnnotatedTestClass> clazz = AnnotatedTestClass.class;
		
		for (Annotation annotation : clazz.getAnnotations()) {
			System.out.println(annotation);
			// 运行时获取自定义注解的内部信息。
			if (MyRunTimeAnnotation.class.isInstance(annotation)) {
				final MyRunTimeAnnotation myAnnotation = (MyRunTimeAnnotation)annotation;
				System.out.println(myAnnotation.message()); 
			}
		}
	}
}

如果你跑一下会发现结果如下,能看到我们的类运行时只有一个MyRunTimeAnnotation而Author注解的信息没有被加载到内存里。

@per.eicho.test.annotation.MyRunTimeAnnotation(message=任意消息能在运行时被看到)
任意消息能在运行时被看到

通过上述例子,我们能够发现一些信息是能够通过注解Annotation在运行时或者编译时传递给外部工具如编译器、Lombok或如Spring等框架的,如果我们按照外部工具约定好的格式提供对应信息,那么就能够成功”告知“对方我们的意图并被理解。而对方也能根据这些信息做出相应的反应,如以下两个注解就是告诉Spring框架来了/users/{id}这样的Get请求请交给getUser方法处理,而PathVariable注解则告诉Spring框架调用的时候请把路径里的id部分单独抽出来放到这个ID参数里。

@GetMapping("/users/{id}")
public String getUser(@PathVariable("id") String ID)

结语


Annotation,注解是提供信息的一种方式,注解是多面手能为许多不同的对象提供信。当其提供的信息能够被加载到运行时的时候,其作用就像配置文件、配置表、程序启动传入的参数时,都是为程序运行提供配置信息。Spring、Mybatis等框架就是利用这些信息来对其行为作出配置,理解注解和其中的信息是如何被使用的是理解流行框架的基础。我是虎猫,希望本文能够帮到你。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值