AOP实践-自定义注解实现日志记录
项目环境springboot
spring AOP默认是使用AspectJ的注解 https://www.eclipse.org/aspectj/
1.引入jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.自定义注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodLog {
String remark() default "";
int operType() default 0;
}
3.日志记录
此处每次操作完成之后记录日志
@Component
@Aspect
public class LogService {
@Autowired
OperateLogMapper operateLogMapper;
/**
* 切点
*/
@Pointcut("@annotation(com.cmft.basic.aspect.annotation.MethodLog)")
public void methodCachePointcut() {
}
@AfterThrowing("methodCachePointcut()")
public void test(JoinPoint point) {
}
/**
* 切面
*
* @param point
* @return
* @throws Throwable
*/
@AfterReturning("methodCachePointcut()")
public void recordOperateLog(JoinPoint point) throws Throwable {
Map<String, Object> methodMap = getMthodMap(point);
String packages = point.getThis().getClass().getName();
if (packages.indexOf("$$EnhancerByCGLIB$$") > -1) { // 如果是CGLIB动态生成的类
packages = packages.substring(0, packages.indexOf("$$"));
return;
}
Object[] methodParam = null;
methodParam = point.getArgs(); // 获取方法参数
Map<String, Object> parMap = objectToMap(methodParam[0]);
// 记录日志
//...
operateLog.setRemark(String.valueOf(methodMap.get("remark")));
operateLog.setTypeId((Integer)methodMap.get("operType"));
//...
}
/**
* 获取利用反射获取类里面的值和名称
*
* @param obj
* @return
* @throws IllegalAccessException
*/
public static Map<String, Object> objectToMap(Object obj) throws IllegalAccessException {
Map<String, Object> map = new HashMap<>();
Class<?> clazz = obj.getClass();
if (clazz.isPrimitive() || clazz.getName().equals("java.lang.String")) {
map.put("id", obj);
return map;
}
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
String fieldName = field.getName();
Object value = field.get(obj);
map.put(fieldName, value);
}
return map;
}
/**
* 获取方法中的中文备注
*
* @param joinPoint
* @return
* @throws Exception
*/
public static Map<String, Object> getMthodMap(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class<?> targetClass = Class.forName(targetName);
Method[] method = targetClass.getMethods();
Map<String, Object> methodMap = new HashMap<String, Object>();
for (Method m : method) {
if (m.getName().equals(methodName)) {
@SuppressWarnings("rawtypes")
Class[] tmpCs = m.getParameterTypes();
if (tmpCs.length == arguments.length) {
MethodLog methodCache = m.getAnnotation(MethodLog.class);
if (methodCache != null) {
int operType = methodCache.operType();
String remark = methodCache.remark();
methodMap.put("operType", operType);
methodMap.put("remark", remark);
}
break;
}
}
}
return methodMap;
}
}
4.使用
AOP必须基于接口实现,所以在接口实现类的方法上加入如下注解即可
@MethodLog(remark = "更新", operType = Constant.APPROVE)