5 minutes to understand the specific use of java annotation @ Annotation

  • 2021-07-26 07:52:01
  • OfStack

First of all, a conclusion: Annotation is a means to "tag" classes, methods, or attributes in a way similar to @ xxx, and then analyze the contents of tags through reflection mechanism and process them accordingly.

Annotation is an important knowledge point in java, which has been introduced since java5, and is widely used in spring framework. Commonly used are @ controller, @ service and so on. This paper will start from the implementation principle of annotations and analyze the implementation of some demo codes.

1. How to define annotations

Go directly to the code and look at the definition of @ Service annotation in spring:


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

 String value() default "";
 
}

You can see that the annotation definition is very similar to the interface definition, but with the @ character, the annotation definition has the following conventions:

You can only define property names, not methods The visibility of attributes is only public and default, and the latter is defaulted if it is not written The type of attribute can only support arrays of basic data type, string, class, enum, Annotation and above You can add defult keyword to indicate the default value. When a field does not indicate the default value, you must specify the value of this field when annotating. When using value as the attribute name, you can not explicitly specify value= "xxx", for example, you can directly use @ Service ("xxxService")

2. Meta-annotation

The so-called meta-annotation is the annotation which is implemented by default in java. The total number of meta-annotations is 5. Let's take the @ Service annotation mentioned above as an example:

1.@Target

This annotation is used to indicate the scope of use of the current annotation, and @ Target ({ElementType. TYPE}) represents @ Service. This annotation is specifically used to annotate classes, interfaces, or enumerated types. When this annotation is added to a method, an error will be reported. You can see that the annotation position is an enumerated type, which is fully defined as follows


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

This annotation is used to indicate the life cycle of the current annotation. When the annotation function will be retained, for example, @ Retention (RetentionPolicy. RUNTIME) means that it is still valid during the running of the program. At this time, the annotation information can be obtained through reflection. The complete enumeration definition is as follows


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

When annotated by this annotation, documents generated using the javadoc tool carry annotation information.

4.@Inherited

This annotation is related to inheritance. When the A annotation is added, the A annotation is added to a class, and the subclasses of this class inherit the A annotation.


@Inherited
public @interface A{
}

@A
public class Parent{}

public class Son entends Parant{}//Son Class inherits the parent class's A Annotation 

5.@Repeatable

As the name implies, this annotation has the ability to repeat annotations. Imagine such a scenario, we need to execute a task regularly, which needs to be executed on Monday and Wednesday every week, and this time can be flexibly adjusted. At this time, this meta-annotation can come in handy:


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

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

@Schedule(date = " Week 1")
@Schedule(date = " Week 3")
public class Executor {
}

Notice the contents in parentheses after this meta-annotation. The class specified here is called container annotation, which means the container that holds these annotations. Therefore, we create a @ Schedules annotation as the container annotation of @ Schedule. The container annotation must contain an attribute named value and the return type is the annotation array to be put into this container.

3. Custom implementation of 1 annotation

Let's take the authentication scenario which is very common in web project as an example to implement a custom annotation.

First of all, we define the identity of the users of the system, including super administrator, administrator and visitor.


public enum IdentityEnums {

  SUPER_ADMIN,
  ADMIN,
  VISIVOR

}

Next, we define one permission annotation:


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

  IdentityEnums[] value();
  
}


Then use the interceptor to carry out unified authentication management for all pages. Only one key code is shown here:


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);// Here from request Get the account information and judge the identity, and realize it yourself 
      Authorization auth =((HandlerMethod) handler).getMethodAnnotation(Authorization.class);// Get the annotation above the method 
      if (!Arrays.asList(auth.value()).contains(user)){
        return false;
      }
    }
    return true;
  }
}

Finally, configure the interceptor in the spring configuration file to open the interceptor:


<!--  Interceptor  -->
 <mvc:interceptors>
 <mvc:interceptor>
  <!--  What matches is url Path,   If you do not configure or /**, Will intercept all Controller -->
  <mvc:mapping path="/**" />
  <!--  Interceptor class  -->
  <bean
  class="com.xx.xx.AuthInterceptor"></bean>
 </mvc:interceptor>
 </mvc:interceptors>

In actual use, we will add this custom annotation to the method, and only when the identity permissions meet can we access the page as follows:
@ResponseBody


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

Related articles: