Spring(三)

文章详细介绍了如何使用Spring管理第三方bean,以Druid和C3P0数据源为例,展示了配置管理过程。同时,讲解了如何加载properties文件,优化第三方bean属性,以及读取单个属性的方法。此外,文章还探讨了核心容器的概念,包括容器的创建、bean的获取方式、容器类层次结构以及BeanFactory的使用,总结了容器和bean的相关知识。
摘要由CSDN通过智能技术生成

目录

五.IOC/DI配置管理第三方bean

5.1 案例:数据源对象管理

5.1.1 环境准备

5.1.2 实现Druid管理

5.1.3 实现C3P0管理

5.2 加载properties文件

5.2.1 第三方bean属性优化

5.2.2 读取单个属性

六. 核心容器

6.1 环境准备

6.2 容器

6.2.1 容器的创建方式

6.2.2 Bean的三种获取方式

6.2.3 容器类层次结构

6.2.4 BeanFactory的使用

6.3 核心容器总结

6.3.1 容器相关

6.3.2 bean相关

6.3.3 依赖注入相关


五.IOC/DI配置管理第三方bean

前面所讲的知识点都是基于我们自己写的类,现在如果有需求让我们去管理第三方jar包中的类,该如何管理?

5.1 案例:数据源对象管理

接下来通过一个案例来学习下对于第三方bean该如何进行配置管理。

以后我们会用到很多第三方的bean,本次案例将使用咱们前面提到过的数据源Druid(德鲁伊)C3P0来配置学习下。

5.1.1 环境准备

学习之前,先来准备下案例环境:

  • 创建一个Maven项目

  • pom.xml添加依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
    </dependencies>
  • resources下添加spring的配置文件applicationContext.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">
    ​
    </beans>
  • 编写一个运行类App

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

5.1.2 实现Druid管理

步骤1:导入druid的依赖

pom.xml中添加依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.16</version>
</dependency>

步骤2:配置第三方bean

在applicationContext.xml配置文件中添加DruidDataSource的配置

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

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

步骤4:运行程序

打印如下结果: 说明第三方bean对象已经被spring的IOC容器进行管理

5.1.3 实现C3P0管理

步骤1:导入C3P0的依赖

pom.xml中添加依赖

<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>

步骤2:配置第三方bean

在applicationContext.xml配置文件中添加配置

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

==注意:==

  • ComboPooledDataSource的属性是通过setter方式进行注入

  • 想注入属性就需要在ComboPooledDataSource类或其上层类中有提供属性对应的setter方法

  • C3P0的四个属性和Druid的四个属性是不一样的

步骤3:运行程序

程序会报错,错误如下

报的错为==ClassNotFoundException==,翻译出来是类没有发现的异常,具体的类为com.mysql.jdbc.Driver。错误的原因是缺少mysql的驱动包。

分析出错误的原因,具体的解决方案就比较简单,只需要在pom.xml把驱动包引入即可。

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

添加完mysql的驱动包以后,再次运行App,就可以打印出结果:

注意:

  • 数据连接池在配置属性的时候,除了可以注入数据库连接四要素外还可以配置很多其他的属性,具体都有哪些属性用到的时候再去查,一般配置基础的四个,其他都有自己的默认值

  • Druid和C3P0在没有导入mysql驱动包的前提下,一个没报错一个报错,说明Druid在初始化的时候没有去加载驱动,而C3P0刚好相反

  • Druid程序运行虽然没有报错,但是当调用DruidDataSource的getConnection()方法获取连接的时候,也会报找不到驱动类的错误

5.2 加载properties文件

上节中我们已经完成两个数据源druidC3P0的配置,但是其中包含了一些问题,我们来分析下:

  • 这两个数据源中都使用到了一些固定的常量如数据库连接四要素,把这些值写在Spring的配置文件中不利于后期维护

  • 需要将这些值提取到一个外部的properties配置文件中

  • Spring框架如何从配置文件中读取属性值来配置就是接下来要解决的问题。

问题提出来后,具体该如何实现?

5.2.1 第三方bean属性优化

1. 实现思路

需求:将数据库连接四要素提取到properties配置文件,spring来加载配置信息并使用这些信息来完成属性注入。

1.在resources下创建一个jdbc.properties(文件的名称可以任意)

2.将数据库连接四要素配置到配置文件中

3.在Spring的配置文件中加载properties文件

4.使用加载到的值实现属性注入

其中第3,4步骤是需要大家重点关注,具体是如何实现。

2. 实现步骤

步骤1:准备properties配置文件

resources下创建一个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:开启context命名空间

在applicationContext.xml中开context命名空间

<?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配置文件

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

步骤4:完成属性注入

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

<?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配置文件中的内容就已经完成。

5.2.2 读取单个属性

1. 实现思路

对于上面的案例,效果不是很明显,我们可以换个案例来演示下:

需求:从properties配置文件中读取key为name的值,并将其注入到BookDao中并在save方法中进行打印。

1.在项目中添加BookDao和BookDaoImpl类

2.为BookDaoImpl添加一个name属性并提供setter方法

3.在jdbc.properties中添加数据注入到bookDao中打印方便查询结果

4.在applicationContext.xml添加配置完成配置文件加载、属性注入(${key})

2. 实现步骤

步骤1:在项目中添对应的类

BookDao和BookDaoImpl类,并在BookDaoImpl类中添加name属性与setter方法

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依赖注入:

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

步骤3:运行程序

在App类中,从IOC容器中获取bookDao对象,调用方法,查看值是否已经被获取到并打印控制台

public class App {
    public static void main(String[] args) throws Exception{
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
​
    }
}

结果如下图所示:

3. 注意事项

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

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

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

    username=root666

    2.在applicationContext.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"/>
        
        <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl">
            <property name="name" value="${username}"/>
        </bean>
    </beans>

    3.运行后,在控制台打印的却不是root666,而是自己电脑的用户名

    4.出现问题的原因是<context:property-placeholder/>标签会加载系统的环境变量,而且环境变量的值会被优先加载,如何查看系统的环境变量?

    public static void main(String[] args) throws Exception{
        Map<String, String> env = System.getenv();
        System.out.println(env);
    }

    大家可以自行运行,在打印出来的结果中会有一个USERNAME=XXX[自己电脑的用户名称]

    5.解决方案

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

    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

    username=root666

    2.修改applicationContext.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>    

    说明:

    • 方式一:可以实现,如果配置文件多的话,每个都需要配置

    • 方式二:*.properties代表所有以properties结尾的文件都会被加载,可以解决方式一的问题,但是不标准

    • 方式三:标准的写法,classpath:代表的是从根路径下开始查找,但是只能查询当前项目的根路径

    • 方式四:不仅可以加载当前项目还可以加载当前项目所依赖的所有项目的根路径下的properties配置文件

六. 核心容器

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

  • 如何创建容器?

  • 创建好容器后,如何从容器中获取bean对象?

  • 容器类的层次结构是什么?

  • BeanFactory是什么?

6.1 环境准备

在学习和解决上述问题之前,先来准备下案例环境:

  • 创建一个Maven项目

  • pom.xml添加Spring的依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
    </dependencies>
  • resources下添加applicationContext.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">
        <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
    </beans>
  • 添加BookDao和BookDaoImpl类

    public interface BookDao {
        public void save();
    }
    public class BookDaoImpl implements BookDao {
        public void save() {
            System.out.println("book dao save ..." );
        }
    }
  • 创建运行类App

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

最终创建好的项目结构如下:

6.2 容器

6.2.1 容器的创建方式

1.由类路径下的XML配置文件创建容器

案例中创建ApplicationContext的方式为:

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

2.由文件系统下的XML配置文件创建容器

ApplicationContext ctx = new FileSystemXmlApplicationContext("applicationContext.xml");

使用这种方式,运行,会出现如下错误:

从错误信息中能发现,这种方式是从项目路径下开始查找applicationContext.xml配置文件的,所以需要将其修改为:

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

说明:大家练习的时候,写自己的具体路径。

这种方式虽能实现,但是当项目的位置发生变化后,代码也需要跟着改,耦合度较高,不推荐使用。

6.2.2 Bean的三种获取方式

1.通过bean的id获取

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

这种方式存在的问题是每次获取的时候都需要进行类型转换,有没有更简单的方式呢?

方式二:通过bean的id+类型获取

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

这种方式可以解决类型强转问题,但是参数又多加了一个,相对来说没有简化多少。

方式三:通过bean的类型获取

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

这种方式就类似依赖注入中的按类型注入。必须要确保IOC容器中该类型对应的bean对象只能有一个。

6.2.3 容器类层次结构

(1)在IDEA中双击shift,输入BeanFactory

(2)点击进入BeanFactory类,ctrl+h,就能查看到如下结构的层次关系

从图中可以看出,容器类也是从无到有根据需要一层层叠加上来的,大家重点理解下这种设计思想。

6.2.4 BeanFactory的使用

使用BeanFactory来创建IOC容器的具体实现方式为:

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添加如下构造函数:

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要想成为延迟加载,只需要按照如下方式进行配置

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

6.3 核心容器总结

这节中没有新的知识点,只是对前面知识的一个大总结,共包含如下内容:

6.3.1 容器相关

  • BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载

  • ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载

  • ApplicationContext接口提供基础的bean操作相关方法,通过其他接口扩展其功能

  • ApplicationContext接口常用初始化类

    • ==ClassPathXmlApplicationContext(常用)==

    • FileSystemXmlApplicationContext

6.3.2 bean相关

其实整个配置中最常用的就两个属性==id==和==class==。

把scope、init-method、destroy-method框起来的原因是,后面注解在讲解的时候还会用到,所以大家对这三个属性关注下。

6.3.3 依赖注入相关

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

真滴book理喻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值