Spring
1.本章学习内容
1.Spring框架概要
2.IOC容器
3.AOP
4.jdbcTemplate
5.事务管理
6.Spring5新特性
7.Spring整合MyBatis
2.Spring概要
**概述:**它是轻量级的开源的JavaEE框架
-
轻量级:他的体积小,依赖的jar包比较少,并且不需要额外依赖其他的组件
-
开源:免费提供源代码
-
框架:可以简化我们构建软件的过程
**目的:**为了解决企业级应用的复杂性
核心:
- IOC:控制反转- 把创建对象的过程交给Spring进行管理
- AOP:面向切面编程 - 不修改源码进行功能增强
优点:
-
方便解耦,简化开发
-
对AOP编程的支持
-
方便程序的测试
-
方便整合其他各种的框架
-
方便进行事务操作
-
降低API开发
3.入门案例
4.IOC容器
概述:
-
控制反转
-
综上所述:控制反转就是 把创建对象,和对象的调用的过程交给Spring来管理 。目的是为了降低类与类之间的耦合性。
底层原理:
-
XML解析
-
工厂模式
-
反射
原理图解:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EYaHb63p-1617528150776)(D:\图片\IOC.png)]
重要概念:
-
IOC 容器:IOC的实现,依赖于IOC容器,而IOC容器的本质就是对象工厂
-
IOC容器的实现:
-
BeanFactory:是最底层的接口,他只提供了最简单的容器功能:加载配置文件 和 创建对象
- 当加载配置文件时,不会创建被配置的对象,只有在使用时,对象才会创建。
- 好处:节省内存
- 坏处:因为在服务器运行的时候去创建对象,会影响执行效率
- 当加载配置文件时,不会创建被配置的对象,只有在使用时,对象才会创建。
-
ApplicationContext:应用上下文,它是继承了BeanFactory。它是Spring更高级的一个容器接口,他提供了更多有用的功能
- 当配置文件的时候,会同时创建被创建配置的对象
- 好处:效率高,将复杂的创建过程在服务器启动时完成
- 坏处:耗费资源
- 当配置文件的时候,会同时创建被创建配置的对象
-
3.ApplicationContext的两个实现类
-
ClassPathXmlApplicationContext:从项目中的resources文件中加载配置文件
-
FileSystemXmlApplicationContext:从文件系统读取配置文件(需要访问权限)
-
AnnotionConfigApplicationContext:读取注解配置
5.IOC操作 - Bean管理
概念:IOC操作 - Bean管理是指两个操作: 1.Spring创建对象 2.Spring注入属性(属性赋值)
实现方式:
1.XML方式
2.注解方式
5.1基于XML方式-创建对象
该方式与入门案列方式相同
bean标签中常用属性
- id:唯一标识,通过该属性可以找到对应的Bean标签
- class:类的全限定类名
注意事项:
创建对象时,默认执行无参构造方法来完成对象的创建(反射)
5.2基于XML方式-注入属性
**DI:**依赖注入,它是IOC的一个具体操作
分类:
- 使用Set方法进行注入
- 使用构造器方式经行注入
演示:
1.实体类
public class Book {
private String name;
private String author;
public Book(String name, String author) {
this.name = name;
this.author = author;
}
public Book() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
}
2.配置XML文件
Set方法
属性注入通过<property>
name
:实体类属性名
value
:属性值
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 创建User对象-->
<bean id="book" class="com.wdzl.pojo.Book">
<property name="name" value="Java从入门到入土"></property>
<property name="author" value="詹姆士"></property>
</bean>
</beans>
构造器方法
属性注入通过<constructor-arg>
name
:实体类属性名 index
:通过索引
value
:属性值
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 创建User对象-->
<bean id="book" class="com.wdzl.pojo.Book">
<!-- <constructor-arg name="name" value="Java高级数"></constructor-arg>-->
<!-- <constructor-arg name="author" value="赵子龙"></constructor-arg>-->
<constructor-arg index="0" value="Java高级数"></constructor-arg>
<constructor-arg index="1" value="赵子龙"></constructor-arg>
</bean>
</beans>
P命名空间注入
xmlns:p="http://www.springframework.org/schema/p" 引入约束
<bean id="book" class="com.wdzl.pojo.Book" p:name="Java入门宝典" p:author="詹姆士·赵大帅哥"></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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- P命名空间注入-->
<bean id="book" class="com.wdzl.pojo.Book" p:name="Java入门宝典" p:author="詹姆士·赵大帅哥"></bean>
</beans>
3.测试
public class BookTest {
@Test
public void Test(){
//1.加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("Beans2.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
}
特殊符号注入
1.null
<constructor-arg name="name" >
<null></null>
</constructor-arg>
2.转义字符
<constructor-arg name="author" >
<value>"<关羽>"</value>
</constructor-arg>
3.CDATA
<constructor-arg name="author" >
<value><![CDATA[<詹姆斯·屈波>]]></value>
</constructor-arg>
外部Bean
1.新建Moule,在pom.xml中添加依赖
2.按照三层架构成绩:Dao,Service,Web,在dao层中添加方法,在Service层中添加对Dao层的依赖(dao成员变量,对应的set方法)
3.配置对象信息
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 创建userDao对象-->
<bean id="userDao" class="com.wdzl.dao.impl.UserDaoImpl">
</bean>
<!-- 创建UserService对象-->
<bean id="userService" class="com.wdzl.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
内部类
1.再上一个演示案例的基础上,创建两个实体类Emp和Dept,其中Emp包含Dept对象属性
2.配置对象信息
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--内部Bean-->
<bean id="emp" class="com.wdzl.pojo.Emp">
<!-- 基本数据类型-->
<property name="name" value="赵童"></property>
<property name="gender" value="男"></property>
<!-- 引用数据类型-->
<property name="dept">
<bean id="dept" class="com.wdzl.pojo.Dept">
<property name="deptName" value="研发部"></property>
</bean>
</property>
</bean>
</beans>
级联操作
1.方式一
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--级联操作1-->
<bean id="dept" class="com.wdzl.pojo.Dept">
<property name="deptName" value="运营部"></property>
</bean>
<bean id="emp" class="com.wdzl.pojo.Emp">
<!-- 基本数据类型-->
<property name="name" value="赵童"></property>
<property name="gender" value="男"></property>
<!-- 引用数据类型-->
<property name="dept" ref="dept"></property>
</bean>
</beans>
2.方式二
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dept" class="com.wdzl.pojo.Dept">
</bean>
<bean id="emp" class="com.wdzl.pojo.Emp">
<!-- 基本数据类型-->
<property name="name" value="赵童"></property>
<property name="gender" value="男"></property>
<!-- 引用数据类型-->
<property name="dept" ref="dept"></property>
<property name="dept.deptName" value="运营部"></property>
</bean>
</beans>
注意事项:
针对方式2: - -定要提供get. set方法,否则配置文件中的某些属性就会报红。
(基本数据类型)数组,集合属性的注入
1.创建一个实体类
package com.wdzl.pojo;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class Demo {
private String[] string;
private List<String> list;
private Map<String ,String> map;
@Override
public String toString() {
return "Demo{" +
"string=" + Arrays.toString(string) +
", list=" + list +
", map=" + map +
'}';
}
public String[] getString() {
return string;
}
public void setString(String[] string) {
this.string = string;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public Demo(String[] string, List<String> list, Map<String, String> map) {
this.string = string;
this.list = list;
this.map = map;
}
public Demo() {
}
}
2.配置对象属性
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="demo" class="com.wdzl.pojo.Demo">
<!-- 字符串数组-->
<property name="strings">
<array>
<value>你好</value>
<value>小老弟</value>
</array>
</property>
<!-- list集合-->
<property name="list">
<list>
<value>hello</value>
<value>people</value>
</list>
</property>
<!-- map集合-->
<property name="map">
<map>
<entry key="你好" value="世界"></entry>
<entry key="哈哈" value="屈波"></entry>
<entry key="好" value="唐康"></entry>
</map>
</property>
</bean>
</beans>
- 引用数据类型
城市类:
package com.wdzl.pojo;
public class City {
private String cityName;
@Override
public String toString() {
return "City{" +
"cityName='" + cityName + '\'' +
'}';
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public City(String cityName) {
this.cityName = cityName;
}
public City() {
}
}
省类:
package com.wdzl.pojo;
import java.util.List;
public class Province {
private List<String> cities;
@Override
public String toString() {
return "Province{" +
"cities=" + cities +
'}';
}
public List<String> getCities() {
return cities;
}
public void setCities(List<String> cities) {
this.cities = cities;
}
public Province(List<String> cities) {
this.cities = cities;
}
public Province() {
}
}
2.配置对象信息
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
https://www.springframework.org/schema/util/spring-util.xsd">
<util:list id="cityList">
<value>西安</value>
<value>宝鸡</value>
<value>延安</value>
</util:list>
<bean id="province" class="com.wdzl.pojo.Province">
<property name="cities" ref="cityList"></property>
</bean>
<!-- <bean id="city" class="com.wdzl.pojo.City">-->
<!-- <property name="cityName" value="西安"></property>-->
<!-- </bean>-->
<!-- <bean id="city2" class="com.wdzl.pojo.City">-->
<!-- <property name="cityName" value="宝鸡"></property>-->
<!-- </bean>-->
<!-- <bean id="city3" class="com.wdzl.pojo.City">-->
<!-- <property name="cityName" value="安康"></property>-->
<!-- </bean>-->
<!-- <bean id="city4" class="com.wdzl.pojo.City">-->
<!-- <property name="cityName" value="延安"></property>-->
<!-- </bean>-->
<!-- <bean id="province" class="com.wdzl.pojo.Province">-->
<!-- <property name="cities">-->
<!-- <list>-->
<!-- <ref bean="city"></ref>-->
<!-- <ref bean="city2"></ref>-->
<!-- <ref bean="city3"></ref>-->
<!-- <ref bean="city4"></ref>-->
<!-- </list>-->
<!-- </property>-->
<!-- </bean>-->
</beans>
FactoryBean:
**概述:**Spring中有两种类型的Bean,一种是普通Bean,一种是工厂Bean
- 普通Bean:在配置文件中定义的Bean类型就是返回类型。
- 工厂Bean:在配置文件中配置bean类型与返回类型不同。
演示:
创建一个工厂类
/**
* 工厂Bean类型
*/
public class MyBean implements FactoryBean<String> {
/**
* 获取对象:此方法中定义了注入MyBean时,真正返回的对象
* @return
* @throws Exception
*/
@Override
public String getObject() throws Exception {
return "我是钢铁侠";
}
/**
* 返回对象类型
* @return
*/
@Override
public Class<?> getObjectType() {
return null;
}
/**
* 是否是单例
* @return
*/
@Override
public boolean isSingleton() {
return false;
}
}
配置对象信息
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myBean" class="com.wdzl.pojo.MyBean"></bean>
</beans>
测试案例
@Test
public void factoryBeanTest(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean6.xml");
String province = (String)context.getBean("myBean",String.class);
System.out.println(province);
}
5.3 Bean的作用域
**概述:**在Spring中,设置创建Bean实例是单例还是多例。默认情况,Bean是单例。
注意:
Singleton
和 prototype
的区别:
Singleton
:在加载配置文件时,对象便会创建,并且,只创建一个对象prototype
:在加载配置文件时,并不会创建对象,在调用getBean方法时,才会创建对象,并且每次调用都会创建。
5.4 Bean的生命周期
概述:
一个对象从创建到销毁的过程
过程:
- 通过构造器创建Bean实例
- 为Bean的属性设置值或引用其他Bean(调用set)
- 调用Bean初始化方法
- Bean对象获取
- 容器关闭,调用销毁Bean的方法
演示:
实体类
public class User {
private String name;
public User(){
System.out.println("第一步:通过构造器创建对象");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("第二步,为Bean属性设置值");
this.name = name;
}
public void init(){
System.out.println("第三步:调用Bean初始化方法");
}
public void destroy(){
System.out.println("第五步:调用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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.wdzl.pojo.User" init-method="init" destroy-method="destroy">
<property name="name" value="周星驰"></property>
</bean>
<!-- <bean id="myBeanLast" class="com.wdzl.pojo.MyBeanLast"></bean>-->
</beans>
结果
第一步,通过构造器创建对象
第二步,为Bean属性设值
第三步,调用初始化方法
第四步:Bean的对象获取
第五步,调用摧毁方法
在Bean的生命周期中,如果配置了后置处理,生命周期会额外增加两步
- 通过构造器创建Bean实例
- 为Bean的属性设置值或引用其他Bean(调用set)
- 执行后置处理
- 调用Bean初始化方法
- 执行后置处理
- Bean对象获取
- 容器关闭,调用销毁Bean的方法
演示:
在上述演示中再加入一个实体类
/**
* 后置处理类
*/
public class MyBeanLast implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第三步:执行后置处理+postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("第五步:执行后置处理+postProcessAfterInitialization");
return 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.wdzl.pojo.User" init-method="init" destroy-method="destroy">
<property name="name" value="周星驰"></property>
</bean>
<bean id="myBeanLast" class="com.wdzl.pojo.MyBeanLast"></bean>
</beans>
结果
第一步,通过构造器创建对象
第二步,为Bean属性设值
执行后置处理:postProcessBeforeInitialization
第三步,调用初始化方法
执行后置处理:postProcessAfterInitialization
第四步:Bean的对象获取
第五步,调用摧毁方法
5.5 XML方式-自动装配
概述:
根据指定的装配规则(属性名称,属性类型),Spring自动将匹配的属性经行注入
实现:
借助<bean>
标签里的autowrie
属性来实现自定装配,该属性有两个值
- byName:根据属性名称注入
- byType:根据属性类型注入
注意:
- byType:如果有多个
class
属性相同的bean
标签,自动装配会报错
5.6 引入外部标签
<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">
<!-- 引入外部配置文件-->
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${druid.driverClassName}"></property>
<property name="url" value="${druid.url}"></property>
<property name="username" value="${druid.username}"></property>
<property name="password" value="${druid.password}"></property>
</bean>
<!-- 直接方式:配置连接信息-->
<!-- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
<!-- <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>-->
<!-- <property name="url" value="jdbc:mysql:///test"></property>-->
<!-- <property name="username" value="root"></property>-->
<!-- <property name="password" value="13992794421"></property>-->
<!-- </bean>-->
5.7基于注解方式-创建对象
**注解概述:**注解是代码的特殊标记
注解格式:@注解名称(属性名=属性值,属性名2=属性值2。。。。)
**注解应用:**它可以简化XML的配置,注解可以用在类上,属性上,方法上。
Spring针对创建对象提供了4个注解
- @Component:普通类使用
- @Service:Service层使用
- @Controller:Web层使@
- @Repository:Dao层使用
这四个注解功能是相同的,都可以用来创建Bean实例。
1.新建Model,添加依赖
2.创建Dao层实体类,在该类上添加注解
@Repository(value = "userDao")//相当于配置文件中Bean id属性
public class UserDao {
public void addUser(){
System.out.println("UserDao:addUser....");
}
}
3.在配置文件中开启注解扫描
<?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
">
<!-- 直接方式配置连接信息-->
<!-- 直接方式:配置连接信息-->
<!-- <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">-->
<!-- <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>-->
<!-- <property name="url" value="jdbc:mysql:///test"></property>-->
<!-- <property name="username" value="root"></property>-->
<!-- <property name="password" value="13992794421"></property>-->
<!-- </bean>-->
<!-- 引用外部配置-->
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${druid.driverClassName}"></property>
<property name="url" value="${druid.url}"></property>
<property name="username" value="${druid.username}"></property>
<property name="password" value="${druid.password}"></property>
</bean>
<bean id="emp" class="com.wdzl.pojo.Emp" autowire="byName"></bean>
<bean id="dept" class="com.wdzl.pojo.Dept">
<property name="name" value="研发部"></property>
</bean>
</beans>
测试
import com.wdzl.pojo.Emp;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AutowireTest {
@Test
public void test(){
ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
Emp emp = context.getBean("emp", Emp.class);
System.out.println(emp);
}
}
5.8基于注解方式-属性注入
常用注解:
1.@AutoWired:根据属性类型进行自动重装载
2.@Qualifier :根据属性名进行注入
3.@Resource:根据类型注入,也可以根据名称注入
4.@Value:基本数据类型的注入
演示:
@AutoWired
@Qualifier
- 要与@AutoWired同时使用
- 同时使用的目的是为了解决根据属性类型无法自动
@Resource
@Value
6.AOP
概述:
面向切面编程-在不改变源码的情况下,对现有程序功能进行维护。
6.1AOP底层原理
概述:底层实用了动态代理技术
分类:两种情况的动态代理
- 有接口的情况:使用了JDK的动态代理
- 代理对象与被代理对象实现相同的接口
- 没有接口的情况,使用了CGLIB动态代理
- 通过创建子类对象,在子类中重写方法,并通过super.方法名()调用被代理类中的方法
6.2AOP相关术语
- 连接点(JoinPoint):类里面那些方法可以被增强,这些方法就叫做连接点
- 切入点(PoinCut):类中实际被增强的方法,称为切入点
- 通知/增强(Advice):被增强的方法中增强部分的代码称为通知或者增强
- 前置增强:在调用被增强方法前执行
- 后置增强:在调用被增强方法后执行
- 环绕增强:在调用被增强方法前后都执行
- 异常增强:在调用被增强方法出现异常时增强
- 最终增强:在调用被增强方法后,无论是否出现异常,都会被执行
- 切面(Aspect):切面本身是一个动作,将增强应用到切入点的过程
- 代理(Proxy)
- 目标对象(Target)
- 织入(Weaving)
6.3AspectJ
概述:
AspectJ时一个独立的AOP框架,一般开发中将AspectJ 与Spring框架-起使用,进行AOP操作
实现AOP的两种方式:
1.基于XML方式实现
2.基于注解方式实现
相关依赖:
<dependencies>
<!-- Spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<!-- 日志依赖-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<!-- 测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- aspectJ依赖-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>
切入点表达式
**概述:**让Spring框架知道哪个类里面的那个方法需要增强
语法结构:
-
execution([权限修饰符] [返回值类型] [全限定类名] .[方法名]([参数列表]))
- 权限修饰符 可以省略
- 返回值
*
代表任意返回值类型
-
举例
- 对com.wdzl.dao.UserDao类中的addUser方法进行增强
execution(* com.wdzl.dao.UserDao.addUser(…))
1.新建Module,添加依赖
2.按照三层架构创建包结构
3.编写dao层接口
package com.wdzl.dao;
public interface UserDao {
void addUser();
}
4.实现dao层接口的方法
package com.wdzl.dao.Impl;
import com.wdzl.dao.UserDao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao {
@Override
public void addUser() {
System.out.println(3/0);
System.out.println("天不生我李志刚");
}
}
5.产生代理对象
package com.wdzl.proxy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect//将该类生产代理对象
public class UserDaoProxy {
/**
* 前置增强
*/
@Before(value = "execution(* com.wdzl.dao.Impl.UserDaoImpl.addUser(..))")
public void before(){
System.out.println("before:前置增强.....");
}
/**
* 最终增强
*/
@After(value = "execution(* com.wdzl.dao.Impl.UserDaoImpl.addUser(..))")
public void after(){
System.out.println("after:最终增强...");
}
/**
* 后置增强
*/
@AfterReturning(value ="execution(* com.wdzl.dao.Impl.UserDaoImpl.addUser(..))")
public void afterReturning(){
System.out.println("AfterReturning:后置增强...");
}
/**
* 异常增强
*/
@AfterThrowing(value ="execution(* com.wdzl.dao.Impl.UserDaoImpl.addUser(..))")
public void afterThrowing(){
System.out.println("AfterThrowing:异常增强...");
}
/**
* 环绕增强
*/
@Around(value = "execution(* com.wdzl.dao.Impl.UserDaoImpl.addUser(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕之前...");
joinPoint.proceed();
System.out.println("环绕之后...");
}
}
6.编写配置文件
<?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: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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
>
<!-- 开启组件扫描-->
<context:component-scan base-package="com.wdzl"></context:component-scan>
<!--生成Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
7。测试
import com.wdzl.dao.Impl.UserDaoImpl;
import com.wdzl.dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AopTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
UserDao userDaoImpl = context.getBean("userDaoImpl", UserDao.class);
userDaoImpl.addUser();
}
}
7.JDBCTemplate
概述:
Spring对JDBC的封装,使用可以方便的去操作数据库
对用户进行增删改查
1.新建Module添加相关依赖
2.按照三层架构创建包结构
3.创建Student实体类
package com.wdzl.pojo;
/**
* 学生类
*/
public class Student {
private int id;
private String username;
private String gender;
private String birthday;
private String address;
public Student() {
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", username='" + username + '\'' +
", gender='" + gender + '\'' +
", birthday='" + birthday + '\'' +
", address='" + address + '\'' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Student(int id, String username, String gender, String birthday, String address) {
this.id = id;
this.username = username;
this.gender = gender;
this.birthday = birthday;
this.address = address;
}
}
4.编写dao层接口及其实现方法
接口:
package com.wdzl.dao;
import com.wdzl.pojo.Student;
import java.util.List;
/**
* 学生持久层接口
*/
public interface StudentDao {
/**
* 添加
*/
public void addStudent(Student student);
/**
* 修改
*/
public void updateStudent(Student student);
/**
* 删除
*/
public void deleteStudent(Integer id);
/**
* 根据id查询学生详细信息
*/
public Student findStudentById(Integer id);
/**
* 查询学生总数
*/
List<Student> findStudentList();
/**
* 查询学生总数
*/
public int total();
/**
* 批量增加
*/
public void batchAdd(List<Object[]> students);
/**
* 批量删除
*/
public void batchDelete(List<Object[]> students);
/**
* 批量修改
*/
public void batchUpdate(List<Object[]> students);
}
实现:
package com.wdzl.dao.impl;
import com.wdzl.dao.StudentDao;
import com.wdzl.pojo.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.Arrays;
import java.util.List;
/**
* 学生持久层实现类
*/
@Repository
public class StudentDaoImpl implements StudentDao{
//注入jdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void addStudent(Student student) {
String sql="insert into student(id,username,gender,birthday,address) values (?,?,?,?,?)";
int update = jdbcTemplate.update(sql, student.getId(), student.getUsername(), student.getGender(), student.getBirthday(), student.getAddress());
System.out.println(update);
}
@Override
public void updateStudent(Student student) {
String sql="update student set address=? where username=?";
int update = jdbcTemplate.update(sql, student.getAddress(), student.getUsername());
System.out.println(update);
}
@Override
public void deleteStudent(Integer id) {
String sql="delete from student where id=? ";
int update = jdbcTemplate.update(sql,id);
System.out.println(update);
}
@Override
public Student findStudentById(Integer id) {
String sql="select*from student where id=?";
Student student = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Student.class), id);
return student;
}
@Override
public List<Student> findStudentList() {
String sql="select*from student ";
List<Student> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Student.class));
return query;
}
@Override
public int total() {
String sql="select count(*) from student ";
Integer integer = jdbcTemplate.queryForObject(sql, Integer.class);
return integer;
}
@Override
public void batchAdd(List<Object[]> students) {
String sql="insert into student(username,gender,birthday,address) values (?,?,?,?)";
/**
* 批量增加
* 参数1:sql语句
* 参数2:
*/
int[] ints = jdbcTemplate.batchUpdate(sql, students);
System.out.println(Arrays.toString(ints));
}
@Override
public void batchDelete(List<Object[]> students) {
String sql="delete from student where username=? ";
int[] ints = jdbcTemplate.batchUpdate(sql, students);
System.out.println(Arrays.toString(ints));
}
@Override
public void batchUpdate(List<Object[]> students) {
String sql="update student set address=? where id=?";
int[] ints = jdbcTemplate.batchUpdate(sql, students);
System.out.println(Arrays.toString(ints));
}
}
5.创建service层接口及其实现方法
接口:
package com.wdzl.service;
import com.wdzl.pojo.Student;
import java.util.List;
/**
* 学生业务成接口
*/
public interface StudentService {
/**
* 添加学生
*/
public void addStudent(Student student);
/**
* 修改
*/
public void updateStudent(Student student);
/**
* 删除
*/
public void deleteStudent(Integer id);
/**
* 根据id查询学生详细信息
*/
public Student findStudentById(Integer id);
/**
* 查询学生总数
*/
List<Student> findStudentList();
/**
* 查询学生总数
*/
public int total();
/**
* 批量增加
*/
public void batchAdd(List<Object[]> students);
/**
* 批量删除
*/
public void batchDelete(List<Object[]> username);
/**
* 批量修改
*/
public void batchUpdate(List<Object[]> students);
}
实现:
package com.wdzl.service.impl;
import com.wdzl.dao.StudentDao;
import com.wdzl.pojo.Student;
import com.wdzl.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentDao studentDao;
@Override
public void addStudent(Student student) {
studentDao.addStudent(student);
}
@Override
public void updateStudent(Student student) {
studentDao.updateStudent(student);
}
@Override
public void deleteStudent(Integer id) {
studentDao.deleteStudent(id);
}
@Override
public Student findStudentById(Integer id) {
Student studentById = studentDao.findStudentById(id);
return studentById;
}
@Override
public List<Student> findStudentList() {
List<Student> studentList = studentDao.findStudentList();
return studentList;
}
@Override
public int total() {
int total = studentDao.total();
return total;
}
@Override
public void batchAdd(List<Object[]> students) {
studentDao.batchAdd(students);
}
@Override
public void batchDelete(List<Object[]> students) {
studentDao.batchDelete(students);
}
@Override
public void batchUpdate(List<Object[]> students) {
studentDao.batchAdd(students);
}
}
6.编写配置文件
<?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: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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
>
<!-- 开启组件扫描-->
<context:component-scan base-package="com.wdzl"></context:component-scan>
<!--数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///mybatis?useUnicode=true&characterEncoding=utf-8"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--jdbcTempLate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
7.测试
import com.wdzl.pojo.Student;
import com.wdzl.service.StudentService;
import com.wdzl.service.impl.StudentServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.List;
public class StudentTest {
@Test
public void testAddStudent(){
//1.获取配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("Beans.xml");
//2.创建服务层接口对象
StudentService studentServiceImpl = context.getBean("studentServiceImpl", StudentService.class);
Student student=new Student(0,"赵童","男","2000-1-1","宝鸡");
studentServiceImpl.addStudent(student);
}
@Test
public void testUpdateStudent(){
//1.获取配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("Beans.xml");
//2.创建服务层接口对象
StudentService studentServiceImpl = context.getBean("studentServiceImpl", StudentService.class);
Student student=new Student();
student.setAddress("北京");
student.setUsername("赵童");
studentServiceImpl.updateStudent(student);
}
@Test
public void testDeleteStudent(){
//1.获取配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("Beans.xml");
//2.创建服务层接口对象
StudentService studentServiceImpl = context.getBean("studentServiceImpl", StudentService.class);
studentServiceImpl.deleteStudent(1);
}
@Test
public void testFindStudentById(){
//1.获取配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("Beans.xml");
//2.创建服务层接口对象
StudentService studentServiceImpl = context.getBean("studentServiceImpl",StudentService.class);
Student studentById = studentServiceImpl.findStudentById(2);
System.out.println(studentById);
}
@Test
public void testFindStudentList(){
//1.获取配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("Beans.xml");
//2.创建服务层接口对象
StudentService studentServiceImpl = context.getBean("studentServiceImpl",StudentService.class);
List<Student> studentList = studentServiceImpl.findStudentList();
for (Student student:studentList){
System.out.println(student);
}
}
@Test
public void testFindStudentTotal(){
//1.获取配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("Beans.xml");
//2.创建服务层接口对象
StudentService studentServiceImpl = context.getBean("studentServiceImpl",StudentService.class);
int total = studentServiceImpl.total();
System.out.println(total);
}
@Test
public void testAddBatch(){
//1.获取配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("Beans.xml");
//2.创建服务层接口对象
StudentService studentServiceImpl = context.getBean("studentServiceImpl",StudentService.class);
List<Object[]> args=new ArrayList<>();
Object[] o1={"王必武","男","2020-2-2","湖南"};
Object[] o2={"王必武1","男","2020-2-2","湖南"};
Object[] o3={"王必武2","男","2020-2-2","湖南"};
Object[] o4={"王必武3","男","2020-2-2","湖南"};
args.add(o1);
args.add(o2);
args.add(o3);
args.add(o4);
studentServiceImpl.batchAdd(args);
}
@Test
public void testDelete(){
//1.获取配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("Beans.xml");
//2.创建服务层接口对象
StudentService studentServiceImpl = context.getBean("studentServiceImpl",StudentService.class);
List<Object[]> args=new ArrayList<>();
Object[] o1={"王必武"};
args.add(o1);
studentServiceImpl.batchDelete(args);
}
@Test
public void testUpdateBatch(){
//1.获取配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("Beans.xml");
//2.创建服务层接口对象
StudentService studentServiceImpl = context.getBean("studentServiceImpl",StudentService.class);
List<Object[]> args=new ArrayList<>();
Object[] o1={"北京",1};
Object[] o2={"西安",2};
args.add(o1);
args.add(o2);
studentServiceImpl.batchUpdate(args);
}
}
8.事务
8.1事务环境搭建
1.新建Module添加相关依赖
2.编写配置文件
- 配置数据源
- 配置JDBCTemplate
- 开启组件扫描
3.编写Dao层接口,Service层接口,及相应的实现类
Dao层
接口
package com.wdzl.dao;
/**
* 账户持久层接口
*/
public interface AccountDao {
/**
* 转入操作
*/
public void moneyIn(String name,double money);
public void moneyOut(String name,double money);
}
实现
package com.wdzl.dao.Impl;
import com.wdzl.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
/**
* 账户持久层实现类
*/
@Repository
public class AccountDaoImpl implements AccountDao {
//注入jdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public void moneyIn(String name, double money) {
String sql="update account set money=money+? where name=?";
int update = jdbcTemplate.update(sql, money, name);
System.out.println(update);
}
@Override
public void moneyOut(String name, double money) {
String sql="update account set money=money-? where name=?";
int update = jdbcTemplate.update(sql, money, name);
System.out.println(update);
}
}
Service层
接口
package com.wdzl.service;
public interface AccountService {
/**
* 转账操作
*/
public void transferAccounts(String outName,String inName,double money);
}
实现
package com.wdzl.service.impl;
import com.wdzl.dao.AccountDao;
import com.wdzl.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class AccountServiceImpl implements AccountService {
//注入AccountDao
@Autowired
private AccountDao accountDao;
@Override
public void transferAccounts(String outName, String inName, double money) {
accountDao.moneyIn(inName,money);
// System.out.println(1/0);
accountDao.moneyOut(outName,money);
}
}
4.测试
import com.wdzl.config.TxConfig;
import com.wdzl.service.AccountService;
import com.wdzl.service.impl.AccountServiceImpl;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AccountTest {
@Test
public void test(){
String outName="aa";
String inName="bb";
double money=400.00;
//1.获取配置文件
ApplicationContext context=new ClassPathXmlApplicationContext("Beans2.xml");
//2.创建服务层接口对象
AccountService accountService = context.getBean("accountServiceImpl", AccountService.class);
accountService.transferAccounts(outName,inName,money);
}
@Test
public void test2(){
String outName="aa";
String inName="bb";
double money=400.00;
//1.获取配置文件
ApplicationContext context=new AnnotationConfigApplicationContext(TxConfig.class);
//2.创建服务层接口对象
AccountService accountService = context.getBean("accountServiceImpl", AccountService.class);
accountService.transferAccounts(outName,inName,money);
}
}
8.2事务操作
1.事务因该加入到Service层
- 因为service层负责组装业务
2.在spring中进行事务管理
- 编译式事务
- 声明式事务
3.声明式事务管理
- 基于注解方式
- 基于xml方式
4.在spring中进行声明式事务管理使用AOP原理
5.spring针对不同的框架使用了不同的API
- JDBC,mybatis:DataSourceransTransactionManager
- Hibernate:HibernateTransactionManager
8.4基于XML方式的事务管理
读取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:aop ="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd"
>
<!-- 开启组件扫描-->
<context:component-scan base-package="com.wdzl"></context:component-scan>
<!--数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql:///test?useUnicode=true&characterEncoding=utf-8"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--jdbcTempLate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 创建事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置通知advice-->
<tx:advice id="txAdvice">
<!-- 配置事务数据-->
<tx:attributes>
<tx:method name="transferAccounts" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置切入点和切面-->
<aop:config>
<aop:pointcut id="pt" expression="execution(* com.wdzl.service.impl.AccountServiceImpl.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"></aop:advisor>
</aop:config>
</beans>
8.3基于注解方式的事务管理
**@Transaction常见配置
- propagation :事务传播行为
- isolation: 事务隔离级别
- timeout:超时时间
- readOnly:是否只读
- rollbackFor:回滚
- noRollbackFor:不回滚
引用配置类(注解)
package com.wdzl.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
/**
* 配置类
*/
@Configuration//配置类
@ComponentScan(basePackages = "com.wdzl")//开启组件扫描
@EnableTransactionManagement//开启事务
public class TxConfig {
//配置数据源
@Bean
public DruidDataSource getDruidDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///test?useUnicode=true&characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
//配置jdbcTemplate
@Bean
public JdbcTemplate getJdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
return jdbcTemplate;
}
//配置事务管理器
@Bean
public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
9.Spring 整合mybatis
9.1注解版声明式事务
1、导⼊依赖坐标
<?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.wdzl</groupId>
<artifactId>Spring_Mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.16</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
2.创建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>
<mappers>
<!--引入dao层文件-->
<mapper class="com.wdzl.dao.AccountDao"></mapper>
</mappers>
</configuration>
3.提取数据源、SqlSessionFactory
package com.wdzl.jdbc;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
/**
* 数据库连接配置类
*/
public class JdbcConfig {
//用于获取数据源dataSouce的方法
@Bean//将DataSource注入Spring中
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
//用于获取sqlSessionFactory的方法
@Bean
public SqlSessionFactoryBean create(DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
Resource resource = new ClassPathResource("SqlMapConfig.xml");
sqlSessionFactory.setConfigLocation(resource);
return sqlSessionFactory;
}
}
4.提取事务管理类和配置类
1.事务管理类
package com.wdzl.tx;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
/**
* 事务管理类
*/
public class TransactionConfig {
//获取事务管理对象的方法
@Bean //注入事务增强类DataSourceTransactionManager
public PlatformTransactionManager createTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
2.配置类
package com.wdzl.tx;
import com.wdzl.jdbc.JdbcConfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* 配置类 相当于bean。xml文件作用
*/
@Configuration//定义配置类
@ComponentScan(basePackages = "com.wdzl")//开启组件扫描
@Import(value = {JdbcConfig.class, TransactionConfig.class})//引入其他配置
@EnableTransactionManagement//开启事务
public class SpringConfig {
}
5.编写pojo–>dao–>service–>controller–>test
pojo
package com.wdzl.pojo;
/**
* 账户类
*/
public class Account {
private int id ;
private String name;
private double money;
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 double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
dao层
接口
package com.wdzl.dao;
import com.wdzl.pojo.Account;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
/**
* 账户持久层接口
*/
public interface AccountDao {
/**
* 根据用户名查询账户信息
* @param name
* @return
*/
@Select("select * from account where name=#{name}")
Account findAccountByName(String name) ;
/**
* 更新账户信息
* @param account
*/
@Update("update account set name=#{name},money=#{money} where id=#{id}")
void updateAccount(Account account);
}
实现类
package com.wdzl.dao.impl;
import com.wdzl.dao.AccountDao;
import com.wdzl.pojo.Account;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
/**
* 账户持久层接口实现类
*/
@Repository
public class AccountDaoImpl implements AccountDao {
@Autowired
private SqlSessionFactory sqlSessionFactory;
@Override
public Account findAccountByName(String name) {
SqlSession sqlSession = sqlSessionFactory.openSession();
AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
//获取sqlsession对象
return accountDao.findAccountByName(name);
}
@Override
public void updateAccount(Account account) {
SqlSession sqlSession = sqlSessionFactory.openSession();
AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
accountDao.updateAccount(account);
}
}
service层
接口
package com.wdzl.service;
/**
* 账户业务层接口
*/
public interface AccountService {
/**
* 转账方法
* @param sourceName 转出账户姓名
* @param targetName 转入账户姓名
* @param money 转账金额
*/
void transfer(String sourceName, String targetName, double money);
}
实现类
package com.wdzl.service.impl;
import com.wdzl.dao.AccountDao;
import com.wdzl.pojo.Account;
import com.wdzl.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* 账户业务层实现类
*/
@Service
@Transactional(propagation = Propagation.REQUIRED,readOnly = false)//此⽅法需要加⼊事务,并且为读写事务
public class AccountServiceImpl implements AccountService {
@Autowired
//注⼊数据访问层接口
private AccountDao accountDao;
public AccountDao getAccountDao() {
return accountDao;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String sourceName, String targetName, double money) {
//查询转出账户对象
Account source = accountDao.findAccountByName(sourceName);
//查询注入账户对象
Account target = accountDao.findAccountByName(targetName);
//判断账户是否存在
if (source !=null && target != null) {
//设置转出转入金额
source.setMoney(source.getMoney() - money);
target.setMoney(target.getMoney() + money);
//更新账户信息
accountDao.updateAccount(source);
accountDao.updateAccount(target);
}
}
}
controller层
package com.wdzl.controller;
import com.wdzl.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
/**
* 账户控制层
*/
@Controller
public class AccountController {
@Autowired//注入业务接口
private AccountService accountService;
//为视图提供转账请求接口
public void transfer(String sourceName, String targetName, double money) {
try {
//调用业务层转账方法
accountService.transfer(sourceName, targetName, money);
System.out.println("转账成功");
} catch (Exception e) {
System.out.println("转账失败");
}
}
}
test(测试)
import com.wdzl.controller.AccountController;
import com.wdzl.tx.SpringConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AccountTest {
@Test
public void test() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
AccountController accountController = context.getBean("accountController", AccountController.class);
accountController.transfer("aa", "bb",500);
// accountController.transfer("王必无","唐康",500.00);
}
}
结果:转账成功
9.2XML版声明式事务
1.导⼊依赖坐标
<?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.wdzl</groupId>
<artifactId>Spring_mybatis_xml</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!--mybatis 和 Spring整合包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>
<!--spring 声明式事务必须所使⽤的依赖坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
2.创建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>
<mappers>
<!--引入dao成文件-->
<mapper class="com.wdzl.dao.AccountDao"></mapper>
</mappers>
</configuration>
3.db.properties ⽂件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
4.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: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/aop
http://www.springframework.org/schema/aop/spring-beans.aop">
<bean id="logger" class="com.wdzl.log.Logger"></bean>
<bean id="accountService" class="com.wdzl.service.impl.AccountServiceImpl"></bean>
<aop:config>
<!--定义切⼊点-->
<aop:pointcut id="mypointcut" expression="execution(*
com.wdzl.service.impl.*.*(..))"/>
<!--配置增强处理类-->
<aop:aspect id="logAdvice" ref="logger">
<!--将logger类中的⽅法内容通过前置的⽅式植⼊到⽬标⽅法中-->
<aop:before method="before" pointcut-ref="mypointcut"></aop:before>
<!--最终增强处理:在没有异常的情况下,此增强内容会被植⼊-->
<aop:after method="after" pointcut-ref="mypointcut"></aop:after>
<!--后置增强处理:在有⽆异常的情况下,均进⾏内容增强处理的植⼊-->
<aop:after-returning method="afterReturning" pointcut-ref="mypointcut" ></aop:after-returning>
<!--异常增强处理:在异常的情况下,此增强内容会被植⼊ 注:和后置增强处理⼆者不能
同时出现-->
<aop:after-throwing method="afterThrowing" pointcut-ref="mypointcut"></aop:after-throwing>
</aop:aspect>
</aop:config>
</beans>
5.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:aop="http://www.springframework.org/schema/aop"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
"
>
<!--引⼊db.properties ⽂件-->
<context:property-placeholder location="db.properties"></context:property-placeholder>
<!--注⼊数据访问层实现类-->
<bean id="accountDao" class="com.wdzl.dao.impl.AccountDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!--注⼊业务逻辑层-->
<bean id="accountService" class="com.wdzl.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--注⼊控制层-->
<bean id="accountController" class="com.wdzl.controller.AccountController">
<property name="accountService" ref="accountService"></property>
</bean>
<!--注⼊数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--注⼊sqlsession-->
<bean id="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="SqlMapConfig.xml"></property>
</bean>
<!--注⼊Spring 声明式事务对象-->
<bean id="dataSourceTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<!--为连接点中的所有⽅法加⼊读写事务-->
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
<!--给连接点中所有查询⽅法加⼊只读事务-->
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!--aop 配置-->
<aop:config>
<!--配置通⽤化切⼊点表达式-->
<aop:pointcut id="pointcut" expression="execution( *
com.wdzl.service.impl.*.*(..))"/>
<!--建⽴切⾯-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
</beans>
6.编写pojo–>log–dao–>service–>controller–>test
1.Logger日志增强类
package com.wdzl.log;
public class Logger {
public void before(){
System.out.println("前置增强处理内容被植⼊......");
}
public void after(){
System.out.println("最终增强(有⽆异常均执⾏)处理内容被植⼊......");
}
public void afterReturning(){
System.out.println("后置增强(⽆异常情况)处理内容被植⼊......");
}
public void afterThrowing(){
System.out.println("异常增强处理内容被植⼊......");
}
}
2.pojo实体类
package com.wdzl.pojo;
/**
* 账户类
*/
public class Account {
private int id ;
private String name;
private double money;
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 double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", name='" + name + '\'' +
", money=" + money +
'}';
}
}
3.dao层
接口
package com.wdzl.dao;
import com.wdzl.pojo.Account;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
public interface AccountDao {
/**
* 根据用户名查询账户信息
* @param name
* @return
*/
@Select("select * from account where name=#{name}")
Account findAccountByName(String name) ;
/**
* 更新账户信息
* @param account
*/
@Update("update account set name=#{name},money=#{money} where id=#{id}")
void updateAccount(Account account);
}
实现
package com.wdzl.dao.impl;
import com.wdzl.dao.AccountDao;
import com.wdzl.pojo.Account;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
/**
* 账户接口实现类
*/
@Repository
public class AccountDaoImpl extends SqlSessionDaoSupport implements AccountDao {
/**
* 查询账户信息
* @param name
* @return
*/
@Override
public Account findAccountByName(String name) {
//获取session
SqlSession session = super.getSqlSession();
AccountDao mapper = session.getMapper(AccountDao.class);
Account account = mapper.findAccountByName(name);
//释放资源
return account;
}
/**
* 更新账户信息
* @param account
*/
@Override
public void updateAccount(Account account) {
SqlSession session = super.getSqlSession();
AccountDao mapper = session.getMapper(AccountDao.class);
mapper.updateAccount(account);
}
}
4。service层
接口
package com.wdzl.service;
public interface AccountService {
/**
*转账业务
*/
void transfer(String sourceName, String targetName, double money);
void testLog();
}
实现
package com.wdzl.service.impl;
import com.wdzl.dao.AccountDao;
import com.wdzl.log.Logger;
import com.wdzl.pojo.Account;
import com.wdzl.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional
public class AccountServiceImpl implements AccountService {
public AccountDao getAccountDao() {
return accountDao;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
private AccountDao accountDao;
@Override
public void transfer(String sourceName, String targetName, double money) {
//查询转出账户对象
Account source = accountDao.findAccountByName(sourceName);
//查询注入账户对象
Account target = accountDao.findAccountByName(targetName);
//判断账户是否存在
if (source !=null && target != null) {
//设置转出转入金额
source.setMoney(source.getMoney() - money);
target.setMoney(target.getMoney() + money);
//更新账户信息
accountDao.updateAccount(source);
accountDao.updateAccount(target);
}
}
private Logger logger;
public Logger getLogger() {
return logger;
}
public void setLogger(Logger logger) {
this.logger = logger;
}
@Override
public void testLog() {
System.out.println("测试日志增强有没有加入");
}
}
5.controller层
package com.wdzl.controller;
import com.wdzl.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class AccountController {
public AccountService getAccountService() {
return accountService;
}
public void setAccountService(AccountService accountService) {
this.accountService = accountService;
}
private AccountService accountService;
public void transfer(String sourceName, String targetName, double money) {
try {
accountService.transfer(sourceName, targetName, money);
System.out.println("转账成功");
} catch (Exception e) {
System.out.println("转账失败");
}
}
}
6.test测试
LoggerTest测试类
import com.wdzl.service.AccountService;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class LoggerTest {
private ApplicationContext context;
@Test
public void testLog(){
AccountService accountService = context.getBean("accountService", AccountService.class);
accountService.testLog();
}
@Before
public void springinit(){
context = new ClassPathXmlApplicationContext("bean2.xml");
}
}
结果:
前置增强处理内容被植⼊…
测试日志增强有没有加入
最终增强(有⽆异常均执⾏)处理内容被植⼊…
后置增强(⽆异常情况)处理内容被植⼊…
AccountControllerTest测试类
import com.wdzl.controller.AccountController;
import com.wdzl.service.AccountService;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AccountControllerTest {
private ApplicationContext context;
@Before
public void springinit(){
context = new ClassPathXmlApplicationContext("bean.xml");
}
@Test
public void testTransfer(){
AccountController accountController =
context.getBean("accountController", AccountController.class);
accountController.transfer("aa","bb",5000);
}
@Test
public void test(){
AccountService accountService = context.getBean("accountService", AccountService.class);
accountService.testLog();
}
}
结果:
1.转账成功
2.测试日志增强有没有加入