Java custom annotations in action

What are annotations?

Annotations are written in a.java file using @interface as the keyword, so annotations are a Java data type; Annotations A feature introduced since JDK1.5 to annotate classes, interfaces, methods, properties, method parameters, and so on.

The role of annotations

Annotations have the following four functions:

  • Generate a document: GeneratejavadocDocuments, such as@Documented;
  • Compile check: Checking and validating code during compilation, as in@Override;
  • Compile-time processing: Specific processing of code at compile time, such as@Data;
  • Runtime processing: The runtime performs specific processing on code, such as@Slf4j;

Annotations and reflections

After defining the annotation, we can retrieve the content of the annotation by reflecting the java.lang.Reflect mechanism. Note: This is only available by reflection if the scope of the annotation is defined as Runtime.

The following are the specific apis:

Method statement methods
Gets an annotation of a certain type public <A extends Annotation> A getAnnotation(Class<A> annotationClass);
Get all annotations (including Inherited annotations in the parent class) public Annotation[] getAnnotations();
Gets annotations for declarations (excluding Inherited annotations in the parent class) public Annotation[] getDeclaredAnnotations();
Determines whether an object is annotated by an annotation public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
Gets all fields declared by a class public Field[] getDeclaredFields() throws SecurityException;
Get a method public Method getMethod(String name, Class<? >... parameterTypes);

Custom annotation practice

AOP can be used to control permissions, log output and idempotence check.

Take the idempotent one check as an example:

Step 1: Define annotations

package com.wedjg.cloud.finance.aspect.idem;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableIdem {
    /** * idempotent time interval (seconds) *@return* /
    int expired(a) default 3;
}
Copy the code

Step 2: Use annotations

@PostMapping("test")
@EnableIdem
public CommonResult test(@RequestBody DemoDTO dto) {
    financeService.test(dto);
    return CommonResult.success(true);
}
Copy the code

Step 3: Write the cut

@Aspect
@Component
public class IdempotentAspect {

    public static final Log log = LogFactory.get();

    public static final String KEY = "Idem|";

    @Before("@annotation(com.wedjg.cloud.aspect.idem.EnableIdem)")
    public void handle(JoinPoint joinPoint) throws Exception{
        // Get parameter values
        Object[] args = joinPoint.getArgs();
        // Construct the cache key
        // The hashcode of the method path + parameter is used as the key, which may be repeated in some cases
        // It should be adjusted according to business in actual use
        StringBuilder sb = new StringBuilder();
        for (Object arg : args) {
            sb.append(Convert.toStr(arg));
        }
        String methodPath = joinPoint.getSignature().getDeclaringTypeName() + CharUtil.DOT + joinPoint.getSignature().getName();
        String redisKey = KEY + methodPath + sb.toString().hashCode();

        // Save the key to redis. Be careful to keep setNx and EXPIRED atomic;
        // If the key already exists, the request was made within the expired() time range. The current request is a duplicate request.
        // If the key does not exist, set the current key to redis and set the expiration time.
        // Get information about annotations
        EnableIdem enableIdem = this.getDeclaredAnnotation(joinPoint);
        if(JedisUtil.setnxAndExpire(redisKey, enableIdem.expired(), "1") = =0L) {
            throw new BaseException("Operation too frequent, please try again later!"); }}/** * Get the annotation declared in the method **@param joinPoint
     * @return
     * @throws NoSuchMethodException
     */
    public EnableIdem getDeclaredAnnotation(JoinPoint joinPoint) throws NoSuchMethodException {
        // Get the method name
        String methodName = joinPoint.getSignature().getName();
        // reflection gets the target classClass<? > targetClass = joinPoint.getTarget().getClass();// Get the parameter type of the methodClass<? >[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();// Get method details based on class, method, parameter type (overload)
        Method objMethod = targetClass.getMethod(methodName, parameterTypes);
        // Get the annotation information for the method definition
        EnableIdem annotation = objMethod.getDeclaredAnnotation(EnableIdem.class);
        / / return
        returnannotation; }}Copy the code

Refer to the article

  • Java custom Annotation Annotation details
  • Java Basics – Annotation mechanism details
  • Redis operates both setnx and EXPIRE

  1. The results of one or multiple requests initiated by the user for the same operation are consistent, without side effects caused by multiple clicks ↩