Star: github.com/yehongzhi/l…

What are annotations

Annotations are a new feature introduced in JDK1.5 to simplify code and make programming more efficient. In fact, annotations are not uncommon in daily development, such as @Override and @SuppressWarnings built into Java, or @Service and @Controller provided by Spring, etc. As these annotations are used more and more frequently, As a developer, you really need to learn more.

Built-in Annotations in Java

Let’s start with three built-in annotations in Java:

Override: Checks if the current method definition overrides a method in the parent class. If it does not, the compiler reports an error.

@SuppressWarnings: Ignore compiler warnings.

Deprecated: Used to indicate that the class or method is Deprecated and developers are advised not to use it.

Yuan notes

Meta-annotations are just annotations that describe annotations. There are four main meta-annotations, which are:

@Target

Used to describe the scope of the annotation, that is, where the annotation can be used. The value can be:

CONSTRUCTOR: Used to describe the CONSTRUCTOR.

FIELD: Describes a FIELD.

LOCAL_VARIABLE: Used to describe local variables.

METHOD: Describes methods.

PACKAGE: Used to describe packages.

PARAMETER: describes parameters.

TYPE: Describes classes, including class, interface, and enum.

@Retention

Indicates the level at which the annotation information needs to be saved and is used to describe the annotation life cycle, as defined by the enumeration RetentionPoicy.

SOURCE: Valid in SOURCE files (i.e., retained in SOURCE files), appears only in SOURCE code and is discarded by the compiler.

CLASS: Valid in the CLASS file (that is, CLASS preserved), but discarded by the JVM.

RUNTIME: The JVM will retain annotations at RUNTIME, so they can be read by reflection.

If you’re just doing some checking, use SOURCE, such as @Override and @SuppressWarnings.

If you want to do some pre-processing at compile time, use CLASS.

If you need to retrieve attribute values for annotations to do some RUNTIME logic, you can use RUNTIME.

@Documented

Including this annotation in Javadoc means that the annotation will be extracted into a document by the Javadoc tool. It is a tag annotation and has no members.

@Inherited

Is a tag annotation that specifies that the annotation can be inherited. Using the @Inherited Class annotation indicates that this annotation can be used with a child Class of the Class.

Custom annotations

Let’s use a custom annotation @logAPI for a method that prints logs when called and displays the arguments passed in by the caller and the result returned by the call on the console.

Custom annotation

First I define the annotation @logAPI, which is used in the method, in order to be able to read the annotation information in reflection, which is of course set to RUNTIME.

@Target(value = ElementType.METHOD)
@Documented
@Retention(value = RetentionPolicy.RUNTIME)
public @interface LogApi {
}
Copy the code

Annotations, which have no attributes, are tag annotations.

If you want to pass a property value, you can also set the value of the property, such as the @requestMapping annotation.

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
    @AliasFor("path")
	String[] value() default {};
}
Copy the code

If in use. Set value only, you can ignore value, for example:

RequestMapping(value = {"/list"})
// Ignore value
@RequestMapping("/list")
public Map<String, Object> list(a) throws Exception {
    Map<String, Object> userMap = new HashMap<>();
    userMap.put("Miss Number One"."Michelle Reis");
    userMap.put("Miss 2"."Wing Yee Yuen");
    userMap.put("Miss 3"."Zhang");
    userMap.put("Miss 4".Maggie Cheung);
    return userMap;
}
Copy the code

Tag annotation

Once you’ve defined annotations, it’s easy to mark them where you need them.

@LogApi
@RequestMapping("/list")
public Map<String, Object> list(a) throws Exception {
	// Business code...
}
Copy the code

Parsing the annotation

The most important step is to parse annotations, which are typically resolved using Spring’s AOP techniques in a project, or the Lifecycle functions of the Spring container if you only need to parse once.

The scenario here is to print a log every time a method is called, so AOP is appropriate.

Create a section class LogApiAspect to parse.

@Aspect
@Component
public class LogApiAspect {
	// The cut point is the method marked with the @logAPI annotation
    @Pointcut("@annotation(io.github.yehongzhi.user.annotation.LogApi)")
    public void logApi(a) {}// Wrap around the notification
    @Around("logApi()")
    @SuppressWarnings("unchecked")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long starTime = System.currentTimeMillis();
        // Get the Class of the called method by reflection
        Class type = joinPoint.getSignature().getDeclaringType();
        // Get the class name
        String typeName = type.getSimpleName();
        // Get the Logger object
        Logger logger = LoggerFactory.getLogger(type);
        / / the method name
        String methodName = joinPoint.getSignature().getName();
        // Get the parameter list
        Object[] args = joinPoint.getArgs();
        // An array of arguments to Class
        Class[] clazz = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            clazz[i] = args[i].getClass();
        }
        // Get the method called by reflection
        Method method = type.getMethod(methodName, clazz);
        // Get method parameters
        Parameter[] parameters = method.getParameters();
        // Concatenate string in the format {parameter 1: value 1, parameter 2:: value 2}
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            String name = parameter.getName();
            sb.append(name).append(":").append(args[i]).append(",");
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.lastIndexOf(","));
        }
        // Execution result
        Object res;
        try {
            // Execute the target method to get the execution result
            res = joinPoint.proceed();
            logger.info("The {}.{} method was successfully called with [{}] and returns [{}].", typeName, methodName, sb.toString(), JSONObject.toJSONString(res));
        } catch (Exception e) {
            logger.error("An exception occurred when calling the {}.{} method", typeName, methodName);
            // If an exception occurs, an exception is thrown
            throw e;
        } finally {
            logger.info("Call {}.{} method, time {}ms", typeName, methodName, (System.currentTimeMillis() - starTime));
        }
        // Returns the execution result
        returnres; }}Copy the code

After defining the aspect class, you need to add start AOP annotations to the start class.

@SpringBootApplication
// Add this annotation to turn on AOP
@EnableAspectJAutoProxy
public class UserApplication {
    public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); }}Copy the code

test

We will also add a parameter interface to the Controller control layer.

@LogApi
@RequestMapping("/get/{id}")
public String get(@PathVariable(name = "id") String id) throws Exception {
    HashMap<String, Object> user = new HashMap<>();
    user.put("id", id);
    user.put("name"."Guan Zhilin");
    user.put("Classic role".Thirteen Aunts);
    return JSONObject.toJSONString(user);
}
Copy the code

Start the project, then request the interface list(), and we see log information for the called method appear on the console.

Request the interface get() with parameters, and you can see that the parameter name and parameter value are printed on the console.

This function of recording interface request parameters and return values is almost always used in real projects, because it facilitates system troubleshooting and performance tuning, etc.

We can also learn how to use annotations and aspect programming in this example, and kill two birds with one stone!

conclusion

The use of annotations can greatly reduce the amount of code required for development, so there will be a lot of annotations used in actual project development. Especially for common basics such as logging, transaction management, and permission control, annotations are efficient and elegant.

For custom annotations, there are three main steps: define annotations, mark annotations, and parse annotations.

That’s the end of this article, thank you for reading, I hope you can have a harvest after reading this article!

The article continues to update, wechat search “Java technology enthusiasts”, the first time after paying attention to the technical article push, article classification is collected on github: github.com/yehongzhi, you can always find what you are interested in

Please give me a thumbs-up if you think it is useful. Your thumbs-up is the biggest motivation for my creation

I’m a programmer who tries to be remembered. See you next time!!

Ability is limited, if there is any mistake or improper place, please criticize and correct, study together!