美文网首页spring framework
Spring AOP实现原理

Spring AOP实现原理

作者: 梦想实现家_Z | 来源:发表于2021-07-05 10:32 被阅读0次

    通过上一篇文章Spring Bean的创建过程及相关扩展点的介绍,我们知道getBean()创建Bean实例的过程,有以下几个扩展点:

    • Bean实例创建之前实现InstantiationAwareBeanPostProcessor接口
    • Bean实例创建成功后,未设置属性时,立马创建一个工厂方法。可通过实现SmartInstantiationAwareBeanPostProcessor接口对Bean增强
    • Bean初始化的生命周期中,实现BeanPostProcessor接口对Bean增强

    SpringBoot如何实现Aop:

    1.先从spring-boot-autoconfigure包下面的/META-INF/spring.factories开始,可以发现AopAutoConfiguration这个类,说明在引入spring-boot-autoconfigure这个jar包后,就会自动加载AopAutoConfiguration。

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
    public class AopAutoConfiguration {
    
        @Configuration(proxyBeanMethods = false)
        @ConditionalOnClass(Advice.class)
        static class AspectJAutoProxyingConfiguration {
    
            @Configuration(proxyBeanMethods = false)
            @EnableAspectJAutoProxy(proxyTargetClass = false)
            @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
                    matchIfMissing = false)
            static class JdkDynamicAutoProxyConfiguration {
    
            }
    
            @Configuration(proxyBeanMethods = false)
            @EnableAspectJAutoProxy(proxyTargetClass = true)
            @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
                    matchIfMissing = true)
            static class CglibAutoProxyConfiguration {
    
            }
        }
    
        @Configuration(proxyBeanMethods = false)
        @ConditionalOnMissingClass("org.aspectj.weaver.Advice")
        @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
                matchIfMissing = true)
        static class ClassProxyingConfiguration {
    
            ClassProxyingConfiguration(BeanFactory beanFactory) {
                if (beanFactory instanceof BeanDefinitionRegistry) {
                    BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
                    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                }
            }
        }
    }
    

    主要是看EnableAspectJAutoProxy这个注解,无论如何,这个注解都会生效

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(AspectJAutoProxyRegistrar.class)
    public @interface EnableAspectJAutoProxy {
    
        /**
         * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
         * to standard Java interface-based proxies. The default is {@code false}.
         */
        boolean proxyTargetClass() default false;
    
        /**
         * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
         * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
         * Off by default, i.e. no guarantees that {@code AopContext} access will work.
         * @since 4.3.1
         */
        boolean exposeProxy() default false;
    
    }
    

    进一步看一下

    class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    
        /**
         * Register, escalate, and configure the AspectJ auto proxy creator based on the value
         * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
         * {@code @Configuration} class.
         */
        @Override
        public void registerBeanDefinitions(
                AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 这是重点------这是重点------这是重点------
        // 这里就是注入AnnotationAwareAspectJAutoProxyCreator对象入口
            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);
                }
            }
        }
    }
    
    AnnotationAwareAspectJAutoProxyCreator类的UML图 image-20210701142934998.png

    可以看到,AnnotationAwareAspectJAutoProxyCreator这个类是实现了InstantiationAwareBeanPostProcessor、SamrtInstantiationAwareBeanPostProcessor、BeanPostProcessor接口的,那么说明这个类是可以在Bean实例创建过程中,对Bean创建过程进行拦截和增强的。

    同样的,AspectJAwareAdvisorAutoProxyCreator这个类其实就是基于XML配置来对Bean进行拦截和增强的。

    1.在Bean实例化之前:

    @Override
        public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
            Object cacheKey = getCacheKey(beanClass, beanName);
    
            if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
                if (this.advisedBeans.containsKey(cacheKey)) {
                    return null;
                }
                if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
                    this.advisedBeans.put(cacheKey, Boolean.FALSE);
                    return null;
                }
            }
        // 这是重点----这是重点-----这是重点
        // 从这里可以看出,这又是一种创建Bean实例的方式
        // 通过自定义的TargetSource来创建Bean实例。属于非常规用法。
            // Create proxy here if we have a custom TargetSource.
            // Suppresses unnecessary default instantiation of the target bean:
            // The TargetSource will handle target instances in a custom fashion.
            TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
            if (targetSource != null) {
                if (StringUtils.hasLength(beanName)) {
                    this.targetSourcedBeans.add(beanName);
                }
                Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
          // 收集所有的Advisor后,通过MethodInterceptor创建代理。具体的实现可以是JDK或者CGLIB
                Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
                this.proxyTypes.put(cacheKey, proxy.getClass());
                return proxy;
            }
    
            return null;
        }
    

    在此基础上,我们可以自定义一个BeanPostProcessor,针对AnnotationAwareAspectJAutoProxyCreator进行拦截,在AnnotationAwareAspectJAutoProxyCreator初始化生命周期中,给它创建一个TargetSource对象设置进去,这样就可以促使getCustomTargetSource()方法生效了。

    2.另一个就是在Bean实例化后,把Bean对象放进第三级缓存中

    // AbstractAutowireCapableBeanFactory类中587行
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    
    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
            Object exposedObject = bean;
            if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                        SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
              // ********这是关键点********这是关键点********这是关键点********这是关键点********
                        exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                    }
                }
            }
            return exposedObject;
        }
    
    // AbstractAutoProxyCreator类中237行,AbstractAutoProxyCreator是SmartInstantiationAwareBeanPostProcessor子类,是实现AOP的入口
    @Override
        public Object getEarlyBeanReference(Object bean, String beanName) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            this.earlyProxyReferences.put(cacheKey, bean);
        // ********这是关键点********这是关键点********这是关键点********这是关键点********
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
            if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
                return bean;
            }
            if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
                return bean;
            }
            if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
    
            // 获取所有的Advisor实例,并筛选出匹配的Advisor实例
        // 获取Advisor的方式也是通过getBean()的方式,根据指定目标为Advisor.class查找
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
            if (specificInterceptors != DO_NOT_PROXY) {
                this.advisedBeans.put(cacheKey, Boolean.TRUE);
          // 根据筛选出来的Advisor实例,创建代理对象
          // 如何创建的代理,其实就是使用了JDK动态代理或者CGLIB动态代理实现
                Object proxy = createProxy(
                        bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                this.proxyTypes.put(cacheKey, proxy.getClass());
          // 返回增强后的Bean对象
                return proxy;
            }
    
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    

    3.Bean初始化后

    // AbstractAutoProxyCreator类中295行
    @Override
        public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
            if (bean != null) {
                Object cacheKey = getCacheKey(bean.getClass(), beanName);
                if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            // ********这是关键点********同上********同上********这是关键点********
            // 和上面的wrapIfNecessary()一样
                    return wrapIfNecessary(bean, beanName, cacheKey);
                }
            }
            return bean;
        }
    

    根据AbstractAutoProxyCreator来看,AOP切入的点有三个地方:

    1.postProcessBeforeInstantiation():就是在Bean还没有创建出来之前,这个点是留给开发者自己扩展的。针对自定义TargetSource,检查是否有匹配的Advisor,如果有的话,那么就创建对应的代理对象。

    2.postProcessAfterInitialization():这个就是Bean已经完成了初始化了,这个时候的Bean已经准备发布了,那么针对这个Bean对象,检查是否有匹配的Advisor,有的话,就创建对应的代理对象。

    3.getEarlyBeanReference():这个就是Bean刚刚创建出来,还没有设置属性值,还不能发布,但是为了解决循环依赖的问题,需要先把这个Bean的引用发布出去。那么针对这个Bean就要检查是否有匹配的Advisor,有的话,创建代理对象。

    在这三个扩展点,分别会做以下几件事情:

    1.findCandidateAdvisors()方法获取所有的Advisor实例,并存放到一个数组里面;原理还是getBean()方式查找Advisor.class所有实例

    2.findAdvisorsThatCanApply()方法从数组中筛选出拦截这个Bean的Advisor,有拦截class的,也有method;主要区分出IntroductionAdvisor、PointcutAdvisor;

    • 2.1:IntroductionAdvisor只能拦截class,PointcutAdvisor可以拦截method和class。

    3.针对筛选出来的Advisor排序

    4.根据筛选出来的Advisor对象,通过ProxyFactory.getProxy()创建代理。

    另外,再介绍两个手动编程创建代理对象的类:

    • AspectJProxyFactory
      • 这个类包含两个功能:创建代理的功能;处理Advisor、Advice的功能
    • ProxyFactory
      • 这个类只能创建代理,Advisor、Advice需要自己手动创建

    以上两个类的区别在于,AspectJProxyFactory这个类里面有一个ReflectiveAspectJAdvisorFactory对象属性专门用来处理并生成Advisor、Advice。

    共同点就是都能创建代理对象,主要是因为这两个类都继承自ProxyCreatorSupport。

    相关文章

      网友评论

        本文标题:Spring AOP实现原理

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