• 记录-spring


    1. Spring 概述

    Spring 是一个开源的轻量级 Java 开发框架,目的是为了解决企业级应用开发的业务逻辑层和其他层的耦合问题,为开发 Java 应用提供全面的基础架构支持,解决企业级应用开发的复杂性,简化 Java 开发

    Spring 核心的两个特性:IOC (控制反转,依赖注入)、AOP

    为了降低 Java 开发的复杂性,Spring 采用了以下 4 中策略:

    • 基于 POJO 的轻量级和最小侵入性编程
    • 通过依赖注入和面向接口实现松耦合
    • 基于切面和惯例进行声明式编程
    • 通过切面和模版减少样板式代码
    2.  什么是 IOC 容器?

    IOC 容器是 spring 基础模块的核心,控制反转的理论思想,依赖注入的手段实现,将对象的控制权转移,交由 spring 来创建、管理、装配对象,通过 map 数据结构来存储。整个 bean 的生命周期都由 spring 来管理

    IOC 容器的创建过程:

    • 调用 prepareRefresh 方法做容器创建前的准备工作,设置其启动日期和活动标志以及执行属性源的任何初始化(属性资源、监听器、事件)。
    • 调用 obtainFreshBeanFactory 创建容器 DefaultListableBeanFactory ,设置一些初始化属性(BeanPostProcessor,Aware接口的子类等)
    • 通过 BeanDefinitionReader 加载 bean 的定义信息 BeanDefinition
    • 调用 invokeBeanFactoryPostProcessors  处理 bean 的定义信息(如:PalceHodlerConfigurerSupport 对占位符的处理)
    • 调用 registerBeanPostProcessors 向容器中注册 BeanPostProcessors ,方便后续对 bean 对象完成功能扩展 
    • 初始化消息资源、事件多播器、添加 bean 的监听器
    • 通过反射的方式将 BeanDefinition 实例化 instantiateBean(默认无参构造器,ctor.newInstance()) 为具体的对象(getBeandoGetBeancreateBeandoCreateBean)
    • 对象的初始化 initializeBean 过程(填充属性population,调用 aware 子类方法,调用 BeanPostProcessors 的前置处理方法,调用 init-method 方法,调用 BeanPostProcessors 的后置处理方法)
    • 生成完整对象,通过 getBean() 获取
    • 容器关闭销毁对象
    3. Bean 的生命周期
    • 调用 instantiateBean 通过无参构造器的 newInstance() 实例化 bean 对象
    • 调用 population() 填充属性 (循环依赖)
    • 调用 initializeBean() 初始化 bean,
      • 调用 invokeAwareMenthod 完成 beanName、beanClassLoader、beanFactory 属性设置
      • 调用 applyBeanPostProcessorsBeforeInitialization() 应用 BeanPostProcessors 的前置处理方法
      • 调用 invokeInitMenthod()
        • 判断是否实现了 InitializingBean 接口,若实现了,则调用 afterPropertiesSet() 
        • 判断是否有自定义的初始化方法,若有,则调用 invokeCustomInitMehtod()
      • 调用 applyBeanPostProcessorsAfterInitialization() 应用 BeanPostProcessors 的后置处理方法 (aop 增强,AbstractAutoProxyCreator)
    • 调用 registerDisposableBeanIfNecessary 注册 bean 销毁时的工作:DistructionAwareBeanPostProcessors,DisposableBean 接口,自定义 destroy 方法
    4. Spring 是如何解决循环依赖的

    循环依赖:一个 bean 对象的成员属性是另一个 bean 对象,如:A 依赖 B,B 依赖 A,bean A 在创建的过程中,进行属性填充时,需要引用 bean B,而 bean B 在创建的过程中进行属性填充时也需要应用 bean A,这样就形成了一个闭环

    Spring 是通过三级缓存来解决循环依赖的问题的,ioc 容器中维护了三个 map 结构:singletonObjects(一级缓存)、earlySingletonObejcts(二级缓存)、singletonFactories(三级缓存),一级缓存用来存放完整对象,二级缓存用来存放不完整对象(一般是创建中未初始化完成),三级缓存用来存放 ObjectFactory 函数式接口,通过 getEarlyBeanReference 来判断返回代理对象还是原始对象,保证容器在运行的过程中同名的 bean 只有一个

    三级缓存:在 doCreateBean 中执行完 createBeanInstance 之后判断是否为单例、是否创建中、是否允许早期暴露来判断是否通过 addSingletonFactoy 添加到三级缓存中

    二级缓存:在 getSingleton 中第一次从三级缓存确定对象是代理对象还是普通对象的时候,同时删除三级缓存

    一级缓存:生成完整对象之后,在 addSingleton 中放到一级缓存,删除二三级缓存

    5. BeanFactory 和 FactoryBean 的区别

    相同点:两者都是用来创建 bean 对象的

    不同点:BeanFactory 是 IOC 容器的根接口,为 Spring 工厂提供了规范,使用 BeanFactory 创建 bean 对象需要遵循完整的生命周期流程;而 FactoryBean 提供了三个方法:isSingleton() -- 是否是单例、getObjectType() -- 获取返回对象类型、getObject() -- 自定义创建的过程(new、反射、动态代理),很容易的创建一个由 spring 容器管理的 bean 对象

    6. spring 中用到的设计模式

    单例模式:spring 中 bean 默认都是单例的

    工厂模式:BeanFactory

    原型模式:scope 为 prototype

    模版方法模式:postProcessBeanFactory,onRefresh

    装配者模式:BeanWrapper

    策略模式:XmlBeanDefiniationReader

    观察者模式:listener,event,multicast

    适配器模式:adapter

    7. spring aop 原理

    aop 面向切面,是 ioc 容器的一个扩展,通过 BeanPostProcessors 的后置处理方法,来对 bean 进行功能扩展实现增强

    1. 代理对象的创建过程(advice,切面,切点)
    2. 通过jdk或者cglib的方式来生成代理对象
    3. 在执行方法调用的时候,会调用到生成的字节码文件中,直接回找到DynamicAdvisoredInterceptor类中的intercept方法,从此方法开始执行
    4. 根据之前定义好的通知来生成拦截器链
    5. 从拦截器链中依次获取每一个通知开始进行执行,在执行过程中,为了方便找到下一个通知是哪个,会有一个CglibMethodInvocation的对象,找的时候是从-1的位置一次开始查找并且执行的。

    aop 通知:before(前置通知)、after(返回通知)、after_returning(正常返回通知)、after_throwing(异常返回通知)、round(环绕通知)

    8. Spring 是如何事务回滚

    spring 的事务是由 aop 来实现的,首先要生成具体的代理对象,然后按照 aop 的整套流程来执行具体的操作逻辑,正常情况下要通过通知来完成核心功能,但是事务不是通过通知来实现的,而是通过一个 TransactionInterceptor 来实现的,然后调用 invoke 来实现具体的逻辑

    1、先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务

    2、当需要开启的时候,获取数据库连接,关闭自动提交功能,开起事务

    3、执行具体的sql逻辑操作

    4、在操作过程中,如果执行失败了,那么会通过 completeTransactionAfterThrowing 看来完成事务的回滚操作,回滚的具体逻辑是通过 doRollBack 方法来实现的,实现的时候也是要先获取连接对象,通过连接对象来回滚

    5、如果执行过程中,没有任何意外情况的发生,那么通过 commitTransactionAfterReturning 来完成事务的提交操作,提交的具体逻辑是通过 doCommit 方法来实现的,实现的时候也是要获取连接,通过连接对象来提交

    6、当事务执行完毕之后需要清除相关的事务信息 cleanupTransactionInfo

    9. spring 事务的传播行为

    propagation_required:当前存在事务,则加入事务;当前没有事务,则创建一个新的事务,默认

    propagation_requires_new: 不管有没有事务都创建一个新的事务,若当前存在事务,则挂起,等待内层事物处理完毕,恢复上层事物

    propagation_supports: 如果当前存在事务,则加入当前事物;若当前没有事务,则以非事务的方式继续运行

    propagation_not_supported: 不支持事务,若当前存在事务,则挂起当前事务,等待内层执行结束后在恢复

    propagation_nested: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于 propagation_required。

    propagation_mondatory: 如果当前存在事务,则加入该事务;如果不存在事务,则抛出异常

    propagation_never: 以非事务的方式运行,若当前存在事务,则抛出异常

    10. Spring AOP and AspectJ AOP 有什么区别?

    AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。

    (1) AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。

    (2) Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP

    对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

    11. JDK动态代理和CGLIB动态代理的区别

    Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:

    • JDK动态代理只提供接口的代理,不支持类的代理。核心 InvocationHandler 接口和 Proxy 类,InvocationHandler 通过 invoke() 方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy 利用 InvocationHandler 动态创建一个符合某一接口的的实例, 生成目标类的代理对象。

    • 如果代理类没有实现 InvocationHandler 接口,那么 Spring AOP 会选择使用 CGLIB 来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现 AOP。CGLIB  是通过继承的方式做的动态代理,因此如果某个类被标记为  final,那么它是无法使用  CGLIB  做动态代理的。

    静态代理与动态代理区别在于生成 AOP  代理对象的时机不同,相对来说  AspectJ 的静态代理方式具有更好的性能,但是 AspectJ  需要特定的编译器进行处理,而 Spring AOP 则无需特定的编译器处理。

  • 相关阅读:
    推荐有关微信开发的十个开源项目
    curl 常见错误码
    mysql修改root密码
    BAT批处理之文件与文件夹操作代码(附xcopy命令详解)
    UE4 Pak包加载
    libcurl 文件上传
    win7右键在目录当前打开命令cmd窗口
    SQLiteDeveloper破解
    Excel替换应用
    解决局域网2级路由互相连接共享的问题
  • 原文地址:https://www.cnblogs.com/zhuozhang/p/14883003.html
Copyright © 2020-2023  润新知