前言

本文概括

  • 掌握IOC/DI配置管理第三方bean
  • 掌握IOC/DI的注解开发
  • 掌握IOC/DI注解管理第三方bean
  • 完成Spring与Mybatis及Junit的整合开发

SSM学习目录

  1. Spring(一)-SSM框架(了解即可(๑・̀ㅂ・́)و✧ ) 点击我查看
  2. Spring(二)-SSM框架(了解即可ヾ (≧▽≦*) o) 点击我查看(当前位置)
  3. Spring(三)-SSM框架(了解即可(^▽^)) 点击我查看
  4. SpringMVC-SSM框架(~(〃∀`)ノ) 点击我查看

IOC/DI配置管理第三方bean

我们先在演示一下管理我们之前提过的Druid(德鲁伊)数据源池的配置

环境准备

查看代码

1.pom.xml添加依赖

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>

2.resources下添加spring的配置文件applicationContext.xml

1
2
3
4
5
6
7
8
<?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">

</beans>

编写一个运行类App

1
2
3
4
5
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}

思路分析

需求:使用Spring的IOC容器来管理Druid连接池对象
1.使用第三方的技术,需要在pom.xml添加依赖
2.在配置文件中将【第三方的类】制作成一个bean,让IOC容器
3.数据库连接需要基础的四要素驱动连接用户名密码,【如何注入】到对应的bean中
4.从IOC容器中获取对应的bean对象,将其打印到控制台查看结果

代码实现

查看代码

步骤1:导入druid的依赖(在pom.xml中添加依赖)

1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>

步骤2:配置第三方bean
在applicationContext.xml配置文件中添加DruidDataSource的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>

``` xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--管理DruidDataSource对象-->
<bean class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring_db"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
</beans>

说明:

  • driverClassName:数据库驱动
  • url:数据库连接地址
  • username:数据库连接用户名
  • password:数据库连接密码
  • 数据库连接的四要素要和自己使用的数据库信息一致。

步骤3:从IOC容器中获取对应的bean对象

1
2
3
4
5
6
7
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource = (DataSource) ctx.getBean("dataSource");
System.out.println(dataSource);
}
}

加载properties文件

在上面我们已经完成了druid的配置,但包含一些问题:

  • 这个数据源中都使用到了一些固定的常量如数据库连接四要素,把这些值写在Spring的配置文件中不利于后期维护
  • 需要将这些值提取到一个外部的properties配置文件中
  • Spring框架如何从配置文件中读取属性值来配置就是接下来要解决的问题。

第三方bean属性优化

需求:将数据库连接四要素提取到properties配置文件,spring来加载配置信息并使用这些信息来完成属性注入。
1.在resources下创建一个jdbc.properties(文件的名称可以任意)
2.将数据库连接四要素配置到配置文件中
3.在Spring的配置文件中加载properties文件
4.使用加载到的值实现属性注入

步骤1:准备properties配置文件
resources下创建一个jdbc.properties文件,并添加对应的属性键值对

1
2
3
4
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root

步骤2:开启context命名空间
在applicationContext.xml中开context命名空间

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
</beans>

步骤3:加载properties配置文件
在配置文件中使用context命名空间下的标签来加载properties配置文件

1
<context:property-placeholder location="jdbc.properties"/>

步骤4:完成属性注入
使用${key}来读取properties配置文件中的内容并完成属性注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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">

<context:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>

至此,读取外部properties配置文件中的内容就已经完成

读取单个属性

需求:从properties配置文件中读取key为name的值,并将其注入到BookDao中并在save方法中进行打印。
1.在项目中添加BookDao和BookDaoImpl类
2.为BookDaoImpl添加一个name属性并提供setter方法
3.在jdbc.properties中添加数据注入到bookDao中打印方便查询结果
4.在applicationContext.xml添加配置完成配置文件加载、属性注入(${key})

步骤1:在项目中添对应的类
BookDao和BookDaoImpl类,并在BookDaoImpl类中添加name属性与setter方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface BookDao {
public void save();
}

public class BookDaoImpl implements BookDao {
private String name;

public void setName(String name) {
this.name = name;
}

public void save() {
System.out.println("book dao save ..." + name);
}
}

步骤2:完成配置文件的读取与注入
在applicationContext.xml添加配置,bean的配置管理读取外部properties依赖注入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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">

<context:property-placeholder location="jdbc.properties"/>

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<property name="name" value="${jdbc.driver}"/>
</bean>
</beans>

注意事项
至此,读取properties配置文件中的内容就已经完成,但是在使用的时候,有些注意事项:

  • 问题一:键值对的key为username引发的问题

    1.在properties中配置键值对的时候,如果key设置为username

    1
    username=root666

    2.在applicationContext.xml注入该属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?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">

    <context:property-placeholder location="jdbc.properties"/>

    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
    <property name="name" value="${username}"/>
    </bean>
    </beans>

    3.运行测试类,发现控制台打印的不是root666而是自己的电脑用户名
    4.出现问题的原因是<context:property-placeholder/>标签会加载系统的环境变量,而且环境变量的值会被优先加载,如何查看系统的环境变量?
    大家可以自行运行,在打印出来的结果中会有一个USERNAME=XXX[自己电脑的用户名称]
    5.解决问题的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <?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">

    <context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
    </beans>

    system-properties-mode:设置为NEVER,表示不加载系统属性,就可以解决上述问题。当然还有一个解决方案就是避免使用username作为属性的key

  • 问题二:当有多个properties配置文件需要被加载,该如何配置?
    1.调整下配置文件的内容,在resources下添加jdbc.properties,jdbc2.properties,内容如下:jdbc.properties

    1
    2
    3
    4
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
    jdbc.username=root
    jdbc.password=root

    jdbc2.properties

    1
    2
    3
    4
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
    jdbc.username=root
    jdbc.password=root

    2.修改applicationContext.xml配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <?xml version="1.0" encoding="UTF-8"?>
    配置文件
    ``` 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"
    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,jdbc2.properties" system-properties-mode="NEVER"/>
    <!--方式二-->
    <context:property-placeholder location="*.properties" system-properties-mode="NEVER"/>
    <!--方式三 -->
    <context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
    <!--方式四-->
    <context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
    </beans>

核心容器

前面已经完成bean与依赖注入的相关知识学习,接下来我们主要学习的是IOC容器中的核心容器
这里所说的核心容器,大家可以把它简单的理解为ApplicationContext,前面虽然已经用到过,但是并没有系统的学习,接下来咱们从以下几个问题入手来学习下容器的相关知识:

如何创建容器?
创建好容器后,如何从容器中获取bean对象?
容器类的层次结构是什么?
BeanFactory是什么?

环境准备

查看代码

1.在项目中创建一个dao包,在包下创建BookDaoBookDaoImpl
创建一个Maven项目,pom.xml添加Spring的依赖

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>

resources下添加spring的配置文件applicationContext.xml

1
2
3
4
5
6
7
<?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">
</beans>

添加BookDao和BookDaoImpl类

1
2
3
4
5
6
7
8
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ..." );
}
}

创建运行类App

1
2
3
4
5
6
7
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}

容器

如何创建容器

案例中创建ApplicationContext的方式为:

1
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

除了上面这种方式,Spring还提供了另外一种创建方式为:

1
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace\\spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml");

两种方式的区别:

  • ClassPathXmlApplicationContext:加载类路径下的配置文件,加载的配置文件必须在类路径下
  • FileSystemXmlApplicationContext:加载磁盘路径下的配置文件,加载的配置文件可以在磁盘的任意位置

如何从容器中获取bean对象

方式一,就是目前案例中获取的方式:通过id来获取bean对象

1
BookDao bookDao = (BookDao) ctx.getBean("bookDao");

方式二,使用idclass来获取bean对象:

1
BookDao bookDao = ctx.getBean("bookDao",BookDao.class);   

方式三,使用Class对象来获取bean对象(推荐):

1
BookDao bookDao = ctx.getBean(BookDao.class);

BeanFactory的使用

BeanFactory是Spring框架中最基本的容器接口,它提供了一种管理和获取bean对象的方式。
使用BeanFactory来创建IOC容器的具体实现方式为:

1
2
3
4
5
6
7
8
public class AppForBeanFactory {
public static void main(String[] args) {
Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resources);
BookDao bookDao = bf.getBean(BookDao.class);
bookDao.save();
}
}

为了更好的看出BeanFactoryApplicationContext之间的区别,在BookDaoImpl添加如下构造函数:

1
2
3
4
5
6
7
8
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("constructor");
}
public void save() {
System.out.println("book dao save ..." );
}
}

如果不去获取bean对象,打印会发现:

  • BeanFactory是延迟加载,只有在获取bean对象的时候才会去创建
  • ApplicationContext是立即加载,容器加载的时候就会创建bean对象
  • ApplicationContext要想成为延迟加载,只需要按照如下方式进行配置
1
2
3
4
5
6
7
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl" lazy-init="true"/>
</beans>

小结

这一节中所讲的知识点包括:

  • 容器创建的两种方式

    • ClassPathXmlApplicationContext[掌握]
    • FileSystemXmlApplicationContext[知道即可]
  • 获取Bean的三种方式

    • getBean(“名称”):需要类型转换
    • getBean(“名称”,类型.class):多了一个参数
    • getBean(类型.class):容器中不能有多个该类的bean对象

    上述三种方式,各有各的优缺点,用哪个都可以。

  • 容器类层次结构

    • 只需要知晓容器的最上级的父接口为 BeanFactory即可
  • BeanFactory

    • 使用BeanFactory创建的容器是延迟加载
    • 使用ApplicationContext创建的容器是立即加载
    • 具体BeanFactory如何创建只需要了解即可。

IOC/DI注解开发

在前面的案例中,我们都是在配置文件中配置bean,而在实际开发中,我们更多的是使用注解来配置bean,接下来我们就来学习下IOC/DI注解开发。

环境准备

查看代码

1.pom.xml添加Spring的依赖

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>

2.resources下添加spring的配置文件applicationContext.xml

1
2
3
4
5
6
7
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
</beans>

3.添加BookDao、BookDaoImpl、BookService、BookServiceImpl类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ..." );
}
}
public interface BookService {
public void save();
}

public class BookServiceImpl implements BookService {
public void save() {
System.out.println("book service save ...");
}
}

4.创建运行类App

1
2
3
4
5
6
7
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
}
}

注解开发

在上述环境的基础上,我们来学一学Spring是如何通过注解实现bean的定义开发?
步骤1:删除原XML配置
将配置文件中的<bean>标签删除掉

1
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

步骤2:Dao上添加注解
在BookDaoImpl类上添加@Component注解

1
2
3
4
5
6
@Component("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ..." );
}
}

注意:@Component注解不可以添加在接口上,因为接口是无法创建对象的。

步骤3:配置Spring的注解包扫描
为了让Spring框架能够扫描到写在类上的注解,需要在配置文件上进行包扫描

1
2
3
4
5
6
7
<?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">
<context:component-scan base-package="com.itheima"/>
</beans>

说明:
component-scan

  • component:组件,Spring将管理的bean视作自己的一个组件
  • scan:扫描

base-package指定Spring框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解。

  • 包路径越多[如:com.itheima.dao.impl],扫描的范围越小速度越快
  • 包路径越少[如:com.itheima],扫描的范围越大速度越慢
  • 一般扫描到项目的组织名称即Maven的groupId下[如:com.itheima]即可。

步骤5:Service上添加注解
在BookServiceImpl类上也添加@Component交给Spring框架管理

1
2
3
4
5
6
7
8
9
10
11
12
13
@Component
public class BookServiceImpl implements BookService {
private BookDao bookDao;

public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}

public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}

步骤6:运行程序
在App类中,从IOC容器中获取BookServiceImpl对应的bean对象,打印

1
2
3
4
5
6
7
8
9
10
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);
//按类型获取bean
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
}

说明:

  • BookServiceImpl类没有起名称,所以在App中是按照类型来获取bean对象
  • @Component注解如果不起名称,会有一个默认值就是当前类名首字母小写,所以也可以按照名称获取,如
1
2
BookService bookService = (BookService)ctx.getBean("bookServiceImpl");
System.out.println(bookService);

对于@Component注解,还衍生出了其他三个注解@Controller@Service@Repository

  1. @Controller:处理web请求
  2. @Service:处理业务逻辑
  3. @Repository:处理数据访问
    这三个注解都是@Component的衍生注解,它们的作用都是将类交给Spring框架管理,只是在Spring框架中它们的作用不同。

纯注解开发模式

上面已经可以使用注解来配置bean,但是依然有用到配置文件,在配置文件中对包进行了扫描,Spring在3.0版已经支持纯注解开发模式,不需要配置文件了。

步骤1:创建配置类,并标识该类为配置类
创建一个配置类SpringConfig,在配置类上添加@Configuration注解,将其标识为一个配置类,替换applicationContext.xml

1
2
3
@Configuration
public class SpringConfig {
}

步骤2:用注解替换包扫描配置
在配置类上添加包扫描注解@ComponentScan替换<context:component-scan base-package=""/>

1
2
3
4
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}

步骤3:创建运行类并执行
创建一个新的运行类AppForAnnotation

1
2
3
4
5
6
7
8
9
10
public class AppForAnnotation {

public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
}

注解知识点小结

知识点1:@Configuration

名称 @Configuration
类型 类注解
位置 类定义上方
作用 设置该类为spring配置类
属性 value(默认):定义bean的id

知识点2:@ComponentScan

名称 @ComponentScan
类型 类注解
位置 类定义上方
作用 设置spring配置类扫描路径,用于加载使用注解格式定义的bean
属性 value(默认):扫描路径,此路径可以逐层向下扫描

知识点3:@Component

名称 @Component
类型 类注解
位置 类定义上方
作用 将类交给spring管理,相当于在xml配置文件中定义bean标签
属性 value(默认):定义bean的id

注解开发bean作用范围与生命周期管理

使用注解已经完成了bean的管理,接下来按照前面所学习的内容,将通过配置实现的内容都换成对应的注解实现,包含两部分内容:bean作用范围bean生命周期

环境准备

查看代码

pom.xml添加Spring的依赖

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>

添加一个配置类SpringConfig

1
2
3
4
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}

添加BookDao、BookDaoImpl类

1
2
3
4
5
6
7
8
9
public interface BookDao {
public void save();
}
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ..." );
}
}

创建运行类App

1
2
3
4
5
6
7
8
9
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao1 = ctx.getBean(BookDao.class);
BookDao bookDao2 = ctx.getBean(BookDao.class);
System.out.println(bookDao1);
System.out.println(bookDao2);
}
}

bean作用范围

(1)先运行App类,在控制台打印两个一摸一样的地址,说明默认情况下bean是单例
(2)要想将BookDaoImpl变成非单例,只需要在其类上添加@scope注解

1
2
3
4
5
6
7
8
9
@Repository
//@Scope设置bean的作用范围
@Scope("prototype")
public class BookDaoImpl implements BookDao {

public void save() {
System.out.println("book dao save ...");
}
}

(3)再次运行App类,在控制台打印两个不同的地址,说明BookDaoImpl变成了非单例

Bean的生命周期

(1)在BookDaoImpl中添加两个方法,initdestroy,方法名可以任意

1
2
3
4
5
6
7
8
9
10
11
12
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
public void init() {
System.out.println("init ...");
}
public void destroy() {
System.out.println("destroy ...");
}
}

(2)在对应的方法上添加@PostConstruct@PreDestroy注解即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
@PostConstruct //在构造方法之后执行,替换 init-method
public void init() {
System.out.println("init ...");
}
@PreDestroy //在销毁方法之前执行,替换 destroy-method
public void destroy() {
System.out.println("destroy ...");
}
}

(3)要想看到两个方法执行,需要注意的是destroy只有在容器关闭的时候,才会执行,所以需要修改App的类

1
2
3
4
5
6
7
8
9
10
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao1 = ctx.getBean(BookDao.class);
BookDao bookDao2 = ctx.getBean(BookDao.class);
System.out.println(bookDao1);
System.out.println(bookDao2);
ctx.close(); //关闭容器
}
}

注解知识点小结

知识点1:@Scope
| 名称 | @Scope |
| —— | —————————————————————————————— |
| 类型 | 类注解 |
| 位置 | 类定义上方 |
| 作用 | 设置该类创建对象的作用范围
可用于设置创建出的bean是否为单例对象 |
| 属性 | value(默认):定义bean作用范围,
==默认值singleton(单例),可选值prototype(非单例)== |

知识点2:@PostConstruct

名称 @PostConstruct
类型 方法注解
位置 方法上
作用 设置该方法为初始化方法
属性

知识点3:@PreDestroy

名称 @PreDestroy
类型 方法注解
位置 方法上
作用 设置该方法为销毁方法
属性

注解开发依赖注入

Spring为了使用注解简化开发,并没有提供构造函数注入setter注入对应的注解,只提供了自动装配的注解实现。

环境准备

查看代码

1.pom.xml添加Spring的依赖

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>

添加一个配置类SpringConfig

1
2
3
4
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}

添加BookDao、BookDaoImpl、BookService、BookServiceImpl类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface BookDao {
public void save();
}
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ..." );
}
}
public interface BookService {
public void save();
}
@Service
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}

创建运行类App

1
2
3
4
5
6
7
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookService bookService = ctx.getBean(BookService.class);
bookService.save();
}
}

注解实现按照类型注入

(1) 在BookServiceImpl类的bookDao属性上添加@Autowired注解

1
2
3
4
5
6
7
8
9
10
11
12
13
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;

// public void setBookDao(BookDao bookDao) {
// this.bookDao = bookDao;
// }
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}

注意:

  • @Autowired可以写在属性上,也可也写在setter方法上,最简单的处理方式是写在属性上并将setter方法删除掉
  • 为什么setter方法可以删除呢?
    • 自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值
    • 普通反射只能获取public修饰的内容
    • 暴力反射除了获取public修饰的内容还可以获取private修改的内容
    • 所以此处无需提供setter方法

(2)@Autowired是按照类型注入,那么对应BookDao接口如果有多个实现类,比如添加BookDaoImpl2

1
2
3
4
5
6
@Repository
public class BookDaoImpl2 implements BookDao {
public void save() {
System.out.println("book dao save ...2");
}
}

这个时候再次运行App,就会报错,此时,按照类型注入就无法区分到底注入哪个对象,解决方案:按照名称注入
先给两个Dao类分别起个名称

1
2
3
4
5
6
7
8
9
10
11
12
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ..." );
}
}
@Repository("bookDao2")
public class BookDaoImpl2 implements BookDao {
public void save() {
System.out.println("book dao save ...2" );
}
}

此时就可以注入成功了。

注解实现按照名称注入

当根据类型在容器中找到多个bean,注入参数的属性名又和容器中bean的名称不一致,这个时候该如何解决,就需要使用到@Qualifier来指定注入哪个名称的bean对象。

1
2
3
4
5
6
7
8
9
10
11
@Service
public class BookServiceImpl implements BookService {
@Autowired
@Qualifier("bookDao1")
private BookDao bookDao;

public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}

@Qualifier注解后的值就是需要注入的bean的名称。
注意:@Qualifier不能独立使用,必须和@Autowired一起使用

简单数据类型注入

引用类型看完,简单类型注入就比较容易懂了。简单类型注入的是基本数据类型或者字符串类型,下面在BookDaoImpl类中添加一个name属性,用其进行简单类型注入

1
2
3
4
5
6
7
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}

数据类型换了,对应的注解也要跟着换,这次使用@Value注解,将值写入注解的参数中就行了

1
2
3
4
5
6
7
8
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("itheima")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}

注意数据格式要匹配,如将”abc”注入给int值,这样程序就会报错。

介绍完后,会有一种感觉就是这个注解好像没什么用,跟直接赋值是一个效果,还没有直接赋值简单,所以这个注解存在的意义是什么?

注解读取properties配置文件

@Value一般会被用在从properties配置文件中读取内容进行使用,具体如何实现?
步骤1:resource下准备properties文件

1
name=itheima888

步骤2: 使用注解加载properties配置文件

在配置类上添加@PropertySource注解

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

步骤3:使用@Value读取配置文件中的内容

1
2
3
4
5
6
7
8
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
@Value("${name}")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}

注意:

  • 如果读取的properties配置文件有多个,可以使用@PropertySource的属性来指定多个

    1
    @PropertySource({"jdbc.properties","xxx.properties"})
  • @PropertySource注解属性中不支持使用通配符*,运行会报错

    1
    @PropertySource({"*.properties"})
  • @PropertySource注解属性中可以把classpath:加上,代表从当前项目的根路径找文件

    1
    @PropertySource({"classpath:jdbc.properties"})

注解依赖注入注解知识点

知识点1:@Autowired

名称 @Autowired
类型 属性注解 或 方法注解(了解) 或 方法形参注解(了解)
位置 属性定义上方 或 标准set方法上方 或 类set方法上方 或 方法形参前面
作用 为引用类型属性设置值
属性 required:true/false,定义该属性是否允许为null

知识点2:@Qualifier

名称 @Qualifier
类型 属性注解 或 方法注解(了解)
位置 属性定义上方 或 标准set方法上方 或 类set方法上方
作用 为引用类型属性指定注入的beanId
属性 value(默认):设置注入的beanId

知识点3:@Value

名称 @Value
类型 属性注解 或 方法注解(了解)
位置 属性定义上方 或 标准set方法上方 或 类set方法上方
作用 为 基本数据类型 或 字符串类型 属性设置值
属性 value(默认):要注入的属性值

知识点4:@PropertySource

名称 @PropertySource
类型 类注解
位置 类定义上方
作用 加载properties文件中的属性值
属性 value(默认):设置加载的properties文件对应的文件名或文件名组成的数组

IOC/DI注解开发管理第三方bean

前面定义bean的时候都是在自己开发的类上面写个注解就完成了,但如果是第三方的类,这些类都是在jar包中,我们没有办法在类上面添加注解,这个时候该怎么办?
遇到上述问题,我们就需要有一种更加灵活的方式来定义bean,这种方式不能在原始代码上面书写注解,一样能定义bean,这就用到了一个全新的注解@Bean
这个注解该如何使用呢?
咱们把之前使用配置方式管理的数据源使用注解再来一遍,通过这个案例来学习下@Bean的使用。

环境准备

查看代码

pom.xml添加Spring的依赖

1
2
3
4
5
6
7
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>

添加一个配置类SpringConfig

1
2
3
@Configuration
public class SpringConfig {
}

添加BookDao、BookDaoImpl类

1
2
3
4
5
6
7
8
9
public interface BookDao {
public void save();
}
@Repository
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ..." );
}
}

创建运行类App

1
2
3
4
5
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
}
}

注解开发第三方bean

步骤1:导入对应的jar包

1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>

步骤2:在配置类中添加一个方法
注意该方法的返回值就是要创建的Bean对象类型

1
2
3
4
5
6
7
8
9
10
11
@Configuration
public class SpringConfig {
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}

步骤3:在方法上添加@Bean注解

@Bean注解的作用是将方法的返回值制作为Spring管理的一个bean对象

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class SpringConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}

注意:不能使用DataSource ds = new DruidDataSource()
因为DataSource接口中没有对应的setter方法来设置属性。
步骤4:从IOC容器中获取对象并打印

1
2
3
4
5
6
7
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
DataSource dataSource = ctx.getBean(DataSource.class);
System.out.println(dataSource);
}
}

至此使用@Bean来管理第三方bean的案例就已经完成。
如果有多个bean要被Spring管理,直接在配置类中多些几个方法,方法上添加@Bean注解即可。

引入外部配置类

如果把所有的第三方bean都配置到Spring的配置类SpringConfig中,虽然可以,但是不利于代码阅读和分类管理,所有我们就想能不能按照类别将这些bean配置到不同的配置类中?
对于数据源的bean,我们新建一个JdbcConfig配置类,并把数据源配置到该类下。

1
2
3
4
5
6
7
8
9
10
11
public class JdbcConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}

现在的问题是,这个配置类如何能被Spring配置类加载到,并创建DataSource对象在IOC容器中?
针对这个问题,有两个解决方案:
1.使用包扫描引入
步骤1:在Spring的配置类上添加包扫描

1
2
3
4
5
@Configuration
@ComponentScan("com.itheima.config")
public class SpringConfig {

}

步骤2:在JdbcConfig上添加配置注解

JdbcConfig类要放入到com.itheima.config包下,需要被Spring的配置类扫描到即可

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
public class JdbcConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}

步骤3:运行程序

依然能获取到bean对象并打印控制台。

这种方式虽然能够扫描到,但是不能很快的知晓都引入了哪些配置类,所有这种方式不推荐使用。

2.使用@Import注解引入
步骤1:去除JdbcConfig类上的注解

1
2
3
4
5
6
7
8
9
10
11
public class JdbcConfig {
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}

步骤2:在Spring配置类中引入

1
2
3
4
5
6
@Configuration
//@ComponentScan("com.itheima.config")
@Import({JdbcConfig.class})
public class SpringConfig {

}

注意:

  • 扫描注解可以移除

  • @Import参数需要的是一个数组,可以引入多个配置类。

  • @Import注解在配置类中只能写一次,下面的方式是==不允许的==

    1
    2
    3
    4
    5
    6
    7
    @Configuration
    //@ComponentScan("com.itheima.config")
    @Import(JdbcConfig.class)
    @Import(Xxx.class)
    public class SpringConfig {

    }

步骤3:运行程序
依然能获取到bean对象并打印控制台

知识点1:@Bean

名称 @Bean
类型 方法注解
位置 方法定义上方
作用 设置该方法的返回值作为spring管理的bean
属性 value(默认):定义bean的id

知识点2:@Import

名称 @Import
类型 类注解
位置 类定义上方
作用 导入配置类
属性 value(默认):定义导入的配置类类名,
当配置类有多个时使用数组格式一次性导入多个配置类

注解开发实现为第三方bean注入资源

简单数据类型

步骤1:类中提供四个属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class JdbcConfig {
private String driver;
private String url;
private String userName;
private String password;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}

步骤2:使用@Value注解引入值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class JdbcConfig {
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("root")
private String userName;
@Value("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;
}
}

引用数据类型

步骤1:在SpringConfig中扫描BookDao

扫描的目的是让Spring能管理到BookDao,也就是说要让IOC容器中有一个bookDao对象

1
2
3
4
5
@Configuration
@ComponentScan("com.itheima.dao")
@Import({JdbcConfig.class})
public class SpringConfig {
}

步骤2:在JdbcConfig类的方法上添加参数

1
2
3
4
5
6
7
8
9
10
@Bean
public DataSource dataSource(BookDao bookDao){
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}

引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象。

Spring整合

Spring整合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连接
添加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();
}
}

我们已经分析了SpringMybatis的整合,大体需要做两件事,第一件事是: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;
}
}

步骤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);
}
}

Spring整合Junit

整合Junit与整合Druid和MyBatis差异比较大,为什么呢?Junit是一个搞单元测试用的工具,它不是我们程序的主体,也不会参加最终程序的运行,从作用上来说就和之前的东西不一样,它不是做功能的,看做是一个辅助工具就可以了。
步骤1:引入依赖

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>

步骤2:编写测试类

在test\java下创建一个AccountServiceTest,这个名字任意

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//设置类运行器
@RunWith(SpringJUnit4ClassRunner.class)
//设置Spring环境对应的配置类
@ContextConfiguration(classes = {SpringConfiguration.class}) //加载配置类
//@ContextConfiguration(locations={"classpath:applicationContext.xml"})//加载配置文件
public class AccountServiceTest {
//支持自动装配注入bean
@Autowired
private AccountService accountService;
@Test
public void testFindById(){
System.out.println(accountService.findById(1));

}
@Test
public void testFindAll(){
System.out.println(accountService.findAll());
}
}

注意:

  • 单元测试,如果测试的是注解配置类,则使用@ContextConfiguration(classes = 配置类.class)
  • 单元测试,如果测试的是配置文件,则使用@ContextConfiguration(locations={配置文件名,...})
  • Junit运行后是基于Spring环境运行的,所以Spring提供了一个专用的类运行器,这个务必要设置,这个类运行器就在Spring的测试专用包中提供的,导入的坐标就是这个东西SpringJUnit4ClassRunner
  • 上面两个配置都是固定格式,当需要测试哪个bean时,使用自动装配加载对应的对象,下面的工作就和以前做Junit单元测试完全一样了

注释知识点小结

知识点1:@RunWith

名称 @RunWith
类型 测试类注解
位置 测试类定义上方
作用 设置JUnit运行器
属性 value(默认):运行所使用的运行期

知识点2:@ContextConfiguration

名称 @ContextConfiguration
类型 测试类注解
位置 测试类定义上方
作用 设置JUnit加载的Spring核心配置
属性 classes:核心配置类,可以使用数组的格式设定加载多个配置类
locations:配置文件,可以使用数组的格式设定加载多个配置文件名称