• 创建AOP静态代理(下篇)


    织入

    当我们完成了所有的AspectJ的准备工作后便可以进行织入分析了,首先还是从LoadTimeWeaverAwareProcessor开始。

      LoadTimeWeaverAwareProcessor实现BeanPostProcessor方法,那么对于BeanPostProcessor接口来讲,postProcessBeforeInitialization和postProcessAfterInitialization有着其特殊的意义,也就是说在所有bean的初始化之前和初始化之后都会分别调用的方法,那么LoadTimeWeaverAwareProcessor中的postProcessBeforeInitialization函数中完成了什么样的逻辑呢?

    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中的postProcessBeforeInitialization函数中,因为最开始的if判断注册这个后处理只是对LoadTimeWeaverAware类型的bean起作用,而纵观所有的bean,实现LoadTimeWeaverAware接口的只有AspectJWeavingEnabler。

      当在Spring中调用AspectJWeavingEnabler时,this.loadTimeWeaver尚未被初始化,那么,会直接调用BeanFactory.getBean方法获取对应的DefaultContextLoadTimeWeaver类型的bean,并将其设置为AspectJWeavingEnabler类型的bean的loadTimeWeaver属性中。当然AspectJWeavingEnabler同样实现了BeanClassLoaderAware以及Ordered接口,实现BeanClassLoaderAware接口保证了在bean初始化的时候调用AbstractAutowireCapableBeanFactory的invokeAwareMethods的时候将beanClassLoader赋值给当前类。而实现Ordered接口则保证在实例化bean时当前bean会被最先初始化。

      而DefaultContextLoadTimeWeaver类又同时实现了LoadTimeWeaver、BeanClassLoaderAware以及DisposableBean。其中DisposableBean接口保证在bean销毁时会调用destroy方法进行bean的清理,而BeanClassLoaderAware接口则保证在bean的初始化调用AbstractAutowireCapableBeanFactory的invokeAwareMethods时调用setBeanClassLoader方法。

    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");
                //检查当前虚拟机中的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类型的实例,而且在实例化过程中还做了一些额外的操作。

    在实例化的过程中会对当前的this.instrumentation属性进行初始化,而初始化的代码如下:this.instrumentation = getInstrumentation(),也就是说在InstrumentationLoadTimeWeaver实例化后其属性Instrumentation已经被初始化为代表着当前虚拟机的实例了。

    也就是经过以上程序处理后,在Spring中的bean之间的关系如下:

      ❤ AspectJWeavingEnabler 类型的 bean中的loadTimeWeaver属性被初始化为DefaultContextLoadTimeWeaver类型的bean;

      ❤ DefaultContextLoadTimeWeaver类型的bean中的loadTimeWeaver属性被初始化为InstrumentationLoadTimeWeaver。

    因为AspectJWeavingEnabler类同样实现了BeanFactoryPostProcessor,所以当所有bean解析结束后会调用其postProcessBeanFactory方法:

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            enableAspectJWeaving(this.loadTimeWeaver, this.beanClassLoader);
        }
    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;
                }
                return this.delegate.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
            }
        }
    AspectJClassBypassingClassFileTransformer的作用仅仅是告诉AspectJ以org.aspectj开头的或者org/aspectj开头的类不进行处理。

    参考:《Spring源码深度解析》 郝佳 编著:

  • 相关阅读:
    Flink (一)概述
    【转】你未必知道的49个CSS知识点
    【转】清除浮动的四种方式及其原理理解
    前端知识总结
    【转】CSS为什么这么难学?方法很重要!
    【转】chrome开发者工具各种骚技巧
    【ASP.NET Core】设置Web API 响应的数据格式——Produces 特性篇
    【ASP.NET Core】绑定到 CancellationToken 对象
    【ASP.NET Core】设置 Web API 响应数据的格式——FormatFilter特性篇
    【ASP.NET Core】MVC 控制器的模型绑定(宏观篇)
  • 原文地址:https://www.cnblogs.com/Joe-Go/p/10244469.html
Copyright © 2020-2023  润新知