曹工说Spring Boot源码(14)-- AspectJ的Load-Time-Weaving的两种实现方式细细讲解,以及怎么和Spring Instrumentation集成 (4)

所以,只能采用其他方式,而java instrumentation就可以。这部分呢,大家请翻阅前一篇文章,里面讲得比较细,大家请看完下面一篇,再回头来看这部分。

曹工说Spring Boot源码(13)-- AspectJ的运行时织入(Load-Time-Weaving),基本内容是讲清楚了(附源码)

我们在使用aspectJ的LTW时,-javaagent是直接使用了aspectjweaver.jar,类似下面这样子:

java -javaagent:aspectjweaver-1.8.2.jar -cp java-aspectj-agent-1.0-SNAPSHOT.jar foo.Main

但如果有同学使用过spring集成aspectJ的LTW的话,会发现使用方法略有差异:

java -javaagent:spring-instrument-4.3.7.RELEASE.jar -cp java-aspectj-agent-1.0-SNAPSHOT.jar foo.Main

这里可以发现,-javaagent指定的jar包不一样,为啥呢?

我这里写了一个利用spring-instrumentation来集成aspectJ的ltw的例子。

思路如下:

利用spring-instrumentation jar包来作为javaagent参数,这个jar包作为agent,会在main执行前先执行,里面的逻辑主要是:把JVM暴露出来的instrumentation,保存起来,保存到一个static field里,方便后续使用;

在测试代码中,获取到第一步保存的instrumentation,给它设置一个ClassFileTransformer,这个ClassFileTransformer不用自己写,直接使用aspectJ的即可。这个ClassFileTransformer呢,会去读取META-INF/aop.xml里面,看看要去增强哪些类,去增强即可。

在开始之前,我们先看看spring-instrumentation这个jar包:

曹工说Spring Boot源码(14)-- AspectJ的Load-Time-Weaving的两种实现方式细细讲解,以及怎么和Spring Instrumentation集成

所以,spring-instrumentation很简单,一个类而已。

好了,我们开始试验:

测试类

package foo; import java.lang.instrument.Instrumentation; public final class Main { public static void main(String[] args) { // 下面这行是重点,完成前面说的第二步思路的事情 InstrumentationLoadTimeWeaver.init(); /** * 经过了上面的织入,下边这个StubEntitlementCalculationService已经是ltw增强过的了 */ StubEntitlementCalculationService entitlementCalculationService = new StubEntitlementCalculationService(); entitlementCalculationService.calculateEntitlement(); } } package foo; public class StubEntitlementCalculationService { public void calculateEntitlement() { System.out.println("calculateEntitlement"); } }

集成aspectJ

foo.InstrumentationLoadTimeWeaver#init // 这个方法里的 ClassPreProcessorAgentAdapter,就是aspectJ的类,实现了ClassFileTransformer接口; // AspectJClassBypassingClassFileTransformer装饰了ClassPreProcessorAgentAdapter,对aspectJ本身的类不进行ltw,类似于一个静态代理,把需要ltw的类,交给ClassPreProcessorAgentAdapter public static void init() { addTransformer(new AspectJClassBypassingClassFileTransformer(new ClassPreProcessorAgentAdapter())); }

这里的addTransformer,我们看下,首先获取到spring-instrumentation.jar作为javaagent,保存起来的Instrumentation,然后调用其addTransformer,添加ClassFileTransformer

public static void addTransformer(ClassFileTransformer transformer) { Instrumentation instrumentation = getInstrumentation(); if (instrumentation != null) { instrumentation.addTransformer(transformer); } } private static final boolean AGENT_CLASS_PRESENT = isPresent( "org.springframework.instrument.InstrumentationSavingAgent", InstrumentationLoadTimeWeaver.class.getClassLoader()); private static Instrumentation getInstrumentation() { if (AGENT_CLASS_PRESENT) { // 获取保存起来的Instrumentation return InstrumentationAccessor.getInstrumentation(); } else { return null; } } private static class InstrumentationAccessor { public static Instrumentation getInstrumentation() { return InstrumentationSavingAgent.getInstrumentation(); } }

其他aspectJ的ltw需要使用的东西

我们上面添加了aspectJ的ClassPreProcessorAgentAdapter,这个ClassFileTransformer就会去查找META-INF/aop.xml,进行处理。

package foo; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; @Aspect public class ProfilingAspect { @Around("methodsToBeProfiled()") public Object profile(ProceedingJoinPoint pjp) throws Throwable { System.out.println("before"); try { return pjp.proceed(); } finally { System.out.println("after"); } } @Pointcut("execution(public * foo..*.*(..))") public void methodsToBeProfiled(){} }

aop.xml:

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "https://www.eclipse.org/aspectj/dtd/aspectj.dtd"> <aspectj> <weaver> <!-- only weave classes in our application-specific packages --> <include within="foo.*"/> </weaver> <aspects> <!-- weave in just this aspect --> <aspect/> </aspects> </aspectj>

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzjzzy.html