-
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、调用
-
-
-
-