5 минут, чтобы понять аннотацию java @Annotation

Java

Вывод из первого предложения: аннотация — это средство «маркировки» с использованием метода, аналогичного @xxx, для класса, метода или атрибута, а затем содержимое метки может быть проанализировано и обработано соответствующим образом с помощью механизма отражения.

Аннотации — важная часть знаний в java, они были введены начиная с java5, особенно в фреймворке spring. Чаще всего используются @controller, @service и т. д. В этой статье мы начнем с принципа реализации аннотации и проанализируем его с помощью некоторых демонстрационных кодов.

1. Метод определения аннотации

Перейдите непосредственно к коду и посмотрите определение аннотации @Service весной:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {

	String value() default "";
	
}

Можно видеть, что определение аннотации очень похоже на определение интерфейса, но с добавлением символа @ определение аннотации имеет следующие соглашения:

  1. Можно определить только имена атрибутов, но не методы
  2. Видимость атрибутов только публичная и по умолчанию, а последняя по умолчанию, если не написано
  3. Типы атрибутов могут поддерживать только: базовые типы данных, строку, класс, перечисление, типы аннотаций и массивы вышеуказанных типов.
  4. Можно добавить ключевое слово по умолчанию, чтобы указать значение по умолчанию.Если поле не указывает значение по умолчанию, значение поля должно быть указано при аннотировании.
  5. При использовании значения в качестве имени атрибута вы не можете указать значение = "xxx" явно, например, вы можете использовать @Service ("xxxService") напрямую

2. Мета-аннотации

Так называемая мета-аннотация — это аннотация, реализованная по умолчанию в java, которая специально аннотирует аннотацию. Общее количество мета-аннотаций равно 5. Давайте возьмем аннотацию @Service, упомянутую выше, в качестве примера, чтобы разбить их:

1.@Target

Эта аннотация используется для указания области применения текущей аннотации. @Target({ElementType.TYPE}) означает, что аннотация @Service специально используется для аннотирования классов, интерфейсов или типов перечисления. При добавлении этого в метод Когда аннотации, будет сообщено об ошибке. Вы можете видеть, что местоположение аннотации является типом перечисления, полное определение выглядит следующим образом.

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

2.@Retention

Эта аннотация используется для обозначения жизненного цикла текущей аннотации.Говоря человеческими словами, это означает, как долго будет сохраняться функция этой аннотации.Например, @Retention(RetentionPolicy.RUNTIME) означает, что она все еще действительна в течение работа программы.В это время аннотацию можно получить посредством отражения.информация, полное перечисление определяется следующим образом

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

3.@Documented

При аннотации этой аннотации документация, созданная с помощью инструмента javadoc, будет содержать аннотационную информацию.

4.@Inherited

Эта аннотация связана с наследованием.Когда аннотация A добавляет эту аннотацию, аннотация A добавляется к классу, и подкласс этого класса наследует аннотацию A.

@Inherited
public @interface A{
}

@A
public class Parent{}

public class Son extends Parent{}//Son类继承了父类的A注解

5.@Repeatable

Эта аннотация, как следует из названия, имеет возможность повторять аннотацию. Представьте себе сценарий, в котором нам нужно регулярно выполнять некую задачу, которую нужно выполнять каждый понедельник и среду, и это время можно гибко регулировать, в это время может пригодиться эта мета-аннотация:

@Repeatable(Schedules.class)
public @interface Schedule {
    String date();
}

public @interface Schedules {
    Schedule[] value();
}

@Schedule(date = "周一")
@Schedule(date = "周三")
public class Executor {
}

Обратите внимание на содержание в скобках после этой мета-аннотации. Указанный класс здесь называется аннотацией контейнера, что означает контейнер для хранения этих нескольких аннотаций. Следовательно, мы создаем аннотацию @schedules в качестве аннотации контейнера @schedule. Аннотация контейнера должна содержать имя, это значение, тип возврата - это атрибут массива аннотации, который будет помещен в этот контейнер.

В-третьих, настройте одну аннотацию

Давайте возьмем очень распространенный сценарий аутентификации в веб-проектах в качестве примера, чтобы реализовать пользовательскую аннотацию самостоятельно. Во-первых, мы определяем личность пользователя системы, есть три личности: суперадминистратор, администратор и гость.

public enum  IdentityEnums {

    SUPER_ADMIN,
    ADMIN,
    VISIVOR

}

Затем мы определяем аннотацию разрешения:

@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Authorization {

    IdentityEnums[] value();
    
}

Затем используйте метод перехватчика, чтобы выполнить единое управление аутентификацией на всех страницах. Здесь показаны только некоторые коды клавиш:

public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if (handler instanceof HandlerMethod)
        {
            IdentityEnums user = getIdentityFromRequset(request);//这里从request里获取账号信息并判断身份,自己实现
            Authorization auth =((HandlerMethod) handler).getMethodAnnotation(Authorization.class);//获取方法上面的注解
            if (!Arrays.asList(auth.value()).contains(user)){
                return false;
            }
        }
        return true;
    }
}

Наконец, настройте перехватчик в файле конфигурации spring, чтобы открыть перехватчик:

<!-- 拦截器 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->
			<mvc:mapping path="/**" />
			<!-- 拦截器类 -->
			<bean
				class="com.xx.xx.AuthInterceptor"></bean>
		</mvc:interceptor>
	</mvc:interceptors>

При фактическом использовании мы добавим эту пользовательскую аннотацию к методу. Доступ к странице можно будет получить только при соблюдении разрешений удостоверения. Использование выглядит следующим образом:

@ResponseBody
@RequestMapping(value = "/management")
@Authorization({IdentityEnums.ADMIN,IdentityEnums.SUPER_ADMIN})
public String management(HttpServletRequest request, HttpServletResponse response)
{
    log.info("has permission!");
}