是否可以将AspectJ编译时编织到WAR打包的项目中?

时间:2019-06-13 17:20:28

标签: java maven aop aspectj

关于编织成JAR文件的文档很多,例如AspectJ in Action: Second Edition书中描述的示例。

但是,我几乎看不到有关编织到WAR文件中的任何问题。由于WAR文件和AspectJ库的流行,我很难相信它不受支持,因此我希望能找到一些答案。

假设您有一个“旧版” Java项目,该项目正在使用maven-war-plugin插件打包为WAR文件。请记住,由于涉及风险,几乎不可能将其从WAR更改为JAR包装。

现在,假设我想为一些跨领域功能引入AOP。由于我们应用程序的性质,我最好的选择是创建一个单独的项目。因此,基本上,方面类将与旧项目不在同一项目中。它将是分开的。

在这部分之后,我被卡住了。通过在线阅读本书和其他文档,似乎可以采用两种方法进行编译时编织:

  1. 直接编织源。这可以通过直接在旧项目中创建方面类,然后使用aspectj-maven-plugin插件来完成。这并不是真正的选择,因为我希望我的AOP逻辑影响多个项目,而不仅仅是一个项目。
  2. 创建一个单独的库,并使用Aspectj-maven-plugin插件对其进行编译。然后创建另一个Maven项目,该项目将纳入非织造应用程序和方面库中,并将其编织在一起。从书中摘录的示例:
<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <weaveDependencies>
                    <weaveDependency>
                        <groupId>ajia.helloworld</groupId>
                        <artifactId>application-unwoven</artifactId>
                    </weaveDependency>
                </weaveDependencies>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>ajia.helloworld</groupId>
                        <artifactId>profiling-aspect-library</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
            </configuration>
        </plugin>
    </plugins>
</build>

第二个选项的问题是<weaveDependency>要求应用程序为JAR文件。据我所知,Atleast。

我确实在AspectJ邮件列表中遇到了类似的问题:http://aspectj.2085585.n4.nabble.com/Weaving-into-a-war-file-td2082924.html。 万一链接过期,问题的答案是:

  

您需要将其拆开,编织.jar并将其放回原处。   您不能直接在战争中编织广口瓶

但这有可能吗?我也没有任何文档。

SO上存在类似的问题,这些问题根本没有任何答复,或者是错误/过时的。

由于我不知道下一步该怎么做,因此我将不胜感激。

1 个答案:

答案 0 :(得分:1)

我将尝试提出两种不同的解决方案,然后您可以选择/选择或混合/匹配实施解决方案的方式。


示例1 :已要求您将一些文本转储到pg_dump中的org.apache.log4j.Logger.info(Object o)方法的执行前和执行后。

(这是一个非常的示例,但我使用它是因为过去我被要求做一些不完全不同的事情!)

我假设您使用的是Multi-Module Maven Project

要实现此目的,我们可以使用log4j jar(已编译类),对其应用Aspect,然后吐出一组新的加载时编织的已编译类。我们通过利用您已经在其自身模块中调用的weaveDependency功能来实现此目的。因此,如下所述,您将不再依赖log4j,而将依赖log4j

请牢记这一点,从而创建您的项目层次结构:

ltwjar-enhanced-log4j

将您的父pom.xml设置为如下所示(为了方便/一致起见,我们在此处设置了几个属性-还有其他控制版本控制的方法,例如dependencyManagementimported depdendencies,但是那是一个不同的问题!):

ltwjar
      /ltwjar-ltwjar-enhanced-log4j
      /ltwjar-runtime

像这样设置<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> pom.xml:

ltwjar-enhanced-log4j

现在,让我们设置存根“运行时”模块,以便在日志记录时通过配置pom.xml来利用其加载时日志log4j <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>

ltw-enhanced-log4j

好的,这就是我们的框架设置。现在,让我们创建一个无意义的方面来说明这一点!

<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

输出应该是这样的(因为您的类路径中没有log4j.xml):

mvn -pl ltwjar-runtime exec:java -Dexec.mainClass="com.example.Driver"

注意第一行和最后一行。

这是怎么回事:

  1. 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
  2. 我们将Logger.info(Object o)重新包装到一个包含机织类型的新罐log4j.jar
  3. 我们在应用程序代码中依靠ltwjar-enhanced-log4j.jar 而不是 ltwjar-enhanced-log4j.jar ...
  4. ...而这样做,则忠告

好吧,这如何适合最初询问的warfile?

简单-不要在warfile模块中放置任何代码。如果必须在其中放置一些东西,请对其进行配置。而是将所有代码移至log4jyourproject-domain或...(在此处插入模块名称),并使warfile依赖于 that 模块。这是一个好习惯,因为它启用了Separation of Concerns:您的应用程序不应该知道它在warfile伞下运行;它可以像Spring Boot tomcat uberwar等一样轻松地运行。包装方面的关注点(war)与业务方面的关注点(domain)不同。

今天晚上我将更新另一个共享方面库的示例,除非有人殴打我。另外,如果其中一些没有意义,请大声疾呼!