spring 启动前的 AspectJ
AspectJ before spring boot starts
假设我有一个 spring 启动应用程序
@SpringBootApplication
public abstract class AbstractMicroServer {
public static void main(final String[] args) {
// here some asppect should start
final SpringApplication app = new SpringApplication(AbstractMicroServer.class);
app.run(args);
}
}
我的方面Jclass
@Aspect
public class AOP{
@Pointcut("execution(* org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.ignoreResourceType(..)")
public void intercept() {
}
@Around("intercept()")
public Object intercept(final ProceedingJoinPoint joinPoint) throws Throwable {
return joinPoint.getArgs();
}
}
我希望这个方面在 spring 引导开始之前就绪。这可能是我想做的吗?由于某种我不知道的原因,该方面没有被拦截。
POM
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.12</version><!--$NO-MVN-MAN-VER$ -->
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.12</version><!--$NO-MVN-MAN-VER$-->
</dependency>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.10</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>UTF-8</encoding>
<includes>
<include>**/*.java</include>
<include>**/*.aj</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<!-- use this goal to weave all your main classes -->
<goal>compile</goal>
<!-- use this goal to weave all your test classes -->
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
我没有使用 spring boot starter aop。以上是我对 aop 的所有配置和代码。
在我看来,您想拦截 Spring 类 中的方法执行。为此,您有两个选择:
- 使用加载时间编织(
-javaagent:/path/to/aspectjweaver-<version>.jar
作为 JVM 参数)
在构建时编织您的 Spring 库 类 以创建库的特殊编织版本 (see relevant aspectj-maven-plugin documentation),并使用生成的编织 类 而不是原来的 spring jar 文件。您生成的配置类似于:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<configuration>
<weaveDependencies>
<weaveDependency>
<groupId>org.agroup</groupId>
<artifactId>to-weave</artifactId>
</weaveDependency>
<weaveDependency>
<groupId>org.anothergroup</groupId>
<artifactId>gen</artifactId>
</weaveDependency>
</weaveDependencies>
</configuration>
</plugin>
Spring AOP
运行时编织
由于 Spring 框架基于代理的性质,Spring AOP 基于 运行时编织 。这意味着目标 class 在 Spring 运行时变成了代理。
在大多数情况下,Spring 框架不会代理其框架 classes。您感兴趣的 class CommonAnnotationBeanPostProcessor
未被代理。因此,Spring AOP 无法拦截对 CommonAnnotationBeanPostProcessor
.
的 ignoreResourceType
方法的任何调用
然而,这并不意味着你运气不好。您仍然可以利用 AspectJ 的 二进制编织.
AspectJ
二进制编织
在二进制编织中,目标和方面源代码(*.java)分别编译成二进制classes(.class)。然后将二进制 classes 与 AspectJ 编译器 (ajc) 编织在一起。
在您的情况下,方面源代码 (AOP.java
) 将使用 AspectJ 编译器编译成二进制 class (AOP.class
)。 AOP.class
和现有的Spring、class、CommonAnnotationBeanPostProcessor.class
将被编织到一起成为一个新编织的CommonAnnotationBeanPostProcessor.class
。
编织前的代码
这里是ignoreResourceType
方法的代码片段 class CommonAnnotationBeanPostProcessor
,
public void ignoreResourceType(String resourceType) {
Assert.notNull(resourceType, "Ignored resource type must not be null");
this.ignoredResourceTypes.add(resourceType);
}
编织后的代码
现在,注意方法被AspectJ编织后的变化。
public void ignoreResourceType(String resourceType) {
JoinPoint var3 = Factory.makeJP(ajc$tjp_0, this, this, resourceType);
SpringFrameworkClassAspect var10000 = SpringFrameworkClassAspect.aspectOf();
Object[] var4 = new Object[]{this, resourceType, var3};
var10000.adviceAround((new CommonAnnotationBeanPostProcessor$AjcClosure1(var4)).linkClosureAndJoinPoint(69648));
}
如何实现AspectJ二进制编织?
- 您可以在Mojo's AspectJ Maven plugin的帮助下生成二进制编织。
- 你仍然需要你的方面class。
- 确保在
weaveDependencies
下包含 spring-context
依赖项。
以下是您项目 pom.xml
的插件部分的摘录。您可以找到完整的工作示例 here.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.10</version>
<configuration>
<showWeaveInfo/>
<source>1.8</source>
<target>1.8</target>
<complianceLevel>${java.version}</complianceLevel>
<Xlint>ignore</Xlint>
<forceAjcCompile>true</forceAjcCompile>
<sources/>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
<weaveDependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</weaveDependencies>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
假设我有一个 spring 启动应用程序
@SpringBootApplication
public abstract class AbstractMicroServer {
public static void main(final String[] args) {
// here some asppect should start
final SpringApplication app = new SpringApplication(AbstractMicroServer.class);
app.run(args);
}
}
我的方面Jclass
@Aspect
public class AOP{
@Pointcut("execution(* org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.ignoreResourceType(..)")
public void intercept() {
}
@Around("intercept()")
public Object intercept(final ProceedingJoinPoint joinPoint) throws Throwable {
return joinPoint.getArgs();
}
}
我希望这个方面在 spring 引导开始之前就绪。这可能是我想做的吗?由于某种我不知道的原因,该方面没有被拦截。
POM
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.12</version><!--$NO-MVN-MAN-VER$ -->
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.12</version><!--$NO-MVN-MAN-VER$-->
</dependency>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.10</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>1.8</source>
<target>1.8</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>ignore</Xlint>
<encoding>UTF-8</encoding>
<includes>
<include>**/*.java</include>
<include>**/*.aj</include>
</includes>
</configuration>
<executions>
<execution>
<goals>
<!-- use this goal to weave all your main classes -->
<goal>compile</goal>
<!-- use this goal to weave all your test classes -->
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
我没有使用 spring boot starter aop。以上是我对 aop 的所有配置和代码。
在我看来,您想拦截 Spring 类 中的方法执行。为此,您有两个选择:
- 使用加载时间编织(
-javaagent:/path/to/aspectjweaver-<version>.jar
作为 JVM 参数) 在构建时编织您的 Spring 库 类 以创建库的特殊编织版本 (see relevant aspectj-maven-plugin documentation),并使用生成的编织 类 而不是原来的 spring jar 文件。您生成的配置类似于:
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <configuration> <weaveDependencies> <weaveDependency> <groupId>org.agroup</groupId> <artifactId>to-weave</artifactId> </weaveDependency> <weaveDependency> <groupId>org.anothergroup</groupId> <artifactId>gen</artifactId> </weaveDependency> </weaveDependencies> </configuration> </plugin>
Spring AOP
运行时编织
由于 Spring 框架基于代理的性质,Spring AOP 基于 运行时编织 。这意味着目标 class 在 Spring 运行时变成了代理。
在大多数情况下,Spring 框架不会代理其框架 classes。您感兴趣的 class CommonAnnotationBeanPostProcessor
未被代理。因此,Spring AOP 无法拦截对 CommonAnnotationBeanPostProcessor
.
ignoreResourceType
方法的任何调用
然而,这并不意味着你运气不好。您仍然可以利用 AspectJ 的 二进制编织.
AspectJ
二进制编织
在二进制编织中,目标和方面源代码(*.java)分别编译成二进制classes(.class)。然后将二进制 classes 与 AspectJ 编译器 (ajc) 编织在一起。
在您的情况下,方面源代码 (AOP.java
) 将使用 AspectJ 编译器编译成二进制 class (AOP.class
)。 AOP.class
和现有的Spring、class、CommonAnnotationBeanPostProcessor.class
将被编织到一起成为一个新编织的CommonAnnotationBeanPostProcessor.class
。
编织前的代码
这里是ignoreResourceType
方法的代码片段 class CommonAnnotationBeanPostProcessor
,
public void ignoreResourceType(String resourceType) {
Assert.notNull(resourceType, "Ignored resource type must not be null");
this.ignoredResourceTypes.add(resourceType);
}
编织后的代码
现在,注意方法被AspectJ编织后的变化。
public void ignoreResourceType(String resourceType) {
JoinPoint var3 = Factory.makeJP(ajc$tjp_0, this, this, resourceType);
SpringFrameworkClassAspect var10000 = SpringFrameworkClassAspect.aspectOf();
Object[] var4 = new Object[]{this, resourceType, var3};
var10000.adviceAround((new CommonAnnotationBeanPostProcessor$AjcClosure1(var4)).linkClosureAndJoinPoint(69648));
}
如何实现AspectJ二进制编织?
- 您可以在Mojo's AspectJ Maven plugin的帮助下生成二进制编织。
- 你仍然需要你的方面class。
- 确保在
weaveDependencies
下包含spring-context
依赖项。
以下是您项目 pom.xml
的插件部分的摘录。您可以找到完整的工作示例 here.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.10</version>
<configuration>
<showWeaveInfo/>
<source>1.8</source>
<target>1.8</target>
<complianceLevel>${java.version}</complianceLevel>
<Xlint>ignore</Xlint>
<forceAjcCompile>true</forceAjcCompile>
<sources/>
<weaveDirectories>
<weaveDirectory>${project.build.directory}/classes</weaveDirectory>
</weaveDirectories>
<weaveDependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</weaveDependencies>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>