目录
1、pom文件中引入 spring-context jar包
2、创建spring核心配置文件,并且设置需要spring容器帮忙创建的实体类。
3、引用类型:如果一个类有多个IOC服务,创建多个对象,使用DI初始化值,怎么区分?
六、ApplicationContext接口下两个常见实现类
(一)、ClassXmlApplicationContext:
(二)、FileSystemXmlApplicationContext
3、Aspest切面类中,前置、后置、环绕方法等。proceedingjoinpoint 和 joinpoint 的区别
八、DataSourceTransactionManager(spring事务相关)
3、如何确保两条sql语句生成的备份表能够被同一个事务对象管理?
(二)、监听器解决,每访问servlet后创建一个spring容器对象问题
一、Spring框架介绍
Spring使用java语言开发开源框架, Spring 的主要作用就是为代码“解耦”,降低代码间的耦合度。就是让对象和对象(模 块和模块)之间关系不是使用代码关联,而是通过配置来说明。即在 Spring 中说明对象(模 块)的关系。
Spring 根据代码的功能特点,使用 Ioc 降低业务对象之间耦合度。IoC 使得主业务在相互 调用过程中,不用再自己维护关系了,即不用再自己创建要使用的对象了。而是由 Spring 容器统一管理,自动“注入”,注入即赋值。 而 AOP 使得系统级服务得到了最大复用,且 不用再由程序员手工将系统级服务“混杂”到主业务逻辑中了,而是由 Spring 容器统一完成 “织入”。
二、Spring框架提供的服务
1、IOC服务(控制反转服务)
原来在程序中的创建对象方式,现在有Spring容器对象帮助创建指定类的对象,减少手动创建创建对象;
2、DI服务(依赖注入服务)
有Spring容器对象帮助开发人员,对指定对象进行【初始化】服务,只有被Spring容器对象创建的对象,才有资格享受【DI】服务
3、AOP服务(面向切面编程服务)
有Spring容器对象帮助开发人员降低JDK动态代理设计模式的使用难度,由Spring容器对象负责【代理类生成】、【代理对象创建】以及【目标类】、【切面类】的实例对象创建;
三、IOC服务
由Spring容器对象,对指定类对象的创建
(一)、开发环境搭建
1、pom文件中引入 spring-context jar包
2、创建spring核心配置文件,并且设置需要spring容器帮忙创建的实体类。
<bean> id:表示创建实体类对应的key, class:表示需要帮忙创建的实体类
3、获取 ApplicationContext接口的实现类
4、获取实体类对象
(二)、IOC服务获取方式
1、基于XML文件方式获取
将指定创建类的信息,写在xml bean标签中,spring容器会自动读取xml文件中指定类进行创建对象
注意:
- Spring容器在创建对象完毕后,就会负责将bean标签指定的类进行创建
- 一个bean标签spring只会创建一个指定类的对象
- 通过bean标签让spring创建实体类对象,该实体类必须要有无参构造方法(底层通过反射创建)
面试题:是不是所有类都能被spring容器对象来创建实例化对象,如果不存在请说明?
答案: 不是 ,有些类就不能让spring容器来创建实例化对象
以下类就不可以:.
- servlet相关的实现类,比如HttpServle...,监听器、过滤器等实现类。因为这些类的对象都是由Http服务器来创建。
- 没有无参构造方法的类或者接口等
2、通过注解的方式
1、需要给让Spring容器对象创建的实体类上面添加 @Component注解
2、在Spring核心文件中配置,Spring扫描那些包下,遇到@Component注解就会创建实体类对象。如果不告诉Spring,将会整个项目扫描,耗费性能资源;
3、测试一下
3、两种索要IOC服务方式对比
1、基于XML文件方式获取
优点:
- 管理范围非常广,即可以是项目中开发人员开发的类,也可以是来自于jar包中类;
- 集中化关了,对于后续维护降低难度
缺点:
- 随着项目中开发的类的数量增加。, spring核心配置占用空间也会逐渐增加,增加项目的容积,来增加项目运营的成本
2、基于注解方式获取
优点:不会增加spring核心配置文件的容积
缺点:只能创建设定范围内包下的类的对象创建,jar包情况不能创建
四、DI服务
通过XML标签或者注解的形式通知spring对象为某个对象的指定属性设置指定的初始化值;
(一)通过XML标签形式
1、给基本类型的属性设置默认值
实体类
spring核心配置文件配置
测试方法
2、给引用类型的属性设置默认值
实体类
spring核心配置文件
测试方法
(二)、通过注解的方式
1、使用注解,基本数据类型进行设置默认值
实体类
测试类
2、 使用注解,引用数据类型进行设置默认值
实体类
测试类
3、引用类型:如果一个类有多个IOC服务,创建多个对象,使用DI初始化值,怎么区分?
xml中配置一个类中多个IOC服务,并且使用DI初始化值
实体类
测试类
我们发现运行报错,原因:就是spring检测到2个符合的IOC对象,spring不知道使用那个。
解决办法:使用 @Qualifier()标签,告诉spring使用那个
再次测试,发现解决问题了!
五、 Spring集成MyBatis
Spring集成某一种技术:由Spring容器对象负责为指定技术中【核心对象】和【辅助对象】进行初始化和创建,当开发人员使用该技术的时候,直接从Spring容器中获取【核心对象】降低开发人员使用该技术的难度;
比如:我们要使用JDBC操作数据库,核心对象就是:PreparedStatment,为了得到它我们需要创建Driver对象,connect对象,PreparedStatment对象。
后面上述的创建那么多的辅助对象和核心对象,我们就可以交给Spring容器,进行创建;
理解Spring继承MyBatis框架
1、mybatis框架作者,不希望Spring直接与mybatis的核心类:SqlSessionFactoryBuilder、SqlSessionFactory,直接接触,因此提供了一个SqlSessionFactoryBean类,spring容器创建SqlSessionFactoryBean类对象后,mybatis自动创建SqlSessionFactoryBuilder、SqlSessionFactory类对象
2、如果想用mybatis Dao层代理服务,需要创建:SqlSession对象;但是mybatis不希望spring直接创建该类对象,因此提供了MapperScannerConfigure类,spring容器创建MapperScannerConfigure对象后,该类会对SqlSession对象进行创建;
SqlSessionFactoryBean 和 MapperScannerConfigure类存储在mybaits-spring.jar包中
(一)、Spring集成MyBatis框架的开发环境搭建
1、导入jar包
依赖jar包:
JDK的jar包: java.sql.Driver接口、java.sql.Connect接口、 java.sql.PreparedStatement接口、 java.sql.ResultSet接口、 java.sql.DriverManager类
mysql-conector-java.jar包(MySql厂商提供的,主要是实现MySql相关的接口):com.mysql.jdbc.Driver类、com.mysql.jdbc.JDBC4Connection类、com.mysql.jdbc.JDBC4PreparedStatement类、com.mysql.jdbc.JDBC4ResultSet类
mybatis的jar包:SqlSessionFactoryBuilder类、SqlSessionFactory类、SqlSession类
mybatis-spring.jar(mybatis提供给spring): SqlSessionFactoryBean 类、MapperScanerConfigure类
spring-context.jar(spring)
2、编写spring 配置文件
创建SqlSessionFactoryBean、MapperScanerConfigure对象以及对应属性赋值
3、配置mybatis文件
mybatis中不用配置数据库环境信息以及datasource,后面会在spring中配置
4、 编写dao层代理
dao层接口
dao层接口对应的sql映射文件
5、实体类
6、服务层接口以及实现
服务层接口
实现类
7、测试类
运行
报错:spring提示解析spring.xml文件时候,创建MapperScannerConfigurer类对象报错,提示没有找到下面的类 "org/springframework/dao/support/DaoSupport"
解决办法:pom文件中少jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.18</version>
</dependency>
添加jar包后再次运行
报错: spring提示创建sqlSessionFactoryBean对象时候提示,dataSource属性必须要有值,dataSource中存放的是数据相关信息;
解决办法,在spring.xml文件中配置dataSource属性,并且给它附初始值
我们查看SqlSessionFactoryBean的源码,发现需要附一个dataSource类型的对象
此时我们需要借助一个jar包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
添加jar包,后在spring.xml文件中配置dataSource对象,并且给SqlSessionFactoryBean配置dataSource属性
创建properties文件,配置数据库信息
再次运行,提示没有找到sql映射文件。
解决办法:pom文件中配置
配置完成,再次运行,运行成功!
六、ApplicationContext接口下两个常见实现类
(一)、ClassXmlApplicationContext:
由这个类生成的spring容器对象只能在当前, 在当前项目的编译路径下寻找spring核心配置文件
(二)、FileSystemXmlApplicationContext
由这个类生成的spring容器对象只能在当前计算机的文件系统中寻找spring核心配置文件
我们将spring配置文件放在E盘,测试一下
运行成功
七、JDK动态代理设计模式:
(一)、介绍
SUN公司在jdk.jar提供一组工具类。用来帮助开发人员降低【动态代理设计模式】使用难度,提供一个【代理对象】帮助开发人员得到本次目标类的Class对象,帮助开发人员得到本次目标方法Method对象,并自动将这些信息传入到切面对象中invoke方法
(二)、角色划分
1、目标方法
来自于对应接口中的方法,这些接口需要与新增功能进行关联
2、目标类
就是对应接口的实现类
3、目标对象
目标类生成的实例对象
4、切面类
负责将【新增功能】与目标方法进行关联的一个工具类。在JDK动态代理模式中,要求所有切面类必须实现InvocationHandler接口,用于对切面类中invoke方法进行统一管理;
5、代理对象
JDK动态代理设计模式,提供一个工具类Proxy。这个工具类负责在内存中生成一个【代理类】,并且负责创建【代理类】的实例对象,这个对象就是【代理对象】。负责帮助开发人员简化切面类中invoke方法调用难度。 代理对象接收到请求信息并将请求信息交给切面对象,切面对象调用目标类的方法
(三)、通知(advice)分类
1、前置通知
先【新增功能方法】在【目标方法】
2、后置通知
先【目标方法】在【新增功能方法】
3、环绕通知
先【新增功能1】在【目标方法】最后【新增功能2】
4、异常通知
只有【目标方法】运行抛出异常时,才会进行执行【新功能】
5、最终通知
先运行目标方法,无论目标方法是否正常执行,都会执行新功能
(四)、JDK动态代理模式代码实现
目标类接口,目标方法
目标类(实现目标接口的类)
目标类1
目标类2
目标类3
代理对象工程类(生成代理对象) 传入目标类的反射对象,生成该类的代理服务对象,通过代理对象调用目标方法
切面类
负责关联目标方法和新增功能的一个工具类
package com.zxb.aspect;
import com.zxb.sevice.BaseService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;
//切面类:解决将【新增功能】与【目标方法】关联起来的工具类
public class MyAspect implements InvocationHandler {
//目标对象
private BaseService target;
public MyAspect(BaseService target) {
this.target = target;
}
//解决问题inovke:BaseService接口下所有服务方法在运行完毕时,输出【结束时间】
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try{
/*
* 前置通知: 前置方法
*/
//1.目标方法执行
result = method.invoke(target, args);
/*
* 后置通知: 后置方法
*/
//2.目标方法执行后,调用新增功能
newFun();
}catch (Exception e){
/*
* 异常通知: 出现异常执行方法
*/
}finally {
/*
* 最终通知 最终执行方法
*/
}
return result;
}
//新增功能
private void newFun(){
System.out.println("service_1方法运行结束的时间是 "+new Date());
}
}
测试类
(五)、JDK代理模式的优缺点
1、优点:通过一个代理对象,操作目标方法,降低了开发人员使用切面对象来解决问题的难度
2、缺点:代理对象生成步骤过于晦涩难懂,目标方法与新增功能调用顺序过于死板
八、 Spring框架之AOP服务
(一)、介绍
AOP服务称为【面向切面编程服务】,降低了开发人员使用JDK动态代理模式的使用难度。aop由spring容器对象负责代理对象的生成,为了得到这个服务,开发人员必须将【目标对象】和【切面对象】都交给Spring容器对象来创建
(二)、AOP服务环境搭建
需要jar包: spring-context.jar、
spring-aspectj.jar
(三)、获取AOP服务两种方式
1.XML的形式
目标类接口
目标类
切面类
spring.xml文件
测试类
我们发现执行目标方法service_01时,先执行了前置方法,最后执行了后置方法,service_02未执行;
2、注解形式
目标类接口
目标类
切面类
spring.xml文件
测试类
我们发现twoService代理服务对象调用目标方法,不走前置和后置方法,因为twoService不满足Aspect切入表达式。
2.1、注解使用Around
切面类
使用around时候需要注意 方法是否有返回值,因为method.proceed()调用目标方法,目标方法有返回值,这边需要将返回值返回,没有则使用void;
测试类
3、Aspest切面类中,前置、后置、环绕方法等。proceedingjoinpoint 和 joinpoint 的区别
JoinPoint:提供访问连接点的静态部分,如被通知方法签名、连接点类型等:
Proceedingjoinpoint 继承了 JoinPoint :是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。
环绕通知 ProceedingJoinPoint 执行proceed方法的作用是让目标方法执行,这也是环绕通知和前置、后置通知方法的一个最大区别。
八、DataSourceTransactionManager(spring事务相关)
(一)、事务
1、什么是事务
事务(Transaction)。对采用了InnoDB管理的表文件的数据行, 来进行操作时,InnoDB要求MySql服务器必须先对表文件内容进行备份,生成一个备份表,然后才能对表中的数据行进行处理,事务是MySql服务器生成的一个管理对象,专门用来针对本次操作中生成的备份表进行管理。
2、事务管理
1) commit: 提交;销毁掉本次操作中所有的备份表
2) rollback:回滚;将本次操作中所有的备份表覆盖到原始表,从而达到恢复数据的目的
3、如何确保两条sql语句生成的备份表能够被同一个事务对象管理?
只要确保两天sql语句由同一个通道推送到mysql即可。就是使用同一个connection对象;
(二)、spring集成事务使用
spring容器对象来创建来自于spring-jdbc.jar中; DataSourceTransactionManager类的对象,这个对象将作为切面对象,为指定的service层中方法提供事务管理服务
1.这个类来自于spring-jdbc.jar
2.这个类用来充当【切面类】,为项目中指定的service
方法提供事务管理。
3.此时借助于Spring容器对象来创建当前类的代理对象。
4.开发人员从今往后,在service层开发中只需要关注服务
而不必关心事务管理。
5.将DataSourceTransactionManager与服务方法关联方式
1、环境搭建
1、需要引入spring-jdbc.jar包
2、spring.xml文件中,配置DataSourceTransactionManager的对象,通知spring创建DataSourceTransactionManager容器对象创建代理对象
2、通过注解的形式
pom文件引入相关jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zxb</groupId>
<artifactId>17_XML_DataSourceTransactionManger</artifactId>
<version>1.0-SNAPSHOT</version>
<name>17_XML_DataSourceTransactionManger</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- myBatis相关jar包 -->
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<!-- mybatis框架 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!-- spring 主要提供:IOC,DI,AOP服务 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
<!-- mybatis 提供给spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- 提供dataSource类 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<!-- DataSourceTransactionManager事务类,提供给spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.14</version>
</dependency>
<!-- AOP切面类 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.18</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
resource文件夹
jdbc配置文件
mybatis配置文件 spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.zxb.serviceImpl"></context:component-scan>
<!-- 设置dataSource -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${jdbc_url}"></property>
<property name="username" value="${jdbc_userName}"></property>
<property name="password" value="${jdbc_passWord}"></property>
<property name="initialSize" value="${initialSize}"></property>
<property name="maxActive" value="${maxActive}"></property>
</bean>
<!-- 设置sqlSessionFactoryBean -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis.xml"></property>
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 设置MapperScannerConfigurer -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"></property>
<property name="basePackage" value="com.zxb.dao"></property>
</bean>
<!--
要求Spring容器对象来创建来自于spring-jdbc.jar中
DataSourceTransactionManger的对象,这个对象将作为切面对象
为指定的service层中方法提供事务管理服务
-->
<!--
要求spring容器对象来创建来自于spring-jdbc.jar中;
DataSourceTransactionManager的对象,这个对象将作为切面对象,为指定的service层中方法提供事务管理服务
-->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 通知spring容器对象为DataSourceTransactionManager容器对象创建代理对象 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"></tx:annotation-driven>
</beans>
dao层接口
实体类
service层
我们只需要给对应方法上面添加@Transactional标签,该方法就是添加事务。
测试类
1、我们先验证一下回滚的操作,我们将sql映射文件,sql语句写错。
2、运行测试类方法
我可以看出,每个sql都是用的同一个sqlsession对象, 我们发现其中一个sql运行报错了,查看数据库。数据显示所有的数据都已经进行回滚了,说明事务起到作用了,失败则rollback;
3、我们修改正确sql语句,运行测试方法
4、发现数据库数据都已经删除
3、通过XML文件配置的形式(建议使用)
修改spring.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.zxb.serviceImpl"></context:component-scan>
<!-- 设置dataSource -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driver}"></property>
<property name="url" value="${jdbc_url}"></property>
<property name="username" value="${jdbc_userName}"></property>
<property name="password" value="${jdbc_passWord}"></property>
<property name="initialSize" value="${initialSize}"></property>
<property name="maxActive" value="${maxActive}"></property>
</bean>
<!-- 设置sqlSessionFactoryBean -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis.xml"></property>
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 设置MapperScannerConfigurer -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"></property>
<property name="basePackage" value="com.zxb.dao"></property>
</bean>
<!--
在容器中添加事务管理器:
要求Spring容器对象来创建来自于spring-jdbc.jar中
DataSourceTransactionManger的对象,这个对象将作为切面对象
为指定的service层中方法提供事务管理服务
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--
配置事务通知:
指定需要与DataSourceTransactionManger
关联的服务方法名称,(可以是表达式)
-->
<tx:advice id="advice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="delete.*"/>
<tx:method name="add.*"></tx:method>
</tx:attributes>
</tx:advice>
<!--
配置增强器:
指定将配置好的事务通知,植入给谁
-->
<!-- aop配置: 通知应用的切入点 -->
<aop:config>
<aop:pointcut id="servicePt" expression="execution(public * com.zxb.serviceImpl.*(..))"/>
<!-- 声明增强器: 通知和切入点组合 -->
<aop:advisor advice-ref="advice" pointcut-ref="servicePt"></aop:advisor>
</aop:config>
</beans>
从上面配置可以看出,只有 add*和delete*的方法走事务,其他方法不走事务;
注意:不要写add.*、delete.*,如果这样写就是找 add. 、delete. 相关的方法,而不是 add、delet相关方法
dao层接口以及sql映射文件
service接口以及实现
测试类方法
我们故意将sql映射文件修改错误,执行test01方法
我们发现给dept表插入sql执行成功,给student表插入sql失败。我们查看数据库,dept和student表都没有插入成功。从而证明addStuDept方法走事务,因此数据回滚了
我们故意将删除deptNo表sql书写错误,我们测试removeDeptNo方法,我们运行test02方法
我们发现student表中数据删除了,dept表数据没有删除,因此没有走事务,没有产生回滚的作用;
注意:我们平时使用事务,最好使用xml文件配置,这样可以归到那些方法走事务,那些方法不走事务。
九、spring结合servlet
(一)、spring结合sevlet基础使用
项目结构
controller里面的servlet,其他文件数据和上面spring项目一样
我们通过spring容器对象创建的对象,功能非常饱满,Dao层的属性已经初始化,并且service也已经关联了事务。
我们可以发现我们在每个servlet对应的方法中获取,spring容器对象。假如有多个人访问servlet,每个servlet都创建一个spring容器对象,这样很浪费内存空间。创建spring容器过程中,spring会给对应类创建对象或者创建对应的代理对象;这样也会增加访问servlet的效率;
解决办法,我们可以使用servlet阶段学到的监听器。我们使用监听器对spring容器对象进行创建;
(二)、监听器解决,每访问servlet后创建一个spring容器对象问题
监听器
我们使用监听器,只要tomcat启动后就会执行的方法,里面写入创建spring容器对象,并且将spring容器对象放到全局作用域中,因此整个项目就只会使用这一个spring容器对象,这样就减少了每次访问servlet创建spring容器对象的问题。我们每次tomcat启动时候,会创建,不存在访问servlet时候创建,访问servlet效率提高,但是启动tomcat时间增加;
servlet中使用spring容器对象
十、spring集成监听器
我们上面看到,如果想优化spring容器对象的创建,需要在监听器中写创建spring容器对象的代码;spring也给我们提供了创建监听器,创建spring容器对象的类;
(一)、环境搭建
可以看出我们没有写监听器,我们使用spring给我们创建的监听器,并且给我们把spring容器对象创建好了
1、需要jar包
2、web.xml文件中配置监听器
3、servlet中获取spring容器对象
4、spring创建容器对象源码分析
1、spring给我们创建容器对象主要依赖ContextLoaderListener类
ContextLoaderListener类实现了ServletContextListener
contextInitialized,方法负责创建监听器,并且创建spring容器对象,并且将spring容器对象放到全局作用域中
在 createWebApplicationContext 方法里面创建
createWebApplicationContext创建完成返回一个WebApplicationContext对象(spring容器对象)
WebApplicationContext 继承的就是ApplicationContext 对象
我们在看initWebApplicationContext方法中,将获取WebApplicationContext,转换成了ConfigurableWebApplicationContext,正好是ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext的祖先类,这两个类都能创建spring容器对象
将spring容器对象设置到servletContext(全局作用域)中
因此我们获取spring容器对象就要使用 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE(key)来获取;