How to use Java annotations

what is annotation

Annotation in Java is a kind of metadata that can provide additional information about the program and help programmers better manage the program. Annotations are often used as markers for code or as a way to specify certain behaviors. In Java, annotations start with the @ symbol and are placed in various places in the code, including classes, methods, member variables, parameters, etc. Annotations can be obtained when the program is running through the reflection mechanism, and can have a certain impact on the execution of the program. Java provides some system annotations, such as @Override, @Deprecated, etc., and also supports custom annotations.

What is the difference between annotation and annotation

Annotations and annotations may seem similar, but they have very different meanings and how they are used.

Comments are some explanatory information added by programmers to the code. They will not have any impact on the operation of the program, but are only for the convenience of programmers to understand and maintain the code. Comments can be single-line or multi-line, added in the form of // or /.../.

Annotation is a kind of metadata used to mark program elements and provide additional information for compilers and frameworks. Annotations start with the @ symbol and can be added to various program elements such as classes, methods, and variables. They can provide a lot of convenience for various aspects of program development, maintenance, testing, and deployment. The role of annotations is not limited to providing explanatory information, it can also dynamically check and manipulate program elements through the reflection mechanism when the program is running.

Therefore, the main difference between annotations and annotations is that: annotations are only for code readability and assist programmers to understand, and have no actual function; while annotations have clear semantics and functions, and can provide various functions for program development and maintenance. Serve.

How to use custom annotations

Custom annotations need to be @interfacedefined, and its content can be defined by the programmer. Here is an example of a simple custom annotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    String value() default "";
}

The annotation is defined as @Log and can be used on methods. It has an optional value attribute for annotation users to add some descriptive information.

Note that the above code cannot be run directly, because it also involves the knowledge of aop aspects and reflection, see the end of the article for a complete sample program.

Custom annotations can have many uses in actual development, here are a few examples:

@ParamName annotation

In Java, method parameters do not have names and can only be accessed by index. Sometimes code readability will be affected by this problem, so we can use custom annotations to add names to method parameters:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface ParamName {
    String value();
}

How to use:

public void foo(@ParamName("param1") int param1, @ParamName("param2") double param2) {
    // do something
}

In this way, we can obtain the name of each parameter through the reflection mechanism at runtime.

@Cacheable annotation

In actual development, we often need to cache some methods that are computationally intensive or time-consuming. This function can be easily realized with custom annotations:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cacheable {
    String value();
}

Then we can use the reflection mechanism to get the method annotated by @Cacheable and cache its return value.

@Encrypt annotation

In actual development, we may need to encrypt some sensitive data instead of directly storing plaintext. Use custom annotations to add automatic encryption functions for certain variables, for example:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Encrypt {
    boolean enable() default true;
}

Then we can obtain the variable annotated by @Encrypt through the reflection mechanism. If the enable attribute of the annotation is true, the variable will be encrypted.

Common annotations in SpringBoot

@SpringBootApplication: This annotation is the entry annotation of Spring Boot, which integrates three annotations @Configuration, @EnableAutoConfiguration and @ComponentScan.

@RestController: declares a controller class, and all methods in this class return in the form of JSON.

@RequestBody: This annotation is used to receive the data of the request body and convert it into a Java object.

@RequestMapping: Define access routes, you can set request methods, parameters, request headers, etc.

@PathVariable: Get the path parameters in the RESTful interface.

@RequestParam: Get request parameters.

@Autowired: This annotation is used to automatically inject dependencies, and can be matched accurately with the @Qualifier annotation.

@Value: This annotation is used to obtain the attribute value in the configuration file.

@ConfigurationProperties: This annotation is used to inject the property values ​​in the configuration file into the Java Bean.

@EnableAutoConfiguration: This annotation automatically configures Spring applications, simplifying the configuration of Spring applications.

@ConditionalOnProperty: This annotation is used to control whether a configuration item is enabled, and can set default values, matching rules, etc.

@EnableAsync: This annotation enables asynchronous calls.

@Async: This annotation executes the marked method asynchronously.

@Scheduled: This annotation is used for timing tasks.

How do we use custom annotations in our daily development

Check parameter

We can perform parameter verification on the parameters of the controller method through custom annotations, for example:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidParam {
    String value();
}

public void update(@ValidParam("id") long id, @ValidParam("name") String name) {
    // do something
}

Then before the method is executed, we can verify the parameters according to the value of the @ValidParam annotation.

log output

We can mark some methods that need to log output through custom annotations, for example:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    String value();
}

@Log("更新订单状态")
public void updateOrderStatus() {
    // do something
}

Then when the method is executed, we can output the corresponding log according to the value of the @Log annotation.

cache management

We can mark some methods that need to be cached through custom annotations, for example:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Cache {
    long expire() default 3600; // 缓存失效时间,默认为3600秒
    String key() default ""; // 缓存key
}

@Cache(expire = 1800, key = "user_{#id}")
public User getUserById(long id) {
    // do something
}

Then before the method is executed, we can judge whether to obtain data from the cache according to the value of the @Cache annotation.

Spring AOP

We can use custom annotations to match Spring AOP to complete some requirements, for example:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckLogin {
    boolean required() default true; // 该接口是否需要登录
}
@CheckLogin
@RequestMapping("/getUserInfo")
public UserInfo getUserInfo() {
    // do something
}

Then in the AOP aspect, we can use the value of the @CheckLogin annotation to determine whether login verification is required.

Complete example code

Taking the first Log annotation as an example, let's see how to run the program.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    String value() default "";
}

Create a maven project with idea, open pom.xml, and add spring aop module. In addition, Spring IoC container and AspectJ dependencies need to be introduced.

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.9</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.3.9</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>

Log annotation

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Log {
    String value();
}

Log section

@Aspect
public class LogAspect {
    @Around("@annotation(com.zhujie.Log)")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        Log logAnnotation = method.getAnnotation(Log.class);
        if (logAnnotation != null) {
            String value = logAnnotation.value();
            System.out.println("Log: " + value);
        }

        return joinPoint.proceed();
    }


}

@Around

@Around("@annotation(com.zhujie.Log)")

The parameter in this @Around annotation is a pointcut expression, which is used to match the method that needs to be cut. The "@annotation(com.example.Log)" part is an annotation cut point, indicating that all methods modified by the @Log annotation need to be matched.

Specifically, @Around means that a piece of code is executed before and after the method is executed, wrapping the method that was originally to be executed. When this code is executed, the information of the method and parameters can be obtained, processed or logged.

@annotation indicates the aspect of annotation, followed by the type of annotation, for example, @annotation(com.zhujie.Log) indicates the aspect of @Log annotation. This aspect specifies that all methods modified by @Log annotation need to be intercepted to complete the corresponding operation.

UserService

@Service
class UserService {
    @Log("用户新增")
    public void add() {
    }
}

The @Log annotation is added to the add method, as long as the add method is executed, the user's addition will be printed.

Startup class:

@Configuration
@ComponentScan
@EnableAspectJAutoProxy
public class AppConfig {

    @Bean
    public LogAspect logAspect() {
        return new LogAspect();
    }

    public static void main(String[] args) {
        // 使用Spring上下文来管理Bean
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 获取LogService Bean
        UserService userService = context.getBean(UserService.class);

        // 调用含有@Log注解的方法
        userService.add();
    }
}

The @ComponentScan annotation is used to scan all components under the specified package and its subpackages, and inject them into the container automatically. However, for some special components, such as AOP aspects, etc., it needs to be manually injected into the container in the configuration class.

When using AOP, there are two ways: one is to use XML configuration to create aspects, and the other is to use annotations to create aspects. When using annotations to create an aspect, you need to use the @Bean annotation in the configuration class to create an aspect instance, and use the @EnableAspectJAutoProxy annotation to enable AOP proxy support.

Running AppConfig works as expected.

 

Guess you like

Origin blog.csdn.net/weixin_39570751/article/details/129682955