浏览器运行环境异常,请检查是否开启本站的JavaScript权限或下载最新版浏览器
springboot自定义注解这么用,轻松捕获系统操作日志(下)

springboot自定义注解这么用,轻松捕获系统操作日志(下)

在上一篇中我们讲到了将日志保存到数据库,有点遗憾的地方是方法的中文名字得在Log2DBApiOperation中写两次,有点不人性化。今天我们就来解决这个问题。
如果只能写一次,那我们只能改自己的代码读取ApiOperation中的value属性(因为swagger是不会改代码适配你d的),那如果要读取别人的属性,有什么方法呢?
  1. 继承
  2. 扫描ApiOperation
如果我们的Log2DB继承ApiOperation呢?注解能否继承?答案是肯定的。
我们看下RestController的注解,其实是继承了Controller注解的
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller//就在这里继承的
@ResponseBody
public @interface RestController {
    @AliasFor(
        annotation = Controller.class
    )
    String value() default "";
}
但是注解的继承依赖如下一个因素:
  1. 首先要想Annotation能被继承,需要在注解定义的时候加上@Inherited,并且如果要被反射应用的话,还需要@Retention(RetentionPolicy.RUNTIME)标识
  2. JDK文档中说明的是:只有在类上应用Annotation才能被继承,而实际应用结果是:除了类上应用的Annotation能被继承外,没有被重写的方法的Annotation也能被继承;
  3. 当方法被重写后,Annotation不会被继承
  4. Annotation的继承不能应用在接口
遗憾的是ApiOperation不符合条件,那我们就只剩下第二个方法了。
第二个我们要解决几个问题
1、怎么扫描读取ApiOperation所有的配置
2、用什么key存储关系
先解决第一个,我们可以在工程启动的时候获取所有的ApiOperation,如下
@Slf4j
@Component
public class ApisScaner {

    @Resource
    private ApplicationContextProvider applicationContextProvider;

    //key是全类名.方法名,value是ApiOperation的name属性
    public static Map<String,String> APIS = new HashMap<String,String>();

    @PostConstruct
    public void handler() throws ClassNotFoundException {
        log.info("SwaggerScaner.handler");
        ApplicationContext applicationContext = applicationContextProvider.getApplicationContext();
        //获取自定义注解的配置
        final Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(Api.class);

        for (String key : beansWithAnnotation.keySet()) {
            Method[] methods = Class.forName(beansWithAnnotation.get(key).getClass().getName()).getMethods();
            for (Method method : methods) {
                ApiOperation annotation = AnnotationUtils.findAnnotation(method, ApiOperation.class);
                if(annotation!=null){
                    String value = annotation.value();
                    String className = beansWithAnnotation.get(key).toString();
                    String methodName = method.getName();
                    className = className.substring(0,className.indexOf("@"));

                    APIS.put(className+"."+methodName,value);
                }
            }
        }

        for (String item : APIS.keySet()) {
            log.info("item:{}-->value:{}",item, APIS.get(item));
        }
    }
}
ApplicationContextProvider (动态获取spring的bean对象)的源码也贴下:
@Component
public class ApplicationContextProvider implements ApplicationContextAware {

     /**
      * 上下文对象实例
      */
     private static ApplicationContext applicationContext;

     @Override
     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
         ApplicationContextProvider.applicationContext = applicationContext;
     }

     /**
      * 获取Spring上下文
      *
      * @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);
     }

 }
好了,看了代码大伙基本也明白了,用什么存储,我暂时是用map存储的,大家可以写到数据库中,也可以用redis,mongodb,随意。启动一下试试:
SwaggerScaner.handler
item:com.example.lesson20.controller.TestController.getUser-->value:获取用户1
item:com.example.lesson20.controller.TestController.postUser-->value:保存用户1
数据我们都拿到了,改下上一节的一个小点即可:
//name = logAnnotation.name();
name = ApisScaner.APIS.get(clazz_method);
这样我们就搞定了,so easy!
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得UP主同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理: DMCA投诉/Report
赞 4
踩 1
评论
收藏
评论区
晓雾觉得你应该发点骚的
因为评论区空空如也