是否可以从jar中编织一些类,同时排除其余的类?(Is it possible to weave some classes from a jar while excluding the rest of

编程入门 行业动态 更新时间:2024-10-25 08:25:13
是否可以从jar中编织一些类,同时排除其余的类?(Is it possible to weave some classes from a jar while excluding the rest of the classes?) java

我正在尝试使用新功能扩展第3个lib代码。

因为我只需要从一个类中为一个方法注入一些代码,我想我可以:

分叉项目并应用我的更改( seems sloppy, and will definitely require lots of work whenever I try to upgrade to a newer version of the lib, not to mention licensing nightmare ) 使用[AOP]拦截一个巨大的jar中的一个类的方法( seems cleaner )并注入我的额外测试

如果您想知道任何一个类,那么一个类不是一个Spring bean并且在代码中深入使用,所以我不能简单地扩展它并轻松覆盖/包装该方法,它至少需要几个额外的层延伸覆盖&/包装。 所以AspectJ和AOP似乎是更好的方式。

我设法用一些插件设置我的项目来调用ajc并在-inpath param中用我想要的jar编写代码。 唯一的问题是ajc似乎编织了所有东西(或者至少重复它);

所以我最需要的就是让AJC简单地从那个jar中挥动那个类,而不是整个jar!

I am trying to to extend a 3rd lib code with new capabilities.

And since I only need to inject some code around one method from one class, I figured I can either:

Fork the project and apply my changes (seems sloppy, and will definitely require lots of work whenever I try to upgrade to a newer version of the lib, not to mention licensing nightmare) Use [AOP] to intercept that one method from that one class inside a huge jar (seems cleaner) and inject my extra tests

In case any of you wants to know, that one class is not a spring bean and is used deep in the code, so I can not simply extend it and override/wrap that method easily, it would require at least a couple extra layers of extend&override/wrap. So AspectJ & AOP seems like the better way to go.

I managed to set my project up with some plugin to invoke ajc and weave the code with my desired jar in the -inpath param. And the only problem is that ajc seems to weave everything (or at least duplicate it);

So what I need basically is to ask AJC to simply wave that class from that jar, and not the whole jar !

最满意答案

正如您所注意到的,AspectJ编译器始终输出在weave依赖项(in-JAR)中找到的所有文件,无论它们是否被更改。 无法通过命令行AFAIK更改此行为。 因此,您需要自己负责包装JAR。

这是一个示例项目,包括。 Maven POM向您展示如何做到这一点。 我选择了一个涉及Apache Commons Codec的相当愚蠢的例子:

样品申请:

应用程序base64对文本进行编码,再次对其进行解码并将两个文本打印到控制台。

package de.scrum_master.app;

import org.apache.commons.codec.binary.Base64;

public class Application {
    public static void main(String[] args) throws Exception {
        String originalText = "Hello world!";
        System.out.println(originalText);
        byte[] encodedBytes = Base64.encodeBase64(originalText.getBytes());
        String decodedText = new String(Base64.decodeBase64(encodedBytes));
        System.out.println(decodedText);
    }
}
 

通常输出如下所示:

Hello world!
Hello world!
 

这里没有惊喜。 但是现在我们定义一个方面来操纵从第三方库返回的结果,将每个字符'o'(oh)替换为'0'(零):

package de.scrum_master.aspect;

import org.apache.commons.codec.binary.Base64;

public aspect Base64Manipulator {
    byte[] around() : execution(byte[] Base64.decodeBase64(byte[])) {
        System.out.println(thisJoinPoint);
        byte[] result = proceed();
        for (int i = 0; i < result.length; i++) {
            if (result[i] == 'o')
                result[i] = '0';
        }
        return result;
    }
}
 

顺便说一句,如果你只是在这里使用call()而不是execution() ,那么就没有必要真正编织成第三方代码。 但无论如何,你要求它,所以我告诉你如何做到这一点。

Maven POM:

<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>de.scrum-master.stackoverflow</groupId>
  <artifactId>aspectj-weave-single-3rd-party-class</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.source-target.version>1.8</java.source-target.version>
    <aspectj.version>1.8.10</aspectj.version>
    <main-class>de.scrum_master.app.Application</main-class>
  </properties>

  <build>

    <pluginManagement>
      <plugins>

        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.6.0</version>
          <configuration>
            <source>${java.source-target.version}</source>
            <target>${java.source-target.version}</target>
            <!-- IMPORTANT -->
            <useIncrementalCompilation>false</useIncrementalCompilation>
          </configuration>
        </plugin>

        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>aspectj-maven-plugin</artifactId>
          <version>1.9</version>
          <configuration>
            <!--<showWeaveInfo>true</showWeaveInfo>-->
            <source>${java.source-target.version}</source>
            <target>${java.source-target.version}</target>
            <Xlint>ignore</Xlint>
            <complianceLevel>${java.source-target.version}</complianceLevel>
            <encoding>${project.build.sourceEncoding}</encoding>
            <!--<verbose>true</verbose>-->
            <!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn>-->
            <weaveDependencies>
              <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
              </dependency>
            </weaveDependencies>
          </configuration>
          <executions>
            <execution>
              <!-- IMPORTANT -->
              <phase>process-sources</phase>
              <goals>
                <goal>compile</goal>
                <goal>test-compile</goal>
              </goals>
            </execution>
          </executions>
          <dependencies>
            <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjtools</artifactId>
              <version>${aspectj.version}</version>
            </dependency>
            <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjweaver</artifactId>
              <version>${aspectj.version}</version>
            </dependency>
          </dependencies>
        </plugin>

        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>exec-maven-plugin</artifactId>
          <version>1.5.0</version>
          <configuration>
            <mainClass>${main-class}</mainClass>
          </configuration>
        </plugin>

      </plugins>
    </pluginManagement>

    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
      </plugin>
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>2.5</version>
        <executions>
          <execution>
            <id>remove-unwoven</id>
            <!-- Phase 'process-classes' is in between 'compile' and 'package' -->
            <phase>process-classes</phase>
            <goals>
              <goal>clean</goal>
            </goals>
            <configuration>
              <!-- No full clean, only what is specified in 'filesets' -->
              <excludeDefaultDirectories>true</excludeDefaultDirectories>
              <filesets>
                <fileset>
                  <directory>${project.build.outputDirectory}</directory>
                  <includes>
                    <include>org/apache/commons/codec/**</include>
                    <include>META-INF/**</include>
                  </includes>
                  <excludes>
                    <exclude>**/Base64.class</exclude>
                  </excludes>
                </fileset>
              </filesets>
              <!-- Set to true if you want to see what exactly gets deleted -->
              <verbose>false</verbose>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
      </plugin>
    </plugins>

  </build>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
        <scope>runtime</scope>
      </dependency>
      <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.10</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
    </dependency>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
    </dependency>
  </dependencies>

  <organization>
    <name>Scrum-Master.de - Agile Project Management</name>
    <url>http://scrum-master.de</url>
  </organization>
</project>
 

正如您所看到的,我在AspectJ Maven插件中使用<weaveDependencies> (转换为AspectJ编译器的-inpath ),并结合Maven Clean插件的特殊执行,删除所有不需要的类和META-INF目录。原始JAR。

如果你运行mvn clean package exec:java你看到:

[INFO] ------------------------------------------------------------------------
[INFO] Building aspectj-weave-single-3rd-party-class 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
(...)
[INFO] --- aspectj-maven-plugin:1.9:compile (default) @ aspectj-weave-single-3rd-party-class ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
(...)
[INFO] --- maven-clean-plugin:2.5:clean (remove-unwoven) @ aspectj-weave-single-3rd-party-class ---
[INFO] Deleting C:\Users\Alexander\Documents\java-src\SO_AJ_MavenWeaveSingle3rdPartyClass\target\classes (includes = [org/apache/commons/codec/**, META-INF/**], excludes = [**/Base64.class])
(...)
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ aspectj-weave-single-3rd-party-class ---
[INFO] Building jar: C:\Users\Alexander\Documents\java-src\SO_AJ_MavenWeaveSingle3rdPartyClass\target\aspectj-weave-single-3rd-party-class-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- exec-maven-plugin:1.5.0:java (default-cli) @ aspectj-weave-single-3rd-party-class ---
Hello world!
execution(byte[] org.apache.commons.codec.binary.Base64.decodeBase64(byte[]))
Hell0 w0rld!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
 

这就是我的target/classes目录在构建之后的样子:

目录'目标/类'

如您所见,只剩下一个Apache Commons类文件进入创建的JAR。

As you have noticed, the AspectJ compiler always outputs all files found in weave dependencies (in-JARs), no matter if they are changed or not. This behaviour cannot be changed via command line, AFAIK. So you need to take care of packaging your JARs by yourself.

Here is a sample project incl. Maven POM showing you how to do that. I have chosen a rather stupid example involving Apache Commons Codec:

Sample application:

The application base64-encodes a text, decodes it again and prints both texts to console.

package de.scrum_master.app;

import org.apache.commons.codec.binary.Base64;

public class Application {
    public static void main(String[] args) throws Exception {
        String originalText = "Hello world!";
        System.out.println(originalText);
        byte[] encodedBytes = Base64.encodeBase64(originalText.getBytes());
        String decodedText = new String(Base64.decodeBase64(encodedBytes));
        System.out.println(decodedText);
    }
}
 

Normally the output looks like this:

Hello world!
Hello world!
 

No surprises here. But now we define an aspect which manipulates the results returned from the third party library, replacing each character 'o' (oh) by '0' (zero):

package de.scrum_master.aspect;

import org.apache.commons.codec.binary.Base64;

public aspect Base64Manipulator {
    byte[] around() : execution(byte[] Base64.decodeBase64(byte[])) {
        System.out.println(thisJoinPoint);
        byte[] result = proceed();
        for (int i = 0; i < result.length; i++) {
            if (result[i] == 'o')
                result[i] = '0';
        }
        return result;
    }
}
 

BTW, if you would just use call() instead of execution() here, there would be no need to actually weave into third party code. But anyway, you asked for it, so I am showing you how to do it.

Maven POM:

<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>de.scrum-master.stackoverflow</groupId>
  <artifactId>aspectj-weave-single-3rd-party-class</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.source-target.version>1.8</java.source-target.version>
    <aspectj.version>1.8.10</aspectj.version>
    <main-class>de.scrum_master.app.Application</main-class>
  </properties>

  <build>

    <pluginManagement>
      <plugins>

        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.6.0</version>
          <configuration>
            <source>${java.source-target.version}</source>
            <target>${java.source-target.version}</target>
            <!-- IMPORTANT -->
            <useIncrementalCompilation>false</useIncrementalCompilation>
          </configuration>
        </plugin>

        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>aspectj-maven-plugin</artifactId>
          <version>1.9</version>
          <configuration>
            <!--<showWeaveInfo>true</showWeaveInfo>-->
            <source>${java.source-target.version}</source>
            <target>${java.source-target.version}</target>
            <Xlint>ignore</Xlint>
            <complianceLevel>${java.source-target.version}</complianceLevel>
            <encoding>${project.build.sourceEncoding}</encoding>
            <!--<verbose>true</verbose>-->
            <!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn>-->
            <weaveDependencies>
              <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
              </dependency>
            </weaveDependencies>
          </configuration>
          <executions>
            <execution>
              <!-- IMPORTANT -->
              <phase>process-sources</phase>
              <goals>
                <goal>compile</goal>
                <goal>test-compile</goal>
              </goals>
            </execution>
          </executions>
          <dependencies>
            <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjtools</artifactId>
              <version>${aspectj.version}</version>
            </dependency>
            <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjweaver</artifactId>
              <version>${aspectj.version}</version>
            </dependency>
          </dependencies>
        </plugin>

        <plugin>
          <groupId>org.codehaus.mojo</groupId>
          <artifactId>exec-maven-plugin</artifactId>
          <version>1.5.0</version>
          <configuration>
            <mainClass>${main-class}</mainClass>
          </configuration>
        </plugin>

      </plugins>
    </pluginManagement>

    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
      </plugin>
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>2.5</version>
        <executions>
          <execution>
            <id>remove-unwoven</id>
            <!-- Phase 'process-classes' is in between 'compile' and 'package' -->
            <phase>process-classes</phase>
            <goals>
              <goal>clean</goal>
            </goals>
            <configuration>
              <!-- No full clean, only what is specified in 'filesets' -->
              <excludeDefaultDirectories>true</excludeDefaultDirectories>
              <filesets>
                <fileset>
                  <directory>${project.build.outputDirectory}</directory>
                  <includes>
                    <include>org/apache/commons/codec/**</include>
                    <include>META-INF/**</include>
                  </includes>
                  <excludes>
                    <exclude>**/Base64.class</exclude>
                  </excludes>
                </fileset>
              </filesets>
              <!-- Set to true if you want to see what exactly gets deleted -->
              <verbose>false</verbose>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
      </plugin>
    </plugins>

  </build>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
        <scope>runtime</scope>
      </dependency>
      <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.10</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
    </dependency>
    <dependency>
      <groupId>commons-codec</groupId>
      <artifactId>commons-codec</artifactId>
    </dependency>
  </dependencies>

  <organization>
    <name>Scrum-Master.de - Agile Project Management</name>
    <url>http://scrum-master.de</url>
  </organization>
</project>
 

As you can see I am using <weaveDependencies> in the AspectJ Maven plugin (which translates to -inpath for the AspectJ compiler) in combination with a special execution of the Maven Clean plugin that deletes all unneeded classes and the META-INF directory from the original JAR.

If the you run mvn clean package exec:java you see:

[INFO] ------------------------------------------------------------------------
[INFO] Building aspectj-weave-single-3rd-party-class 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
(...)
[INFO] --- aspectj-maven-plugin:1.9:compile (default) @ aspectj-weave-single-3rd-party-class ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
(...)
[INFO] --- maven-clean-plugin:2.5:clean (remove-unwoven) @ aspectj-weave-single-3rd-party-class ---
[INFO] Deleting C:\Users\Alexander\Documents\java-src\SO_AJ_MavenWeaveSingle3rdPartyClass\target\classes (includes = [org/apache/commons/codec/**, META-INF/**], excludes = [**/Base64.class])
(...)
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ aspectj-weave-single-3rd-party-class ---
[INFO] Building jar: C:\Users\Alexander\Documents\java-src\SO_AJ_MavenWeaveSingle3rdPartyClass\target\aspectj-weave-single-3rd-party-class-1.0-SNAPSHOT.jar
[INFO] 
[INFO] --- exec-maven-plugin:1.5.0:java (default-cli) @ aspectj-weave-single-3rd-party-class ---
Hello world!
execution(byte[] org.apache.commons.codec.binary.Base64.decodeBase64(byte[]))
Hell0 w0rld!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
 

And this is what my target/classes directory looks like after the build:

Directory 'target/classes'

As you can see, there is only one Apache Commons class file left which goes into the created JAR.

更多推荐

本文发布于:2023-08-05 19:07:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1437385.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:weave   jar   classes   rest   excluding

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!