AspectJ с загрузчиком классов jar

Я пытаюсь использовать Oracle Rest Data Service (ORDS), построенную на Jetty. Аспект должен отслеживать вызовы JDBC. Я не вижу, как происходит плетение.

Я пробовал AspectJ в другом автономном приложении, которое использовало JDBC, а также профилировало вызовы сервлетов в приложении, работающем в автономном Jetty, и все это сработало для меня. Но в этом случае есть исключение и не похоже, что происходит переплетение. Само приложение работает должным образом со всеми примененными конфигурациями AspectJ.

Были опробованы два варианта:

  • класс аспекта и файл конфигурации aop были помещены в банку, и эта банка была помещена в WEB-INF/lib. В этот каталог также был скопирован аспект jrt.jar.
  • класс аспекта и конфигурация аспекта были скопированы в WEB-INF/классы, подобные этому
   ├── WEB-INF
   │   ├── beans.xml
   │   ├── classes
   │   │   ├── META-INF
   │   │   │   ├── MANIFEST.MF
   │   │   │   └── aop-ajc.xml
   │   │   └── WhereTheStatementTimeGo.class 

В обоих случаях было исключение, как показано ниже.

Вот командная строка и исключение:

$JAVA_HOME/bin/java -javaagent:/DATA/PROJECTS/ASPECTJ19/lib/aspectjweaver.jar -Dorg.aspectj.tracing.enabled=true -Dorg.aspectj.tracing.factory=defaug.aspectj.tracing.messages=true   -jar ords.war standalone

[JarClassLoader@17f052a3] warning parse definitions failed -- (IllegalStateException) sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
java.lang.IllegalStateException: sun.misc.Launcher$AppClassLoader@18b4aac2
    at oracle.dbtools.jarcl.NestedResourceHandler.jarClassLoader(NestedResourceHandler.java:36)
    at oracle.dbtools.jarcl.NestedResourceHandler.openConnection(NestedResourceHandler.java:23)
    at java.net.URL.openConnection(URL.java:979)
    at java.net.URL.openStream(URL.java:1045)
    at org.aspectj.weaver.loadtime.definition.DocumentParser.saxParsing(DocumentParser.java:157)
    at org.aspectj.weaver.loadtime.definition.DocumentParser.parse(DocumentParser.java:123)
    at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.parseDefinitions(ClassLoaderWeavingAdaptor.java:290)
    at org.aspectj.weaver.loadtime.DefaultWeavingContext.getDefinitions(DefaultWeavingContext.java:130)
    at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.initialize(ClassLoaderWeavingAdaptor.java:174)
    at org.aspectj.weaver.loadtime.Aj$ExplicitlyInitializedClassLoaderWeavingAdaptor.initialize(Aj.java:337)
    at org.aspectj.weaver.loadtime.Aj$ExplicitlyInitializedClassLoaderWeavingAdaptor.getWeavingAdaptor(Aj.java:342)
    at org.aspectj.weaver.loadtime.Aj$WeaverContainer.getWeaver(Aj.java:316)
    at org.aspectj.weaver.loadtime.Aj.preProcess(Aj.java:108)
    at org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:51)
    at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
    at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
    at oracle.dbtools.jarcl.JarClassLoader.findClass(JarClassLoader.java:77)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at oracle.dbtools.jarcl.Entrypoint.invoke(Entrypoint.java:50)
    at oracle.dbtools.jarcl.Entrypoint.main(Entrypoint.java:77)

2019-07-02 16:47:29.822:INFO::main: Logging initialized @3375ms to org.eclipse.jetty.util.log.StdErrLog
Jul 02, 2019 4:47:29 PM  
INFO: HTTP and HTTP/2 cleartext listening on port: 8080
Jul 02, 2019 4:47:29 PM  
INFO: Disabling document root because the specified folder does not exist: /Users/slinetsk/Downloads/ORDS/ords/standalone/doc_root
2019-07-02 16:47:30.632:INFO:oejs.Server:main: jetty-9.4.z-SNAPSHOT; built: 2019-02-20T15:50:58.683Z; git: 3285c4dd4bb00caddcded77f8e44e72c61b9ab72; jvm 1.8.0_211-b12
2019-07-02 16:47:30.693:INFO:oejs.session:main: DefaultSessionIdManager workerName=node0
2019-07-02 16:47:30.693:INFO:oejs.session:main: No SessionScavenger set, using defaults
2019-07-02 16:47:30.694:INFO:oejs.session:main: node0 Scavenging every 600000ms

В выходных данных не было никакой информации, связанной с трассировкой AspectJ.


person Sergey Linetskiy    schedule 03.07.2019    source источник
comment
Добро пожаловать в SO, Сергей. Вот как это работает здесь: сначала вы узнаете, что такое MCVE, а затем предоставляете его либо в своем вопросе (нажмите изменить ) или вы можете добавить ссылку на репозиторий GitHub, содержащий MCVE (сначала удалите материалы, защищенные авторскими правами, и просто оставьте достаточно, чтобы я мог собрать и запустить приложение, например, через Maven, и воспроизвести проблему). Одного журнала ошибок мне недостаточно, чтобы ответить на ваш вопрос.   -  person kriegaex    schedule 03.07.2019
comment
Спасибо. У меня есть пример, но он не подходит для MCVE. Это виртуальная машина VirtualBox с Oracle DB и ORDS внутри. Проблема в том, что размер образов ВМ составляет 26 ГБ. Я надеялся, что проблема с загрузчиком классов Jar уже известна.   -  person Sergey Linetskiy    schedule 03.07.2019
comment
Я уверен, что простая установка Jetty также работает вне контейнера. И, возможно, проблема также воспроизводится с другой сторонней библиотекой, которая не требует Oracle DB в фоновом режиме. И даже если ему нужна библиотека Oracle, вероятно, ошибка возникает до того, как будет выполнен реальный доступ к БД, трассировка стека предполагает время загрузки классов. Это должно быть воспроизводимо. Вы хотите помочь? Помогите своим потенциальным помощникам! Создавая MCVE, вы обычно даже больше узнаете о своей проблеме.   -  person kriegaex    schedule 04.07.2019
comment
С самим Jetty все работало нормально, и я попытаюсь получить доступ к источнику ORDS, чтобы посмотреть, как используется oracle.dbtools.jarcl (часть oracle.dbtools.jarcl.JarClassLoader.findClass(JarClassLoader.java:77 в стек вызовов) для создания MCVE   -  person Sergey Linetskiy    schedule 05.07.2019
comment
На самом деле я скачал ORDS и могу воспроизвести ошибку. Похоже, что пользовательский загрузчик классов JAR от Oracle делает что-то, что не нравится агенту плетения AspectJ, но не имеет готового решения. Я попытался исключить загрузчик классов через -Daj.weaving.loadersToSkip=oracle.dbtools.jarcl.JarClassLoader. Это работает, но тогда ткач больше не будет ничего вплетать в JAR-файлы библиотеки. Вы можете создать собственный файл WAR с разархивированными интересующими вас библиотеками. Некрасиво, но, по крайней мере, ткач найдет целевые классы.   -  person kriegaex    schedule 06.07.2019


Ответы (1)


Я нашел обходной путь, который позволяет мне без проблем запускать сервер, а также использовать различные типы аспектов для всех видов классов, таких как внутренние классы Jetty:

Скопируйте AspectJ weaver и свою библиотеку аспектов (JAR, содержащий аспекты и META-INF/aop.xml) в подкаталог lib, откуда вы начинаете свои орды. война. Затем добавьте библиотеку аспектов в путь к классам загрузки JVM. Вам нужно использовать версию JRE/JDK, например Java 8, которая на самом деле все еще поддерживает загрузочный путь к классам. (На самом деле я только что проверил, JDK 11 все еще поддерживает его.) Я не знаю, как это сделать с модульными JRE. Тогда начните свою ВОЙНУ так:

java -Xbootclasspath/a:lib/aspect.jar -javaagent:lib/aspectjweaver.jar -jar ords.war standalone

Еще раз, со вставленными разрывами строк:

java
  -Xbootclasspath/a:lib/aspect.jar
  -javaagent:lib/aspectjweaver.jar
  -jar ords.war standalone

Этот подход гарантирует, что weaver подключен и его классы, а также классы аспектов будут найдены до того, как загрузчик классов Oracle JAR выполнит свою магическую точку входа.

Обратите внимание, что здесь вообще не нужно изменять файл WAR.


Обновление: в качестве альтернативы вы можете динамически подключить агент плетения AspectJ, а не через -javaagent, см.

Быстро проверил, работает. Однако это довольно сложно:

  • Вам нужно будет поместить свой собственный основной класс, аналогичный тому, что в файле readme AspectJ, в WAR в качестве основного класса. Этот класс подключит ткач, а затем запустит загрузчик классов JAR. Теперь вивер уже на месте и все работает как положено.
  • A caveat is that you need to start the JVM with tools.jar, myaspect.jar and aspectjweaver.jar on the classpath,
    • either on boot classpath if you want to start the application with java -jar my.war
    • или по обычному пути к классам Вы, если это нормально, запускаете приложение с -cp ...;my.war my.own.MainClass.
  • Кроме того, начиная с Java 9 больше нет tools.jar, но вам нужно сделать свой собственный класс точки входа зависимым от модуля jdk.attach, а также убедиться, что вы действительно запускаете приложение с JDK, а не с JRE. В противном случае вы не сможете использовать API для динамического подключения агентов.

В целом я по-прежнему предпочитаю оригинальное решение, его намного проще реализовать.

person kriegaex    schedule 06.07.2019
comment
Я создал MCVE, который является урезанной версией ORDS, имеющей только компоненты загрузчика классов. Его можно скачать отсюда github.com/lsa5521/AJCUSTLOADERTEST. С помощью этого кода я подтвердил, что предлагаемый обходной путь действительно работает. Спасибо! - person Sergey Linetskiy; 08.07.2019
comment
Тогда я был бы рад видеть, что вы принимаете + проголосовали за мой ответ, Сергей. Интересный вопрос, это была моя воскресная утренняя головоломка, пока я пил чай. ;-) - person kriegaex; 08.07.2019
comment
Я только что обновил ответ. Я поэкспериментировал с другим решением и проверил его в своем собственном проекте, используя другой загрузчик классов JAR (потому что проблема та же, что и в связи с переплетением во время загрузки). - person kriegaex; 08.07.2019
comment
Еще одно обновление: исходному решению не нужен JAR-файл агента ткачества в пути к классам загрузки, достаточно JAR-файла аспекта, потому что ткач в любом случае находится через -javaagent:lib\aspectjweaver.jar. - person kriegaex; 08.07.2019
comment
Я определенно принимаю ответ, как я уже упоминал, но я не вижу, как я могу это сделать на сайте. Кажется, у меня еще недостаточно очков репутации, чтобы сделать это - person Sergey Linetskiy; 08.07.2019
comment
Под счетчиком голосов каждого вопроса должна быть серая галочка. Автор вопроса может щелкнуть тот, который она хочет принять, и сделать его зеленым. - person kriegaex; 09.07.2019