In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article introduces the relevant knowledge of "how to use custom annotations". In the operation of actual cases, many people will encounter such a dilemma. Then let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Basic knowledge
In Java, there are two types of annotations, meta-annotations and custom annotations.
Many people mistakenly think that custom annotations are defined by developers, while those provided by other frameworks do not count, but in fact, the annotations we mentioned above are actually custom annotations.
There are many descriptions of "meta" in the programming world, such as "meta-annotations", "meta-data", "metaclass", "meta-table" and so on.
In general, we understand meta-annotations as annotations that describe annotations, metadata as data that describe data, and metaclass as classes that describe classes.
So, in Java, except for a limited number of fixed "descriptive annotations", all annotations are custom annotations.
Four standard annotation classes (meta-annotations) are provided in JDK to annotate annotation types. They are:
@ Target @ Retention @ Documented @ Inherited
Except for the above four, all other annotations are custom annotations.
We are not going to introduce the functions of the above four meta-annotations in depth here. You can learn by yourself.
The examples to be mentioned in this article are all real scenarios used by the author in his daily work, and one thing in common is that they all use Spring's AOP technology.
I believe many people know what AOP is and its usage, so I won't introduce it here.
Use custom annotations for logging
I don't know if you have ever encountered a similar request, that is, we hope to do unified log processing at the entrance or exit of a method, such as recording the input and output parameters, recording the execution time of the method, and so on.
If you write such code in each method, on the one hand, there will be a lot of code repetition, on the other hand, it is easy to be left out.
In this scenario, you can use custom annotations + facets to achieve this function.
Suppose we want to record exactly what is done in this operation on some web request methods, such as adding a record or deleting a record.
First, let's customize an annotation:
/ * * Operate Log Custom Notes * / @ Target (ElementType.METHOD) @ Retention (RetentionPolicy.RUNTIME) public @ interface OpLog {/ * Business types, such as add, delete, modify * @ return * / public OpType opType () / * business object name, such as order, inventory, price * @ return * / public String opItem (); / * Business object number expression, which describes how to get the order number expression * @ return * / public String opItemId_Expression ();}
Because we not only need to record what is done in the log, but also need to know the specific unique identification of the object being operated, such as the order number information.
But the parameter type of each interface method must be different, so it is difficult to have a unified standard, so we can use the Spel expression to indicate how to obtain the unique identity of the corresponding object.
With the above notes, you can write the section next. The main code is as follows:
The aspect processing class of / * OpLog, which is used to obtain log information through annotations and log records * @ author Hollis * / @ Aspect @ Component public class OpLogAspect {private static final Logger LOGGER = LoggerFactory.getLogger (OpLogAspect.class); @ Autowired HttpServletRequest request @ Around ("@ annotation (com.hollis.annotation.OpLog)") public Object log (ProceedingJoinPoint pjp) throws Exception {Method method = ((MethodSignature) pjp.getSignature ()) .getMethod (); OpLog opLog = method.getAnnotation (OpLog.class); Object response = null; try {/ / Target method execution response = pjp.proceed () } catch (Throwable throwable) {throw new Exception (throwable);} if (StringUtils.isNotEmpty (opLog.opItemId_Expression () {SpelExpressionParser parser = new SpelExpressionParser (); Expression expression = parser.parse_Expression (opLog.opItemId_Expression ()); EvaluationContext context = new StandardEvaluationContext () / / get the parameter value Object [] args = pjp.getArgs (); / / get the name of the runtime parameter LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer (); String [] parameterNames = discoverer.getParameterNames (method) / / bind parameters to if (parameterNames! = null) {for (int I = 0; I < parameterNames.length; iTunes +) {context.setVariable (parameterNames [I], args [I]) in context }} / / put the resp of the method into context as a variable The variable name is the hump form if (response! = null) {context.setVariable (CaseFormat.UPPER_CAMEL.to (CaseFormat.LOWER_CAMEL, response.getClass (). GetSimpleName ()), response) whose name is converted to lowercase. } / / parse the expression and get the result String itemId = String.valueOf (expression.getValue (context)); / / execute logging handle (opLog.opType (), opLog.opItem (), itemId);} return response } private void handle (OpType opType, String opItem, String opItemId) {/ / print out LOGGER.info via log ("opType =" + opType.name () + ", opItem =" + opItem + ", opItemId =" + opItemId);}}
Among the above sections, there are a few points that we should pay attention to:
1. Use the @ Around annotation to specify that the section is set for the method marked with OpLog.
2. Using the relevant methods of Spel, through the specified representation, the unique identity of the target object is obtained from the corresponding parameters.
3. After the execution of the remethod is successful, the log is output.
With the above sections and notes, we only need to add annotations to the corresponding methods, such as:
@ RequestMapping (method = {RequestMethod.GET, RequestMethod.POST}) @ OpLog (opType = OpType.QUERY, opItem = "order", opItemIdExpression = "# id") public @ ResponseBody HashMap view (@ RequestParam (name = "id") String id) throws Exception {}
The unique identity of the manipulated object is already found in the parameter list of the input parameters, which can be specified directly using # id.
If the unique identity of the object being manipulated is not in the input parameter list, it may be one of the attributes in the input object. The usage is as follows:
RequestMapping (method = {RequestMethod.GET, RequestMethod.POST}) @ OpLog (opType = OpType.QUERY, opItem = "order", opItemIdExpression = "# orderVo.id") public @ ResponseBody HashMap update (OrderVO orderVo) throws Exception {}
The above can be obtained from the value of the id property of the OrderVO object of the input parameter.
What if the unique identity we want to record is not in the input parameter? The most typical is the insertion method, until the insertion is successful, do not know what the primary key ID is, what to do?
One thing we did in the section above is that we parse the return value of the method using an expression, and if we can parse to get a specific value, we can. As follows:
RequestMapping (method = {RequestMethod.GET, RequestMethod.POST}) @ OpLog (opType = OpType.QUERY, opItem = "order", opItemIdExpression = "# insertResult.id") public @ ResponseBody InsertResult insert (OrderVO orderVo) throws Exception {return orderDao.insert (orderVo);}
The above is a simple logging scenario using custom annotations and facets. Let's take a look at how to use annotations to verify method parameters.
Use custom annotations for pre-checking
When we provide an interface to the outside, we will have certain requirements for some of the parameters, such as some parameter values cannot be empty. In most cases, we need to check on our own initiative to determine whether the value passed in by the other party is reasonable.
A method of parameter verification using HibernateValidator + custom annotations + AOP is recommended.
First, we will have a specific input class, which is defined as follows:
Public class User {private String idempotentNo; @ NotNull (message = "userName can't be null") private String userName;}
Above, note that the parameter userName cannot be null.
Then use Hibernate Validator to define a utility class for parameter verification.
/ * Parameter Verification tool * @ author Hollis * / public class BeanValidator {private static Validator validator = Validation.byProvider (HibernateValidator.class) .configure () .failFast (true) .buildValidatorFact ory () .getValidator (); / * * @ param object object * @ param groups groups * / public static void validateObject (Object object, Class...) Groups) throws ValidationException {Set constraintViolations = validator.validate (object, groups); if (constraintViolations.stream (). FindFirst (). IsPresent ()) {throw new ValidationException (constraintViolations.stream (). FindFirst (). Get (). GetMessage ());}
The above code verifies a bean, and if it fails, it throws a ValidationException.
Next, define an annotation:
/ * * facade API annotation for unified parameter verification and exception capture of facade * * Note: note that the return value of this method must be a subclass of BaseResponse * * / @ Target (ElementType.METHOD) @ Retention (RetentionPolicy.RUNTIME) public @ interface Facade {}
This annotation does not contain any parameters and is only used to indicate which methods need to be checked for parameters.
Next, define the section:
/ * * Facade aspect handling class, unified statistics for parameter verification and exception capture * @ author Hollis * / @ Aspect @ Component public class FacadeAspect {private static final Logger LOGGER = LoggerFactory.getLogger (FacadeAspect.class); @ Autowired HttpServletRequest request @ Around ("@ annotation (com.hollis.annotation.Facade)") public Object facade (ProceedingJoinPoint pjp) throws Exception {Method method = ((MethodSignature) pjp.getSignature ()) .getMethod (); Object [] args = pjp.getArgs (); Class returnType = ((MethodSignature) pjp.getSignature ()) .getMethod () .getReturnType () / / iterate through all parameters and verify the parameters for (Object parameter: args) {try {BeanValidator.validateObject (parameter);} catch (ValidationException e) {return getFailedResponse (returnType, e) }} try {/ / Target method executes Object response = pjp.proceed (); return response;} catch (Throwable throwable) {return getFailedResponse (returnType, throwable) }} / * defines and returns a generic failure response * / private Object getFailedResponse (Class returnType, Throwable throwable) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {/ / if the return value is a subclass of type BaseResponse Then create a general failure response if (returnType.getDeclaredConstructor () .newInstance () instanceof BaseResponse) {BaseResponse response = (BaseResponse) returnType.getDeclaredConstructor () .newInstance () Response.setSuccess (false); response.setResponseMessage (throwable.toString ()); response.setResponseCode (GlobalConstant.BIZ_ERROR); return response;} LOGGER.error ("failed to getFailedResponse, returnType (" + returnType + ") is not instanceof BaseResponse"); return null;}}
The above code, similar to the previous section, mainly defines an aspect, which uniformly handles all methods marked @ Facade, that is, verifies the parameters before starting the method call, and returns a fixed failed Response if the verification fails.
It is important to note that a fixed BaseResponse can be returned here because we will require that the response of all our external interfaces must inherit the BaseResponse class, which defines some default parameters, such as error codes.
After that, you only need to add corresponding annotations to the methods that require parameter verification:
@ Facade public TestResponse query (User user) {}
In this way, with the above notes and sections, we can exercise unified control over all external methods.
In fact, the above facadeAspect I omitted a lot of things, we really use that section, not only do the parameter check, but also do a lot of other things. For example, the unified handling of exceptions, the unified conversion of error codes, the execution time of recording methods, the input and output parameters of recording methods, and so on.
In short, using aspect + custom annotations, we can do a lot of things together. In addition to the above scenarios, we have many similar uses, such as:
Unified cache processing. For example, some operations need to check the cache before and update the cache after the operation. This can be handled uniformly through custom annotations and sections.
In fact, the code is similar, and the idea is relatively simple, that is, through custom annotations to mark tired or methods that need to be processed by the section, and then interfere with the execution process of the method in the section, such as doing some special operations before or after execution.
Using this method can greatly reduce the repetitive code, greatly improve the elegance of the code, and make it easy for us to use.
This is the end of "how to use Custom comments". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.