The original address

preface

Annotations are a new feature introduced after JDK1.5 in java.lang. Annotation, which is essentially a special mark on code that can be read and processed at compile, class load, and run time. This article looks at how to customize annotations and some of the basics of annotations, and then makes some new tricks with this AOP in practice.

This paper is divided into three parts

  • Annotation analysis
  • Custom annotations
    • Compile-time annotations
    • Runtime annotations
  • Integrating AOP

It could have been divided into two articles, but I decided to write one after thinking about it. Strike while the iron is hot.

Annotation analysis

How do annotations work

To customize annotations, you need to know how annotations are constructed and analyze how annotations work in conjunction with common annotations in your project.

Take a look at the @Override annotation, whose main purpose is to do format checking at compile time. Click on the @Override implementation.

I click on it and it’s empty and there’s nothing but two meta-annotations, so how does that work

In fact, @Override can be understood as a tag, which has no actual logic processing, and the logic is implemented by the user of the annotation. It is essentially a “token annotation” known only to the compiler.

For example, your boss asks you to organize some important documents, but there are so many documents that you definitely need to mark some important documents. When you hand them to your boss, what will he do? The boss, of course, sees a marked document and checks it.

In conjunction with the above example, you are using the @Override annotation. Your boss is the JVM. At compile time, your boss checks the annotation and the JVM finds it and processes it.

To sum it up:

Define annotations, scan annotations, and perform logic

Yuan notes

The JDK provides several “meta annotations” before we customize them. Meta annotations are the annotations that define the annotations.

There are four meta-annotations, all of which can be found under java.lang.annotation

  • @Target
  • @Retention
  • @Documented
  • @Inherited

@Target

The @target annotation is used to define where the annotation will be used, where the described annotation can be used. The @target argument is an ElementType enumeration class, which is explained below.

Enumeration 😀

Role 😊

ElementType.PACKAGE Annotations are used in packages

ElementType.TYPE Annotations apply to types (classes, interfaces, annotations, enumerations)

ElementType.ANNOTATION_TYPE Annotations act on annotations

ElementType.CONSTRUCTOR Annotations apply to constructors

ElementType.METHOD Annotations apply to methods

ElementType.PARAMETER Annotations apply to method parameters

ElementType.FIELD Annotations apply to attributes

ElementType.LOCAL_VARIABLE Annotations apply to local variables

@target applies to all targets by default if the range is not set

Take a look at the @target source code

There is a Value argument that returns ElementType[], which is the enumerated class above.

@Retention

The purpose of the @Retention annotation is to specify the annotation’s lifetime. For example, it can be handled at compile time and run time. Its enumerated class is RetentionPolicy

Enumeration 😀

Role 😊

RetentionPolicy.SOURCE Source reserved, compile time can be processed

RetentionPolicy.CLASS The Class file is reserved for Class loading

RetentionPolicy.RUNTIME Reserved at run time and processed at run time

The default for @retention is retentionPolicy. CLASS which is handled when the CLASS loads

@ Retention source

@Documented

Well, @documented is a simpler one, and their main purpose is to document an annotation. When javadoc is generated, there is no annotation, but if the annotation is qualified with @documented, the resulting document contains the annotation. This comment may be removed in a later version but I won’t go into details here.

@Inherited

The @Inherited annotations are inheritable, which means that when we decorate a class with @Inherited, the child classes of the class inherit the annotations by default.

The source code

Custom annotations

The meta-annotation of annotations was introduced above, so now it’s time to practice custom annotations.

GIT project address: https://github.com/scramblecode/project-demos

Create the project as usual. Here is an example of this article you can download.

Let’s start with a simple example. The request parameters are then retrieved using custom annotations and interceptors in SpringBoot.

Simple definition annotations

Here are two examples: compile-time annotations and run-time annotations. Finally, in conjunction with SpringBoot+AOP to write a very practical example in a project

Compile-time annotations

Creating compile-time annotations We start by creating a dependency project as the annotation handler.

First create an annotation interface, using IDEA to create optional annotations.

When creating a DataTest annotation, the purpose of the annotation is to print Hello World! At compile time if the annotation is used. .

Then write an annotation processor, using AbstractProcessor, which I’ll use only briefly in this article, if I get the chance to write an article on AbstractProcessor.

Specific code

Then you need to create the meta-inf file, here it is recommended to use Google’s auto – service can automatically generate meta-inf/services/javax.mail annotation. Processing. The Processor.

Add dependencies

< the dependency > < groupId > com. Google. Auto. Service < / groupId > < artifactId > auto - service < / artifactId > < version > 1.0 rc5 < / version >  </dependency>Copy the code

Introduce annotation handlers in your main project after definition. Add a dependency on the local annotation processor to the POM file

Create a simple class and annotate it with @datatest

Run the start build, and you’ll see the console output the following.

Compile-time annotations can be written to generate code using tools such as Lombok.

Runtime annotations

Simply create an annotation to get the name and package path identified by the annotation.

Start by creating an annotation, defining the runtime annotation target as a class attribute, etc.

Using annotations

@getClassName (value = "") public class Student {}Copy the code

Then create an annotation handling class and run

Console output.

Integrating AOP

In Web development, there is often logging output, and then there is the runtime of the interface. Now let’s implement this functionality using custom annotations plus AOP.

First, improve the project and add a test interface

Then create log annotations.

Then define the aspect class

@Aspect @Component @Slf4j public class LoggerAspect { private static final Logger logger = LoggerFactory.getLogger(LoggerAspect.class); @Pointcut("@annotation(com.lqcoder.annotationdemo.annotation.OutputLog)") public void weblog(){ } @Around("weblog()") public Object around(ProceedingJoinPoint point) throws Throwable { long beginTime = System.currentTimeMillis(); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); List<Object> logArgs = Arrays.stream(point.getArgs()) .filter(arg -> (! (arg instanceof HttpServletRequest) && ! (arg instanceof HttpServletResponse))) .collect(Collectors.toList()); Try {logger.info(" Request URL ={}, request parameter ={}", request.getrequestUri (), json.tojsonString (logArgs)); } catch (Exception e) {logger.error(" error ", e); } Object result = point.proceed(); // Run time (ms) long time = system.currentTimemillis () -beginTime; Try {logger.info(" request time ={}ms, return result ={}", time, json.tojsonString (result)); } catch (Exception e) {logger.error(" return parameter fetch Exception ", e); } return result; }}Copy the code

Once defined, restart the project and invoke the interface

The running result shows that it takes effect.

End of this article.