《spring源码深度解析》spring 静态Aop

———— 5.1.3.RELEASE
words: 3.2k    views:    time: 16min

静态代理是指在虚拟机载入字节码文件时动态织入切面行为,相对于动态代理具有更高的效率,因为动态代理调用的过程中,还需要一个动态创建代理类并代理目标对象的步骤,而静态代理在启动时便完成了字节码增强,当系统调用目标类时将与调用正常的类没有区别,它以一种更底层、更松耦合的方式改变了一个类的行为。

Instrumentation

先说下javaagent,它是java命令的一个参数,用于指定一个jar包,但是对该jar包有2个要求:

  • jar 包的 MANIFEST.MF 中必须指定 Premain-Class
  • Premain-Class 指定的类必须实现 premain() 方法

premain意思就是运行在 main 函数之前,即当Java虚拟机启动时,在执行 main 函数之前,JVM会先运行 -javaagent 所指定 jar 包内 Premain-Class 指定的类的 premain 方法 。

但是,对于 javaagent 指定的类有一些约束要求,即必须要有 premain() 方法,并且方法的签只能是以下两种格式:

JVM会优先加载带Instrumentation签名的方法,加载成功则忽略第二种

1
2
3
public static void premain(String agentArgs, Instrumentation inst)

public static void premain(String agentArgs)

下面看下接口Instrumentation,它是java1.5新增的,用来帮助开发者修改目标类的class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public interface Instrumentation {

//增加一个Class文件的转换器,转换器用于改变Class二进制流的数据,参数canRetransform设置是否允许重新转换。
void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

//在类加载之前,重新定义Class文件,ClassDefinition表示对一个类新的定义,如果在类加载之后,需要使用retransformClasses方法重新定义。
//addTransformer方法配置之后,后续的类加载都会被Transformer拦截。对于已经加载过的类,可以执行retransformClasses来重新触发这个Transformer的拦截。类加载的字节码被修改后,除非再次被retransform,否则不会恢复。
void addTransformer(ClassFileTransformer transformer);

//删除一个类转换器
boolean removeTransformer(ClassFileTransformer transformer);

boolean isRetransformClassesSupported();

//在类加载之后,重新定义Class。1.6之后加入的,事实上,该方法是update了一个类。
void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;

boolean isRedefineClassesSupported();

void redefineClasses(ClassDefinition... definitions)throws ClassNotFoundException, UnmodifiableClassException;

boolean isModifiableClass(Class<?> theClass);

@SuppressWarnings("rawtypes")
Class[] getAllLoadedClasses();

@SuppressWarnings("rawtypes")
Class[] getInitiatedClasses(ClassLoader loader);

//获取一个对象的大小
long getObjectSize(Object objectToSize);

void appendToBootstrapClassLoaderSearch(JarFile jarfile);

void appendToSystemClassLoaderSearch(JarFile jarfile);

boolean isNativeMethodPrefixSupported();

void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
}

因此,我们便可以在agent中通过Instrumentation来修改类的字节码,达到实现Aop的效果,即在运行之前修改目标类class,插入一些操作。

示例

首先创建一个agent包

test.selfagent.PerMonformer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class PerMonformer implements ClassFileTransformer {

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] transformed = null;
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = null;
try{
ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
if(!ctClass.isInterface()){
CtBehavior[] methods = ctClass.getDeclaredBehaviors();
for(int i = 0; i < methods.length; i++){
if(!methods[i].isEmpty()){
doMethod(methods[i]);
}
}
transformed = ctClass.toBytecode();
}
}catch(Exception e){
System.out.println("instrument " + className + " failed: " + e.getMessage());
}finally{
if(ctClass != null){
ctClass.detach();
}
}
return transformed;
}

private void doMethod(CtBehavior method) throws CannotCompileException{
String methodName = method.getLongName();

method.addLocalVariable("stime", CtClass.longType);
method.insertBefore("long stime = System.nanoTime();");
method.insertAfter("System.out.println(\"" + methodName + " cost=\" + (System.nanoTime() - stime));");
}
}
test.selfagent.TestAgent
1
2
3
4
5
6
7
8
9
10
public class TestAgent {

static private Instrumentation inst = null;

public static void premain(String agentArgs, Instrumentation _inst){
inst = _inst;
ClassFileTransformer trans = new PerMonformer();
inst.addTransformer(trans);
}
}
pom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<archive>
<!-- 打包时在MANIFEST.MF中写入Premain-Class和Boot-Class-Path(引入的其它包) -->
<manifestEntries>
<Premain-Class>test.selfagent.TestAgent</Premain-Class>
<Boot-Class-Path>D:/repository/javassist/javassist/3.8.0.GA/javassist-3.8.0.GA.jar</Boot-Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.8.0.GA</version>
</dependency>
</dependencies>

然后写个demo测试下,通过-javaagent:D:/temp/selfagent/target/selfagent-0.0.1-SNAPSHOT.jar指定路径(只能绝对路径)

Demo.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Demo {

public static void main(String[] args) {
new Demo().hello();
}

public void hello(){
System.out.println("Hello World.");
}
}

...
sun.launcher.LauncherHelper$FXHelper.<clinit>() cost=11869
sun.launcher.LauncherHelper$FXHelper.doesExtendFXApplication(java.lang.Class) cost=1142557478651491
sun.launcher.LauncherHelper$FXHelper.access$100(java.lang.Class) cost=43945
Hello World.
demo.Demo.hello() cost=58058
demo.Demo.main(java.lang.String[]) cost=89493
instrument java/lang/Shutdown failed: no method body
java.lang.Shutdown$Lock(java.lang.Shutdown$1) cost=10906
java.lang.Shutdown$Lock(java.lang.Shutdown$1) cost=642

AspectJ

AspectJ在Instrument的基础上进行了封装,可以更方便的修改class,但是它定义了新的关键字aspect,需要在Jdk中安装AspectJ才能进行编译(点击下载,然后在文件目录下执行java -jar aspectj-1.9.6.jar进行安装即可),另外如果是Eclipse,需要安装Aspect对应版本的插件,下载地址:http://www.eclipse.org/ajdt/downloads/index.php

示例

Test.java
1
2
3
4
5
6
public class Test {

public void hello(){
System.out.println("Hello World.");
}
}
TestAspect.java
1
2
3
4
5
6
7
public aspect TestAspect {

void around():call(void hello()){
System.out.println("Hello AspectJ.");
proceed();
}
}
App.java
1
2
3
4
5
6
7
8
9
10
public class App {

public static void main(String[] args) {
Test test = new Test();
test.hello();
}
}

Hello AspectJ.
Hello World.

spring 静态Aop

示例

spring静态Aop直接使用AspectJ提供的方法,如果要将前面[spring. 动态Aop]中的示例改成静态Aop的话,只需修改三处

bean.xml 需要添加标签:context:load-time-weaver

bean.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="true"/>

<bean id="testBean" class="test.aop.TestBean" />

<bean id="logAspect" class="test.aop.LogAspect" />

<context:load-time-weaver aspectj-weaving="on" />
</beans>

另外添加 META-INF/aop.xml,告诉AspectJ需要对那些包进行织入,以及使用那些增强器

META-INF/aop.xml
1
2
3
4
5
6
7
8
9
<aspectj>
<weaver>
<include within="* *..*Bean.*(..)" />
</weaver>

<aspects>
<aspect name="test.aop.LogAspect" />
</aspects>
</aspectj>

还需要指定javaagent,不过jar包是spring提供的

-javaagent:D:/repository/org/springframework/spring-instrument/5.1.3.RELEASE/spring-instrument-5.1.3.RELEASE.jar

其它的则不需要修改

TestBean.java
1
2
3
4
5
6
7
8
9
10
11
public class TestBean {

public int calculate(int i, int j){
this.valid(i, j);
return i / j;
}

public void valid(int i, int j){
Assert.isTrue(i > 0 && j > 0, "");
}
}
LogAspect.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Aspect
public class LogAspect {

private ThreadLocal<Long> localTime = new ThreadLocal<>();

@Pointcut("execution(* *..*Bean.*(..))")
public void point(){

}

@Before("point()")
public void before(JoinPoint point){
localTime.set(System.currentTimeMillis());
String method = point.getSignature().getName();
System.out.println("aspect before: " + method + Arrays.asList(point.getArgs()));
}

@AfterReturning(pointcut = "point()", returning = "result")
public void after(Object result){
long now = System.currentTimeMillis();
System.out.println("aspect: after: result=" + result + ", cost=" + (now - localTime.get()) + "ms");
}
}

从打印的class可以发现,这里的代理并没有像之前的动态代理利用继承或者接口方式创建一个新的class来代替,而是直接对目标class进行了修改,这样即便对于自我嵌套调用也可以直接体现出代理行为,而不再需要通过暴露的代理对象

App.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class App {
public static void main( String[] args ){
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
TestBean test = (TestBean)context.getBean("testBean");
System.out.println(test.getClass());
test.calculate(4, 2);
}
}

class test.aop.TestBean
aspect before: calculate[4, 2]
aspect before: valid[4, 2]
aspect: after: result=null, cost=0ms
aspect: after: result=2, cost=0ms

LoadTimeWeaverBeanDefinitionParser

下面还是从标签入手进行分析,首先找到ContextNamespaceHandler,并定位到LoadTimeWeaverBeanDefinitionParser

org.springframework.context.config.ContextNamespaceHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ContextNamespaceHandler extends NamespaceHandlerSupport {

@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}

LoadTimeWeaverBeanDefinitionParser实现了BeanDefinitionParser接口,那么从parse开始进行分析,这里实际上就是注册了两个BeanDefinition

org.springframework.beans.factory.xml.AbstractBeanDefinitionParser
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public final BeanDefinition parse(Element element, ParserContext parserContext) {
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
String id = resolveId(element, definition, parserContext);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error(
"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
+ "' when used as a top-level tag", element);
}
String[] aliases = null;
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
registerBeanDefinition(holder, parserContext.getRegistry());
if (shouldFireEvents()) {
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
}catch (BeanDefinitionStoreException ex) {
String msg = ex.getMessage();
parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
return null;
}
}
return definition;
}

首先parseInternal中构造了一个BeanDefinition,以loadTimeWeaver为id,class为DefaultContextLoadTimeWeaver

org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}

Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
}else {
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
if (containingBd != null) {
// Inner bean definition must receive same scope as containing bean.
builder.setScope(containingBd.getScope());
}
if (parserContext.isDefaultLazyInit()) {
// Default-lazy-init applies to custom bean definitions as well.
builder.setLazyInit(true);
}
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}

另外在doParse中是注册了AspectJWeavingEnabler

org.springframework.context.config.LoadTimeWeaverBeanDefinitionParser
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private static final String ASPECTJ_WEAVING_ENABLER_CLASS_NAME = 
"org.springframework.context.weaving.AspectJWeavingEnabler";

private static final String DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME =
"org.springframework.context.weaving.DefaultContextLoadTimeWeaver";

protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
return ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME; // loadTimeWeaver
}

protected String getBeanClassName(Element element) {
if (element.hasAttribute(WEAVER_CLASS_ATTRIBUTE)) { // weaver-class
return element.getAttribute(WEAVER_CLASS_ATTRIBUTE);
}
return DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME; // DefaultContextLoadTimeWeaver
}

protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 判断aspect-weaving属性,有三个值on、off、autodetect
if (isAspectJWeavingEnabled(element.getAttribute(ASPECTJ_WEAVING_ATTRIBUTE), parserContext)) {
if (!parserContext.getRegistry().containsBeanDefinition(ASPECTJ_WEAVING_ENABLER_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ASPECTJ_WEAVING_ENABLER_CLASS_NAME);
parserContext.registerBeanComponent(new BeanComponentDefinition(def, ASPECTJ_WEAVING_ENABLER_BEAN_NAME));
}

if (isBeanConfigurerAspectEnabled(parserContext.getReaderContext().getBeanClassLoader())) {
new SpringConfiguredBeanDefinitionParser().parse(element, parserContext);
}
}
}
AbstractApplicationContext

后面AbstractApplicationContextrefresh()时会调用prepareBeanFactory,其中就根据有没有loadTimeWeaver来决定是否注册LoadTimeWeaverAwareProcessor

org.springframework.context.support.AbstractApplicationContext
1
2
3
4
5
6
7
8
9
10
11
12
13
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {

// ...

// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { // loadTimeWeaver
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

// ...
}
LoadTimeWeaverAwareProcessor

LoadTimeWeaverAwareProcessor就是一个BeanPostProcessor,它实现了postProcessBeforeInitialization方法,其逻辑就是实例化DefaultContextLoadTimeWeaver,并赋值给了AspectJWeavingEnabler,可以理解成为AspectJWeavingEnabler做了一个准备操作

org.springframework.context.weaving.LoadTimeWeaverAwareProcessor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LoadTimeWeaverAware) { // 这里bean只可能是AspectJWeavingEnabler
LoadTimeWeaver ltw = this.loadTimeWeaver;
if (ltw == null) {
Assert.state(this.beanFactory != null, "BeanFactory required if no LoadTimeWeaver explicitly specified");
// 这里ltw就是上面注册的DefaultContextLoadTimeWeaver
ltw = this.beanFactory.getBean(
ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME, LoadTimeWeaver.class);
}
// 将DefaultContextLoadTimeWeaver赋给AspectJWeavingEnabler
((LoadTimeWeaverAware) bean).setLoadTimeWeaver(ltw);
}
return bean;
}

同时DefaultContextLoadTimeWeaver实现了接口BeanClassLoaderAware,那么在其初始化时会调用方法setBeanClassLoader,其中初始化了一个InstrumentationLoadTimeWeaver

org.springframework.context.weaving.DefaultContextLoadTimeWeaver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void setBeanClassLoader(ClassLoader classLoader) {
LoadTimeWeaver serverSpecificLoadTimeWeaver = createServerSpecificLoadTimeWeaver(classLoader);
if (serverSpecificLoadTimeWeaver != null) {
if (logger.isDebugEnabled()) {
logger.debug("Determined server-specific load-time weaver: " +
serverSpecificLoadTimeWeaver.getClass().getName());
}
this.loadTimeWeaver = serverSpecificLoadTimeWeaver;
}else if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
logger.debug("Found Spring's JVM agent for instrumentation");
this.loadTimeWeaver = new InstrumentationLoadTimeWeaver(classLoader);
}else {
try {
this.loadTimeWeaver = new ReflectiveLoadTimeWeaver(classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Using reflective load-time weaver for class loader: " +
this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
}
}catch (IllegalStateException ex) {
throw new IllegalStateException(ex.getMessage() + " Specify a custom LoadTimeWeaver or start your " +
"Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar");
}
}
}

这里,在初始化InstrumentationLoadTimeWeaver时初始化了Instrumentation

1
2
3
4
public InstrumentationLoadTimeWeaver(@Nullable ClassLoader classLoader) {
this.classLoader = classLoader;
this.instrumentation = getInstrumentation();
}

顺着调用关系,将会一直跟到提供了premain方法的InstrumentationSavingAgent,而对应的jar包正是上面示例中javaagent所指定的spring-instrument,也就是说当AspectJWeavingEnabler实例化时,它已经拿到了premain所提供的Instrumentation了,接下来就是怎么使用了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public final class InstrumentationSavingAgent {

private static volatile Instrumentation instrumentation;

private InstrumentationSavingAgent() {

}

public static void premain(String agentArgs, Instrumentation inst) {
instrumentation = inst;
}

public static void agentmain(String agentArgs, Instrumentation inst) {
instrumentation = inst;
}

public static Instrumentation getInstrumentation() {
return instrumentation;
}
}

另外,AspectJWeavingEnabler自己实现了BeanFactoryPostProcessor接口,从之前对应用上下文refresh()过程的介绍可以知道,当所有BeanDefinition解析完成时,会率先对BeanFactoryPostProcessor实例化并调用其postProcessBeanFactory方法,而在实例化的过程中必然会调用上面的postProcessBeforeInitialization,也就是说实际上在调用之前一切已经准备就绪

而这里所做的实际上就是创建一个ClassFileTransformer交给上面准备好的Instrumentation,其中封装了如何对加载了的bean的字节码进行修改的逻辑

org.springframework.context.weaving.AspectJWeavingEnabler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
enableAspectJWeaving(this.loadTimeWeaver, this.beanClassLoader);
}

public static void enableAspectJWeaving(
@Nullable LoadTimeWeaver weaverToUse, @Nullable ClassLoader beanClassLoader) {
// weaverToUse即loadTimeWeaver,在postProcessBeforeInitialization中已经赋值过
if (weaverToUse == null) {
if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
weaverToUse = new InstrumentationLoadTimeWeaver(beanClassLoader);
}else {
throw new IllegalStateException("No LoadTimeWeaver available");
}
}
// 调用下去其实就是Instrumentation.addTransformer
weaverToUse.addTransformer(new AspectJClassBypassingClassFileTransformer(new ClassPreProcessorAgentAdapter()));
}

最终交给InstrumentationAspectJClassBypassingClassFileTransformer其实是一个简单的装饰器,实际上对字节码的修改委托给了ClassPreProcessorAgentAdapter,而它又委托给了ClassPreProcessor的实现,具体的逻辑这里就不再细究下去了

org.springframework.context.weaving.AspectJClassBypassingClassFileTransformer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private static class AspectJClassBypassingClassFileTransformer implements ClassFileTransformer {

private final ClassFileTransformer delegate;

public AspectJClassBypassingClassFileTransformer(ClassFileTransformer delegate) {
this.delegate = delegate;
}

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

if (className.startsWith("org.aspectj") || className.startsWith("org/aspectj")) {
return classfileBuffer;
}
// 具体哪些bean的class要修改,怎么修改,则统一委托给了ClassFileTransformer
return this.delegate.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
}
}


参考:

  1. 《spring源码深度解析》 郝佳
  2. https://www.cnblogs.com/rickiyang/p/11368932.html