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.