更新于 

SpringFramework源码阅读

[TOC]

Spring源码

Spring IOC源码

  • 抓住主干:
    • 解析配置
    • 定位与注册对象
      • 容器初始化主要做的事情:配置文件读取,Resource解析,BeanDefinition注册到容器
    • 注入对象
  • xml(注解)配置的资源定位、加载、解析、注册全链路分析

BeanDefinition

  • org.springframework.beans.factory.config.BeanDefinition的定义
    • 在JVM中使用java.lang.Class对象来描述对象。
    • 在spring中使用org.springframework.beans.factory.config.BeanDefinition来描述Bean的配置信息
    • 常用属性
      • @Scope作用范围
      • @Lzy决定Bean实例是否延迟加载
      • Primary:设置为true的bean会是优先的实现类
      • 工厂方法提现:factory-bean(工厂bean名称)和factory-method(工厂方法名称)(@Configuration和@Bean)
    • spring中有大量的接口,如果某个类实现了接口,就说明这个接口有某种能力。
    • 源码架构图BeanDefinition
      • org.springframework.beans.factory.support.RootBeanDefinition:用来合并具有继承的BeanDefination
      • org.springframework.core.AttributeAccessor:提供访问和修改元数据信息的能力
      • org.springframework.beans.factory.support.GenericBeanDefinition:在spring 2.5之后,是RootBeanDefinition和ChildBeanDefinotion的替换,用于bean的配置文件类

BeanFactory

  • org.springframework.beans.factory.BeanFactory的定义
    • 要求所有的IOC容器都要实现该接口
    • org.springframework.beans.factory.BeanFactoryorg.springframework.beans.factory.FactoryBean的区别
      • BeanFactory是顶级的容器接口,定义了IOC容器最基本的功能,是管理Bean的容器,等价工厂方法的抽象工厂方法
      • FactoryBean基于getObject()可以使用一套更加复杂的逻辑生成bean,用来生成bean,等价于在工厂方法的具体工厂方法。
    • 架构图BeanFactory
      • 那么多接口是因为架构的设计遵循设计模式单一职责原则
      • AutowireCapableBeanFactory:组件扫描和组件装配
  • ?

ApplicationContext(上下文)

  • spring的IOC容器分为2类:
    • org.springframework.beans.factory.BeanFactory为主的简单IOC容器,已org.springframework.context.ApplicationContext为高级的IOC容器
    • ApplicationContext
    • BeanFactory是spring IOC容器的基本设施(面向spring自身),与用户打交道的ApplicationContext的高级IOC容器,除了创建bean之外很多额外的功能
  • ApplicationContext常用容器
    • 传统的基于XML配置的经典容器
      • org.springframework.context.support.FileSystemXmlApplicationContext:从文件系统加载配置
      • org.springframework.context.support.ClassPathXmlApplicationContext:从classpath加载配置
      • org.springframework.web.context.support.XmlWebApplicationContext:用于web应用程序的容器
    • 目前比较流行的容器
      • AnnotationConfigServletWebServerApplicationContext(springboot)
      • AnnotationConfigReactiveWebServerApplicationContext(springboot响应式编程)
      • AnnotationConfigApplicationContext(spring,基于注解的容器)

DefaultListableBeanFactory

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

Resource

  • org.springframework.core.io.Resource
  • Resource
  • ResourceLoader:根据资源自动地址自动选择正确的Resource
    • 自动识别”classpath:”、’file:” 等资源地址前缀
    • 支持自动解析Ant风格带通配符的资源地址(路径匹配表达式,用来对URI进行匹配)

ResourceLoad

  • ResourceLoader
  • org.springframework.core.io.DefaultResourceLoader#getResource
    • 大部分Resource的实现逻辑:根据不同的路径返回不同的resouce实例
    • 非简单工厂模式(黑盒,用户完全不了解内部),而是策略模式

BeanDefinitionReader

  • org.springframework.beans.factory.support.BeanDefinitionReader:使用ResourceLoad读取配置来转换为BeanDefinition。
  • BeanDefinitionReader
  • org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions(java.lang.String, java.util.Set<org.springframework.core.io.Resource>):核心逻辑
  • 问:BeanDefinitionDocumentReader documentReader替换为(DefaultBeanDefinitionDocumentReader):错误!!!!!DefaultListableBeanFactory通过实现了BeanDefinitionRegistry,实现Map<String, BeanDefinition> beanDefinitionMap 作为BeanDefinition存储的载体。在分析XmlBeanDefinitionReader的时候,DefaultListableBeanFactory通过献祭自己转换为BeanDefinitionRegistry给XmlBeanDefinitionReader使用

DefaultBeanDefinitionDocumentReader

  • org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions
  • 事情监听:xml中的import标签和alias标签完成后都发送事件
  • org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition,把创建好的BeanDefinition注册到容器BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

BeanDefinitionRegistry

AbstractBeanDefinitionReader

protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;

// Determine ResourceLoader to use.
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
this.resourceLoader = new PathMatchingResourcePatternResolver();
}

// Inherit Environment if possible
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
this.environment = new StandardEnvironment();
}
}
  • 细节:也就是说可以把IOC容器(DefaultListableBeanFactory和ApplicationContext)当成ResourceLoad来使用

PostProcessor

  • postProcessor作为容器或者bean的后置处理器
  • 本身也是一种需要注册到容器的bean
    • 其里面的方法会在特定的时机被容器调用
    • 实现不改变容器或者Bean核心逻辑的情况下对Bean进行扩展.
    • 对bean进行包装,影响其行为、修改bean的内容等
  • 种类:大类分为容器级别的后置处理器以及Bean级别的后置处理器
    • BeanDefinitionRegistryPostProcessor(容器级别)
    • BeanFactoryPostProcessor(容器级别)
    • BeanPostProcessor(bean级别)
  • org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor:
    • 允许在正常的BeanFactoryPostProcessor检测开始之前注册更多的自定义beandefinition
  • org.springframework.beans.factory.config.BeanFactoryPostProcessor:
  • org.springframework.beans.factory.config.BeanPostProcessor:
  • 责任链模式:为什么能能够在容器内调用postprocessor方法?
    • 排序好的postprocessor按照责任链模式来执行

Aware(可感知)

  • 从Bean里面获取到的容器实例并对其进行操作
  • 需要获取容器能力的实现,实现特定的Aware接口,就能得到该能力。在创建该bean的时候,将能力赋值给bean。
  • 本身也必须是bean

AbstractApplicationContext#refresh(模板方法)

prepareRefresh();刷新前的工作准备

obtainFreshBeanFactory();获取子类刷新后的内部beanFactory实例,对于xml这里对beanDefinition进行解释了注册,注解比较简单

prepareBeanFactory(beanFactory);为容器注册必要的系统级别的Bean

postProcessBeanFactory(beanFactory);允许容器的子类去注册postProcessor

invokeBeanFactoryPostProcessors(beanFactory);调用容器注册的容器级别的后置处理器(而注解的方式,是在容器后置处理器警醒解析和注册的)

registerBeanPostProcessors(beanFactory);向容器注册bean级别的后置处理器

initMessageSource();初始化国际化配置

initApplicationEventMulticaster();初始化事件发布者组件

onRefresh();在单例bean初始化之前预留给子类初始化其他特殊bean的口子

registerListeners();向前面的事件发布者组件注册事件监听器

finishBeanFactoryInitialization(beanFactory);设置系统级别的服务,实例化所有非懒加载的单例(依赖注入)

finishRefresh();触发初始化完成的回调方法,并发布容器刷新完成的事件给监听者

resetCommonCaches();重置spring内核中的共用缓存

依赖注入

image-20200731080951959

  • AbstractBeanFactory
    • doGetBean
      • 尝试从缓存获取bean(bean实例或者factoryBean.getObject()方法)
      • 循环依赖的判断
      • 递归去父容器获取bean实例
      • 从当前容器获取beanDefinition实例
      • 递归实例化显示依赖的bean(depengs-on,后者会先实例化)
      • 依据不同的scope采用不同的策略创建bean实例
      • 对bean进行类型检查
  • DefaultSingletonBeanRegistry
  • AbstractAutowireCapableBeanFactory
    • createBean
      • bean类型解析
      • 处理方法覆盖(lookup-method和replace-method等替换bean属性)
      • bean实例化前的后置处理
      • doCreateBean
    • doCreateBean
      • 创建bean实例(工厂方法,含参构造器注入、无参数构造器注入)
      • 记录下被@Autowired或者@value标记上的方法和成员变量(通过MergedBeanDefinitionPostProcessor的后置处理器,将其放到InjectionMetadata中,为后面依赖注入做准备,还是责任链模式)
      • 是否允许提前暴露(bean是单例&&允许循环依赖&&正在创建的)
      • 填充bean属性
      • initializabean(beanpostProcessor)
        • 如果实现了aware接口,则设置值
        • Aop:初始化前操作
        • Aop:初始化操作
        • Aop:初始化后操作
      • 注册相关销毁逻辑
      • 返回创建好的实例
    • AbstractAutowireCapableBeanFactory#populateBean(属性填充)
      • postProcessAfterInitialization:在设置属性前去修改bean状态,也可以控制是否继续给bean设置属性值
      • 注入属性到propertyValue中(按名字装配 or 按类型装配)
      • postProcessPropertyValue:对解析完但是未设置的属性进行再处理
      • 是否进行依赖检查
      • 将propertyValue中的属性值设置到beanwrapper中
  • AutowiredAnnotationBeanPostProcessor
  • DefaultListableBeanFactory
  • DependencyDescriptor

spring循环依赖

  • 针对prototype的循环依赖,spring无解,直接抛出异常
  • spring不支持显示循环依赖,(depends-on)
  • 静态的file不支持依赖注入,代码报错
  • 要想框架设计的好(强大和灵活),就要把功能拆拆的够细,每个过程都留有可操作的空间,使用责任链模式完美
  • 一图胜前文spring解决单例循环依赖
  • 循环依赖的情况
    • 构造器循环依赖(Singleton、prototype)
    • Setter注入循环依赖(Singleton、prototype)
    • 总结:构造器或者prototype都不支持循环依赖
  • 三级缓存解决的问题:
    1. 解决了单例循环依赖问题
    2. 单例的唯一性问题
    3. prototype无三级缓存(故不支持)
    4. AbstractAutowireCapableBeanFactory#createBeanInstance(构造器依赖注入,不支持循环依赖的问题,因为这里还没有使用到缓存)
    5. 总结:只支持setter注入的单例循环依赖
    6. singletonObjects:一级缓存
    7. singletonFactories:三级缓存
    8. earlySingletonObjects:二级缓存

BeanWrapperImpl

  • 功能:修改bean里面的属性

Spring AOP源码

AOP源码流程

  1. 注册解析AOP的服务
  2. 解析和加载横切逻辑
  3. 将横切逻辑织入目标Bean中
  4. 具体实现细节
    1. Bean级别的后置处理器的执行时机分析
      • SmartInstantiationAwareBeanPostProcessor及其子类
      • abstractAutoProxyCreator
    2. AnnotationAwareAspectJAutoProxyCreator的注册
      • @import:BeanDefinitionRegistry.postProcessBeanDefinitionRegistr
    3. 将切面逻辑解析成一个个advisor实例
      • InstantiationAwareBeanPostProcessor . postProcessBeforeInstantiation
      • @aspect的解析和加载
    4. 针对每个bean筛选出匹配的advisor并创建动态代理
      • cglib or jdk动态大理
      • BeanPostProcessor . postProces sAfterInitialization
    5. 通过调用链按顺序递归执行被代理的方法

BeanPostProcessor

  • InstantiationAwareBeanPostProcessor:
    • 在bean的实例化过程中(在实例化(依赖注入附上属性)之前的),给bean加上额外的逻辑。它区别于BeanPostProcessor,里面的方法先执行。
    • InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation:用来在对象实例化前直接返回一个对象 (如代理对象)来代替通过内置的实例化流程创建对象
    • InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation:在对象实例化完毕执行populateBean之前(在bean实例化之后),如果返回false则spring不再对对应的bean实例进行自动依赖注入
  • SmartInstantiationAwareBeanPostProcessor
  • MergedBeanDefinitionPostProcessor
  • DestructionAwareBeanPostProcessor
  • BeanPostProcessor的执行顺序
    • 1——->InstantiationAwareBeanPostProcessor . postProcessBeforeInstantiation
    • 2——– >SmartInstantiat ionAwareBeanPostProcessor.determineCandidateConstructors
    • 3——– >MergedBeanDefinitionPostProces sor . postProces sMergedBeanDefinition
    • 4——–>Instantiat ionAwareBeanPostProcessor . postProcessAfterInstantiation
    • 5——–>InstantiationAwareBeanPostProcessor . postProces sProperties
    • 6——— >BeanPostProcessor . postProcessBeforeInitialization
    • 7——– >BeanPostProcessor . postProces sAfterInitialization
    • 8——– >DestructionAwareBeanPostProces sor . postProcessBeforeDestruction

EnableAspectJAutoProxy

  • boolean proxyTargetClass() default false;
    • 表明该类采用CGLIB(true)代理还是使用JDK(false)的动态代理
  • boolean exposeProxy() default false;
    • Spring框架上下文中拿到当前代理对象
  • AspectJAutoProxyRegistrar

通过注解将类当做Bean管理起来的方式

  • @Controller @Service @Repository @Component标记的类
  • @Bean标记的方法
  • @Import标签
    • 获取bean需要加上包名

AnnotationAwareAspectJAutoProxyCreator

  • 基于注解的动态代理创建器

AdvisedSupport

  • getInterceptorsAndDynamicInterceptionAdvice:递归方式,获取被代理方法的拦截器链(多个切面命中同一个类)

ProxyCreatorSupport

TargetSource

  • SingletonTargetSource
  • PrototypeTargetSource
  • CommonsPool2TargetSource
  • ThreadLocalTargetSource
  • HotSwappableTargetSource

解析和加载横切逻辑

  1. AbstractAutowireCapableBeanFactory#createBean()
  2. AbstractAutoProxyCreator#postProcessBeforeInstantiation
  3. AbstractAutoProxyCreator#shouldSkip
  4. AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
    • 合并注解和非注解的advisors
  5. BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
    • 从容器获取所有beanName
    • 遍历beanName,解析出被@Aspect标记的类
    • 提出aspect类哩的advisors
    • 将提取的结果加入缓存

将横切逻辑织入目标Bean中

  • 在bean初始化完之后才织入横切逻辑。入口:AbstractAutowireCapableBeanFactory#initializeBean()
    • postProcessAfterInitialization :正常流程的织入入口
    • getEarlyBeanReference :循环依赖的织入入口
  • 一图胜千文系列spring-aop织入横切逻辑

泛型Generics

  • 让数据类型变得参数化

    1. 定义泛型时,对应的数据类型是不确定的
    2. 泛型方法被调用时,会指定具体类型
    3. 核心目标:解决容器类型在编译时安全检查的问题
  • 泛型类

    1. 泛型的参数不支持基本类型

    2. 泛型相关的信息不会进入到运行时阶段

    3. 能否在泛型里面使用具备继承关系的类?

      • 使用通配符?,但是会使得泛型的类型检查失去意义

      • 给泛型加入上边界? Extends E

      • 给泛型加入下边界? super E

  • 泛型接口

    1. 与泛型类的用法基本相同,常用于数据类型的生产工厂接口中
  • 泛型方法

    1. 既能用在泛型类、泛型接口里,也能用在普通类或者接口里
    2. 泛型方法不被泛型类约束
  • 泛型字母的含义

    1. E- Element :在集合中使用,因为集合中存放的是元素
    2. T- Type : Java类
    3. K-Key :键
    4. V-Value:值
    5. N-Number:数值类型

工厂模式

简单工厂模式

  • 定义:一个工厂类,根据传入的参数的值不同返回不同的实例
  • 特点:被创建的实例具有共同的父类或接口
  • 适用场景:
    • 需要创建的对象较少
    • 客户端不关心对象的创建过程
  • 优缺点:
    • 优点:可以对创建的对象进行”加工”, 对客户端隐藏相关细节
    • 缺点:因创建逻辑复杂或创建对象过多而造成代码臃肿
    • 缺点:新增、删除子类均会违反开闭原则
      • 开闭原则:一个软件实体(一个函数、类、模块),应该对扩展开放,对修改关闭

工厂方法模式

  • 定义:一个用于创建对象的接口,让子类决定实例化哪一个类。(对类的实例化延迟到其子类)
  • 优缺点:
    • 优点:符合开闭原则、符合单一职责原则
    • 优点: 对客户端隐藏相关细节(是简单工厂模式的进一步抽象和扩展)
    • 缺点:添加子类的时候”拖家带口”(类的个数指数增加,系统复杂和臃肿)
    • 缺点:只支持同一类产品的创建

抽象工厂模式

  • 定义:提供一个创建一系列相关或者相互依赖对象的接口。(对工厂模式进行了抽象)
    • 抽象工厂模式侧重的是同一产品族
    • 工厂方法模式更加侧重于同一产品等级
  • 优缺点:
    • 优点:解决了工厂模式只支持生成一种产品的弊端
    • 优点:新增一个产品族,只需要增加一个新的具体工厂,不需要修改代码
    • 缺点:添加新产品时依旧违反开闭原则

反射

  • 定义:允许程序在运行时来进行自我检查并且对内部的成员进行操作
  • 作用:
    • 在运行时判断任意一个对象所属的类
    • 在运行时获取类的对象
    • 在运行时访问java对象的属性,方法,构造方法等
  • java.lang.reflect类库中主要的类
    • Field : 表示类中的成员变量
    • Method : 表示类中的方法
    • Constructor :表示类的构造方法
    • Array :该类提供了动态创建数组和访问数组元素的静态方法
  • 反射依赖的Class
    • 用来表示运行时类型信息的对应类
      • 每个类都有唯一一个 与之相对应的Class对象
      • Class类为类类型,而Class对象为类类型对象
    • 特点
      • Class类也是类的一种, class则是关键字
      • Class类只有一个私有的构造函数,只有JVM能够创建Class类的实例
      • JVM中只有唯一一个和类相对应的Class对象来描述其类型信息
    • 获取Class对象的三种方式
      • Object 一> getClass()
      • 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
      • 通过Class类的静态方法: forName(String className)(常用)
      • 在运行期间,一个类,只有一个与之相对应的Class对象产生(单例,构造方法私有)
      • Class对象就像一面镜 子,透过这面镜子可以看到类的结构
    • 反射的主要用法
      • 如何获取类的构造方法并使用
      • 如何获取类的成员变量并使用
      • 如何获取类的成员方法并使用
  • 反射的获取源
    • 用XML来保存类相关的信息以供反射调用
    • 以注解来保存类相关的信息以供反射调用

注解

  • 定义:提供一种为程序元素设置元数据的方法
    • 元数据:元数据是添加到程序元素如方法、字段、类和包上的额外信息
    • 注解不能直接干扰程序代码的运行
    • 注解是一分钟分散式的元数据设置方式,XML是集中式的设置方式
  • java.lang.annotation.Annotation
    • 所有的注解都继承自该接口
    • public interface demo.annotation.TestAnnotation extends java.lang.annotation.Annotation
  • 编译(.java->.class)和反编译(javap -verbose
    • javac将.java编译为.class信息
    • javap -verbose反编译为可读的信息
  • 注解的功能
    • 作为特定的标记,用于告诉编译器一些信息
    • 编译时动态处理,如动态生成代码
    • 运行时动态处理,作为额外信息的载体,如获取注解信息
  • 注解的分类
    • 标准注解 : @Override. @Deprecated. @SuppressWarnings
    • 元注解 : @Retention. @Target. @Inherited. @Documented
    • 自定义注解
  • 元注解:用于修饰注解的注解,通常用在注解的定义上
    • @Target:注解的作用目标
    • @Retention:注解的生命周期
    • @Documented:注解是否应当被包含在JavaDoc文档中
    • @Inherited:是否允许子类继承该注解
  • 注解的底层实现(JDK动态代理)
    • -Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true,展示JDK动态代理中间类细节。
    • -XX:+TraceClassLoading,追踪类加载详情
  • 注解的工作原理
    • 通过键值对的形式为注解属性赋值
    • 编译器检查注解的使用范围,将注解信息写入元素属性表
    • 运行时JVM将RUNTIME的所有注解属性取出并最终存入Map里
    • 创建AnnotationInvocationHandler实例并传入前面的map
    • JVM使用JDK动态代理为注解生成代理类,并初始化处理器
    • 调用invoke方法,通过传入方法名返回注解对应的属性值
  • 意义
    • 使用注解标记需要工厂管理的实例,并依据注解属性做精细控制

控制反转

  • 控制反转IOC:Inversion of Control
    • 依托一个类似工厂的IoC容器
    • 将对象的创建、依赖关系的管理以及生命周期交由IoC容器管理
    • 降低系统在实现上的复杂性和耦合度,易于扩展,满足开闭原则
  • 依赖注入(Dependency Inversion)
    • 含义:把底层类作为参数传递给上层类,实现上层对下层的控制,而不是上层类直接new对象
    • 注入方式:Set注入、接口注入、注解注入、构造器注入
  • 梳理依赖倒置原则、IOC、DI/IOC容器的关系
    • 关系图image-20200726082248389
  • IOC容器的优势
    • 避免在各处使用new来创建类,并且可以做到统一维护
    • 创建实例的时候不需要了解其中的细节
    • 反射+工厂方法模式的合体,满足开闭原则

自研框架IOC

  • 自研IOC架构最基本功能:
    • 解析配置
    • 定位(注解)和注册对象
    • 注入对象
    • 提供通用的工具类
    • 实现的点:创建注解,提取标记对象,实现容器,依赖注入
  • 创建注解
  • 提取标记对象
    • org.simpleframework.util.ClassUtil#extractPackageClass,需要实现的功能:
      • 获取到类的加载器(获取项目发布的实际路径)
      • 通过类加载器获取到加载的资源信息
      • 依据不同的资源类型,采用不同的方式获取资源的集合
    • 为什么不让用户传入绝对路径?
      • 不够友好:不同机器之间的路径可能不相同
      • 如果打的是war包或者jar包,根本找不到路径
      • 因此通用的做法是通过项目的类加载器来获取
  • java.lang.Class#isAssignableFrom:判断某个类是否实现该接口或者是该类的子类

模板方法模式

  • 定义:围绕抽象类,实现通用逻辑,定义模板结构,部分逻辑由子类实现(复用代码、反向控制)
  • 模板方法种类:
    • 模板方法:包括下面三种方法
    • 具体方法:模板里自带的实现方法,不改变
    • 钩子方法:子类可以依据情况实现的方法
    • 抽象方法:必须让子类实现的方法

事件监听器模式

  • 回调函数:往组件(new Thread())注册自定义的方法(Runnable#run())以便组件在特定场景下调用(thread.start())
  • 事件监听器模式:监听器将监听感兴趣的事件,一旦事件发生,便做出响应。观察者模式的一种实现,解耦。
    • 事件源 ( Event Source ):发布事件,注册监听器
    • 事件监听器 ( Event Listener )
    • 事件对象 ( Event Object )
  • 观察者模式:事件源+事件对象=主题主键,事件监听器=观察者
  • spring的事件驱动模型
    • 事件:ApplicationEvent抽象类
    • 事件监听器:ApplicationListner(方式一:实现ApplicationListner接口,方式二:加上@EventListener注解)
    • 事件发布器:Publisher以及Multicaster
      • org.springframework.context.ApplicationEventPublisher:实现了这个接口就说明有能力发布容器事件了
      • org.springframework.context.event.ApplicationEventMulticaster:多线程执行监听器的方法
    • 事件源:ApplicationEvent的souce成员变量(容器本身)
    • ApplicationContext使用DefaultListableBeanFactory作为代理,而ApplicationContext的使用ApplicationEventPublisher发布事件,.ApplicationEventMulticaster才真的执行发布事件
  • org.springframework.context.PayloadApplicationEvent,
  • org.springframework.core.ResolvableType

初体验SpringAOP

  • 容器是OOP的高级工具,以低耦合低侵入的方式打通从上到下的开发通道。

  • AOP:关注点分离(Concern Separation),不同的问题交给不同的部分去解决,每部分专注解决自己的问题

    • Aspect Oriented Programming就是其中一种关注点分离的技术
    • 通用化功能的代码实现即切面Aspect
    • Aspect之于AOP ,就相当于Class之于OOP , Bean之于Spring
  • AOP术语

    • 切面Aspect :将横切关注点逻辑进行模块化封装的实体对象
    • 通知Advice :好比是Class里面的方法,还定义了织入逻辑的时机
    • 连接点Joinpoint ,允许使用Advice的地方
    • spring aop默认只支持方法级别的jointpoint
    • 切入点Pointcut :定义-系列规则对Joinpoint进行筛选
    • 目标对象Target :符合Pointcut条件,要被织入横切逻辑的对象
    • Advice的种类
      • BeforeAdvice:在joinPoint前被执行的advice
      • AfterAdvice : 好比try..catch..finaly里面的finally
      • AfterReturningAdvice : 在Joinpoint执行流程正常返回后被执行
      • AfterThrowingAdvice : Joinpoint执行过程中抛出异常才会触发
      • AroundAdvice :在Joinpoint前和后都执行,最常用的Advice
      • Introduction(引入型Advice,很少使用):
        • 为目标类引入新接口,而不需要目标类做任何实现
        • 使得目标类在使用的过程中转型成新接口]对象,调用新接口的方法
        • 让任意一组类实现共同的接口,让其有能力转换为执行子类
    • AOP是0OP里的”寄生虫”
      • AOP需要OOP理解自己的语义,所以并不像单独使用这么灵活
      • 织入:将Aspect模块化的横切关注点集成到OOP里
      • 织入器:完成织入过程的执行者,如ajc
      • Spring AOP则会使用一组类来作为织入器以完成最终的织入操作
  • 单个Aspcet的执行顺序:

  • image-20200809094340227

  • 多个Aspect的执行顺序image-20200809094757568

  • 源码分析

    /**
    * aspect使用大全
    *
    * @author codingprh
    */
    @Component
    @Aspect
    public class ServiceAspect {

    @Pointcut("execution(* com.imooc.service..*.*(..))")
    public void embed() {
    }

    @Before("embed()")
    public void before(JoinPoint joinPoint) {
    System.out.println("开始调用" + joinPoint);
    }

    @After("embed()")
    public void after(JoinPoint joinPoint) {
    System.out.println("结束调用" + joinPoint);
    }

    @Around("embed()")
    public Object aroundme(JoinPoint joinPoint) {
    long startTime = System.currentTimeMillis();
    Object returnValue = null;

    System.out.println("开始计时" + joinPoint);

    try {
    returnValue = ((ProceedingJoinPoint) joinPoint).proceed();
    } catch (Throwable throwable) {
    throwable.printStackTrace();
    System.out.println("执行失败" + joinPoint);
    } finally {
    System.out.println("耗时=" + (System.currentTimeMillis() - startTime) + "ms");
    }
    return returnValue;
    }

    @AfterReturning(pointcut = "embed()", returning = "returnValue")
    public void afterReturning(JoinPoint joinPoint, Object returnValue) {
    System.out.println("无论是空置还是有值返回" + joinPoint + ",返回值是" + returnValue);
    }

    @AfterThrowing(pointcut = "embed()", throwing = "exception")
    public void afterException(JoinPoint joinPoint, Exception exception) {
    System.out.println("抛出异常通知" + joinPoint + ",异常信息为" + exception.getMessage());
    }

    @DeclareParents(value = "com.imooc.controller..*", defaultImpl = com.imooc.declareParents.NoahDeclareParentsImpl.class)
    public NoahDeclareParents noahDeclareParents;


    }

AOP实现原理和代理模式

  • 静态代理 :OOP的局限,下面是静态代理改进。
  • 溯源ClassLoader
    1. 通过带有包名的类来获取对应class文件的二 进制字节流
    2. 根据读取的字节流,将代表的静态存储结构转化为运行时数据结构
    3. 生成一 个代表该类的Class对象,作为方法区该类的数据访问入口
  • 根据一定规则去改动或者生成新的字节流,将切面逻辑织入其中
    • 行之有效的方案就是取代被代理类的动态代理机制
    • 根据接口或者目标类,计算出代理类的字节码并加载到JVM中去
  • 动态代理总结:
    • JDK动态代理:基于反射机制实现,要求业务类必须实现接口
      • JDK原生,在JVM里运行较为可靠
      • 平滑支持JDK版本的升级
    • CGLIB :基于ASM机制实现,生成业务类的子类作为代理类
      • 被代理对象无需事实现接口,能实现代理类的无侵入
    • SpringAop同时使用JDK动态代理和CGLIB,默认策略,Bean实现了接口则用JDK,否则使用CGLIB

SpringAOP的实现原理之JDK动态代理

  • 静态代理是生成.java硬编码生成的代理对象。而JDK动态代理是没生成代理的class对象。

  • 程序要求运行时动态生成类的字节码,并加载到JVM中

  • 要求【被代理的类】必须实现接口

  • 并不要求【代理对象】去实现接口,所以可以服用代理对象的逻辑

  • java.lang.reflect.Proxy:创建动态代理类

    • java.lang.reflect.Proxy#newProxyInstance:创建代理类
      • ClassLoader loader:类加载器
      • Class<?>[] interfaces:代理那一组接口
      • InvocationHandler h:调用横切织入逻辑
    • 生成的目标代理对象,对于代理对象对于用户来说是透明的
  • java.lang.reflect.InvocationHandler:

    • 等价@Aspect功能,只有实现了该接口才具有jdk动态代理的能力。管理横切逻辑
    • invoke:唯一的方法
      • Object proxy:代理对象
      • Method method:目标对象的方法
  • 本质原理:生成*$Proxy的字节码,跟注解原理分析一致

    /*
    * Generate the specified proxy class.
    */
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
    proxyName, interfaces, accessFlags);

SpringAOP的实现原理之CGLIB动态代理

  • 代码生成库: Code Generation Library
  • 不要求被代理类实现接口
  • 内部主要封装了ASM Java字节码操控框架(等价使用es,而非使用es的底层lua)
  • 动态生成子类以覆盖非final的方法,绑定钩子回调自定义拦截器(net.sf.cglib.proxy.MethodInterceptor)
  • net.sf.cglib.proxy.MethodInterceptor:
    • 具有回调能力,等价于 InvocationHandler,也就是等价于定义切面逻辑
    • 前三个参数和java.lang.reflect.InvocationHandler的invoke一致
    • 第四个参数MethodProxy:是动态代理方法(因此这里解决了jdk动态代理为什么要实现接口,还要传入被代理对象的实现)
  • net.sf.cglib.proxy.Enhancer:
    • 生成代理对象

自研AOP框架

  • 使用CGLIB来实现:不需要业务类实现接口,相对灵活

  • 解决标记的问题,定义横切逻辑的骨架

  • 定义Aspect横切逻辑以及被代理方法的执行顺序

  • 将横切逻辑织入到被代理的对象以生成动态代理对象

  • 实现Aspect横切逻辑以及被代理方法的定序执行

    • 创建MethodInterceptor的实现类
    • 定义必要的成员变量—被代理的类以及Aspect列表
    • 按照Order对Aspect进行排序
    • 实现对横切逻辑以及被代理对象方法的定序执行
  • 增强AOP功能,集成AspectJ,更细粒度的控制

    • 提供了完整的AOP解决方案,是AOP的Java实现版本
      • 定义切面语法以及切面语法的解析机制
      • 提供了强大的织入工具
    • 图文比较
      • springAop和AspectJ比较
    • AspectJ框架的织入时机:静态织入(前面2中)和LTW(load time weaving)
    • 编译时织入 :利用ajc(而不是javac) ,将切面逻辑织入到类里生成class文件
    • 编译后织入:利用ajc ,修改javac编译出来的class文件
    • 类加载期织入:利用java agent ,在类加载的时候织入切面逻辑
    • AspectJ的性能比spring aop要强大,因为即使是CGLIB(底层是ASM)修改字节码也是运行时通过继承生成的代理对象,而JDK动态代理通过接口反射来生成代理对象,但是AspectJ是通过在类加载的时候就完成了织入逻辑。
      • springAOP仅仅用到了AspectJ的切面语法,并没有使用ajc编译工具。因为完成动态代理在启动项目加载单例非延迟加载的对象,就完成了bean的代理对象生成,并且加入缓存,能够满足性能要求了。

适配器模式

  • org.springframework.aop.framework.adapter.AdvisorAdapter:适配器模式,只有在spring当中才有advisor的概念,通过this这个类转换为外部aop框架能够识别的MethodInterceptor。

  • 一图胜前文AdvisorAdapter

自研SpringMVC框架

  • spring-mvc架构图:spring-MVC模块
  • ControllerRequestProcessor实现分析
    • 针对特定请求,选择匹配的Controller方法进行处理
    • 解析请求里的参数及其对应的值,并赋值给Controller方法的参数
    • 选择合适的Render ,为后续请求处理结果的渲染做准备

#SpringMVC源码分析

WebApplicationInitializer

  • 架构图:介绍springmvc的tomcat容器和spring容器是怎么初始化的WebApplicationInitializer
  • AbstractAnnotationConfigDispatcherServletInitializer#createRootApplicationContext:将service和repositories存放到该上下文中。分层设计,解耦。
  • AbstractAnnotationConfigDispatcherServletInitializer#createServletApplicationContext:将springMVC相关的存放到该上下文中。

Spring MVC源码分析流程

  • 建立请求和Controller方法的映射集合的流程
  • 根据请求查找对应的Controller方法的流程
  • 请求参数绑定到方法形参,执行方法处理请求,渲染视图的流程

image-20200820073337683

DispatcherServlet

  • 架构分析图DispatcherServlet

RequestMappingHandlerMapping

  • 流程架构图:建立请求路径和Controoler方法的映射关系

RequestMappingHandlerMapping