1.简介
Spring是一个分层的JavaSE及JavaEE应用于全栈的轻量级(所谓轻量级就是spring框架在系统初始化的时候不用加载所有的服务,为系统节约了资源 )开源框架,以IOC(控制反转\DI依赖注入)和AOP(面向切面编程)为核心,提供了表现层SpringMVC和持久层SpringJDBC以及业务层事务管理等众多模块的企业级应用技术,还能整合开源世界中众多著名的第三方框架和类库,逐渐成为使用最多的JavaEE企业应用开源框架
2.为什么要使用 spring
spring的本质是管理软件中的对象,即对象的创建和对象之间的维护 的关系
2.1简介
-
目的:解决企业应用开发的复杂性
-
功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
-
范围:任何Java应用
简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
2.2轻量
从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。
2.3控制反转
Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
2.4面向切面
Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
2.5容器
Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
2.6框架
Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。
什么是程序的耦合
耦合性,也称为耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间的接口的复杂性,调用模块的方式及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系
在软件工程中,耦合度指定就是对象之间的依赖关系,对象之间的依赖程度越高,耦合性越高,维护成本越高
降低程序之间的依赖程度,即降低程度之间的耦合度的过程叫解耦
总结:在软件工程中,耦合指的是对象之间的依赖关系。对象之间的依赖程度越高,耦合度就越高,维护成本越高
3.IOC控制反转
3.1谁控制谁,控制了什么?
传统的JavaSE程序设计,是直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IOC是专门一个容器来创建对象;即由容器控制对象的创建、初始化、销毁
3.2为何是反转,哪些方面反转了?
有反转就有正转,传统应用程序是由程序员自己在对象中主动控制去直接获取依赖对象,而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?获得依赖对象的过程被反转
IOC也被称为DI,即:依赖注入
描述了对象的定义和依赖的一个过程,也就是说,依赖的对象通过构造参数、工厂方法参数或属性注入,当对象实例化后依赖度对象才被创建,当创建bean后容器注入这些依赖对象
理解DI的关键是:
谁依赖谁:对象依赖IOC容器
为什么需要依赖:应用程序需要IOC容器来提供对象和该对象需要的外部资源
谁注入谁:IOC容器注入应用程序中的某个对象,应用程序依赖的对象
注入了什么:注入了某个对象所需的外部资源(包括对象、资源、常量数据等)
3.3IOC(控制反转)和DI(依赖注入)有什么关系
是同一个概念的不同角度描述
IOC强调的是容器和对象的控制权发生了反转,而DI强调的是对象的依赖由容器进行注入,广义上IOC是一种软件开发模式,也就是说还可以通过别的方式实现,而DI只是其中一种
3.4IOC(控制反转)和DI(依赖注入)有什么区别
控制反转:创建对象实例的控制权从代码控制剥离到IOC容器控制,实际就是你在xml文件控制,侧重于原理。
依赖注入:创建对象实例时,为这个对象注入属性值或其它对象实例,侧重于实现。
4.AOP
AOP是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
即统一处理某一切面(类)问题的编程思想,比如统一处理异常
5.Spring的常用注入方式
Spring通过DI(依赖注入)实现IOC(控制反转),常用的注入方式有三种
5.1构造器注入
指IOC容器使用构造函数注入被依赖的实例。可以通过调用带参数的构造函数实现,每个参数代表一个依赖
<!--构造器注入,通过constructor-arg标签实现实现构造器注入
name:属性字段名
ref:对应bean标签的id属性值
value:具体的值
index:参数的索引(位置、下标)
-->
<bean id="typeService" class="cn.tedu.service.TypeService">
<constructor-arg name="typeDao" ref="typeDao" />
<constructor-arg name="name" value="刘向东" />
<constructor-arg name="age" value="20" />
</bean>
5.2setter注入
指IOC容器使用setter方法注入被依赖的实例。通过调用无参构造器或无参静态工厂方法
setter是Spring现在最主流的注入方式,他可以利用Java Bean规范所定义set/get方法来完成注入,可读性灵活性高,他不需要构造器注入时出现的多个参数,他可以把构造方法声明成无参构造,再使用setter注入设置相对应的值,其实也就是通过java反射技术去实现的
<!--set方法注入,通过property属性实现set注入
name:属性字段名
ref:对应bean标签的id属性值
value:具体的值-->
<bean>
<property name="typeDao" ref="typeDao"/>
<property name="name" value="王向东"/>
<property name="age" value="20"/>
</bean>
5.3基于注解的注入
5.3.1定义Bean@Component
需要在类上使用注解@Component,该注解的value属性用于指定该bean的id值
另外,Spring还提供了3个功能基本和@Component等效的注解:
@Repository 用于对DAO实现类进行注解
@Service 用于对Service实现类进行注解
@Controller 用于对Controller实现类进行注解
之所以创建这三个功能与@Component等效的注解,是为了以后对其进行功能上的扩展,使它们不再等效。
5.3.2Bean的作用域@Scope
需要在类上使用注解@Scope,其value属性用于指定作用域。默认为singleton
5.3.3基本类型属性注入@Value
需要在属性上使用注解@Value,该注解的value属性用于指定要注入的值。
使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上
5.3.4按类型注入域属性@Autowired,@Autowired是spring的注解
需要在域属性上使用注解@Autowired,该注解默认使用按类型自动装配Bean的方式。
使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上
5.3.5按名称注入域属性@Autowired与@Qualifier
需要在域属性上联合使用注解@Autowired与@Qualifier。@Qualifier的value属性用于指定要匹配的Bean的id值。同样类中无需setter,也可加到setter上
@Autowired还有一个属性required,默认值为true,表示当匹配失败后,会终止程序运行。若将其值设置为false,则匹配失败,将被忽略,未匹配的属性值为null
5.3.6域属性注解@Resource,也就是说@Resource是java自带的注解
Spring提供了对JSR-250规范中定义@Resource标准注解的支持。@Resource注解既可以按名称匹配Bean,也可以按类型匹配Bean。使用该注解,要求JDK必须是6及以上版本
(1)按类型注入域属性
@Resource注解若不带任何参数,则会按照类型进行Bean的匹配注入
(2)按名称注入域属性
@Resource注解指定其name属性,则name的值即为按照名称进行匹配的Bean的id
6.Spring 中的 Bean 是线程安全的吗
Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究
7.Spring 支持几种 Bean 的作用域?
当通过spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下5种作用域:
-
singleton:单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
-
prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例
-
request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
-
session:对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
-
globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效
其中比较常用的是singleton和prototype两种作用域。对于singleton作用域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的生命周期行为;如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会新建一个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。
如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在创建Java实例时,需要进行内存申请;销毁实例时,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此,prototype作用域Bean的创建、销毁代价比较大。而singleton作用域的Bean实例一旦创建成功,可以重复使用。因此,除非必要,否则尽量避免将Bean被设置成prototype作用域。
8.Spring中Bean的作用域
单例
一个bean只会创建一个对象,存在内置map中,之后不管无论获取多少次,都返回同一个对象。这个单一的实例会被存储到一个叫做单例的缓存中,并且所有针对这个bean的后续请求和引用都会返回被缓存的对象,唯一的这个对象是实例
<bean id="dept" class="com.tedu.pojo.Dept" scope="singleton"></bean>
默认创建的对象是单例模式
多例
IOC容器会在每一次 获取当前bean时,都会产生一个新的bean实例(相当于new对象的操作),prototype只负责对象的创建和初始化,不负责销毁
<bean id="dept" class="com.tedu.pojo.Dept" scope="prototype"></bean>
9.Spring 自动装配 Bean 有哪些方式?
Bean的装载可以理解为依赖关系注入,Bean的装配方式也就是Bean的依赖注入
Spring容器负责创建应用程序中的bean同时通过ID来协调这些对象之间的关系。作为开发人员,我们需要告诉Spring要创建哪些bean并且如何将其装配到一起。
spring中bean装配有两种方式:
-
隐式的bean发现机制和自动装配
-
在java代码或者XML中进行显示配置
当然这些方式也可以配合使用。
10.Spring事务实现方式有哪些
- 声明式事务:声明式事务也有两种实现方式,基于 xml 配置文件的方式和注解方式(在类上添加 @Transaction 注解)
- 编码方式:提供编码的形式管理和维护事务
11.Spring的事务隔离
事务隔离:https://blog.csdn.net/weixin_60109352/article/details/120536305
事务隔离级别指的是一个事务对数据的修改与另一个并行的事务的隔离程度,当多个事务同时访问相同数据时,如果没有采取必要的隔离机制,就可能发生以下问题:
-
脏读:一个事务读到另一个事务未提交的更新数据。
-
幻读:例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还存在没有修改的数据行,就好象发生了幻觉一样。
-
不可重复读:比方说在同一个事务中先后执行两条一模一样的select语句,期间在此次事务中没有执行过任何DDL语句,但先后得到的结果不一致,这就是不可重复读。