Java Annotations注解和Java Comments正文,英文里查别很大,在中文中一字之差让人颇为费解。Java Comments正文是随着Java语言的诞生就有的,意义明确,简略易懂,就是在源代码中的解释信息,通常用在帮忙代码编写人员了解代码。Java Annotations呈现的较晚,在Java 1.5(Java 5)中才引入,目前(2022年)Java部署的支流是Java 8(Java 1.8),最新发行版是Java 11(Java 1.11).

但Java Annotations注解的意义和作用就显得有些费解,比方官网文档中:

Annotations do not directly affect program semantics, but they do affect the way programs are treated by tools and libraries, which can in turn affect the semantics of the running program. Annotations can be read from source files, class files, or reflectively at run time.

Annotations注解不会间接影响程序的语义,然而他们的确影响工具和库处理程序的形式,进而影响运行中的程序的语义。Annotations注解能够从源文件 ,class文件,或者运行时的反射中读取。

随着“工具和库处理程序”的风行,比方在Java开发中逐步风行的Spring全家桶等,处处可见的@RequestXXX 等表述,让后生Java Annotations逐步走入开发者的视线。然则只言片语地要解释分明Java Annotations注解是什么货色及怎么作用或者工作的,却非易事。

咱们所主导的Java 开发框架GWA2 in Java( https://ufqi.com/dev/gwa2/ )并没有过多地倚重Java Annotations注解,次要是在初期技术架构选型时,咱们考查了应用Reflection等相干技术时,发现其性能会降落平安受影响。

Due to 1) issues of performance and security of java.lang.reflection, We do not use it as routing or dynamic module invoking at present.

鉴于Reflection相干技术存在性能和平安相干方面问题,GWA2 in Java 目前没有思考将其作为路由和动静模块加载技术手段。

然而,Java开发业界仿佛造成了一种站在“伟人肩膀”上搭积木式地的重叠,第一个扣子歪了大家也就一顺溜地持续歪上来,所谓性能和平安问题都是能够克服的,不能解决的局部也是在可承受范畴内,大快人心。

近期咱们接手了两个Java开发的二期我的项目,基于Java Spring全家桶,我的项目技术栈尽管是Java,但其所依赖的各种第三方组件达到令人目迷五色的境地(如下图)。


Java Spring 组件套系

既然Java Annotations如此重要,天然要弄清楚,然而当咱们试图向一些工程师解释Java Annotations是什么、怎么样的时候,发现并不容易,一方面是Java语言自身的复杂性,另一方面是Annotations是下层利用,是可选项。通过一番搜寻、思考和探索,我感觉如下两个实例能够清晰地解释Java Annotations注解的基本原理和利用实际,答复了Java Annotations注解是什么,为什么和怎么样的问题。

实例1. 用Java Annotations注解标记某个对象类、实例、办法和属性具备或不具备某个属性。

这个实例来自官网 ( https://docs.oracle.com/javas... )

e.g.1.1. SampleTestTag.java: 自定义一个Java Annotation注解对象,其中的 @Retention 和 @Target 是注解的注解,称之为“元注解”, 注解类的什么是在名称前加 “@” at符号

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SampleTestTag {

}

e.g.1.2. FooBar.java: 创立一个对象类 FooBar , 应用下面创立的Java注解 SampleTestTag

public class FooBar {

@SampleTestTag public static void m1() { }public static void m2() { }@SampleTestTag public static void m3() {    throw new RuntimeException("Boom");}public static void m4() { }@SampleTestTag public static void m5() { }public static void m6() { }@SampleTestTag public static void m7() {    throw new RuntimeException("Crash");}public static void m8() { }

}

e.g.1.3. FooBarTest.java: 创立一个测试程序,调用对象类 FooBar, 测试 SampleTestTag 的辨别作用

import java.lang.reflect.*;

public class FooBarTest {
public static void main(String[] args) throws Exception {

  int passed = 0, failed = 0;  for (Method m : Class.forName(args[0]).getMethods()) {     if (m.isAnnotationPresent(SampleTestTag.class)) {        try {           m.invoke(null);           passed++;        } catch (Throwable ex) {           System.out.printf("Test %s failed: %s %n", m, ex.getCause());           failed++;        }     }  }  System.out.printf("Passed: %d, Failed %d%n", passed, failed);

}
}

该测试程序预期运行的后果大抵为:

$ java FooBarTest FooBar
Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom
Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash
Passed: 2, Failed 2

这个实例示意,通过自定义一个注解,能够将对象类的某些办法标记进去,外围办法是isAnnotationPresent。这只是一个简略的实例,如果这个路子走得通,有这种简略的办法或范式,能够将对象类、实例、办法和属性进行分类,好像关上了潘多拉的盒子,赋予开发者无穷尽的分类能力。
当具备这种能力后,能够在运行时依据分类,让A类的运行,让B类的都熄火;在英国区运行A类,在北美运行B类;让VIP的运行A类,让非VIP的运行B类;让小孩看A类,让老人看B类,其他人看C类….

显然这种能力是弱小的,但同时其复杂性也显现出来了,开发者看到的代码和最终运行时的代码可能高度的 不–一–致。只管代码都摆在哪里,但具体跑那些代码须要看运行时的状态。由此造成了可怕的所见非所得。

实例2. 用Java Annotations注解标记某个对象类、实例、办法和属性具备某个属性的某种赋值。

这是对实例1的进化和降级,如果实例1提供让某个对象具备或不具备,是与非的简略二元分类,则实例2将这种能力有限降级到让某个对象的领有某个属性,而且这个属性的赋值能够变幻无穷。

更多全文内容: 两个实例解释分明Java Annotations注解 | -UFQI-Blog , https://ufqi.com/blog/gwa2-ja...