Как контролировать выполнение метода в сторонней библиотеке? - PullRequest
0 голосов
/ 19 февраля 2020

У меня есть задача как-то отслеживать вызов метода в библиотеке logback. Я начал делать это с весны AOP. Так, например, я должен отлавливать выполнение всех методов в классе ch.qos.logback.classi c .Logger. И у меня есть Аспект для этого:

@Aspect
@Configuration
public class LogbackAspect {

    @Before(value = "execution(* ch.qos.logback.classic.Logger.*(..))")
    public void getInfo(JoinPoint joinPoint) {
         System.out.println("+++++AOP " + joinPoint.getSignature().getName());
}
}

Но пока он не работает, так есть ли возможность перехватить выполнение метода с помощью Spring AOP? Или есть способы получше?

Ответы [ 2 ]

5 голосов
/ 19 февраля 2020

К сожалению, вы можете создавать только свой собственный код.

Ответ Брендона неверен, поскольку он сфокусирован на Android. На платформах с обычными Java, такими как Windows, MacOS, Linux, вы можете перехватить сторонний код при следующих условиях:

  • Вы используете полный AspectJ, а не Spring AOP. AspectJ может использоваться без Spring или также в проектах Spring.
  • Вы используете LTW (ткачество во время загрузки), обычно через параметр JVM -javaagent:/path/to/aspectjweaver.jar, и правильно настраиваете aop. xml .
  • В качестве альтернативы вы можете использовать компилятор AspectJ aj c напрямую через командную строку или через плагин AspectJ Maven для выполнения бинарного ткачества, то есть ткачества. код аспекта в вашу стороннюю библиотеку, создавая новые сплетенные файлы классов и переупаковывая их в новый JAR. Тогда вы будете использовать этот JAR вместо оригинала. (Кстати, это также будет работать для Android, если библиотека - это то, что вы можете поставить и установить вместе с вашим приложением, а не какой-нибудь системный класс / библиотека, которую нельзя заменить или переопределить.)

Я рекомендую LTW вместо бинарного ткачества, если у вас нет ограничений при использовании Java параметров командной строки. В руководстве Spring даже есть глава, описывающая, как использовать его непосредственно в Spring.


Обновление: Вот MCVE , показывающий, как это сделать. это просто Java + AspectJ LTW.

Давайте создадим проект AspectJ в Eclipse с установленным AJDT (AspectJ Development Tools). Конечно, вы также можете создать проект Maven с плагином AspectJ Maven или даже без него, потому что на самом деле вам не нужен компилятор AspectJ, если вы используете LTW через -javaagent:/path/to/aspectjweaver.jar. Мой пример проекта имеет такую ​​структуру (макет Eclipse, а не Maven, я просто сделал это быстро):

Eclipse AspectJ project

Содержимое файла выглядит следующим образом.

src / de / scrum_master / app / Application. java

package de.scrum_master.app;

import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.Logger;

public class Application {
  private static final Logger logger = (Logger) LoggerFactory.getLogger(Application.class);

  public static void main(String[] args) {
    logger.info("Example log from {}", Application.class.getSimpleName());
  }
}

src / logback. xml

<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

src / de / scrum_master / aspect / LogbackAspect.aj (или просто LogbackAspect. java)

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LogbackAspect {
  @Before(value = "execution(* ch.qos.logback.classic.Logger.*(..))")
  public void getInfo(JoinPoint joinPoint) {
    System.out.println(joinPoint);
  }
}

src / META-INF / aop. xml

<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
  <aspects>
    <aspect name="de.scrum_master.aspect.LogbackAspect" />
  </aspects>
  <weaver options="-verbose -showWeaveInfo" />
</aspectj>

Теперь создайте простую Java конфигурацию запуска для Application и добавьте агента Java в командную строку:

AspectJ LTW run configuration

Теперь запустите программу, и журнал консоли будет выглядеть так:

[AppClassLoader@18b4aac2] info AspectJ Weaver Version 1.9.5 built on Thursday Nov 28, 2019 at 11:28:53 PST
[AppClassLoader@18b4aac2] info register classloader sun.misc.Launcher$AppClassLoader@18b4aac2
[AppClassLoader@18b4aac2] info using configuration /C:/Users/alexa/Documents/java-src/SO_AJ_LTW_Logback_60295366/bin/META-INF/aop.xml
[AppClassLoader@18b4aac2] info register aspect de.scrum_master.aspect.LogbackAspect
[AppClassLoader@18b4aac2] weaveinfo Join point 'method-execution(ch.qos.logback.classic.Level ch.qos.logback.classic.Logger.getEffectiveLevel())' in Type 'ch.qos.logback.classic.Logger' (Logger.java:109) advised by before advice from 'de.scrum_master.aspect.LogbackAspect' (LogbackAspect.aj)
[AppClassLoader@18b4aac2] weaveinfo Join point 'method-execution(int ch.qos.logback.classic.Logger.getEffectiveLevelInt())' in Type 'ch.qos.logback.classic.Logger' (Logger.java:113) advised by before advice from 'de.scrum_master.aspect.LogbackAspect' (LogbackAspect.aj)
[AppClassLoader@18b4aac2] weaveinfo Join point 'method-execution(ch.qos.logback.classic.Level ch.qos.logback.classic.Logger.getLevel())' in Type 'ch.qos.logback.classic.Logger' (Logger.java:117) advised by before advice from 'de.scrum_master.aspect.LogbackAspect' (LogbackAspect.aj)
(...)
[AppClassLoader@18b4aac2] weaveinfo Join point 'method-execution(java.lang.Object ch.qos.logback.classic.Logger.readResolve())' in Type 'ch.qos.logback.classic.Logger' (Logger.java:787) advised by before advice from 'de.scrum_master.aspect.LogbackAspect' (LogbackAspect.aj)
[AppClassLoader@18b4aac2] info processing reweavable type de.scrum_master.aspect.LogbackAspect: de\scrum_master\aspect\LogbackAspect.aj
[AppClassLoader@18b4aac2] info successfully verified type de.scrum_master.aspect.LogbackAspect exists.  Originates from de\scrum_master\aspect\LogbackAspect.aj
execution(void ch.qos.logback.classic.Logger.setLevel(Level))
execution(void ch.qos.logback.classic.Logger.setLevel(Level))
execution(String ch.qos.logback.classic.Logger.toString())
execution(void ch.qos.logback.classic.Logger.addAppender(Appender))
execution(Logger ch.qos.logback.classic.Logger.getChildByName(String))
execution(Logger ch.qos.logback.classic.Logger.createChildByName(String))
execution(Logger ch.qos.logback.classic.Logger.getChildByName(String))
execution(Logger ch.qos.logback.classic.Logger.createChildByName(String))
execution(Logger ch.qos.logback.classic.Logger.getChildByName(String))
execution(Logger ch.qos.logback.classic.Logger.createChildByName(String))
execution(Logger ch.qos.logback.classic.Logger.getChildByName(String))
execution(Logger ch.qos.logback.classic.Logger.createChildByName(String))
execution(void ch.qos.logback.classic.Logger.info(String, Object))
execution(void ch.qos.logback.classic.Logger.filterAndLog_1(String, Marker, Level, String, Object, Throwable))
execution(void ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(String, Marker, Level, String, Object[], Throwable))
execution(String ch.qos.logback.classic.Logger.getName())
execution(LoggerContext ch.qos.logback.classic.Logger.getLoggerContext())
execution(void ch.qos.logback.classic.Logger.callAppenders(ILoggingEvent))
execution(int ch.qos.logback.classic.Logger.appendLoopOnAppenders(ILoggingEvent))
execution(int ch.qos.logback.classic.Logger.appendLoopOnAppenders(ILoggingEvent))
execution(int ch.qos.logback.classic.Logger.appendLoopOnAppenders(ILoggingEvent))
execution(int ch.qos.logback.classic.Logger.appendLoopOnAppenders(ILoggingEvent))
execution(int ch.qos.logback.classic.Logger.appendLoopOnAppenders(ILoggingEvent))
16:04:52.791 [main] INFO  de.scrum_master.app.Application - Example log from Application

Я думаю, это именно то, что вы хотите. Пожалуйста, обратитесь к руководству Spring , чтобы узнать, как настроить AspectJ LTW там.

0 голосов
/ 19 февраля 2020

Проверьте этот другой ответ Перехват сторонних функций в android с использованием AspectJ

К сожалению, вы можете создавать только свой собственный код.

Однако, в зависимости от того, что вам на самом деле нужно делать с Logback, вы можете создать собственный Appender и делать там, что вам нужно?

UPDATE

Если вы хотите записать некоторую форму метри c этих исключений, вы можете настроить StatusListener в соответствии с logsta sh -logback docs

https://github.com/logstash/logstash-logback-encoder#status -listeners

С этим вы можете получить событие и записать любые метрики, которые вам нужны

...