美文网首页
Spring AOP源码浅析

Spring AOP源码浅析

作者: Coding小聪 | 来源:发表于2020-03-28 00:10 被阅读0次

    1. Spring AOP示例代码


    示例代码结构如下图所示:

    其中切面类AspectObject的代码:

    @Aspect
    @Component
    public class AspectObject {
    
        //抽取公共的切入点表达式
        //1、本类引用
        //2、其他的切面引用
        @Pointcut("execution(public * io.zgc.spring.features.aop.annotation.TargetObject.*(..))")
        public void pointCut(){};
    
        //@Before在目标方法之前切入;切入点表达式(指定在哪个方法切入)
        @Before("pointCut()")
        public void logStart(JoinPoint joinPoint){
            Object[] args = joinPoint.getArgs();
            System.out.println(""+joinPoint.getSignature().getName()+"运行。。。@Before:参数列表是:{"+ Arrays.asList(args)+"}");
        }
    
        @After("io.zgc.spring.features.aop.annotation.AspectObject.pointCut()")
        public void logEnd(JoinPoint joinPoint){
            System.out.println(""+joinPoint.getSignature().getName()+"结束。。。@After");
        }
    
        //JoinPoint一定要出现在参数表的第一位
        @AfterReturning(value="pointCut()",returning="result")
        public void logReturn(JoinPoint joinPoint,Object result){
            System.out.println(""+joinPoint.getSignature().getName()+"正常返回。。。@AfterReturning:运行结果:{"+result+"}");
        }
    }
    

    被代理类TargetObject的代码:

    @Component
    public class TargetObject implements TargetInterface{
    
        public String sayHello(String name) {
            System.out.println("hello,"+name);
            return "hello---"+name;
        }
    
    }
    

    测试客户端Client的代码:

    package io.zgc.spring.features.aop.annotation;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class Client {
        public static void main(String[] args) {
            ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
    
            TargetInterface bean = applicationContext.getBean(TargetInterface.class);
            bean.sayHello("zgc");
            System.out.println(bean.getClass().getName());
        }
    }
    

    运行测试代码,输入如下结果

    sayHello运行。。。@Before:参数列表是:{[zgc]}
    hello,zgc
    sayHello结束。。。@After
    sayHello正常返回。。。@AfterReturning:运行结果:{hello---zgc}
    com.sun.proxy.$Proxy21
    

    从输出结果,可以看出TargetObject类,已经被Spring修改成了代理类com.sun.proxy.$Proxy21并在sayHello方法执行的织入了代理逻辑。接下来,我们就来分析下Spring是在什么地方以及通过什么方式将TargetObject替换成代理对象。

    2. Debug调试


    我们使用倒推的方式进行debug,重点关注我们需要关注的代码。

    2.1. getBean调试

    我们先假设代理对象实在获取bean的时候发生的。

    TargetInterface bean = applicationContext.getBean(TargetInterface.class);
    

    Debug跟进去发现,它最终是在singletonObjects中将代理对象获取出来的,而singletonObjects是个Map结构,它里面存放的是单例bean,可以简单将其理解为bean工厂(tips:这种理解并不准确)。

    这里我们可以得出结论:代理对象的创建一定是包含在ApplicationContext对象创建的过程中

    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
    

    那我们就在singletonObjects放置值的地方加上断点,再通过程序的调用栈尝试查看代理对象在什么地方生成。

    为了减低干扰,断点需要加上条件beanName.equals("targetObject");

    2.2. ApplicationContext创建debug

    上面断点设置后,我们重新运行程序,可以看到以下程序调用栈

    我们向上追溯一下调用栈上的代码,调用addSingleton()方法时已经将代理对象通过入参传递进来。而DefaultSingletonBeanRegistry#getSingleton()的伪代码如下:

      public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
            synchronized (this.singletonObjects) {
                Object singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    ... ...
                    try {
                        // 这里获取targetObject的代理对象,实际会调用createBean方法
                        singletonObject = singletonFactory.getObject();
                    }
                    ... ...
                    addSingleton(beanName, singletonObject);
                }
                return singletonObject;
            }
        }
    

    继续向上追溯, AbstractBeanFactory#doGetBean, 其伪代码如下:

    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                              @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
        // Create bean instance.
        if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
                try {
                    return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                    ... ...
                }
            });
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
        }
        return (T) bean;
    }
    

    结合getSingletondoGetBean方法可知,当调用ObjectFactorygetObject方法时,会触发ObjectFactory类的createBean方法执行。

    至此,我们知道了代理对象的创建是发生在createBean方法中,因此我们在此处增加条件断点,看看springcreateBean方法中做了哪些操作。

    2.3. createBean调试

    设置好断点之后,我们重新执行程序,一路step into

    图中最下面的lambda$doGetBean就是我们给createBean设置断点的地方。最终程序执行到了AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization。其代码如下:

        public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
                throws BeansException {
    
            Object result = existingBean;
            for (BeanPostProcessor processor : getBeanPostProcessors()) {
                Object current = processor.postProcessAfterInitialization(result, beanName);
                if (current == null) {
                    return result;
                }
                result = current;
            }
            return result;
        }
    

    可以看到这里是遍历所有的BeanPostProcessor,然后依次执行其postProcessAfterInitialization方法。此时Spring运行的相关变量如下

    这里注意一下,程序运行到这里,TargetObject对应的是原始对象,还没有被代理。

    另外当前Spring上下文中包含的BeanPostProcessor中,有一个AnnotationAwareAspectJAutoProxyCreator。这个类是个后置处理器,它和代理对象的创建密不可分。

    2.4. AnnotationAwareAspectJAutoProxyCreator调试

    我们先来看看AnnotationAwareAspectJAutoProxyCreator类的继承结构

    可以看到AnnotationAwareAspectJAutoProxyCreator类继承了BeanPostProcessorBeanFactoryAware。而BeanFactoryAware接口的postProcessAfterInitialization方法是在父类AbstractAutoProxyCreator中实现。

    下面接着上面的applyBeanPostProcessors方法继续调试。

    最终请求链路进入到ProxyCreatorSupport#createAopProxy方法(接下来的代码都是创建aop代理对象的核心逻辑),其源码如下:

        protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                activate();
            }
            return getAopProxyFactory().createAopProxy(this);
        }
    

    DefaultAopProxyFactory#createAopProxy

        public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
                Class<?> targetClass = config.getTargetClass();
                if (targetClass == null) {
                    throw new AopConfigException("TargetSource cannot determine target class: " +
                            "Either an interface or a target is required for proxy creation.");
                }
                if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                    return new JdkDynamicAopProxy(config);
                }
                return new ObjenesisCglibAopProxy(config);
            }
            else {
                return new JdkDynamicAopProxy(config);
            }
        }
    

    最终调用JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)方法,其内部同步JDK动态代理,创建代理对象。

    Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    

    至此,我们已经清楚的知道Spring是如何创建AOP代理对象。

    2.5. 小结

    Spring在创建IOC容器时,通过Spring提供的后置处理器扩展点,先向容器注册一个AnnotationAwareAspectJAutoProxyCreator后置处理器。再通过该后置处理器(其他后置处理器也如此)可以介入bean创建的生命周期,将原生bean通过JDK动态代理和cglib的方式替换成AOP代理类。

    3. @EnableAspectJAutoProxy


    上面还有一个疑问,AnnotationAwareAspectJAutoProxyCreator是怎么注册到IOC容器中的?答案就是@EnableAspectJAutoProxy

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AspectJAutoProxyRegistrar.class)
    public @interface EnableAspectJAutoProxy {
    
        boolean proxyTargetClass() default false;
    
        boolean exposeProxy() default false;
    
    }
    

    可以看到在@EnableAspectJAutoProxy注解中,为引入了(向容器注册)AspectJAutoProxyRegistrar类。

    @Import(AspectJAutoProxyRegistrar.class)
    

    AspectJAutoProxyRegistrar类最终会引入AnnotationAwareAspectJAutoProxyCreator后置处理器,相关代码如下:

    class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    
        @Override
        public void registerBeanDefinitions(
                AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
            AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
    
            AnnotationAttributes enableAspectJAutoProxy =
                    AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
            if (enableAspectJAutoProxy != null) {
                if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                }
                if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                    AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
                }
            }
        }
    
    }
    
    AopConfigUtils
    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                BeanDefinitionRegistry registry, @Nullable Object source) {
    
            return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
        }
    

    注册AnnotationAwareAspectJAutoProxyCreator的代码最终是需要创建IOC容器时来触发,调用链路图如下:

    3.1. 创建和注册AnnotationAwareAspectJAutoProxyCreator流程

    流程:
    1)、传入配置类(或者配置文件),创建ioc容器
    2)、注册配置类,调用refresh()刷新容器;
    3)、registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建;


    AnnotationAwareAspectJAutoProxyCreator创建时序图

    1、先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
    2、给容器中加别的BeanPostProcessor
    3、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
    4、再给容器中注册实现了Ordered接口的BeanPostProcessor;
    5、注册没实现优先级接口的BeanPostProcessor;
    6、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;创建internalAutoProxyCreator BeanPostProcessor 【 AnnotationAwareAspectJAutoProxyCreator 】

    • 6.1. 创建Bean的实例
    • 6.2. populateBean;给bean的各种属性赋值
    • 6.3. initializeBean:初始化bean;
      • 6.3.1. invokeAwareMethods():处理Aware接口的方法回调
      • 6.3.2. applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
      • 6.3.3. invokeInitMethods();执行自定义的初始化方法
      • 6.3.4. applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
    • 6.4. BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
      1. 把BeanPostProcessor注册到BeanFactory中;
    beanFactory.addBeanPostProcessor(postProcessor);
    

    相关文章

      网友评论

          本文标题:Spring AOP源码浅析

          本文链接:https://www.haomeiwen.com/subject/nhyjkftx.html