Spring 是轻量级的 IOC 和 AOP 框架,是为 Java 应用程序提供基础服务的框架。目的是为了简化企业应用程序的开发,让开发人员只关心业务逻辑。Spring 是模块式的框架,包括 20 多个模块。
- Spring core:提供 IOC 容器
- Spring context:提供 Spring 应用程序上下文信息
- Spring AOP:提供 AOP 功能
- Spring Dao:提供数据库访问的统一接口,对 JDBC 的抽象和封装
- Spring ORM:集成 ORM 框架,比如 Struts、Mybatis 等
- Spring Web:提供 Spring web 程序的上下文信息
- Spring MVC:Spring 的 MVC 框架
Spring 优点
- Spring 简化企业应用程序的开发,使开发人员只关心业务逻辑
- Spring 使用 IOC 容器管理 bean,可以通过 DI 注入对象,减小了代码的耦合度
- Spring 提供 AOP 技术,提高代码的可复用性。通过使用 AOP 可以实现事务、权限校验、日志、安全等功能
- Spring 对主流框架提供了集成支持,方便开发人员灵活的选择技术
IOC 初始化过程
Resource 定位(Bean 的定义文件定位)
获取文件。Resource 是 Spring 封装的 IO 操作接口,可以读取 XML、文件、二进制流、classpath 等
将 Resource 定位好的资源载入到 BeanDefinition
解析文件。bean 在 Spring IOC 内部被表示成了 BeanDefinition 这种数据结构
将 BeanDefinition 注册到容器中
将 BeanDefinition 封装成 BeanDefinitionHolder 类并注册到 beanDefinitionMap 中
Bean 生命周期
Spring IOC 容器主要包括 BeanFactory 和 ApplicationContext 两类,用于创建和管理 bean 。bena 的生命周期中涉及两个易混淆的概念:
- 实例化:创建对象,并为对象开辟空间
- 初始化:对对象中的值赋上初始值
ApplicationContext 生命周期
- 由 ApplicationContext 读取配置文件或配置类,并通过 Java 反射机制调用 bean 的构造方法生成实例
- setter 方法注入
- 如果实现了
BeanNameAware
接口,执行setBeanName()
方法(为 bean 命名) - 如果实现了
ApplicationContextAware
接口,执行setApplicationContext()
方法 - 如果实现了
BeanPostProcessor
接口,执行processBeforeInitialization()
方法(初始化前代理) - 如果实现了
InitializingBean
接口,执行afterPropertiesSet()
方法 - 如果定义了
init-method
,执行init-method
方法(初始化方法) - 如果实现了
BeanPostProcessor
接口,执行processAfterInitialization()
方法(初始化后代理) - 如果实现了
DisposableBean
接口,在容器关闭时执行destroy()
方法 - 如果定义了
destory-method
,在容器关闭时执行destory-method
方法
BeanFactory & ApplicationContext
- BeanFactory 是 Spring 中最底层的接口,提供了实例化对象和获取对象的方法;ApplicationContext 是 BeanFactory 的子接口,并提供了更多的功能,包括国际化、载入多个上下文、AOP 等
- BeanFactory 在启动时不会实例化 bean,只有在使用时才会去实例化;ApplicationContext 在启动时就会实例化 bean
Bean 作用域
- singleton
- prototype
- request
- session
- global-session:仅在门户网站中有意义
循环依赖
- 构造器循环依赖:无法解决,抛出
BeanCurrentlyInCreationException
异常 - setter 方法循环依赖:只能解决单例作用域的循环依赖
AOP
AOP 全称是面向切面编程,是面向对象编程的补充。 AOP 将可重用代码抽取出来并封装在一个模块中,便于代码复用。使用 AOP 可以实现事务、安全、日志和权限校验等功能。Spring AOP 是基于动态代理的,使用 JDK 动态代理和 cglib 动态代理。
- 静态代理:在编译阶段生成 AOP 代理类,也称为编译时增强。在编译时将切面织入 Java 字节码中,运行时就是被增强的 AOP 对象
- 动态代理:不修改 Java 字节码,而是在运行时在内存中生成 AOP 对象,这个对象包含了目标对象的全部方法,并且在特定的切点进行了增强
AOP 执行顺序
没有异常的执行顺序:
- around before advice
- before advice
- target method
- around after advice
- after advice
- afterReturning
有异常的执行顺序:
- around before advice
- before advice
- target method
- around after advice
- after advice
- afterThrowing
- java.lang.RuntimeException
事务传播行为
1 | public void methodA() { |
Propagation_REQUIRED
- 如果外围方法
methodA()
未开启事务,内部方法methodB()
和methodC()
会自己的创建事务,并且事务之间相互独立 - 如果外围方法
methodA()
开启事务,内部方法methodB()
和methodC()
会使用外围方法的事务,即三个方法使用一个事务。只要有一个方法回滚,整个事务回滚
- 如果外围方法
PROPAGATION_REQUIRES_NEW
- 如果外围方法
methodA()
未开启事务,内部方法methodB()
和methodC()
会自己的创建事务,并且事务之间相互独立 - 如果外围方法
methodA()
开启事务,内部方法methodB()
和methodC()
会自己的创建事务,并且事务之间相互独立,和外围事务也相互独立
- 如果外围方法
PROPAGATION_NESTED
- 如果外围方法
methodA()
未开启事务,内部方法methodB()
和methodC()
会自己的创建事务,并且事务之间相互独立 - 如果外围方法
methodA()
开启事务,内部方法methodB()
和methodC()
的事务是外围方法的子事务,属于嵌套关系,外围事务回滚,子事务一定回滚;子事务回滚,不影响外围事务和其他子事务
- 如果外围方法
PROPAGATION_SUPPORTS
- 如果外围方法
methodA()
未开启事务,内部方法methodB()
和methodC()
以非事务方式运行 - 如果外围方法
methodA()
开启事务,内部方法methodB()
和methodC()
使用外围方法的事务
- 如果外围方法
PROPAGATION_MANDATORY
- 如果外围方法
methodA()
未开启事务,抛异常 - 如果外围方法
methodA()
开启事务,内部方法methodB()
和methodC()
使用外围方法的事务
- 如果外围方法
PROPAGATION_NOT_SUPPORTED
如果外围方法
methodA()
未开启事务,内部方法methodB()
和methodC()
以非事务方式运行如果外围方法
methodA()
开启事务,将外围方法的事务挂起,内部方法methodB()
和methodC()
以非事务方式运行
PROPAGATION_NEVER
- 如果外围方法
methodA()
开启事务,抛出异常 - 如果外围方法
methodA()
未开启事务,内部方法methodB()
和methodC()
以非事务方式运行
- 如果外围方法