精华内容
下载资源
问答
  • spring源码深度解析
    千次阅读
    2022-04-11 13:47:49

    Spring源码深度解析 PDF 下载

    下载地址:https://pan.baidu.com/s/1o9qEwXW密码:vwyo

    转载:http://download.csdn.net/detail/reflourish/9744199

    更多相关内容
  • Spring源码深度解析百度网盘下载-附件资源
  • Spring源码深度解析-附件资源
  • Spring 源码深度解析

    2018-04-01 21:51:11
    Spring源码深度解析》不仅介绍了使用Spring框架开发项目必须掌握的核心概念,还指导读者如何使用Spring框架编写企业级应用,并针对在编写代码的过程中如何优化代码、如何使得代码高效给出切实可行的建议,从而帮助...
  • spring源码深度解析(包含所有spring源码,带全部的注释以及案例,很适合入门级)
  • spring 源码深度解析

    2018-03-06 23:31:18
    完全从开发者的角度剖析源码,每一章都提供了容易理解的实例
  • 如在创建TestA类时,构造器需要TestB类,那将去创建TestB,在创建TestB类时又发现需要TestC类,则又去创建TestC,最终在创建TestC时发现又需要TestA,从而形成一个环,则没办法创造spring容器将每一个正在创建的bean...
  • Spring3源码深度解析[目录+高清版],这个高清版可以看清类图的内容,然后手动加了目录便于查阅
  • Spring源码深度解析 郝佳 第2版》容器的基本实现与XML文件的加载 《Spring源码深度解析 郝佳 第2版》XML标签的解析 《Spring源码深度解析 郝佳 第2版》bean的加载、循环依赖的解决 《Spring源码深度解析 郝佳 第2...

    往期博客


    《Spring源码深度解析 郝佳 第2版》容器的基本实现与XML文件的加载

    《Spring源码深度解析 郝佳 第2版》XML标签的解析

    《Spring源码深度解析 郝佳 第2版》bean的加载、循环依赖的解决

    《Spring源码深度解析 郝佳 第2版》ApplicationContext


    1、AOP面向切面编程,是一种思想,不同于OOP,他可以为不具有继承关系的对象引入一个公共行为如日志,安全监测等。具体实现分为两种参考:Spring AOP概念理解 (通俗易懂)先理解几个概念

    1. 通知Advice:也就是需要的功能,如安全、事务、日志等
    2. 切入点Pointcut:目标方法的前、后以及异常处都可以作为切入点
    3. 切面Aspect:就是 Advice + Pointcut,给哪个地方做什么增强
    4. 织入weaving:就是把切面应用到目标对象来创建新的代理对象的过程。Spring AOP或者Aspect AOP实现,区别就是织入时机不同

    2、Spring AOP和Aspect AOP的区别

    • Spring AOP:动态代理,运行时生成代理对象。他的方便在于Spring帮助我们完成增强的自动织入,在Java中可以根据接口使用JDK动态代理和Cglib动态代理。由Spring自动为我们完成运行时织入。
    • AspectJ:静态代理,编译时直接修改字节码,AspectJ是一套独立的面向切面编程的解决方案。它基于ASM字节码编辑技术,在不使用Spring的时候也可单独使用,需要导入对应的aspect相应的jar包,然后编写静态增强逻辑之后,
      • 编译时织入:利用ajc编译器替代javac编译器,直接将源文件(java或者aspect文件)编译成class文件并将切面织入进代码。
      • 编译后织入:利用ajc编译器向javac编译期编译后的class文件或jar文件织入切面代码。
      • 加载时织入(LTW):不使用ajc编译器,利用aspectjweaver.jar工具,使用java agent代理在类加载期将切面织入进代码。这和之前的二进制编织完全一样,所不同的是织入会被延后,直到类加载器将类加载到JVM。

    Spring AOP 与ApectJ 的目的一致,都是为了统一处理横切业务,但与AspectJ不同的是,Spring AOP并不尝试提供完整的AOP功能(即使它完全可以实现),Spring AOP 更注重的是与Spring IOC容器的结合,并结合该优势来解决横切业务的问题,因此在AOP的功能完善方面,相对来说AspectJ具有更大的优势,同时,Spring注意到AspectJ在AOP的实现方式上依赖于特殊编译器(ajc编译器),因此Spring很机智回避了这点,转向采用动态代理技术的实现原理来构建Spring AOP的内部机制(动态织入),这是与AspectJ(静态织入)最根本的区别。

    在AspectJ1.5后,引入@Aspect形式的注解风格的开发,Spring也非常快地跟进了这种方式,因此Spring 2.0后便使用了与AspectJ一样的注解。请注意,Spring 只是使用了与 AspectJ 5 一样的注解,但仍然没有使用 AspectJ 的编译器,底层依是动态代理技术的实现,因此并不依赖于 AspectJ 的编译器,因此无论是使用spring aop还是 aspectj都需要aspectjweaver.jar spring-aop.jar这两个jar包。使用AspectJ 的 动态织入LTW 还 需要额外的jar包 spring-instrument.jar。

    3、在Spring中配置<aop:aspectj-autoproxy>标签之后使用Spring AOP

    • 创建用于拦截的bean
    • 创建Advisor:定义切面@AspectJ,声明切点@Pointcut("execution(* *.xxx(..))"),声明通知@Before@After@Around等注解
    • 创建配置文件:在xml配置文件加上<aop:aspectj-autoproxy> 和待拦截的bean、切面bean
    • 测试

    4、在SpringBoot中使用 Spring AOP步骤:https://cloud.tencent.com/developer/article/1690944


    目录

    1. <aop:aspectj-autoproxy>标签

      • AopNamespaceHandler的init方法注册AspectJAutoProxyBeanDefinitionParser
      • AspectJAutoProxyBeanDefinitionParser的parse方法注册AnnotationAwareAspectJAutoProxyCreator,并设置target-proxy-class和expose-proxy属性值到BeanDefinition中
    2. AnnotationAwareAspectJAutoProxyCreator解析@AspectJ注解标识的Advisor

      • Spring AOP的时机
      • AbstractAutoProxyCreator核心实现AOP
        • wrapIfNessary方法对目标bean封装,然后调用getAdvicesAndAdvisorForBean查找能用到的advisors
        • ProxyFactory内部封装advisors然后createProxy方法创建代理对象
      • JdkDynamicAopProxy分析
      • Cglib2AopProxy分析
    3. AspectJ AOP


    一、<aop:aspectj-autoproxy>标签

    只要是声明的自定义注解,一定在需要一个他的解析器,解析器名称一般为XxxNamespaceHandler,在AopNamespaceHandler可以看到 设置对@AspectJ注解的解析器AspectJAutoProxyBeanDefinitionParser
    在这里插入图片描述

    public class AopNamespaceHandler extends NamespaceHandlerSupport {
        public AopNamespaceHandler() {
        }
    
        public void init() {
            this.registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
            // 设置对@AspectJ注解的解析器AspectJAutoProxyBeanDefinitionParser
            this.registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
            this.registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
            this.registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
        }
    }
    
    

    在这里插入图片描述

    1.注册AspectJAutoProxyBeanDefinitionParser

    所有的解析器都是对BeanDefinitionParser接口的统一实现,入口都是parse()方法,然后调用registerAspectJAnnotationAutoProxyCreatorIfNecessary() 注册 AnnotationAwareAspectJAutoProxyCreator 解析器的beanDefinition用于实现AOP

    // AspectJAutoProxyBeanDefinitionParser的parse()方法
     @Nullable
        public BeanDefinition parse(Element element, ParserContext parserContext) {
        	// 1. 注册AnnotationAwareAspectJAutoProxyCreator
            AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
            // 2. 对于注解类的子类的处理
            this.extendBeanDefinition(element, parserContext);
            return null;
        }
    
        private void extendBeanDefinition(Element element, ParserContext parserContext) {
            BeanDefinition beanDef = parserContext.getRegistry().getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
            if (element.hasChildNodes()) {
                this.addIncludePatterns(element, parserContext, beanDef);
            }
    
        }
    

    2. 注册AnnotationAwareAspectJAutoProxyCreator

    // AopNamespaceUtils
    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {
    		// 1.1. 注册或者升级 AutoProxyCreator定义beanName为
    		// org.Springframework.aop.configinternalAutoProxyCreator的BeanDefinition
            BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
            // 1.2. 对proxy-target-class以及expose-proxy属性的处理
            useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
            // 1.3. 注册组件并通知,便于监听器做进一步处理
            registerComponentIfNecessary(beanDefinition, parserContext);
        }
    
    // 2.1 真正注册AnnotationAwareAspectJAutoProxyCreator
    // AopConfigUtils
    @Nullable
        public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
        	// 对beanDefinition进行注册或者升级
            return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
        }
    // AopConfigUtils
     @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());
                    int requiredPriority = findPriorityForClass(cls);
                    if (currentPriority < requiredPriority) {
                        apcDefinition.setBeanClassName(cls.getName());
                    }
                }
    
                return null;
            } else {
            	// 容器中还不存在自动代理创建器,注册对应的beanDefinition
                RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
                beanDefinition.setSource(source);
                beanDefinition.getPropertyValues().add("order", -2147483648);
                beanDefinition.setRole(2);
                registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
                return beanDefinition;
            }
        }
    
    // 2.2. 对proxy-target-class以及expose-proxy属性设置到BeanDefinition

    在xml配置文件中对<aop:aspectj-autoproxy proxy-target-class = "true" expose-proxy = "true">或者<aop:config proxy-target-class = "true" expose-proxy = "true"> ... <aop:config> ,此处就是解析并给beanDefinition设置两个属性

    • proxy-target-class:默认Spring AOP使用JDK动态代理,给此属性设置为true表示强制使用Cglib动态代理,需要注意使用Cglib时候不能对final修饰的类代理和需要将Cglib的二进制包放在classpath下面
    • expose-proxy:主要是暴露动态代理上下文AopContext,使用AopContext.currentProxy()获得当前代理,以便解决同类内调用方法不走代理的情况(具体事例就是@Transcation注解使用时的一种情况)
    // AopNamespaceUtils
     private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
            if (sourceElement != null) {
                boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute("proxy-target-class"));
                if (proxyTargetClass) {
                    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                }
    
                boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute("expose-proxy"));
                if (exposeProxy) {
                    AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
                }
            }
    
        }
    // AopConfigUtils
    public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
            if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
                BeanDefinition definition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
                definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
            }
    
        }
    
        public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
            if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
                BeanDefinition definition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
                definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
            }
    
        }
    
    

    二、AnnotationAwareAspectJAutoProxyCreator解析@AspectJ

    1. Spring AOP的时机

    // 不存在循环依赖AOP的时机postProcessAfterInitialization()

    AnnotationAwareAspectJAutoProxyCreator实现AbstractAutoProxyCreatorlei完成AOP的核心功能。
    在这里插入图片描述

    他实现BeanProcessor接口,因此无循环依赖的情况下对Bean的具体AOP的逻辑在父类AbstractAutoProxyCreator的postProcessAfterInitalization()方法中

    // 存在循环依赖AOP时机getEarlyBeanReference()

    首先需要明白解决单例bean循环依赖的关键就是在三级缓存中暴露ObjectFactory

    addSingletonFactory(beanName, new ObjectFactory<Object>() {
        @Override
        public Object getObject() throws BeansException {
            return getEarlyBeanReference(beanName, mbd, bean);
        }
    });
    

    有循环依赖的情况并且A不需要AOP增强的情况,如A和B互相依赖,并且都是单例的,会使用三级缓存解决循环依赖,大致过程

    1. A在实例化完成之后会进行属性填充,此时会将ObjectFactory放到三级缓存,然后进行populateBean()、initializationBean()、postProcessAfterInitialization()等。

    2. A在populateBean()时发现A依赖B,就会转去B的getBean()…然后就是B的一系列流程…直到B需要populateBean()的时候发现需要A,会从三级缓存中的ObjectFactory实际调用AbstractAutoProxyCreator重写的getEarlyBeanReference()拿到半实例的A,假如A不需要AOP,那么完全没问题在getEarlyBeanReference()直接返回A即可,B此时就会拿到半实例不需要增强的A完成初始化,然后初始化好的B被移动到一级缓存

    3. 然后转回A的populateBean(),在一级缓存中拿到初始化好的B,然后完成后续初始化。

    但是有循环依赖并且A需要AOP增强的时候,发挥关键的就是暴露在三级缓存中的getEarlyBeanReference()了。

    1. 主要逻辑在AbstractAutoProxyCreator重写的getEarlyBeanReference(),当B需要从三级缓存中拿到半实例的A时候,这个时候getEarlyBeanReference()就会被调用,会判断A是否需要增强。

    2. 当A需要增强,此时B需要填充A增强的代理对象,那么AOP的时机不能像往常一样放到postProcessAfterInitiallization()中了,而是在这里直接进行AOP返回给B的是A的增强代理实例,然后放到earlyProxyReferences, 标记这个bean已经被early处理过了,避免在postProcessAfterInitiallization()中重复处理

    回顾往期博客《Spring源码深度解析 郝佳 第2版》bean的加载、循环依赖的解决,会发现如果B想要从三级缓存拿到代理的A,会调用getEarlyBeanReference()会进入SmartInstantiantionAwareBeanPostProcess的getEarlyBeanReference(),然后返回exposedObject并移动到二级缓存。就是在这里完成的提前AOP。
    在这里插入图片描述
    而看关键SmartInstantiationAwareBeanPostProcess的getEarlyBeanReference()核心实现

    // SmartInstantiationAwareBeanPostProcess是一个接口,默认方法实现
    default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
            return bean;
        }
    // 查看他的实现类,发现真正的方法在AbstractAutoProxyCreator类重写实现
    // AbstractAutoProxyCreator
    public Object getEarlyBeanReference(Object bean, String beanName) {
            Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
            this.earlyProxyReferences.put(cacheKey, bean);
            return this.wrapIfNecessary(bean, beanName, cacheKey);
        }
    

    于是有转到和AbstractAutoProxyCreator类

    在这里插入图片描述

    2. AbstractAutoProxyCreator核心类实现AOP

    // 提前AOP的情况

    
    
     private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap(16);// 主要是循环依赖下的AOP解决
     // aop相关的代理,相当于会把bean替换成一个代理类。那看下循环依赖的时候怎么处理
     // 主要逻辑在AbstractAutoProxyCreator中
    // 实现了getEarlyBeanReference,会在这里直接返回一个代理类
    // 然后放到earlyProxyReferences, 标记这个bean已经被early处理过了
    // 
    public Object getEarlyBeanReference(Object bean, String beanName) {
            Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
            this.earlyProxyReferences.put(cacheKey, bean);
            return this.wrapIfNecessary(bean, beanName, cacheKey);
        }
    

    // 正常AOP的情况

     @Nullable
     private BeanFactory beanFactory; // 成员变量
    
    
    
    private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap(256); // 记录那些bean需要增强
    
    // AbstractAutoProxyCreator重写了BeanPostProcessor的postProcessAfterInitialization()等方法
     public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
            if (bean != null) {
            	// 1. 根据给定的class和beanName构造一个key,格式beanClassName_beanName
                Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
                // 主要处理循环依赖情况下提前AOP和现在和AOP重复
                if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                	// 2. 适合被代理,需要封装成指定bean
                    return this.wrapIfNecessary(bean, beanName, cacheKey);
                }
            }
    
            return bean;
        }
    
    

    // 2. wrapIfNecessary

    如果适合被代理,需要封装成指定bean,放到adviserBeans

    // AbstractAutoProxyCreator 
    //  适合被代理,需要封装成指定bean
    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    		// 已经处理过了
            if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
                return bean;
                
            } 
            // 无需增强
            else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
                return bean;
            } 
    		// 基础设施类和指定的类跳过不增强
    		// 需要增强的类
    		else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
    			
    			// 2.1 如果存在增强方法需要创建代理,如@AspectJ注解配置的切面、通知
                Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
                
                if (specificInterceptors != DO_NOT_PROXY) {
                    this.advisedBeans.put(cacheKey, Boolean.TRUE);
                    // 2.2 增强方法不为空,需要创建代理执行增强方法
                    Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                    
                    this.proxyTypes.put(cacheKey, proxy.getClass());
                    return proxy;
                } else {
                    this.advisedBeans.put(cacheKey, Boolean.FALSE);
                    return bean;
                }
            } else {
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
        }
    
    // 2.1 getAdvicesAndAdvisorsForBean

    解析增强方法,如@AspectJ注解配置的切面、通知,然后找到该bean能运用的增强

    • // 找出所有的增强方法放到List
    • // 找出针对该bean的增强方法放到List
    // AbstractAutoProxyCreator 
    // 模板方法,由子类AbstractAdvisorAutoProxyCreator 重写
     @Nullable
        protected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> var1, String var2, @Nullable TargetSource var3) throws BeansException;
    
    // AbstractAdvisorAutoProxyCreator 
     @Nullable
        protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
        	// 调用 findEligibleAdvisors
            List<Advisor> advisors = this.findEligibleAdvisors(beanClass, beanName);
            return advisors.isEmpty() ? DO_NOT_PROXY : advisors.toArray();
        }
    // AbstractAdvisorAutoProxyCreator的findEligibleAdvisors查找所有增强方法或者增强器
     protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
     
     		// 2.1.1查找所有的增强方法,因为分析的使用注解@AspectJ配置的AOP,
     		// 因此查找方法其实是子类AnnotationAwareAspectJAutoProxyCreator类
     		
            List<Advisor> candidateAdvisors = this.findCandidateAdvisors();
            // 2.1.2针对该bean的增强方法
            List<Advisor> eligibleAdvisors = this.findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
            
            this.extendAdvisors(eligibleAdvisors);
            if (!eligibleAdvisors.isEmpty()) {
                eligibleAdvisors = this.sortAdvisors(eligibleAdvisors);
            }
    
            return eligibleAdvisors;
        }
    
    // 2.1.1查找所有的增强方法,因为分析的使用注解@AspectJ配置的AOP, 因此查找方法其实是子类AnnotationAwareAspectJAutoProxyCreator类
    // AbstractAdvisorAutoProxyCreator 
    protected List<Advisor> findCandidateAdvisors() {
            Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
            return this.advisorRetrievalHelper.findAdvisorBeans();
        }
    
    // AnnotationAwareAspectJAutoProxyCreator
    protected List<Advisor> findCandidateAdvisors() {
    		// 父类查找
            List<Advisor> advisors = super.findCandidateAdvisors();
            if (this.aspectJAdvisorsBuilder != null) {
            	// 核心实现 BeanFactoryAspectJAdvisorsBuilder
            
                advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
            }
    
            return advisors;
        }
    

    // 核心实现 BeanFactoryAspectJAdvisorsBuilder.buildAspectJAdvisors()

    1. 获取所有注册在beanFactory的beanName
    2. 遍历所有beanName,找出@AspectJ标注的类,然后 就是最复杂的地方,委托给AspectJAdvisorFactory接口的实现类ReflectiveAspectJAdvisorFactory的getAdvisors方法
    3. 对于切面类增强方法提取
    4. 将提取结果加入缓存
    // BeanFactoryAspectJAdvisorsBuilder
    public List<Advisor> buildAspectJAdvisors() {
            List<String> aspectNames = this.aspectBeanNames;
            if (aspectNames == null) {
                synchronized(this) {
                    aspectNames = this.aspectBeanNames;
                    if (aspectNames == null) {
                        List<Advisor> advisors = new ArrayList();
                        List<String> aspectNames = new ArrayList();
                        String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
                        String[] var18 = beanNames;
                        int var19 = beanNames.length;
    
                        for(int var7 = 0; var7 < var19; ++var7) {
                            String beanName = var18[var7];
                            if (this.isEligibleBean(beanName)) {
                                Class<?> beanType = this.beanFactory.getType(beanName, false);
                                // 对标注@AspectJ的切面解析
                                if (beanType != null && this.advisorFactory.isAspect(beanType)) {
                                    aspectNames.add(beanName);
                                    AspectMetadata amd = new AspectMetadata(beanType, beanName);
                                    if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                                        MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                                        // 最复杂的地方,委托给AspectJAdvisorFactory接口的实现类ReflectiveAspectJAdvisorFactory的getAdvisors方法
                                        List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                                        if (this.beanFactory.isSingleton(beanName)) {
                                        	// 加入缓存
                                            this.advisorsCache.put(beanName, classAdvisors);
                                        } else {
                                            this.aspectFactoryCache.put(beanName, factory);
                                        }
    
                                        advisors.addAll(classAdvisors);
                                    } else {
                                        if (this.beanFactory.isSingleton(beanName)) {
                                            throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton");
                                        }
    
                                        MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                                        this.aspectFactoryCache.put(beanName, factory);
                                        advisors.addAll(this.advisorFactory.getAdvisors(factory));
                                    }
                                }
                            }
                        }
    
                        this.aspectBeanNames = aspectNames;
                        return advisors;
                    }
                }
            }
    
            if (aspectNames.isEmpty()) {
                return Collections.emptyList();
            } else {
                List<Advisor> advisors = new ArrayList();
                Iterator var3 = aspectNames.iterator();
    
                while(var3.hasNext()) {
                    String aspectName = (String)var3.next();
                    List<Advisor> cachedAdvisors = (List)this.advisorsCache.get(aspectName);
                    if (cachedAdvisors != null) {
                        advisors.addAll(cachedAdvisors);
                    } else {
                        MetadataAwareAspectInstanceFactory factory = (MetadataAwareAspectInstanceFactory)this.aspectFactoryCache.get(aspectName);
                        advisors.addAll(this.advisorFactory.getAdvisors(factory));
                    }
                }
    
                return advisors;
            }
        }
    

    // 获取切面的增强方法是最复杂的地方,委托给AspectJAdvisorFactory接口的实现类ReflectiveAspectJAdvisorFactory的getAdvisors方法
    在这里插入图片描述

    public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    		// 标记为@AspectJ的切面类
            Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
            String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
            this.validate(aspectClass);
            
            MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
            List<Advisor> advisors = new ArrayList();
            // 1.  获取切面每个方法
            Iterator var6 = this.getAdvisorMethods(aspectClass).iterator();
    
            while(var6.hasNext()) {
                Method method = (Method)var6.next();
                // 2.  对每个方法解析
                Advisor advisor = this.getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
                if (advisor != null) {
                    advisors.add(advisor);
                }
            }
    
            if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
                Advisor instantiationAdvisor = new ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
                // 3.  配置了增强延迟初始化,需要在在首部加上同步增强实例化加载器
                advisors.add(0, instantiationAdvisor);
            }
    
            Field[] var12 = aspectClass.getDeclaredFields();
            int var13 = var12.length;
    
            for(int var14 = 0; var14 < var13; ++var14) {
                Field field = var12[var14];
                Advisor advisor = this.getDeclareParentsAdvisor(field);
                if (advisor != null) {
                    advisors.add(advisor);
                }
            }
    
            return advisors;
        }
    // 1. 获取切面每个方法
    private List<Method> getAdvisorMethods(Class<?> aspectClass) {
            List<Method> methods = new ArrayList();
            ReflectionUtils.doWithMethods(aspectClass, (method) -> {
                if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
                    methods.add(method);
                }
    
            }, ReflectionUtils.USER_DECLARED_METHODS);
            if (methods.size() > 1) {
                methods.sort(METHOD_COMPARATOR);
            }
    
            return methods;
        }
    
    // 2. 调用解析每个方法以及增强注解
    
    @Nullable
        public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) {
            this.validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
            // 2.1  解析PointCut切点
            AspectJExpressionPointcut expressionPointcut = this.getPointcut(candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
            // 切点表达式封装为 InstantiationModelAwarePointcutAdvisorImpl
            return expressionPointcut == null ? null : new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod, this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
        }
    
    // 2.1 解析PointCut切点表达式,封装到 InstantiationModelAwarePointcutAdvisorImpl
    @Nullable
        private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
            AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
            if (aspectJAnnotation == null) {
                return null;
            } else {
                AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class[0]);
                ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
                if (this.beanFactory != null) {
                    ajexp.setBeanFactory(this.beanFactory);
                }
    
                return ajexp;
            }
        }
        // 2.2. 调用解析每个方法以及增强注解
    @Nullable
        public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
            Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
            this.validate(candidateAspectClass);
            // 获取方法上的注解
            AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
            if (aspectJAnnotation == null) {
                return null;
            } else if (!this.isAspect(candidateAspectClass)) {
                throw new AopConfigException("Advice must be declared inside an aspect type: Offending method '" + candidateAdviceMethod + "' in class [" + candidateAspectClass.getName() + "]");
            } else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Found AspectJ method: " + candidateAdviceMethod);
                }
    
                Object springAdvice;
                // 根据注解类型解析
                switch(aspectJAnnotation.getAnnotationType()) {
                // Pointcut切点不解析
                case AtPointcut:
                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
                    }
    
                    return null;
                case AtAround:
                    springAdvice = new AspectJAroundAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    break;
                case AtBefore:
                    springAdvice = new AspectJMethodBeforeAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    break;
                case AtAfter:
                    springAdvice = new AspectJAfterAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    break;
                case AtAfterReturning:
                    springAdvice = new AspectJAfterReturningAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    AfterReturning afterReturningAnnotation = (AfterReturning)aspectJAnnotation.getAnnotation();
                    if (StringUtils.hasText(afterReturningAnnotation.returning())) {
                        ((AbstractAspectJAdvice)springAdvice).setReturningName(afterReturningAnnotation.returning());
                    }
                    break;
                case AtAfterThrowing:
                    springAdvice = new AspectJAfterThrowingAdvice(candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
                    AfterThrowing afterThrowingAnnotation = (AfterThrowing)aspectJAnnotation.getAnnotation();
                    if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
                        ((AbstractAspectJAdvice)springAdvice).setThrowingName(afterThrowingAnnotation.throwing());
                    }
                    break;
                default:
                    throw new UnsupportedOperationException("Unsupported advice type on method: " + candidateAdviceMethod);
                }
    
                ((AbstractAspectJAdvice)springAdvice).setAspectName(aspectName);
                ((AbstractAspectJAdvice)springAdvice).setDeclarationOrder(declarationOrder);
                String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
                if (argNames != null) {
                    ((AbstractAspectJAdvice)springAdvice).setArgumentNamesFromStringArray(argNames);
                }
    
                ((AbstractAspectJAdvice)springAdvice).calculateArgumentBindings();
                return (Advice)springAdvice;
            }
        }
    

    可以看出Spring会对不同注解的方法生成不同的增强器如AspectJAroundAdvice、AspectJAfterReturningAdvice等

    在这里插入图片描述

    在这里插入图片描述

    以@Before注解为例
    • 在拦截链中放置MethodBeforeAdviceInterceptor ,MethodBeforeAdviceInterceptor 完成了增强逻辑
    • 在MethodBeforeAdviceInterceptor 放置AspectJMethodBeforeAdvice
    • 在调用invoke方法的时候串联调用,// 调用AspectJMethodBeforeAdvice的前置增强方法然后才是 // 方法执行
    public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
        private final MethodBeforeAdvice advice;
    
        public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
            Assert.notNull(advice, "Advice must not be null");
            this.advice = advice;
        }
    	// @Before注解增强逻辑
        public Object invoke(MethodInvocation mi) throws Throwable {
        	// 调用AspectJMethodBeforeAdvice的方法前置增强
            this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
            // 方法执行
            return mi.proceed();
        }
    }
    
    
    
    
    // AspectJMethodBeforeAdvice
     public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
     		// 激活增强方法
            this.invokeAdviceMethod(this.getJoinPointMatch(), (Object)null, (Throwable)null);
        }
    // AbstractAspectJAdvice
    protected Object invokeAdviceMethod(@Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex) throws Throwable {
    		// 重载
            return this.invokeAdviceMethodWithGivenArgs(this.argBinding(this.getJoinPoint(), jpMatch, returnValue, ex));
        }
    // AbstractAspectJAdvice
    
    protected transient Method aspectJAdviceMethod; // 正是对前置增强的方法
    
    protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
            Object[] actualArgs = args;
            if (this.aspectJAdviceMethod.getParameterCount() == 0) {
                actualArgs = null;
            }
    
            try {
                ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
                // 真正激活,调用的Method的invoke
                return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
            } catch (IllegalArgumentException var4) {
                throw new AopInvocationException("Mismatch on arguments to advice method [" + this.aspectJAdviceMethod + "]; pointcut expression [" + this.pointcut.getPointcutExpression() + "]", var4);
            } catch (InvocationTargetException var5) {
                throw var5.getTargetException();
            }
        }
    
    以@After注解为例

    和前置不同,直接在拦截器链中使用了中间的AspectJAfterAdvice

    public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice, Serializable {
        public AspectJAfterAdvice(Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
            super(aspectJBeforeAdviceMethod, pointcut, aif);
        }
    
        public Object invoke(MethodInvocation mi) throws Throwable {
            Object var2;
            try {
                var2 = mi.proceed();
            } finally {
            	// 激活增强方法
                this.invokeAdviceMethod(this.getJoinPointMatch(), (Object)null, (Throwable)null);
            }
    
            return var2;
        }
    
        public boolean isBeforeAdvice() {
            return false;
        }
    
        public boolean isAfterAdvice() {
            return true;
        }
    }
    
    
    // 2.1.2 findAdvisorsThatCanApply

    之前找到所有的增强之后封装为XxxAdvice,然后就是遍历找出该bean能运用的放到List集合

    protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
            ProxyCreationContext.setCurrentProxiedBeanName(beanName);
    
            List var4;
            try {
            	// 委托
                var4 = AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
            } finally {
                ProxyCreationContext.setCurrentProxiedBeanName((String)null);
            }
    
            return var4;
        }
     
     // AopUtils
     public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
            if (candidateAdvisors.isEmpty()) {
                return candidateAdvisors;
            } else {
                List<Advisor> eligibleAdvisors = new ArrayList();
                Iterator var3 = candidateAdvisors.iterator();
    
                while(var3.hasNext()) {
                    Advisor candidate = (Advisor)var3.next();
                    // 引介增强
                    if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
                        eligibleAdvisors.add(candidate);
                    }
                }
    
                boolean hasIntroductions = !eligibleAdvisors.isEmpty();
                Iterator var7 = candidateAdvisors.iterator();
    
                while(var7.hasNext()) {
                    Advisor candidate = (Advisor)var7.next();
                    // 普通bean的增强
                    if (!(candidate instanceof IntroductionAdvisor) && canApply(candidate, clazz, hasIntroductions)) {
                        eligibleAdvisors.add(candidate);
                    }
                }
    
                return eligibleAdvisors;
            }
        }
    // canApply
    public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
            if (advisor instanceof IntroductionAdvisor) {
                return ((IntroductionAdvisor)advisor).getClassFilter().matches(targetClass);
            } else if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pca = (PointcutAdvisor)advisor;
                return canApply(pca.getPointcut(), targetClass, hasIntroductions);
            } else {
                return true;
            }
        }
    
    // 2.2 ProxyFactory内部封装advisors然后createProxy创建代理

    如果可以运用的增强方法不为空,需要为该bean创建代理执行增强方法,

    // 2.2.1 设置beanDefinition原来的属性

    // 2.2.2 实例化proxyFactory ,内部封装了getProxy等方法,需要根据下面的配置进去的属性获取代理对象

    // 2.2.3 获取当前bean的属性

    // 2.2.4 设置属性,根据我们配置的proxy-target-class属性,选用JDK还是Cglib动态代理时需要用到保存在ProxyFactory中的该属性

    // 2.2.5 加入能用的增强器,复杂

    // 2.2.6 设置被代理类

    // 2.2.7 定制代理

    // 2.2.8 委托ProxyFactory获取代理对象,复杂

    // AbstractAutoProxyCreator 
     protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
     		// 2.2.1 设置beanDefinition原来的属性
            if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
            
                AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
            }
    		// 2.2.2 实例化proxyFactory 封装了getProxy等方法,需要根据下面的配置进去的属性获取代理对象
            ProxyFactory proxyFactory = new ProxyFactory();
            // 2.2.3 获取当前bean的属性
            proxyFactory.copyFrom(this);
            // 2.2.4 设置属性,根据我们配置的proxy-target-class属性
            if (!proxyFactory.isProxyTargetClass()) {
                if (this.shouldProxyTargetClass(beanClass, beanName)) {
                	// Cglib动态代理
                    proxyFactory.setProxyTargetClass(true);
                } else {
                	// JDK动态代理
                    this.evaluateProxyInterfaces(beanClass, proxyFactory);
                }
            }
    		// 2.2.5 加入能用的增强器
            Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
            proxyFactory.addAdvisors(advisors);
            // 2.2.6 设置被代理类
            proxyFactory.setTargetSource(targetSource);
            // 2.2.7 定制代理
            this.customizeProxyFactory(proxyFactory);
            proxyFactory.setFrozen(this.freezeProxy);
            if (this.advisorsPreFiltered()) {
                proxyFactory.setPreFiltered(true);
            }
    		// 2.2.8 委托ProxyFactory获取代理对象
            return proxyFactory.getProxy(this.getProxyClassLoader());
        }
    
    // 2.2.5 buildAdvisors封装能用的增强器

    因为Spring涉及了过多的拦截器、增强器、增强方法等方式对逻辑进行增强,所以非常有必要封装成为Advisor来进行代理的创建

    简单来说:Advice 是通知,Advisor 是增强器。使用 spring aop 要定义切面,切面里面有 通知 和 切点。

    在项目启动的过程中,项目中的所有切面会被 AnnotationAwareAspectJAutoProxyCreator 解析,它会找到切面中的每一个通知以及通知对应的切点,拿这二者构建一个新的对象,这个对象就是 Advisor。最后将所有解析得到的增强器注入到容器中。

    protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
            Advisor[] commonInterceptors = this.resolveInterceptorNames();
            List<Object> allInterceptors = new ArrayList();
            if (specificInterceptors != null) {
                allInterceptors.addAll(Arrays.asList(specificInterceptors));
                if (commonInterceptors.length > 0) {
                    if (this.applyCommonInterceptorsFirst) {
                        allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
                    } else {
                        allInterceptors.addAll(Arrays.asList(commonInterceptors));
                    }
                }
            }
    
            int i;
            if (this.logger.isTraceEnabled()) {
                int nrOfCommonInterceptors = commonInterceptors.length;
                i = specificInterceptors != null ? specificInterceptors.length : 0;
                this.logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors + " common interceptors and " + i + " specific interceptors");
            }
    
            Advisor[] advisors = new Advisor[allInterceptors.size()];
    
            for(i = 0; i < allInterceptors.size(); ++i) {
            	// 封装
                advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
            }
    
            return advisors;
        }
    //DefaultAdvisorAdapterRegistry
    
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
            if (adviceObject instanceof Advisor) {
                return (Advisor)adviceObject;
            } else if (!(adviceObject instanceof Advice)) {
                throw new UnknownAdviceTypeException(adviceObject);
            } else {
                Advice advice = (Advice)adviceObject;
                if (advice instanceof MethodInterceptor) {
                	// MethodInterceptor 类型使用 DefaultPointcutAdvisor封装
                    return new DefaultPointcutAdvisor(advice);
                } else {
                    Iterator var3 = this.adapters.iterator();
    
                    AdvisorAdapter adapter;
                    // 存在 AdvisorAdapter 也需要封装 DefaultPointcutAdvisor
                    do {
                        if (!var3.hasNext()) {
                            throw new UnknownAdviceTypeException(advice);
                        }
    
                        adapter = (AdvisorAdapter)var3.next();
                    } while(!adapter.supportsAdvice(advice));
    
                    return new DefaultPointcutAdvisor(advice);
                }
            }
        }
    
    // 2.2.8 委托ProxyFactory获取代理对象
    // ProxyFactory
    public Object getProxy(@Nullable ClassLoader classLoader) {
            return this.createAopProxy().getProxy(classLoader);
        }
    // ProxyCreatorSupport
     protected final synchronized AopProxy createAopProxy() {
            if (!this.active) {
                this.activate();
            }
    		// 委托AopProxyFactory接口的createProxy()
            return this.getAopProxyFactory().createAopProxy(this);
        }
    // DefaultAopProxyFactory 实现AopProxyFactory
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
            if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
                return new JdkDynamicAopProxy(config);
            } else {
                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.");
                } else {
                	// 选用Cglib还是JDK动态代理
                    return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
                }
            }
        }
    

    在分析JDK动态代理和Cglib动态代理之前,先看看如何使用

    1. 使用JDK动态代理:需要被代理类实现某个接口
      • 创建处理器MyInvocationHandler实现InvocationHandler接口,重写invoke、getProxy()方法(也可以放到外面直接Proxy.newProxyInstance()获得代理对象),然后构造方法传入被代理对象
      • 创建被代理对象实例,传入MyInvocationHandler实例
      • 通过MyInvocationHandler.getProxy()获得代理对象proxy
      • 测试 proxy.test()
    2. 使用Cglib动态代理:要求被代理类不能被final修饰
      • 创建处理器MyMethodInterceptor实现MethodInterceptor,重写intercepter()方法
      • 测试,创建Enhancer实例
        • 调用setSuperClass()设置被代理类Class,
        • 调用setCallback()传入MyMethodInterceptor实例,
        • 调用create()方法创建代理对象,然后调用方法test()

    // 3. JdkDynamicAopProxy处理器分析

    可以看到// final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable 它也实现 InvocationHandler

    关键点就是invoke、getProxy方法

      public Object getProxy() {
            return this.getProxy(ClassUtils.getDefaultClassLoader());
        }
    
        public Object getProxy(@Nullable ClassLoader classLoader) {
            if (logger.isTraceEnabled()) {
                logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
            }
    
            Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
            this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
            return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
        }
    

    invoke方法主要是创建了一个拦截器链,然后使用ReflectiveMethodInvocation封装,在他的proceed()方法实现拦截器的逐一调用
    在这里插入图片描述

     @Nullable
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object oldProxy = null;
            boolean setProxyContext = false;
            TargetSource targetSource = this.advised.targetSource;
            Object target = null;
    
            Object retVal;
            try {
                if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                    Boolean var18 = this.equals(args[0]);
                    return var18;
                }
    
                if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                    Integer var17 = this.hashCode();
                    return var17;
                }
    
                if (method.getDeclaringClass() == DecoratingProxy.class) {
                    Class var16 = AopProxyUtils.ultimateTargetClass(this.advised);
                    return var16;
                }
    
                if (this.advised.opaque || !method.getDeclaringClass().isInterface() || !method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // 自身类.class.isAssignableFrom(自身类或者子类.class) 返回true,其他情况返回false
                    if (this.advised.exposeProxy) {
                        oldProxy = AopContext.setCurrentProxy(proxy);
                        setProxyContext = true;
                    }
    
                    target = targetSource.getTarget();
                    Class<?> targetClass = target != null ? target.getClass() : null;
                    // 拦截器链
                    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                    if (chain.isEmpty()) {
                    	// 没有发现拦截器链,直接调用切点方法
                        Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                    } else {
                        MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                        // 剩下的拦截器链执行
                        retVal = invocation.proceed();
                    }
    
                    Class<?> returnType = method.getReturnType();
                    if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                        retVal = proxy;
                    } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                        throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
                    }
    
                    Object var12 = retVal;
                    return var12;
                }
    
                retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            } finally {
                if (target != null && !targetSource.isStatic()) {
                    targetSource.releaseTarget(target);
                }
    
                if (setProxyContext) {
                    AopContext.setCurrentProxy(oldProxy);
                }
    
            }
    
            return retVal;
        }
    
    // ReflectiveMethodInvocation
     @Nullable
        public Object proceed() throws Throwable {
            if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            	// 切点
                return this.invokeJoinpoint();
            } else {
            	// 拦截器链
                Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
                if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                    InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                    Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();
                    return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
                } else {
                    return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
                }
            }
        }
    

    // 4. Cglib2AopProxy处理器分析

    首先需要导入依赖

    <dependency>
    	<groupId>springframework</groupId>
    	<artifactId>spring-aop</artifactId>
    	<version>1.2.5</version>
    </dependency>
    

    getProxy方法

    public Object getProxy() {
            return this.getProxy((ClassLoader)null);
        }
    
        public Object getProxy(ClassLoader classLoader) {
            if (logger.isDebugEnabled()) {
                Class targetClass = this.advised.getTargetSource().getTargetClass();
                logger.debug("Creating CGLIB2 proxy" + (targetClass != null ? " for [" + targetClass.getName() + "]" : ""));
            }
    
            Enhancer enhancer = new Enhancer();
    
            try {
                Class rootClass = this.advised.getTargetSource().getTargetClass();
                Class proxySuperClass = AopUtils.isCglibProxyClass(rootClass) ? rootClass.getSuperclass() : rootClass;
                this.validateClassIfNecessary(proxySuperClass);
                enhancer.setSuperclass(proxySuperClass);
                enhancer.setCallbackFilter(new Cglib2AopProxy.ProxyCallbackFilter(this.advised));
                enhancer.setStrategy(new UndeclaredThrowableStrategy(class$java$lang$reflect$UndeclaredThrowableException == null ? (class$java$lang$reflect$UndeclaredThrowableException = class$("java.lang.reflect.UndeclaredThrowableException")) : class$java$lang$reflect$UndeclaredThrowableException));
                enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
                Callback[] callbacks = this.getCallbacks(rootClass);
                enhancer.setCallbacks(callbacks);
                if (Cglib2AopProxy.CglibUtils.canSkipConstructorInterception()) {
                    enhancer.setInterceptDuringConstruction(false);
                }
    
                Class[] types = new Class[callbacks.length];
    
                for(int x = 0; x < types.length; ++x) {
                    types[x] = callbacks[x].getClass();
                }
    
                enhancer.setCallbackTypes(types);
                Object proxy;
                if (this.constructorArgs != null) {
                    proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
                } else {
                    proxy = enhancer.create();
                }
    
                return proxy;
            } catch (CodeGenerationException var8) {
                throw new AspectException("Couldn't generate CGLIB subclass of class '" + this.advised.getTargetSource().getTargetClass() + "': " + "Common causes of this problem include using a final class or a non-visible class", var8);
            } catch (IllegalArgumentException var9) {
                throw new AspectException("Couldn't generate CGLIB subclass of class '" + this.advised.getTargetSource().getTargetClass() + "': " + "Common causes of this problem include using a final class or a non-visible class", var9);
            } catch (Exception var10) {
                throw new AspectException("Unexpected AOP exception", var10);
            }
        }
    

    intercepter方法

    private class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
            private DynamicAdvisedInterceptor() {
            }
    
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                MethodInvocation invocation = null;
                Object oldProxy = null;
                boolean setProxyContext = false;
                Class targetClass = null;
                Object target = null;
    
                Object var12;
                try {
                    Object retVal = null;
                    if (Cglib2AopProxy.this.advised.exposeProxy) {
                        oldProxy = AopContext.setCurrentProxy(proxy);
                        setProxyContext = true;
                    }
    
                    target = this.getTarget();
                    if (target != null) {
                        targetClass = target.getClass();
                    }
    
                    List chain = Cglib2AopProxy.this.advised.getAdvisorChainFactory().getInterceptorsAndDynamicInterceptionAdvice(Cglib2AopProxy.this.advised, proxy, method, targetClass);
                    if (chain.isEmpty()) {
                        retVal = methodProxy.invoke(target, args);
                    } else {
                        invocation = new Cglib2AopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy);
                        retVal = invocation.proceed();
                    }
    
                    retVal = Cglib2AopProxy.massageReturnTypeIfNecessary(proxy, target, retVal);
                    var12 = retVal;
                } finally {
                    if (target != null) {
                        this.releaseTarget(target);
                    }
    
                    if (setProxyContext) {
                        AopContext.setCurrentProxy(oldProxy);
                    }
    
                }
    
                return var12;
            }
    
            public int hashCode() {
                return Cglib2AopProxy.this.advised.hashCode();
            }
    
            protected Object getTarget() throws Exception {
                return Cglib2AopProxy.this.advised.getTargetSource().getTarget();
            }
    
            protected void releaseTarget(Object target) throws Exception {
                Cglib2AopProxy.this.advised.getTargetSource().releaseTarget(target);
            }
        }
    

    三、AspectJ动态织入

    AspectJ 的底层技术是 静态代理 ,主要是在虚拟机启动的时候通过改变目标对象字节码的方式来完成对目标对象的增强,它比动态代理有更高的效率,因为在动态代理调用过程中,还需要一个动态创建代理类并代理目标对象的步骤,而静态代理是在启动时完成了字节码增强,当系统调用目标类和正常的类无差别,所以效率上会相对高一些。

    Aspect是实现AOP编程的一种具体实现

    • 编译时织入,利用ajc编译器替代javac编译器,直接将源文件(java或者aspect文件)编译成class文件并将切面织入进代码。
    • 编译后织入,利用ajc编译器向javac编译期编译后的class文件或jar文件织入切面代码。
    • 加载时织入(LTW),不使用ajc编译器,利用aspectjweaver.jar工具,使用java agent代理在类加载期将切面织入进代码。

    前两种织入方法都依赖于ajc的编译工具,LTW却通过java agent机制在内存中操作类文件,可以不需要ajc的支持做到 动态织入

    不过,这里有一个挺有意思的问题,我们知道编译期一定会编译AnnoAspect类,那么这时候通过切面语法我们就可以找到他要处理的App类,这大概就是编译阶段织入的大概流程。

    但是如果在类加载期处理的话,当类加载到App类的时候,我们并不知道这个类需要被AnnoAspect处理。。。因此为了实现LTW,我们肯定要有个配置文件,来告诉类加载器,某某某切面需要优先考虑,他们很可能会影响其他的类。为了实现LTW,我们需要在资源目录下配置META-INF/aop.xml文件,来告知类加载器我们当前注册的切面。

    比如说Load-Time Weaving的方式 还 需要额外的jar包 spring-instrument.jar。
    当然,无论是使用spring aop还是 aspectj都需要aspectjweaver.jar spring-aop.jar这两个jar包。

    参考:https://blog.csdn.net/whatigame/article/details/103173308

    使用步骤

    • 在xml配置文件中加上<aop:aspect-autoproxy> <context:load-time-weaver>开启Load-Time Weaving开关
    • 在class路径下新建META-INF文件夹,文件夹创建aop.xml文件,里面配置<aspect>、 <weaver>、<aspects>主要是告诉AspectJ哪些包进行织入,并使用哪些增强器
    • 加入启动参数,也就是应用指定的jar包
    • 测试
    展开全文
  • 绝对没有代码生成,以及对 XML 没有配置要求 首先搭建一个 maven 工程, pom 如下: 然后建立一个 controller 类 最后再加入启动整个项目的 main 函数 最后启动main函数并在浏览器中输入localhost:8080 第一个 ...

    Spring Boot 特点如下:
    创建独立的 Spring 应用程序;
    嵌入的 Tomcat ,无须部署 WAR 文件;
    简化 Maven 配置;
    自动配置 Spring;
    提供生产就绪型功能,如指标、健康检查和外部配置;
    绝对没有代码生成,以及对 XML 没有配置要求

    首先搭建一个 maven 工程, pom 如下:
    在这里插入图片描述
    在这里插入图片描述
    然后建立一个 controller 类
    在这里插入图片描述
    最后再加入启动整个项目的 main 函数
    在这里插入图片描述
    最后启动main函数并在浏览器中输入localhost:8080
    在这里插入图片描述

    第一个 Starter
    spring starter 的出现,可以让模块开发更加独立化,相互间依赖更加松散以及可以更加方便地集成
    在这里插入图片描述

    另建一个 maven 工程 pom 如下
    在这里插入图片描述
    在这里插入图片描述
    然后定义一个接口,可以认为它是当前独立业务开发模块对外暴露的可以直接调用的
    接口,如下:
    在这里插入图片描述
    对这个接口做一个简单的实现,返回 hello 字符串:
    在这里插入图片描述
    继续追加代码,添加自动配置项:
    在这里插入图片描述
    最后一步,声明这个配置文件的路径,在 Spring 的跟路径下建立 META-INF/spring.factories 文件 ,并声明配置项路

    在这里插入图片描述
    修改 Web 工程,加入依赖
    在这里插入图片描述
    更改 Controller 逻辑,将模块的逻辑引入
    在这里插入图片描述
    在这里插入图片描述
    刚才开发的 Starter 非常的方便 除了在 pom 中引入依赖
    ,什么都不做就可以直接使用模块内部的接口注入
    在这里插入图片描述

    探索 SpringApplication 启动 Spring
    在这里插入图片描述
    当顺着 SpringApplication.run 方法进入的时候找到了 SpringApplication 的一个看似核心
    逻辑的方法
    在这里插入图片描述
    在这里插入图片描述
    关键字眼:
    在这里插入图片描述

    SpringContext 创建
    在这里插入图片描述
    这个函数似乎没有什么特别之处,元非就是实例化一个 ApplicationContext ,因为
    ApplicationContext 是 Spring 存在的基础 而对应的 SpringContext 候选类如下:
    在这里插入图片描述

    bean 的加载
    继续返回追踪 prepareContext:
    在这里插入图片描述
    这里面的 load 函数是比较感兴趣的,代码如下:
    在这里插入图片描述

    Spring 扩展属性的加载
    在这里插入图片描述

    Spring Boot 的启动并不是想象的那么神秘,按照约定大于配置的原则,内
    置了 Spring 原有的启动类 并在启动的时候启动及刷新,仅此而已
    在这里插入图片描述

    Starter 自动化配置原理
    继续追查代码,看一看 SpringBootApplication 注解内容
    在这里插入图片描述
    注解具有传递性,EnableAutoConfiguration 是个非常特别的注解 ,它是 Spring Boot 的全局开关 ,如果把这个注解
    去掉,则一切 Starter 都会失效 ,这就是约定大于配置的潜规则 那么 Spring Boot 的核心很可
    能就藏在这个注解里面
    在这里插入图片描述
    在这里插入图片描述
    这个类中只有一个方法,那么只要
    看一看到底是哪个方法调用了它,就可以顺藤摸瓜找到最终的调用点
    在这里插入图片描述

    spring.factories 的加载
    顺着思路反向查找,看一看究竟是谁在哪里调用了 isEnabled 函数,强大的编译器很容易
    定位到了 AutoConfigurationImportSelector 类的方法
    在这里插入图片描述
    它是一个非常核心的函数,可以解释很多问题 在上面的函数中,有一个是比
    较关注的 getCandidateConfigurations 函数
    在这里插入图片描述
    继续进入 SpringFactoriesLoader 类:
    在这里插入图片描述
    上面函数中对 FACTORIES_RESOURCE_LOCATION 定义为:
    在这里插入图片描述
    Starter 的生效必须要依赖于配置 META-INF/spring. factories
    文件,因为在启动过程中有一个硬编码的逻辑就是会扫描各个包中的对应文件,并把配置捞取出来

    factories 调用时序图
    META-INF/spring.factories 中的配置文件是如何与 Spring 整合的呢?
    在这里插入图片描述
    ConfigurationClassPostProcessor 的继承关系
    在这里插入图片描述

    配置类的解析
    通过AutoConfigurationlmportSelector.selectlmports 方法返回后的配置类又是如何进一步处理的呢?
    抽出 ConfigurationClassParser 的 processDeferredlmportSelectors 方法代码查看
    在这里插入图片描述
    在这里插入图片描述
    的 imports 对应的就是定义的配置文件中配置的类,通过断点调试
    在这里插入图片描述
    也就是说在 Spring 启动的时候会扫描所有 JAR 中的 spring.factories 定义的类,而这些对于
    用户来说如果不是通过调试信息可能根本就感知不到
    那么也就是说,下面运行代码就是配置文件的处理逻辑:
    在这里插入图片描述
    时序图
    在这里插入图片描述
    ConfigurationClassPostProcessor 作为 Spring 扩展点是 Spring Boot 一系列功能的基础入口
    ConfigurationClassParser 作为解析职责的基本处理类,涵盖了各种解析处理的逻辑,
    如@Import 、@Bean 、@ImportResource 、@Property Source 、@ComponentScan 等注解
    都是在这个注解类中完成的,而这个类对外开放的函数入口就是 parse 方法 对应时
    序图中的步骤3
    在完成步骤 3 后,所有解析的结果已经通过 3.2.2 步骤放在了 parse 的 configurationClasses
    属性中,这时候对这个属性进行统一的 spring bean 硬编码注册,注册逻辑统一委托给
    ConfigurationClassBeanDefinitionReader ,对外的接口是 loadBeanDefinitions ,对应步
    骤4
    当然,在 parse 中的处理是最复杂的, parse 中首先会处理自己本身能扫描到的 bean 注
    册逻辑,然后才会处理 spring.factories 定义的配置 处理 spring. factories 定义的配置首
    先就是要加载配置类,这个时候 EnableAutoConfigurationlmportSelector 提供的
    selectlmports 就被派上用场了,它返回的配置类需要进行进一步解析,因为这些配置
    类中可能对应不同的类型,如@Import 、@Bean @lmportResource 、@PropertySource
    @ComponentScan ,而这些类型又有不同的处理逻辑,例如 ComponentScan ,就能
    猜到这里面除了解析外一定还会有逆归解析的处理逻辑,因为很有可能通过
    ComponentScan 又扫描出了另一个 ComponentScan 配置

    Componentscan 的切入点
    在这里插入图片描述
    在这里插入图片描述
    以上函数中传递过来的参数 ConfigurationClass configClass 就是 spring.factories 中定义的
    配置类 ,这里重点关注一下 ComponentScan 注解的实现逻辑, 首先通过代码
    在这里插入图片描述
    获取对应的注解配置信息 ,也就是对应的@ComponentScan( {”com.spring.study.module"})
    中最主要的扫描路径信息,然后委托给 ComponentScanAnnotationParser 的 parse 进一步扫描:
    在这里插入图片描述
    顺着思路继续跟进 parse 方法 ,这里面还会有一些额外的处理分支 ,顺着主流
    程一层一层跟进,直到进入一个核心解析类 ComponentScanAnnotationParser 的函数中
    在这里插入图片描述
    在这里插入图片描述
    上面提到的最为核心的解析工具类 ClassPathBeanDefinitionScanner 就是 Spring 原生的解
    析类,这是 Spring 核心解析类,它通过字节码扫描的方式,效率要 比通常我们用的反正机制效
    率要高很多,如果在日常工作中有扫描路径下类的需求,哪怕脱离了 Spring 环境也可以直
    接使用这个工具类

    Conditional 机制实现
    Conditional 使用
    Spring 提供了一个更通用的基于条件的 bean 的创建一一使用@Conditional 注解 @Conditional
    根据满足的某一个特定条件创建一个特定的 bean 比方说, 当某一个 JAR 包在一个类路径下
    的时候,会自动配置一个或多个 bean ;或者只有某个 bean 被创建后才会创建另外一个 bean
    总的来说,就是根据特定条件来控制 bean 的创建行为,这样可以利用这个特性进行一些
    自动的配置。

    在配置类中增加 Conditiona!OnProperty 注解:
    在这里插入图片描述
    上面的声明想要表达的逻辑是如果配置属性中显示的声明 study.enable=true ,则当前的整
    套体系才生效,可以进行验证
    在这里插入图片描述
    发现启动失败,而报错信息则是注入时找不到对应的 bean 这说明 Starter 中的 bean 并未
    生效 当加入 study.enabled=true 配置后
    在这里插入图片描述
    继续启动,发现启动成功
    在这里插入图片描述

    Conditional 原理
    如果想反推 ConditionalOnProperty 的实现机制,那么在代码中必然会存在
    ConditionalOnProperty.class 的调用,于是搜索 ConditionalOnProperty class
    在这里插入图片描述
    发现所有的调用都出现在一个类 OnPropertyCondition 中,于是进入这个类
    在这里插入图片描述
    OnPropertyCondition 类的 getMatchOutcome 方法如下:
    在这里插入图片描述
    在这里插入图片描述
    按照通常的设计,这里应该返回是否匹配的 boolean 值,但是现在却返回 ConditionOutcome
    这样一个对象,这是什么道理呢?看一下这个数据结构:
    在这里插入图片描述
    这里面除了大量的方法外有一个比较重要的属性字段,就是类型为 boolean 的 match 字段,
    根据直觉,大致可以断定这个属性很重要,再来看
    在这里插入图片描述
    对应的构造逻辑
    在这里插入图片描述
    以及
    在这里插入图片描述
    对应的构造逻辑:
    在这里插入图片描述
    差别仅仅是这个属性的初始化值,那么根据这个信息可以断定, getMatchOutcome 方法中
    noMatch 这个属性的逻辑一定是整个逻辑的核心
    重新再去分析 getMatchOutcome 函数中的逻辑:
    在这里插入图片描述
    这句代码是要扫描出 ConditionalOnProperty 的注解信息
    在这里插入图片描述
    通过 Debug 进一步确认:
    通过断点信息,可以看到 name 对应的 enabled 属性已经被读取
    那么 现在核心的验证逻辑就应该在 ConditionOutcome outcome = detennineOutcome
    ( annotationAttributes, context. getEnvironment())中了 顺着函数继续进行下一步探索:
    在这里插入图片描述
    在这里插入图片描述
    这个逻辑表明,不匹配有两种情况 missingProperties 对应属性缺失的情况;
    nonMatchingProperties 对应不匹配的情况 而这两个属性的初始化都在 spec.collectProperties
    (resolver, missingProperties, nonMatchingProperties )中,于是进入这个函数
    在这里插入图片描述
    在这里插入图片描述
    这个函数尝试使用 PropertyResolver 来验证对应的属性是
    否存在, 如果不存在则验证不通过,因为 PropertyResolver 中包含了所有的配置属性信息

    调用切入点
    那么现在的问题是 OnPropertyCondition. getMatchOutcome 方法是谁去调用的呢
    再从全局的角度来梳理下 Conditional 的实现逻辑
    在 3.2.1 processConfigurationClass 步骤中的主要逻辑是对即将解析的注解做预处理
    在这里插入图片描述
    通过分析代码定位到原来整个判断逻辑的切人点就是在 processConfigurationClass 中,代码如下:
    在这里插入图片描述
    代码的第一行就是整个 Conditional 逻辑生效的切人点,如果验证不通过则会直接忽略掉后
    面的解析逻辑,那么这个类的属性以及 componentScan 之类的配置也自然不会得到解析了 这
    个方法会拉取所有的 condition 属性, onConditionProperty 就是这里拉取的:
    在这里插入图片描述
    在这里插入图片描述
    这段方法里面有几个关键的地方
    condition 的获取
    通过代码 getConditionClasses(metadata)调用, 因为代码走到这里已经是对某一个特定类的
    解析, metadata 中包含了完整的配置类信息,只要通过 metadata. getAIIAnnotationAttributes
    (Conditional.class.getName(), true)即可获取,所以这一步的逻辑并不复杂
    condition 的运行匹配
    通过代码 condition.matches(this.context, metadata)调用,因为配置为@ConditionalOn
    Property(prefix = ”study ”, name = ”enabled ”, having Value =”true”)
    所以此时 condition 对应的运行态类为 OnPropertyCondition

    属性自动化配置实现
    示例
    对于下述注解 Spring Boot 会读取配置拼装成
    study.enabled 并作为 key ,然后尝试使用 PropertyResolver 来验证对应的属性是否存在,如果不
    存在则验证不通过, 自然也就不会继续后面的解析流程,因为 PropertyResolver 中包含了所有
    的配置属性信息
    在这里插入图片描述
    那么, PropertyResolver 又是如何被初始化的呢 同样,这一功能并不仅仅供 Spring 内部
    使用,在现在的 Spring 中也可以通过 Value 注解直接将属性赋值给类的变量 这两个问题
    都涉及 Spring 的属性处理逻辑 在研究它的属性处理逻辑前先体验一下通过 Value 注解注
    入属性的样例
    在这里插入图片描述
    在 studyweb 中的 application.properties 加入 study.testStr=this is testStr
    在这里插入图片描述
    运行后显示了配置的结果的属性,证明属性生效
    在这里插入图片描述

    原理
    首先定位关键字然后反推代码逻辑 通过搜索 Value.class 进行反推
    在这里插入图片描述
    找到了一个看起来像是调用点的地方,进入 QualifierAnnotationAutowireCandidateResolver
    这个类查看代码:
    在这里插入图片描述
    这是一个属性定义,那么进一步查看使用这个属性的地方:
    在这里插入图片描述
    然后设置断点来看一看系统在启动的时候是否在此停留,进而验证判断
    在这里插入图片描述
    尝试运行代码后程序在断点处停住,而尝试 evaluate 断点处的方法后能看到返回的
    就是在@Value(“$ {study.testStr”)中配置的值。因为属性注解已经找到,所以获取注解中的
    属性就比较简单了
    在这里插入图片描述
    现在要解决两个疑问
    表达式对应的值是在哪里被替换的?
    表达式替换后的值又是如何与原有的 bean 整合的
    带着这两个疑问,顺着调用栈继续找线索,发现当获取到 Value 的表达式属性后程序
    进入了 DefaultListableBeanFactory 类的 resolveEmbeddedValue 方法,并且在尝试 evaluate 后发
    现返回的值正是属性替换后的值
    在这里插入图片描述
    那么现在问题就比较清晰了 ,替换的逻辑一定是在 resolveEmbeddedValue 方法中
    在这里插入图片描述
    在这里插入图片描述
    通过代码逻辑看到 ,对于属性的解析已经委托给了 StringValueResolver 对应的实现类,
    接下来我们就要分析一下这个 StringValueResolver 是如何初始化的
    StringValueResolver 功能实现依赖 Spring 的切人点是 PropertySourcesPlaceholderConfigurer
    看一下它的依赖结构,它的关键是实现了 BeanFactoryPostProcessor 接口,
    从而利用实现对外扩展函数 postProcessBeanFactory 来进行对 Spring 的扩展
    在这里插入图片描述
    继续通过对 postProcessBeanFactory 函数人口的分析来详细了解 StringValueResolver 初始化
    的全过程,初始化逻辑以实现 PropertySourcesPlaceholderConfigurer 类的
    postProcessBeanFactory 函数作为入口
    在这里插入图片描述
    初始化 MutablePropertySources
    首先会通过 this.environment 来初始化 MutablePropertySources 这里面有几点要说明,
    environment 是 Spring 属性加载的基础,里面包含了 Spring 已经加载的各个属性,而之所以使
    用 MutabIePropertySources 封装,是因为 MutablePropertySources 还能实现单独加载自定义的额
    外属性的功能
    初始化 PropertySourcesPropertyResolver
    使用 PropertySourcesPropertyResolver 对 MutablePropertySources 的操作进行进一步封装,
    使得操作多个文件属性对外部不感知。当然 PropertySourcesPropertyResolver 还提供一个重要的
    功能就是对变量的解析,例如,它的初始化过程会包含这样的设置
    在这里插入图片描述
    StringValueResolver 初始化
    StringValueResolver 存在的目的主要是对解析逻辑的进一步封装,例如通过变量 ignore
    UnresolvablePlaceholders 来控制是否对变量做解析,它的初始化代码如下:
    在这里插入图片描述
    在上面的代码中 resolvePlaceholders 表示如果变量无法解析则 忽略 resolveRequired
    Placeholders 表示如果变量无法解析则抛异常
    StringValueResolver 注册
    最后将 StringValueResoIver 实例注册到单例 ConfigurableListableBeanFactory 中,也就是在
    真正解析变量时使用的 StringValueResolver 实例
    这里面有一个关键点,就是在初始化 MutablePropertySources 的时候依赖的一个变量
    environment Environment 是 Spring 所有配置文件转换为 KV 的基础,而后续的一系列操作都
    是在 environment 基础上做的进一步封装,那么就再来探索一下 environment 的实现路径
    在这里插入图片描述
    environment 初始化过程并不是之前通用的在 PostProcessor 类型的扩展口
    上做扩展, 而是通过 ConfigFileApplicationListener 监听机制完成 当然这里面要重点提到步骤4
    load 方法,它是整个流程的核心点:
    在这里插入图片描述
    在这里插入图片描述
    这里面涉及我们经常使用的 profile 机制 的实现, profile 机制是 Spring 提供的一个用来标
    明当前运行环境的注解 在正常开发的过程中经常遇到这样的问题,开发环境是一套环境,
    QA 测试是一套环境,线上部署又是一套环境 从开发到测试再到部署,会对程序中的配置修
    改多次,尤其是从 QA 到上线这个环节,经过 QA 测试的也不敢保证改了哪个配置之后能不能
    在线上运行
    为了解决上面的问题 一般会使用一种方法一一配置文件,然后通过不同的环境读取
    不同的配置文件 ,从而在不同的场景中运行我们的程序
    Spring 中的 profile 机制的作用就体现在这里 在 Spring 使用 DI 来依赖注入的时候,能
    够根据当前制定的运行环境来注入相应的 bean 最常见的就是使用不同的环境对应不同的数
    据源
    这个机制的实现就是在 load( location name, profile )这段代码中控制 ,这里只会加载当前设
    置 profile 对应的配置文件

    Tomcat 启动
    分析 Tomcat 嵌入原理首先要找到扩展入口,可以从启动信息开始
    在这里插入图片描述
    当然,为了整个说明的连贯性还是从入口处讲起
    在这里插入图片描述
    其中,下述代码就是默认配置
    在这里插入图片描述
    这也是 Web 扩展的关键
    在这里插入图片描述
    在这里插入图片描述
    刚才说的 AnnotationConfigEmbeddedWebApplicationContext 正是扩展了这个类 ,看一下
    AnnotationConfigEmbeddedWebApplicationContext 类的层次结构
    在这里插入图片描述
    而 EmbeddedWebApplicationContext 类对于 Tomcat 嵌入的一个关键点就是 onRefresh()函数
    的重写
    在这里插入图片描述
    EmbeddedServletContainerFactory 是服务器启动的上层抽象, 无论是 Tomcat 还是 Jetty 都要通
    过这个类实现对 Spring 服务器的注册 现在通过断点来看看它的返回结果
    在这里插入图片描述
    正如所料,它返回的就是 Tomcat 对应的子类实现 于是找到 TomcatEmbedded
    ServletContainerFactory 来查看它的实现逻辑,但是却发现这个类既没有打一些 Spring 注册的注
    解也没有配置在任何配置文件中,那么它是如何注入到 Spring 容器中的呢?
    带着这个疑问,搜索代码, 看一看是否会有其他地方对这个类进行了硬编码的注册
    在这里插入图片描述
    果然,发现 EmbeddedServletContainerAutoConfiguration 这个类进行了调用,这是 Spring 自
    动化整合各种服务器注册的非常关键的入口类
    在这里插入图片描述
    在这里插入图片描述
    这个类中包含了 Tomcat Jetty Undertow 3种类型的服务器自动注册逻辑 ,而选择条件则
    是通过@ConditionalOnClass 注解控制 之前讲解过 ConditionalOnProperty 注解的实现逻辑,
    而 @ConditionalOnClass 实现逻辑与之类似,对应的类在 classpath 目录下存在时,才会去解析
    对应的配置文件 这也就解释了之所以 Spring 默认会启动 Tomcat 正是由于在启动的类目录下存在
    Servlet.class Tomcat.class 而这个依赖是由 Spring 自己在 spring-boot-starter-web 中默认引入,
    按照代码逻辑,如果默认的服务器不希望使用 Tomcat 而是希望使用 Jetty时,那么只
    需要将 Tomcat 对应的 jar 从 spring-boot-starter-web 中排除掉, 然后加入 Jetty 依赖即可
    在这里插入图片描述
    TomcatEmbeddedServletContainerFactory 类的 getEmbeddedServletContainer() 实现类如下
    Tomcat 会在 getTomcatEmbeddedServletContainer(tomcat)代码中异步启动
    在这里插入图片描述

    展开全文
  • Spring源码深度解析 郝佳 第2版》容器的基本实现与XML文件的加载 《Spring源码深度解析 郝佳 第2版》XML标签的解析 《Spring源码深度解析 郝佳 第2版》bean的加载、循环依赖的解决 《Spring源码深度解析 郝佳 第2...

    往期博客

    《Spring源码深度解析 郝佳 第2版》容器的基本实现与XML文件的加载

    《Spring源码深度解析 郝佳 第2版》XML标签的解析

    《Spring源码深度解析 郝佳 第2版》bean的加载、循环依赖的解决

    《Spring源码深度解析 郝佳 第2版》ApplicationContext

    《Spring源码深度解析 郝佳 第2版》AOP

    目录

    1. JDBC
      1. update方法实现原理
      2. execute方法真正执行逻辑
        • // 获取connection对象
        • 根据connection使用PreparedStatementCreator创建PreparedStatement
        • 设置DataSource填充的属性到PreparedStatement
        • 重载调用回调函数逻辑,此处是参数值、参数类型填充setValues到PreparedStatement和真正执行executeUpdate的逻辑
        • 处理警告
        • 释放连接
      3. query方法实现原理
    2. MyBatis

    一、JDBC

    JDBC是一种用于执行SQL语句的Java API ,可以为多种关系型数据库提供统一访问,它由一组用Java语言编写的类和接口组成,具体的以MySQL为例原生方式使用步骤

    1. 引入MySQL支持的驱动程序jar包,mysql-connector-java.xxx.jar
    2. 使用Class.forName(“com.mysql.jdbc.Driver”)加载驱动
    3. 创建数据库连接对象,DriverManager静态方法创建onnection对象,如不指定DataSource连接池的配置,就要在这里配置url和账号密码
    4. 使用Connection对象创建Statement对象,调用execuUpdate、executeQuery等方法,主要执行静态的SQL语句。
    5. 根据返回的ResultSet对象可以指向当前行数据的指针,可以使用next方法逐行获取,具体的行数据格式可以创建XxxRowMapper实现RowMapper然后重写mapRow(ResuleSet set,int index)方法,将set中对应数据库的列设置到POJO实例然后返回。
    6. 使用完关闭连接调用Connection的close方法

    也可以使用封装的JdbcTemplate直接操作,他的构造参数可以传入DataSource实例,他是为了创建第三方连接池,然后直接调用系列方法

    1.update方法的实现原理

    在这里插入图片描述

    在这里插入图片描述

    update方法的7种重载

    // JdbcTemplate
    
    // 1. 只包含sql
     public int update(final String sql) throws DataAccessException {
            Assert.notNull(sql, "SQL must not be null");
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Executing SQL update [" + sql + "]");
            }
    
            class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider {
                UpdateStatementCallback() {
                }
    
                public Integer doInStatement(Statement stmt) throws SQLException {
                    int rows = stmt.executeUpdate(sql);
                    if (JdbcTemplate.this.logger.isTraceEnabled()) {
                        JdbcTemplate.this.logger.trace("SQL update affected " + rows + " rows");
                    }
    
                    return rows;
                }
    
                public String getSql() {
                    return sql;
                }
            }
    
            return updateCount((Integer)this.execute((StatementCallback)(new UpdateStatementCallback())));
        }
    // 2. 包含 PreparedStatementCreator 、 PreparedStatementSetter 
     protected int update(PreparedStatementCreator psc, @Nullable PreparedStatementSetter pss) throws DataAccessException {
            this.logger.debug("Executing prepared SQL update");
            return updateCount((Integer)this.execute(psc, (ps) -> {
                Integer var4;
                try {
                    if (pss != null) {
                        pss.setValues(ps);
                    }
    
                    int rows = ps.executeUpdate();
                    if (this.logger.isTraceEnabled()) {
                        this.logger.trace("SQL update affected " + rows + " rows");
                    }
    
                    var4 = rows;
                } finally {
                    if (pss instanceof ParameterDisposer) {
                        ((ParameterDisposer)pss).cleanupParameters();
                    }
    
                }
    
                return var4;
            }));
        }
    
    // 3. 只包含 PreparedStatementCreator 
        public int update(PreparedStatementCreator psc) throws DataAccessException {
            return this.update(psc, (PreparedStatementSetter)null);
        }
    
    // 4. 包含 PreparedStatementCreator 、generatedKeyHolder
        public int update(PreparedStatementCreator psc, KeyHolder generatedKeyHolder) throws DataAccessException {
            Assert.notNull(generatedKeyHolder, "KeyHolder must not be null");
            this.logger.debug("Executing SQL update and returning generated keys");
            return updateCount((Integer)this.execute(psc, (ps) -> {
                int rows = ps.executeUpdate();
                List<Map<String, Object>> generatedKeys = generatedKeyHolder.getKeyList();
                generatedKeys.clear();
                ResultSet keys = ps.getGeneratedKeys();
                if (keys != null) {
                    try {
                        RowMapperResultSetExtractor<Map<String, Object>> rse = new RowMapperResultSetExtractor(this.getColumnMapRowMapper(), 1);
                        generatedKeys.addAll((Collection)result(rse.extractData(keys)));
                    } finally {
                        JdbcUtils.closeResultSet(keys);
                    }
                }
    
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("SQL update affected " + rows + " rows and returned " + generatedKeys.size() + " keys");
                }
    
                return rows;
            }));
        }
    
    // 5. 包含sql、PreparedStatementSetter 
        public int update(String sql, @Nullable PreparedStatementSetter pss) throws DataAccessException {
            return this.update((PreparedStatementCreator)(new JdbcTemplate.SimplePreparedStatementCreator(sql)), (PreparedStatementSetter)pss);
        }
    // 6. 包含sql、args、argTypes
        public int update(String sql, Object[] args, int[] argTypes) throws DataAccessException {
            return this.update(sql, this.newArgTypePreparedStatementSetter(args, argTypes));
        }
    
    // 7. 包含sql、args
        public int update(String sql, @Nullable Object... args) throws DataAccessException {
            return this.update(sql, this.newArgPreparedStatementSetter(args));
        }
    

    2.execute方法真正执行逻辑

    execute是真正的执行者,query、update方法都是调用的它,以包含sql、args、argTypes的update方法为例分析

    public int update(String sql, Object[] args, int[] argTypes) throws DataAccessException {
    		// 1. 重载,使用ArgTypePreparedStatementSetter封装参数值,这些值对应sql中占位“?”、参数类型
            return this.update(sql, this.newArgTypePreparedStatementSetter(args, argTypes));
        }
    // 重载
    public int update(String sql, @Nullable PreparedStatementSetter pss) throws DataAccessException {
    		// 2. 重载,使用SimplePreparedStatementCreator封装sql
            return this.update((PreparedStatementCreator)(new JdbcTemplate.SimplePreparedStatementCreator(sql)), (PreparedStatementSetter)pss);
        }
    // 重载
    protected int update(PreparedStatementCreator psc, @Nullable PreparedStatementSetter pss) throws DataAccessException {
            this.logger.debug("Executing prepared SQL update");
            // 3. 真正的执行时execute方法
            return updateCount(
            (Integer)this.execute(psc, (ps) -> {
                Integer var4;
                try {
                    if (pss != null) {
                    	
                        pss.setValues(ps);
                    }
    				
                    int rows = ps.executeUpdate();
                    if (this.logger.isTraceEnabled()) {
                        this.logger.trace("SQL update affected " + rows + " rows");
                    }
    
                    var4 = rows;
                } finally {
                    if (pss instanceof ParameterDisposer) {
                        ((ParameterDisposer)pss).cleanupParameters();
                    }
    
                }
    
                return var4;
            }));
        }
    
    
    

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    重载调用另外一个 execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action),因为回调函数是一个函数式接口,真正的执行是在这个回调函数里面的。
    在这里插入图片描述

    接下来详细分析这个

    // JdbcTemplate
    
     @Nullable
        public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException {
            Assert.notNull(psc, "PreparedStatementCreator must not be null");
            Assert.notNull(action, "Callback object must not be null");
            
            if (this.logger.isDebugEnabled()) {
                String sql = getSql(psc);
                this.logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));
            }
    		// 1. 获取connection对象
            Connection con = DataSourceUtils.getConnection(this.obtainDataSource());
            
            PreparedStatement ps = null;
    
            Object var13;
            try {
            	// 2. 要执行的ps,使用PreparedStatementCreator 创建 PreparedStatement
                ps = psc.createPreparedStatement(con);
                // 3. 设置用户指定的参数值到ps
                this.applyStatementSettings(ps);
                // 4. 回调函数doInPreparedStatement,也是真正执行的过程,获取执行结果result
                T result = action.doInPreparedStatement(ps);
    			// 5. 处理警告
                this.handleWarnings((Statement)ps);
                var13 = result;
            } catch (SQLException var10) {
                if (psc instanceof ParameterDisposer) {
                    ((ParameterDisposer)psc).cleanupParameters();
                }
    			
                String sql = getSql(psc);
                psc = null;
                JdbcUtils.closeStatement(ps);
                ps = null;
                // 6.  释放连接
                DataSourceUtils.releaseConnection(con, this.getDataSource());
                con = null;
                throw this.translateException("PreparedStatementCallback", sql, var10);
            } finally {
                if (psc instanceof ParameterDisposer) {
                    ((ParameterDisposer)psc).cleanupParameters();
                }
    
                JdbcUtils.closeStatement(ps);
                DataSourceUtils.releaseConnection(con, this.getDataSource());
            }
    
            return var13;
        }
    
    // 1. 获取connection对象

    委托DataSourceUtils去获取连接,实现在doGetConnection方法,该方法内部部不是简单的使用DataSource.getConnection获取连接的,还要考虑其他情况,主要是事务相关的一些处理。

    // DataSourceUtils
    public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
            try {
            	// 调用
                return doGetConnection(dataSource);
            } catch (SQLException var2) {
                throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection", var2);
            } catch (IllegalStateException var3) {
                throw new CannotGetJdbcConnectionException("Failed to obtain JDBC Connection: " + var3.getMessage());
            }
        }
    
    // 委托
    public static Connection doGetConnection(DataSource dataSource) throws SQLException {
            Assert.notNull(dataSource, "No DataSource specified");
            ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);
            if (conHolder == null || !conHolder.hasConnection() && !conHolder.isSynchronizedWithTransaction()) {
                logger.debug("Fetching JDBC Connection from DataSource");
    
                Connection con = fetchConnection(dataSource);
    			// 当前线程支持同步,就是在一个方法内部单线程串行调用
                if (TransactionSynchronizationManager.isSynchronizationActive()) {
                    try {
    					// 在同一事务中使用同一数据库连接connection
                        ConnectionHolder holderToUse = conHolder;
                        if (conHolder == null) {
                            holderToUse = new ConnectionHolder(con);
                        } else {
                            conHolder.setConnection(con);
                        }
    					// 记录数据库连接
                        holderToUse.requested();
                        TransactionSynchronizationManager.registerSynchronization(new DataSourceUtils.ConnectionSynchronization(holderToUse, dataSource));
                        holderToUse.setSynchronizedWithTransaction(true);
                        if (holderToUse != conHolder) {
                            TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
                        }
                    } catch (RuntimeException var4) {
                    	
                        releaseConnection(con, dataSource);
                        throw var4;
                    }
                }
    
                return con;
            } else {
                conHolder.requested();
                if (!conHolder.hasConnection()) {
                    logger.debug("Fetching resumed JDBC Connection from DataSource");
                    conHolder.setConnection(fetchConnection(dataSource));
                }
    
                return conHolder.getConnection();
            }
        }
    
    // 2. 根据connection使用PreparedStatementCreator 创建 PreparedStatement

    在这里插入图片描述

    // PreparedStatementCreatorFactory,包含内部类PreparedStatementCreatorImpl
    // PreparedStatementCreatorImpl
    public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
                PreparedStatement ps;
                if (PreparedStatementCreatorFactory.this.generatedKeysColumnNames == null && !PreparedStatementCreatorFactory.this.returnGeneratedKeys) {
                    if (PreparedStatementCreatorFactory.this.resultSetType == 1003 && !PreparedStatementCreatorFactory.this.updatableResults) {
                        ps = con.prepareStatement(this.actualSql);
                    } else {
                        ps = con.prepareStatement(this.actualSql, PreparedStatementCreatorFactory.this.resultSetType, PreparedStatementCreatorFactory.this.updatableResults ? 1008 : 1007);
                    }
                } else if (PreparedStatementCreatorFactory.this.generatedKeysColumnNames != null) {
                    ps = con.prepareStatement(this.actualSql, PreparedStatementCreatorFactory.this.generatedKeysColumnNames);
                } else {
                    ps = con.prepareStatement(this.actualSql, 1);
                }
    
                this.setValues(ps);
                return ps;
            }
    
    // 3. 设置用户指定的DataSource值到PreparedStatement
     protected void applyStatementSettings(Statement stmt) throws SQLException {
     		// 主要是减少网络交互次数,访问ResultSet的时候,如果调用next一次从服务器取一条数据
     		// 就会产生大量开销,因此设置参数可以决定一次从数据库服务器取对少条数据放到内存缓存起来
            int fetchSize = this.getFetchSize();
            if (fetchSize != -1) {
                stmt.setFetchSize(fetchSize);
            }
    
            int maxRows = this.getMaxRows();
            if (maxRows != -1) {
                stmt.setMaxRows(maxRows);
            }
    
            DataSourceUtils.applyTimeout(stmt, this.getDataSource(), this.getQueryTimeout());
        }
    
    // 4. 回调函数doInPreparedStatement,包含参数值的填充、真正的执行逻辑
    • // sql中对应占位符值的填充,主要是Spring做的封装,从而不用依次调用setXxx方法this.setValues(ps, lobCreator);,借助两个设置器ArgumentPreparedStatementSetter、ArgumentTypePreparedStatementSetter,他们都实现PreparedStatementSetter
    • // 真正执行 var3 = ps.executeUpdate();借助
    // PreparedStatementCallback的实现类AbstractLobCreatingPreparedStatementCallback
    public final Integer doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
            LobCreator lobCreator = this.lobHandler.getLobCreator();
    
            Integer var3;
            try {
            	// sql中对应占位符值的填充,主要是Spring做的封装,从而不用依次调用setXxx方法
                this.setValues(ps, lobCreator);
                // 真正执行
                var3 = ps.executeUpdate();
            } finally {
                lobCreator.close();
            }
    
            return var3;
        }
    
    // setValues方法

    // sql中对应占位符值的填充,主要是Spring做的封装,从而不用依次调用setXxx方法this.setValues(ps, lobCreator);,借助两个设置器ArgumentPreparedStatementSetter、ArgumentTypePreparedStatementSetter,他们都实现PreparedStatementSetter

    在这里插入图片描述

    
    // ArgumentPreparedStatementSetter 设置参数值
     public void setValues(PreparedStatement ps) throws SQLException {
            if (this.args != null) {
                for(int i = 0; i < this.args.length; ++i) {
                    Object arg = this.args[i];
                    this.doSetValue(ps, i + 1, arg);
                }
            }
    
        }
    
        protected void doSetValue(PreparedStatement ps, int parameterPosition, Object argValue) throws SQLException {
            if (argValue instanceof SqlParameterValue) {
                SqlParameterValue paramValue = (SqlParameterValue)argValue;
                StatementCreatorUtils.setParameterValue(ps, parameterPosition, paramValue, paramValue.getValue());
            } else {
                StatementCreatorUtils.setParameterValue(ps, parameterPosition, -2147483648, argValue);
            }
    
        }
    
    // ArgumentTypePreparedStatementSetter 设置参数类型
    public void setValues(PreparedStatement ps) throws SQLException {
            int parameterPosition = 1;
            if (this.args != null && this.argTypes != null) {
                label45:
                for(int i = 0; i < this.args.length; ++i) {
                    Object arg = this.args[i];
                    if (arg instanceof Collection && this.argTypes[i] != 2003) {
                        Collection<?> entries = (Collection)arg;
                        Iterator var6 = entries.iterator();
    
                        while(true) {
                            while(true) {
                                if (!var6.hasNext()) {
                                    continue label45;
                                }
    
                                Object entry = var6.next();
                                if (entry instanceof Object[]) {
                                    Object[] valueArray = (Object[])((Object[])entry);
                                    Object[] var9 = valueArray;
                                    int var10 = valueArray.length;
    
                                    for(int var11 = 0; var11 < var10; ++var11) {
                                        Object argValue = var9[var11];
                                        this.doSetValue(ps, parameterPosition, this.argTypes[i], argValue);
                                        ++parameterPosition;
                                    }
                                } else {
                                    this.doSetValue(ps, parameterPosition, this.argTypes[i], entry);
                                    ++parameterPosition;
                                }
                            }
                        }
                    } else {
                        this.doSetValue(ps, parameterPosition, this.argTypes[i], arg);
                        ++parameterPosition;
                    }
                }
            }
    
        }
    
        protected void doSetValue(PreparedStatement ps, int parameterPosition, int argType, Object argValue) throws SQLException {
            StatementCreatorUtils.setParameterValue(ps, parameterPosition, argType, argValue);
        }
    
    // executeUpdate方法

    在这里插入图片描述

    // ProxyPreparedStatement实现PreparedStatement
    public int executeUpdate() throws SQLException {
            this.connection.markCommitStateDirty();
            return ((PreparedStatement)this.delegate).executeUpdate();
        }
    
    // 5. 处理警告
    
    protected void handleWarnings(Statement stmt) throws SQLException {
    		// 设置为忽略警告时只打印日志
            if (this.isIgnoreWarnings()) {
                if (this.logger.isDebugEnabled()) {
                // 如果日志开始的情况下打印日志
                    for(SQLWarning warningToLog = stmt.getWarnings(); warningToLog != null; warningToLog = warningToLog.getNextWarning()) {
                        this.logger.debug("SQLWarning ignored: SQL state '" + warningToLog.getSQLState() + "', error code '" + warningToLog.getErrorCode() + "', message [" + warningToLog.getMessage() + "]");
                    }
                }
            } else {
                this.handleWarnings(stmt.getWarnings());
            }
    
        }
    
        protected void handleWarnings(@Nullable SQLWarning warning) throws SQLWarningException {
            if (warning != null) {
                throw new SQLWarningException("Warning not ignored", warning);
            }
        }
    
    
    // 6. 释放连接

    这里的释放连接同样考虑到事务的问题,如果当前线程下面还存在存在事务,因为使用的是一个connection因此需要根据前面的计数减1,因此不是简单的connection.close(),而是进行逻辑事务数量减1

     public static void releaseConnection(@Nullable Connection con, @Nullable DataSource dataSource) {
            try {
                doReleaseConnection(con, dataSource);
            } catch (SQLException var3) {
                logger.debug("Could not close JDBC Connection", var3);
            } catch (Throwable var4) {
                logger.debug("Unexpected exception on closing JDBC Connection", var4);
            }
    
        }
    
        public static void doReleaseConnection(@Nullable Connection con, @Nullable DataSource dataSource) throws SQLException {
            if (con != null) {
                if (dataSource != null) {
                    ConnectionHolder conHolder = (ConnectionHolder)TransactionSynchronizationManager.getResource(dataSource);
                    if (conHolder != null && connectionEquals(conHolder, con)) {
                        conHolder.released();
                        return;
                    }
                }
    			// 真正关闭connection
                doCloseConnection(con, dataSource);
            }
        }
    
    

    3.query方法的实现原理

    基本逻辑和update方法一致,只不过是回调函数传递的不同
    在这里插入图片描述

    然后就是重载调用

    // 主要是定义回调方法,然后最后在调用回调函数中的执行逻辑
     @Nullable
        public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
            Assert.notNull(sql, "SQL must not be null");
            Assert.notNull(rse, "ResultSetExtractor must not be null");
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Executing SQL query [" + sql + "]");
            }
    		
    		// 定义内部类,作为回调传入下面调用
            class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
                QueryStatementCallback() {
                }
    
                @Nullable
                public T doInStatement(Statement stmt) throws SQLException {
                    ResultSet rs = null;
    
                    Object var3;
                    try {
                        rs = stmt.executeQuery(sql);
                        var3 = rse.extractData(rs);
                    } finally {
                        JdbcUtils.closeResultSet(rs);
                    }
    
                    return var3;
                }
    
                public String getSql() {
                    return sql;
                }
            }
    
    		// 回调调用入口
            return this.execute((StatementCallback)(new QueryStatementCallback()));
        }
        
    // 回调调用入口
     @Nullable
        public <T> T execute(StatementCallback<T> action) throws DataAccessException {
            Assert.notNull(action, "Callback object must not be null");
            Connection con = DataSourceUtils.getConnection(this.obtainDataSource());
            Statement stmt = null;
    
            Object var11;
            try {
                stmt = con.createStatement();
                this.applyStatementSettings(stmt);
                // 回调真正调用,也就是上面的回调方法
                T result = action.doInStatement(stmt);
                
                this.handleWarnings(stmt);
                var11 = result;
            } catch (SQLException var9) {
                String sql = getSql(action);
                JdbcUtils.closeStatement(stmt);
                stmt = null;
                DataSourceUtils.releaseConnection(con, this.getDataSource());
                con = null;
                throw this.translateException("StatementCallback", sql, var9);
            } finally {
                JdbcUtils.closeStatement(stmt);
                DataSourceUtils.releaseConnection(con, this.getDataSource());
            }
    
            return var11;
        }
    

    在这里插入图片描述

    而对于第二步的映射
    在这里插入图片描述

    在这里插入图片描述

    二、MyBatis

    MyBatis是支持普通SQL查询、存储过程和高级映射的持久层框架。消除了JDBC所有的JDBC代码和参数的手工设置以及结果集的检索,使用简单的XML或者注解用于配置原始映射,将接口和Java的POJOS映射成数据库中的记录

    可以不集成Spring的情况下单独使用

    1. 建立PO
    2. 建立XxxMapper接口,包含crud方法
    3. 建立配置文件,如数据源dataSource、环境environment、事务管理器transcationManager、mappers映射文件的路径
    4. 建立映射文件,主要是将sql和Mapper接口方法映射
    5. 建立测试类

    整合Spring的情况下使用

    1. 建立PO
    2. 建立XxxMapper接口,包含crud方法
    3. 在Spring的xml配置文件中配置DataSource、SqlSessionFactoryBean、MapperFactoryBean类型的的bean
    4. 在MyBatis的xml配置文件配置映射文件,mappers映射文件的路径
    5. 建立映射文件,主要讲sql和Mapper接口方法映射
    6. 建立测试类

    其中MyBatis的重要的几个类

    • DataSource:主要是数据源的一些配置,包括连接池等
    • SqlSessionFactoryBean:主要是创建SqlSessionFactory,它是MyBatis所有功能的基础,在他的子标签<property>配置的DataSource、ConfigLocation、pluhs等配置都需要初始化SqlSessionFactory传入。
    • MapperFactoryBean:主要是创建XxxMapper代理实例,以便调用相应的sql,整合Spring之后可以getBean的方式获取,就是内部封装了MapperFactoryBean的一些列逻辑
    • MapperScannerConfigurer:配置在applicationContext的XxxMapper接口信息需在<property>标签指定全类名和sqlSessionFactory。如果很多就不太方便了,因此需要一个自动扫描包下的XxxMapper功能,直接配置MapperScannerConfigurer类型的bean在<property>标签指定包路径即可

    1.SqlSessionFactoryBean原理分析

    它的继承体系
    在这里插入图片描述

    • 实现了FactoryBean:实现此接口的bean在调用getBean方法会返回getObject方法返回的我们需要的bean。
    • 实现了InitilzationBean:实现此接口的bean会在初始化之后调用afterPropertiesSet方法进行bean的逻辑初始化。其中SqlSessionFactory就是在这里做的初始化
    // 1. SqlSessionFactory的初始化的buildSqlSessionFactory方法

    // 实现InitalizatioBean接口之后,会在SqlSessionFactoryBean类型的bean初始化完成之后调用afterPropertiesSet方法进行sqlSessionFactory 属性初始化

    // SqlSessionFactoryBean的入口方法 afterPropertiesSet
    
     public void afterPropertiesSet() throws Exception {
            Assert.notNull(this.dataSource, "Property 'dataSource' is required");
            Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
            Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
            // 调用 buildSqlSessionFactory
            this.sqlSessionFactory = this.buildSqlSessionFactory();
        }
    
    

    该方法内部就是创建Configuration实例,将各种配置设置到内部,由此可见尽管把Spring的配置文件和MyBatis的配置文件分开,但是在Spring配置文件中依然可以配置MyBatis的配置

    protected SqlSessionFactory buildSqlSessionFactory() throws Exception {
            XMLConfigBuilder xmlConfigBuilder = null;
            Configuration targetConfiguration;
            
            Optional var10000;
           
           // configuration标签配置
            if (this.configuration != null) {
                targetConfiguration = this.configuration;
                if (targetConfiguration.getVariables() == null) {
                    targetConfiguration.setVariables(this.configurationProperties);
                } else if (this.configurationProperties != null) {
                    targetConfiguration.getVariables().putAll(this.configurationProperties);
                }
            } else if (this.configLocation != null) {
                xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), (String)null, this.configurationProperties);
                // configLocation标签配置,一般用于在Spring配置文件指定MyBatis配置文件地址,用于逻辑分离
                targetConfiguration = xmlConfigBuilder.getConfiguration();
            } else {
                LOGGER.debug(() -> {
                    return "Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration";
                });
                targetConfiguration = new Configuration();
                var10000 = Optional.ofNullable(this.configurationProperties);
                Objects.requireNonNull(targetConfiguration);
                var10000.ifPresent(targetConfiguration::setVariables);
            }
    
            var10000 = Optional.ofNullable(this.objectFactory);
            Objects.requireNonNull(targetConfiguration);
            var10000.ifPresent(targetConfiguration::setObjectFactory);
            var10000 = Optional.ofNullable(this.objectWrapperFactory);
            Objects.requireNonNull(targetConfiguration);
            var10000.ifPresent(targetConfiguration::setObjectWrapperFactory);
            var10000 = Optional.ofNullable(this.vfs);
            Objects.requireNonNull(targetConfiguration);
            var10000.ifPresent(targetConfiguration::setVfsImpl);
            Stream var24;
            // 1. typeAliasesPackage
            if (StringUtils.hasLength(this.typeAliasesPackage)) {
                var24 = this.scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType).stream().filter((clazz) -> {
                    return !clazz.isAnonymousClass();
                }).filter((clazz) -> {
                    return !clazz.isInterface();
                }).filter((clazz) -> {
                    return !clazz.isMemberClass();
                });
                TypeAliasRegistry var10001 = targetConfiguration.getTypeAliasRegistry();
                Objects.requireNonNull(var10001);
                var24.forEach(var10001::registerAlias);
            }
    		// 2. typeAliases
            if (!ObjectUtils.isEmpty(this.typeAliases)) {
                Stream.of(this.typeAliases).forEach((typeAlias) -> {
                    targetConfiguration.getTypeAliasRegistry().registerAlias(typeAlias);
                    LOGGER.debug(() -> {
                        return "Registered type alias: '" + typeAlias + "'";
                    });
                });
            }
    		// 3. plugins
            if (!ObjectUtils.isEmpty(this.plugins)) {
                Stream.of(this.plugins).forEach((plugin) -> {
                    targetConfiguration.addInterceptor(plugin);
                    LOGGER.debug(() -> {
                        return "Registered plugin: '" + plugin + "'";
                    });
                });
            }
    		// 4. typeHandlersPackage
            if (StringUtils.hasLength(this.typeHandlersPackage)) {
                var24 = this.scanClasses(this.typeHandlersPackage, TypeHandler.class).stream().filter((clazz) -> {
                    return !clazz.isAnonymousClass();
                }).filter((clazz) -> {
                    return !clazz.isInterface();
                }).filter((clazz) -> {
                    return !Modifier.isAbstract(clazz.getModifiers());
                });
                TypeHandlerRegistry var25 = targetConfiguration.getTypeHandlerRegistry();
                Objects.requireNonNull(var25);
                var24.forEach(var25::register);
            }
    		// 5. typeHandlers
            if (!ObjectUtils.isEmpty(this.typeHandlers)) {
                Stream.of(this.typeHandlers).forEach((typeHandler) -> {
                    targetConfiguration.getTypeHandlerRegistry().register(typeHandler);
                    LOGGER.debug(() -> {
                        return "Registered type handler: '" + typeHandler + "'";
                    });
                });
            }
            targetConfiguration.setDefaultEnumTypeHandler(this.defaultEnumTypeHandler);
            
            // 6. scriptingLanguageDrivers
            if (!ObjectUtils.isEmpty(this.scriptingLanguageDrivers)) {
                Stream.of(this.scriptingLanguageDrivers).forEach((languageDriver) -> {
                    targetConfiguration.getLanguageRegistry().register(languageDriver);
                    LOGGER.debug(() -> {
                        return "Registered scripting language driver: '" + languageDriver + "'";
                    });
                });
            }
    
            var10000 = Optional.ofNullable(this.defaultScriptingLanguageDriver);
            Objects.requireNonNull(targetConfiguration);
            var10000.ifPresent(targetConfiguration::setDefaultScriptingLanguage);
            if (this.databaseIdProvider != null) {
                try {
                    targetConfiguration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
                } catch (SQLException var23) {
                    throw new NestedIOException("Failed getting a databaseId", var23);
                }
            }
    
            var10000 = Optional.ofNullable(this.cache);
            Objects.requireNonNull(targetConfiguration);
            var10000.ifPresent(targetConfiguration::addCache);
            if (xmlConfigBuilder != null) {
                try {
                    xmlConfigBuilder.parse();
                    LOGGER.debug(() -> {
                        return "Parsed configuration file: '" + this.configLocation + "'";
                    });
                } catch (Exception var21) {
                    throw new NestedIOException("Failed to parse config resource: " + this.configLocation, var21);
                } finally {
                    ErrorContext.instance().reset();
                }
            }
    		// 7. environment
            targetConfiguration.setEnvironment(new Environment(this.environment, (TransactionFactory)(this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory), this.dataSource));
            if (this.mapperLocations != null) {
                if (this.mapperLocations.length == 0) {
                    LOGGER.warn(() -> {
                        return "Property 'mapperLocations' was specified but matching resources are not found.";
                    });
                } else {
                    Resource[] var3 = this.mapperLocations;
                    int var4 = var3.length;
    
                    for(int var5 = 0; var5 < var4; ++var5) {
                        Resource mapperLocation = var3[var5];
                        if (mapperLocation != null) {
                            try {
                                XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());
                                xmlMapperBuilder.parse();
                            } catch (Exception var19) {
                                throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", var19);
                            } finally {
                                ErrorContext.instance().reset();
                            }
    
                            LOGGER.debug(() -> {
                                return "Parsed mapper file: '" + mapperLocation + "'";
                            });
                        }
                    }
                }
            } else {
                LOGGER.debug(() -> {
                    return "Property 'mapperLocations' was not specified.";
                });
            }
    		// 调用
            return this.sqlSessionFactoryBuilder.build(targetConfiguration);
        }
    
    	
    

    其中SqlSession是一个接口,作为接口创建映射器代理 的接触类,内部包含各种crud、commit、rollback的定义,在setSqlSession的setSqlSessionFactory方法中最终封装的是DefaultSqlSessionFactory到成员变量sqlSession

    在这里插入图片描述

    // DefaultSqlSessionFactory 继承 SqlSessionFactory
    public SqlSessionFactory build(Configuration config) {
            return new DefaultSqlSessionFactory(config);
        }
    // 构造函数
     public DefaultSqlSessionFactory(Configuration configuration) {
            this.configuration = configuration;
        }
    
    // 2. SqlSessionFactory的获取

    // 实现了FactoryBean接口,会在在调用getBean方法会返回getObject方法返回的我们需要的bean,没有初始化的时候进行afterPropertiesSet初始化。

    // 重写getObject方法,也就是在getBean的时候完成 afterPropertiesSet 调用初始化sqlSessionFactory
        public SqlSessionFactory getObject() throws Exception {
            if (this.sqlSessionFactory == null) {
            	// 初始化sqlSessionFactory入口
                this.afterPropertiesSet();
            }
    
            return this.sqlSessionFactory;
        }
    

    2.MapperFactoryBean原理分析

    假如我们定义UserMapper接口内部包含getUser方法,然后

    • 单独使用MyBatis的时候是UserMapper up = sqlSession.getMapper(UserMapper.class)
    • 整合Spring之后可以使用UserMapper up =(Usermapper) context.getBean("userMapper"),它的原理就是对上面的在一次封装

    所以内部逻辑在MapperFactoryBean中实现

    // 1.MapperFactory的初始化

    先看继承体系
    在这里插入图片描述

    和上面类似,它实现InitalizationBean接口,所以初始化方法在afterPropertiesSet方法,在DaoSupport中实现,也就initDao方法

     public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException {
     		// 1. 验证DAO配置,由MapperFactoryBean实现,核心逻辑
            this.checkDaoConfig();
    
            try {
            	// 2. 模板方法,留给子类拓展
                this.initDao();
            } catch (Exception var2) {
                throw new BeanInitializationException("Initialization of DAO failed", var2);
            }
        }
    
    // 1. 验证DAO配置checkDaoConfig,由MapperFactoryBean实现

    主要进行的验证

    • 父类SqlSessionDaoSupport对sqlSession不为空的验证,也就是不开启自动扫描XxxMapper的时候,在每个映射文件xml配置XxxMapper的标签都应该设置sqlSessionFactory,不配置就会报错
    • 映射接口的验证
    • 映射文件存在性验证,防止出现XxxMapper无对应映射接口

    主要是将所有配置的XxxMapper接口放到configuration属性中,这里也可以看出Spring配置、MyBatis配置文件分离并不影响

     protected void checkDaoConfig() {
     		// 父类SqlSessionDaoSupport实现
            super.checkDaoConfig();
            Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required");
            Configuration configuration = this.getSqlSession().getConfiguration();
            if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
                try {
                	// 添加XxxMapper到SqlSessionFactoryBean的configuration属性
                    configuration.addMapper(this.mapperInterface);
                } catch (Exception var6) {
                    this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6);
                    throw new IllegalArgumentException(var6);
                } finally {
                    ErrorContext.instance().reset();
                }
            }
    
        }
    
    // 2.MapperFactory的获取
    //MapperFactoryBean
     public T getObject() throws Exception {
            return this.getSqlSession().getMapper(this.mapperInterface);
        }
    
    // SqlSessionDaoSupport的getSqlSession方法
     public SqlSession getSqlSession() {
            return this.sqlSessionTemplate;
        }
    // 可见 sqlSessionTemplate 成员属性封装了  sqlSessionFactory
    protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    
    

    3.MapperScannerConfigurer原理分析

    继承体系

    在这里插入图片描述

    // MapperScannerConfigurer
    
     private boolean processPropertyPlaceHolders;
    
     public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
            if (this.processPropertyPlaceHolders) {
            	// 1. 关键地方,如在xml中取出properties配置的basePackge值
                this.processPropertyPlaceHolders();
            }
    		// 2.  初始化扫描器ClassPathMapperScanner
            ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
            scanner.setAddToConfig(this.addToConfig);
            scanner.setAnnotationClass(this.annotationClass);
            scanner.setMarkerInterface(this.markerInterface);
            scanner.setSqlSessionFactory(this.sqlSessionFactory);
            scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
            scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
            scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
            scanner.setResourceLoader(this.applicationContext);
            scanner.setBeanNameGenerator(this.nameGenerator);
            scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
            if (StringUtils.hasText(this.lazyInitialization)) {
                scanner.setLazyInitialization(Boolean.valueOf(this.lazyInitialization));
            }
    
            if (StringUtils.hasText(this.defaultScope)) {
                scanner.setDefaultScope(this.defaultScope);
            }
    		// 3. 注册对应的过滤器
            scanner.registerFilters();
            //4.  开始扫描Java文件
            scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
        }
    
    // 1. 关键地方processPropertyPlaceHolders,如在xml中取出properties配置的basePackge值

    往期博客对postProcessBeanFactory、PropertyPlaceholderConfigurer的分析
    在这里插入图片描述

    • BeanDefinitionRegistries会在应用启动的时候调用registryBeanDefinitions方法注册BeanDefinition,早于BeanFactoryPostProcessors的调用。

    • PropertyPlaceholderConfigurer将properties文件中的值取出到xml配置文件的原理是实现了BeanFactoryPostProcessors的postProcessBeanFactory,因此正常情况会在registryBeanDefinitions的后面,导致注册BeanDefinition时候xml中还没取出properties配置内容,自然映射不到BeanDefintion中了

    因此MyBatis的解决就是使用注册的MapperScannerConfigurer提前借助PropertyResourceConfigurer的processPropertyPlaceHolders取出值注册BeanDefinition

    1. 找出所有配置在xml中的PropertyResourceConfigurer类型的bean
    2. 模拟Spring环境来使用mapperScannerBean类型的Bean提前调用后处理器postProcessBeanFactory,进而调用PropertyResourceConfigurer处理器值提取保存到成员变量,然后设置到scanner中等下真正注册BeanDefinition
    private void processPropertyPlaceHolders() {
            Map<String, PropertyResourceConfigurer> prcs = this.applicationContext.getBeansOfType(PropertyResourceConfigurer.class, false, false);
            
            if (!prcs.isEmpty() && this.applicationContext instanceof ConfigurableApplicationContext) {
                BeanDefinition mapperScannerBean = ((ConfigurableApplicationContext)this.applicationContext).getBeanFactory().getBeanDefinition(this.beanName);
    			
    			// 虚拟 DefaultListableBeanFactory ,为了营造factory环境,完成调用PropertyResourceConfigurer处理器就失效
                DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
                // 提前取值
                factory.registerBeanDefinition(this.beanName, mapperScannerBean);
                Iterator var4 = prcs.values().iterator();
    
                while(var4.hasNext()) {
                    PropertyResourceConfigurer prc = (PropertyResourceConfigurer)var4.next();
                    // 接着调用 postProcessBeanFactory,进而调用PropertyResourceConfigurer处理器完成值取出
                    prc.postProcessBeanFactory(factory);
                }
    			// 取出值
                PropertyValues values = mapperScannerBean.getPropertyValues();
                
                this.basePackage = this.getPropertyValue("basePackage", values);
                this.sqlSessionFactoryBeanName = this.getPropertyValue("sqlSessionFactoryBeanName", values);
                this.sqlSessionTemplateBeanName = this.getPropertyValue("sqlSessionTemplateBeanName", values);
                this.lazyInitialization = this.getPropertyValue("lazyInitialization", values);
                this.defaultScope = this.getPropertyValue("defaultScope", values);
            }
    
    		// 真实值使用保存到成员变量
            Optional var10001 = Optional.ofNullable(this.basePackage);
            Environment var10002 = this.getEnvironment();
            Objects.requireNonNull(var10002);
            this.basePackage = (String)var10001.map(var10002::resolvePlaceholders).orElse((Object)null);
            var10001 = Optional.ofNullable(this.sqlSessionFactoryBeanName);
            var10002 = this.getEnvironment();
            Objects.requireNonNull(var10002);
            this.sqlSessionFactoryBeanName = (String)var10001.map(var10002::resolvePlaceholders).orElse((Object)null);
            var10001 = Optional.ofNullable(this.sqlSessionTemplateBeanName);
            var10002 = this.getEnvironment();
            Objects.requireNonNull(var10002);
            this.sqlSessionTemplateBeanName = (String)var10001.map(var10002::resolvePlaceholders).orElse((Object)null);
            var10001 = Optional.ofNullable(this.lazyInitialization);
            var10002 = this.getEnvironment();
            Objects.requireNonNull(var10002);
            this.lazyInitialization = (String)var10001.map(var10002::resolvePlaceholders).orElse((Object)null);
            var10001 = Optional.ofNullable(this.defaultScope);
            var10002 = this.getEnvironment();
            Objects.requireNonNull(var10002);
            this.defaultScope = (String)var10001.map(var10002::resolvePlaceholders).orElse((Object)null);
        }
    
    //4. scan方法,开始扫描Java文件
    // ClassPathBeanDefinitionScanner
     public int scan(String... basePackages) {
            int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
            // 真正扫描
            this.doScan(basePackages);
            if (this.includeAnnotationConfig) {
                AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
            }
    
            return this.registry.getBeanDefinitionCount() - beanCountAtScanStart;
        }
    

    doScan真正扫描

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
            Assert.notEmpty(basePackages, "At least one base package must be specified");
            // 需要注册的XxxMapper的BeanDefintion
            Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet();
            String[] var3 = basePackages;
            int var4 = basePackages.length;
    
            for(int var5 = 0; var5 < var4; ++var5) {
                String basePackage = var3[var5];
                // 扫描basePackage包下的java文件,也就是XxxMapper
                Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage);
                Iterator var8 = candidates.iterator();
    			// 遍历
                while(var8.hasNext()) {
                    BeanDefinition candidate = (BeanDefinition)var8.next();
                    
                    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
                    // 设置scope属性
                    candidate.setScope(scopeMetadata.getScopeName());
                    
                    String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
                    
                    if (candidate instanceof AbstractBeanDefinition) {
                        this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName);
                    }
    				// 如果是AnnotatedBeanDefinition 类型,需要检查常用注解如Lazy、Primary
                    if (candidate instanceof AnnotatedBeanDefinition) {
                        AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate);
                    }
    
                    if (this.checkCandidate(beanName, candidate)) {
                        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                        // 如果当前bean需要生成代理需要进一步处理
                        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                        beanDefinitions.add(definitionHolder);
                        // 注册
                        this.registerBeanDefinition(definitionHolder, this.registry);
                    }
                }
            }
    
            return beanDefinitions;
        }
        
    // scanCandidateComponents方法
    
     private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
            LinkedHashSet candidates = new LinkedHashSet();
    
            try {
                String packageSearchPath = "classpath*:" + this.resolveBasePackage(basePackage) + '/' + this.resourcePattern;
                Resource[] resources = this.getResourcePatternResolver().getResources(packageSearchPath);
                boolean traceEnabled = this.logger.isTraceEnabled();
                boolean debugEnabled = this.logger.isDebugEnabled();
                Resource[] var7 = resources;
                int var8 = resources.length;
    
                for(int var9 = 0; var9 < var8; ++var9) {
                    Resource resource = var7[var9];
                    if (traceEnabled) {
                        this.logger.trace("Scanning " + resource);
                    }
    
                    if (resource.isReadable()) {
                        try {
                            MetadataReader metadataReader = this.getMetadataReaderFactory().getMetadataReader(resource);
                            if (this.isCandidateComponent(metadataReader)) {
                                ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
                                sbd.setSource(resource);
                                // 判断扫描文件是否符合要求
                                if (this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) {
                                    if (debugEnabled) {
                                        this.logger.debug("Identified candidate component class: " + resource);
                                    }
    
                                    candidates.add(sbd);
                                } else if (debugEnabled) {
                                    this.logger.debug("Ignored because not a concrete top-level class: " + resource);
                                }
                            } else if (traceEnabled) {
                                this.logger.trace("Ignored because not matching any filter: " + resource);
                            }
                        } catch (Throwable var13) {
                            throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, var13);
                        }
                    } else if (traceEnabled) {
                        this.logger.trace("Ignored because not readable: " + resource);
                    }
                }
    
                return candidates;
            } catch (IOException var14) {
                throw new BeanDefinitionStoreException("I/O failure during classpath scanning", var14);
            }
        }
    
    展开全文
  • Spring源码解析.zip

    2020-07-31 16:21:16
    spring源码解析。使用xmind进行代码整理。包含ioc,aop,tr相关代码部分。
  • Spring源码深度解析 郝佳 第2版》容器的基本实现与XML文件的加载 《Spring源码深度解析 郝佳 第2版》XML标签的解析 《Spring源码深度解析 郝佳 第2版》bean的加载、循环依赖的解决 《Spring源码深度解析 郝佳 第2...
  • spring
  • spring初始,第一章spring的整体架构
  • Spring源码阅读笔记
  • 通过对spring源码的学习深入对spring的研究,适合于已经有spring使用基础,想深入研究spring的同学
  • Spring源码深度解析

    万次阅读 多人点赞 2021-06-21 09:43:30
    Spring整体架构和环境搭建 Spring整体架构 Spring Core:框架的最基础部分,提供 IoC 容器,对 bean 进行管理。 Spring Context:继承BeanFactory,提供上下文信息,扩展出JNDI、EJB、电子邮件、国际化等功能。 ...
  • Spring的影响力想必无需与大家多说,如果你用spring,那么读读源码有助于对你最重要的工具的理解,好的框架...但现在我的想法改变了,下面我就我自己的一些见解来与大家聊聊为什么要读Spring源码。为什么要读Spri...
  • Spring源码深度解析 AOP总结

    千次阅读 2022-03-15 17:37:15
    Spring 中的自定义注解,如果声明了自定义的注解,那么就一定会在程序中的某 个地方注册了对应的解析器 在 AopNamespaceHandler 中对应着这样一段函数: 在解析配 文件的时候, 旦遇到 aspectjautoproxy 注解时就会...
  • Spring的影响力想必无需与大家多说,如果你用spring,那么读读源码有助于对你最重要的工具的理解,好的框架...但现在我的想法改变了,下面我就我自己的一些见解来与大家聊聊为什么要读Spring源码。为什么要读Spri...
  • spring源码深度解析第2版+pdf百度云盘

    千次阅读 2020-07-22 22:51:12
    https://pan.baidu.com/s/1ZedWWt_P-g6Rb03rM4rVHw 百度提取码:9hh4
  • Spring4源码深度解析

    2017-10-30 20:26:05
    者详细地列出Spring API,而是希望通过现实中的实际示例代码来为Java EE开发人员展现Spring框架。因为Spring是一个模块化的框架,所以 这本书也是按照这种方式编写的。我们知道并不是所有的开发人员都有相同的需求,...
  • Spring源码深度解析与注解驱动开发文档结构1.1目录视图Spring注解驱动开发容器·AnnotationConfigApplicationContext·
  • 下面是最近更新的Spring源码解析类文章,欢迎移步至公众号查看,微信搜索公众号:”菜鸟封神记“,或者扫描下面公众号关注即可。 菜鸟封神记 近期发布过以下文章,后续会持续分享更多关于Spring源码的文章,笔者...
  • 前面暂时结束jvm与java基础的整理,今天开始整理spring的内容。 demo 先从一个demo开始,最开始学spring,大家都写过这样的demo。 //实体类 package com.ycf.test; public class User { private String userName; ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 17,641
精华内容 7,056
关键字:

spring源码深度解析

spring 订阅
友情链接: PCB-Protel.rar