什么是Spring
Spring 是分层的 full-stack(全栈) 轻量级开源框架,以 IoC 和 AOP 为内核,提供了展现层 SpringMVC 和业务层事务管理等众多的企业级应⽤技术,还能整合开源世界众多著名的第三⽅框架和类库,已经成为使⽤最多的 Java EE 企业应⽤开源框架。
Spring是一个开源框架,是一个生态,也是一个生态的基石。像Springboot 、Springcloud都是以Spring为基石进行开发的。都是在Spring基础上进行延伸和扩展。Spring是为了简化企业开发而生的,使的开发变得更加优雅和简洁, Spring当中最核心的就是IOC和AOP
Spring的优势
整个 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的核心结构
Spring是⼀个分层⾮常清晰并且依赖关系、职责定位⾮常明确的轻量级框架,主要包括⼏个⼤模块:数据处理模块、Web模块、AOP(Aspect Oriented Programming)/Aspects模块、Core Container模块和 Test 模块,如下图所示,Spring依靠这些基本模块,实现了⼀个令⼈愉悦的融合了现有解决⽅案的零侵⼊的轻量级框架。

- Spring核⼼容器(Core Container) 容器是Spring框架最核⼼的部分,它管理着Spring应⽤中bean的创建、配置和管理。在该模块中,包括了Spring bean⼯⼚,它为Spring提供了DI的功能。基于bean⼯⼚,我们还会发现有多种Spring应⽤上下⽂的实现。所有的Spring模块都构建于核⼼容器之上。
- ⾯向切⾯编程(AOP)/Aspects Spring对⾯向切⾯编程提供了丰富的⽀持。这个模块是Spring应⽤系统中开发切⾯的基础,与DI⼀样,AOP可以帮助应⽤对象解耦。
- 数据访问与集成(Data Access/Integration)。Spring的JDBC和DAO模块封装了⼤量样板代码,这样可以使得数据库代码变得简洁,也可以更专注于我们的业务,还可以避免数据库资源释放失败⽽引起的问题。 另外,Spring AOP为数据访问提供了事务管理服务,同时Spring还对ORM进⾏了集成,如Hibernate、MyBatis等。该模块由JDBC、Transactions、ORM、OXM 和 JMS 等模块组成。
- Web 该模块提供了SpringMVC框架给Web应⽤,还提供了多种构建和其它应⽤交互的远程调⽤⽅案。 SpringMVC框架在Web层提升了应⽤的松耦合⽔平。
- Test 为了使得开发者能够很⽅便的进⾏测试,Spring提供了测试模块以致⼒于Spring应⽤的测试。 通过该模块,Spring为使⽤Servlet、JNDI等编写单元测试提供了⼀系列的mock对象实现。
核心思想
IOC和AOP不是spring提出的,在spring之前就已经存在,只不过更偏向于理论化,spring在技术层次把这两个思想做了⾮常好的实现(Java)
什么是IOC
IOC(Inversion of Control)就是控制反转,说到IOC就要说到DI,因为IOC是实现思想,而DI是实现方式,控制反转就是原来对象需要我们进行创建,现在交给容器来帮我们控制,包括对象属性的注入,原先由我们手动的操作,现在由容器来帮我们完成这些属性注入的功能,全部交给容器进行操作了,维护会变得特别简单。

IOC解决了对象之间耦合的问题

IOC和DI的区别

什么是AOP
当我们需要做到一些跟业务无关的功能,比如日志,就可以aop方式把关键的核心代码切入我们业务逻辑内,而不需要我们去改每一行代码了,它用起来特别的方便。
AOP: Aspect oriented Programming ⾯向切⾯编程/⾯向⽅⾯编程
AOP是OOP的延续,从OOP说起
OOP三大特征:封装、继承、多态
OOP是一种垂直继承体系

OOP编程思想可以解决⼤多数的代码重复问题,但是有⼀些情况是处理不了的,⽐如下⾯的在顶级⽗类
Animal中的多个⽅法中相同位置出现了重复代码,OOP就解决不了

横切逻辑代码

横切逻辑代码的问题
- 代码重复
- 横切逻辑和业务代码混杂在一起,代码臃肿,维护不便
AOP独辟蹊径提出横向抽取机制,将横切逻辑代码和业务逻辑代码分析

代码拆分容易,那么如何在不改变原有业务逻辑的情况下,悄⽆声息的把横切逻辑代码应⽤到原有的业
务逻辑中,达到和原来⼀样的效果,这个是⽐较难的
AOP解决的问题
在不改变原有业务逻辑情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复
「切」:指的是横切逻辑,原有业务逻辑代码我们不能动,只能操作横切逻辑代码,所以⾯向横切逻辑
「⾯」:横切逻辑代码往往要影响的是很多个⽅法,每⼀个⽅法都如同⼀个点,多个点构成⾯,有⼀个⾯的概念在⾥⾯
容器
容器就是存放bean对象的地方,在Spring框架中,他用的是一系列的map结构来存储
scope
1,什么是单例和多例
单例:所有请求用同一个对象来处理。通过单例模式,可以保证系统中一个类只有一个实例。 多例:每个请求用一个新的对象来处理。
2,Spring中的单例与多例
spring ioc容器的bean都是默认单例的,即spring依赖注入Bean实例默认是单例的。
spring提供了5种scope,分别是singleton,prototype,request,session,global session,常用是前两种。
单例bean与多例(原型)bean的区别: 如果一个bean被声明为单例的时候,在处理多次请求的时候,在spring容器里只实例化出一个bean,后续的请求都公用这个对象,这个对象会保存在一个map里面。当有请求来的时候,会先从缓存(map)里查看有没有,有的话直接使用这个对象,没有的话才实例化一个新的对象,所以这是个单例的。但是对于原型(prototype)bean来说,当每次请求来的时候,会直接实例化新的bean,没有缓存以及缓存查询的过程。
3,单例的优势与劣势
优势: 由于不会创建新的对象,所以有以下几个性能上的优势:
减少新生成实例的消耗。新生成实例包括两个方面,
- 第一,spring会通过反射或者cglib来生成bean实例,这都是耗性能的操作。
- 第二,给对象分配内存也会涉及负责算法。
减少jvm垃圾回收。由于不会给每个请求都生成bean实例,所以回收的对象就少了。 可以快速获取到bean。因为单例获取bean操作,除了第一次生成之外,其余都是从缓存里获取的,所以很快。 劣势: 一个很大的劣势是它不能做到线程安全。由于所有请求都共享一个bean实例,那么如果这个bean是一个有状态的bean的话,在并发场景下就有可能出现问题。
4,spring单例模式与线程安全:
当多用户同时请求一个服务时,容器会给每一个请求分配一个线程,这时多个线程会并发执行该请求所对应的业务逻辑(成员方法),此时就要注意了,如果该处理逻辑中有对该单例状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题(此时该状态就是一个临界资源(共享数据),如果多个线程同时操作(修改)这个临界资源就会诱发线程安全问题)。
线程安全:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行的结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。或者说:一个类或者程序所提供的接口对于线程来说是原子操作,或者多线程之间的切换不会导致该接口的执行结果存在二义性,就是线程安全的。
线程安全问题都是由全局变量及静态变量引起的。 若每个线程中对全局变量,静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
常量始终是线程安全的,因为只存在读操作; 每次调用方法前都新建一个实例是线程安全的,因为不会访问共享的资源; 局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享资源。局部变量包括方法的参数变量和方法内的变量。 在关于spring单例与线程安全的很多文章中,会提到一个概念,即有状态bean和无状态bean。
- 无状态bean:无状态,就是一次操作,不能保存数据。无状态bean,就是没有实例变量的对象,不能保存数据,是不变类,在线程安全的。
- 有状态bean:有状态,就是有数据存储功能。有状态bean,就是有实例变量的对象,可以保存数据,是非线程安全的。
如何解决线程安全问题? (1)使用线程同步机制:通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序缜密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂问题,程序设计和编写难度相对较大。 (2)使用ThreadLocal:为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。
概括起来就是:对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
Spring事务
特性
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
原子性(Atomicity)
比如张三给李四5块钱,然后李四给赵四3块钱。原子性就是这些步骤要不都执行要不都别执行,如果某一步出现问题就回滚撤销。
一致性(Consistency)
数据保证在业务上是正确的
隔离性(isolation)
两个事务的执行要互不影响,互不干扰,
持久性(Durability)
一旦提交事务成功,数据会到数据库持久化保存,也就是拥有保存。
Spring事务管理机制
Spring事务时在数据库事务的基础上进行封装扩展的,主要特性如下
1.支持原有的数据库事务的隔离级别,加入了事务传播的概念
2.提供国际事务的合并或隔离的功能
3.提供声明式事务,让业务代码与事务分离,事务变得更加易用(AOP)
Spring提供了事务相关的接口
Spring事务管理高层抽象主要包含3个接口,Spring的事务主要通过他们三个共同完成
TransactionDefinition
事务定义: 事务定义信息(隔离、传播、只读、超时)
PlatformTransactionManager
事务管理器,主要用于平台相关事务的管理、
TransactionStatus
获取事务的运行状态
Spring框架中使用了那些设计模式和应用场景
1.工厂模式
在各种BeanFactory以及ApplicationContext创建中都用到了
2.模板模式
在公众BeanFactory以及ApllicationContext创建中都用到了
3.代理模式
Spring Aop利用了AspectJ AOP实现的 AspectJ AOP的底层用了动态代理
4.单列模式
比如说在创建Bean的时候
5.策略模式
加载资源文件的方式,使用了不同的方法,比如:ClassPathResourece,FileSystemResource,ServletContextResource,UrlResource单他们都有共同的接口;在Aop的实现中,采用了2中不同的方式,JDK动态代理和CGLIB代理。
6.观察者模式
Spring中的ApplicationEvent,ApplicationListener,ApplicationEventPublisher
7.适配器模式
MethodBeforeAdviceAdapter,ThrowsAdviceAdapter,AfterReurningAdapter
8.装饰者模式
源码类型中的哎Wrapper或者Decorator的都是