你一直在用Spring,但你可能真的不懂它
本文于2020-04-24进行重构
看我的文章,如果关于某些定义觉得读完不太明白,那是正常的,我会在后面进行阐述,尽量用自己的理解,使用大白话,讲清楚
任何学习都是一样,不要纠结于一处,也许学到后面,再回过头来看,一目了然了呢
Spring的专题我做了分离,本文旨在"让你更懂Spring"
实操分离:
相关:
文章目录
WHAT IS SPRING
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。
它是为了解决企业应用开发的复杂性而创建的,框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。
Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
Spring的核心是控制反转(IoC)和面向切面(AOP)
简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架
重要的Spring framworks
这是Spring的架构图,它包含以下重要组件
Spring Data Access 数据相关组件模块:
- Spring JDBC : Java数据库连接
- Spring ORM : 用于支持Hibernate等ORM工具
- Spring JMS :Java消息服务
- Spring Transactions:事务管理组件
Spring Web模块
- 这块是Spring MVC的内容
Core Containner 容器相关模块
-
Spring Beans:实体类的容器组件
-
Spring Core: Spring 其他所有的功能都需要依赖于该类库。主要提供 IoC 依赖注入功能
-
Spring Context:Spring上下文组件,Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能
其他:
- Spring AOP :提供了面向切面的编程实现
- Spring Test : 提供了对 JUnit 和 TestNG 测试的支持
控制反转(IOC)
IOC是Spring为Java提供的一种全新的设计思想,这也是Spring提出的核心思想,也是Spring为我们做的一件了不起的事情!
控制反转(Inversion of Control),就是应用本身不负责对象的创建(new object())和维护,对象和依赖对象创建完全交给Spring的容器去管理和维护,这个权利反转给容器
在学习Spring 之前,所有我们需要用到对象,都由我们手动new,如
new DaoImpl();
这样做,在项目开发中有很大的问题:
带来了很大的耦合性,项目不好维护,测试成本也高
每次用到对象,都要new,那为何不把这个对象放到容器中,我们用到的时候,直接去取呢?所以,我们把new对象这件事就交给了Spring,即所谓的控制反转,将对对象的控制权反转给Spring的容器
Spring 早期时代我们一般通过 XML 文件来配置 Bean,后来开发人员觉得 XML 文件来配置过于繁琐,于是
SpringBoot 时代,注解配置就慢慢开始流行起来,到现在,基本已经成为Spring的主流玩法
面向切面(AOP)
AOP(Aspect-Oriented Programming:面向切面编程)
这也是一种伟大的设计思想,它能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性
很简单,想想你是否在基础的Web学习中学过拦截器,拦截器就是AOP思想的主要应用了
AOP(Aspect Oriented Programming),通过预编译的方式在运行期使用动态代理的方式来实现的一种技术
动态代理是一个核心设计思想,你最好能够掌握它,才能更好的理解Spring
关于动态代理,可以参考我之前些的一篇Blog:
Bean
你可以将之理解为我们创建的对象,对象即Bean
Spring通过容器,存储我们需要创建对象,并针对这些对象,构建了一套完整的生命周期
Bean作用域?
Spring为我们创建的对象,有不同的类型,不同类型的Bean特性不同,具体:
- singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
- prototype : 每次请求都会创建一个新的 bean 实例。
- request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
- session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
- global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。
单例Bean的线程安全问题?
大部分时候我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例 bean 存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题
解决方法:
在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal 中
bean的生命周期?
我们必须知道,Bean是何时被容器创建出来的,又是何时被销毁的,我们先要知道bean是如何被创建出来的
下图是Bean被创建的过程
- Bean 容器找到配置文件中 Spring Bean 的定义。
- Bean 容器利用 Java Reflection API 创建一个Bean的实例。
- 如果涉及到一些属性值 利用
set()
方法设置一些属性值。- 如果 Bean 实现了
BeanNameAware
接口,调用setBeanName()
方法,传入Bean的名字。- 如果 Bean 实现了
BeanClassLoaderAware
接口,调用setBeanClassLoader()
方法,传入ClassLoader
对象的实例。- 与上面的类似,如果实现了其他
*.Aware
接口,就调用相应的方法。- 如果有和加载这个 Bean 的 Spring 容器相关的
BeanPostProcessor
对象,执行postProcessBeforeInitialization()
方法- 如果Bean实现了
InitializingBean
接口,执行afterPropertiesSet()
方法。- 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
- 如果有和加载这个 Bean的 Spring 容器相关的
BeanPostProcessor
对象,执行postProcessAfterInitialization()
方法- 当要销毁 Bean 的时候,如果 Bean 实现了
DisposableBean
接口,执行destroy()
方法。- 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。
关于Spring中的设计模式
目前,我还没整理出我学习的设计模式的笔记心得,有机会的话,我会做一期设计模式的专栏
下面列举一些Spring中的设计模式
- 工厂设计模式 : Spring使用工厂模式通过
BeanFactory
、ApplicationContext
创建 bean 对象 - 代理设计模式 : Spring AOP 功能的实现,Spring使用的是JDK动态代理模式
- 单例设计模式 : Spring 中的 Bean 默认都是单例的
- 模板方法模式 : Spring 中
jdbcTemplate
、hibernateTemplate
等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式 - 包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源
- 观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用
- 适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配
Controller
Spring事务
这里你应该想想数据库中的事务概念了,在数据库中,我们需要用到Spring的事务管理!
在我之前谈到Mysql的锁的时候,我详细介绍了有关事务内容,可以复习一下
Spring管理事务的方式分为:
- 编程式事务,在代码中硬编码。(不推荐使用)
- 声明式事务,在配置文件中配置**(推荐使用)**
- 基于XML的声明式事务
- 基于注解的声明式事务**(推荐使用)**
Spring事务隔离级别
TransactionDefinition 接口中定义了五个表示隔离级别的常量:
- TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
- TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
- TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。