spring 源码探索-- 静态AOP代理

来源:互联网 发布:云计算发展与政策论坛 编辑:程序博客网 时间:2024/05/18 02:38

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代理

  1. 解析自定义标签,注册LoadTimeWeaverBeanDefinitionParser,
    和动态代理类似.
  2. 解析时,先调用 AbstractSingleBeanDefinitionParser 中的 parseInternal,会产生一个bean DefaultContextLoadTimeWeaver,这个bean 实现了 LoadTimeWeaver

  3. 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代理的效果。

0 0
原创粉丝点击