SpringBoot+AOP+自定义注解,实现日志记录
一.定义自定义注解
import java.lang.annotation.*;
/**
* @author awen
* 定义注解目的 想让他当作切点
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) //.java .class 字节码
@Documented
public @interface Log {
/**
* 处理类型
*
* @return {@link String}
*/
String handleType() default "";
/**
* 操作功能
*
* @return {@link String}
*/
String cagn() default "";
}
1.@Target 这个注解可以往什么上面加 这个就是可以往方法上面加
2.Retention 在哪个生命周期生效
生命周期: .java文件 .class文件 字节码文件(最常用 RUNTIME)
3.@Documented 的含义 @Document 是 java 在生成文档,显示注解
4.注意注解里面的定义
类型 +参数名字() 默认值 xx:
二.AOP切面类编写
1.导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.切面类
import com.alibaba.fastjson.JSONObject;
import com.example.demo2.service.CjzlMarkService;
import com.example.demo2.utils.JsonResult;
import com.example.demo2.utils.SpringFactoryUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* 操作记录切点
*
* @author awen
* @date 2022/12/03
*/
@Aspect //让springboot 知道我是切点
@Component //让springboot 识别到
@DependsOn("springFactoryUtils")
public class CzjlMark {
private static Map<String,CjzlMarkService> beanMap = SpringFactoryUtils.getBeanMap(CjzlMarkService.class);
/**
* 日志切点
*/
//1.定义切点 往哪里切 通过注解来去切
@Pointcut("@annotation(com.example.demo2.annotation.Log)")
//这个方法就和形参一样 他不会执行他就是代表着我们真实切入的那些方法
public void logPointCut(){
System.out.println(1);
};
//2.实现切点 ,切点前执行,和方法一起执行,方法执行完之后执行
//在切点前执行
@Before("logPointCut()&&@annotation(log)") //参数是切点 和 切点对象
public void beforePointCut(JoinPoint joinPoint,Log log){
Object[] args = joinPoint.getArgs();
CjzlMarkService cjzlMarkService = beanMap.get(log.handleType());
cjzlMarkService.before(args,log);
}
//切点执行完之后执行
@AfterReturning(returning = "result",value = "logPointCut()") //返回值result拿到这个结果 看看返回成功了嘛
public void afterPointCut(JoinPoint joinPoint,Object result){
JSONObject jsonResult = (JSONObject) result;
if(200==Integer.valueOf(jsonResult.get("code").toString())){
Object[] args = joinPoint.getArgs();
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
CjzlMarkService cjzlMarkService = beanMap.get(signature.getMethod().getAnnotation(Log.class).handleType());
cjzlMarkService.after(args,signature);
}
}
//和方法一起执行 很少用
public void aroundPointCut(){}
}
3.工具类SpringUtils 用于获取Spring管理的bean
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class SpringFactoryUtils implements ApplicationContextAware {
//Spring中的核心接口和容器,允许容器通过应用程序上下文环境创建、获取、管理bean
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringFactoryUtils.applicationContext = applicationContext;
}
/**
* 获取applicationContext
*
* @return
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 通过name获取 Bean.
*
* @param name
* @return
*/
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
/**
* 通过class获取Bean.
*
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
/**
* 通过name,以及Clazz返回指定的Bean
*
* @param name
* @param clazz
* @param <T>
* @return
*/
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
public static <T> Map<String, T> getBeanMap(Class<T> clazz) {
return getApplicationContext().getBeansOfType(clazz);
}
}
4.返回类 JsonResult
import com.alibaba.fastjson.JSONObject;
public class JsonResult {
private JsonResult() {
throw new IllegalStateException("Utility class");
}
public static JSONObject ok(String msg, Object data) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg", msg);
jsonObject.put("data", data);
jsonObject.put("code", 200);
return jsonObject;
}
public static JSONObject ok(String msg) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg", msg);
jsonObject.put("code", 200);
return jsonObject;
}
public static JSONObject not0k(String msg) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg", msg);
jsonObject.put("code", 500);
return jsonObject;
}
}
5.Service 前后执行什么
import com.example.demo2.annotation.Log;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Component
@Slf4j
public abstract class CjzlMarkService {
public void before(Object[] args, Log loga){
log.info("handle:{},入参:{}",loga.handleType(),args);
};
public abstract void after(Object[] args, MethodSignature signature);
}
6.实现类 我们可以写多个实现类 然后通过Componet里的value来区分 这个value 和 注解类 Log里面 的handleType是一致的
import com.example.demo2.annotation.Log;
import com.example.demo2.service.CjzlMarkService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
@Component("bmcx")
@Slf4j
public class bmcxCjzlService extends CjzlMarkService {
@Override
public void after(Object[] args, MethodSignature signature) {
log.info("handle:{},入参:{}",signature.getMethod().getAnnotation(Log.class).handleType(),args);
}
}
7.测试
@Log(handleType = "bmcx",cagn="部门查询")
@GetMapping("getAll")
public JSONObject getAll(){
List<UserPo> userPos = userMapper.selectList(null);
return JsonResult.ok("成功",userPos);
}
8.执行顺序
@Before里面代码 方法里面代码 @AfterReturning里面的代码 @PointCut不会执行
还没有评论,来说两句吧...