文章目录
一、Spring
1.1 简介
- Spring 历史:2002年,Rod Jahnson首次推出Spring框架的雏形 interface21 框架。2004年,Spring矿界以interface21框架为基础,重新设计,发布1.0正式版。
- Spring 理念:使现有的技术更加容易使用,本身就是一个大杂烩,整合了现有的框架技术。
- 官网地址:https://spring.io/
- 官方下载:https://repo.spring.io/libs-release-local/org/springframework/spring/
- GitHub:https://github.com/spring-projects/spring-framework
- 导包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.3</version>
</dependency>
1.2 优点
- Spring是一个开源免费的框架(容器)
- Spring是一个轻量级、非入侵式的框架
- 控制反转(IOC)、面向切面编程(AOP)
- 支持事务的处理,支持框架的整合
Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!
1.3 组成
二、IOC 理论推导
2.1 理论推导
- 原来写代码 :
新建一个UserDAO接口→实现UserDAO接口→新建UserService接口→实现UserService接口→测试时调用service接口实现类
当需要新增一个 UserDAO实现类时,并且被测试方法调用,我们需要修改service实现类中的源码:
若是代码量非常大,那么改动的代价也很昂贵!
- 改进:在service实现类上添加setUserDAO方法
测试
- 对比:
- 之前程序主动创建对象,控制权在程序员手上。
- 使用set注入,程序不具有主动性,而是被动接受创建的对象。
程序员不用管理对象的创建,系统耦合性大大降低,可以专注于业务的实现,这是IOC的原型。
2.2 IOC本质
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。 没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
三、Hello Spring
- 配置 Maven 环境,导包
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.3</version>
</dependency>
- 编写实体类
由于在理论推导中创建了三个实体类,所以直接拿过来用。 - 配置beans.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
bean就是java对象,由spring创建和管理
正常创建对象 :
类名 变量名 = new 类名
spring创建对象
id 相当于变量名,类是class=""中的全类名
property 可以调用实体类中的set方法进行赋值
当更改userDao的实现类时,只需要更改配置文件
-->
<bean id="userDaoImpl" class="com.study.dao.UserDAOImpl"></bean>
<bean id="UserDAOMysqlImpl" class="com.study.dao.UserDAOMysqlImpl"></bean>
<bean id="userService" class="com.study.service.UserServiceImpl">
<property name="userDAO" ref="UserDAOMysqlImpl"></property>
<!--
ref对应的是bean的id,代表实现类
value对应的是具体的值
-->
</bean>
</beans>
- 测试
@Test
public void test(){
//解析xml文件,生成管理相应的bean对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//参数为spring中的bean标签的id属性
UserServiceImpl userService = (UserServiceImpl) context.getBean("userService");
userService.getService();
}
四、IOC创建对象方式
-
通过无参构造来创建:
bean类
package com.study.pojo;
public class User {
private String name;
public User(){
System.out.println("user 类被创建了 ");
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 通过有参构造来创建:
<bean id="user" class="com.study.pojo.User"><!--只能三选一-->
<constructor-arg index="0" value="name1"></constructor-arg><!--方式一:通过下标赋值-->
<constructor-arg type="java.lang.String" value="name2"></constructor-arg><!--方式二(不推荐):通过类型赋值-->
<constructor-arg name="name" value="name3"></constructor-arg><!--方式三:通过形参名赋值-->
</bean>
- 总结:在配置文件加载的时候,容器中管理的对象就已经初始化了。
spring容器:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
五、Spring配置
5.1 别名
beans.xml
<bean id="user" class="com.study.pojo.User">
<constructor-arg name="name" value="name3"></constructor-arg>
</bean>
<alias name="user" alias="NewUser"></alias><!--为user起别名,获取bean的时候可以用别名获取-->
测试
5.2 bean配置
<!--
id为bean的唯一标识符,
name可以作为别名(可以取多个别名,中间可用逗号、空格分开)
class是bean的全类名
-->
<bean id="user" class="com.study.pojo.User" name="userNew newUser">
<constructor-arg name="name" value="name3"></constructor-arg>
</bean>
5.3 import
六、依赖注入
- 依赖:Bean对象的创建依赖于容器
- 注入:Bean对象所依赖的资源,由容器来装配或设置
6.1 构造器注入
IOC创建对象方式已经写过。
6.2 Set注入
要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is 。
测试类:
public class Address {
private String address;
/*自动生成get set 方法*/
}
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private Properties info;
/*自动生成get set 方法*/
}
- 注入信息
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="com.study.pojo.Address">
<property name="address" value="河南"></property>
</bean>
<bean id="student" class="com.study.pojo.Student">
<!--1. 普通值注入-->
<property name="name" value="张三"></property>
<!--2. bean注入-->
<property name="address" ref="address"></property>
<!--3. 数组注入-->
<property name="books" >
<array>
<value>海底两万里</value><!--数组中的值-->
<value>浪潮之巅</value>
<value>狂神说java</value>
</array>
</property>
<!--4. list注入-->
<property name="hobbys">
<list>
<value>打球</value>
<value>唱歌</value>
<value>敲代码</value>
</list>
</property>
<!--5. map注入-->
<property name="card">
<map>
<entry key="phone" value="123456"></entry>
<entry key="id" value="666666"></entry>
</map>
</property>
<!--6. set注入-->
<property name="games" >
<set>
<value>王者</value>
<value>吃鸡</value>
<value>lol</value>
</set>
</property>
<!--7. null 空值注入-->
<property name="wife">
<null></null>
</property>
<!--8. properties注入-->
<property name="info">
<props>
<prop key="email">32142241@qq.com</prop>
<prop key="user">root</prop>
<prop key="password">12356</prop>
</props>
</property>
</bean>
</beans>
6.3 拓展注入
- 使用 p 命名空间注入
<!--
p命名空间 xmlns:p="http://www.springframework.org/schema/p"
相当于 property 给属性赋值
-->
<bean id="user" class="com.study.pojo.User" p:name="jingyang" p:age="18"></bean>
- 使用 c 命名空间注入
<!--
c命名空间 xmlns:c="http://www.springframework.org/schema/c"
相当于 constructor-arg 给构造器中的参数赋值
-->
<bean id="user" class="com.study.pojo.User" c:name="yao" c:age="20" ></bean>
6.4 Bean的作用域
- 单例模式(Spring默认,每次都获取的同一个对象)
<bean id="user" class="com.study.pojo.User" p:name="jingyang" p:age="18" scope="singleton"></bean>
- 原型模式(每次获取的对象都不同)
<bean id="user" class="com.study.pojo.User" p:name="jingyang" p:age="18" scope="prototype"></bean>
- 其余的实在web中使用
七、Bean的自动装配
7.1 自动装配说明
- 自动装配是使用 spring 满足 bean 依赖的一种方法
- Spring 会在上下文为某个bean寻找其依赖的 bean
- Spring 中的bean有三种装配机制:
- xml中显式配置
- java中显式配置
- 隐式的bean发现机制和自动装配
7.2 测试环境搭建
- Cat 类
public class Cat {
void shout(){
System.out.println("miao~");
}
}
- Dog 类
public class Dog {
void shout(){
System.out.println("wang~");
}
}
- person 类
public class Person {
private Cat cat;
private Dog dog;
private String name;
/*自动生成 get set方法*/
}
- 装配 普通bean
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.study.pojo.Cat"></bean>
<bean id="dog" class="com.study.pojo.Dog"></bean>
<bean id="person" class="com.study.pojo.Person" >
<property name="name" value="快乐撸代码"></property>
<property name="cat" ref="cat"></property>
<property name="dog" ref="dog"></property>
</bean>
</beans>
7.3 ByName
设置autowire=“byName” ,通过 setCat 方法,找到 id 为 cat 和dog 的 bean 对person进行装配,若id名不符合要求,则不装配。
<bean id="cat" class="com.study.pojo.Cat"></bean>
<bean id="dog" class="com.study.pojo.Dog"></bean>
<bean id="person" class="com.study.pojo.Person" autowire="byName">
<property name="name" value="快乐撸代码"></property>
</bean>
- 注意:id 名称应当唯一且对应其方法名
7.4 ByType
设置 autowire=“byType”,通过查找class中的类型对 person 进行装配
<bean id="cat" class="com.study.pojo.Cat"></bean><!--通过class="com.study.pojo.Cat"装配-->
<bean id="dog" class="com.study.pojo.Dog"></bean>
<bean id="person" class="com.study.pojo.Person" autowire="byType">
<property name="name" value="快乐撸代码"></property>
</bean>
7.5 使用注解自动装配
-
引入约束 context文件头
-
开启注解支持
<context:annotation-config/>
@Autowired
- @Autowired是按类型自动转配的(通过唯一的class装配bean),不支持id匹配。
配置文件:
<bean id="person" class="com.study.pojo.Person"></bean>
<bean id="cat" class="com.study.pojo.Cat"></bean>
<bean id="dog" class="com.study.pojo.Dog"></bean>
public class Person {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;
/*自动生成get set方法*/
}
@Qualifier
<bean id="person" class="com.study.pojo.Person"></bean>
<bean id="cat1" class="com.study.pojo.Cat"></bean>
<bean id="cat2" class="com.study.pojo.Cat"></bean>
<bean id="dog" class="com.study.pojo.Dog"></bean>
当出现的class不唯一时,@Autowired无法确定装配的bean,可以和 @Qualifier 结合使用,指定到唯一的bean。
public class Person {
@Autowired
@Qualifier(value = "cat1")
private Cat cat;
@Autowired
private Dog dog;
private String name;
}
@Resource
- 如果有指定的 name 属性,则先按该属性进行 byName 的方式查找装配
- 其次进行默认的 byName 方式查找装配
- 若以上方式都不成功,则按照 byType 的方式进行查找装配
- 若再不成功,则报异常。
- 指定 name
<bean id="dog1" class="com.study.pojo.Dog"></bean>
<bean id="dog2" class="com.study.pojo.Dog"></bean>
public class Person {
@Autowired
@Qualifier(value = "cat1")
private Cat cat;
@Resource(name = "dog1")
private Dog dog;
private String name;
}
- 默认的byName
<bean id="dog" class="com.study.pojo.Dog"></bean>
<bean id="dog1" class="com.study.pojo.Dog"></bean>
public class Person {
@Autowired
@Qualifier(value = "cat1")
private Cat cat;
@Resource
private Dog dog;
private String name;
}
- byType查找
<bean class="com.study.pojo.Dog"></bean>
public class Person {
@Autowired
@Qualifier(value = "cat1")
private Cat cat;
@Resource
private Dog dog;
private String name;
}
@Autowired与@Resource异同:
1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在set方法上。
2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用
3、@Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在set 方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。
八、使用注解开发
要使用注解,必须导入 aop 的包
在配置文件中,引入context约束
<?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"
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.xsd">
</beans>
注意:
<!--开启注解支持:使值可以注入-->
<context:annotation-config/>
8.1 bean的实现
扫描包下的注解
<!--扫描包下的注解,使类可以装配到Spring容器-->
<context:component-scan base-package="com.study.pojo"/>
//相当于配置文件中的 <bean id="person" class="com.study.pojo.Person"></bean>
@Component("person")
public class Person {
private Cat cat;
private Dog dog;
public String name="景阳";
}
8.2 属性注入
在变量名或者set方法上直接添加注解@value("值") 即可注入属性
@Component("person")
public class Person {
/*相当于<property name="name" value="快乐撸代码"></property>*/
@Value("快乐撸代码")
private String name;
}
8.3 衍生注解
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。相当于@Component
-
@Controller:web层
-
@Service:service层
-
@Repository:dao层
加上这些注解,相当于将类交给Spring容器管理装配。
8.4 自动装配注解
在 7.5 中已经写过。
8.5 作用域
@Scope
-
singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
-
prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
8.6 xml 与 注解
xml 与 注解 比较
- xml 可以适用任何场景 ,结构清晰,维护方便。
- 注解 不是自己提供的类使用不了,但是开发简单方便。
xml 与注解整合开发
- xml管理bean
- 注解完成属性注入
- 使用过程中可以不用扫描,扫描是为了类上的注解.
8.7 基于java类进行配置
实体类
@Component("user")
public class User {
private String name;
private int age;
}
Config配置类
@Configuration//代表一个配置类(代替xml配置文件)
public class MyConfig {
@Bean//使用方法注册一个bean,方法名就是bean的id
public User getUser(){
return new User();
}
}
导入其他配置类
@import(类名.class)
测试
@Test
public void test2(){
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MyConfig.class);
User user = (User) applicationContext.getBean("User");
System.out.println(User);
}
九、AOP
9.1 什么是AOP
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
9.2 AOP在Spring中的作用
几个名词:
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice
即 Aop 在 不改变原有代码的情况下 , 去增加新的功能 .
9.3 使用Spring 实现AOP
- 导入依赖
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
方式一:Spring API 实现
当实现接口以后,要在每次执行方法前后说明是哪个类执行的什么方法。
业务接口和实现类
- 接口
public interface UserService {
public void add();
public void delete();
public void query();
public void update();
}
- 实现类
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("执行方法 add");
}
@Override
public void delete() {
System.out.println("执行方法 delete");
}
@Override
public void query() {
System.out.println("执行方法 query");
}
@Override
public void update() {
System.out.println("执行方法 update");
}
}
- 编写增强类
前置增强
public class Log implements MethodBeforeAdvice {
/**
*
* @param method 要执行目标对象的方法
* @param objects 被调用方法的参数
* @param o 目标对象
* @throws Throwable
*/
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(method.getClass().getName()+"类的"+method.getName()+"方法被执行 ");
}
}
后置增强
public class Afterlog implements AfterReturningAdvice {
/**
*
* @param o 返回值
* @param method 被调用的方法
* @param objects 被调用的方法的对象的参数
* @param o1 被调用的目标对象
* @throws Throwable
*/
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println(method.getName()+"方法被执行了 ");
}
}
- 导入约束,aop切入实现
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd ">
<!--注册bean-->
<bean id="userServiceImpl" class="com.study.Service.UserServiceImpl"></bean>
<bean id="afterlog" class="com.study.log.Afterlog"></bean>
<bean id="log" class="com.study.log.Log"></bean>
<!--配置AOP-->
<aop:config>
<!--aop切入点 expression 定位到切入点 (定位到UserServiceImpl的所有方法) -->
<aop:pointcut id="pointCut" expression="execution(* com.study.Service.UserServiceImpl.*(..))"/>
<!--执行环绕 advice-ref:执行方法 pointcut-ref:切入点 -->
<aop:advisor advice-ref="afterlog" pointcut-ref="pointCut"></aop:advisor>
<aop:advisor advice-ref="log" pointcut-ref="pointCut"></aop:advisor>
</aop:config>
</beans>
- 测试
public class test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService service = context.getBean("userServiceImpl", UserService.class);//注意 被代理的是接口
service.add();
}
}
Spring的Aop就是将公共的业务 (日志 , 安全等) 和领域业务结合起来 , 当执行领域业务时 , 将会把公共业务加进来 . 实现公共业务的重复利用 . 领域业务更纯粹 , 程序猿专注领域业务 , 其本质还是动态代理 .
方式二:自定义类实现AOP【推荐】
自定义类:
public class Diy {
public void before(){
System.out.println("=======方法执行前=======");
}
public void after(){
System.out.println("========方法执行后=======");
}
}
配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd ">
<!--注册bean-->
<bean id="userServiceImpl" class="com.study.Service.UserServiceImpl"></bean>
<bean id="afterlog" class="com.study.log.Afterlog"></bean>
<bean id="log" class="com.study.log.Log"></bean>
<bean id="diy" class="com.study.diy.Diy"></bean>
<aop:config>
<aop:aspect ref="diy"><!--切面-->
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.study.Service.UserServiceImpl.*(..))"></aop:pointcut>
<!--切入点之后执行-->
<aop:after pointcut-ref="point" method="after"></aop:after>
<!--切入点之前执行-->
<aop:before pointcut-ref="point" method="before"></aop:before>
</aop:aspect>
</aop:config>
</beans>
方式三:使用注解实现
前后方法
@Aspect
public class AnnotationDiy {
@Before("execution(* com.study.Service.UserServiceImpl.*(..))")
public void before(){
System.out.println("注解方法执行前");
}
@After("execution(* com.study.Service.UserServiceImpl.*(..))")
public void after(){
System.out.println("注解方法执行后");
}
@Around("execution(* com.study.Service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕方法执行前");
Object proceed = pjp.proceed();
System.out.println("环绕方法执行后");
}
}
配置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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd ">
<!--注册bean-->
<bean id="userServiceImpl" class="com.study.Service.UserServiceImpl"></bean>
<bean id="annotationDiy" class="com.study.diy.AnnotationDiy"></bean>
<!--开启注解支持-->
<aop:aspectj-autoproxy/>
</beans>
十、mybatis — Spring整合
10.1 方式一
参考入门文档:http://mybatis.org/spring/zh/getting-started.html
- 在原有 mybatis 依赖基础上导入其他依赖
<!--mybatis-spring依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc
spring-jdbc依赖
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.4</version>
</dependency>
- 配置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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--datasource 数据源 使用Spring的数据源代替mybatis的配置(mybatis中mybatis-config.xml中,有关于<datasource/> 的配置 这里代替掉)
这里用Spring提供的jdbc
-->
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=true"></property>
<property name="username" value="root"></property>
<property name="password" value="123456"></property>
</bean>
<!--使用 SqlSessionFactoryBean来创建 SqlSessionFactory(使用数据源)-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource" />
<!--绑定Mybatis配置文件,将该bean和mybatis-config.xml连起来,也可以将其和UserMapper.xml文件绑定 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="mapperLocations" value="classpath:com/study/dao/UserMapper.xml"><!--注意不能有空格,会把空格识别成路径--></property>
</bean>
<!--注入SqlSessionTemplate 就是我们使用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入 因为SqlSessionTemplate没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
</bean>
<!--实现 UserMaper接口 -->
<bean id="userMapper" class="com.study.dao.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"></property>
</bean>
</beans>
- 实现 UserMaper接口
public class UserMapperImpl implements UserMapper {
//原来的操作使用SqlSession,现在使用SqlSessionTemplate
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> getUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.getUser();
}
}
- 总结
其实就是用spring的配置文件方式代替了mybatis配置文件的方式,mybatis中的测试类变成了Spring中的实现Mapper接口。
10.2 方式二
/**
* 继承SqlSessionDaoSupport类,get方法获取sqlSession
*/
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
public List<User> getUser() {
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.getUser();
}
}
- Spring配置文件
<!--可以不用注入SqlSessionTemplate 通过继承SqlSessionDaoSupport类,获取sqlSession-->
<bean id="userMapper2" class="com.study.dao.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
十一、Spring 声明式事务
- 事务:
- 声明式事务:通过AOP实现
- 编码式事务:通过修改源代码实现
xml配置事务:
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"></property>
</bean>
<!--结合AOP实现事务织入-->
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务-->
<!--给事务配置传播特性 propagation="REQUIRED"默认 (声明以下方法是一个事务)-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<!--切入点-->
<aop:pointcut id="txPoint" expression="execution(* com.study.dao.*.*(..))"/><!--dao下的所有类的所有方法-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"/>
</aop:config>
Mapper接口
public interface UserMapper {
public List<User> getUser();
public void addUser(User user);
public void deleteUser(int id);
}
接口实现类
package com.study.dao;
import com.study.pojo.User;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper {
//原来的操作使用SqlSession,现在使用SqlSessionTemplate
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
/*getUser方法测试事务*/
public List<User> getUser() {
User user = new User(4, "王林", "0000");
addUser(user);
deleteUser(3);//若删除出现异常 则原来的插入进行事务的回滚
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.getUser();
}
public void addUser(User user) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(user);
}
public void deleteUser(int id) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(id);
}
}