Skip to content

1. 第三方资源配置管理

说明

以管理 DataSource 连接池对象为例讲解第三方资源配置管理

  • 数据库连接池

    1. 概念:其实就是一个容器(集合),存放数据库连接的容器。
      • 当系统初始化好后,容器被创建,容器中会申请一些连接对象,
      • 当用户来访问数据库时,从容器中获取连接对象,
      • 用户访问完之后,会将连接对象归还给容器。
    2. 好处:
    • 节约资源
    • 用户访问高效

点击查看连接池图解

1.1 管理 DataSource 连接池对象

15 分钟

1.1.1「管理 DataSource」核心问题&答案

问题:DataSource 是接口还是类?

点击查看答案

  1. DataSource 是接口
  2. com.alibaba.druid.pool.DruidDataSource 是具体的实现类
<bean id="dataSource" 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>

1.1.2 管理 Druid 连接池【重点】

提示

  • 【起 步】数据库准备
  • 【第一步】添加 Druid 连接池依赖
  • 【第二步】配置 DruidDataSource 连接池 Bean 对象
  • 【第三步】在测试类中从 IOC 容器中获取连接池对象并打印
1️⃣ 数据库准备
create database if not exists spring_db character set utf8;
use spring_db;
create table if not exists tbl_account(
    id int primary key auto_increment,
    name varchar(20),
    money double
);
insert into tbl_account values(null,'Tom',1000);
insert into tbl_account values(null,'Jerry',1000);
2️⃣ 添加 Druid 连接池依赖
<!--      springcontext依赖-->
<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>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

注意:除了添加以上两个依赖之外,别忘了添加 spring-context 依赖。

3️⃣ 配置 DruidDataSource 连接池 Bean 对象
<bean id="dataSource" 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>
4️⃣ 在测试类中从 IOC 容器中获取连接池对象并打印
public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
       //从容器中获得DataSource实例对象
        DataSource dataSource = (DataSource) ctx.getBean("dataSource");
        System.out.println(dataSource);
        //获得链接,开始查询
        Connection connection = dataSource.getConnection();
        System.out.println(connection);

        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery("select * from tb_brand");

        while (resultSet.next()){
            System.out.println(resultSet.getString("brand_name"));
        }
    }
}

1.1.3 管理 c3p0 连接池【了解】

相关信息

C3P0 是一个开源的 JDBC 连接池,它实现了数据源和 JNDI 绑定,支持 JDBC3 规范和 JDBC2 的标准扩展。目前使用它的开源项目有 Hibernate、Spring 等。

  • c3p0 连接池是全自动化操作,相比于 dbcp 可以自动回收空闲连接,此外还能自动连接。
  • C3P0 功能简单易用,稳定性好这是它的优点,但是性能上的缺点却让它彻底被打入冷宫。
  • C3P0 的性能很差,差到即便是同时代的产品相比它也是垫底的,更不用和 Druid 等相比了。正常来讲,有问题很正常,改就是了,但 c3p0 最致命的问题就是架构设计过于复杂,让重构变成了一项不可能完成的任务。随着国内互联网大潮的涌起,性能有硬伤的 c3p0 彻底的退出了历史舞台
1️⃣ 添加 c3p0 连接池依赖
<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>
2️⃣ 配置 c3p0 连接池 Bean 对象

maxPoolSize 最大连接数

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring_db"/>
    <property name="user" value="root"/>
    <property name="password" value="root"/>
    <property name="maxPoolSize" value="1000"/>
</bean>

同一个 Spring 容器中不能有两个 id="dataSource"的连接池。(回顾按类型装配的特征)

3️⃣ 在测试类中从 IOC 容器中获取连接池对象并打印
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);
    }
}

思考题:

Druid 配置的数据源(DataSource),用构造注入还是 setter 注入?

image-20220513095535207image-20220513095432857

随着 applicationContext.xml 配置文件越来越大,密码和用户名等信息写在里面,为了提高维护性,可以将数据库的配置信息放在专门的文件中,如 jdbc.properties

image-20220513095400015

1.2 加载 properties 属性文件【重点】

目的

将数据库的连接参数抽取到一个单独的文件中,与 Spring 配置文件解耦。

1.2.1 「加载 properties」核心问题&答案 🍐

注意

问题:如何解决使用 EL 表达式读取属性文件中的值结果读取到了系统属性问题?

点击查看答案

<!--classpath*:*.properties  :  设置加载当前工程类路径和当前工程所依赖的所有jar包中的所有properties文件-->
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>

1.2.2 基本用法

1️⃣ 【第一步】编写 jdbc.properties 属性文件

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 中开启开启 context 命名空间,加载 jdbc.properties 属性文件

image-20210730101826913

源码如下:

<?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>

小技巧:如果同学们觉得上述复制粘贴方式不好改或者容易改错,其实 idea 是有提示功能的,注意不要选错就行了。有些版本的 idea 没有这个提示,那么就按照上面复制粘贴的方式改,改完之后可以做成 live template 模板,后期直接用

image-20210730102053281

<!--classpath*:*.properties  :  设置加载当前工程类路径和当前工程所依赖的所有jar包中的所有properties文件-->
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
3️⃣ 【第三步】在配置连接池 Bean 的地方使用 EL 表达式获取 jdbc.properties 属性文件中的值

<!--    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>

配置完成之后,运行之前的获取 Druid 连接池代码,可以获取到连接池对象就表示配置成功。

1.2.3 配置不加载系统属性

问题

如果属性文件中配置的不是 jdbc.username,而是 username=root666,那么使用${username}获取到的不是 root666,而是计算机的名称。

原因

系统属性的优先级比我们属性文件中的高,替换了我们的 username=root666。

解决方案

  • 解决 1:换一个名称,例如不叫 username,叫 jdbc.username。

  • 解决 2:使用**system-properties-mode="NEVER"**属性表示不使用系统属性。

点击查看详情

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

加载类路径所有的
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>

为什么不在 xml 文件中书写密码和用户名信息等数据库链接信息,而写在 properties 中?

  1. 方便管理,未来可能有很多 propertis 文件,每个文件配置对应的信息,如 jdbc.properties,druid.properties, logback.properties 👈

    使用前缀进行区分,如下述的:jdbc和logback
    jdbc.properties
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://127.0.0.1:3306/db1?useSSL=false
    jdbc.username=root
    jdbc.password=root

    logback.properties
    logback.driver=com.mysql.jdbc.Driver
    logback.url=jdbc:mysql://127.0.0.1:3306/db1?useSSL=false
    logback.username=root
    logback.password=win10139741
  1. 实际开发中使用第三方框架,第三方框架提供了对应的.properties 文件

1.3.4 加载 properties 文件写法[了解]

点击查看详情

  • 不加载系统属性
<context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>
  • 加载多个 properties 文件
<context:property-placeholder location="jdbc.properties,msg.properties"/>
  • 加载所有 properties 文件
<context:property-placeholder location="*.properties"/>
  • 加载 properties 文件**标准格式**
<context:property-placeholder location="classpath:*.properties"/>
  • 加载 properties 文件标准格式【常用】
<context:property-placeholder location="classpath*:*.properties"/>

1.3 连接池练习 ✏️

10 分钟

1.3.0「连接池练习」目的

熟悉数据库连接池的使用以及配置第三方 Bean

1.3.1「连接池练习」需求&效果

打印连接池对象

1.3.2「连接池练习」步鄹

步鄹提示

  1. 参考 1.1.2 1.1.2 管理 Druid 连接池【重点】
  2. 创建 jdbc.properties,将链接信息存入
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://127.0.0.1:3306/db1?useSSL=false
    jdbc.username=root
    jdbc.password=root
  1. 加载 properties 进入容器,使用 el 表达式获取值
<?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
            ">
   <!--classpath*:*.properties  :  设置加载当前工程类路径和当前工程所依赖的所有jar包中的所有properties文件-->
    <context:property-placeholder location="jdbc.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>
</beans>
  1. 在 main 方法中打印对象
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);


    }
}

2. Spring 容器

2.1 Spring 核心容器介绍

15 分钟

2.1.1「Spring 核心容器」核心问题&答案

创建容器有几种方式?

  • 方式一:类路径加载配置文件
  • 方式二:文件路径加载配置文件

2.1.2 创建容器的方式

点击查看创建容器的方式

  • 方式一:类路径加载配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  • 方式二:文件路径加载配置文件
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\applicationContext.xml");
  • 加载多个配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml", "bean2.xml");

2.1.3 获取 bean 对象的方式

点击查看创建容器的方式

  • 方式一:使用 bean 名称获取

弊端:需要自己强制类型转换

BookDao bookDao = (BookDao) ctx.getBean("bookDao");
  • 方式二:使用 bean 名称获取并指定类型

弊端:暂无,推荐使用

BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
  • 方式三:使用 bean 类型获取

弊端:如果 IOC 容器中同类型的 Bean 对象有多个,此处获取会报错

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

image-20220413191026729

2.2 容器类层次结构

image-20210730102842030

2.3 BeanFactory 🚀

  • 类路径加载配置文件
Resource resources = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(resources);
BookDao bookDao = bf.getBean("bookDao", BookDao.class);
bookDao.save();

总结

  • BeanFactory 创建完毕后,所有的 Bean 均为延迟加载 ,也就是说我们调用 getBean()方法获取 Bean 对象时才创建 Bean 对象并返回给我们 👈
  • lazy-init="false" 立退加载, 表示 spring 启动时,立刻进行实例化(lazy-init 设置只对 scope 属性为singleton的 bean 起作用)
  • lazy-init="true"> 延迟加载 ,设置为 lazy 的 bean 将不会在 ApplicationContext 启动时提前被实例化,而是在第一次向容器通过 getBean 索取 bean 时实例化的

2.4 Spring 核心容器总结

5 分钟

点击查看总结

1️⃣ 容器相关

  • BeanFactory 是 IoC 容器的顶层接口,初始化 BeanFactory 对象时,加载的 bean 延迟加载 👈
  • ApplicationContext 接口是 Spring 容器的核心接口,初始化时 bean 立即加载
  • ApplicationContext 接口提供基础的 bean 操作相关方法,通过其他接口扩展其功能
  • ApplicationContext 接口常用初始化类
    • ClassPathXmlApplicationContext(常用)
    • FileSystemXmlApplicationContext

2️⃣bean 相关

image-20210730103438742

3️⃣ 依赖注入相关

image-20210730103701525

3.Spring 注解开发

3.1 注解开发定义 Bean 对象

目的

xml 配置 Bean 对象有些繁琐,使用注解简化 Bean 对象的定义

3.1.1「注解开发定义 Bean 对象」核心问题&答案

@Component 注解和@Controller、@Service、@Repository 三个衍生注解有什么区别?

点击查看答案

  • Spring 提供**@Component**注解的三个衍生注解 👈
    • @Controller:用于表现层 bean 定义
    • @Service:用于业务层 bean 定义
    • @Repository:用于数据层 bean 定义

3.1.2 基本使用

提示

  • 【第一步】在 applicationContext.xml 中开启 Spring 注解包扫描
  • 【第二步】在类上使用@Component 注解定义 Bean。
  • 【第三步】在测试类中获取 Bean 对象
1️⃣ 在 applicationContext.xml 中开启 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">
 <!--扫描com.itheima包及其子包下的类中注解-->
    <context:component-scan base-package="com.itheima"/>
</beans>
2️⃣ 在类上使用@Component 注解定义 Bean。
//@Component定义bean
@Component("bookDao")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}
@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();
    }
}

补充说明:如果@Component 注解没有使用参数指定 Bean 的名称,那么类名首字母小写就是 Bean 在 IOC 容器中的默认名称。例如:BookServiceImpl 对象在 IOC 容器中的名称是 bookServiceImpl。

3️⃣ 在测试类中获取 Bean 对象
public class AppForAnnotation {
    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);
    }
}

注意:在测试类中不要调用 bookService 的 save 方法,因为还没有给 BookServiceImpl 中的 bookDao 赋值,调用 bookService 的 save 方法会出现空指针异常。

运行结果image-20210730104835746

3.1.3 @Component 三个衍生注解【掌握】 🍐

  • Spring 提供**@Component**注解的三个衍生注解
    • @Controller:用于表现层 bean 定义
    • @Service:用于业务层 bean 定义
    • @Repository:用于数据层 bean 定义
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
}

@Service
public class BookServiceImpl implements BookService {
}

3.2 纯注解开发模式 🍐 ✏️

3.2.1「纯注解开发模式」核心问题&答案

问题

  1. 配置类上使用什么注解表示该类是一个配置类?
  2. 配置类上使用什么注解进行 Spring 注解包扫描?

3.2.2 纯注解开发模式介绍

介绍

  • Spring3.0 开启了纯注解开发模式,使用 Java 类替代配置文件,开启了 Spring 快速开发赛道 👈
  • Java 类代替 Spring 核心配置文件 image-20210803192052811
    • @Configuration注解用于设定当前类为配置类
    • @ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式

3.2.3 代码演示

1️⃣ 【第一步】定义配置类代替配置文件
//声明当前类为Spring配置类
@Configuration
//Spring注解扫描,相当于<context:component-scan base-package="com.itheima"/>
@ComponentScan("com.itheima")
//设置bean扫描路径,多个路径书写为字符串数组格式
//@ComponentScan({"com.itheima.service","com.itheima.dao"})
public class SpringConfig {
}
2️⃣ 【第二步】在测试类中加载配置类,获取 Bean 对象并使用
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);
    }
}

3.3 注解开发 Bean 作用范围和生命周期管理

3.3.1 「注解开发 Bean 作用范围和生命周期管理」核心问题&答案

问题

  1. 类上使用什么注解定义 bean 作用范围?
  2. 类上使用什么注解定义 定义 bean 生命周期?

点击查看答案

  • 使用 @Scope 定义 bean 作用范围 👈
@Repository
@Scope("singleton")
public class BookDaoImpl implements BookDao {
}

3.3.2 bean 生命周期注解配置

使用@PostConstruct、@PreDestroy 定义 bean 生命周期

点击查看代码

@Repository
@Scope("singleton")
public class BookDaoImpl implements BookDao {
    public BookDaoImpl() {
        System.out.println("book dao constructor ...");

    @PostConstruct
    public void init(){
        System.out.println("book init ...");
    }
    @PreDestroy
    public void destroy(){
        System.out.println("book destory ...");
    }
}

注意:@PostConstruct 和@PreDestroy 注解是 jdk 中提供的注解,从 jdk9 开始,jdk 中的 javax.annotation 包被移除了,也就是说这两个注解就用不了了,可以额外导入一下依赖解决这个问题。

<dependency>
  <groupId>javax.annotation</groupId>
  <artifactId>javax.annotation-api</artifactId>
  <version>1.3.2</version>
</dependency>
  1. 实际开发使用 JDK8 即可,安全。 👈
  2. 理解这句话:因为 Spring 不会破坏原型 bean,因此代码中的任何@PreDestroy 挂钩永远不会被容器调用

3.4 注解开发依赖注入 🍐

3.4.1 「注解开发依赖注入」核心问题&答案

问题

  1. 请描述@Autowired 注解是如何进行自动装配的?
  2. 请描述@Qualifier 注解的作用

点击查看答案

  • @Autowired:注入引用类型,自动装配模式,默认按类型装配 👈
  • @Qualifier:自动装配 bean 时按 bean 名称装配 👈

3.4.2 使用@Autowired 注解开启自动装配模式(按类型)

@Autowired:注入引用类型,自动装配模式,默认按类型装配

点击查看代码

@Service
public class BookServiceImpl implements BookService {
    //@Autowired:注入引用类型,自动装配模式,默认按类型装配
    @Autowired
    private BookDao bookDao;

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

说明:不管是使用配置文件还是配置类,都必须进行对应的 Spring 注解包扫描才可以使用。@Autowired 默认按照类型自动装配,如果 IOC 容器中同类的 Bean 有多个,那么默认按照变量名和 Bean 的名称匹配,建议使用@Qualifier 注解指定要装配的 bean 名称

注意:自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供 setter 方法。

联想:xml 的自动注入:autowire="byType"

3.4.3 使用@Qualifier 注解指定要装配的 bean 名称

目的:解决 IOC 容器中同类型 Bean 有多个装配哪一个的问题

点击查看代码

@Service
public class BookServiceImpl implements BookService {
    //@Autowired:注入引用类型,自动装配模式,默认按类型装配
    @Autowired
    //@Qualifier:自动装配bean时按bean名称装配
    @Qualifier("bookDao")
    private BookDao bookDao;

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

注意:@Qualifier 注解无法单独使用,必须配合@Autowired 注解使用

3.4.4 使用@Value 实现简单类型注入

点击查看代码

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    //@Value:注入简单类型(无需提供set方法)
    @Value("${name}")
    private String name;

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

以上@Value 注解中使用${name}从属性文件中读取 name 值,那么就需要在配置类或者配置文件中加载属性文件。 👈

@Configuration
@ComponentScan("com.itheima")
//@PropertySource加载properties配置文件
@PropertySource({"classpath:jdbc.properties"}) //{}可以省略不写
public class SpringConfig {
}

注意:可以使用下述配置吗?

@Configuration
@ComponentScan("com.itheima")
//@PropertySource加载properties配置文件
@PropertySource({"classpath:*.properties"})
public class SpringConfig {
}

image-20220413201252862

注意:@PropertySource()中加载多文件请使用数组格式配置,不允许使用通配符\*

  1. @PropertySource()中加载多文件请使用数组格式配置,不允许使用通配符*
  2. @Value("${name}") private String name;
  3. //@Autowired:注入引用类型,自动装配模式,默认按类型装配 @Autowired private BookDao bookDao;

3.5 注解开发管理第三方 Bean 🍐

3.5.1 「注解开发管理第三方 Bean」核心问题&答案

第三方 Bean 配置注解是什么?

点击查看答案

  • @Bean:表示当前方法的返回值是一个 bean 对象,添加到 IOC 容器中 👈

image-20220414180852105

3.5.2 「解开发管理第三方 Bean」步鄹

1️⃣ 【第一步】单独定义配置类
public class JdbcConfig {
    //@Bean:表示当前方法的返回值是一个bean对象,添加到IOC容器中
    @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️⃣ 【第二步】将独立的配置类加入核心配置
  • 方式 1:@Import 注解导入式 👈
@Configuration
@ComponentScan("com.itheima")
//@Import:导入配置信息
@Import({JdbcConfig.class})
public class SpringConfig {
}
  • 方式 2:@ComponentScan 扫描式 🚀
@Configuration
@ComponentScan({"com.itheima.config","com.itheima.service","com.itheima.dao"})  //只要com.itheima.config包扫到了就行,三个包可以合并写成com.itheima
public class SpringConfig {
}

3.6 注解开发为第三方 Bean 注入资源 🍐

3.6.1 「注解开发为第三方 Bean 注入资源」核心问题&答案

问题

  1. 配置类中如何注入简单类型数据,如何注入引用类型数据?

点击查看答案

  • @Value("xxx") 注入简单类型 👈
  • 引用类型注入只需要为 bean 定义方法设置形参即可,容器会根据类型自动装配对象

3.6.2 简单类型依赖注入

点击查看代码

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对象,添加到IOC容器中
    @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }
}

说明:如果@Value()中使用了 EL 表达式读取 properties 属性文件中的内容,那么就需要加载 properties 属性文件。

3.6.3 引用类型依赖注入

点击查看代码

//Spring会自动从IOC容器中找到BookDao对象赋值给参数bookDao变量,如果没有就会报错。
@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 定义方法设置形参即可,容器会根据类型自动装配对象

3.7 第三方 Bean 注入练习 ✏️

10 分钟

3.7 .0「第三方 Bean 注入」目的

熟悉第三方 Bean 注入到 IoC 容器中

3.7 .1「第三方 Bean 注入」需求&效果

从 Ioc 容器中,按类型获取 Bean 并且打印在控制台

3.7 .2「第三方 Bean 注入」步鄹

  • 下载飞秋的 spring02-共享资料中的 spring_14_annotation_third_bean_managertest 压缩包
  • 导入到项目中
  • 查看项目中的 todo 提示
  • 然后配置加载 DataSource,最后运行 app 主类,将数据库中的数据打印在控制台
  • 截图发到飞秋群中

3.8 注解开发总结

image-20210730113548708

4. Spring 整合其他技术

4.1 Spring 整合 mybatis ❤️ ✏️

7 分钟

4.1.1 「Spring 整合 mybatis」核心问题&答案

问题

  1. Mybatis 进行数据层操作的核心对象是谁?
  2. Spring 整合 mybatis 需要管理配置哪两个 Bean,这两个 Bean 作用分别是什么?

4.1.2 MyBatis 程序核心对象分析

点击查看MyBatis 程序核心对象分析

image-20210730114303147

整合 MyBatis 思路

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

image-20210730114342060

  • 使用 MapperScannerConfigurer 加载 Dao 接口,创建代理对象保存到 IOC 容器中

image-20210730114356175

4.1.2 代码实现

【前置工作】
  1. 准备数据库数据和创建 domain 下的 Account 类
  2. 在 pom.xml 中添加 spring-context、druid、mybatis、mysql-connector-java 等基础依赖。
  3. 准备 service 和 dao 层基础代码
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  `money` double(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of account
-- ----------------------------
INSERT INTO `account` VALUES ('1', '张三', '2000.00');
INSERT INTO `account` VALUES ('2', '李四', '6000.00');
// domain包下
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 +
                '}';
    }
}
// service包下
public interface AccountService {

    void save(Account account);

    void delete(Integer id);

    void update(Account account);

    List<Account> findAll();

    Account findById(Integer id);

}
// service/impl包下
@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();
    }
}
// dao包下
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);
}
【第一步】导入 Spring 整合 Mybatis 依赖
<!-- 连接池 -->
 <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.16</version>
</dependency>
<!-- mybaits -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.6</version>
    </dependency>
<!-- mysql驱动 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
    </dependency>
<!--spring操作jdbc的依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.10.RELEASE</version>
</dependency>
<!--spring操作mybaits的依赖  注意版本不要改-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.0</version>
</dependency>
【第二步】创建 JdbcConfig 配置 DataSource 数据源
  • properties 文件中配置数据源信息
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?useSSL=false
jdbc.username=root
jdbc.password=root
  • JdbcConfig 配置 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;
    }
}
【第三步】创建 MybatisConfig 整合 mybatis
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;
    }
}
【第四步】创建 SpringConfig 主配置类进行包扫描和加载其他配置类
@Configuration
@ComponentScan("com.itheima")
//@PropertySource:加载类路径jdbc.properties文件
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}
【第五步】定义测试类进行测试
public class App {
    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);
    }
}

4.2 Spring 整合 Junit 单元测试❤️ ✏️

4.2.1 「Spring 整合 Junit 单元测试」核心问题&答案

问题

  1. Spring 整合 Junit 的两个注解作用分别是什么?

点击查看代码

//使用Spring整合Junit专用的类加载器
@RunWith(SpringJUnit4ClassRunner.class)
//【加载配置文件或者配置类
@ContextConfiguration(classes = {SpringConfig.class}) //加载配置类

【第一步】导入整合的依赖坐标 spring-test

<!--junit-->
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>
</dependency>
<!--spring整合junit-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>5.1.9.RELEASE</version>
</dependency>

【第三步】使用 Spring 整合 Junit 专用的类加载器以及加载配置文件或者配置类

//【第二步】使用Spring整合Junit专用的类加载器
@RunWith(SpringJUnit4ClassRunner.class)
//【第三步】加载配置文件或者配置类
@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());
    }
}

注意:junit 的依赖至少要是 4.12 版本,可以是 4.13 等版本,否则出现如下异常:

image-20200831155517797

用心去做高质量的内容网站,欢迎 star ⭐ 让更多人发现