基于 B站狂神说Java,非常非常感谢秦老师! 内容\排版经过完全理解后重新组织输出, 原创度较高.
源于 Spring 5.2.0.RELEASE 官网文档
给 Java 软件开发行业带来了"春天"
作者 Rod Johnson, 是悉尼大学音乐博士…
理念
使现有技术更加容易使用, Servlet 更简单好用. Spring 本身是个大杂烩, 可以整合现有的其他技术框架
导入依赖
直接导入MVC的, 互相依赖比较’完整’, 不需要手动导入多种互相依赖
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.2.0.RELEASEversion>
dependency>
Spring 就是一个轻量级的控制反转和面向切面编程的 IoC 和 AOP 框架
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sB7jPWyQ-1587282086571)(D:\微云同步助手\364291826\同步文件夹\知识库\10 - md文库 秦疆老师\框架\Spring.assets\image-20200414101635262.png)]
现代化的Java开发, 就是Spring开发
Spring Boot
Spring Cloud
大多数公司都在使用Spring Boot进行快速开发, 学习的前提是完全掌握 Spring 及 SpringMVC
Spring 发展时间久出现弊端, (秦老师认为唯一弊端) 违背原来的理念, 配置十分繁琐, 人称 “配置地狱”
Spring 的核心配置文件: beans.xml, 名字可以随便取. 官网叫ApplicationContext.xml
并配入一个 bean 元素
<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="hello" class="com.zhangcl.pojo.Hello">
<property name="str" value="Hello, Spring!">property>
bean>
beans>
测试执行
import com.zhangcl.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTests {
public static void main(String[] args) {
/*获取 SpringContext 对象
* 这之后,我们的对象都在Spring中管理了, 如果要使用, 直接取就行了
* */
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
/*取对象*/
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello);
}
}
控制反转是一种通过描述 (XML或注解) + 通过第三方去生产或获取特定兑现的方式.
在Spring中实现控制反转的是IoC容器, 实现方法是DI
采用XML方式配置Bean
要怎样真正体会\理解 IoC 思想的带来的革命性变化?
用户直接调用的是业务层, 而DAO是由业务来调用的, 所以如果要改动具体调哪个DAO的实现则需要去修改业务层的代码
以前写代码实现类对接口的注入需要把实现在业务层手动赋值给接口
后来, 第一次革命性的变化是可以由调用方通过一个setter把自己需要的实现类set给接口, 不再需要改动业务层
控制的主动权在调用方手里
程序不再具有主动性, 而是被动接受注入对象
系统耦合性大大降低
IoC创建对象的方式
借助对象的无参构造创建 (默认)
借助对象的有参构造创建
报错
假如有参构造"被不存在" (故意手写个有参构造, 编译器就不自动提供无参构造了), 但又强行在beans中配置, 则Idea会报错, 并且运行后会报init错
编译器报错
No matching constructor found in class 'User'
运行报错
Caused by: java.lang.NoSuchMethodException: com.zhangcl.pojo.User.()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cEjvDm0y-1587282086574)(D:\微云同步助手\364291826\同步文件夹\知识库\10 - md文库 秦疆老师\框架\Spring.assets\image-20200414192140329.png)]
Spring 中自动装配Bean的三种方式:
, 具体方式又分为:
byName
setXX()
的XX名字相匹配的BeanNullPointer
byType
@Autowired
is ‘better’ than XML)
byType
@Qualifier(value=BEANID)
配合, 以通过byName
匹配@Resource
功能与之非常接近!需要先配置对annotation的支持
@Autowired
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
beans>
如果@Autowired
装配的对象name和class都匹配不到或者同类多个, 则可以通过增加此注解显式地指定一个bean, 以配合@Autowired
//
@Autowired
@Qualifier(value=dog222)
private Dog dog;
与@Autowired
的很像:
from javax.annotation.Resource
可能是Java提供的, 想要代替@Autowired
的.
匹配方式: byName
或者byType
// 一般情况
@Resource
private Dog dog;
// 如果匹配不到
@Resource(name="dog222")
前提:
since Spring 4, 必须导入aop
依赖才可以使用注解开发
步骤:
aop
依赖存在
配置 - 指定扫描包, 这样此次包下的注解才会被识别. 在applicationContext.xml中:
<context:component-scan base-package="com.zhangcl.pojo"/>
标识 - 类, 在需要被Spring管理的类上增加注解@Component
标识 - 属性, 在属性上增加@Value
package com.zhangcl.pojo;
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Component;
@Component
public class User{
//
@Value("张三")
public String name;
}
@Component
有一些衍生注解: 例如在web开发中, 按照MVC三层架构, 他们本质功能相同
@Component
@Scope("singleton")
public class User{
// ...
}
对比
ref=otherBean
最佳实践
XML - 负责管理Bean
注解 - 负责属性注入
只需要注意: 要确保注解生效 (别忘了扫描包)
@Nullable
NullPointer
JavaConfig, 原是Spring的一个子项目, 在 Spring 4 之后成为核心功能
在SpringBoot中, 这种纯Java配置随处可见!
package com.zhangcl.config;
import com.zhangcl.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration // 标识
@ComponentScan("com.zhangcl.pojo") // 扫描
@Import(ConfigurationBean2.class) // 相当于import
public class ConfigurationBean {
// 相当于beans
@Bean // 相当于bean
public User getUser(){
// 方法名相当于bean的id, 返回值相当于class
return new User();
}
}
Context实现类
调用时获取bean的Context实现类需要换成AnnotationConfigApplicationContext
XML文件配置 - 整理
<alias name="user2" alias="user2Alias">alias>
注意: 别名和原名共存
其实还有另一种取别名方式
<bean id="bean的唯一标识" class="对象的全限定名" name="别名1 别名2 别名3 ...">bean>
<bean .... .... name="别名1,别名2,别名3,...">bean>
团队开发用, 将其他配置文件的信息import进来
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tL4Jhrnf-1587282086576)(D:\微云同步助手\364291826\同步文件夹\知识库\10 - md文库 秦疆老师\框架\Spring.assets\image-20200414145916208.png)]
团队成员开发各个beans.xml, 再在applicationContext.xml 中import合并为一个, 就不需要读取时候读太多xml文件了
<import resource="beans.xml">import>
<import resource="beans2.xml">import>
<import resource="beans3.xml">import>
注意: 可能有重名, 可以通过别名规避问题
本质是Set注入, 有三种方式
Setter
构造器
拓展方式
pojo
package com.zhangcl.pojo;
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Address{" +
"address='" + address + '\'' +
'}';
}
}
package com.zhangcl.pojo;
import java.util.*;
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbies;
private Map<String,String> cards;
private Set<String> games;
private Properties info;
private String girlFriend;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public Map<String, String> getCards() {
return cards;
}
public void setCards(Map<String, String> cards) {
this.cards = cards;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
public String getGirlFriend() {
return girlFriend;
}
public void setGirlFriend(String girlFriend) {
this.girlFriend = girlFriend;
}
@Override
public String toString() {
return "Address{" +
"name='" + name + '\'' +
", address=" + address +
", books=" + Arrays.toString(books) +
", hobbies=" + hobbies +
", cards=" + cards +
", games=" + games +
", info=" + info +
", girlFriend='" + girlFriend + '\'' +
'}';
}
}
beans.xml
<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.zhangcl.pojo.Address">
<property name="address" value="北京 互联网">property>
bean>
<bean id="student" class="com.zhangcl.pojo.Student">
<property name="name" value="秦疆">property>
<property name="address" ref="address">property>
<property name="books">
<array>
<value>红楼梦value>
<value>水浒传value>
<value>西游记value>
<value>三国演义value>
array>
property>
<property name="hobbies">
<list>
<value>爱好足球value>
<value>爱好篮球value>
<value>爱好代码value>
list>
property>
<property name="cards">
<map>
<entry key="身份证" value="111111222222223333">entry>
<entry key="银行卡" value="1234545345234234234">entry>
map>
property>
<property name="games">
<set>
<value>LOLvalue>
<value>COCvalue>
<value>BOBvalue>
set>
property>
<property name="girlFriend">
<null>null>
property>
<property name="info">
<props>
<prop key="url">12.44.222.1prop>
<prop key="username">rootprop>
<prop key="password">*****prop>
props>
property>
bean>
beans>
Tests.java
import com.zhangcl.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Tests {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) context.getBean("student");
System.out.println(student);
}
}
<bean id="user" class="com.zhangcl.pojo.User">
<constructor-arg type="java.lang.String" value="创建: 有参 type">constructor-arg>
<constructor-arg index="0" value="创建: 有参 index">constructor-arg>
<constructor-arg name="name" value="创建: 有参 name">constructor-arg>
bean>
注意:
个人认为有两种 :
其中我们侧重整理一下 p-namespace and c-namespace:
是一种注入值的 Shortcut (更快捷的方式)
p-namespace
- 通过property直接注入, 相当于set注入
c-namespace
- 通过constructor-arg注入
基本使用:
<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="user-p" class="com.zhangcl.pojo.User" p:name="pname" p:age="18">bean>
<bean id="user-c" class="com.zhangcl.pojo.User" c:name="cname" c:age="19">bean>
beans>
理解 - 角色分析:
抽象角色: 一般是使用接口和抽象类
真实角色: 被代理的
代理角色: 去代理真实角色的, 代理后还可以增加一些附属操作
客户: 访问真实角色的人
优势 - 静态代理:
**缺点: **
基本步骤:
和静态代理比较
实现方式, 分为两大类
基于接口
基于类的动态代理
还有一个方式是 Java字节码
JAVAssist
, jBoos服务器, 简单\快速\直接使用Java编码的格式会用到两个重要的类:
Proxy
Foo f = Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class>[]{Foo.class}, handler);
InvocationHandler
基本实现流程
准备一些环境
package com.zhangcl.demo02;
public interface UserService {
void add();
void update();
void delete();
void query();
}
package com.zhangcl.demo02;
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("add了数据");
}
public void update() {
System.out.println("update了数据");
}
public void delete() {
System.out.println("delete了数据");
}
public void query() {
System.out.println("query了数据");
}
}
创建MyInvocationHandler.java, 实现InvocationHandler接口, 用于生成动态代理类实例
package com.zhangcl.demo02;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = method.invoke(target, args);
// 增加个日志功能
System.out.println("[日志]" + proxy.getClass().getSimpleName() +
"在" + new Date() + "时间执行了" + method.getName() + "方法");
System.out.println("结果" + result);
return result;
}
/**
* 其实也可以把获取proxy instance的方法也给封装进来, 就不需要再在调用处写太复杂了
* 这个封装只是为了调用得更加简洁
*/
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
}
测试 MyTests.java
package com.zhangcl.demo02;
public class MyTest {
public static void main(String[] args) {
// 目标角色 真实角色
UserService userService = new UserServiceImpl();
// 代理角色 暂时还没有xx
MyInvocationHandler handler = new MyInvocationHandler();
// 传入要代理的目标角色
handler.setTarget(userService);
// 动态生成代理橘色 有了xx
UserService proxy = (UserService) handler.getProxy();
proxy.update();
}
}
/*
update了数据
[日志]$Proxy0在Fri Apr 17 16:57:20 CST 2020时间执行了update方法
结果null
*/
AOP在Spring中的作用:
提供声明式事务 | 允许用户自定义切面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-expX6QFC-1587282086578)(D:\微云同步助手\364291826\同步文件夹\知识库\10 - md文库 秦疆老师\框架\Spring.assets\image-20200417183154436.png)]
前提: 需要导入依赖
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.4version>
dependency>
Java接口和实现
package com.zhangcl.service;
public interface UserService {
int add();
void delete();
void update();
void select();
}
/
package com.zhangcl.service;
public class UserServiceImpl implements UserService {
public int add() {
System.out.println("增加了一个User");
return 1;
}
public void delete() {
System.out.println("删除了一个User");
}
public void update() {
System.out.println("修改了一个User");
}
public void select() {
System.out.println("查询了一个User");
}
}
Log.java
package com.zhangcl.log;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行了");
}
}
class AfterLog implements AfterReturningAdvice{
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName() + "执行了" + method.getName() + "方法, 返回结果: " + returnValue);
}
}
注册Bean
<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 id="userService" class="com.zhangcl.service.UserServiceImpl">bean>
<bean id="log" class="com.zhangcl.log.Log">bean>
<bean id="agterLog" class="com.zhangcl.log.AfterLog">bean>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* com.zhangcl.service.UserServiceImpl.*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut">aop:advisor>
<aop:advisor advice-ref="agterLog" pointcut-ref="pointcut">aop:advisor>
aop:config>
beans>
测试
import com.zhangcl.service.UserService;
import com.zhangcl.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 = (UserService) context.getBean("userService", UserService.class);
userService.add();
}
}
自定义类, 被切面引用
Java的接口和类还用方法一中的, 也体现了AOP能"提高代码的复用"
自定义一个PointCut类: DiyPointCut.java
package com.zhangcl.diy;
public class DiyPointCut {
public void before(){
System.out.println("======方法执行之前======");
}
public void after(){
System.out.println("======方法执行之后======");
}
}
在Spring的核心配置文件中中配置AOP的切面: applicationContext.xml
<bean id="diyPointCut" class="com.zhangcl.diy.DiyPointCut">bean>
<aop:config>
<aop:aspect ref="diyPointCut">
<aop:pointcut id="pointcut" expression="execution(* com.zhangcl.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="pointcut">aop:before>
<aop:after method="after" pointcut-ref="pointcut">aop:after>
aop:aspect>
aop:config>
测试: MyTest.java, 还是之前的
配置文件: applicationContext.xml
<bean id="annotationPointCut" class="com.zhangcl.diy.AnnotationPointCut">bean>
<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
编写切面类
package com.zhangcl.diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* 使用注解方式使用AOP
*/
@Aspect // 标识此类为切面类
public class AnnotationPointCut {
@Before("execution(* com.zhangcl.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("注解使用: 方法执行之前");
}
/*这里我还测试了切入点定位到接口 结果一样*/
@After("execution(* com.zhangcl.service.UserService.*(..))")
public void after(){
System.out.println("注解使用: 方式执行之后!");
}
/*环绕增强中可以给定一个参数, 代表我们要获取处理切入的点
* 理解:*/
@Around("execution(* com.zhangcl.service.UserService.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("注解: 方法执行环绕前");
// 执行方法
Object proceed = jp.proceed();
System.out.println("注解: 方法执行环绕之后");
System.out.println("#####################################");
System.out.println("签名:" + jp.getSignature()); // 获得类的信息
System.out.println("proceed:" + proceed);
// /*
打印结果
// 注解: 方法执行环绕前
// 注解使用: 方法执行之前
// 增加了一个User
// 注解: 方法执行环绕之后
// 签名:int com.zhangcl.service.UserService.add()
// proceed:1
// 注解使用: 方式执行之后! // 他怎么跑最后的最后了? 是不是说明around整个优先级太高了
// */
}
}
测试, 还是之前的测试类
在applicationContext.xml
<!--开启注解支持!-->
<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>
line 2: proxy-target-class="false"
, false或者不写, 则默认开启JDK代理, 如果true
, 开启cglib
步骤:
导入jar包
<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">
<parent>
<artifactId>spring-studyartifactId>
<groupId>com.zhangclgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>spring-09-mybatisartifactId>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.2version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.1.9.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.1.9.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.8.13version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.2version>
dependency>
dependencies>
project>
编写配置文件
<configuration>
<typeAliases>
<package name="com.zhangcl.pojo"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.159.128:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="Ms_910613"/>
dataSource>
environment>
environments>
<mappers>
<mapper class="com.zhangcl.mapper.UserMapper"/>
mappers>
configuration>
接口
package com.zhangcl.mapper;
import com.zhangcl.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> selectUser();
}
Mapper.xml文件
<mapper namespace="com.zhangcl.mapper.UserMapper">
<select id="selectUser" resultType="User">
select * from user
select>
mapper>
先测试一下
import com.zhangcl.mapper.UserMapper;
import com.zhangcl.pojo.User;
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 org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyTest {
@Test
public void test() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sessionFactory.openSession(true); // 自动commit
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.selectUser();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
}
配置文件:
mybatis-config.xml
<configuration>
<typeAliases>
<package name="com.zhangcl.pojo"/>
typeAliases>
configuration>
spring-dao.xml
<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 id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver">property>
<property name="url" value="jdbc:mysql://192.168.159.128:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8">property>
<property name="username" value="root">property>
<property name="password" value="Ms_910613">property>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource">property>
<property name="configLocation" value="classpath:mybatis-config.xml">property>
<property name="mapperLocations" value="classpath:com/zhangcl/mapper/*.xml">property>
bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
bean>
beans>
applicationContext.xml
<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">
<import resource="classpath:spring-dao.xml">import>
<bean id="userMapper" class="com.zhangcl.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSessionTemplate">property>
bean>
beans>
实现接口: UserMapperImpl.java, 获取并调用sqlSessionTemplate对象
package com.zhangcl.mapper;
import com.zhangcl.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
/**
* 所有操作都使用sqlSession来执行, 也就是sqlSessionTemplate
*/
public class UserMapperImpl implements UserMapper {
private SqlSessionTemplate sqlSession;
// setter
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
public List<User> getUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.getUser();
return users;
}
}
测试
import com.zhangcl.mapper.UserMapper;
import com.zhangcl.pojo.User;
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 org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class MyTest {
@Test
public void test() throws IOException {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
List<User> users = userMapper.getUser();
for (User user : users) {
System.out.println(user);
}
}
}
官网新版本,通过SqlSessionDaoSupport
获取sqlSession
通过继承这个类, 可获取sqlSession对象: UserMapperImpl.java
package com.zhangcl.mapper;
import com.zhangcl.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
public List<User> getUser() {
SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.getUser();
return users;
}
}
注册给Spring. 需要注意注入的SqlSessionFactory
是父类SqlSessionDaoSupport
所需要的, 官网的示例要求
<bean id="userMapper2" class="com.zhangcl.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory">property>
bean>
测试, 稍微改动原来的测试类即可
UserMapper userMapper = context.getBean("userMapper2", UserMapper.class);
还可以考虑MyBatisPlus或通用Mapper
事务: 都成功或都失败
"ACID原则": 原子性 | 一致性 | 隔离性 | 永久性
编程式事务对业务代码有侵犯, 轻易不考虑, 我们主要考虑声明式事务
为什么要配置事务?
开启事务: spring-dao.xml, 按照官网文档, 但之后织入用的是秦老师自创的AOP织入.
文件头4 9 10引入约束, 35行配置事务
<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:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver">property>
<property name="url" value="jdbc:mysql://192.168.159.128:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8">property>
<property name="username" value="root">property>
<property name="password" value="Ms_910613">property>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource">property>
<property name="configLocation" value="classpath:mybatis-config.xml">property>
<property name="mapperLocations" value="classpath:com/zhangcl/mapper/*.xml">property>
bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource">property>
bean>
beans>
使用AOP织入: 同文件中
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete"/>
<tx:method name="update"/>
<tx:method name="query"/>
<tx:method name="*" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="txPointCut" expression="execution(* com.zhangcl.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut">aop:advisor>
aop:config>
了解, 一般不需要改动.
声明式事务中, 配置切面时会用到propagation: 打算对这些方法怎样使用事务? 用还是不用
Spring 中 propagation 有7种配置:
将影响数据存储, 必须根据情况慎重选择
用REQUIRED和NESTED是确保事务正常存在的, 是比较谨慎的选择