load-time weaving LTW 表示的是
在虚拟机载入字节码文件时动态植入AspectJ切面。 比动态代理效率更高
开关 <context:load-time-weaver />
创建AOP静态代理
使用instrumentation,其实就是一个简化版的aop。
应用小案例,计算一个方法的执行时间。
1. 使用jboss的javassist动态改变字节码文件
2. 在虚拟机实例instrumentation中添加transformer.Instrumentation.addTransformer(ClassFileTransformer former)
3. ClassFileTransformer 实现类里面 transform
方法改变字节码文件的内容,加入需要增强的功能。比如计算当前时间。
aop代理
- 解析自定义标签,注册LoadTimeWeaverBeanDefinitionParser,
和动态代理类似. 解析时,先调用
AbstractSingleBeanDefinitionParser
中的 parseInternal,会产生一个beanDefaultContextLoadTimeWeaver
,这个bean 实现了LoadTimeWeaver
LoadTimeWeaverBeanDefinitionParser
里面注册AspectJWeavingEnabler
,这个bean 实现了 BeanFactoryPostProcessor, BeanClassLoaderAware, LoadTimeWeaverAware, Ordered 各个接口都有作用
DefaultContextLoadTimeWeaver
实现了BeanClassLoaderAware,在bean初始化的时候,先调用invokeAwareMethods(ps:在postProcessBeforeInitialization方法前调用),会执行setBeanClassLoader
,将类DefaultContextLoadTimeWeaver中的loadTimeWeaver属性赋值为InstrumentationLoadTimeWeaver
this.loadTimeWeaver = new InstrumentationLoadTimeWeaver(classLoader);
上面的代码,实例化的过程中,也将instrumentation 这个虚拟机实例也初始化好了。后面可以直接使用这个来操作addTransformer方法了。
注册LoadTimeWeaverAwareProcessor
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;
}
以上代码的功能是,将AspectJWeavingEnabler 中的LoadTimeWeaver 属性赋值为DefaultContextLoadTimeWeaver。
AspectJWeavingEnabler postProcessBeanFactory
AspectJWeavingEnabler
,这个bean 实现了 BeanFactoryPostProcessor,会在所有bean解析结束后,调用postProcessBeanFactory
public static void enableAspectJWeaving(LoadTimeWeaver weaverToUse, ClassLoader beanClassLoader) {
if (weaverToUse == null) {
if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
weaverToUse = new InstrumentationLoadTimeWeaver(beanClassLoader);
}
else {
throw new IllegalStateException("No LoadTimeWeaver available");
}
}
weaverToUse.addTransformer(new AspectJClassBypassingClassFileTransformer(
new ClassPreProcessorAgentAdapter()));
}
注册转换器
weaverToUse.addTransformer(new AspectJClassBypassingClassFileTransformer(new ClassPreProcessorAgentAdapter()));
此时,weaverToUse已经是DefaultContextLoadTimeWeaver,调用addTransformer方法,会再次调用类中的loadTimeWeaver,也就是前面已经赋值的InstrumentationLoadTimeWeaver对象,这个对象里面就有Instrumentation。
这行代码就是:把改变字节码文件的处理类加入到虚拟机实例Instrumentation中。
最终就是调用了
InstrumentationLoadTimeWeaver.addTransformer()
@Override
public void addTransformer(ClassFileTransformer transformer) {
Assert.notNull(transformer, "Transformer must not be null");
FilteringClassFileTransformer actualTransformer =
new FilteringClassFileTransformer(transformer, this.classLoader);
synchronized (this.transformers) {
if (this.instrumentation == null) {
throw new IllegalStateException(
"Must start with Java agent to use InstrumentationLoadTimeWeaver. See Spring documentation.");
}
this.instrumentation.addTransformer(actualTransformer);
this.transformers.add(actualTransformer);
}
}
最后,一旦把actualTransformer 加入到Instrumentation中,JVM进行类加载的时候,会在字节码文件中织入需要增强的代码,达到了静态aop代理的效果。