Суть и принцип реализации Java Annotations (аннотации) (Часть 1)

Java
Суть и принцип реализации Java Annotations (аннотации) (Часть 1)

введение

давным-давно,XMLвсегдаJavaОсновные метаданные конфигурации фреймворка (meta data) Главный путь. но какцентрализованныйИнструмент управления метаданными для , элемент конфигурации находится слишком далеко от кода действия"далекий», что очень вредно для обслуживания и отладки кода.XML本身复杂的语法结构,往往令码农们大感头疼。一种与作用代码耦合在一起的元数据配置方式呼之欲出。 тогдааннотация(Аннотации) вJDK 5Официально появляются в линии зрения разработчика.

ежедневное использованиеSpring BootСтуденты, которые более знакомы с использованием аннотаций, должны быть знакомы с ним. Но задумывались ли вы когда-нибудь об этих аннотациях, таких как@Configuration @Component @BeanИ так далее, в чем его суть, и как он играет свою конкретную роль?

Характер аннотаций

Официальный сайт 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.

Аннотации — это форма метаданных, предоставляющая данные о программе, которые не принадлежат самой программе. Аннотация не оказывает прямого влияния на работу кода, который она аннотирует.

Из этого определения мы видим, что, во-первых, аннотация несет в себе метаданные, а во-вторых, может вызывать некоторые операции, связанные с метаданными, ноНе влияет на логику аннотированного кода.

пока вJDKВ интерфейсе Annotation есть строка комментариев, поэтому написано:

/**
 * The common interface extended by all annotation types. 
 * ...
 */
public interface Annotation {...}

Это показывает, что другие аннотации расширеныAnnotationЭтот интерфейс, то есть сущность аннотации, и есть интерфейс.

Для Spring Boot в примечании в качестве примера:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
    String value() default "";
}

На самом деле это эквивалентно:

public interface Component extends Annotation{...}

и@interfaceЕго можно рассматривать как синтаксический сахар.

Элементы аннотации

Мы все еще видим@ComponentЭтот пример:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
    String value() default "";
}

В определении аннотации есть несколько аннотаций.@Target, @Retention, @Documented,называетсяметааннотация.

Так называемая мета-аннотация - это аннотация, которая описывает аннотацию, которая похоже наPythonметакласс в .

JavaИмеются следующие мета-аннотации:

@Target

Как следует из названия, эта аннотация идентифицирует объект, к которому применяется измененная аннотация. Давайте посмотрим на его исходный код:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

Как видите, значение этой аннотации является массивом, что означает, что аннотация может иметь несколько объектов. Его ценностный диапазонElementTypeСреди этого перечисления:

public enum ElementType {
    /** 类、接口、枚举定义 */
    TYPE,
    /** 字段,包括枚举值 */
    FIELD,
    /** 方法 */
    METHOD,
    /** 参数 */
    PARAMETER,
    /** 构造方法 */
    CONSTRUCTOR,
    /** 局部变量 */
    LOCAL_VARIABLE,
    /** 元注解 */
    ANNOTATION_TYPE,
    /** 包定义 */
    PACKAGE...
}

Различные значения представляют диапазон, который может быть изменен путем аннотации, напримерTYPEМожно декорировать только определения класса, интерфейса и перечисления. Существует особое значение, называемоеANNOTATION_TYPE, специально для мета-аннотаций.

оглядываясь назад@ComponentЭтот пример,TargetценностьTYPE. Знаком сSpring BootОдноклассники тоже должны знать,@ComponentЕго действительно нельзя размещать перед методами или свойствами.

@Retention

@RetentionАннотации определяют время жизни декорируемой аннотации. Определяется следующим образом:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

Вы можете увидеть эту аннотацию с помощью одногоRetentionPolicyЗначение перечисления:

public enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}
  • SOURCEУказывает, что аннотация видна во время компиляции и удаляется после компиляции. Эта аннотация обычно используется для выполнения каких-либо действий в компиляторе;
  • CLASSУказывает, что файл класса записывается после компиляции, но отбрасывается после загрузки класса. Эта аннотация обычно используется для выполнения каких-либо действий на этапе загрузки класса;
  • RUNTIMEЭто означает, что аннотация всегда будет работать.

@Documented

Эта аннотация относительно проста и указывает, следует ли добавлять кjava docсередина.

@Inherited

Это также относительно просто, указывая, наследуется ли аннотация. Эта аннотация не очень часто используется.

Примечание. Мета-аннотации используются только при определении аннотаций!

Аннотированная схема

Как вы можете видеть из вышеуказанных мета-аннотаций, аннотация может быть связана с несколькимиElementType, но только одинRetentionPolicy:

Встроенные аннотации Java

В Java есть три широко используемых встроенных аннотации, на самом деле, я думаю, что каждый их использовал или видел. Но разобравшись с истинным лицом аннотаций, давайте познакомимся с ними заново!

@Override

Он определяется как:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

Видно, что эта аннотация не имеет никакого значения, она может только модифицировать метод, а RetentionPolicy имеет значение SOURCE, что указывает на то, что это аннотация, которая работает только на этапе компиляции.

Его реальная роль должна быть известна всем, то есть на этапе компиляции, если метод класса@OverrideМодифицированный, компилятор проверит, есть ли в его родительском классе функция с такой же сигнатурой, если нет, то скомпилирует ошибку. Видно, что это действительно аннотация, которая бесполезна, кроме как на этапе компиляции.

@Deprecated

Он определяется как:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

Эта аннотация также не имеет никакого значения, он может изменить все типы, и он существует навсегда. Целью этой аннотации - рассказать пользователю, что модифицированный код устарел и может быть удален в следующей версии программного обеспечения. Эта аннотация служит только механизмом уведомления. Если код вызывает код, украшенный @deprected, компилятор выводит предупреждение о компиляции при компиляции.

@SuppressWarnings

Он определяется как:

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    /**
     * The set of warnings that are to be suppressed by the compiler in the
     * annotated element.  Duplicate names are permitted.  The second and
     * successive occurrences of a name are ignored.  The presence of
     * unrecognized warning names is <i>not</i> an error: Compilers must
     * ignore any warning names they do not recognize.  They are, however,
     * free to emit a warning if an annotation contains an unrecognized
     * warning name.
     *
     * <p> The string {@code "unchecked"} is used to suppress
     * unchecked warnings. Compiler vendors should document the
     * additional warning names they support in conjunction with this
     * annotation type. They are encouraged to cooperate to ensure
     * that the same names work across multiple compilers.
     * @return the set of warnings to be suppressed
     */
    String[] value();
}

Эта аннотация имеет значение массива строк, которое необходимо передать, когда мы используем аннотацию. Его можно использовать перед типами, свойствами, методами, параметрами, конструкторами и локальными переменными Цикл объявления — это время компиляции.

Основная функция этой аннотации — подавить предупреждения компиляции.

Например

public static void main(String[] args) {
    Date date = new Date(2020, 5, 22);
}

Мы видим, что,DateЭтот конструктор изменен @deprected:

@Deprecated
public Date(int year, int month, int date) {
    this(year, month, date, 0, 0, 0);
}

Таким образом, приведенный выше код сообщит оWarning:

java: java.util.Date 中的 Date(int,int,int) 已过时

Чтобы не дать компилятору вывести этоWarning, необходимо использовать вышеуказанноеmainдобавить один перед методом@SuppressWarningsаннотация:

@SuppressWarning(value = "deprecated")
public static void main(String[] args) {
    Date date = new Date(2020, 5, 22);
}

Аннотировать входную строкуdeprecatedУказывает, что компилятор игнорирует@DeprecatedПредупреждения компиляции, вызванные аннотациями.

Резюме и уведомление

Эта статья в основном вводитJavaСуть, элементы и метааннотации аннотаций, триJavaВстроенные аннотации.

Следующиймы будем стоятьJVMС точки зрения углубленного анализа функционального принципа реализации аннотаций и напишите собственную заметку.