Вывод из первого предложения: аннотация — это средство «маркировки» с использованием метода, аналогичного @xxx, для класса, метода или атрибута, а затем содержимое метки может быть проанализировано и обработано соответствующим образом с помощью механизма отражения.
Аннотации — важная часть знаний в java, они были введены начиная с java5, особенно в фреймворке spring. Чаще всего используются @controller, @service и т. д. В этой статье мы начнем с принципа реализации аннотации и проанализируем его с помощью некоторых демонстрационных кодов.
1. Метод определения аннотации
Перейдите непосредственно к коду и посмотрите определение аннотации @Service весной:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
String value() default "";
}
Можно видеть, что определение аннотации очень похоже на определение интерфейса, но с добавлением символа @ определение аннотации имеет следующие соглашения:
- Можно определить только имена атрибутов, но не методы
- Видимость атрибутов только публичная и по умолчанию, а последняя по умолчанию, если не написано
- Типы атрибутов могут поддерживать только: базовые типы данных, строку, класс, перечисление, типы аннотаций и массивы вышеуказанных типов.
- Можно добавить ключевое слово по умолчанию, чтобы указать значение по умолчанию.Если поле не указывает значение по умолчанию, значение поля должно быть указано при аннотировании.
- При использовании значения в качестве имени атрибута вы не можете указать значение = "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!");
}