spring's Custom Annotation Analysis

Preface spring provides rich annotations, but sometimes does not meet the complex needs of existing businesses. We can refine our business framework b...
@Target
@Retention
@Document
@Inherited
OperationType.java
OperationUnit.java
OperationLog.java
OperationLogDetail.java
LogAspect.java
DemoController.java
DemoServiceImpl.java
DemoService.java
Preface

spring provides rich annotations, but sometimes does not meet the complex needs of existing businesses. We can refine our business framework by customizing annotations.

Sending:
The only way to success is to make things perfect and reward people for their diligence.

Note Creation Notes

@Target

@Target - Where is the comment used and the default value is any element, indicating where the comment is used.Available ElementType s specify parameters
ElementType.CONSTRUCTOR: Used to describe constructors
ElementType.FIELD: Member variables, objects, attributes (including enum instances)
ElementType.LOCAL_VARIABLE: Used to describe local variables
ElementType.METHOD: Used to describe methods
ElementType.PACKAGE: Used to describe packages
ElementType.PARAMETER: Used to describe parameters
ElementType.TYPE: Used to describe classes, interfaces (including annotation types), or enum declarations

@Retention

Indicates at what level the annotation information needs to be saved.
When to use this annotation, the life cycle of the annotation, specified using RetentionPolicy
RetentionPolicy.SOURCE: Discarded at compile time.These annotations have no meaning after compilation, so they do not write byte codes.@Override, @SuppressWarnings are notes of this type.
RetentionPolicy.CLASS: Discarded when class loads.Useful in the processing of byte code files.Annotations use this method by default
RetentionPolicy.RUNTIME: This annotation is never discarded and is maintained during runtime, so you can use a reflection mechanism to read its information.This is often the way we customize annotations.

@Document

Include comments in Javadoc

@Inherited

Allow subclasses to inherit comments from their parent

Example description

OperationType.java

`package com.basic.bl.rest.demo.aop;
public enum OperationType {

/** * Operation type */ UNKNOWN("unknown"), DELETE("delete"), SELECT("select"), UPDATE("update"), INSERT("insert"); private String value; public String getValue() { return value; } public void setValue(String value) { this.value = value; } OperationType(String s) { this.value = s; }

}`

OperationUnit.java

`package com.basic.bl.rest.demo.aop;

public enum OperationUnit {

/** * Unit to be operated on */ UNKNOWN("unknown"), USER("user"), EMPLOYEE("employee"), SELLER("seller"); private String value; OperationUnit(String value) { this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; }

}
`

OperationLog.java

`package com.basic.bl.rest.demo.aop;

import java.util.Date;

public class OperationLog {

private String id; private Date createTime; /** * Log Level */ private Integer level; /** * Operated Objects */ private String operationUnit; /** * Method Name */ private String method; /** * parameter */ private String args; /** * Operator id */ private String userId; /** * Operator */ private String userName; /** * Log Description */ private String describe; /** * Operation type */ private String operationType; /** * Method Runtime */ private Long runTime; /** * Method Return Value */ private String returnValue; @Override public String toString() { return "OperationLog{" + "id='" + id + '\'' + ", createTime=" + createTime + ", level=" + level + ", operationUnit='" + operationUnit + '\'' + ", method='" + method + '\'' + ", args='" + args + '\'' + ", userId='" + userId + '\'' + ", userName='" + userName + '\'' + ", describe='" + describe + '\'' + ", operationType='" + operationType + '\'' + ", runTime=" + runTime + ", returnValue='" + returnValue + '\'' + '}'; } public Long getRunTime() { return runTime; } public void setRunTime(Long runTime) { this.runTime = runTime; } public String getReturnValue() { return returnValue; } public void setReturnValue(String returnValue) { this.returnValue = returnValue; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public Integer getLevel() { return level; } public void setLevel(Integer level) { this.level = level; } public String getOperationUnit() { return operationUnit; } public void setOperationUnit(String operationUnit) { this.operationUnit = operationUnit; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public String getArgs() { return args; } public void setArgs(String args) { this.args = args; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getDescribe() { return describe; } public void setDescribe(String describe) { this.describe = describe; } public String getOperationType() { return operationType; } public void setOperationType(String operationType) { this.operationType = operationType; }

}
`

OperationLogDetail.java

`package com.basic.bl.rest.demo.aop;

import java.lang.annotation.*;

//@OperationLogDetail(detail = Get user name from mobile number [{}], level = 3,operationUnit = OperationUnit.USER,operationType = OperationType.SELECT)
@Documented
@Target()
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationLogDetail {

/** * Method description, using placeholders to get parameters: {} */ String detail() default ""; /** * Log Level: Self-defined, 1-9 here */ int level() default 0; /** * Operation type (enum): mainly select,insert,update,delete */ OperationType operationType() default OperationType.UNKNOWN; /** * The object being manipulated (enum is used here): can be any object, such as a table name (user), or a tool (redis) */ OperationUnit operationUnit() default OperationUnit.UNKNOWN;

}
`

LogAspect.java

`package com.basic.bl.rest.demo.aop;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@Aspect
@Component
public class LogAspect {

/** * The point of tangency here is the way you annotate, or you can achieve the same effect by using a package name * '@Pointcut("execution(* com.basic.bl.rest.demo.aop.service.impl.*.*(..))")' */ @Pointcut("@annotation(com.basic.bl.rest.demo.aop.OperationLogDetail)") public void operationLog(){} /** * Enhanced surround, equivalent to MethodInterceptor */ @Around("operationLog()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { Object res = null; long time = System.currentTimeMillis(); try { res = joinPoint.proceed(); time = System.currentTimeMillis() - time; return res; } finally { try { //Add log after method execution addOperationLog(joinPoint,res,time); }catch (Exception e){ System.out.println("LogAspect Operation failed:" + e.getMessage()); e.printStackTrace(); } } } private void addOperationLog(JoinPoint joinPoint, Object res, long time){ MethodSignature signature = (MethodSignature)joinPoint.getSignature(); OperationLog operationLog = new OperationLog(); operationLog.setRunTime(time); operationLog.setReturnValue(JSON.toJSONString(res)); operationLog.setId(UUID.randomUUID().toString()); operationLog.setArgs(JSON.toJSONString(joinPoint.getArgs())); operationLog.setCreateTime(new Date()); operationLog.setMethod(signature.getDeclaringTypeName() + "." + signature.getName()); operationLog.setUserId("#"); operationLog.setUserName("#"); OperationLogDetail annotation = signature.getMethod().getAnnotation(OperationLogDetail.class); if(annotation != null){ operationLog.setLevel(annotation.level()); operationLog.setDescribe(getDetail(((MethodSignature)joinPoint.getSignature()).getParameterNames(),joinPoint.getArgs(),annotation)); operationLog.setOperationType(annotation.operationType().getValue()); operationLog.setOperationUnit(annotation.operationUnit().getValue()); } //TODO Save Log Here System.out.println("Logging:" + operationLog.toString());

// operationLogService.insert(operationLog);

} /** * Processing of current logged-in users and placeholders * @param argNames Array of method parameter names * @param args Array of method parameters * @param annotation annotation * @return Return description after processing */ private String getDetail(String[] argNames, Object[] args, OperationLogDetail annotation){ Map<Object, Object> map = new HashMap<>(4); for(int i = 0;i < argNames.length;i++){ map.put(argNames[i],args[i]); } String detail = annotation.detail(); try { detail = "'" + "#" + "'=>" + annotation.detail(); for (Map.Entry<Object, Object> entry : map.entrySet()) { Object k = entry.getKey(); Object v = entry.getValue(); detail = detail.replace("{{" + k + "}}", JSON.toJSONString(v)); } }catch (Exception e){ e.printStackTrace(); } return detail; } @Before("operationLog()") public void doBeforeAdvice(JoinPoint joinPoint){ System.out.println("Execute before entering method....."); } /** * After processing the request, return the content * @param ret */ @AfterReturning(returning = "ret", pointcut = "operationLog()") public void doAfterReturning(Object ret) { System.out.println("Return value of method : " + ret); } /** * Post-exception notification */ @AfterThrowing("operationLog()") public void throwss(JoinPoint jp){ System.out.println("Execute on Method Exception....."); } /** * Post-final notification, final enhancement, executed regardless of exception throw or normal exit */ @After("operationLog()") public void after(JoinPoint jp){ System.out.println("Method Last Execution....."); }

}`

DemoController.java

`package com.basic.bl.rest.demo.aop;
import com.basic.bl.rest.demo.aop.service.DemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("demo")
public class DemoController {

@Autowired private DemoService demoService; /** * Access path http://localhost:11000/user/findUserNameByTel?tel=1234567 * @param tel Cell-phone number * @return userName */ @ResponseBody @RequestMapping("/findUserNameByTel") public String findUserNameByTel(@RequestParam("tel") String tel){ return demoService.findUserName(tel); }

}
``

DemoServiceImpl.java

`package com.basic.bl.rest.demo.aop.service.impl;

import com.basic.bl.rest.demo.aop.OperationLogDetail;
import com.basic.bl.rest.demo.aop.OperationType;
import com.basic.bl.rest.demo.aop.OperationUnit;
import com.basic.bl.rest.demo.aop.service.DemoService;
import org.springframework.stereotype.Service;

@Service
public class DemoServiceImpl implements DemoService {

@OperationLogDetail(detail = "Via mobile number[{}]Get User Name",level = 3,operationUnit = OperationUnit.USER,operationType = OperationType.SELECT) @Override public String findUserName(String tel) { System.out.println("tel:" + tel); return "zhangsan"; }

}`

DemoService.java

`package com.basic.bl.rest.demo.aop.service;
public interface DemoService {

/** * Get user information * @return * @param tel */ String findUserName(String tel);

}
`

Result



Execute before entering the method...
tel:1721212121
Log records: OperationLog ' ###', userName}', userName}, level=3, 45:26 CST 2019, level=3, operationUnit='user'='#', describe=''#'= via mobile phoneNumber ["17212121"] Get user name', operationType='select', runTime=5, returnValue=''zhangsan'}
Method last executed...
Return value of method: zhangsan

4 December 2019, 17:01 | Views: 1454

Add new comment

For adding a comment, please log in
or create account

0 comments