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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值