Spring学习笔记
Spring的优势
⽅便解耦,简化开发
通过Spring提供的IoC容器,可以将对象间的依赖关系交由Spring进⾏控制,避免硬编码所造成的
过度程序耦合。⽤户也不必再为单例模式类、属性⽂件解析等这些很底层的需求编写代码,可以更
专注于上层的应⽤。AOP编程的⽀持
通过Spring的AOP功能,⽅便进⾏⾯向切⾯的编程,许多不容易⽤传统OOP实现的功能可以通过
AOP轻松应付。声明式事务的⽀持
@Transactional
可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式⽅式灵活的进⾏事务的管理,提⾼
开发效率和质量。⽅便程序的测试
可以⽤⾮容器依赖的编程⽅式进⾏⼏乎所有的测试⼯作,测试不再是昂贵的操作,⽽是随⼿可做的
事情。⽅便集成各种优秀框架
Spring可以降低各种框架的使⽤难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、
Quartz等)的直接⽀持。降低JavaEE API的使⽤难度
Spring对JavaEE API(如JDBC、JavaMail、远程调⽤等)进⾏了薄薄的封装层,使这些API的使⽤
难度⼤为降低。源码是经典的 Java 学习范例
Spring的源代码设计精妙、结构清晰、匠⼼独⽤,处处体现着⼤师对Java设计模式灵活运⽤以及对
Java技术的⾼深造诣。它的源代码⽆意是Java技术的最佳实践的范例。
Spring IoC
bean的生命周期
bean的生命周期是指一个bean对象从创建到销毁的过程. bean不等于普通对象, 是里胡一个java对象只是bean的生命周期过程的一步,只有走完了流程, 才能称之为bean. 核心过程如下:
实例化bean: 主要通过反射技术实例化
设置对象属性(依赖注入)
处理Aware接口
如果实现了xxxAware接口, 会将相关的xxxAware实例注入给bean
如果实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法
如果事项了BeanFactoryAware接口, 会调用它实现的setBeanFactory()方法, 传递的是Spring工厂
如果实现了ApplicationContextAware接口, 会调用它实现的setApplicationContext()方法,传递的是Spring上下文
BeanPostProcessor:
如果实现了此接口,会调用 postProcessBeforeInitialization()方法
InitializingBean与 init-method:
实现bean初始化的一些逻辑
如果配置了init-method,则会自动调用此方法,完成自定义初始化逻辑
如果实现了BeanPostProcessor接口,会调用 postProcessAfterInitialization()方法
DisposableBean:
当bean不需要使用时, 会经过清理阶段, 如果实现了此接口, 则会调用它实现的destroy()方法
最后,如果配置了destroy-method:则会自动调用此方法,完成自定义销毁逻辑
高级特性
lazy-Init 延迟加载
设置 lazy-init 为 true 或者注解 @Lazy 的 bean 将不会在 ApplicationContext 启动时提前被实例化,⽽是第⼀次向容器
通过 getBean 索取 bean 或者在 bean被其他立即实例化的bean引用时实例化的。
FactoryBean 和 BeanFactory
BeanFactory接⼝是容器的顶级接⼝,定义了容器的⼀些基础⾏为,负责⽣产和管理Bean的⼀个⼯⼚,
具体使⽤它下⾯的⼦接⼝类型,⽐如ApplicationContext;此处我们重点分析FactoryBean
Spring中Bean有两种,⼀种是普通Bean,⼀种是⼯⼚Bean(FactoryBean),FactoryBean可以⽣成
某⼀个类型的Bean实例(返回给我们),也就是说我们可以借助于它⾃定义Bean的创建过程。
自定义FactoryBean
1 | // 可以让我们⾃定义Bean的创建过程(完成复杂Bean的定义) |
后置处理器
Spring提供了两种后处理bean的扩展接⼝, 分别为 BeanPostProcessor 和BeanFactoryPostProcessor,两者在使⽤上是有所区别的。⼯⼚初始化(BeanFactory)—> Bean, 对象在BeanFactory初始化之后可以使⽤BeanFactoryPostProcessor进⾏后置处理, 做⼀些事情在Bean对象实例化(并不是Bean的整个⽣命周期完成)之后可以使⽤BeanPostProcessor进⾏后置处理做⼀些事情
注意:对象不⼀定是springbean,⽽springbean⼀定是个对象
自动装配
有五种自动装配方式, 可以用来知道Spring容器用自动装配方式来依赖注入:
- no: 默认不进行自动装配, 通过显式设置ref属性来进行装配
- byName: 通过参数名自动装配, Spring容器在配置文件中发现bean的autowire属性被设置成byName,止呕容器试图装配和该bean的属性具有相同名字的bean
- byType: 通过参数类型自动装配, Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
- constructor:这个方式类似于byType,但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
- autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。
SpringAOP及应用
AOP的实现
Spring 实现AOP思想使⽤的是动态代理技术
默认情况下,Spring会根据被代理对象是否实现接⼝来选择使⽤JDK还是CGLIB。当被代理对象没有实现
任何接⼝时,Spring会选择CGLIB。当被代理对象实现了接⼝,Spring会选择JDK官⽅的代理技术,不过
我们可以通过配置的⽅式,让Spring强制使⽤CGLIB
Spring 声明式事务的⽀持
编程式事务:在业务代码中添加事务控制代码,这样的事务控制机制就叫做编程式事务
声明式事务:通过xml或者注解配置的⽅式达到事务控制的⽬的,叫做声明式事务
事务的四大特性
原⼦性(Atomicity) 原⼦性是指事务是⼀个不可分割的⼯作单位,事务中的操作要么都发⽣,要么都
不发⽣。从操作的⻆度来描述,事务中的各个操作要么都成功要么都失败⼀致性(Consistency)事务必须使数据库从⼀个⼀致性状态变换到另外⼀个⼀致性状态。
例如转账前A有1000,B有1000。转账后A+B也得是2000。
⼀致性是从数据的⻆度来说的,(1000,1000) (900,1100),不应该出现(900,1000)隔离性(Isolation)事务的隔离性是多个⽤户并发访问数据库时,数据库为每⼀个⽤户开启的事务,
每个事务不能被其他事务的操作数据所⼲扰,多个并发事务之间要相互隔离。
⽐如:事务1给员⼯涨⼯资2000,但是事务1尚未被提交,员⼯发起事务2查询⼯资,发现⼯资涨了2000
块钱,读到了事务1尚未提交的数据(脏读)持久性(Durability)持久性是指⼀个事务⼀旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发⽣故障
也不应该对其有任何影响。
事务的隔离级别
Serializable(串⾏化):可避免脏读、不可重复读、虚读情况的发⽣。(串⾏化) 最⾼
Repeatable read(可重复读):可避免脏读、不可重复读情况的发⽣。(幻读有可能发⽣) 第⼆
该机制下会对要update的⾏进⾏加锁Read committed(读已提交):可避免脏读情况发⽣。不可重复读和幻读⼀定会发⽣。 第三
Read uncommitted(读未提交):最低级别,以上情况均⽆法保证。(读未提交) 最低
事务隔离级别 脏读 不可重复度 幻读 Read uncommitted(读未提交) 是 是 是 Read committed(读已提交) 否 是 是 Repeatable read(可重复读) 否 否 是 Serializable(串行化) 否 否 否
Spring设计模式
工厂设计模式: BeanFactory, ApplicationContext 通过工厂模式创建对象
代理设计模式: SrpingAOP 用到了JDK动态代理和CGLIB动态代理
单例设计模式: bean默认都是单例
模板方法模式: jdbcTemplate, hibernateTemplate 等以Template结尾的对数据库操作的类,用到了模板设计模式
包装器设计模式: 动态数据源的支持
观察者设计模式: Spring时间驱动模型
适配器模式: SpringAOP的增强或者通知(Advice)使用了适配器模式, SpringMVC也是用到了该模式适配Controller