SpringBoot+AOP+自定义注解,实现日志记录

蔚落 2024-04-20 22:06 215阅读 0赞

一.定义自定义注解

  1. import java.lang.annotation.*;
  2. /**
  3. * @author awen
  4. * 定义注解目的 想让他当作切点
  5. */
  6. @Target({ElementType.METHOD})
  7. @Retention(RetentionPolicy.RUNTIME) //.java .class 字节码
  8. @Documented
  9. public @interface Log {
  10. /**
  11. * 处理类型
  12. *
  13. * @return {@link String}
  14. */
  15. String handleType() default "";
  16. /**
  17. * 操作功能
  18. *
  19. * @return {@link String}
  20. */
  21. String cagn() default "";
  22. }

1.@Target 这个注解可以往什么上面加 这个就是可以往方法上面加

2.Retention 在哪个生命周期生效

生命周期: .java文件 .class文件 字节码文件(最常用 RUNTIME)

3.@Documented 的含义 @Document 是 java 在生成文档,显示注解

4.注意注解里面的定义

类型 +参数名字() 默认值 xx:

二.AOP切面类编写

1.导包

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-aop</artifactId>
  4. </dependency>

2.切面类

  1. import com.alibaba.fastjson.JSONObject;
  2. import com.example.demo2.service.CjzlMarkService;
  3. import com.example.demo2.utils.JsonResult;
  4. import com.example.demo2.utils.SpringFactoryUtils;
  5. import org.aspectj.lang.JoinPoint;
  6. import org.aspectj.lang.Signature;
  7. import org.aspectj.lang.annotation.*;
  8. import org.aspectj.lang.reflect.MethodSignature;
  9. import org.springframework.context.annotation.DependsOn;
  10. import org.springframework.stereotype.Component;
  11. import java.util.Map;
  12. /**
  13. * 操作记录切点
  14. *
  15. * @author awen
  16. * @date 2022/12/03
  17. */
  18. @Aspect //让springboot 知道我是切点
  19. @Component //让springboot 识别到
  20. @DependsOn("springFactoryUtils")
  21. public class CzjlMark {
  22. private static Map<String,CjzlMarkService> beanMap = SpringFactoryUtils.getBeanMap(CjzlMarkService.class);
  23. /**
  24. * 日志切点
  25. */
  26. //1.定义切点 往哪里切 通过注解来去切
  27. @Pointcut("@annotation(com.example.demo2.annotation.Log)")
  28. //这个方法就和形参一样 他不会执行他就是代表着我们真实切入的那些方法
  29. public void logPointCut(){
  30. System.out.println(1);
  31. };
  32. //2.实现切点 ,切点前执行,和方法一起执行,方法执行完之后执行
  33. //在切点前执行
  34. @Before("logPointCut()&&@annotation(log)") //参数是切点 和 切点对象
  35. public void beforePointCut(JoinPoint joinPoint,Log log){
  36. Object[] args = joinPoint.getArgs();
  37. CjzlMarkService cjzlMarkService = beanMap.get(log.handleType());
  38. cjzlMarkService.before(args,log);
  39. }
  40. //切点执行完之后执行
  41. @AfterReturning(returning = "result",value = "logPointCut()") //返回值result拿到这个结果 看看返回成功了嘛
  42. public void afterPointCut(JoinPoint joinPoint,Object result){
  43. JSONObject jsonResult = (JSONObject) result;
  44. if(200==Integer.valueOf(jsonResult.get("code").toString())){
  45. Object[] args = joinPoint.getArgs();
  46. MethodSignature signature = (MethodSignature)joinPoint.getSignature();
  47. CjzlMarkService cjzlMarkService = beanMap.get(signature.getMethod().getAnnotation(Log.class).handleType());
  48. cjzlMarkService.after(args,signature);
  49. }
  50. }
  51. //和方法一起执行 很少用
  52. public void aroundPointCut(){}
  53. }

3.工具类SpringUtils 用于获取Spring管理的bean

  1. import org.springframework.beans.BeansException;
  2. import org.springframework.context.ApplicationContext;
  3. import org.springframework.context.ApplicationContextAware;
  4. import org.springframework.stereotype.Component;
  5. import java.util.Map;
  6. @Component
  7. public class SpringFactoryUtils implements ApplicationContextAware {
  8. //Spring中的核心接口和容器,允许容器通过应用程序上下文环境创建、获取、管理bean
  9. private static ApplicationContext applicationContext;
  10. @Override
  11. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  12. SpringFactoryUtils.applicationContext = applicationContext;
  13. }
  14. /**
  15. * 获取applicationContext
  16. *
  17. * @return
  18. */
  19. public static ApplicationContext getApplicationContext() {
  20. return applicationContext;
  21. }
  22. /**
  23. * 通过name获取 Bean.
  24. *
  25. * @param name
  26. * @return
  27. */
  28. public static Object getBean(String name) {
  29. return getApplicationContext().getBean(name);
  30. }
  31. /**
  32. * 通过class获取Bean.
  33. *
  34. * @param clazz
  35. * @param <T>
  36. * @return
  37. */
  38. public static <T> T getBean(Class<T> clazz) {
  39. return getApplicationContext().getBean(clazz);
  40. }
  41. /**
  42. * 通过name,以及Clazz返回指定的Bean
  43. *
  44. * @param name
  45. * @param clazz
  46. * @param <T>
  47. * @return
  48. */
  49. public static <T> T getBean(String name, Class<T> clazz) {
  50. return getApplicationContext().getBean(name, clazz);
  51. }
  52. public static <T> Map<String, T> getBeanMap(Class<T> clazz) {
  53. return getApplicationContext().getBeansOfType(clazz);
  54. }
  55. }

4.返回类 JsonResult

  1. import com.alibaba.fastjson.JSONObject;
  2. public class JsonResult {
  3. private JsonResult() {
  4. throw new IllegalStateException("Utility class");
  5. }
  6. public static JSONObject ok(String msg, Object data) {
  7. JSONObject jsonObject = new JSONObject();
  8. jsonObject.put("msg", msg);
  9. jsonObject.put("data", data);
  10. jsonObject.put("code", 200);
  11. return jsonObject;
  12. }
  13. public static JSONObject ok(String msg) {
  14. JSONObject jsonObject = new JSONObject();
  15. jsonObject.put("msg", msg);
  16. jsonObject.put("code", 200);
  17. return jsonObject;
  18. }
  19. public static JSONObject not0k(String msg) {
  20. JSONObject jsonObject = new JSONObject();
  21. jsonObject.put("msg", msg);
  22. jsonObject.put("code", 500);
  23. return jsonObject;
  24. }
  25. }

5.Service 前后执行什么

  1. import com.example.demo2.annotation.Log;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.aspectj.lang.reflect.MethodSignature;
  4. import org.springframework.stereotype.Component;
  5. import org.springframework.stereotype.Service;
  6. @Component
  7. @Slf4j
  8. public abstract class CjzlMarkService {
  9. public void before(Object[] args, Log loga){
  10. log.info("handle:{},入参:{}",loga.handleType(),args);
  11. };
  12. public abstract void after(Object[] args, MethodSignature signature);
  13. }

6.实现类 我们可以写多个实现类 然后通过Componet里的value来区分 这个value 和 注解类 Log里面 的handleType是一致的

  1. import com.example.demo2.annotation.Log;
  2. import com.example.demo2.service.CjzlMarkService;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.aspectj.lang.reflect.MethodSignature;
  5. import org.springframework.stereotype.Component;
  6. @Component("bmcx")
  7. @Slf4j
  8. public class bmcxCjzlService extends CjzlMarkService {
  9. @Override
  10. public void after(Object[] args, MethodSignature signature) {
  11. log.info("handle:{},入参:{}",signature.getMethod().getAnnotation(Log.class).handleType(),args);
  12. }
  13. }

7.测试

  1. @Log(handleType = "bmcx",cagn="部门查询")
  2. @GetMapping("getAll")
  3. public JSONObject getAll(){
  4. List<UserPo> userPos = userMapper.selectList(null);
  5. return JsonResult.ok("成功",userPos);
  6. }

8.执行顺序

@Before里面代码 方法里面代码 @AfterReturning里面的代码 @PointCut不会执行

发表评论

表情:
评论列表 (有 0 条评论,215人围观)

还没有评论,来说两句吧...

相关阅读

    相关 定义注解实现日志收集

    在日常开发过程中,需要记录日志,但是每次都要写日志收集的代码就会很繁琐,那么如何优雅的实现日志收集呢?利用自定义注解可以很好的实现,下面就来说一说如何利用切面实现日志的收集