Spring Boot 2.x (11): информация об интерфейсе печати AOP

Spring Boot

Какая польза от журнала интерфейса

В нашем ежедневном процессе разработки мы можем просмотреть некоторую подробную информацию об этом интерфейсе через журнал интерфейса. Например, IP-адрес клиента, тип клиента, время отклика, тип запроса, метод интерфейса запроса и т. д. Мы можем выполнить статистический анализ этих данных и извлечь нужную информацию.

Как получить лог интерфейса

Здесь мы используем АОП, один из двух убийц Spring, определяя точки на уровне контроллера, затем анализируя объект запроса для получения информации об интерфейсе и в то же время открывая ThreadLocal для записи времени ответа.

Примечания к АОП

  • @Aspect: определяет класс как класс аспекта.
  • @Pointcut: определяет точечный разрез.
  • @Before: Вырезать содержимое в начале pointcut.
  • @After: Вырезать содержимое в конце pointcut.
  • @AfterReturning: вырезать содержимое после того, как pointcut вернет содержимое (может использоваться для некоторой обработки возвращаемого значения.
  • @Around: вырезать содержимое до и после pointcut и контролировать, когда выполняется содержимое самого pointcut
  • @AfterThrowing: используется для обработки логики обработки при возникновении исключения из раздела содержимого.
  • @Order: Операции до pointcut выполняются в соответствии со значением порядка от меньшего к большему, операции после pointcut выполняются в соответствии со значением порядка от большего к меньшему.

Практическое применение

Первый: импортировать зависимости

Во-первых, нам нужно добавить зависимости для внедрения аоп, а также пакет UserAgentUtils для анализа клиентской информации, а также для@Slf4jПакет Lombok для печати логов:

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>eu.bitwalker</groupId>
            <artifactId>UserAgentUtils</artifactId>
            <version>1.20</version>
        </dependency>

Второе: определить класс аспекта ResponseAop

Мы определили этот класс в предыдущем унифицированном возвращаемом значении и обработке исключений, и теперь его нужно улучшить. Здесь я снова переписываю код:

@Aspect
@Order(5)
@Component
@Slf4j
public class ResponseAop

Три: определить переменную ThreadLocal

Определение базового типа непосредственно здесь приведет к проблемам с синхронизацией, поэтому мы определяем объект ThreadLocal для записи прошедшего времени.

ThreadLocal<Long> startTime = new ThreadLocal<>();

Четыре: определить точку отсечки

Здесь нужно обратить внимание на способ написания pointcut, он должен быть правильным, чтобы АОП работал! Вот несколько простых методов написания, и отдельная глава будет посвящена объяснению написания выражений выполнения.

  • Любой публичный метод:execution(public * *(..))
  • Выполнение любого метода, начинающегося с «set»:execution(* set*(..))
  • Выполнение любого метода интерфейса Сервиса:execution(* com.xyz.service.Service.*(..))
  • Выполнение любого метода, определенного в сервисном пакете:execution(* com.xyz.service.*.*(..))
  • Выполнение любого метода любого класса, определенного в сервисном пакете и всех подпакетах: еxecution(* com.xyz.service..*.*(..))
	/**
     * 切点
     */
    @Pointcut("execution(public * indi.viyoung.viboot.*.controller..*(..))")
    public void httpResponse() {
    }

Пятое: получить информацию о запросе в @Before

@Before("httpResponse()")
    public void doBefore(JoinPoint joinPoint){
    	//开始计时
        startTime.set(System.currentTimeMillis());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //打印请求的内容
        UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent"));//获取请求头中的User-Agent
        log.info("接口路径:{}" , request.getRequestURL().toString());
        log.info("浏览器:{}", userAgent.getBrowser().toString());
        log.info("浏览器版本:{}",userAgent.getBrowserVersion());
        log.info("操作系统: {}", userAgent.getOperatingSystem().toString());
        log.info("IP : {}" , request.getRemoteAddr());
        log.info("请求类型:{}", request.getMethod());
        log.info("类方法 : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("请求参数 : {} " + Arrays.toString(joinPoint.getArgs()));
    }

Шестое: получить возвращаемое значение и время выполнения метода в @AfterReturning

	@AfterReturning(returning = "ret" , pointcut = "httpResponse()")
    public void doAfterReturning(Object ret){
        //处理完请求后,返回内容
        log.info("方法返回值:{}" , ret);
        log.info("方法执行时间:{}毫秒", (System.currentTimeMillis() - startTime.get()));
    }

Семь: результаты испытаний

Ниже мы получаем доступ к интерфейсу:

2019-02-21 21:03:31.358  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : 接口路径:http://localhost:8090/users
2019-02-21 21:03:31.359  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : 浏览器:CHROME
2019-02-21 21:03:31.359  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : 浏览器版本:72.0.3626.109
2019-02-21 21:03:31.360  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : 操作系统: MAC_OS_X
2019-02-21 21:03:31.360  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : IP : 0:0:0:0:0:0:0:1
2019-02-21 21:03:31.360  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : 请求类型:GET
2019-02-21 21:03:31.360  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : 类方法 : indi.viyoung.viboot.apilog.controller.UserController.findAll
2019-02-21 21:03:31.360  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : 请求参数 : {} []
...
2019-02-21 21:03:31.393  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : 方法返回值:ReturnVO{code='2000', message='操作成功', data=[User(id=10000001, password=123456, userName=vi-young), User(id=10000002, password=123456, userName=vi-young), User(id=10000003, password=123123, userName=lxt), User(id=10000004, password=123456, userName=yangwei)]}
2019-02-21 21:03:31.393  INFO 11788 --- [nio-8090-exec-5] indi.viyoung.viboot.aop.ResponseAop      : 方法执行时间:36毫秒

Видно, что мы получили нужную информацию~

В реальном приложении мы сохраним эту информацию в базе данных и будем использовать некоторые инструменты анализа данных для анализа.

Нет публики

Ваша рекомендация - самая большая помощь для меня!