--- title: Spring5 author: TianZD top: true cover: true toc: true mathjax: false summary: SSM中的Spring5框架学习笔记,粗略学了一下,没有参考价值 tags: - Spring - java - 学习笔记 categories: - java reprintPolicy: cc_by abbrlink: 7f09f5da date: 2022-04-29 11:06:51 coverImg: img: password: --- [toc] # Spring # 1、概述 > 概述 Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,**是针对bean的生命周期进行管理的轻量级容器**(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大**IOC、AOP及Web MVC**等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于J2EE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。 > 理念 使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架 > SSH和SSM SSH:Struct2+Spring+Hibernate SSM:SpringMVC+Spring+Mybatis > 优点 * **开放源**代码的**免费**的J2EE应用程序框架(容器) * **轻量级、非入侵式**的框架 * 是针对bean的生命周期进行管理的**轻量级**容器 * 提供了功能强大**IOC、AOP及Web MVC**等功能 * **支持事务的处理** * Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架**组合使用** **总结**:Spring就是一个**轻量级**的控制反转**IOC**和面向切面编程**AOP**的框架 > 缺点 * 配置十分繁琐,人称“配置地狱” > 组成 ![查看源图像](https://gitee.com/tianzhendong/img/raw/master//images/403a0003482fc287bac5) Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。 > 扩展 现代化的java开发,就是基于spring的开发 ![image-20210808065217942](https://gitee.com/tianzhendong/img/raw/master//images/image-20210808065217942.png) * Spring Boot 快速开发的脚手架,基于springboot可以快速开发单个微服务 约定大于配置 * Spring Cloud 基于Spring Boot实现 现在大多数公司都在使用springboot进行快速开发 学习springboot需要完全掌握spring 和springmvc # 2、IOC理论推导 ## 原来方式 > 基础代码 1. 编写Dao层UserDao接口 ```java public interface UserDao { void getUser(); } ``` 2. 编写Dao层UserDaoImpl实现类和UserDaoMysqlImpl实现类 ```java public class UserDaoImpl implements UserDao { @Override public void getUser() { System.out.println("默认获取用户数据"); } } ``` ```java public class UserDaoMysqlImpl implements UserDao{ @Override public void getUser() { System.out.println("Mysql获取用户数据"); } } ``` 3. 编写Service层UserService接口 ```java public interface UserService { void getUser(); } ``` 4. 编写Service层UserServiceImpl实现类 ```java public class UserServiceImpl implements UserService { //创建dao层对应接口的实现类对象,从而调用dao层的方法 //弊端:新增或者改变需求时,dao层实现类增加或改变,需要更改这里的代码 private UserDao userDao = new UserDaoImpl(); @Override public void getUser() { //调用dao层对应方法 userDao.getUser(); } } ``` 5. 编写用户代码MyTest类 ```java public class MyTest { public static void main(String[] args) { //用户实际调用的是业务层,不接触dao层 UserService userService = new UserServiceImpl(); userService.getUser(); } } ``` > 分析 用户实际调用的是业务层,不接触dao层,通过创建`userservice`接口引用指向一个`UserServiceImpl`实现类对象,调用`UserServiceImpl`中的`getUser()`方法。由于`UserServiceImpl`中创建dao层对应接口的实现类对象,从而调用dao层的`getUser()`方法 **弊端**: 在我们之前的业务中,用户的需求可能会影响我们原来的代码,需要根据用户的需求去修改源代码,如果程序代码量大,修改的成本十分昂贵 * 新增或者改变需求时,dao层实现类增加或改变,需要更改这里的代码,比如要调用`UserDaoMysqlImpl`中的方法,需要改变UserServiceImpl中的代码 ## 改进-IOC原型 > 代码 1. 改变Service层UserServiceImpl实现类 ```java public class UserServiceImpl implements UserService { private UserDao userDao; //通过set进行动态实现值的注入 public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void getUser() { //调用dao层对应方法 userDao.getUser(); } } ``` 2. 改变用户代码MyTest类 ```java public class MyTest { public static void main(String[] args) { //用户实际调用的是业务层,不接触dao层 UserService userService = new UserServiceImpl(); // 实现UserDaoImpl类中的方法 ((UserServiceImpl) userService).setUserDao(new UserDaoImpl()); userService.getUser(); //实现UserDaoMysqlImpl方法 ((UserServiceImpl) userService).setUserDao(new UserDaoMysqlImpl()); userService.getUser(); } } ``` > 分析 在新增或者改变需求时,只需要更改MyTest类中的代码 使用一个set接口实现,实现了革命性的变化 ```java private UserDao userDao; //通过set进行动态实现值的注入 public void setUserDao(UserDao userDao) { this.userDao = userDao; } ``` * 之前程序是主动创建对象,控制权在程序员手上,用户访问业务层,由程序员代码决定用户调用什么 * 使用**set注入**后,程序不具有主动性,通过把**接口给用户**,用户访问业务层,主动权在用户,由用户选择调用什么,程序变成了**被动接收对象**(来自用户) **这种思想即控制反转IOC的原型,从本质上解决了问题,程序员不需要再管理对象的创建了,系统的耦合性大大降低,可以更加专注在业务的实现上** ## IOC本质 **控制反转是一种通过描述(XML或者注解)并通过第三方去生产或获取特定对象的方式,在Spring中实现控制反转的是IOC容器,实现方式是依赖注入** * 控制反转IOC(inversion of control)是一种设计思想,DI(依赖注入)是实现IOC的一种方式。 * 在没有IOC的程序中,使用面向对象编程,对象的创建和对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制 * 控制反转后,对象的创建转移给了第三方 * 控制反转就是获得依赖对象的方式反转了 IOC是Spring框架的核心内容,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IOC。采用XML方式配置Bean的时候,Bean的的定义信息和实现是分离的,采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的 **Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建于组织对象存入容器中,程序使用时再从IOC容器中取出需要的对象** # 3、HelloSpring ## 代码 > 创建实体类Hello.class 该类为后续要生成的对象的类,**必须要有set方法(依赖注入要用)** ```java public class Hello { private String str; public String getStr() { return str; } public void setStr(String str) { this.str = str; } public Hello() { } public Hello(String str) { this.str = str; } public void helloSpring() { System.out.println("hello " + str); } } ``` > Spring配置文件Beans.xml ```xml ``` > 业务代码MyTest.class ```java import com.tian.pojo.Hello; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args) { //获取Spring的上下文对象,固定语句 ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); //对象都在Spring中进行管理,要使用的化直接去里面取 Hello hello = (Hello) context.getBean("hello"); hello.helloSpring(); } } ``` ## 分析 对象由spring进行创建,对象的属性由Spring容器设置,这个过程就叫控制反转IOC,一句话说就是对象由Spring来创建、管理、装配 * **控制**:传统应用程序的对象由程序本身控制创建,使用SPring后,对象由Spring进行创建 * **反转**:程序本身不创建对象,变为被动的接收对象 * **依赖注入**:利用set方法进行注入,对象必须要有set方法 # 4、IOC创建对象的方式 在xml中使用<**bean**>后,不管有没有使用,都会创建 > 使用无参构造创建对象,**默认** 必须有无参构造函数 ```xml ``` > 有参构造函数——参数名 **重点** ```xml ``` > 通过有参构造函数——参数下标 ```xml ``` > 有参构造函数——参数类型 不建议使用:**当类中有两个或以上属性类型一样时,会导致错误** ```xml ``` > 总结 **在配置文件加载的时候,容器中管理的对象就已经初始化了** # 5、Spring配置 > 别名alias 起一个小名,两个名字hello和hello2都能用来创建对象 ```xml ``` > Bean的配置 ```xml ``` > import 一般用于多个团队开发,可以将多个配置文件导入合成一个 项目中有多个人开发,三个人负责不同的类的开发,不同的类需要注册在不同的bean中,可以利用import将所有的bean.xml合成一个总的。 ```xml ``` # 6、DI依赖注入 ## 构造器注入 见`4、IOC创建对象的方式` ## set方式注入【重点】 > 依赖注入:set注入 * 依赖:bean对象的创建依赖于容器 * 注入:bean对象中的所有属性由容器注入 > 环境搭建 1. 复杂类型 ```java package com.tian.pojo; public class Address { private String address; //get set tostring省略 } ``` 2. 真实类型 ```java public class Student { private String name; private Address address; private String[] books; private List hobbies; private Map card; private Set games; private String wife; private Properties info; //省略了get 和set tostring } ``` 3. 配置文件 ```xml ``` 3. 测试代码 ```java public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = (Student) context.getBean("student"); System.out.println(student.getName()); } } ``` > 注入方式 * 普通值注入value * bean注入ref * 数组注入 * list * map * properties * null ```xml book1 book2 book3 听歌 电影 LOL COD com.mysql.driver ual root 123456 ``` ## 扩展C\P命名空间注入 这个的使用要在bean.xml文件的头目录里面加上两行语句 ```xml xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c" ``` # 7、Bean的作用域scope > 单例模式`scope="singleton"` 默认就是单例,也可以手动设置 ```xml ``` > 原型模式`scope="prototype"` 每次从容器中get的时候,都会产生一个新对象 ```xml ``` > 其余的request、session、application 只能在web开发中使用 # 8、Bean的自动装配 自动装配:Spring会在上下文中自动寻找、装配属性 装配方式: * 在xml中显式的配置 * 在java中显式的配置 * 隐式的自动装配Bean【重要】 ## 搭建环境 一个人有两个从宠物,dog和cat xml配置 ```xml ``` ## byName、byType自动装配 > byName byname:会自动在容器上下文中查找和自己对象中set方法后面中的值对应的**bean id**,如果dog改成dog222,则不会成功 ```xml ``` > byType byType:会自动在容器上下文中查找和自己对象属性**类型相同**的bean 如果dog改成dog222 ,依然会成功,甚至注册dog时不需要id属性`` **注意,如果dog注册了多个对象,即同一个类型有两个对象,则bytype不可以使用** ```xml ``` > 总结 * byname:需要保证所有bean的id唯一,并且bean需要和自动注入的属性的set方法的值一致 * byType:需要保证所有bean的class唯一,并且bean需要和自动注入的属性类型一致 ## 使用注解实现自动装配 Spring2.5开始支持注解 > 使用注解: * 导入约束:context约束`xmlns:context="http://www.springframework.org/schema/context"` * 配置注解的支持:` ` ```xml ``` * xml配置 ```xml ``` > @Autowired * 默认为**byType**方式 * 直接在属性上使用或者在set方法上使用 * 可以不需要set方法 ```java public class Person { @Autowired private Cat cat; @Autowired private Dog dog; private String name; } ``` * 扩展:autowired有一个属性,required,默认为true,如果显式的定义了其为false,说明这个对象允许为null ```java @Autowired(required = false) ``` > @Qualifier Autowired默认为byType方式,如果IOC容器中同一个类型注册了多个对象,那么会出现问题,需要配置Qualifier使用,指定具体的对象 ```xml ``` ```java public class Person { @Autowired @Qualifier(value = "cat1") private Cat cat; } ``` > @Resource Resource是java自带的注解 通过**byName方式** ```java public class Person { //@Autowired //@Qualifier(value = "cat1") @Resource(name="cat1") private Cat cat; } ``` # 9、使用注解开发 ## Bean 1. 导包,必须有aop的包,`pop.xml` ```xml org.springframework spring-webmvc 5.3.9 ``` 2. 导入context约束,增加注解支持,`applicationContext.xml` ```xml ``` 3. 实体类@Component **在实体类上使用`@Component`注解等价于``,id默认为类的名字小写** ```java //等价于 // id默认为类的名字小写 @Component public class User { private String name; //get set } ``` ## 属性的注入@Value 适用于简单的,复杂的还是通过配置文件 ```java //等价于 // id默认为类的名字小写 @Component public class User { @Value("tianzd") private String name; //get set } ``` ## 衍生的注解 @Component有几个衍生注解,在web开发中会按照MVC三层架构开发 * @Component 用于pojo层 * @Service 用于service业务层 * @Controller 用于Controller层 * @Repository 用于Dao层 四个功能一样,都是代表将某个类注册到spring中,装配Bean ## 自动装配注解 @Autowired @Resource ## 作用域注解@Scope 在某个类上标注,修改称单例或者多例模式 ## 小结 > xml与注解 * xml更加万能,适用于任何场景,维护简单方便 * 注解不是自己的类使用不了,维护复杂 > 最佳实践 * xml用来管理Bean * 注解只负责完成属性注入@Value # 10、使用java的方式配置Spring 舍弃xml配置文件,使用config类实现 > 实体类 ```java package com.tian.pojo; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; //这个注解的意思就是说明这个类被注册到了容器中 @Component public class User { private String name; public String getName() { return name; } @Value("tianzhendong") public void setName(String name) { this.name = name; } } ``` > 配置类 ```java package com.tian.config; import com.tian.pojo.User; import org.springframework.context.annotation.*; //使其成为配置类,同beans.xml //这个也会被spring容器托管,注册到容器中,因为他也是一个@component @Configuration @ComponentScan("com.tian") //@Import(MyConfig1.class) 合并配置类,相当于xml中的import public class MyConfig { //注册一个bean,相当于一个bean标签 //方法的名字相当于id属性 //返回值类型,相当于class属性 //返回值就是要注入到bean中的对象 @Bean(name = "user1") @Scope(value = "singleton") public User getUser() { return new User(); } } ``` > 测试类 ```java import com.tian.config.MyConfig; import com.tian.pojo.User; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); User user = context.getBean("user1", User.class); System.out.println(user.getName()); } } ``` # 11、代理模式 **中介** > 为什么学习代理模式 ![image-20210808200209343](https://gitee.com/tianzhendong/img/raw/master//images/image-20210808200209343.png) 在业务增删改时,为了避免更改底层的代码 代理模式是SpringAop的底层 **SpringAOP的底层,面试重点** > 分类 * 静态代理 * 动态代理 ## 静态代理 租房:中介,房东,客户,出租房接口(中介和房东的) > 角色分析 * 抽象角色:一般会使用接口或者抽象类解决 * 真实角色:被代理的角色,房东 * 代理角色:代理真实角色,中介,代理真实角色后,一般会做一些附加操作 * 客户:访问代理对象的角色 > 抽象接口 ```java package com.tian.demo1; public interface Rent { public void rent(); } ``` > 实现类 ```java package com.tian.demo1; public class LandLord implements Rent{ @Override public void rent() { System.out.println("房子租出去了"); } } ``` > 代理 ```java package com.tian.demo1; public class Proxy implements Rent{ private Rent landLord; public Proxy(LandLord landLord) { this.landLord = landLord; } public Proxy() { } @Override public void rent() { landLord.rent(); } } ``` > 客户端 ```java package com.tian.demo1; public class Client { public static void main(String[] args) { Proxy proxy = new Proxy(new LandLord()); proxy.rent(); } } ``` > 优点 * 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务 * 公共业务交给代理,实现了业务的分工 * 公共业务发生扩展时,方便集中管理 > 缺点 * *代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。* * *代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。* ## 动态代理 每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类,为了弥补静态代理的缺点:一个真实角色就会产生一个代理,代码量翻倍,开发效率降低 > 概述 动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象 * 角色和静态代理一样 * 动态代理的代理类是动态生成的,不是直接写好的 **分类** * 基于接口的动态代理——JDK动态代理,这里使用这种 * 基于类——cglib * java字节码——javasist > JDK动态代理 在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持 * Proxy类:生成动态代理实例 * InvocationHandler接口:调用处理程序并返回一个结果 > InvocationHandler接口 每一个代理实例都有一个关联的调用处理程序,InvocationHandler是由代理实例的调用处理程序实现的接口 方法:invoke(object, object[]) ```java //Object proxy:被代理的对象 //Method method:要调用的方法 //Object[] args:方法调用时所需要参数 public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } ``` > Proxy类 有个静态方法,可以创建动态代理类的实例 ```java //CLassLoader loader:类的加载器 //Class interfaces:得到全部的接口 //InvocationHandler h:得到InvocationHandler接口的子类的实例 public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) throws IllegalArgumentException ``` > 动态创建代理对象的类 * 动态代理类只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler类,实现invoke方法 * invoke方法就是**调用被代理接口的所有方法时需要调用的**,该invoke方法返回的值是被代理接口的一个实现类 ```java //动态代理类只能代理接口(不支持抽象类),代理类都需要实现InvocationHandler类,实现invoke方法。 //invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类 public class LogHandler implements InvocationHandler { // 目标对象 private Object targetObject; //绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。 public Object newProxyInstance(Object targetObject){ this.targetObject=targetObject; //该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器 //第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口 //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法 //根据传入的目标返回一个代理对象 return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(),this); } @Override //关联的这个实现类的方法被调用时将被执行 /*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/ //invoke方法中实现了代理类要扩展的公共功能。 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ //代理扩展逻辑,实现代理类要扩展的公共功能 System.out.println("proxy do"); return method.invoke(targetObject, args); } } ``` > 优点 * 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务 * 公共业务交给代理,实现了业务的分工 * 公共业务发生扩展时,方便集中管理 * 一个动态代理类代理的是一个接口,一般就是对应一个业务 * 一个动态代理类可以代理多个类,只要是实现了同一个接口即可 # 12、AOP ## 简介 > 什么是AOP **面向切面编程**,AOP是能够让我们在不影响原有功能的前提下,为软件**横向扩展**功能。 那么横向扩展怎么理解呢,我们在WEB项目开发中,通常都遵守三层原则,包括控制层(Controller)->业务层(Service)->数据层(dao),那么从这个结构下来的为纵向,它具**体的某一层就是我们所说的横向**。我们的AOP就是可以作用于这某一个横向模块当中的所有方法。 ![](https://gitee.com/tianzhendong/img/raw/master//images/20210808215619.png) > 和oop区别 AOP和OOP的区别:AOP是OOP的补充,当我们需要为多个对象引入一个公共行为,比如日志,操作记录等,就需要在每个对象中引用公共行为,这样程序就产生了大量的重复代码,使用AOP可以完美解决这个问题。 > AOP在Spring中的作用 **提供声明式事务,允许用户自定义切面** - 横切关注点:跨越应用程序多个模块的方法或功能,即:与我们业务逻辑无关的,但我们需要关注的部分,如日志,安全,缓存,事务等 - 切面:拦截器类,其中会定义切点以及通知 - 切点:具体拦截的某个业务点 - 通知:切面当中的方法,声明通知方法在目标业务层的执行位置,通知类型如下: - 前置通知:@Before 在目标业务方法执行之前执行 - 后置通知:@After 在目标业务方法执行之后执行 - 返回通知:@AfterReturning 在目标业务方法返回结果之后执行 - 异常通知:@AfterThrowing 在目标业务方法抛出异常之后 - 环绕通知:@Around 功能强大,可代替以上四种通知,还可以控制目标业务方法是否执行以及何时执行 ## 方式1:使用Spring的API接口实现AOP > 导包:注意 ```xml org.aspectj aspectjweaver 1.9.7 ``` > 接口 ```java public interface UserService { public void add(); public void delete(); public void update(); public void selete(); } ``` > 接口实现类 ```java public class UserServiceImpl implements UserService{ @Override public void add() { System.out.println("add"); } @Override public void delete() { System.out.println("delete"); } @Override public void update() { System.out.println("update"); } @Override public void selete() { System.out.println("selete"); } } ``` > 增强方法log:注意 ```java package com.tian.log; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.stereotype.Component; import java.lang.reflect.Method; @Component public class Log implements MethodBeforeAdvice { @Override //method:要执行的目标对象的方法 //objects: 参数 //target:目标对象 public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("目标对象为:" + target.getClass().getName()); System.out.println("执行的方法为:" + method.getName()); for (int i = 0; i < args.length; i++) { System.out.println("第"+i+"个参数为:"+args[i]); } } } ``` > xml配置:注意 ```xml ``` > 测试:注意 ```java import com.tian.service.UserService; import com.tian.service.UserServiceImpl; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //动态代理代理的是接口 UserService userService = context.getBean("userService", UserService.class); userService.add(); } } ``` ## 方式2:自定义切入类 > 切入类 ```java public class DiyPointCut { public void before() { System.out.println("---------方法执行前---------"); } public void after() { System.out.println("---------方法执行后---------"); } } ``` > 配置 ```xml ``` ## 方式3:注解 > 增强类 ```java //声明该类是一个切面 @Aspect public class AnnotationPointCut { //声明前置方法 @Before("execution(* com.service.UserServiceImpl.*(..))") public void before() { System.out.println("这是使用注解的前置增强"); } //声明后置方法 @After("execution(* com.service.UserServiceImpl.*(..))") public void after() { System.out.println("使用注解的后置增强"); } //环绕增强的优先级更高 @Around("execution(* com.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕前"); System.out.println("签名:" + jp.getSignature()); //执行目标方法proceed Object proceed = jp.proceed(); System.out.println("环绕后"); System.out.println("proceed对象:"+proceed); } } ``` > 配置 ```xml ``` # 13、整合Mybatis ## 步骤: 1. 导入jar包 - junit单元测试 - mybatis - mysql - spring - aop - mybatis-spring(新包,用于整合) ```xml junit junit 4.12 mysql mysql-connector-java 8.0.25 org.mybatis mybatis 3.5.7 org.springframework spring-webmvc 5.3.9 org.springframework spring-jdbc 5.3.9 org.aspectj aspectjweaver 1.9.7 org.mybatis mybatis-spring 2.0.2 ``` 2. 编写配置文件 3. 测试 ## 回忆mybatis 数据: ![image-20210810222253418](https://gitee.com/tianzhendong/img/raw/master//images/image-20210810222253418.png) 1. 编写实体类 ```java package com.tian.pojo; /** * @program: SpringStudy * @description: * @author: TianZD * @create: 2021-08-10 21:00 **/ public class User { private int id; private String name; private String password; @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", password='" + password + '\'' + '}'; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public User() { } public User(int id, String name, String password) { this.id = id; this.name = name; this.password = password; } } ``` 2. 编写核心配置文件 ```xml ``` 3. 编写核心配置类 ```java package com.tian.utils; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.IOException; import java.io.InputStream; /** * @program: SpringStudy * @description: * @author: TianZD * @create: 2021-08-10 21:07 **/ public class MybatisUtils { public static SqlSessionFactory sqlSessionFactory; static { try { String resources = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resources); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } } ``` 4. 编写接口 ```java package com.tian.dao; import com.tian.pojo.User; import javax.sound.midi.VoiceStatus; import java.util.List; import java.util.Map; /** * @program: SpringStudy * @description: * @author: TianZD * @create: 2021-08-10 21:18 **/ public interface UserMapper { public int insert(User user); public int delete(int id); public int update(User user); public User select(int id); } ``` 5. 编写Mapper.xml ```xml delete from mybatis.user where id = #{id}; update mybatis.user set name = #{name},pwd = #{password} where id =#{id}; insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{password}); ``` 6. 测试 ## Mybatis-Spring http://mybatis.org/spring/zh/ * 不变内容: 实体类User.class UserMapper.interface接口 * 编写数据源 ```xml ``` * SqlSessionFactory ```xml ``` * SqlSessionTemplate ```xml ``` * 给接口加实现类 ```java package com.tian.dao; import com.tian.pojo.User; import org.mybatis.spring.SqlSessionTemplate; /** * @program: SpringStudy * @description: * @author: TianZD * @create: 2021-08-10 22:44 **/ public class UserMapperImpl implements UserMapper{ UserMapper userMapper = null; private SqlSessionTemplate sqlSessionTemplate; public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { this.sqlSessionTemplate = sqlSessionTemplate; } @Override public int insert(User user) { userMapper = sqlSessionTemplate.getMapper(UserMapper.class); return userMapper.insert(user); } @Override public int delete(int id) { userMapper = sqlSessionTemplate.getMapper(UserMapper.class); return userMapper.delete(id); } @Override public int update(User user) { userMapper = sqlSessionTemplate.getMapper(UserMapper.class); return userMapper.update(user); } @Override public User select(int id) { userMapper = sqlSessionTemplate.getMapper(UserMapper.class); return userMapper.select(id); } } ``` * 将实现类注入到spring中 ```xml ``` * 测试 ```xml import com.tian.dao.UserMapper; import com.tian.pojo.User; import com.tian.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @program: SpringStudy * @description: * @author: TianZD * @create: 2021-08-10 21:33 **/ public class MyTest { @Test public void userMapperTest() { ApplicationContext context = new ClassPathXmlApplicationContext("spring-mybatis.xml"); UserMapper userMapper = context.getBean("userMapperImpl", UserMapper.class); System.out.println(userMapper.select(2)); } } ``` ## 进一步简化:SqlSessionDaoSupport `SqlSessionDaoSupport` 是一个抽象的支持类,用来为你提供 `SqlSession`。调用 `getSqlSession()` 方法你会得到一个 `SqlSessionTemplate`,之后可以用于执行 SQL 方法 ```java package com.tian.dao; import com.tian.pojo.User; import org.apache.ibatis.session.SqlSession; import org.mybatis.spring.support.SqlSessionDaoSupport; /** * @program: SpringStudy * @description: * @author: TianZD * @create: 2021-08-10 23:17 **/ public class UserMapperImpl_2 extends SqlSessionDaoSupport implements UserMapper{ SqlSession sqlSession = getSqlSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); @Override public int insert(User user) { return userMapper.insert(user); } @Override public int delete(int id) { return userMapper.delete(id); } @Override public int update(User user) { return userMapper.update(user); } @Override public User select(int id) { return userMapper.select(id); } } ``` 注册:略去了sqlsessiontemplate注册 需要注册userMapperimpl2,SqlSessionDaoSupport` 需要通过属性设置一个 `sqlSessionFactory` 或 `SqlSessionTemplate ```xml ``` # 14、声明式事务 事务分为: * 声明式事务:AOP实现 * 编程式事务 ## 使用声明式事务 > 配置声明式事务 要开启 Spring 的事务处理功能,在 Spring 的配置文件中创建一个 `DataSourceTransactionManager` 对象: ```xml ``` > aop实现事务 ```xml ``` > 事务的传播特性 事务传播特性,就是多个事务方法调用时如何定义方法间事务的传播。Spring 定义了 7 种传播行为: - propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是Spring默认的选择。 - propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。 - propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。 - propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。 - propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 - propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。 - propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作。