Я попытаюсь представить два разных решения, а затем вы сможете выбрать / выбрать или смешать / сопоставить способ реализации вашего решения.
Пример 1 : Вас попросили вывести некоторый текст в stdout до и после выполнения метода org.apache.log4j.Logger.info(Object o)
, найденного в log4j
.
(Это очень придуманный пример, но я использую его, потому что меня попросили сделать что-то не совсем отличное в прошлом!)
Полагаю, вы используете Multi-Module Maven Project .
Для этого мы можем использовать jar log4j
(скомпилированные классы), применять к ним Aspect и выплевывать новый набор скомпилированных классов во время загрузки. Мы делаем это, используя функциональность weaveDependency , которую вы уже вызывали в собственном модуле. Поэтому вместо зависимости от log4j
в ваших проектах вы будете зависеть от ltwjar-enhanced-log4j
, как описано ниже.
Имея это в виду, создайте иерархию вашего проекта следующим образом:
ltwjar
/ltwjar-ltwjar-enhanced-log4j
/ltwjar-runtime
Настройте ваш родительский файл pom.xml так, чтобы он выглядел примерно так (мы установили пару свойств здесь только для удобства / согласованности - существуют другие способы управления версиями, такие как dependencyManagement и импортированные зависимости , но это уже другой вопрос!):
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>ltwjar</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<aspectj.version>1.8.13</aspectj.version>
<log4j.version>1.2.17</log4j.version>
</properties>
<modules>
<module>ltwjar-enhanced-log4j</module>
<module>ltwjar-runtime</module>
</modules>
</project>
Настройте ваш ltwjar-enhanced-log4j
pom.xml следующим образом:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>ltwjar</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>ltwjar-enhanced-log4j</artifactId>
<dependencies>
<!-- we need this because the post-weave classes may (will) depend on aspectj types -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<!-- ATTENTION! Scope this to provided otherwise it won't work - because of transitive dependencies,
anything that depends on this module will end up getting the _actual_ log4j classes versus the ones we are enriching! -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.11</version>
<configuration>
<!-- instruct aspectj to weave the classes in the jar! -->
<weaveDependencies>
<weaveDependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</weaveDependency>
</weaveDependencies>
<Xlint>warning</Xlint>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
А теперь давайте настроим наш заглушенный модуль "runtime", чтобы использовать log4j ltw-enhanced-log4j
при загрузке, когда он регистрируется, сконфигурировав свой pom.xml таким образом:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>ltwjar</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>ltwjar-runtime</artifactId>
<dependencies>
<!-- Note that this module doesn't care (itself) about aspectj.
It _does_ care that it depends on the ltwjar-enhanced-log4j module
and not log4j, however. So let's depend on that! -->
<dependency>
<groupId>com.example</groupId>
<artifactId>ltwjar-enhanced-log4j</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
ОК, это наша установка фреймворка. Теперь давайте создадим бессмысленный аспект, чтобы продемонстрировать смысл!
В ltwjar-enhanced-log4j
создать тип com.example.aspect.LoggingAspect
примерно так:
package com.example.aspect;
import org.apache.log4j.Logger;
public aspect LoggingAspect {
// this pointcut will match "info(Object o)" method executions where the
// target is an instanceof Logger
pointcut logInfoWithObject(Object obj, Logger logger) :
execution(void info(Object)) && args(obj) && target(logger);
// here is our advice - simply sysout something before the execution
// proceeds and after it has finished - regardless of outcome (exception
// or not).
void around(Object obj, Logger logger) : logInfoWithObject(obj, logger) {
System.out.println("Before Logger.info(Object o)");
try {
proceed(obj, logger);
} finally {
System.out.println("After Logger.info(Object o)");
}
}
}
И, наконец, в ltwjar-runtime
создайте драйвер / жгут, который показывает, что все работает. Тип com.example.Driver
:
package com.example;
import org.apache.log4j.Logger;
public class Driver {
private static final Logger LOG = Logger.getLogger(Driver.class);
public static void main(String[] args) {
LOG.info("In main");
}
}
Теперь из вашего родительского проекта запустите mvn clean install
, а затем mvn -pl ltwjar-runtime exec:java -Dexec.mainClass="com.example.Driver"
.
Вывод должен быть примерно таким (поскольку у вас нет log4j.xml в вашем пути к классам):
Before Logger.info(Object o)
log4j:WARN No appenders could be found for logger (com.example.Driver).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
After Logger.info(Object o)
Обратите внимание на первую и последнюю строки.
Что здесь происходит:
- В
ltwjar-enhanced-log4j
мы "улучшаем" log4j, оборачивая совет в Logger.info(Object o)
- Переупаковываем
log4j.jar
в новую банку ltwjar-enhanced-log4j.jar
, которая содержит тканый тип
- Мы зависим от
ltwjar-enhanced-log4j.jar
вместо log4j
в нашем коде приложения ...
- ... И при этом совет придерживается
Хорошо, как это вписывается в военный файл, о котором изначально спрашивали?
Простой - не помещайте код в ваш модуль warfile. Если вам нужно что-то поместить туда, настройте его. Вместо этого переместите весь свой код в yourproject-domain
или yourproject-logic
или ... (введите имя модуля здесь), и ваш warfile зависит от этого модуля. Это хорошая практика, так как она включает Разделение проблем : ваше приложение не должно знать, что оно работает под зонтиком боевого файла; он может быть так же легко запущен, как Spring Boot tomcat uberwar и т. д. Забота об упаковке (война) отличается от заботы бизнеса (домена).
Сегодня вечером я обновлю другой пример библиотеки общих аспектов, если кто-то не побьет меня. Также, если что-то из этого не имеет смысла, кричите в комментариях!