Spring源码解析9——静态AOP
1、创建AOP静态代理
AOP 的静态代理主要是在虚拟机启动时通过改变 目标对象字节码的方式来完成对目标对象的增强,它与动态代理相比具有更高的效率,因为在动态代理调用的过程中,还需要一个动态创建代理类并代理目标对象的步骤,而静态代理则是在启动时便完成了字节码增强,当系统再次调用目标类时与调用正常的类井元差别, 所以在效率上会相对高些。
1.1、Instrumentation的使用
Java 在1.5 引人java.lang.instrument,你可以由此实现一个 Java agent,通过此 agent来修改类的字节码即改变一个类。本节会通过 Java Instrument 实现一个简单的 profiler。
- 实现一个ClassFileTransformer.class的子类
package com.xxx.spring源码深度解析_第七章.AopStaticProxy;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtBehavior;
import javassist.CtClass;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
public class PerfMonXformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
byte[] transformed = null;
System.out.println("Transforming " + className);
ClassPool pool = ClassPool.getDefault();
CtClass cl = null;
try {
cl = pool.makeClass(new java.io.ByteArrayInputStream(classfileBuffer));
if (cl.isInterface() == false) {
CtBehavior[] methods = cl.getDeclaredBehaviors();
for (int i = 0; i < methods.length; i++) {
//修改test()函数的字节码
if ("test".equals(methods[i].getName())) {
doMethod(methods[i]);
}
}
transformed = cl.toBytecode();
}
} catch (Exception e) {
System.err.println("Could not instrument " + className + ", exception :" + e.getMessage());
} finally {
if (cl != null) {
cl.detach();
}
}
return transformed;
}
private void doMethod(CtBehavior method) throws CannotCompileException {
method.insertBefore("System.out.println(\"函数执行前\");");
method.insertAfter("System.out.println(\"函数执行后\");");
}
}
- agent类
package com.xxx.spring源码深度解析_第七章.AopStaticProxy;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
public class PerfMonAgent {
static private Instrumentation inst = null;
public static void premain(String agentArgs, Instrumentation _inst) {
System.out.println("PerfMonAgent.premain() was called.");
inst = _inst;
ClassFileTransformer trans = new PerfMonXformer();
System.out.println("Adding a PerfMonXformer instance to the JVM.");
inst.addTransformer(trans);
}
}
- 通过以下pom文件打包agent
<?xml version="1.0" encoding="UTF-8"?>
<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.xxx</groupId>
<artifactId>Spring03_proxy</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<archive>
<manifestEntries>
<!--JAR 的 META-INF/MANIFEST.MF 加入 Premain-Class:【PerfMonAgent.class的classPath路径(相对路径)】 -->
<Premain-Class>com.xxx.spring源码深度解析_第七章.AopStaticProxy.PerfMonAgent</Premain-Class>
<!--JAR 的 META-INF/MANIFEST.MF 加入 Boot-Class-Path:【javassist-3.8.0.GA.jar的绝对路径】 -->
<Boot-Class-Path>D:\maven_repository\javassist\javassist\3.8.0.GA\javassist-3.8.0.GA.jar</Boot-Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.8.0.GA</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- 打包应用
package com.xxx.spring源码深度解析_第七章.AopStaticProxy;
public class App {
public static void main(String[] args) {
new App().test();
}
public void test() {
System.out.println("Hello World!!");
}
}
-
执行App.class::main()函数时在VM options(idea中)加入--javaagent:【通过上面的maven配置打好的jar包】
![image]()
-
该agent就会在App.class::test()函数执行前,执行System.out.println("函数执行前");和System.out.println("函数执行前");语句,执行结果如下所示:
![image]()
![image]()
![image]()
以上结果表明:通过Instrment 实现 agent 使得监控代码和应用代码完全隔离了。
通过这个案例可以说明,在 Spring 中的静态 AOP 直接使用了AspectJ提供的方法,而 AspectJ又是在 Instrument基础上进行的封装。就以上面的例子来看,至少在 AspectJ 中会有如下功能。
①、读取 META-INF/aop.xml.
②、将 aop.xml 中定义的增强器通过自定义的 ClassFileTransformer 织入对应的类中。
1.2、织入
LoadTimeWeaverAwareProcessor.class 实现 BeanPostProcessor.interface接口中的函数,那么对于 BeanPostProcessor 接口来讲,postProcessBeforeInitialization()函数与postProcessAfterlnitialization()函数 有着其特殊意义,也就是说在所有 bean 的初始化之前与之后都会分别调用对应的方法,那么在 LoadTimeWeaverAwareProcessor.class::postProcessBeforeInitialization()函数中完成了什么逻辑呢?
LoadTimeWeaverAwareProcessor.class::postProcessBeforeInitialization()
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LoadTimeWeaverAware) {
LoadTimeWeaver ltw = this.loadTimeWeaver;
if (ltw == null) {
Assert.state(this.beanFactory != null,
"BeanFactory required if no LoadTimeWeaver explicitly specified");
ltw = this.beanFactory.getBean(
ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME, LoadTimeWeaver.class);
}
((LoadTimeWeaverAware) bean).setLoadTimeWeaver(ltw);
}
return bean;
}
我们综合之前讲解的所有信息,将所有相关信息串联起来一起分析这个函数。在LoadTimeWeaverAwareProcessor.class::postProcessBeforelnitialization() 函数中,因为最开始的if判断注定这个后处理器只对 LoadTimeWeaverAware 类型的 bean 起作用,而纵观所有的bean,实现 LoadTimeWeaverAware 接口的类只有AspectJWeavingEnabler.class。
当在 Spring 中调用 AspectJWeavingEnabler 时,this.loadTimeWeaver()函数尚未被初始化,那么,会直接调用 beanFactory.getBean()函数获取对应的 DefaultContextLoadTimeWeaver.class 类型的 bean,并将其设置为 AspectJWeavingEnabler.class 类型 bean 的loadTimeWeaver属性中。当然 AspectJWeavingEnabler 同样实现了 BeanClassLoaderAware.interface 以及Ordered.interface 接口,实现 BeanClassLoaderAware.interface 接口保证了在 bean初始化的时候调用AbstractAutowireCapableBeanFactory.class::invokeAwareMethods()函数的时候将beanClassLoader 赋值给当前类。而实现 Ordered.interface 则保证在实例化 bean 时当前 bean 会被最先初始化。
而 DefaultContextLoadTimeWeaver.class又同时实现了 LoadTimeWeaver、BeanClassLoaderAware以及 DisposableBean。其中 DisposableBean.interface保证在 bean 销毁时会调用 destroy()函数进行 bean的清理,而 BeanClassLoaderAware.interface接口则保证在 bean 的初始化调用 AbstractAutowireCapableBeanFactory.class::invokeAwareMethods()函数时调用DefaultContextLoadTimeWeaver.class:setBeanClassLoader()函数。
DefaultContextLoadTimeWeaver.class::setBeanClassLoader()函数
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
LoadTimeWeaver serverSpecificLoadTimeWeaver = createServerSpecificLoadTimeWeaver(classLoader);
if (serverSpecificLoadTimeWeaver != null) {
if (logger.isInfoEnabled()) {
logger.info("Determined server-specific load-time weaver: " +
serverSpecificLoadTimeWeaver.getClass().getName());
}
this.loadTimeWeaver = serverSpecificLoadTimeWeaver;
}
else if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
//检查当前虚拟机中的Instrumentation实例是否可用
logger.info("Found Spring's JVM agent for instrumentation");
//实例化了一个 InstrumentationLoadTimeWeaver 类型的实例,而且在实例化过程中还做了一些额外的操作。
this.loadTimeWeaver = new InstrumentationLoadTimeWeaver(classLoader);
}
else {
try {
this.loadTimeWeaver = new ReflectiveLoadTimeWeaver(classLoader);
if (logger.isInfoEnabled()) {
logger.info("Using a 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.class过程中会对private final Instrumentation instrumentation属性进行初始化,代码如下:
InstrumentationAccessor.class的构造函数
public InstrumentationLoadTimeWeaver(@Nullable ClassLoader classLoader) {
this.classLoader = classLoader;
this.instrumentation = getInstrumentation();
}
也就是说在 InstrumentationLoadTimeWeaver 实例化后其属性 Instrumentation 已经被初始化为代表着当前虚拟机的实例了。综合我们讲过的例子,对于注册转换器,如 addTransformer()函数等,便可以直接使用此属性进行操作了。
也就是经过以上程序的处理后,在 Spring 中的 bean 之间的关系如下:
①、AspectJWeavingEnabler.class 类型的 bean 中的 loadTimeWeaver 属性被初始化为 DefaultContextLoadTimeWeaver 类型的 bean。
②、DefaultContextLoadTimeWeaver.class 类型的 bean 中的 loadTimeWeaver 属性被初始化为InstrumentationLoadTimeWeaver.
因为 AspectJWeavingEnabler.class同样实现了 BeanFactoryPostProcessor,所以当所有 bean 解析结束后会调用其 postProcessBeanFactory() 函数。
BeanFactoryPostProcessor.interface
@FunctionalInterface
public interface BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
AspectJWeavingEnabler.class
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
enableAspectJWeaving(this.loadTimeWeaver, this.beanClassLoader);
}
/**
* Enable AspectJ weaving with the given {@link LoadTimeWeaver}.
* @param weaverToUse the LoadTimeWeaver to apply to (or {@code null} for a default weaver)
* @param beanClassLoader the class loader to create a default weaver for (if necessary)
*/
public static void enableAspectJWeaving(
@Nullable LoadTimeWeaver weaverToUse, @Nullable ClassLoader beanClassLoader) {
if (weaverToUse == null) {
//此时已经被初始化为DefaultContextLoadTimeWeaver
if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
weaverToUse = new InstrumentationLoadTimeWeaver(beanClassLoader);
}
else {
throw new IllegalStateException("No LoadTimeWeaver available");
}
}
//使用DefaultContextLoadTimeWeaver类型的bean中的loadTimeWeaver属性注册转换器
weaverToUse.addTransformer(
new AspectJClassBypassingClassFileTransformer(new ClassPreProcessorAgentAdapter()));
}
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;
}
//委托给AspectJ代理继续处理
return this.delegate.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
}
}
AspectJClassBypassingClassFileTransformer.class 的作用仅仅是告诉AspectJ以org.aspectj开头的或者 org/aspectj 开头的类不进行处理。
AspectJWeavingEnabler.class与BeanFactoryPostProcessor.interface、AspectJClassBypassingClassFileTransformer.class之间的UML关系图,如下所示:






浙公网安备 33010602011771号