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.
@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 descriptionOperationType.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);
}
`
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