Springboot源码分析之EnableAspectJAutoProxy

摘要:

Spring Framwork的两大核心技术就是IOCAOPAOPSpring的产品线中有着大量的应用。如果说反射是你通向高级的基础,那么代理就是你站稳高级的底气。AOP的本质也就是大家所熟悉的CGLIB动态代理技术,在日常工作中想必或多或少都用过但是它背后的秘密值得我们去深思。本文主要从Spring AOP运行过程上,结合一定的源码整体上介绍Spring AOP的一个运行过程。知其然,知其所以然,才能更好的驾驭这门核心技术。

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import({AspectJAutoProxyRegistrar.class})
    public @interface EnableAspectJAutoProxy {
        //表明该类采用CGLIB代理还是使用JDK的动态代理
        boolean proxyTargetClass() default false;
         /**
         * @since 4.3.1 代理的暴露方式:解决内部调用不能使用代理的场景  默认为false表示不处理
         * true:这个代理就可以通过AopContext.currentProxy()获得这个代理对象的一个副本(ThreadLocal里面),从而我们可以很方便得在Spring框架上下文中拿到当前代理对象(处理事务时很方便)
         * 必须为true才能调用AopContext得方法,否则报错:Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.
         */
        boolean exposeProxy() default false;
    }

所有的EnableXXX驱动技术都得看他的@Import,所以上面最重要的是这一句@Import(AspectJAutoProxyRegistrar.class),下面看看它

    class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
        AspectJAutoProxyRegistrar() {
        }
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            //注册了一个基于注解的自动代理创建器   AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
            AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
            if (enableAspectJAutoProxy != null) {
                  //表示强制指定了要使用CGLIB
                if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                }
              //强制暴露Bean的代理对象到AopContext
                if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
                    AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
                }
            }
        }
    }

AspectJAutoProxyRegistrar是一个项容器注册自动代理创建器

    @Nullable
        public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                BeanDefinitionRegistry registry, @Nullable Object source) {
            return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
        }

说明spring容器的注解代理创建器就是AnnotationAwareAspectJAutoProxyCreator

    @Nullable
        private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
            Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
          //这里如果我们自己定义了这样一个自动代理创建器就是用我们自定义的
            if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
                BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
                if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
                    int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
                  /**
                   *用户注册的创建器,必须是InfrastructureAdvisorAutoProxyCreator
                   *AspectJAwareAdvisorAutoProxyCreator,AnnotationAwareAspectJAutoProxyCreator之一
                  */
                    int requiredPriority = findPriorityForClass(cls);
                    if (currentPriority < requiredPriority) {
                        apcDefinition.setBeanClassName(cls.getName());
                    }
                }
                return null;
            }
          //若用户自己没有定义,那就用默认的AnnotationAwareAspectJAutoProxyCreator
          RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
              beanDefinition.setSource(source);
          //此处注意,增加了一个属性:最高优先级执行,后面会和@Async注解一起使用的时候起关键作用
            beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
            beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
            return beanDefinition;
        }

我们就成功的注入了一个BeanAnnotationAwareAspectJAutoProxyCreator 基于注解的自动代理创建器

Spring中自动创建代理器

由此可见,Spring使用BeanPostProcessor让自动生成代理。基于BeanPostProcessor的自动代理创建器的实现类,将根据一些规则在容器实例化Bean时为匹配的Bean生成代理实例。

AbstractAutoProxyCreator是对自动代理创建器的一个抽象实现。最重要的是,它实现了SmartInstantiationAwareBeanPostProcessor接口,因此会介入到Spring IoC容器Bean实例化的过程。

SmartInstantiationAwareBeanPostProcessor继承InstantiationAwareBeanPostProcessor所以它最主要的 职责是在bean的初始化前,先会执行所有的InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation,谁第一个返回了不为nullBean,后面就都不会执行了 。然后会再执行BeanPostProcessor#postProcessAfterInitialization

    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;
        }

说明:这个方法是spring的三级缓存中的其中一环,当你调用Object earlySingletonReference = getSingleton(beanName, false);时候就会触发,其实还有一个地方exposedObject = initializeBean(beanName, exposedObject, mbd);也会触发导致返回一个代理对象。

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    invokeAwareMethods(beanName, bean);
                    return null;
                }, getAccessControlContext());
            }
            else {
                invokeAwareMethods(beanName, bean);
            }
            Object wrappedBean = bean;
            if (mbd == null || !mbd.isSynthetic()) {
                wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
            }
            try {
                invokeInitMethods(beanName, wrappedBean, mbd);
            }
            catch (Throwable ex) {
                throw new BeanCreationException(
                        (mbd != null ? mbd.getResourceDescription() : null),
                        beanName, "Invocation of init method failed", ex);
            }
            if (mbd == null || !mbd.isSynthetic()) {
                wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
            }
            return wrappedBean;
        }

强调: 这2个地方虽然都有后置增强的作用,但是@Async所使用的AsyncAnnotationBeanPostProcessor不是SmartInstantiationAwareBeanPostProcessor的实现类,所以此处会导致@Transactional@Async处理循环依赖时候的不一致性。对于循环依赖后续会有单独章节进行分享。

AbstractAdvisorAutoProxyCreator

如何创建代理对象后续文章在进行分析。

原文地址:https://www.cnblogs.com/qinzj/p/11397253.html

时间: 2024-10-09 06:46:53

Springboot源码分析之EnableAspectJAutoProxy的相关文章

[SpringBoot]源码分析SpringBoot的异常处理机制

微信号:GitShare微信公众号:爱折腾的稻草如有问题或建议,请在公众号留言[1] 前续 为帮助广大SpringBoot用户达到"知其然,更需知其所以然"的境界,作者将通过SpringBoot系列文章全方位对SpringBoot2.0.0.RELEASE版本深入分解剖析,让您深刻的理解其内部工作原理. 正文 在SpringBoot启动时,会查找并加载所有可用的SpringBootExceptionReporter,其源码如下: //7 使用SpringFactoriesLoader在

Springboot源码分析之番外篇

摘要: 大家都知道注解是实现了java.lang.annotation.Annotation接口,眼见为实,耳听为虚,有时候眼见也不一定是真实的. /** * The common interface extended by all annotation types. Note that an * interface that manually extends this one does <i>not</i> define * an annotation type. Also no

SpringBoot源码分析之---SpringBoot项目启动类SpringApplication浅析

源码版本说明 本文源码采用版本为SpringBoot 2.1.0BUILD,对应的SpringFramework 5.1.0.RC1 注意:本文只是从整体上梳理流程,不做具体深入分析 SpringBoot入口类 @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args

Springboot源码分析之TypeFilter魔力

摘要: 在平常的开发中,不知道大家有没有想过这样一个问题,为什么我们自定义注解的时候要使用spring的原生注解(这里指的是类似@Component,@Service........),要么就是 随便弄个注解,搭配自己的切面编程来实现某些业务逻辑.这篇文章主要给大家分享一下,如何脱离Spring原生注解自定义注解注入IOC SpringBootApplication注解分析 从源代码很容易看出来,它的作用就是自动装配和扫描我们的包,并将符合的类进行注册到容器.自动装配非常简单,这里不做过多分析,

SpringBoot源码分析----(一)SpringBoot自动配置

前言 springboot项目将模块化设计发挥到及至,需要什么模块,只需导入这个模块对应的stater即可,当然,用户根据业务需要自定义相关的stater,关于自定义stater在后续章节将一一解说,学习springboot,首要了解springboot的自动配置原理,我们从springboot项目的主启动类说起逐步解读springboot自动配置的奥秘. springboot自动配置解读 @SpringBootApplication public class SpringBootQuickAp

Springboot源码分析之项目结构

摘要: 无论是从IDEA还是其他的SDS开发工具亦或是https://start.spring.io/ 进行解压,我们都会得到同样的一个pom.xml文件 xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSc

SpringBoot源码分析----(二)SpringBoot自动配置原理

自动配置原理 1.SpringBoot启动的时候加载主配置类,开启了自动配置功能  @EnableAutoConfiguration [email protected] 功能的作用 @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { 利用  AutoConfigurationImportSelector  给容器

原创001 | 搭上SpringBoot自动注入源码分析专车

前言 如果这是你第二次看到师长的文章,说明你在觊觎我的美色!O(∩_∩)O哈哈~ 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 本系列为SpringBoot深度源码专车系列,第一篇发车! 专车介绍 该趟专车是开往Spring Boot自动注入原理源码分析的专车 专车问题 Spring Boot何时注入@Autowired标注的属性? 如果注入类型的Bean存在多个Spring Boot是如何处理的? 专车示例 定义接口 public interface PersonService

【原创】005 | 搭上SpringBoot请求处理源码分析专车

前言 如果这是你第二次看到师长,说明你在觊觎我的美色! 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 专车介绍 该趟专车是开往Spring Boot请求处理源码分析专车,主要用来分析Spring Boot是如何将我们的请求路由到指定的控制器方法以及调用执行. 专车问题 为什么我们在控制器中添加一个方法,使用@RequestMapping注解标注,指定一个路径,就可以用来处理一个web请求? 如果多个方法的请求路径一致,Spring Boot是如何处理的? 专车示例 @RestCo