Spring笔记

一、Spring框架

1.三层体系架构

在实际开发中,通常服务器端在采用分层方式进行架构。
三层体系架构,分别为:
表示层(Web层,包括控制层,使用SpringMVC框架)、
业务逻辑层(Service,使用Spring框架)、
持久层(数据访问层,Dao,使用Mybatis框架)。
Spring对每一层都提供了技术支持。

2.Spring的核心

Spring的核心是控制反转(IoC: Inverse of Control )和面向切面编程(AOP: Aspect Oriented Programming )。
在使用Spring框架之后,对象的实例不再由调用者来创建,而是由Spring容器来创建,Spring容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。

IoC的全称是Inversion of Control,中文名称为控制反转。控制反转就是指在使用Spring框架之后,对象的实例不再由调用者来创建,而是由Spring容器来创建,Spring容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。这样,控制权由应用代码转移到了Spring容器,控制权发生了反转。

DI的全称是Dependency Injection,中文称之为依赖注入。它与控制反转(IoC)的含义相同,只不过这两个称呼是从两个角度描述的同一个概念。从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,这相当于为调用者注入了它依赖的实例,这就是Spring的依赖注入。

3.Spring 的Bean中主要的装配方式

Spring 的Bean中主要包含三种装配方式,分别为基于XML的装配,基于Annotation的装配和自动装配,这三种装配方式的用法如下:

(1)基于XML的装配:

Spring提供了2种基于XML的装配方式:设值注入(Setter Injection)和构造注入(Constructor Injection)。
一种是属性setter方法注入(或设值注入),另一种是构造方法注入。属性setter方法注入是指IoC容器使用setter方法来注入被依赖的实例。通过调用无参构造器或无参静态工厂方法实例化Bean后,调用该Bean的setter方法,即可实现基于setter方法的依赖注入。属性setter方法注入的必备条件如下:

Bean类必须有一个无参构造方法

Bean类必须为属性提供setter方法

在配置文件中,使用<property>元素来为每个属性注入值

设置注入中的Bean类必须提供一个默认的无参构造方法,同时必须为需要注入的属性提供对应的setter方法。使用设值注入时,在Spring配置文件中,需要使用<bean>元素的子元素<property>来为每个属性注入值。使用构造注入时,在配置文件里,需要使用<bean>元素的子元素<constructor-arg>来定义构造方法的参数,可以使用其value属性(或子元素)来设置该参数的值。
构造方法注入是指IoC容器使用构造方法来注入被依赖的实例。基于构造方法的依赖注入通过调用带参数的构造方法来实现,每个参数代表着一个依赖。要求必须满足如下条件:

Bean类必须提供有参构造方法

配置文件中,使用<constructor-arg>元素来为参数注入值

(2)基于Annotation的装配:

使用基于Annotation的装配时,首先需要使用@Repository、@Service与@Controller分别对实现类进行标注,然后用@Autowired或@Resource注解对注入的Bean的属性进行标注,最后在Spring的配置文件中,通过<context:annotation-config />来开启注解处理器,或使用<context:component-scan base-package="Bean所在的包路径"/>的配置方式即可实现Annotation的装配。

@Controller通常作用在控制层,用于将控制层的类标识为Spring中的Bean。

@Service通常作用在业务层,用于将业务层的类标识为Spring中的Bean。

@Repository通常作用在数据持久层(或数据访问层,DAO层),用于将数据持久层的类标识为Spring中的Bean。

@Autowired或@Resource注解对注入的Bean的属性进行标注,用于将实例化后对象注入到Bean的属性中,实现依赖注入。

(3)自动装配:

<bean>元素中使用 autowire属性,并将其属性值设置为 byName或者 byType即可实现自动装配。

4.Spring框架的优点如下:

(1)非侵入式设计:Spring是一种非侵入式(non-invasive)框架,它可以使应用程序代码对框架的依赖最小化。
(2)方便解耦、简化开发:Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护工作都交给Spring容器管理,大大的降低了组件之间的耦合性。
(3)支持AOP:Spring提供了对AOP的支持,它允许将一些通用任务,如安全、事务、日志等进行集中式处理,从而提高了程序的复用性。
(4)支持声明式事务处理:只需要通过配置就可以完成对事务的管理,而无需手动编程。
(5)方便程序的测试:Spring提供了对Junit4的支持,可以通过注解方便的测试Spring程序。
(6)方便集成各种优秀框架:Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持。
(7)降低了Java EE API的使用难度:Spring对Java EE开发中非常难用的一些API(如:JDBC、JavaMail等),都提供了封装,使这些API应用难度大大降低。

5.Spring框架包:

Spring开发所需的jar包分为两个部分: Spring框架4个核心基础包和一个第三方依赖包。

spring-core-4.3.6.RELEASE.jar
包含Spring框架的核心工具类,Spring其它组件都要用到这个包里的类。

spring-beans-4.3.6.RELEASE.jar
所有应用都要用到的JAR包,它包含访问配置文件、创建和管理Bean以及进行控制反转或者依赖注入操作相关的所有类。

spring-context-4.3.6.RELEASE.jar
提供了在基础IoC功能上的扩展服务,还提供了许多企业级服务的支持

spring-expression-4.3.6.RELEASE.jar
定义了Spring的表达式语言。

在使用Spring开发时,除了要使用自带的JAR包外,Spring的核心容器还需要依赖一个第三方包commons.logging的JAR包。

6.ApplicationContext容器

通常在Java项目中,通常会通过ClassPathXmlApplicationContext类来实例化ApplicationContext容器的方式,而在Web项目中,ApplicationContext容器的实例化工作会交由Web服务器来完成。

7.SpringIOC应用示例核心代码:

main方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {

public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");

UserService userService = (UserService) context.getBean("userService");
User user = new User();
user.setId("11111");
user.setName("zhangsan22222");
userService.addUser(user);
}

}

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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-3.0.xsd">
<!--配置bean,配置后该类由spring管理-->
<bean id="userService" class="spring.ioc.service.UserService">
<!--依赖注入,配置当前类中相应的属性-->
<!-- <property>标签中的name就是UserService类中的userDao属性名,ref指下面<bean name="userDao"...>,这样其实是spring将UserDaoImp对象实例化并且调用UserService的setUserDao方法将UserDao注入 -->
<property name="userDao" ref="userDaoImp"></property>
</bean>
<!—配置bean ,,配置后该类由spring管理-->
<bean id="userDaoImp" class="spring.ioc.dao.imp.UserDaoImp"></bean>

</beans>

UserService.java

1
2
3
4
5
6
7
8
9
10
11
12
public class UserService {
public UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void addUser(User user){
userDao.addUser(user);
}
}

UserDaoImp.java

1
2
3
4
5
6
public class UserDaoImp implements UserDao{
public void addUser(User user){
System.out.println("添加了一个用户,姓名是"
+user.getName()+user.getId());
}
}

二、SpringJDBCTemplate

1.在Spring的配置文件中配置JDBC

在Spring的配置文件中配置JDBC时,需要定义了三个Bean,分别是dataSource、jdbcTemplate和需要注入类的Bean。在定义jdbcTemplate时,需要将dataSource注入到jdbcTemplate中,而其他需要使用jdbcTemplate的Bean,也需要将jdbcTemplate注入到该Bean中,这样配置完成后,Spring JDBC就可以使用了。

2.JdbcTemplate类

Spring框架提供了JdbcTemplate类,该类是Spring框架数据抽象层的基础。JdbcTemplate类是Spring JDBC的核心类。JdbcTemplate的直接父类是抽象类JdbcAccessor,实现了接口JdbcOperations。
在JdbcTemplate类中,提供了大量的更新和查询数据库的方法,使用这些方法来操作数据库,其常用的方法包括execute()、update()和query()。
其中execute()方法能够完成执行SQL语句的功能,update()方法可以完成插入、更新和删除数据的操作,query()方法可以用来处理各种对数据库表的查询操作。

3.dataSource配置

dataSource配置,即JDBC连接数据库时需要4个基本属性,包括有driverClassName、url、username和password。

4.Spring 为JDBC提供了三个模板类供选择:

JdbcTemplate:最基本的Spring JDBC模板,支持简单的JDBC数据访问功能及基于索引参数的查询。使用占位符(?)绑定参数。

NamedParameterJdbcTemplate:该模板查询时可以将值以命名参数(:参数名)的形式绑定到SQL中,而不是使用简单的索引参数。

SimpleJdbcTemplate:该模板利用Java5的一些特性如自动装箱、泛型以及可变参数列表来简化JDBC模板的使用。

5.SpringJDBCTemplate应用示例核心代码:

Main方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
    public static void main( String[] args ){
Test test = new Test();
UserAction userAction = test.getController();
test.testAdd(userAction);
// test.testFindNumbers(userAction);
// test.testFindNameById(userAction);
// test.testFindUser(userAction);
// test.testFindAll(userAction);
// test.testFindMapUser(userAction);
// test.testFindMapAll(userAction);
}
public UserAction getController(){
ApplicationContext context =
new ClassPathXmlApplicationContext("config/applicationContext.xml");
UserAction userAction = (UserAction) context.getBean("userAction");
return userAction;
}

public void testAdd(UserAction userAction){
User user =new User();
user.setId(7);
user.setName("张三");
user.setAge(20);
userAction.add(user);
}

public void testFindNumbers(UserAction userAction){
int numbers = userAction.findNumbers();
System.out.println("findNumbers方法的查询结果:");
System.out.println("共有"+numbers+"个用户!");
}

public void testFindNameById(UserAction userAction){
String name = userAction.findNameById(1);
System.out.println("findNameById方法的查询结果:");
System.out.println("学号为1的学生的姓名为:"+name);
}

public void testFindUser(UserAction userAction){
System.out.println("findUser方法的查询结果:");
User user = userAction.findById(1);
System.out.println("id:"+user.getId()
+",name:"+user.getName()
+",age:"+user.getAge());
}

public void testFindAll(UserAction userAction){
List<User> users = userAction.findAll();
System.out.println("findAll方法的查询结果:");
for(User user:users){
System.out.println("id:"+user.getId()
+",name:"+user.getName()
+",age:"+user.getAge());
}
}

public void testFindMapUser(UserAction userAction){
System.out.println("findMapUser方法的查询结果:");
Map<String,Object> user = userAction.findMapById(1);
System.out.println("id:"+user.get("id")
+",name:"+user.get("name")
+",age:"+user.get("age"));
}

public void testFindMapAll(UserAction userAction){
System.out.println("findMapAll方法的查询结果:");
List<Map<String,Object>> users = userAction.findAllMap();
for(Map<String,Object> user:users){
System.out.println("id:"+user.get("id")
+",name:"+user.get("name")
+",age:"+user.get("age"));
}
}
}

applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<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-3.0.xsd">

<bean id="userAction" class="action.UserAction">
<property name="userService" ref="userService" />
</bean>

<bean id="userService" class="service.UserService">
<property name="userDao" ref="userDao" />
</bean>
<bean id="dataSource1"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">

<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/spring" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean id="userDao" class="dao.UserDao">
<property name="jdbcTemplate" ref="jdbcTemplate1" />
<property name="npjt" ref="namedParameterJdbcTemplate" />
</bean>
<bean id="jdbcTemplate1" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource1" >
</property>
</bean>
<!-- NamedParameterJdbcTemplate配置 -->
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="jdbcTemplate1" />
</bean>

</beans>

UserAction.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class UserAction {
private UserService userService;

public UserService getUserService() {
return userService;
}

public void setUserService(UserService userService) {
this.userService = userService;
}

public void add(User user) {
userService.add(user);
}

public String findNameById(int id) {
return userService.findNameById(id);
}

public int findNumbers() {
return userService.findNumbers();
}

public List<User> findAll() {
return userService.findAll();
}

public User findById(int id) {
return userService.findById(id);
}

public Map<String, Object> findMapById(int id) {
return userService.findMapById(id);
}

public List<Map<String, Object>> findAllMap() {
return userService.findAllMap();
}
}

UserService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class UserService {
private UserDao userDao;

public UserDao getUserDao() {
return userDao;
}

public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}

public void add(User user) {
userDao.add(user);
}

public String findNameById(int id) {
return userDao.findNameById(id);
}

public int findNumbers() {
return userDao.findNumbers();
}

public List<User> findAll() {
return userDao.findAll();
}

public User findById(int id) {
return userDao.findById(id);
}

public Map<String, Object> findMapById(int id) {
return userDao.findMapById(id);
}

public List<Map<String, Object>> findAllMap() {
return userDao.findAllMap();
}
}

UserDao.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public class UserDao {
private JdbcTemplate jdbcTemplate;

private NamedParameterJdbcTemplate npjt;

public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}

public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public NamedParameterJdbcTemplate getNpjt() {
return npjt;
}

public void setNpjt(NamedParameterJdbcTemplate npjt) {
this.npjt = npjt;
}

public void add(User user){
String sql = "insert into CUSTOMERS values(?,?,?)";
jdbcTemplate.update(sql,
new Object[]{user.getId(),user.getName(),user.getAge()});

/*NamedParameterJdbcTemplate使用:Map传参*/
String sql1="insert into CUSTOMERS (id,name,age) values (:id,:name,:age)";
Map<String,Object> paramMap=new HashMap<String,Object>();
paramMap.put("id", 1);
paramMap.put("age", "20");
paramMap.put("name", "npjt");
paramMap.put("sex", "女");
npjt.update(sql1, paramMap);

/*NamedParameterJdbcTemplate使用:实体类(User)传参*/
SqlParameterSource paramSource=new BeanPropertySqlParameterSource(user);
npjt.update(sql1, paramSource);
}

public String findNameById(int id) {
String sql = "SELECT NAME FROM CUSTOMERS WHERE id = ?";
String name = (String) jdbcTemplate.queryForObject(sql, new Object[] { id }, String.class);
return name;
}

public int findNumbers() {
String sql = "SELECT COUNT(*) FROM CUSTOMERS";
int total = jdbcTemplate.queryForObject(sql,Integer.class);
return total;
}

public List<User> findAll() {
String sql = "SELECT * FROM CUSTOMERS";
//List<Customer> customers = jdbcTemplate.query(sql, new BeanPropertyRowMapper(Customer.class));
List<User> customers = jdbcTemplate.query(sql, new CustomerRowMapper());
return customers;
}

public User findById(int id) {
String sql = "SELECT * FROM CUSTOMERS WHERE id = ?";
User customer = (User) jdbcTemplate.queryForObject(sql,
new Object[] { id },new CustomerRowMapper());
return customer;
}

public Map<String,Object> findMapById(int id){
String sql = "SELECT * FROM CUSTOMERS WHERE id = ?";
return jdbcTemplate.queryForMap(sql,new Object[]{id});
}

public List<Map<String,Object>> findAllMap(){
String sql = "SELECT * FROM CUSTOMERS";
return jdbcTemplate.queryForList(sql);
}
}

三、SpringAOP和事务控制

1.AOP(Aspect-Oriented Programming,面向切面编程):

是Spring用到的核心技术之一,是对传统 OOP(Object-Oriented Programming,面向对象编程)的补充。

AOP在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等。

AOP的主要编程对象是切面(aspect),采用AOP,可以对分散在各处且与对象核心功能无关的一些功能行为代码(横切代码)进行封装,使其成为一个可重用的模块,这个模块被命名为“切面”(Aspect),切面将那些与业务无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。

2.AOP框架:Spring AOP和AspectJ。

目前流行的AOP框架有两个:Spring AOP和AspectJ

Spring AOP代理可以是JDK动态代理,也可是CGLIB代理。Spring默认使用JDK动态代理,在需要代理类而不是代理接口的时候,Spring会自动切换为使用CGLIB代理,不过现在的项目都是面向接口编程,所以JDK动态代理相对来说用的还是多一些。

新版本的Spring框架,建议使用AspectJ来开发AOP。 使用AspectJ实现AOP有两种方式:一种是基于XML的声明式AspectJ,另一种是基于注解的声明式AspectJ。

3.AspectJ框架中注解

AspectJ框架中注解@Pointcut用于定义切入点表达式,在使用时还需定义一个包含名字和任意参数的方法签名来表示切入点名称。

4.Spring的配置文件中的<beans>元素

在Spring的配置文件中的<beans>元素下可以包含多个<aop:config>元素,一个<aop:config>元素中又可以包含属性和子元素,其子元素包括<aop:pointcut><aop:advisor><aop:aspect>

配置切面使用的是<aop:aspect>元素,<aop:aspect>子元素的pointcut-ref属性用于指定一个已经存在的切入点名称。

5.AOP术语中Advice

AOP术语中Advice表示AOP框架在特定的切入点执行的通知/增强处理,即在定义好的切入点处所要执行的程序代码。

6.Spring的声明式事务管理的两种实现方式

Spring的声明式事务管理可以通过两种方式来实现,一种是基于XML的方式,另一种是基于注解(Annotation)的方式。

Spring2.0以后,在基于XML文件的方式中,提供了tx命名空间来配置事务,tx命名空间下提供了tx:advice元素来配置事务的通知(增强处理)。

四、Spring整合Mybatis

6.1 Spring整合Mybatis思路分析

6.1.1 环境准备

在准备环境的过程中,我们也来回顾下Mybatis开发的相关内容:

步骤1:准备数据库表

Mybatis是来操作数据库表,所以先创建一个数据库及表

1
2
3
4
5
6
7
create database spring_db character set utf8;
use spring_db;
create table tbl_account(
id int primary key auto_increment,
name varchar(35),
money double
);
步骤2:创建项目导入jar包

项目的pom.xml添加相关依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
步骤3:根据表创建模型类
1
2
3
4
5
6
7
public class Account implements Serializable {

private Integer id;
private String name;
private Double money;
//setter...getter...toString...方法略
}
步骤4:创建Dao接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface AccountDao {

@Insert("insert into tbl_account(name,money)values(#{name},#{money})")
void save(Account account);

@Delete("delete from tbl_account where id = #{id} ")
void delete(Integer id);

@Update("update tbl_account set name = #{name} , money = #{money} where id = #{id} ")
void update(Account account);

@Select("select * from tbl_account")
List<Account> findAll();

@Select("select * from tbl_account where id = #{id} ")
Account findById(Integer id);
}
步骤5:创建Service接口和实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public interface AccountService {

void save(Account account);

void delete(Integer id);

void update(Account account);

List<Account> findAll();

Account findById(Integer id);

}

@Service
public class AccountServiceImpl implements AccountService {

@Autowired
private AccountDao accountDao;

public void save(Account account) {
accountDao.save(account);
}

public void update(Account account){
accountDao.update(account);
}

public void delete(Integer id) {
accountDao.delete(id);
}

public Account findById(Integer id) {
return accountDao.findById(id);
}

public List<Account> findAll() {
return accountDao.findAll();
}
}
步骤6:添加jdbc.properties文件

resources目录下添加,用于配置数据库连接四要素

1
2
3
4
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
jdbc.username=root
jdbc.password=root

useSSL:关闭MySQL的SSL连接

步骤7:添加Mybatis核心配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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>
<!--读取外部properties配置文件-->
<properties resource="jdbc.properties"></properties>
<!--别名扫描的包路径-->
<typeAliases>
<package name="com.itheima.domain"/>
</typeAliases>
<!--数据源-->
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" 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>
</dataSource>
</environment>
</environments>
<!--映射文件扫描包路径-->
<mappers>
<package name="com.itheima.dao"></package>
</mappers>
</configuration>
步骤8:编写应用程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class App {
public static void main(String[] args) throws IOException {
// 1. 创建SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 2. 加载SqlMapConfig.xml配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml.bak");
// 3. 创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
// 4. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 5. 执行SqlSession对象执行查询,获取结果User
AccountDao accountDao = sqlSession.getMapper(AccountDao.class);

Account ac = accountDao.findById(1);
System.out.println(ac);

// 6. 释放资源
sqlSession.close();
}
}
步骤9:运行程序

1630136904087

6.1.2 整合思路分析

Mybatis的基础环境我们已经准备好了,接下来就得分析下在上述的内容中,哪些对象可以交给Spring来管理?

  • Mybatis程序核心对象分析

    1630137189480

    从图中可以获取到,真正需要交给Spring管理的是==SqlSessionFactory==

  • 整合Mybatis,就是将Mybatis用到的内容交给Spring管理,分析下配置文件

    1630137388717

    说明:

    • 第一行读取外部properties配置文件,Spring有提供具体的解决方案@PropertySource,需要交给Spring
    • 第二行起别名包扫描,为SqlSessionFactory服务的,需要交给Spring
    • 第三行主要用于做连接池,Spring之前我们已经整合了Druid连接池,这块也需要交给Spring
    • 前面三行一起都是为了创建SqlSession对象用的,那么用Spring管理SqlSession对象吗?回忆下SqlSession是由SqlSessionFactory创建出来的,所以只需要将SqlSessionFactory交给Spring管理即可。
    • 第四行是Mapper接口和映射文件[如果使用注解就没有该映射文件],这个是在获取到SqlSession以后执行具体操作的时候用,所以它和SqlSessionFactory创建的时机都不在同一个时间,可能需要单独管理。

6.2 Spring整合Mybatis

前面我们已经分析了Spring与Mybatis的整合,大体需要做两件事,

第一件事是:Spring要管理MyBatis中的SqlSessionFactory

第二件事是:Spring要管理Mapper接口的扫描

具体该如何实现,具体的步骤为:

步骤1:项目中导入整合需要的jar包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
<!--Spring操作数据库需要该jar包-->
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<dependency>
<!--
Spring与Mybatis整合的jar包
这个jar包mybatis在前面,是Mybatis提供的
-->
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>

步骤2:创建Spring的主配置类

1
2
3
4
5
6
7
//配置类注解
@Configuration
//包扫描,主要扫描的是项目中的AccountServiceImpl类
@ComponentScan("com.itheima")
public class SpringConfig {
}

步骤3:创建数据源的配置类

在配置类中完成数据源的创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String userName;
@Value("${jdbc.password}")
private String password;

@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}

步骤4:主配置类中读properties并引入数据源配置类

1
2
3
4
5
6
7
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import(JdbcConfig.class)
public class SpringConfig {
}

步骤5:创建Mybatis配置类并配置SqlSessionFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MybatisConfig {
//定义bean,SqlSessionFactoryBean,用于产生SqlSessionFactory对象
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
//设置模型类的别名扫描
ssfb.setTypeAliasesPackage("com.itheima.domain");
//设置数据源
ssfb.setDataSource(dataSource);
return ssfb;
}
//定义bean,返回MapperScannerConfigurer对象
@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
msc.setBasePackage("com.itheima.dao");
return msc;
}
}

说明:

  • 使用SqlSessionFactoryBean封装SqlSessionFactory需要的环境信息

    1630138835057

    • SqlSessionFactoryBean是前面我们讲解FactoryBean的一个子类,在该类中将SqlSessionFactory的创建进行了封装,简化对象的创建,我们只需要将其需要的内容设置即可。
    • 方法中有一个参数为dataSource,当前Spring容器中已经创建了Druid数据源,类型刚好是DataSource类型,此时在初始化SqlSessionFactoryBean这个对象的时候,发现需要使用DataSource对象,而容器中刚好有这么一个对象,就自动加载了DruidDataSource对象。
  • 使用MapperScannerConfigurer加载Dao接口,创建代理对象保存到IOC容器中

    1630138916939

    • 这个MapperScannerConfigurer对象也是MyBatis提供的专用于整合的jar包中的类,用来处理原始配置文件中的mappers相关配置,加载数据层的Mapper接口类
    • MapperScannerConfigurer有一个核心属性basePackage,就是用来设置所扫描的包路径

步骤6:主配置类中引入Mybatis配置类

1
2
3
4
5
6
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}

步骤7:编写运行类

在运行类中,从IOC容器中获取Service对象,调用方法获取结果

1
2
3
4
5
6
7
8
9
10
11
public class App2 {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

AccountService accountService = ctx.getBean(AccountService.class);

Account ac = accountService.findById(1);
System.out.println(ac);
}
}

步骤8:运行程序

1630139036627

支持Spring与Mybatis的整合就已经完成了,其中主要用到的两个类分别是:

  • ==SqlSessionFactoryBean==
  • ==MapperScannerConfigurer==