主要内容:
IOC/DI配置管理第三方beanIOC/DI的注解开发IOC/DI注解管理第三方beanSpring与Mybatis及Junit的整合开发
目录
1.IOC/DI配置管理第三方bean
1.1案例:数据源对象管理
对数据源Druid(德鲁伊)和C3P0对象进行管理
1.1.1环境准备
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<?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>
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
1.1.2思路分析
需求 : 使用 Spring 的 IOC 容器来管理 Druid 连接池对象1. 使用第三方的技术,需要在 pom.xml 添加依赖2. 在配置文件中将【第三方的类】制作成一个 bean ,让 IOC 容器进行管理3. 数据库连接需要基础的四要素 驱动 、 连接 、 用户名 和 密码 ,【如何注入】到对应的 bean 中4. 从 IOC 容器中获取对应的 bean 对象,将其打印到控制台查看结果
1.1.3实现Druid管理
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<?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
">
<!-- 管理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>
class声明操作对象driverClassName: 数据库驱动url: 数据库连接地址username: 数据库连接用户名password: 数据库连接密码数据库连接的四要素要和自己使用的数据库信息一致。
步骤3:从IOC容器中获取对应的bean对象
package com.itheima;
import com.itheima.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource;
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);
}
}
第三方的类指的是什么?DruidDataSource如何注入数据库连接四要素?setter 注入
1.1.4小结
首先在pom.xml中导入druid的坐标,然后对druid进行配置(在applicationContext中配置),然后使用ClassPathXmlApplicationContext方法中加载配置文件,new出一个IOC容器,使用容器中的getBean方法,得到dataSource对象。
1.2加载properties文件
有利于对数据源后期的维护,只需要在properties中修改常量。
1.2.1 第三方bean属性优化
需求 : 将数据库连接四要素提取到 properties 配置文件, spring 来加载配置信息并使用这些信息来完成属性注入。1. 在 resources 下创建一个 jdbc.properties( 文件的名称可以任意 )2.将数据库连接四要素配置到配置文件中
3. 在 Spring 的配置文件中加载 properties 文件4. 使用加载到的值实现属性注入
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=root
<?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
">
注意:配置xmlns:context和xsi:schemaLocation。
<context:property-placeholder location="jdbc.properties"/>
<bean 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>
1.2.2读取单个属性
需求 : 从 properties 配置文件中读取 key 为 name 的值,并将其注入到 BookDao 中并在 save 方法中进行打印。1. 在项目中添加 BookDao 和 BookDaoImpl 类2. 为 BookDaoImpl 添加一个 name 属性并提供 setter 方法3. 在 jdbc.properties 中添加数据注入到 bookDao 中打印方便查询结果4. 在 applicationContext.xml 添加配置完成配置文件加载、属性注入 (${key})
<!-- 1.开启context命名空间-->
<!-- 2.使用context空间加载properties文件-->
<!-- <context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/> -->
<!-- 由于某一些变量名会跟系统产生冲突,比如username为电脑的默认值,使用system-properties-mode="NEVER"属性可以防止properties文件中的username覆盖电脑系统的username-->
<!-- <context:property-placeholder location="jdbc.properties,jdbc2.properties" system-properties-mode="NEVER"/>-->
<!-- 加载的配置文件可以是多个,用空格隔开-->
<!-- classpath:*.properties : 设置加载当前工程类路径中的所有properties文件-->
<!-- system-properties-mode属性:是否加载系统属性-->
<!-- <context:property-placeholder location="*.properties" system-properties-mode="NEVER"/>-->
<!--classpath*:*.properties : 设置加载当前工程类路径和当前工程所依赖的所有jar包中的所有properties文件-->
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
<!-- 3.使用属性占位符${}读取properties文件中的属性-->
<!-- 说明:idea自动识别${}加载的属性值,需要手工点击才可以查阅原始书写格式-->
<bean 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>
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
<property name="name" value="${username}"/>
</bean>
将properties中的属性注入到druid的bean对象中,然后使用DI依赖注入,将单一的属性注入到bookDaoImpl类中,该类使用setter注入,最后输出。
1.2.3加载properties小结
如何开启context命名空间如何加载properties配置文件<context:property-placeholder location="" system-properties-mode="NEVER"/>
如何在applicationContext.xml引入properties配置文件中的值
@{key}
2.核心容器
如何创建容器 ?创建好容器后,如何从容器中获取 bean 对象 ?容器类的层次结构是什么 ?BeanFactory 是什么 ?
2.1容器
2.1.1容器的创建方式
方式一:类路径下的XML配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
方式二:文件系统下的XML配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\workspace
\\spring\\spring_10_container\\s rc\\main\\resources\\applicationContext.xml");
2.1.2bean的三种获取方式
方式一:BookDao bookDao = (BookDao) ctx.getBean("bookDao");
该方式需要进行强制转换
方式二:BookDao bookDao = ctx.getBean("bookDao",BookDao.class);
该方式不需要强制转换,但需要在参数中声明类的类型
方式三:
BookDao bookDao = ctx.getBean(BookDao.class);
这种方式就类似我们之前所学习依赖注入中的按类型注入。必须要确保IOC容器中该类型对应的bean对象只能有一个。
2.1.3容器的层次结构
2.1.4BeanFactory的使用
package com.itheima;
import com.itheima.dao.BookDao;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
//初始化BeanFactory
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();
}
}
BeanFactory和ApplicationContext创建IOC容器的区别:
BeanFactory 是延迟加载,只有在获取 bean 对象的时候才会去创建ApplicationContext 是立即加载,容器加载的时候就会创建 bean 对象ApplicationContext 要想成为延迟加载,只需要按照如下方式进行配置
2.1.5小结
容器创建的两种方式ClassPathXmlApplicationContext[ 掌握 ]FileSystemXmlApplicationContext[ 知道即可 ]获取Bean的三种方式getBean(" 名称 "): 需要类型转换getBean(" 名称 ", 类型 .class): 多了一个参数getBean( 类型 .class): 容器中不能有多个该类的 bean 对象上述三种方式,各有各的优缺点,用哪个都可以。容器类层次结构只需要知晓容器的最上级的父接口为 BeanFactory 即可BeanFactory使用 BeanFactory 创建的容器是延迟加载使用 ApplicationContext 创建的容器是立即加载具体 BeanFactory 如何创建只需要了解即可。
2.2核心容器的总结
2.2.1容器相关
BeanFactory 是 IoC 容器的顶层接口,初始化 BeanFactory 对象时,加载的 bean 延迟加载ApplicationContext 接口是 Spring 容器的核心接口,初始化时 bean 立即加载ApplicationContext 接口提供基础的 bean 操作相关方法,通过其他接口扩展其功能ApplicationContext 接口常用初始化类:ClassPathXmlApplicationContext( 常用 )FileSystemXmlApplicationContext
2.2.2bean相关
2.2.3依赖注入相关
3.IOC/DI注解开发
Spring 对注解支持的版本历程 :2.0 版开始支持注解2.5 版注解功能趋于完善3.0 版支持纯注解开发
3.1注解开发定义bean
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
@Component("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ..." );
}
}
步骤3:配置Spring的注解包扫描
为了让Spring框架能够扫描到写在类上的注解,需要在配置文件上进行包扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.itheima"/>
</beans>
说明 :component-scancomponent: 组件 ,Spring 将管理的 bean 视作自己的一个组件scan: 扫描base-package指定Spring框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解。包路径越多 [ 如 :com.itheima.dao.impl] ,扫描的范围越小速度越快包路径越少 [ 如 :com.itheima], 扫描的范围越大速度越慢一般扫描到项目的组织名称即 Maven 的 groupId 下 [ 如 :com.itheima] 即可。
步骤5:Service上添加注解
在BookServiceImpl类上也添加@Component交给Spring框架管理
@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();
}
}
步骤6:运行程序
在App类中,从IOC容器中获取BookServiceImpl对应的bean对象,打印
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 注解如果不起名称,会有一个默认值就是 当前类名首字母小写 ,所以也可以按照名 称 获取,如BookService bookService = (BookService)ctx.getBean("bookServiceImpl"); System.out.println(bookService);
对于 @Component 注解,还衍生出了其他三个注解 @Controller、@Service、@Repository
3.2纯注解开发模式
@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中
public class SpringConfig { }
@Configuration
public class SpringConfig { }
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig { }
public class AppForAnnotation {
public static void main(String[] args) {
//AnnotationConfigApplicationContext加载Spring配置类初始化Spring容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
System.out.println(bookDao);
//按类型获取bean
BookService bookService = ctx.getBean(BookService.class);
System.out.println(bookService);
}
}
纯注解开发总结:
Java 类替换 Spring 核心配置文件@Configuration注解用于设定当前类为配置类
@ComponentScan 注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式@ComponentScan({com.itheima.service","com.itheima.dao"})
读取 Spring 核心配置文件初始化容器对象切换为读取 Java 配置类初始化容器对象//加载配置文件初始化容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //加载配置类初始化容器 ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
记住@Component、@Controller、@Service、@Repository这四个注解applicationContext.xml中<context:component-san/>的作用是指定扫描包路径,注解为@ComponentScan@Configuration标识该类为配置类,使用类替换applicationContext.xml文件ClassPathXmlApplicationContext是加载XML配置文件AnnotationConfigApplicationContext是加载配置类
3.3注解开发Bean作用范围与生命周期管理
3.3.1Bean的作用范围
3.3.2Bean的生命周期
package com.itheima.dao.impl;
import com.itheima.dao.BookDao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Repository
//@Scope设置bean的作用范围
@Scope("singleton")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//@PostConstruct设置bean的初始化方法
@PostConstruct
public void init() {
System.out.println("init ...");
}
//@PreDestroy设置bean的销毁方法
@PreDestroy
public void destroy() {
System.out.println("destroy ...");
}
}
找不到的原因是,从JDK9以后jdk中的javax.annotation包被移除了,这两个注解刚好就在这个包 中。
3.4注解开发依赖注入
3.4.1注解实现按照类型注入
@Service
public class BookServiceImpl implements BookService{
@Autowired
private BookDao bookDao;
public void save(){
System.out.println("book service ..");
bookDao.save();
}
}
注意 :@Autowired 可以写在属性上,也可也写在 setter 方法上,最简单的处理方式是 写在属性上并将setter 方法删除掉为什么setter方法可以删除呢?自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值普通反射只能获取 public 修饰的内容暴力反射除了获取 public 修饰的内容还可以获取 private 修改的内容所以此处无需提供 setter 方法
@Autowired是按照类型注入,那么对应BookDao接口如果有多个实现类,比如添加BookDaoImpl2此时需要使用 按名称注入 ,即给每一个实体类创建对象。
3.4.2注解实现按照名称注入
当根据类型在容器中找到多个 bean, 注入参数的属性名又和容器中 bean 的名称不一致,这个时候该如何解决,就需要使用到 @Qualifier来指定注入哪个名称的bean 对象。package com.itheima.service.impl; import com.itheima.dao.BookDao; import com.itheima.service.BookService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class BookServiceImpl implements BookService{ @Autowired @Qualifier("bookDao1") private BookDao bookDao; public void save(){ System.out.println("book service .."); bookDao.save(); } }
@Qualifier 注解后的值就是需要注入的 bean 的名称。注意 :@Qualifier 不能独立使用,必须和 @Autowired 一起使用
3.4.3简单数据类型注入
数据类型换了,对应的注解也要跟着换,这次使用 @Value 注解,将值写入注解的参数中就行了@Repository("bookDao") public class BookDaoImpl implements BookDao { //@Value:注入简单类型(无需提供set方法) @Value("itheima") private String name; public void save() { System.out.println("book dao save ..." + name); }
注意数据格式要匹配,如将 "abc" 注入给 int 值,这样程序就会报错。
3.4.4注解读取properties配置文件
name=itheima888
@Configuration //定义该类为配置类
@ComponentScan("com.itheima") //从com.itheima文件开始扫描
@PropertySource("jdbc.properties") //定义jdbc.properties为配置文件,可以使用value进行读取
public class SpringConfig { }
@Repository("bookDao")//使用注解说明该类是一个bean,名称为bookDao
public class BookDaoImpl implements BookDao {
//@Value:注入简单类型(无需提供set方法)
@Value("${name}")
private String name;
public void save() {
System.out.println("book dao save ..." + name);
}
}
注意 :如果读取的 properties 配置文件有多个,可以使用 @PropertySource 的属性来指定多个@PropertySource({"jdbc.properties","xxx.properties"})
@PropertySource 注解属性中不支持使用通配符 * , 运行会报错@PropertySource({"*.properties"})
@PropertySource 注解属性中可以把 classpath: 加上 , 代表从当前项目的根路径找文件@PropertySource({"classpath:jdbc.properties"})
4.IOC/DI注解开发管理第三方bean
之前我们是用xml管理第三方bean,现在我们使用注解来管理第三方bean。
4.1注解开发管理第三方bean
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
@Configuration
public class SpringConfig {
public DataSource dataSource(){
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
步骤3:
在方法上添加
@Bean
注解
@Configuration
public class SpringConfig {
@Bean
public DataSource dataSource(){
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
package com.itheima;
import com.itheima.config.SpringConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.sql.DataSource;
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);
}
}
4.3引入外部配置类
4.3.1使用包扫描引入(不推荐,阅读性差)
@Configuration
@ComponentScan("com.itheima.config")
public class SpringConfig(){
}
@Configuration
public class JdbcConfig {
@Bean
public DataSource dataSource(){
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
4.3.2使用@Import引入
在SpringConfig类中使用@Import注解,并且声明导入包的字节码文件。
@Configuration
//@ComponentScan("com.itheima")
//@Import:导入配置信息
@Import({JdbcConfig.class})
public class SpringConfig {
}
注意 :扫描注解可以移除@Import 参数需要的是一个数组,可以引入多个配置类。@Import 注解在配置类中只能写一次,下面的方式是 不允许的
4.4注解开发实现为第三方bean注入资源
4.4.1注入简单数据类型
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
private String driver;
private String url;
private String userName;
private String password;
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean修饰的方法,形参根据类型自动装配
@Bean
public DataSource dataSource(){
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
public class JdbcConfig {
//1.定义一个方法获得要管理的对象
@Value("com.mysql.jdbc.Driver")
private String driver;
@Value("jdbc:mysql://localhost:3306/spring_db")
private String url;
@Value("root")
private String userName;
@Value("root")
private String password;
//2.添加@Bean,表示当前方法的返回值是一个bean
//@Bean修饰的方法,形参根据类型自动装配
@Bean
public DataSource dataSource(){
System.out.println(bookDao);
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(userName);
ds.setPassword(password);
return ds;
}
}
现在的数据库连接四要素还是写在代码中,需要做的是将这些内容提取到jdbc.properties配置文件,该如何实现?resources 目录下添加 jdbc.properties配置文件中提供四个键值对分别是数据库的四要素使用 @PropertySource 加载 jdbc.properties 配置文件修改 @Value 注解属性的值,将其修改为 ${key} , key 就是键值对中的键的值
4.4.2注入引用数据类型
@Configuration
@ComponentScan("com.itheima.dao")
@Import({JdbcConfig.class})
public class SpringConfig { }
@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;
}
5.注解开发总结
6.Spring整合
6.1Spring整合Mybatis思路分析
步骤1:准备数据库表
Mybatis是来操作数据库表,所以先创建一个数据库及表
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
);
<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>
package com.itheima.domain;
import java.io.Serializable;
public class Account implements Serializable {
private Integer id;
private String name;
private Double money;
public Integer getId() {
return id;
}
public void setId(Integer 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 +
'}';
}
}
package com.itheima.dao;
import com.itheima.domain.Account;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
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);
}
package com.itheima.service;
import com.itheima.domain.Account;
import java.util.List;
public interface AccountService {
void save(Account account);
void delete(Integer id);
void update(Account account);
List<Account> findAll();
Account findById(Integer id);
}
package com.itheima.service.impl;
import com.itheima.dao.AccountDao;
import com.itheima.domain.Account;
import com.itheima.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@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();
}
}
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
jdbc.username=root
jdbc.password=root
<?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>
import com.itheima.dao.AccountDao;
import com.itheima.domain.Account;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
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(2);
System.out.println(ac);
// 6. 释放资源
sqlSession.close();
}
}
*6.1.2整合思路分析
从图中可以获取到,真正需要交给Spring管理的是SqlSessionFactory
说明 :第一行读取外部 properties 配置文件, Spring 有提供具体的解决方案 @PropertySource , 需要交给 Spring第二行起别名包扫描,为 SqlSessionFactory 服务的,需要交给 Spring第三行主要用于做连接池, Spring 之前我们已经整合了 Druid 连接池,这块也需要交给Spring前面三行一起都是为了创建 SqlSession 对象用的,那么用 Spring 管理 SqlSession 对象吗 ?回忆下 SqlSession 是由 SqlSessionFactory 创建出来的,所以只需要将SqlSessionFactory 交给 Spring 管理即可。第四行是 Mapper 接口和映射文件 [ 如果使用注解就没有该映射文件 ] ,这个是在获取到SqlSession 以后执行具体操作的时候用,所以它和 SqlSessionFactory 创建的时机都不在同一个时间,可能需要单独管理。
6.2Spring整合Mybatis
前面我们已经分析了 Spring 与 Mybatis 的整合,大体需要做两件事,第一件事是:Spring要管理MyBatis中的SqlSessionFactory第二件事是:Spring要管理Mapper接口的扫描具体该如何实现,具体的步骤为 :
<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>
//配置类注解
@Configuration
//包扫描,主要扫描的是项目中的AccountServiceImpl类
@ComponentScan("com.itheima")
public class SpringConfig {
}
package com.itheima.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
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;
}
}
@Configuration
@ComponentScan("com.itheima")
//@PropertySource:加载类路径jdbc.properties文件
@PropertySource("classpath:jdbc.properties")
@Import(JdbcConfig.class)
public class SpringConfig {
}
package com.itheima.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
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 是前面我们讲解 FactoryBean 的一个子类,在该类中将SqlSessionFactory 的创建进行了封装,简化对象的创建,我们只需要将其需要的内容设置即可。方法中有一个参数为 dataSource, 当前 Spring 容器中已经创建了 Druid 数据源,类型刚好是DataSource 类型,此时在初始化 SqlSessionFactoryBean 这个对象的时候,发现需要使用DataSource 对象,而容器中刚好有这么一个对象,就自动加载了 DruidDataSource 对象。
这个 MapperScannerConfigurer 对象也是 MyBatis 提供的专用于整合的 jar 包中的类,用来处理原始配置文件中的 mappers 相关配置,加载数据层的 Mapper 接口类MapperScannerConfigurer 有一个核心属性 basePackage ,就是用来设置所扫描的包路径
@Configuration
@ComponentScan("com.itheima")
//@PropertySource:加载类路径jdbc.properties文件
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}
import com.itheima.config.SpringConfig;
import com.itheima.domain.Account;
import com.itheima.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
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与Mybatis的整合就已经完成了,其中主要用到的两个类分别是:
<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>
package com.itheima.service;
import com.itheima.config.SpringConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
//设置类运行器
@RunWith(SpringJUnit4ClassRunner.class)
//设置Spring环境对应的配置类
@ContextConfiguration(classes = SpringConfig.class)
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 单元测试完全一样了