当前位置:   article > 正文

Spring从入门到精通

spring从入门到精通

第一章、Spring简介(给软件行业带来春天)(是个全家桶,有很多单独的框架)

1、什么是spring?(解决企业开发的难度,减轻对项目模块之间的管理,类和类之间的管理,帮助开发人员创建对象,管理对象之间的关系)(核心功能是IOC和AOP,能够实现模块之间,类之间的解耦合)

Spring是一个引擎,是一个开源容器框架,可以接管web层,业务层,dao层,持久层的组件,并且可以配置各种bean,和维护bean与bean之间的关系。其核心就是控制翻转(IOC),和面向切面(AOP),简单的说就是一个分层的轻量级开源框架。
Spring原理和组成:Spring为简化我们的开发工作,封装了一系列的开箱即用的组件功能模块,包括:Spring JDBC 、Spring MVC 、Spring Security、 Spring AOP 、Spring ORM 、Spring Test等。
理念(目的):解决企业应用开发的复杂性,使现有的技术更加容易使用,本身是一个大杂烩整合了现有的框架。
优点:
1、Spring是一个免费开源的框架(容器)!
2、Spring是一个轻量级的非入侵的框架!
3、控制反转(IOC),面向切面编程(AOP)
4、支持事务的处理,对框架整合的支持!
总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程的框架!

在这里插入图片描述
在这里插入图片描述
Spring包含了SpringMVC,而SpringBoot又包含了Spring或者说是在Spring的基础上做得一个扩展。
在这里插入图片描述
spring mvc < spring < springboot
Spring Boot只是Spring本身的扩展,使开发,测试和部署更加方便。
SSM框架:Spring+SpringMVC+MyBatis

Spring MVC:属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。
MyBatis: 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
Rod Johnson:Spring Framework的创始人,音乐学的博士学位,轮子理论:就是不要重复发明轮子

2、什么是框架?

在这里插入图片描述
在这里插入图片描述
框架可以类比如造房子的框架和造桥梁的框架,类库可以类比如为钢材,类库更加通用。

3、为什么使用框架?

软件系统日趋复杂
重用度高,开发效率和质量高
软件设计人员要专注于对领域的了解,使需求更充分易于上手、快速解决问题。

4、Sping IOC容器

在这里插入图片描述
在这里插入图片描述
面向接口编程的例子:
接口:
在这里插入图片描述
实现类:
在这里插入图片描述
调用:
在这里插入图片描述
什么是IOC?
在这里插入图片描述
在这里插入图片描述
依赖:ClassA中使用ClassB的属性或者方法,叫做ClassA依赖于ClassB

5、Spring官网浏览

在这里插入图片描述
每一行是一个单独的框架,所做的工作是不同的
主要学习Spring Framework

6、框架的优点

1、轻量,Spring框架使用的Jar都比较小,一般在1M以下或者几百kb,Spring核心功能所需的jar总共在3M左右。
2、针对接口编程,解耦合,Spring提供了IOC控制反转。由容器管理对象,对象的依赖关系。原来在程序代码中的对象创建方式,现在由容器完成,对象之间依赖解耦合。
3、AOP编程的支持,通过提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付,在Spring中,开发人员可以从繁杂的事物管理代码中解脱出来,通过声明式方式灵活地进行事务的管理,提高开发效率和质量。
4、方便集成各种优秀的框架,spring不排斥各种优秀的开源框架,相反Spring可以降低各种框架的使用难度,Spring提供了对各种优秀框架等的直接支持。简化框架的使用,Spring像插线板一样,其他框架是插头,可以容易的组合到一起。需要使用哪个框架就把这个插头放入插线板。不需要可因轻易移除。

7、Spring框架模块

Spring由20多个模块组成,他们可以分为数据访问/集成、web、面向切面编程(AOP、Aspects)、集成功能模块(JVM代理(instrumentation)、消息返送(Messaging))、核心容器(Core Container)和测试(Test)。
在这里插入图片描述

第二章、IOC控制反转

在这里插入图片描述
IOC:控制反转,是一个理论,概念,思想。
描述:把对象的创建,赋值,管理工作都交给代码之外的容器实现,也就是对象的创建是在其他外部资源完成
控制:创建对象,对象的属性赋值对象之间关系管理。
反转:把原来的开发管理,创建对象的权限转移给代码之外的容器实现。由容器代替开发人员管理对象。创建对象,给属性赋值。
正转:由开发人员在代码中,使用new构造方法创建对象,开发人员主动管理对象。
容器:是一个服务器软件,一个框架(Spring)
为什么要使用IOC:目的是减少对代码的改动,也能实现不同的功能,实现解耦合。
java中创建对象有哪些方式:

  1. 构造方法 , new Student()
  2. 反射
  3. 序列化
  4. 克隆
  5. ioc :容器创建对象
  6. 动态代理
    IOC的技术体现
    servlet
    1: 创建类继承HttpServelt
    2: 在web.xml 注册servlet , 使用 myservlet
    com.bjpwernode.controller.MyServlet1
    3. 没有创建 Servlet对象, 没有 MyServlet myservlet = new MyServlet()
    4. Servlet 是Tomcat服务器它能你创建的。 Tomcat也称为容器
    Tomcat作为容器:里面存放的有Servlet对象, Listener , Filter对象
    IOC的技术实现:DI(依赖注入)是IOC的技术实现,
    依赖注入:DI,程序代码不做定位查询,这些工作由容器自行完成。只需要在程序中提供要使用的对象名称就可以, 至于对象如何在容器中创建, 赋值,查找都由容器内部实现。

Spring是使用的DI实现了IOC的功能,spring底层创建对象,使用的是反射机制。
Spring是一个容器,管理对象,给属性赋值,底层是反射创建对象。

Spring的第一个程序

步骤:
在这里插入图片描述

创建一个maven项目

使用maven骨架quickstart来创建一个maven项目

加入maven依赖

修改pom.xml文件
在这里插入图片描述

创建类接口和它的实现类

在这里插入图片描述
在这里插入图片描述
正传:(测试代码)
在这里插入图片描述
创建Spring配置文件
在resource文件中创建spring配置文件beans.xml文件
在这里插入图片描述

创建容器,使用容器来创建对象, ApplicationContext就是表示spring容器,通过容器获取对象
从容器中获取某个对象,调用对象的方法,getBean(“配置文件中的id值”);
在这里插入图片描述
在这里插入图片描述

spring创建对象的时机

对象是在执行语句时所创建的:
ApplicationContext appCon = new ClassPathXmlApplicationContext(config);

创建对象的时间是:在创建Spring的容器时,它会创建配置文件中所有的对象。
spring创建对象:默认调用的是无参构造方法

获取容器中对象的信息

在这里插入图片描述

让spring创建一个非自定义类的对象吗,创建一个存在的某个类的对象

在这里插入图片描述

在这里插入图片描述

基于XML的DI

DI的实现方式

1、在spring的配置文件中,使用标签和属性完成,叫做基于XML的di实现
2、使用spring中的注解,完成属性赋值,叫做基于注解的di实现

DI的分类

1、set注入(设值注入):spring调用类的set方法,在set方法可以实现属性的赋值。
大部分使用set注入
实现步骤:
1)创建maven项目
2)加入maven的依赖,spring的依赖,版本5.2.5版本,junit依赖
3)创建类(接口和他的实现类)
和没有使用框架一样,就是普通的类。
4)创建spring需要使用的配置文件
声明类的信息,这些类由spring创建和管理
通过spring的语法,完成属性的赋值
5)测试属性的创建。
在这里插入图片描述
注入:就是赋值的意思
简单类型:spring中规定java的基本数据类型和string都是简单类型。
1)简单类型的set注入




一个property只能给一个属性赋值
set注入调用了set方法:
在这里插入图片描述
设值注入的注意事项:
1、如果类中没有set方法,就会报错,说明如果类没有set方法不可以set注入。
2、set注入首先是调用类的无参构造方法创建对象
3、set注入只要有set方法就可以注入,和创建的属性无关,set注入只是使用set方法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2)引用类型的设置注入
引用类型的set注入:spring调用类的set方法

<bean id="类对象的取一个名称" class="类的路径">
  <property name="属性名称l" ref="bean的id(对象的名称)"></property>
</bean>
  • 1
  • 2
  • 3

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、构造注入,spring调用类的有参数构造方法,创建对象,在构造方法中完成赋值。
构造注入使用标签
标签:一个表示构造方法的一个参数
标签属性:
name:表示构造方法的参数的位置,参数从左往右位置是0,1,2的顺序
value:构造方法的形参类型是简单类型,使用value
ref:构造方法的形参类型是引用类型,使用ref
使用name属性实现构造方法注入:(先后顺序可以变)
在这里插入图片描述
使用index属性实现注入:(先后顺序可以变)
在这里插入图片描述
使用非自定义的类进行构造注入:
在这里插入图片描述
单元测试:
main方法测试的话不方便,每个方法单独测试就使用单元测试
使用单元测试:
1、需要在pom.xml文件中加入junit依赖

junit
junit
4.11
test

2、创建测试用的类:叫做测试类
src/test/java目录中创建类

3、创建测试方法
1)public方法
2)没有返回值void
3)方法名称自定义、建议名称是test+你要测试方法的名称
4)方法没有参数
5)方法的上面加入@Test,这样的方法是可以单独执行的。不用使用main方法。

引用类型属性自动注入

1、byName方式自动注入

引用类型的自动注入:spring框架根据某些规则可以给引用类型赋值。不用自己再给引用类型赋值了
使用的规则常用的是byName,byType.
1、byName(按照名称注入):java类中引用类型的属性名和spring容器中(配置文件的id名称一样,且数据类型是一致的,这样的容器中的bean,spring能够赋值给引用类型。
语法:

简单类型属性赋值

定义student类:三个set方法,两个简单类型一个引用类型
在这里插入图片描述
spring配置文件:在student对象中申明autowire属性,赋值byName,对简单类型进行赋值,引用对象的id设置为类中引用属性的属性名
在这里插入图片描述

2、byType方式自动注入(按照类型注入)

java类中引用类型的数据类型和spring容器中(配置文件)的class属性是同源关系的,这样bean能够赋值给引用类型
同源就是一类的意思:
1、java类引用类型的数据类型和bean的class的值是一样的。
2、java类中引用类型的数据类型和bean的class的值父子类关系的。
3、java类中引用类型的数据类型和bean的class值接口和实现类关系的
语法:

简单类型属性赋值

注意:在byType中,在xml配置文件中声明bean只能有一个符合条件的,多余一个是错误的。

为应用指定多个spring配置文件

实际开发中使用多个配置文件
优势是:
1、每个文件的大小比一个文件要小很多,效率高
2、避免多人竞争带来冲突。(多个模块相关功能在一起)
如果你的项目有多个模块(相关的功能在一起),一个模块一个配置文件。
学生考勤模块,一个配置文件, 张三
学生成绩一个配置文件, 李四
多文件的分配方式:
1、按照功能的模块,一个模块一个配置文件
2、按类的功能,数据库相关的配置一个配置文件,做事务的功能的一个配置文件,做service功能的一个配置文件

包含关系的配置文件:
spring-total表示配置文件:包含其他的配置文件,主配置文件一般是不定义对象的。
语法:
关键字:“classpath:”表示类路劲(class文件所在的目录),
在spring的配置文件中要指定其他文件的位置,需要使用classpath,告诉spring到哪去加载读取
例如:(在包含关系的配置文件中,可以使用通配符如:*表示任意字符)
注意:主的配置文件名称不能包含在通配符的范围内(不能叫做spring-total.xml)

这里是引用

例如:总的文件(包含关系的配置文件)
在这里插入图片描述
分文件:
在这里插入图片描述
分文件:
在这里插入图片描述
调用总的文件:
在这里插入图片描述
在包含关系的配置文件中可以使用配置符(*:表示任意字符),下面这个例子,使用通配符注意不能将主文件包含在内,所以需要修改主文件的文件名称。
注意:主的配置文件不能包含在通配符的范围内(不能叫做spring-total.xml)
在这里插入图片描述

基于注解的DI

通过注解来完成java对象的创建,属性赋值。
1、加入maven的依赖 spring-context,在你加入spring-context的同时,间接加入spring-aop的依赖。
使用注解必须使用spring-aop依赖
在这里插入图片描述
2、在类中加入spring的注解(多个不同功能的注解)
3、在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置
学习注解:@Component、@Respotory、@Service、@Controller、@Value、@Autowired、@Resource
重新创建项目:
在这里插入图片描述
可以设置为1.8版本
在这里插入图片描述
在这里插入图片描述
component注解的使用:

/*
* @Component:创建对象的,等同于<bean>的功能
* 属性:value就是对象的名称,也就是bean的id值,
* value的值是唯一的,创建的对象在整个spring容器中就一个
* 位置:在类的上面
* @Component(value = "mystudent")等同于
* <bean id="mystudent" class = "com.springtest.bao01.Student">
但是还需要一个功能,使用spring的配置文件声明扫描器,告诉注解的位置
* */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里是调用的无参构造方法来创建对象
在这里插入图片描述

多注解项目分层

spring中和@Component功能一致,创建对象的注解还有:
1、@Repository(用在持久层的上面):放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的
2、@Service(用在业务层类的上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的。
3、@Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的。
控制器对象,能够接受用户提交的参数,显示请求处理结果。
以上三个注解的使用语法和@Component一样的。都能够创建对象,但是这三个注解还有额外的功能。
@Repository、@Service、@Controller是用来给对象分层的用法一样角色不同
当所创建的类不是上面三种类型,使用@Component

扫描多个包的三种方式

在这里插入图片描述

简单类型属性赋值

@value:简单类型的属性赋值
/*
* @Value:简单类型的属性赋值
* 属性:value是string类型的,表示简单类型的属性
* 位置:
* 1、在属性定义的上面,无需set方法,推荐使用。
* 2、在set方法上面,用的不比较少
* */
在这里插入图片描述
用的少

引用类型的属性赋值

引用类型Autowired
/*
* 引用类型
* @Autowired:spring框架提供的注解,实现引用类型的赋值。
* spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName,byType
* @Autowired:默认使用的是byType自动注入
* 位置:
* 1)在属性定义的上面,无需set方法,推荐使用
* 2)在set方法的上面
* */
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述
使用byName方式:需要做的是
1、在属性上面加入@Autowired
2、在属性上面加入@Qualified(value=“bean的id”):表示使用指定名称的bean完成赋值
在这里插入图片描述

引用类型AutoWired的required属性

属性:required,是一个boolean类型的,默认true
required=true:表示如果引用类型赋值失败,程序报错,并终止执行。
required=false:表示如果引用类型赋值失败,引用类型是null,程序不报错
在这里插入图片描述
引用类型引用类型 AutoWired 的required属性值推荐使用 ture

JDK注解@Resource自动注入

Spring提供了对jdk中@Resource注解的支持。@Resource注解既可以按名称匹配Bean,也可以按类型匹配Bean。默认是按名称注入,使用该注解,要求jdk必须是6及以上版本。

byType注入引用类型属性

@Resource注解若不带任何参数,采用默认名称的方式注入,按名称不能注入bean,则会按照类型进行Bean的匹配注入。
下面例子首先使用byName,来赋值,但是byName不能行,左移最后使用byType方式
在这里插入图片描述
在这里插入图片描述

byName注入引用类型属性

@Resource只使用byName方式,需要增加一个属性name
name的值是bean的id(名称)
在这里插入图片描述
在这里插入图片描述
如果不能byName赋值,那么就会报错

xml和注解的对比

xml配置文件(适用于经常修改)
优点:
1、可以方便修改值,
2、对象之间的关系一目了然;
3、基于xml配置的时候,只需要修改xml即可,不需要对现有的程序进行修改。

缺点:
1、使用配置文件代码量就多,用起来费事费力。
2、解析xml的时候必然会占用资源,势必会影响到应用程序的性能;
3、xml配置文件过多,会导致维护变得困难
4、开发的时候,既要维护代码又要维护配置文件,使得开发的效率降低;
注解(适用于不经常修改)
优点:
1:注解的解析可以不依赖于第三方库,可以之间使用Java自带的反射
2:注解和代码在一起的,之间在类上,降低了维护两个地方的成本
3:注解如果有问题,在编译期间,就可以验证正确性,如果出错更容易找
4:使用注解开发能够提高开发效率。不用多个地方维护,不用考虑是否存在“潜规则”
缺点:
1:修改的话比较麻烦。如果需要对注解进行修改的话,就需要对整个项目重新编译
2:处理业务类之间的复杂关系,不然xml那样容易修改,也不及xml那样明了
3:在程序中注解太多的话,会影响代码质量,代码简洁会有影响
4:如果后来的人对注解不了解,会给维护带来成本
5:注解功能没有xml配置齐全

第三章、AOP面向切面编程

动态代理

可以在程序的执行过程中,创建代理对象。通过代理对象执行方法,给目标类的方法增加额外的功能(功能增强)

JDK动态代理

jdk动态代理实现步骤:
1、创建目标类,SomeServiceImpl目标类,给它的doSome,doOther增加输出时间,事务。
2、创建InvotationHandler接口的实现类,在这个类实现给目标方法增加功能。
3、使用jdk中类Proxy,创建代理对象。实现创建对象的能力。

CGLIB动态代理(了解)

不使用AOP的开发方式(理解)

AOP概述(将动态代理的技术规范化,让大家在掌握和使用中更加容易)

AOP(Aspect Orient Programming),面向切面编程。面向切面编程是从动态角度考虑程序运行过程。
AOP底层,就是采用动态代理模式实现的。采用两种代理:jdk动态代理,与CGLIB动态代理。
AOP意为面向切面编程,可通过运行期间动态代理实现程序功能的统一维护的一种技术。AOP是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发效率。
1.动态代理
实现方式:jdk动态代理,使用jdk中的Proxy,Method,InvocaitonHanderl创建代理对象。
jdk动态代理要求目标类必须实现接口

cglib动态代理:第三方的工具库,创建代理对象,原理是继承。 通过继承目标类,创建子类。
子类就是代理对象。 要求目标类不能是final的, 方法也不能是final的

2.动态代理的作用:
1)在目标类源代码不改变的情况下,增加功能。
2)减少代码的重复
3)专注业务逻辑代码
4)解耦合,让你的业务功能和日志,事务非业务功能分离。

3.Aop:面向切面编程, 基于动态代理的,可以使用jdk,cglib两种代理方式。
Aop就是动态代理的规范化, 把动态代理的实现步骤,方式都定义好了,
让开发人员用一种统一的方式,使用动态代理。

4、AOP(Aspect Orient Programming)面向切面编程
Aspect: 切面,给你的目标类增加的功能,就是切面。 像上面用的日志,事务都是切面。
切面的特点: 一般都是非业务方法,独立使用的。
Orient:面向, 对着。
Programming:编程
OOP:即面向对象编程,本质上是一种编程思想,通过把我们编程中遇到的事物来抽象成对象来编程;
怎么理解面向切面编程 ?
1)需要在分析项目功能时,找出切面。
2)合理的安排切面的执行时间(在目标方法前, 还是目标方法后)
3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能
术语:
1)Aspect:切面,表示增强的功能, 就是一堆代码,完成某个一个功能。非业务功能,
常见的切面功能有日志, 事务, 统计信息, 参数检查, 权限验证。

2)JoinPoint:连接点 ,连接业务方法和切面的位置。 就某类中的业务方法
3)Pointcut : 切入点 ,指多个连接点方法的集合。多个方法
4)目标对象: 给哪个类的方法增加功能, 这个类就是目标对象
5)Advice:通知,通知表示切面功能执行的时间。
说一个切面有三个关键的要素:
1)切面的功能代码,切面干什么
2)切面的执行位置,使用Pointcut表示切面执行的位置
3)切面的执行时间,使用Advice表示时间,在目标方法之前,还是目标方法之后。
5.aop的实现(主要使用aspectJ
aop是一个规范,是动态的一个规范化,一个标准
aop的技术实现框架:
1.spring:spring在内部实现了aop规范,能做aop的工作。
spring主要在事务处理时使用aop。
我们项目开发中很少使用spring的aop实现。 因为spring的aop比较笨重。

2.aspectJ: 一个开源的专门做aop的框架。spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能。
aspectJ框架实现aop有两种方式:
1.使用xml的配置文件 : 配置全局事务
2.使用注解,我们在项目中要做aop功能,一般都使用注解, aspectj有5个注解。
6.学习aspectj框架的使用。
1)切面的执行时间, 这个执行时间在规范中叫做Advice(通知,增强)
在aspectj框架中使用注解表示的。也可以使用xml配置文件中的标签
1)@Before
2)@AfterReturning
3)@Around
4)@AfterThrowing
5)@After
@Before前置通知注解-方法有JoinPoint参数()也就是切面表达式
在目标方法执行之前执行。背注解为前置通知方法,可以包含一个JoinPoint类型参数。该类型对象本身就是切入点表达式。通过该参数,可以获取切入点表达式、方法签名、目标对象。
2)表示切面执行的位置,使用的是切入点表达式。

	AspectJ定义了专门的表达式用于指定切入点。表达式的原型是:
  • 1

在这里插入图片描述
modifiers-pattern 访问权限类型
ret-type-pattern 返回值类型
declaring-type-pattern 包名类名
name-pattern(param-pattern)方法名(参数类型和参数个数)
throws-patern抛出异常类型
?表示可选的部分
以上表达式共四个部分。
execution(访问权限 方法返回值 方发声明 (参数)异常类型)

	切入点表达式要匹配的对象就是目标方法的方法名。所以,execution表达式中明显就是方法的签名。注意,表达式中黑色文字表示省略部分,各部分间用空格分开。在其中使用以下符号
  • 1

在这里插入图片描述
举例:

execution(public * (…))
指定切入点:任意公共方法。
execution(
set*(…))
指定切入点为:任何一个以“set”开始的方法。
execution(* com.xyz.service..(…))
指定切入点为:com.xyz.service包中的任意类的任意方法
execution(* com.xyz.service….(…))
指定切入点为:定义在service包或者子包里的任意类的任意方法。“…”出现在类名中时,后面必须跟“”,表示包、子包下的所有类。
execution(
…service..(…))
指定所有包下所有类(接口)中所有方法为切入点
execution(
.service..(…))
指定只有一级包下的service子包下的所有类(接口)中所有方法为切入点。
例如:指定以下的service包中的所有类中,所有方法为切入点。
com.service.impl
com.bjpowrnode.service.impl
cn.crm.bjpowernode.service
使用表达式为:execution(
…service..*(…))

AOP的功能实现(项目实现)

使用quickstart创建一个项目:
05Spring-aop-aspectJ:使用aspectJ框架实现aop。
使用aop:目的是给已经存在的一些类和方法,增加额外的功能。前提是不改变原来类的代码。
使用aspectJ实现aop的基本步骤:
1、新建maven项目
2、加入依赖
1)spring依赖
2)aspectJ依赖
3)Junit测试单元
3、创建目标类:接口和它的实现类
要做的是给类中的方法增加功能
4、创建切面类:普通类
1)在类的上面加入@Aspect
2)在类中定义方法,方法就是切面要执行的功能代码
在方法的上面加入aspectj中的通知注解,例如@Before
有需要指定切入点表达式execution()
5、创建spring的配置文件:声明对象,把对象交给容器统一管理
声明对象你可以使用注解或者xml配置文件
1)声明目标对象
2)声明切面对象
3)声明aspectJ框架中的自动代理生成器标签
自动代理生成器:用来完成代理对象的自动创建功能的。
6、创建测试类,从spring容器中获取目标对象(实际上就是代理对象)。
通过代理执行方法,实现aop的功能增强。

========================
1、新建maven项目
2、加入依赖
在这里插入图片描述
3、创建目标类:接口和它的实现类
在这里插入图片描述
在这里插入图片描述
4、创建切片类在这里插入图片描述
5、创建spring的配置文件:声明对象,把对象交给容器统一管理
声明对象你可以使用注解或者xml配置文件
在这里插入图片描述
6、创建测试类,从spring容器中获取目标对象
在这里插入图片描述
验证proxy为代理对象,动态代理使用的是jdk动态代理方式。(目标类有接口是jdk动态代理)
自动代理生成器使用AspectJ框架内部的功能,创建目标对象的代理对象。 创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象,所以目标对象就是被修改后的代理对象,aspectj-qutoproxy:会把spring容器中的所有目标对象,一次性都生代理对象。

AspectJ基于注解的AOP实现(掌握)

@Before前置通知注解-方法有JoinPoint参数()也就是切面表达式
在目标方法执行之前执行。背注解为前置通知方法,可以包含一个JoinPoint类型参数。该类型对象本身就是切入点表达式。通过该参数,可以获取切入点表达式、方法签名、目标对象。

JoinPoint(连接点):业务方法,要加入切面功能的业务方法(如果切面中需要用到方法的信息,就要加入JoinPoint)
作用是:可以在通知方法中获取方法执行时的信息,例如方法名称、方法实参。
如果你的切面中需要用到方法的信息,就加入JoinPoint。
这个JoinPoint参数的值是由框架赋予,必须是一个位置的参数
在这里插入图片描述
@AfterReturning:后置通知
/*后置通知定义方法,方法是实现切面功能的。
属性:
1、value切入点表达式
2、returning 自定义的变量、表示目标方法的返回值的。
自定义变量名必须和通知方法的形参名一样。
位置在方法定义的上面
特点:
1、在目标方法之后执行的。
2、能够获取目标方法的返回值,可以根据这个返回值做不同的处理功能
3、可以修改这个返回值
后置通知的定义方法,方法是实现要求:
1、公共方法public
2、方法没有返回值
3、方法名称自定义
4、方法有参数,推荐是Object,参数名自定义

在这里插入图片描述
@Around环绕通知(功能最强的一种通知)(掌握)

  • @Aspect:是AspectJ框架中的注解。
  • 作用:表示当前类是切面类。
  • 切面类:是用来非业务方法增加功能的类,在这个类中有切面的功能代码。
  • 位置:在类定义的上面。
  •  * 环绕通知方法的定义格式
    
    • 1
    • 1、public
    • 2、必须有一个返回值,推荐使用Object
    • 3、方法名称自定义
    • 4、方法有参数,固定的参数ProceedingJoinPoint
      *@Around:环绕通知
    • 属性:value切入点表达式
    • 位置:在方法的上面定义
      *特点:
    • 1、它是功能最强的通知
    • 2、在目标方法前和后都能增强功能
    • 3、控制目标方法是否被调用执行
    • 4、修改原来的目标方法的执行结果。影响最后的调用结果
    • 环绕通知,等同于jdk动态代理的,InvocationHandler接口
    • 参数:ProceedingJointPoint就等同于Method
    • 作用:执行目标方法的
    • 返回值:就是目标方法的执行结果,可以被修改
    • 在这里插入图片描述
      在这里插入图片描述
      说明在环绕通知中能够将结果改变成自己设置的结果。
      环绕通知:经常做的是事务,在目标方法之前开始事务,执行目标方法,在目标方法之后提交事务。

@AfterThrowing异常通知-注解中有throwing属性(了解)
* 异常通知方法的定义格式
* 1、public
* 2、没有返回值
* 3、方法名称自定义
* 4、方法有一个Exception,如果还有就是JoinPoint
*@AfterThrowing:异常通知
* 属性:
* 1、value切入点表达式
* 2、throwing自定义的变量,表示目标方法抛出的异常对象。变量名必须和方法的参数名一样
* 特点:
* 1、在目标方法抛出异常时执行的
* 2、可以做异常的监控程序,监控目标方法执行时是不是有异常。如果有异常,可以发送邮件,短信进行通知
* 位置:在方法的上面定义
在这里插入图片描述
@After: 最终通知
* 属性:value切入点表达式
* 位置:在方法上面
* 特点:
* 1、总是会执行
* 2、在目标方法之后执行的
* 作用一般是做资源清除的
在这里插入图片描述
@Pointcut:定义和管理切入点
如果你的项目中有多个切入点表达式是重复的,可以复用,可以使用@Pointcut

  • 属性:value切入点表达式
  • 位置:在自定义的方法上面
  • 特点:当使用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名,其他的通知中,value属性就可以使用这个方法名称
  • 代替切入点表达式
    在这里插入图片描述
    有接口类和没有接口类的代理方式:
    proxy是代理对象:
    System.out.println(proxy.getClass().getName());
    如果目标类有接口,那么使用的是JDK的动态代理,
    如果目标类没有接口,那么使用的是spring中的CGLIB动态代理,
    在这里插入图片描述
    有接口也可以使用CGLIB动态代理:
  • 如果期望目标类有接口,使用CGLIB代理
  • 设置属性:proxy-target-class=“true”;告诉框架,要使用cglib动态代理
    在这里插入图片描述

第四章 Spring集成MyBatis

将spring和mybatis放在一起用,主要解决的问题就是将SQLSessionFactory对象交由Spring来管理。所以,该整合,只需要将SQLSessionFactory的对象生成器SQLSessionFactoryBean注入册在Spring容器中,再将其注入给Dao的实现类即可完成整合。实现Spring与Mybatis的整合常用的方式:扫描Mapper动态代理
把myBatis框架和spring集成在一起,像一个框架一样使用。使用的技术是:ioc。
为什么IOC能够把mybatis和spring集成在一起,像一个框架一样使用?
是因为ioc能够创建对象。可以把mybatis框架中的对象交给spring统一创建,开发人员从spring中获取对象。开发人员就不用同时面对两个或者多个框架了,就面对一个spring。

mybatis使用步骤,对象
1、定义dao接口,StudentDao
2、定义mapper文件 StudentDao.xml
3、定义mybatis的主配置文件mybatis.xml
4、创建dao的代理对象,StudentDao dao = SQLSession.getMapper(StudentDao.class);
List students = dao.selecStudents();
要使用dao对象,需要使用getMapper()方法,
怎么能使用getMapper()方法,需要哪些条件
1、获取SqlSession对象,需要使用SQLSessionFactory的openSession()方法。
2、创建SqlSessionFactory对象。通过读取mybatis的主配置文件,能创建SQLSessionFactory对象。
需要SQLSessionFactory对象,使用Factory能获取SQLSession,有了SQLSession就能有dao,目的就是获取dao对象。
Factory创建需要读取主配置文件

主配置文件:
1.数据库信息:我们会使用独立的连接池类替换mybatis默认自己带的,把连接池类交给spring创建。

 <environment id="mydev">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库的驱动类名-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
                <!--访问数据库的用户名-->
                <property name="username" value="root"/>
                <!--密码-->
                <property name="password" value="123456"/>
            </dataSource>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  1. mapper文件的位置
   <mappers>
        <mapper resource="com/bjpowernode/dao/StudentDao.xml"/>
        <!--<mapper resource="com/bjpowernode/dao/SchoolDao.xml" />-->
    </mappers>
  • 1
  • 2
  • 3
  • 4

============================================================
通过以上的说明,我们需要让spring创建以下对象
1.独立的连接池类的对象, 使用阿里的druid连接池
2.SqlSessionFactory对象
3.创建出dao对象

需要学习就是上面三个对象的创建语法,使用xml的bean标签。
集成Mybatis的步骤:

06Spring-Mybatis:spring和mybatis的集成
步骤:
1、创建maven项目
2、加入maven依赖
1)spring
2)mybatis
3)mysql驱动
4)spring的事务的依赖
5)mybatis和spring的依赖:mybatis官方体用的,用来在spring项目中创建mybatis的SQLSessionFactory,dao对象
3、创建实体类
4、创建dao接口和mapper文件
5、创建mybatis主配置文件
6、创建Service接口和实现类,属性是dao
7、创建spring的配置文件:声明mybatis的对象交给spring创建
1)数据源
2)SqlSessionFactory
3)dao对象
8、创建测试类,获取Service对象,通过service调用dao完成数据库的访问
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

1、创建maven项目
2、加入maven依赖和插件

<!--单元测试-->
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
<!--    spring核心IOC-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
<!--    做spring事务用到的-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>
<!--    mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <!--    mybatis和spring集成的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
<!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.29</version>
    </dependency>
<!--阿里公司的连接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.12</version>
    </dependency>
<!--lombok快速为类对象创建set、get、构造等函数-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  <build>
    <!--目的是吧src/main/java目录中的xml文件包含到输出结果中。输出到classes目录中-->
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
<!--    指定jdk的版本-->
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

3、创建实体类

@Data
public class Student {
    //属性和列名一样
    private  Integer id;
    private String name;
    private String email;
    private Integer age;
    public Student(Integer id, String name, String email, Integer age) {//用于对对象赋值
        this.id = id;
        this.name = name;
        this.email = email;
        this.age = age;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

4、创建dao接口和mapper文件
dao接口:

public interface StudentDao {

    int inserStudent(Student student);
    List<Student> SelectStudents();
}
  • 1
  • 2
  • 3
  • 4
  • 5

mapper文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//OTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace = "com.Springtest.dao.StudentDao">
    <insert id="insertStudent" >
        insert  into Student values (#{id},#{name},#{email},#{age})
    </insert>
    <select id="selectStudents" resultType="com.Springtest.domain.Student">
        select  id,name,email,age, from student order by id desc
    </select>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

注意:mybatis配置文件,Mapper标签下以package包扫描形式时需要Mapper.xml文件名称和mapper接口名称一致,当核心配置文件mapper标签下以resource形式指向依赖配置文件时,不需要,这样就可以加载到其相应的依赖配置文件通过namespace找到其相应的方法

例如:

    <mappers>
    <mapper resource="grg/auto/mapper/DepartMapper.xml"/>
    </mappers>
  • 1
  • 2
  • 3

5、创建mybatis主配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--settings:控制mybatis全局行为-->
    <settings>
        <!--设置mybatis输出日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--设置别名-->
    <typeAliases>
        <!--<typeAlias type="com.pojo.User" alias="User"></typeAlias>-->
        <!--name:实体类所在的包名,表示可以直接使用该包名下的实体类的大小写-->
        <package name="com.Springtest.domain"/>
    </typeAliases>

    <mappers>
        <package name="com.Springtest.dao"/>
    </mappers>
</configuration>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

6、创建Service接口和实现类,属性是dao

public class StudentServiceImpl implements StudentService {
    //引用类型
    private StudentDao studentDao;
    //使用set注入,赋值
    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
    }
    @Override
    public int addStudent(Student student) {
        int nums = studentDao.inserStudent(student);
        return nums;
    }
    @Override
    public List<Student> queryStudents() {
        return null;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
public interface StudentService {
    int addStudent(Student student);
    List<Student> queryStudents();
}
  • 1
  • 2
  • 3
  • 4

7、创建spring的配置文件:声明mybatis的对象交给spring创建
1)数据源
2)SqlSessionFactory
3)dao对象

<!--声明数据源DataSource,作用是连接数据库-->
    <bean id = "myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!--set注入给DruidDataSource提供数据库信息-->
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property>
        <property name="username" value="root"></property>
        <property name="password" value="admin"></property>
        <property name="maxActive" value="20"></property><!--连接的数量最多是20-->
    </bean>
<!--声明的是mybatis中提供的SQLSessionFactoryBean类,这个类内部创建SQLSessionFactory-->
    <bean id = "sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--set注入,把数据库连接池付给dataSource属性-->
        <property name="dataSource" ref="myDataSource"></property>
        <!--mybatis主配置文件的位置
        configLocation属性是Resource类型,读取配置文件
        它的赋值,使用Value,指定文件的路径,使用classpath:表示文件的位置
        -->
        <property name="configLocation" value="classpath:mybatis.xml"></property>
    </bean>
<!--创建dao对象,使用SQLSessiongetMapper(StudentMapper.class)
        MapperScannerConfigurer:在内部调用
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--指定SqlSessionFactory对象的id-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
        <!--指定包名,包名是dao接口所在的包名。
            MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper方法,得到每个
            接口的dao对象。创建好的dao对象放入到spring的容器中的,dao对象的默认名称是接口名的首字母小写
        -->
        <property name="basePackage" value="com.Springtest.dao"></property>
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

在实际开发中只需要修改dao对象bean配置文件中,指定接口所在包的位置

8、创建测试类,获取Service对象,通过service调用dao完成数据库的访问
声明service:

    <!--声明service-->
    <bean id="StudentService" class="com.Springtest.service.impl.StudentServiceImpl">
        <!--name:属性名     ref:对象的名称       创建的对象赋值给属性,那么service就可以使用dao了-->
        <property name="studentMapper" ref="studentMapper"></property>
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
    /*获取Service对象,通过service调用dao完成数据库的访问,执行查询操作*/
    @Test
    public void test4()
    {
        String config = "applicationContext.xml";
        ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
        StudentService service = (StudentService) ctx.getBean("StudentService");
        List<Student> students = service.queryStudents();
        for (int i = 0; i <students.size() ; i++) {
            System.out.println(students.get(i));
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

9、添加配置文件,对数据库进行配置,写在一个独立的文件中,编译修改数据库的配置内容。

    <!--把数据库的配置,写在一个独立的文件中,编译修改数据库的配置内容
    spring知道jdbc.properties文件的位置
    -->
   <context:property-placeholder location="jdbc.properties" />
  • 1
  • 2
  • 3
  • 4
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=admin
jdbc.maxActive=20
  • 1
  • 2
  • 3
  • 4

**问题解决:**解决通配符的匹配很全面,但是无法找到元素“context:property-placeholder”的声明,引入命名空间时报错
原因:原因是在引入命名空间时没有正确引入它的DTD解析文件。
在这里插入图片描述
在这里插入图片描述

第五章 Spring事务(理论多)

Spring的事务管理

问题:

  1. 什么是事务
    在讲mysql的时候,提出了事务,事务是指一组sql语句的集合,在集合中有多条sql语句可能是insert,update,select,delete,我们希望这些多个sql语句都能够成功,或者都失败,这些sql语句的执行是一致的,作为一个整体执行。
  2. 什么时候想到使用事务?
    当我们的操作,涉及到多个表,或者是多个SQL语句的insert,update,delete。需要保证这些语句都是成功才能完成我的功能,或者都失败,保证操作是符合要求的。

在java代码中要写程序来控制事务,此时事务应该放在那里。
service类的业务方法上,因为业务方法会调用多个dao方法,执行多个sql语句

  1. 通常使用JDBC访问数据库,还是mybatis访问数据库怎么处理事务
    jdbc访问数据库,处理事务 Connection conn ; conn。commit();conn.rollback();mybatis访问数据库处理事务,SQLSession.commit();SqlSession.rollback();
    hibernate访问数据库,处理事务,Session.commit();Session.rollback();

  2. 3问题中事务的处理方式,有什么不足
    1、不同的数据库访问技术,处理事务的对象,方法不同,需要去了解不同数据库访问技术使用事务的原理,
    2、掌握多重数据库中事务的处理逻辑。什么时候提交事务,什么时候回顾事务
    3、处理事务的多种方法
    总结:就是多种数据库的访问技术,有不同的事务处理机制,对象,方法。

  3. 怎么解决不足
    spring提供一种处理事务的统一模型,能使用统一步骤,方式完成多种不同的数据库访问技术的事务处理。
    使用spring的事务处理机制,可以完成mybatis访问数据库的事务处理
    使用spring事务处理机制,可以完成hibernate访问数据库的事务处理

  4. 处理事务,需要怎么做,做什么
    spring处理事务的模型,使用的步骤都是固定的。把事务使用的信息提供给spring就可以了
    1)事务内部提交,回滚事务,使用的事务管理器对象,代替你完成commit,rollback
    事务管理器是一个接口和他的众多实现类。
    接口:PlatformTransactionManager ,定义了事务重要方法 commit ,rollback
    实现类:spring把每一种数据库访问技术对应的事务处理类都创建好了。
    mybatis访问数据库—spring创建好的是DataSourceTransactionManager
    hibernate访问数据库----spring创建的是HibernateTransactionManager
    怎么使用:你需要告诉spring 你用是那种数据库的访问技术,怎么告诉spring呢?
    声明数据库访问技术对于的事务管理器实现类, 在spring的配置文件中使用声明就可以了
    例如,你要使用mybatis访问数据库,你应该在xml配置文件中
    <bean id=“xxx" class=“…DataSourceTransactionManager”>

    2)你的业务方法需要什么样的事务,说明需要事务的类型。
    说明方法需要的事务:
    1)事务的隔离级别:有4个值。
    DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ; Oracle默认为 READ_COMMITTED。
    ➢ READ_UNCOMMITTED:读未提交。未解决任何并发问题。
    ➢ READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
    ➢ REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
    ➢ SERIALIZABLE:串行化。不存在并发问题。

    1. 事务的超时时间: 表示一个方法最长的执行时间,如果方法执行时超过了时间,事务就回滚。
      单位是秒, 整数值, 默认是 -1.

    3)事务的传播行为 : 控制业务方法是不是有事务的, 是什么样的事务的。
    7个传播行为,表示你的业务方法调用时,事务在方法之间是如果使用的。

    	*PROPAGATION_REQUIRED
    	PROPAGATION_REQUIRES_NEW
    	PROPAGATION_SUPPORTS*
    	以上三个需要掌握的
    
    	PROPAGATION_MANDATORY
    	PROPAGATION_NESTED
    	PROPAGATION_NEVER
    	PROPAGATION_NOT_SUPPORTED
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

3)事务提交事务,回滚事务的时机
1)当你的业务方法,执行成功,没有异常抛出,当方法执行完毕,spring在方法执行后提交事务。事务管理器commit

  2)当你的业务方法抛出运行时异常或ERROR, spring执行回滚,调用事务管理器的rollback
     运行时异常的定义: RuntimeException  和他的子类都是运行时异常, 例如NullPointException , NumberFormatException
  
  3) 当你的业务方法抛出非运行时异常, 主要是受查异常时,提交事务
    受查异常:在你写代码中,必须处理的异常。例如IOException, SQLException
  • 1
  • 2
  • 3
  • 4
  • 5

总结spring的事务
1.管理事务的是 事务管理和他的实现类
2.spring的事务是一个统一模型
1)指定要使用的事务管理器实现类,使用
2)指定哪些类,哪些方法需要加入事务的功能
3)指定方法需要的隔离级别,传播行为,超时

  你需要告诉spring,你的项目中类信息,方法的名称,方法的事务传播行为。
  • 1

spring框架中提供的事务处理方案
1.适合中小项目使用的, 注解方案。
spring框架自己用aop实现给业务方法增加事务的功能, 使用@Transactional注解增加事务。
@Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。
可以给注解的属性赋值,表示具体的隔离级别,传播行为,异常信息等等

使用@Transactional的步骤:
1.需要声明事务管理器对象

2.开启事务注解驱动, 告诉spring框架,我要使用注解的方式管理事务。
spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
spring给业务方法加入事务:
在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知

	 @Around("你要增加的事务功能的业务方法名称")
	 Object myAround(){
       开启事务,spring给你开启
		  try{
		     buy(1001,10);
			  spring的事务管理器.commit();
		  }catch(Exception e){
         spring的事务管理器.rollback();
		  }
		 
	 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

3.在你的方法的上面加入@Trancational
2.适合大型项目,有很多的类,方法,需要大量的配置事务,使用aspectj框架功能,在spring配置文件中
声明类,方法需要的事务。这种方式业务方法和事务配置完全分离。

实现步骤: 都是在xml配置文件中实现。
1)要使用的是aspectj框架,需要加入依赖

	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-aspects</artifactId>
		<version>5.2.5.RELEASE</version>
	</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
2)声明事务管理器对象
 
<bean id="xx" class="DataSourceTransactionManager">

3) 声明方法需要的事务类型(配置方法的事务属性【隔离级别,传播行为,超时】)
4) 配置aop:指定哪些哪类要创建代理。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

程序举例环境搭建:

举例:购买商品trans_sale项目
本例要实现购买商品,模拟用户下订单,向订单表添加销售记录,从商品表减少库存。
实现步骤:
1、创建两个数据库表sale,goods
sale销售表
在这里插入图片描述

goods货品表
在这里插入图片描述
2、添加maven依赖

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>
  <!--单元测试-->
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--    spring核心IOC-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--    做spring事务用到的-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>
    <!--    mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <!--    mybatis和spring集成的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.29</version>
    </dependency>
    <!--阿里公司的连接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.12</version>
    </dependency>
    <!--lombok快速为类对象创建set、get、构造等函数-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <!--目的是吧src/main/java目录中的xml文件包含到输出结果中。输出到classes目录中-->
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <!--        —filtering 选项 false 不启用过滤器, *.property 已经起到过滤的作用了 -->
        <filtering>false</filtering>
      </resource>
    </resources>
    <!--    指定jdk的版本-->
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

3、创建实体类
Sale,Goods

@Data
public class Goods {
    private Integer id;
    private String name;
    private Integer amount;
    private Float price;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
@Data
public class Sale {
    private Integer id;
    private Integer gid;
    private Integer nums;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4、创建dao接口和mapper文件
SaleDao接口,GoodsDao接口
响应的XML文件
Sale.xml,GoodsDao.xml

<mapper namespace="org.example.dao.GoodsDao">
    <select id="selectGoods" resultType="goods">
        select id,name,amount,price from goods where id = #{id}
    </select>
    <update id="updateGoods">
        update goods set amount = amount -#{amount} where id = #{id}
    </update>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
<mapper namespace="org.example.dao.SaleDao">
    <insert id="insertSale">
        insert into sale(gid,nums) values(#{gid},#{nums})
    </insert>
</mapper>
  • 1
  • 2
  • 3
  • 4
  • 5
public interface GoodsDao {
//    更新库存
//    goods表示本次用户购买的商品信息,id,购买数量
    int updateGoods(Goods goods);
//    查询商品的信息
    Goods selectGoods(Integer id);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
public interface SaleDao {
//    增加销售记录(订单记录)
    int insertSale(Sale sale);
}
  • 1
  • 2
  • 3
  • 4

5、创建mybatis主配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <typeAliases>
        <!--<typeAlias type="com.pojo.User" alias="User"></typeAlias>-->
        <!--name:实体类所在的包名,表示可以直接使用该包名下的实体类的大小写-->
        <package name="org.example.domain"/>
    </typeAliases>
    <mappers>
<!--        <mapper resource="com/Springtest/dao/StudentMapper.xml"/>-->
          <!--  当核心配置文件mapper标签下以resource形式指向依赖配置文件时,不需要,Mapper.xml文件名称和mapper接口名称一致-->

 <!--       当核心配置文件mapper标签下以class形式指向依赖配置文件时,class指向接口位置-->
<!--        <mapper class="org.example.dao.SaleDao"></mapper>-->

        <package name="org.example.dao"/>
        <!--        mybatis配置文件,Mappers标签下以package包扫描形式时需要Mapper.xml文件名称和mapper接口名称一致,name是包名这个包下的所有xml文件一次性加载-->
    </mappers>
</configuration>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

6、创建异常处理方法

//自定义的运行时异常
//重写两个方法有参和无参
public class NotEnoughException extends RuntimeException{

    public NotEnoughException(){
        super();
    }
    public NotEnoughException(String message){
        super(message);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

7、创建Service接口和实现类

public interface BuyGoodsService {
    //购买商品的方法,goodsId:购买商品的编号 ,nums:购买的数量
    void buy(Integer goodsId,Integer nums);
}
  • 1
  • 2
  • 3
  • 4
public class BuyGoodsServiceImpl implements BuyGoodsService {
    private GoodsDao goodsDao;
    private SaleDao saleDao;
    @Override
    public void buy(Integer goodsId, Integer nums) {//goodsId:表示买入的商品编号,nums:表示买入的数量
        System.out.println("=====buy方法的开始=====");
        //记录销售信息,向sale表添加记录
        Sale sale = new Sale();
        sale.setGid(goodsId);
        sale.setNums(nums);
        saleDao.insertSale(sale);
        //更新库存
        Goods goods = goodsDao.selectGoods(goodsId);
        if (goods==null){
            //商品不存在
            throw new NullPointerException("编号是:"+goodsId+"的商品不存在");
        }else if(goods.getAmount()<nums){
            //商品库存不够
            throw new NotEnoughException("编号是:"+goodsId+"的商品库存不足");
        }
        Goods buyGoods = new Goods();
        buyGoods.setId(goodsId);
        buyGoods.setAmount(nums);
        goodsDao.updateGoods(buyGoods);
        System.out.println("=====buy方法的完成=====");
    }
    //set方法完成属性的赋值
    public void setGoodsDao(GoodsDao goodsDao) {
        this.goodsDao = goodsDao;
    }

    public void setSaleDao(SaleDao saleDao) {
        this.saleDao = saleDao;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

8、创建spring的配置文件:声明mybatis的对象交给spring创建

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.2.xsd
       http://www.springframework.org/schema/util
       https://www.springframework.org/schema/util/spring-util.xsd">
    <!--把数据库的配置,写在一个独立的文件中,编译修改数据库的配置内容
    spring知道jdbc.properties文件的位置
    -->
   <context:property-placeholder location="jdbc.properties" />
    <!--声明数据源DataSource,作用是连接数据库-->
    <bean id = "myDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!--set注入给DruidDataSource提供数据库信息-->
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="maxActive" value="${jdbc.maxActive}"></property><!--连接的数量最多是20-->
    </bean>
    <!--声明的是mybatis中提供的SQLSessionFactoryBean类,这个类内部创建SQLSessionFactory-->
    <bean id = "sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--set注入,把数据库连接池付给dataSource属性-->
        <property name="dataSource" ref="myDataSource"></property>
        <!--mybatis主配置文件的位置
        configLocation属性是Resource类型,读取配置文件
        它的赋值,使用Value,指定文件的路径,使用classpath:表示文件的位置
        -->
        <property name="configLocation" value="classpath:mybatis.xml"></property>
    </bean>

    <!--创建dao对象,使用SQLSessiongetMapper(StudentMapper.class)
        MapperScannerConfigurer:在内部调用
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--指定SqlSessionFactory对象的id-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
        <!--指定包名,包名是dao接口所在的包名。
            MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次getMapper方法,得到每个
            接口的dao对象。创建好的dao对象放入到spring的容器中的,dao对象的默认名称是接口名的首字母小写
        -->
        <property name="basePackage" value="org.example.dao"></property>
    </bean>
    <!--声明service-->
    <bean id="BuyGoodsService" class="org.example.service.impl.BuyGoodsServiceImpl">
        <!--name:属性名     ref:对象的名称       创建的对象赋值给属性,那么service就可以使用dao了-->
        <property name="goodsDao" ref="goodsDao"></property>
        <property name="saleDao" ref="saleDao"></property>
    </bean>
</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

9、创建测试类,获取Service对象

通过增加事务:使数据库的操作处于一种一致的状态之下,添加成功了那么库存就应该更新,如果有一个失败了,那么整个操作需要撤销需要通过事务来进行操作。给buy方法添加事务,它在执行过程中会涉及到多个数据库的操作,buy方法需要添加事务。

如果不添加事务:就会导致sql语句执行不一致,导致最终的结果不正确。,以下实例如果没有添加事务,购买不存在的商品会添加记录到销售表中,而后报错,不会执行,更改库存的sql操作,那么就会导致,两张表的执行不一致。

    @Override
    public void buy(Integer goodsId, Integer nums) {//goodsId:表示买入的商品编号,nums:表示买入的数量
        System.out.println("=====buy方法的开始=====");
        //记录销售信息,向sale表添加记录
        Sale sale = new Sale();
        sale.setGid(goodsId);
        sale.setNums(nums);
        saleDao.insertSale(sale);
        //更新库存
        Goods goods = goodsDao.selectGoods(goodsId);
        if (goods==null){
            //商品不存在
            throw new NullPointerException("编号是:"+goodsId+"的商品不存在");
        }else if(goods.getAmount()<nums){
            //商品库存不够
            throw new NotEnoughException("编号是:"+goodsId+"的商品库存不足");
        }
        Goods buyGoods = new Goods();
        buyGoods.setId(goodsId);
        buyGoods.setAmount(nums);
        goodsDao.updateGoods(buyGoods);
        System.out.println("=====buy方法的完成=====");
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

测试代码:

    @Test
    public void test01()
    {
        String config = "applicationContext.xml";
        ApplicationContext cxt = new ClassPathXmlApplicationContext(config);
//        从容器中获取service
        BuyGoodsService buyGoodsService = (BuyGoodsService) cxt.getBean("BuyGoodsService");
//        调用方法
//        buyGoodsService.buy(1001,10);
        buyGoodsService.buy(1001,200);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

测试结果:
在这里插入图片描述
在这里插入图片描述

增加事务:怎么给已经存在的代码,额外的增加事务功能,在增加时项目中的逻辑代码

通过aop的机制给buy方法增加事务
spring框架中提供的事务处理方案
1、适合中小项目使用的,注解方案。
spring框架自己用aop实现给业务方法增加事务的功能,使用@Transactional注解增加事务。
@Transactional注解是spring框架自己注解,放在public方法的上面,表示当前方法具有事务。
所有属性如下:
propagation:用于设置事务传播属性。该属性类型为Propagation枚举,默认值为Propagation.REQUIRED。
isolation:用于设置事务的隔离级别。该属性类型为Isolation枚举,默认值为Isolation.DEFAULT。
readOnly:用于设置该方法对数据库的操作是否是只读的。该属性为boolean,默认值为false。
timeout:用于设置本操作与数据库连接的超时时限。单位为秒,类型为int,默认值为-1,即没有时限。
rollbackFor:指定需要回滚的异常类。类型为Class[],默认值为空数组。当然,若只有一个异常类时,可以不使用数组。

使用spring的事务注解来管理事务:

在小项目中管理事务

通过@Transactional注解方式,可将事务织入到相应的public方法中,实现事务管理。
使用@Transactional注解的步骤:
1、声明事务管理器对象

<bean id="xx" class="DataSourceTransactionManager">
  • 1

2、开启事务注解驱动,告诉spring框架,我要使用注解的方式管理事务。
spring使用aop机制,创建@Transactional所在的类代理对象,给方法加入事务的功能。
spring给业务方法加入事务:
在你的业务方法执行之前,先开启事务,在业务方法之后提交或回滚事务,使用aop的环绕通知别人已经在里面写过了,不用自己写
@Around(“你要增加的那个事务功能的业务方法名称”)
object myAround(){
开启事务,spring给你开启
try{
buy(1001,10);
spring的事务管理.commit();
}catch(Exception){
spring的事物管理.rollback();
}
}
3、在你的方法上面加入@Transactional注解
步骤:
1、声明事务管理器对象

    <!--使用spring的事务处理-->
    <!--1、声明spring的事务管理器,完成事务提交和事务回滚的-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--连接数据库,指定数据源-->
        <property name="dataSource" ref="myDataSource"/>
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、开启事务注解驱动

    <!--2、开启事务注解驱动,告诉spring使用注解管理事务,创建代理对象transaction-manager:事务管理器对象的id-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
  • 1
  • 2

3、在方法上面加入以下@Transactional注解,其中的设置都是默认值,默认的传播行为、默认的隔离级别、默认抛出运行时异常回滚事务,或者直接加入@Transactional。
rollbackFor:表示发生指定的异常一定回滚。
处理逻辑是:
1、spring框架会首先检查出方法抛出异常是不是在rollbackFor的属性值中,如果异常在rollbackFor列表中,不管是什么类型的异常,一定回滚。
2、如果你的抛出的异常不在rollbackFor列表中,spring会判断异常是不是RuntimeException,如果是一定回滚。

    @Transactional(//rollbackFor,当发生指定异常时,会回滚
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            rollbackFor = {
                    NullPointerException.class,NotEnoughException.class
            }
    )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在大项目中管理事务:

有很多的类,方法,需要大量的配置事务,使用aspectj框架功能,在spring配置文件中声明类,方法需要的事务。这种方式业务方法和事务配置完全分离。

使用AspectJ的AOP配置管理事务(掌握)

实现步骤:
都是在xml配置文件中实现的。
1、要使用aspectj这个框架,加入依赖

    <!--aspectj依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、声明事务管理器对象

    <!--声明式事务处理:和源代码完全分离的-->
    <!--1、声明事务管理器对象-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="myDataSource"></property>
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5

3、声明方法需要配置事务类型(配置方法的事务属性(1、隔离级别 2、传播行为 3、超时 ))

    <tx:advice id = "myAdvice" transaction-manager="transactionManager">
        <!--tx:attributes:配置事务属性-->
        <tx:attributes>
            <!--tx:method :给具体的方法配置事务属性,method可以有多个,分别给不同的方法设置事务属性
                name: 方法名称 1、完整的方法名称,不带有包和类
                              2、方法可以使用通配符,*表示任意字符(适用于多个方法来指定很多的方法)
                propergation:传播行为,枚举值
                isolation: 隔离级别
                rollback-For:你指定的异常类名,全限定类名。发生异常一定回滚
            -->
            <tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT" rollback-for="java.lang.NullPointerException,org.example.excep.NotEnoughException"/>
        </tx:attributes>
    </tx:advice>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

4、配置aop:声明那些类需要创建代理。

    <aop:config>
        <!--配置切入点表达式:指定那些包中类,要用事务
            id:切入点表达式的名称,唯一值
            expression:切入点表达式,指定那些类要使用事务,aspectj会创建代理对象
            com.example.service
            com.service
            com.crm.service
        -->
        <aop:pointcut id="servicePT" expression="execution(* org.example.service.impl.BuyGoodsServiceImpl*.*(..))"/>
        <!--配置增强器:关联advice和pointcut-->
        <aop:advisor advice-ref="myAdvice" pointcut-ref="servicePT"></aop:advisor>
    </aop:config>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

5、测试代码:

    @Test
    public void test01()
    {
        String config = "applicationContext.xml";
        ApplicationContext cxt = new ClassPathXmlApplicationContext(config);
//        从容器中获取service
        BuyGoodsService buyGoodsService = (BuyGoodsService) cxt.getBean("BuyGoodsService");
        System.out.println("service是代理:"+buyGoodsService.getClass().getName());
//        调用方法
//        buyGoodsService.buy(1001,10);
        buyGoodsService.buy(1001,10);

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在这里插入图片描述
service是代理,说明完成了事务管理。

第六章Spring与Web

在web项目中怎么使用容器对象。
实例:在web项目中使用spring,完成学生注册功能
实现步骤:
1、创建一个maven,web项目
在这里插入图片描述
在这里插入图片描述
2、添加依赖(拷贝依赖,添加jsp、servlet依赖)

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>
  <!--单元测试-->
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--    spring核心IOC-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--    做spring事务用到的-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>
    <!--    mybatis依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <!--    mybatis和spring集成的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.29</version>
    </dependency>
    <!--阿里公司的连接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.12</version>
    </dependency>
    <!--lombok快速为类对象创建set、get、构造等函数-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
      <scope>provided</scope>
    </dependency>
    <!--servlet依赖-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
    </dependency>
    <!--jsp依赖-->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2.1-b03</version>
    </dependency>
  </dependencies>

  <build>
    <!--目的是吧src/main/java目录中的xml文件包含到输出结果中。输出到classes目录中-->
    <resources>
      <resource>
        <directory>src/main/java</directory><!--所在的目录-->
        <includes><!--包括目录下的.properties,.xml文件都会扫描到-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <!--        —filtering 选项 false 不启用过滤器, *.property 已经起到过滤的作用了 -->
        <filtering>false</filtering>
      </resource>
    </resources>
    <!--    指定jdk的版本-->
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

3、拷贝06Spring-mybatis的代码和配置文件
在这里插入图片描述
4、创建index.jsp页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
        <p>注册学生</p>
        <form action="" method="post">
            <table>
                <tr>
                    <td>id:</td>
                    <td><input type="text" name="id"></td>
                </tr>
                <tr>
                    <td>姓名:</td>
                    <td><input type="text" name="name"></td>
                </tr>
                <tr>
                    <td>email:</td>
                    <td><input type="text" name="email"></td>
                </tr>
                <tr>
                    <td>年龄:</td>
                    <td><input type="text" name="age"></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="注册学生"></td>
                </tr>
            </table>
        </form>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

查看web.xml
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
再将名称修改为web.xml

4、创建一个jsp发起请求,有参数id、name、email、age

5、创建Servlet,接收请求参数,调用Service,调用dao完成注册

6、创建一个jsp作为显示结果页面

结果演示:
首先注册一个学生
在这里插入图片描述
在这里插入图片描述
创建了一次容器对象
在这里插入图片描述
然后再次注册一个学生
在这里插入图片描述
再次创建了一个容器对象(不同的对象)。

如果文件中有很多对象,那么创建效率就很慢,占用多余的内存。
容器对象包含所有对象,只需要创建一次就可以了。如何操作?
需求在web项目中,容器对象只需要创建一次,把容器对象放入到全局作用域ServletContext中。

怎么实现?使用监听器,当全局作用域对象被创建时,创建容器 存入ServletContext

监听器作用:
1、创建容器对象,执行ApplicationContext ctx = new ClassPathXMLApplicationContext(“applicationContext.xml”);
2、把容器对象放入到ServletContext, ServletContext.setAttribute(key,ctx)

监听器可以自己创建,也可以使用框架中提供好的ContextLoaderListener
private WebApplicationContext context;
public interface WebApplicationContext extends ApplicationContext

 ApplicationContext:javase项目中使用的容器对象
WebApplicationContext:web项目中的使用的容器对象
  • 1
  • 2

把创建的容器对象,放入到全局作用域
key: WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
value:this.context

 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
  • 1

为了使用监听器对象:
1、要加入依赖

    <!--为了使用监听器对象,加入依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、注册监听器ContextLoaderListener(web.xml文件)

    <!--注册监听器ContextLoaderListener
        监听器被创建爱你对象后,会读取/WEB-INF/applicationContext.xml
        为什么要读取文件:因为在监听器中要创建ApplicationContext对象,需要加载配置文件。
        /WEB-INF/applicationContext.xml就是监听器默认读取的spring配置文件的路径

        可以修改默认的文件位置,使用配置项context-param重新指定文件的位置
    -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <!--自定义配置文件的路径-->
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

3、使用监听器(在Servlet代码中使用)


            WebApplicationContext ctx = null;
            //获取ServletContext中的容器对象,创建好的容器对象,拿来就用
            String key = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
            Object attr =  getServletContext().getAttribute(key);
            if (attr!= null){
                ctx = (WebApplicationContext) attr;
            }
            System.out.println("容器对象的信息======="+ctx);
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/461447
推荐阅读
相关标签
  

闽ICP备14008679号