240 次浏览

Spring整理

3 月 31, 2023
  • Spring
    • 一句话概括:轻量级、非侵入式、控制反转和面向切面
    • 优点
      • IOC DI支持
        spring核心:一个大的工厂容器,可以维护所有的对象的创建和依赖关系,Spring工厂生产Bean并管理Bean的生命周期,以实现高内聚低耦合
      • AOP编程支持
        spring提供了面向切口编程,可以方便实现对程序进行权限拦截,运行监控
      • 声明式事务支持
        支持通过配置完成对事务的管理 ,不用硬编码方式,之前的重复的事务提交回滚的JDBC代码都可以不用写
      • 快捷测试支持
        对junit提供支持,可以通过注解快速测试spring程序
      • 快速集成
        内部集成了Struts
        Hibernate、MyBatis、Quartz
      • 复杂API模板封装

        对JDBC、javaMail、远程调用等,都提供了模板化的封装,使得应用难度降低

    • 组成
      • Core Container 核心模块,其余可选
    • 常用注解
      • 按模块功能分
        • Web:
          • Controller:组合注解(组合了Component注解)在MVC的C层(控制层)
          • RestController:组合注解,相当于 Controller和ResponseBody组合//注解在类上,该Controller的所有方法都默认加上了ResponseBody
          • RequestMapping:用于映射web请求,包括访问路径和参数,如果是Restful风格接口,可以根据请求类型使用不同风格注解
            • GetMapping
            • PostMapping
            • PutMapping
            • DeleteMapping
          • ResponseBody //将返回值放在一个Response内,而不是页面,通常用户返回json数据
          • RequestBody //允许请求的参数在request体中而不是在地址后面
          • PathVariable//映射 URL 绑定的占位符
        • 容器
          • Component //表示一个带注释的类是一个“组件”,成为Spring管理的Bean,使用基于注解的配置和类路径扫描时,类被是为自动检测候选对象,同时,Component是一个元注解。
          • Service// 组合了Component注解,应用在service层(业务逻辑)
          • Repository//组合了Component注解,应用在dao层(数据访问)
          • Autowired//自动注入,由Spring依赖注入工具,BeanPostProcessor、BeanFactoryPostProcessor自动注入
          • Qualifier//通常和Autowoired一起用,对注入的过程做更多控制,两个以上相同类型的Bean时,Spring无法抉择,可以用
          • Configuration//声明当前类是一个配置类
          • Value//可用在字段,构造器参数和方法参数,指定一个默认值,支持# {}和${}两种方式,一般将SpringBoot中,application.properties配置的属性值赋值给变量
          • Bean//注解在方法上,声明返回类型为Bean,返回Bean对应的类中定义init方法和destroy方法,在@ Bean(initMethod=”init”,destroyMethod=”destroy”)定义,构造之后执行init,销毁之前执行destroy
          • Scope//定义创建Bean的模式:
            • Singleton
            • Prototype
            • Request
            • Session
            • GlobalSession
        • AOP
          • Aspect//声明一个切面(类)上使用:After、Before、Around定义建言(advice),可直接拦截规则(切点)作为参数
            • After在方法执行之后执行(方法上)
            • Before在方法执行之前执行(方法上)
            • Around在方法执行之前与之后执行(方法上)
            • PointCut声明切点在java配置类在中使用@ EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持(类上)
        • 事务:Transactional //声明式开启事务
    • 涉及设计模式
      • 工厂模式:Spring容器本身,BeanFactory、ApplicationContext创建bean对象
      • 代理模式:AOP通过代理模式实现
        • 动态代理
        • 静态代理
      • 三、单例模式:Spring中Bean默认式单例的,有利于容器管理
      • 模板模式:jdbcTemplate、RestTemplate等以Template结尾的对数据库、网络进行操作的模板类,都使用到了模板模式
      • 观察者模式:事件驱动模型
      • 适配器模式:AOP增强通知(Advice),Spring MVC的Controller
      • 策略模式:Resource接口,不同的实现类,会根据不同的策略去访问资源
    • IOC 和DI//解耦,专心开发,不关心对象间的依赖
      • Java面向对象编程,原生在代码中(引用它的对象负责)创建对象和对象的依赖
      • IOC(控制反转):容器负责控制所有对象生命周期、对象间关系//思想
      • DI(依赖注入):容器在实例化对象时,把它依赖的类注入给它//实现
    • Spring IOC实现机制
      • Bean定义//通过配置文件定义,解析成一个类型
        • beans.properities:
          userDao:cn,fighter3.bean.UserDao//<Key,Value>→<beanName,class>
        • BeanDefinition.java//定义类,配置文件中bean定义的实体
      • Spring 容器
        • 加载资源
        • 实例创建
        • 实例缓存
      • 仓库HashMap
    • BeanFactory 和ApplicantContext
      • BeanFactory:
        • Bean工厂,Spring框架基础设施,面向Spring本身
        • 类通用工厂,创建并管理各种类对象
        • Spring提供了多种实现,eg:XmlBeanFactory,在3.2废弃,XmlBeanDefinitionReader、DefaultListableBeanFactory
      • ApplicantContext:
        • 应用上下文,建立在BeanFactory上,面向使用Spring框架的开发者,提供了更多面向实际应用的功能
        • 继承自HierachicalBeanFactory和ListableBeanFactory接口,通过其他接口拓展了BeanFactory的功能
          • Bean instantiation / wiring
          • Bean的实例化/串联
          • 自动的BeanPostProcessor注册
          • 自动的BeanFactoryPostProcessor注册
          • 方便的MessageSource访问
        • 预加载,每一个bean都在ApplicationContext启动之后实例化
    • Spring容器启动阶段
      • 容器启动和Bean实例化
        • 容器启动://加载和解析配置文件,保存到对应的Bean定义中
          • 加载配置文件(Congiguration MetaData)
          • 分析配置信息//可能依赖某些工具类BeanDefinitionReader对加载的Congiguration MetaData进行解析分析
          • 装配到BeanDefinition
          • 其他后处理//把保存了Bean定义必要信息的BeanDefinition 注册到相应的BeanDefinitionRegistry,容器启动完成
        • Bean实例化阶段
          • 实例化对象
          • 装配依赖
          • 生命周期回调
          • 对象其他处理
          • 注册回调接口
    • Spring Bean生命周期
      • Spring中,BeanFactory和拓展容器ApplicationContext实例化时机不一样
        • BeanFactory采用延迟初始化,第一次getBean()时才实例化Bean,
        • ApplicationContext启动时就会实例化所有的Bean定义
      • 生命周期大致分为四个阶段:
        • 生命周期
        • 实例化Instantiation 1、
        • 属性赋值Populate 2、//为bean设置相关属性和依赖
        • 初始化Initialization 3、4、5、6、7
        • 销毁Destruction8、9、10//使用前会注册销毁的相关调用接口
      • 实例分析生命周期细节
      • 源码中:
        • AbstractBeanFactory.doGetBean()方法可以看到Bean实例化、赋值、初始化过程
        • ConfigurableApplicationContext.colse()可以看到销毁过程
    • Bean定义和依赖定义的方式
      • 直接编码
      • 配置文件 //spring读取配置文件,完成依赖关系注入
        • properties
        • xml
      • 注解方式//使用注解修饰后,spring扫描注解,完成依赖关系的注入
    • 依赖注入的方法
      • 构造方法注入//实例化时完成注入
        调用类的构造方法,将接口实现类通过构造方法变量注入
      • 属性注入//实例化和赋值分开
        通过setter方法完成调用类所需依赖的注入
      • 工厂方法注入
        • 静态工厂注入
          通过调用静态工厂的方法获取需要的对象
        • 非静态工厂注入
          实例工厂,工厂方法非静态,需要先new一个工厂实例,再调用普通实例方法
    • Spring自动装配
      Spring IOC 知道所有Bean的配置信息,通过java反射机制可以获得类的构造器、属性等,掌握这些信息ioc可以根据一定规则进行自动装配,无需显式进行依赖配置
      • 四种装配类型
        • byType
        • byName
        • constructor:和byType类似,针对构造函数注入而言:
          • eg:Boss有一个构造函数,需要一个Car类型的入参,
            • Spring IOC在容器中找到该Bean的话,就将该Bean作为Boss的入参
            • 如果找不到的话,Spring将抛出异常
        • autodetect:根据Bean的自省机制决定用byType还是constructor进行自动装配,
          • 如果Bean提供了默认构造函数,采用byType
          • 未提供,采用constructor
    • Spring Bean的作用域
      • 五种作用域
        • singleton//单例方式存在,Bean默认作用域
        • prototype(原型)//每次从容器重调用Bean时,会返回一个新的实例
        • 以下三种仅仅在web中作用:
          • request//每次http请求都会产生一个bean,该bean只在此http request中有效
          • session//同一个http session共享一个bean,不同http session使用不同bean
          • global-session//同一个全局session使用同一个bean,只基于Protlet的web应用,spring5后不存在
    • Spring 中单例Bean线程安全问题
      • 单例bean,是全局Bean,所有线程共享,如果是有状态的,即会对Bean的成员进行写操作,那存在线程安全问题
      • 但如果说是一个无状态的Bean,即现成的操作不会对Bean中成员变量执行查询以外的操作,那是安全的。eg:
        • Spring MVC 的Controller、
        • Service
        • Dao等
      • 解决办法
        • 将Bean中成员变量保存在ThreadLocal中,
          ThreadLocal能保证多线程下变量的隔离
        • 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量存在ThreadLocal中。
    • 循环依赖//自己依赖自己,或者和别的bean相互依赖,仅单例bean存在循环依赖,原型(prototype)下,spring会直接抛出异常
      • spring不支持基于构造器注入的循环依赖,但AB循环依赖时。存在支持循环依赖情况:
        • 第四种可以,第五种不可以的原因:
          spring在创建bean时,会根据自然排序进行创建,A会先于B进行创建
        • 当循环依赖的实例都采用属性(setter)方法注入时,spring可以支持,
        • 都采用构造器注入时,不支持,
        • 当既采用构造器注入,又采用属性注入时,(看自然排序结果)
      • spring解决的循环依赖情况:使用“三级缓存”//实例化和赋值为分开的步骤的前提下
        • 单例bean初始化,有三步:
          • 实例化
          • 属性赋值 //注入发生在此
          • 初始化
        • 三级缓存定义:
          • 一级:Map<String,Object> singletonObjects //单例池,实例化,属性赋值(注入),初始化完成的bean实例
          • 二级:Map<String,Object> earlySingletonObjects //早期曝光的对象,实例化完成的bean实例
          • 三级:Map<String,ObjectFactory<?>> singletonFactories //早期曝光对象工厂,bean创建工厂,以便之后有机会创建代理对象
        • 三级缓存解决循环依赖例子:
          • 1、创建实例A,实例A时把A对象工厂放进三级缓存//A实例化,但对象不完整,先曝光下
          • 2、A注入属性时,发现依赖B,但B还未创建,去实例化B
          • 3、B注入属性时,发现依赖A,从缓存里找A对象//从缓存(依次从一级到三级缓存)查询A,
            从三级缓存,通过对象工厂拿到A,发现A存在,但不完整,遂把A放到二级缓存里,同时删除三级缓存中的A,此时B实例化并初始化完成,把B放入一级缓存
          • 4、A继续属性赋值,从一级缓存里拿实例化初始化完成的B对象,A的创建也完成,删除二级缓存里的A,同时把A放入一级缓存。
          • 5、最后一级缓存里保存着实例化初始化都完成的A、B对象。
        • 一定是三级缓存,二级缓存不行?
          • 二级缓存不行,主要是为了生成代理对象,如果没有代理对象使用二级缓存解决也可以,但存在代理,只有三级缓存可以解决。(三级缓存放的是生成具体对象的匿名内部类//获取Object时,可以生成代理对象,也可以返回普通对象),三级缓存保证访问的是同一个对象
      • @ Autowired实现原理
        关键为:AutowiredAnnotationBeanPostProcessor
        • 通过后置处理器AutowiredAnnotationBeanPostProcessor完成 //Bean初始化阶段,有BeanPostProcessor(Bean后置处理器)进行前后置处理
        • Spring创建bean过程中(属性赋值阶段),会调到doCreateBean(){ populateBean() //为bean进行属性填充,完成自动装配}
        • populateBean()中调用了两次BeanPostProcessor,
          • 1、为了判断是否需要属性填充
            • 不需要,直接进行return
            • 需要,继续向下执行,进行第二次BeanPostProcessor调用
          • 2、调用

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注