When using the Spring framework, we often extol how much annotated programming simplifies development time. A few annotations can solve a series of configuration problems and make writing code as easy as writing poetry.
We all know that in the early days of the Spring framework, much of the development was done using XML configuration. XML configuration can sometimes be tedious, such as mapping entity classes, and developing with XML can be complex. Also, annotations are sometimes more convenient than XML for dealing with immutable metadata, such as Spring declarative transaction management, which would be much more useful if written in XML. Annotations are tightly integrated with Java beans, greatly reducing the size of configuration files and increasing the readability and cohesiveness of Java beans.
Of course, regardless of whether you use annotations or XML, the simplest approach is best if your requirements are met.
Today I’m going to use a simple example to show you how to customize annotations to help you develop projects using annotations.
1. Meta-annotations
First, we define a class that requires a meta-annotation.
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface NotifyMonitor {
String value() default "";
}
Copy the code
1. @ Target
The @target annotation is specifically used to specify which Java elements a custom annotation can be applied to. It is defined using an enumerated type as follows:
Public enum ElementType {/** Class, interface (including annotation type), or enum declaration */ /** Class, */ TYPE, /** Field declaration (includes enum constants) */ /** Attribute declaration */ Field, /** Method declaration */ /** Formal parameter declaration */ /** Constructor */ /** Local variable declaration */ Local variable declaration */ /** Annotation type declaration */ /** Annotation type declaration */ /** ANNOTATION_TYPE, /** Package declaration */ /** Package declaration */Copy the code
As we have previously defined, @ Target ({ElementType. ANNOTATION_TYPE, ElementType METHOD, ElementType. TYPE}) is the ability to apply on the annotations, methods, and classes.
2, @ Retention
@Retention annotation translated as staying power. This is used to modify the vitality of custom annotations. The annotation life cycle has three phases:
- 1. Java source file stage;
- 2. Compile to.class file stage;
- 3. Operation stage.
Public enum RetentionPolicy {/** * Annotations are to be discarded by the compiler. /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. (Annotations will be recorded by the compiler in the class file, but will not be retained by the virtual machine at runtime, This is a default behavior) */ CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, So they may be read reflectively. * (Annotations will be recorded by the compiler in a.class file and retained by the virtual machine at runtime, So they can be read by reflection) * @ see Java lang. Reflect. AnnotatedElement * / RUNTIME}Copy the code
We use @Retention(retentionPolicy.runtime) so that annotations are recorded by the compiler in.class files and retained by the virtual machine at RUNTIME so that they can be read by reflection.
3, @ Inherited
When you use @Inherited on an annotation, it indicates that the annotation is Inherited by the child classes. Note that this annotation does not affect the member properties and methods of a class.
For classes, when a child inherits an annotation from its parent, the annotation needs to be identified by @Inherited.
For member attributes and methods, non-overridden methods retain the same annotations as their parent class, while implemented abstract methods and overridden methods do not have the same annotations as their parent class.
When the @NotifyMonitor annotation is added to A class, it is also applied to B if class B inherits from A.
As you can see, in SpringBoot, many classes have this annotation as well.
4, @ Documented
In addition to what we apply to annotation classes, the @Documented annotation preserves annotation information when generating a help document for a class using the Javadoc tool.
If you remove this annotation, it will not appear on the generated tool documentation, which is fine for some internal tool class annotations.
Use AOP to implement custom annotations
Let’s implement the following scenario, execute a task, and if the task reports an error, we will notify the designated person via a pin to handle it.
To do this, we might think of a try-catch approach. There’s nothing wrong with that, of course, but if you add this logic to a hundred different methods, wouldn’t you have to implement it a hundred times? Therefore, using custom annotations may be a good idea.
I wrote a class to implement the appeal method:
@Slf4j @Aspect @Component public class NotifyMonitorAspect { @Autowired private DingDingOpe dingDingOpe; @Autowired private StringRedisTemplate stringRedisTemplate; / / than everyone not unfamiliar to aop the @pointcut (" @ the annotation (com) nanju. Aop. NotifyMonitor) ") private void monitor () {} / * * * processing tasks Point.proceed () is used to perform the original task. Dingdingope.sendrobotmsg is a custom method used to notify nail * * @param point */ @around ("monitor()") public Object doAround(ProceedingJoinPoint point) { String jobName = getJobName(point); Object object = null; try { object = point.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); String url = getUrl(jobName); Dingdingope.sendrobotmsg (url, "task handling failed :"+"{"+throwable.getMessage()+"}", false); } return object; } /** * get the Job name, which uses the value of NotifyMonitor, Use different notification * @param Point pointcut */ private String getJobName(ProceedingJoinPoint Point) {MethodSignature signature = (MethodSignature) point.getSignature(); Method method = signature.getMethod(); NotifyMonitor jobs = method.getAnnotation(NotifyMonitor.class); if ("".equals(jobs.value())){ return null; } return jobs.value(); } /** * Get the notification address according to the Job name, use stringRedisTemplate, insert the input into redis, or put it in the database. @param notifyMonitor * */ private String getUrl(String notifyMonitor) {if (objects.isNULL (notifyMonitor)){ return TextUtils.dealNull(stringRedisTemplate.opsForValue().get("warn:dingdingUrl:")); }else{ return TextUtils.dealNull(stringRedisTemplate.opsForValue().get("warn:dingdingUrl:"+notifyMonitor)); }}}Copy the code
Let’s test that out
1. Annotate the method @notifyMonitor
2. Call the method
3. The command is executed successfully
We could also try adding value to @notifyMonitor (value=” XXX “is equivalent to” XXX “because there is only one property)
4. Execution results
Thus, an annotated task handling, notification function is complete. Custom annotations can not only extend before, during, and after method performs, obtain information such as the method, in the class to implement annotation, modify parameters and return values, also can achieve including thread pool, distributed lock, data validation etc when you can think of most of the operation, I also realized some functions in work, reduce a lot of duplicate code, It also makes the code more readable.
With that in mind, you might as well write your own custom annotations to simplify our project.
Hello everyone, I am Nanju who has been practicing Java for two and a half years. Here is my wechat. If you need the previous map or want to exchange experience with each other, you can communicate with each other.