Spring

spring概述

Spring是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以IoC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架

spring官网:http://spring.io/

 

Spring的发展历程

1997年IBM提出了EJB的思想

1998年,SUN制定开发标准规范EJB1.0

1999年,EJB1.1发布

2001年,EJB2.0发布

2003年,EJB2.1发布

2006年,EJB3.0发布

Rod Johnson(spring之父)

2017年9月份发布了spring的最新版本spring5.0通用版

 

框架的定义:拥有一整套解决方案

使用框架使得我们的程序开发变得更高效

1、spring是一个容器,这个容器会管理很多的组件(java bean)

2、spring可以很好的解决程序间的耦合

3、spring可以集成很多第三方框架,可以充当众多技术栈之间的一个粘合剂

 

Spring的优势

方便解耦,简化开发

通过Spring提供的IoC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合,用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于业务层上的应用

 

AOP编程的支持

通过Spring的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付

 

声明式事务的支持

可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明方式灵活的进行事务的管理,提高开发效率和质量

 

方便程序的测试

可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情

 

方便集成各种优秀框架

Spring可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支持

 

降低 JavaEE API 的使用难度

Spring 对 JavaEE API (如JDBC、JavaMail、远程调用等)进行了薄薄的封装,使这些API的使用难度大为降低

 

Java源码是经典学习范例

Spring 的源代码设计精妙,结构清晰,匠心独用,处处体现着大师对Java设计模式灵活运用以及对 Java 技术的高深造诣,它的源代码无疑是Java技术的最佳实践范例

 

Spring的体系结构

Core Container (spring核心容器)

为其它模块提供支持

Data Access/Integration(持久层相关)

Test单元测试模块

 

程序间的耦合

 

 

 

 

工厂模式解耦

 

 

spring中工厂的类结构图

 

控制反转 IoC

 

明确IoC的作用:削减计算机程序的耦合(解除代码中的依赖关系)

IOC是解耦的一种思想:解耦的途径有很多:比如依赖注入DI(只是解耦的一种解决方案)

程序中核心业务代码由主动创建对象变成被动的接收对象

★创建对象的控制权发生了转变(控制反转)

 

依赖注入:不在类中直接new对象,在外部需要使用本类时提供对象(可以通过工厂获取对象) (set注入,构造注入)

例如在业务层不直接提供持久层的实例

 

 

★IOC

Inversion of Control

IOC — spring的IOC解决程序耦合

基于xml的方式来创建spring核心容器对象

基于XML的配置

导入配置文件约束

创建一个xml文件,导入spring核心容器相关的约束 ==> 创建核心容器对象 ==> 从容器中去取出实例

 

1、spring是一个容器,里面存放了很多的实例

2、可以把spring理解成一个工厂,我们需要从工厂中获取实例

3、创建一个xml文件,导入spring核心容器相关的约束,可以使用spring提供的相关标签(标签里面是存放数据的)

4、spring会解析这个xml标签中的数据

 

ApplicationContext 接口的实现类

 

在spring中,如何将一个类的实例装载到spring容器中?

基于xml的方式来创建spring核心容器对象

bean标签的作用:将一个类的实例通过反射机制创建出来,装载进核心容器中,默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功

id属性:唯一标识,不能重复的,给对象在容器中提供唯一标识,用于获取对象 class属性:指定类的全限定类名,用于反射创建对象,默认情况下调用无参构造函数

scope属性:可以去设置该实例的作用范围

 

从容器中取出实例

sping在获取实例时的执行流程:

会解析xml文件,去读取每一个标签,如果发现有bean标签,那么会解析bean标签对应的属性,会去读取class属性的属性值,然后通过反射机制创建实例,保存到容器中,会将id属性作为该实例的标识

 

问:如果将一个实例存放进核心容器中,在程序中多次获取该实例,取得的实例是不是单例的?

默认情况下是单例的,但是我们可以将其修改为多例的

 

在标签下修改scope属性

singleton:默认值,单例的

prototype:多例的

request:WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中

session:WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中

global session:WEB项目中,应用在Portlet环境,如果没有Porlet环境那么globalSession相当于session

 

 

依赖注入 Dependency Injection

 

基于XML配置的依赖注入(set方式)

property标签的作用

要通过set方法在xml配置文件中实现依赖注入,在类中必须实现set方法

name属性:类的属性名

value属性:类的属性值

ref属性:可以去引入容器中别的实例,属性值就是需要传入的实例的唯一标识

 

给数组赋值

 

给自定义引用数据类型赋值

List

Map

Date


 

基于XML配置的依赖注入(构造方式)

基于构造方法完成对值的注入

constructor-arg

根据有参构造来创建实例

 

多个参数构造创建实例

 

关于组件的生命周期

组件的作用范围是单例的:

init-method属性:对象在初始化时会执行的对应方法

destroy-method属性:对象在销毁时会执行的对应方法

需要在类中定义方法

 

关闭容器对象的方法

但是要用ClassPathXmlApplicationContext去接收才能调用此方法

关闭后,容器中的实例会被销毁

 

组件的作用范围是多例的:

 

 

 

BeanFactory和ApplicationContext的区别

BeanFactory才是Spring容器中的顶层接口

ApplicationContext是它的子接口

创建对象的时间点不一样

 

 

通过BeanFactory创建的容器,其中的实例在被用到的时候才会创建

 

三层架构通过xml配置进行依赖注入

 

 

模拟springIOC底层基于工厂模式解耦

首先程序会去读取配置文件,然后获取文件中的全类名数据,根据反射创建对象(单例的),保存在容器里面,后面如果有用到实例的地方,我们从容器中去获取

通过工厂获得业务层的实例

 

 

基于注解的IOC配置
注解作用
@Component把资源让spring来管理,相当于在xml中配置一个bean
@Controller一般用于表现层的注解
@Service一般用于业务层的注解
@Repository一般用于持久层的注解

 

1、在配置文件开启spring对注解的支持

2、直接在类上加对应的注解即可

在使用注解的IOC配置前需要先导入springAOP的jar包底层需要

 

配置文件约束

名称空间:xmlns:context

开启spring对注解的支持,其实就是一个扫描包的过程

spring程序在执行的时候会去解析配置文件的数据,然后找到对应的包结构,并且扫描该包下对应的子包,然后会去检查每一个类上面有没有spring提供的注解,如果有,会将该类的实例装载进spring核心容器中

base-package:指定的包结构

 

在取出实例的时候,要注意,默认的标识是类的类名(首字符要小写)

类注解中的value值代表该类在获取时需要提供的id,给Student类自定义的提供一个id值

 

改变作用范围的注解

@Scope 指定bean 的作用范围

取值:

singleton

prototype

request

session

globalession

 

生命周期相关

@PostConstruct 用于指定初始化的方法

@PreDestroy 用于指定销毁的方法

 

基于注解的方式注入属性的值

用于注入数据的注解

注解作用
@Autowired根据类型注入
@Qualifier按名称注入,不能单独使用
@Resource根据id注入的
@Value用于注入基本数据类型和String类型

 

@Autowired注解

注入流程:首先spring在扫描到该属性上有Autowired注解之后,会去容器中找到该属性对应的类型与之注入

如果spring容器中与该属性类型匹配的实例有多个,那么究竟该注入哪个实例,这种情况下程序会报错

给这个类的实例起标识,起的标识一定要跟被注入属性的属性名称一致

 

@Qualifier注解

跟Autowired结合使用,指由Qualifier来决定究竟要注入哪个实例,需要提供注入实例的标识

Qualifier不能单独使用,只能和Autowried配合使用

 

@Resource注解

根据id去注入,相当于Autowired和Qualifier的结合

 

@Value注解

给属性赋值,能赋值基本数据类型和String类型

 

 

模拟springIoC底层基于注解的方式进行注入

通过设计模式+反射机制来模拟

 

1、spring的配置文件:beans.xml(开启扫描包的过程)spring会去扫描该包下所有子包的类,为了检查有没有spring提供的注解

 

2、要在指定的类上加注解,如果spring检查到该类上有注解的话,就会将该类的实例通过反射机制创建出来,装进spring中

 

3、检查该类中的属性上有没有spring提供的注解,如果有的话,会通过反射的方式去注入实例


修饰持久层的注解

修饰业务层的注解

修饰表现层的注解

根据属性类型注入属性实例的注解

工厂类,用于储存实例

模拟spring底层基于注解Ioc解耦(扫描指定包结构下的类,创建所需要的实例)


 

基于注解的方式来创建核心容器对象

1、之前创建核心容器对象都是基于xml的,必须得有配置文件

2、spring5.0版本之后也是支持基于注解的方式创建核心容器对象,这样我们的程序就可以脱离xml配置文件

 

sping5.0版本后新的注解

@Configuration

声明当前的类是一个配置类,仅起到标识作用

 

@ComponentScan

传入一个指定的包结构路线,开启扫描包,如果被@Component或其它特定注解修饰的类就会被添加到核心容器中

 

@Bean

 

 

 

注意:如果方法名称相同,即使用@Bean起了别名,有参的也会覆盖掉无参的

 

配置类

测试类

 

@PropertySource

引入配置文件,可以通过@Value注解读取数据

classpath: 读取的配置文件资源需要放在src文件下,可以通过el表达式取到值

配置文件jdbc

 

@Import

可以让两个核心配置类之间存在继承的关系

引入其它核心配置类,需要提供一个配置类的字节码属性

 

基于核心配置类配置三层架构

 

总结

XML开发:

 

注解开发:

 

需要配置bean , @Bean与等价

 

需要扫描包, 与@ComponentScan 等价

 

 

★AOP

AOP概述

AOP:全称是 Aspect Oriente Programming

(面向切面编程)

作用

在程序运行期间,不修改源码对已有方法进行增强

优势

 

 

Joinpoint(连接点):

连接点是指那些被拦截到的点,在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,指的就是动态代理在底层可以访问到的所有方法

 

Pointcut(切入点):

所谓切入点是指我们要对哪些Joinpoint进行拦截的定义,就是要对哪些连接点(方法)进行增强,即需要被增强的方法

 

Advice(通知/增强):

所谓通知是指拦截到Joinpoint之后所要做的事情就是通知,通知的类型:

Target(目标对象):

代理的目标对象

 

Weaving(织入):

是指把增强应用到目标对象来创建新的代理对象的过程(增强的过程)

spring采用动态代理织入,而AspectJ采用编译器织入和类装载器织入

 

Proxy(代理):

一个类被AOP织入增强后,就产生一个结果代理类

 

Aspect(切面):

是切入点(要增强的方法)和通知(怎么增强)之间的关系

 

JDK动态代理模拟AOP底层

场景:

之前学习jdbc的时候我们接触到了事务,A账户给B账户赚钱,我们需要加入事务的操作,要满足事务的一致性

如果用代理模式来完成对事务的织入,程序该如何去写?

使用JDK动态代理来为目标类创建代理类

测试类

 

基于XML的AOP配置

通过xml来配置aop(切面):我们配置的是切入点和通知之间的关系

我们想在项目中去加入收集日志的功能,但是不能在核心模块中出现,会通过aop配置切面的方式来完成对核心模块中核心方法的增强

 

引入约束

标签

aop:config:

作用:用于声明开始aop的配置

 

aop:aspect:

作用:配置切面

 

aop:pointcut:

作用:配置切入点表达式

第一个*标识当前工程,后面是资源路径,类.*标识该类下的所有方法,(..)代表匹配所有无参,(String,int)表示匹配指定参数的方法

 

aop:before:

作用:用于配置前置通知

 

aop:after-returning:

作用:用于配置后置通知


配置切面

 

外部声明切入点表达式

 

通知类

 

需要被增强的核心类

 

测试类


 

基于注解的AOP配置

开启AOP对注解的支持

 

@Aspect

声明当前的类是一个切面类

@Pointcut

修饰一个方法,注解中的值为切入点表达式

@Before

前置通知

@AfterReturning

后置通知

@AfterThrowing

异常通知

@After

最终通知

 

通过注解配置通知类

 

测试类

 

环绕通知

在配置环绕通知的时候可以不去配置前置,后置,异常,结束这些通知,因为可以在环绕通知中定义这些通知

xml配置环绕通知

注解配置环绕通知

增强方法内容

 

 

单元测试junit

单元测试在底层是封装了main函数的,在不写主函数的情况下,可以去让程序跑起来

 

通过spring来集成单元测试(可以在不创建核心容器的情况下,取到容器中的实例)

@Test

在方法上加上Test注解,该方法就会变成像主函数一样可以运行

 

在程序运行的时候动态获取核心容器对象

@RunWith

这个注解可以替换运行器,我们选用spring提供的运行器

@ContextConfiguration

指定如何创建核心容器对象,需要提供xml路径或者是配置类class

基于核心配置类创建容器(注解注册)

 

jdbcTemplate模板对象

jdbcTemplate对JDBC做了封装,相当于是一个工具类

 

xml中的特殊符号
表达式符号
&lt;<
&gt;>
&amp;&
&apos;'
&quot;"

 

通过xml配置注入jdbcTemplate模板实例

junit测试类

持久层

 

 

 

Spring中的事务控制

 

 

 

PlatformTransactionManager接口

此接口是spring的事务管理器,它里面提供了我们常用的操作事务的方法

 

管理事务的子类对象:

1.DataSourceTransactionManager使用SpringJDBCiBatis进行持久化数据时使用

 

2.HibernateTransactionManager使用Hibernate版本进行持久化数据时使用

 

 

基于XML的声明式事务控制

配置步骤

1、配置事务管理器

2、配置事务的通知引用事务管理器

3、配置事务的属性

4、配置AOP切入点表达式

5、配置切入点表达式和事务通知的对应关系

 

引入xmlns:tx相关约束

场景:银行转账的场景

 

TransactionDefinition事务属性

isolation

获取事务的隔离级别

默认值是DEFAULT,数据库级别的

 

propagation

获取事务的传播行为,表示是否开启事务,以什么样的策略开启

REQUIRED表示一定会开启事务,无论是增删改查都会开启

SUPPORTS表示有事务就会开启事务,没有事务就不会开启,会在增删改 的场景下开启事务,查询场景不会开启

 

timeout

获取超时时间,默认值是-1,永不超时,如果是正数的话,可以以秒为单 位设置超时时间

 

read-only

会影响事务是否开启

获取是否是只读事务(true/false),默认值是false,在查询的业务场景下,会把该属性设置成true

 

rollback-for:

是否开启回滚,默认值是true 自定义一个异常,除了该异常回滚,所有异常都不回滚 no-rollback-for:

自定义一个异常,除了该异常不回滚,所有异常都回滚

默认情况下,所有异常都回滚

 

只有在增删改的业务场景下,才会取开启事务,查询业务场景下不用开启事务,或者是只读就行

 

注意:spring中单个事务的生命周期只发生在在一个方法中(需要被AOP增强的每个方法)

 

如何配置事务管理器

如何配置事务的通知

 

完整的spring事务织入xml配置

 

基于注解的声明式事务控制

配置步骤

1、配置事务管理器并注入数据源

2、在业务层使用@Transactional注解

3、在配置文件中开启spring对注解事务的支持

 

@Transactional

事务注解,可以修饰类,也可以修饰方法

修饰类:该类下所有的方法都会加入事务的支持

修饰方法:只有指定方法会加入事务支持,方法的优先级比类要高

注意:使用注解,事务管理器还需要在xml中配置,但是事务通知可以不用配置了