四、Spring对IoC的实现

1.IoC 控制反转

  • 控制反转是一种思想。
  • 控制反转是为了降低程序耦合度,提高程序扩展力,达到OCP原则,达到DIP原则。
  • 控制反转,反转的是什么?
    • 将对象的创建权利交出去,交给第三方容器负责。
    • 将对象和对象之间关系的维护权交出去,交给第三方容器负责。
  • 控制反转这种思想如何实现呢?
    • DI(Dependency Injection):依赖注入

2.依赖注入

依赖注入实现了控制反转的思想。
Spring通过依赖注入的方式来完成Bean管理的。
Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。

依赖注入:

  • 依赖指的是对象和对象之间的关联关系。
  • 注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。

依赖注入常见的实现方式包括两种:

  • 第一种:set注入
  • 第二种:构造注入

set注入和构造注入的时机是不同的。set注入是调用set方法,此时对象早已创建出来了。而构造注入调用的是构造方法,是在对象创建的时刻进行注入。

2.1 set注入

set注入,基于set方法实现的,底层会通过反射机制调用属性对应的set方法然后给属性赋值。这种方式要求属性必须对外提供set方法。

通过UserService调用UserDao里面的方法

package com.powernode.spring6.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * bean
 */
public class UserDao {

    // 记录日志
    private static final Logger logger = LoggerFactory.getLogger(UserDao.class);

    public void insert(){
        logger.info("数据库正在保存用户信息");
    }
}
package com.powernode.spring6.service;

import com.powernode.spring6.dao.UserDao;

/**
 * bean
 */
public class UserService {

    private UserDao userDao;

    // set注入,必须要提供一个set方法
    // Spring容器会调用这个set方法,来给userDao属性赋值
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void savaUser(){
        // 调用userDao的insert()方法
        userDao.insert();
    }
}

spring配置文件中配置

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

    <!--配置dao-->
    <bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>
    <!--配置service-->
    <bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
        <!--Spring调用对应的set方法,需要配置property标签-->
        <!--name属性指定值:set方法的方法名去掉set,剩下的单词首字母小写-->
        <!--ref:引用,ref后面指定的是要注入的bean的id-->
        <property name="userDao" ref="userDaoBean"/>
    </bean>
</beans>

测试程序

package com.powernode.spring6.test;

import com.powernode.spring6.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringDITest {
    @Test
    public void testSetDI(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = applicationContext.getBean("userServiceBean", UserService.class);
        userService.savaUser();
    }
}

实现原理:
通过property标签获取到属性名:userDao
通过属性名推断出set方法名:setUserDao
通过反射机制调用setUserDao()方法给属性赋值

property标签的name是属性名,set方法的方法名去掉set,剩下的单词首字母小写。
property标签的ref是要注入的bean对象的id。(通过ref属性来完成bean的装配,这是bean最简单的一种装配方式。装配指的是:创建系统组件之间关联的动作)

总结:set注入的核心实现原理:通过反射机制调用set方法来给属性赋值,让两个对象之间产生关系。

2.2 构造注入

核心原理:通过调用构造方法来给属性赋值。

package com.powernode.spring6.service;

import com.powernode.spring6.dao.UserDao;

/**
 * bean
 */
public class UserService {

    private UserDao userDao;

	// 通过反射机制调用构造方法给属性赋值
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public void savaUser(){
        // 调用userDao的insert()方法
        userDao.insert();
    }
}

spring配置文件中配置

<?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">
    <!--配置dao-->
    <bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>
    <!--配置service-->
    <bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
        <!--构造注入-->
        <!--
            index属性指定参数下标,第一个参数是0,第二个参数是1,...
            ref属性用来指定要注入的bean的id
        -->
        <!--指定构造方法的第一个参数,下标是0-->
        <constructor-arg index="0" ref="userDaoBean"/>
    </bean>
    
    <bean id="userServiceBean2" class="com.powernode.spring6.service.UserService">
        <!--根据参数构造方法的名字注入-->
        <constructor-arg name="userDao" ref="userDaoBean"/>
    </bean>
    
    <bean id="userServiceBean3" class="com.powernode.spring6.service.UserService">
        <!--不指定下标,也不指定参数名,spring自己做类型匹配-->
        <!--这种方法实际上是根据类型进行注入的,spring会自动根据类型来判断把ref注入给哪个参数-->
        <constructor-arg ref="userDaoBean"/>
    </bean>
</beans>

通过构造方法注入的时候:

  • 可以通过下标
  • 可以通过参数名
  • 也可以不指定下标和参数名,可以类型自动推断。

3 set注入专题

3.1 注入外部Bean

<!--声明Bean-->
<bean id="orderDaoBean" class="com.powernode.spring6.dao.OrderDao"/>
<bean id="orderServiceBean" class="com.powernode.spring6.service.OrderService">
    <!--使用ref引入,注入外部Bean-->
    <property name="orderDao" ref="orderDaoBean"/>
</bean>

外部Bean的特点:bean定义到外面,在property标签中使用ref属性进行注入。通常这种方式是常用。

3.2 注入内部Bean

内部Bean的方式:在bean标签中嵌套bean标签。

<bean id="orderServiceBean2" class="com.powernode.spring6.service.OrderService">
    <property name="orderDao">
        <!--property标签使用嵌套的bean标签,内部bean-->
        <bean class="com.powernode.spring6.dao.OrderDao"/>
    </property>
</bean>

这种方式很少用

3.3 注入简单类型

一个普通的java类

package com.powernode.spring6.bean;

public class User {
    private String username;
    private String password;
    private int age;
    // 省略set,toString方法
}
<!--注入简单类型-->
<bean id="userBean" class="com.powernode.spring6.bean.User">
    <!--给简单类型赋值,不能使用ref,需要使用value-->
    <property name="username" value="张三"/>
    <property name="password" value="123"/>
    <property name="age" value="20"/>
</bean>

需要特别注意:如果给简单类型赋值,使用value属性或value标签。而不是ref。

Spring的BeanUtils类源码

	public static boolean isSimpleProperty(Class<?> type) {
        Assert.notNull(type, "'type' must not be null");
        return isSimpleValueType(type) || type.isArray() && isSimpleValueType(type.getComponentType());
    }

    public static boolean isSimpleValueType(Class<?> type) {
		return (Void.class != type && void.class != type &&
				(ClassUtils.isPrimitiveOrWrapper(type) ||
				Enum.class.isAssignableFrom(type) ||
				CharSequence.class.isAssignableFrom(type) ||
				Number.class.isAssignableFrom(type) ||
				Date.class.isAssignableFrom(type) ||
				Temporal.class.isAssignableFrom(type) ||
				URI.class == type ||
				URL.class == type ||
				Locale.class == type ||
				Class.class == type));
	}

通过源码分析得知,简单类型包括:

  • 基本数据类型
  • 基本数据类型对应的包装类
  • String或其他的CharSequence子类
  • Number子类
  • Date子类
  • Enum子类
  • URI
  • URL
  • Temporal子类
  • Locale
  • Class
  • 另外还包括以上简单值类型对应的数组类型。

需要注意的是:

  • 如果把Date当做简单类型的话,日期字符串格式不能随便写。格式必须符合Date的toString()方法格式Thu Mar 02 18:06:45 HKT 2023。显然这就比较鸡肋了。如果我们提供一个这样的日期字符串:2010-10-11,在这里是无法赋值给Date类型的属性的。一般不会把Date当作简单类型,虽然它是简单类型,一般会采用ref给Date类型的属性赋值
  • spring6之后,当注入的是URL,那么这个url字符串是会进行有效性检测的。如果是一个存在的url,那就没问题。如果不存在则报错。

经典案例:给数据源的属性注入值:

假设我们现在要自己手写一个数据源,所有的数据源都要实现javax.sql.DataSource接口,并且数据源中应该有连接数据库的信息,例如:driver、url、username、password等。

package com.powernode.spring6.jdbc;

/**
 * 所有的数据源都要实现java规范:javax.sql.DataSource
 * 什么是数据源:能够提供Connection对象的,都是数据源
 */
public class MyDataSource implements DataSource {
    // 把数据源交给Spring容器来管理
    private String driver;
    private String url;
    private String username;
    private String password;
    @Override
    public Connection getConnection() throws SQLException {
        // 获取数据库连接对象的时候需要4个信息:driver url username password
        return null;
    }
    // 省略接口的其他方法
    // 省略driver url username password的set方法
}
<?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">

	<!--Spring管理数据源-->
    <bean id="myDataSource" class="com.powernode.spring6.jdbc.MyDataSource">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring6"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
</beans>

测试

package com.powernode.spring6.test;
public class SpringSetDITest {
	@Test
    public void testMyDataSource(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
        MyDataSource myDataSource = applicationContext.getBean("myDataSource", MyDataSource.class);
        System.out.println(myDataSource);
    }
}

输出

MyDataSource{driver='com.mysql.cj.jdbc.Driver', url='jdbc:mysql://localhost:3306/spring6', username='root', password='root'}

3.4 级联属性赋值(了解)

    <bean id="clazzBean" class="com.powernode.spring6.beans.Clazz"/>

    <bean id="student" class="com.powernode.spring6.beans.Student">
        <property name="name" value="张三"/>

        <!--要点1:以下两行配置的顺序不能颠倒-->
        <property name="clazz" ref="clazzBean"/>
        <!--要点2:clazz属性必须还要有getter方法-->
        <property name="clazz.name" value="高三一班"/>
    </bean>
</beans>

3.5 注入数组

当数组中的元素是简单类型:
private String[] username;

<bean id="user" class="com.powernode.spring6.beans.User">
	<!--数组属性中的元素类型是String简单类型-->
    <property name="username">
        <array>
            <value>张三</value>
            <value>李四</value>
            <value>王五</value>
        </array>
    </property>
 </bean>

当数组中的元素是非简单类型:

<bean id="goods1" class="com.powernode.spring6.beans.Goods">
    <property name="name" value="西瓜"/>
</bean>

<bean id="goods2" class="com.powernode.spring6.beans.Goods">
    <property name="name" value="苹果"/>
</bean>

<bean id="order" class="com.powernode.spring6.beans.Order">
    <property name="goods">
        <array>
            <!--这里使用ref标签即可-->
            <ref bean="goods1"/>
            <ref bean="goods2"/>
        </array>
    </property>
</bean>

要点:

  • 如果数组中是简单类型,使用value标签。
  • 如果数组中是非简单类型,使用ref标签

3.6 注入List集合和Set集合

List集合:有序可重复
Set集合:无序不可重复

<bean id="personBean" class="com.powernode.spring6.bean.Person">
        <property name="names">
            <list>
                <value>张三</value>
                <value>李四</value>
                <value>李四</value>
            </list>
        </property>
        
        <property name="adds">
            <set>
                <value>北京</value>
                <value>深圳</value>
            </set>
        </property>
</bean>

注入List集合的时候使用list标签,如果List集合中是简单类型使用value标签,反之使用ref标签。
注入Set集合的时候使用set标签 , 如果Set集合中是简单类型使用value标签,反之使用ref标签

3.7 注入Map集合

<bean id="personBean" class="com.powernode.spring6.bean.Person">
      <property name="phones">
          <!--注入Map集合-->
          <map>
              <!--如果key和value是简单类型用key,value-->
              <entry key="1" value="110"/>
              <entry key="2" value="120"/>
              <!--如果key和value不是简单类型用key-ref,value-ref-->
              <!--<entry key-ref="" value-ref=""/>-->
          </map>
      </property>
</bean>

使用<map>标签
如果key是简单类型,使用 key 属性,反之使用 key-ref 属性。
如果value是简单类型,使用 value 属性,反之使用 value-ref 属性

3.8 注入Properties

Properties本质上也是一个Map集合
java.util.Properties继承java.util.Hashtable,Hashtable实现了Map接口
虽然Properties也是一个Map集合,和Map的注入方式有点像,但是不同
Properties的key和value只能是String类型

<bean id="personBean" class="com.powernode.spring6.bean.Person">
      <!--注入Properties属性类对象-->
      <property name="properties">
          <props>
              <prop key="driver">com.mysql.cj.jdbc.Driver</prop>
              <prop key="url">jdbc:mysql://localhost:3306/spring6</prop>
              <prop key="username">root</prop>
              <prop key="password">root</prop>
          </props>
      </property>
</bean>

使用<props>标签嵌套<prop>标签完成。

3.9 注入null和空字符串

<!--注入null和空字符串-->
<bean id="userBean2" class="com.powernode.spring6.bean.User">
    <!--不给属性注入,默认值就是null-->
    <!--<property name="username" value="张三"/>-->
    <!--这不是注入null,只是注入了"null"字符串-->
    <!--<property name="username" value="null"/>-->
    <!--手动注入null-->
    <!--<property name="username">
        <null/>
    </property>-->

    <!--注入空字符串-->
    <!--<property name="username" value=""/>-->
    <!--注入空字符串-->
    <property name="username">
        <value/>
    </property>
    <property name="password" value="123"/>
    <property name="age" value="20"/>
</bean>

注入空字符串使用:<value/> 或者 value=“”
注入null使用:<null/> 或者 不为该属性赋值

3.10 注入的值中含有特殊符号

XML中有5个特殊字符,分别是:<、>、'、"、&
以上5个特殊符号在XML中会被特殊对待,会被当做XML语法的一部分进行解析,如果这些特殊符号直接出现在注入的字符串当中,会报错。

解决方案包括两种:
第一种:特殊符号使用转义字符代替。
第二种:将含有特殊符号的字符串放到:<![CDATA[]]> 当中。因为放在CDATA区中的数据不会被XML文件解析器解析。

5个特殊字符对应的转义字符分别是:

特殊字符转义字符
>&gt;
<&lt;
&apos;
"&quot;
&&amp;
<bean id="mathBean" class="com.powernode.spring6.bean.MathBean">
   <!--第一种方案:使用实体符号代替特殊符号-->
    <!--<property name="result" value="2 &lt; 3"/>-->

    <!--第二种方案:使用<![CDATA[]]>-->
    <property name="result">
        <!--只能使用value标签-->
        <value><![CDATA[2 < 3]]></value>
    </property>
</bean>

使用CDATA时,不能使用value属性,只能使用value标签。

4 p命名空间注入

目的:简化配置。
使用p命名空间注入的前提条件包括两个:
第一:在XML头部信息中添加p命名空间的配置信息:xmlns:p=“http://www.springframework.org/schema/p”
第二:p命名空间注入是基于setter方法的,所以需要对应的属性提供setter方法。

package com.powernode.spring6.bean;

import java.util.Date;

public class Dog {
    // 简单类型
    private String name;
    private int age;
    // 非简单类型,虽然Date是简单类型,当作非简单类型看待
    private Date birth;
    // 省略set、toString方法
<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--在spring的配置文件头部添加p命名空间 xmlns:p="http://www.springframework.org/schema/p"-->
    <!--使用 p:属性名 = "属性值"-->
    <bean id="dogBean" class="com.powernode.spring6.bean.Dog" p:name="张三" p:age="3" p:birth-ref="birthBean"/>
    <!--获取系统当前时间-->
    <bean id="birthBean" class="java.util.Date"/>
</beans>

测试

@Test
public void testP(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-p.xml");
    Dog dogBean = applicationContext.getBean("dogBean", Dog.class);
    System.out.println(dogBean);
}

p命名空间实际上是对set注入的简化。

5.c命名空间注入

c命名空间是简化构造方法注入的。
使用c命名空间的两个前提条件:
第一:需要在xml配置文件头部添加信息:xmlns:c=“http://www.springframework.org/schema/c”
第二:需要提供构造方法。

Dog类添加构造方式

<?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:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--在spring的配置文件头部添加c命名空间 xmlns:c="http://www.springframework.org/schema/c"-->
    <!--使用 下标方式 c:_0 = "属性值"-->
    <!--使用 参数名方式 c:name = "属性值"-->
    <bean id="dogBean" class="com.powernode.spring6.bean.Dog" c:name="张三" c:age="3" c:birth-ref="birthBean"/>
    <!--获取系统当前时间-->
    <bean id="birthBean" class="java.util.Date"/>
</beans>

c命名空间是依靠构造方法的。
不管是p命名空间还是c命名空间,注入的时候都可以注入简单类型以及非简单类型。

6 util命名空间

使用util命名空间可以让配置复用。
使用util命名空间的前提是:在spring配置文件头部添加配置信息。
xmlns:util=“http://www.springframework.org/schema/util”
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd

假设有两个自己定义的数据源MyDataSource1和MyDataSource2

package com.powernode.spring6.jdbc;
public class MyDataSource1 implements DataSource {
    // 把数据源交给Spring容器来管理
    // Properties属性类对象,这是一个Map集合,key和value都是String类型
    private Properties properties;

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    // 省略接口方法和toString方法
package com.powernode.spring6.jdbc;
public class MyDataSource2 implements DataSource {
    private Properties properties;

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    // 省略接口方法和toString方法
<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <!--引入util命名空间
    在spring的配置文件头部添加
    xmlns:util="http://www.springframework.org/schema/util"
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
    -->
    <util:properties id="prop">
        <prop key="driver">com.mysql.cj.jdbc.Driver</prop>
        <prop key="url">jdbc:mysql://localhost:3306/spring6</prop>
        <prop key="username">root</prop>
        <prop key="password">root</prop>
    </util:properties>

    <!--数据源1-->
    <bean id="myDataSource1" class="com.powernode.spring6.jdbc.MyDataSource1">
        <property name="properties" ref="prop"/>
    </bean>
    <!--数据源2-->
    <bean id="myDataSource2" class="com.powernode.spring6.jdbc.MyDataSource2">
        <property name="properties" ref="prop"/>
    </bean>
</beans>

测试

@Test
    public void testUtil(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-util.xml");
        MyDataSource1 myDataSource1 = applicationContext.getBean("myDataSource1", MyDataSource1.class);
        MyDataSource2 myDataSource2 = applicationContext.getBean("myDataSource2", MyDataSource2.class);
        System.out.println(myDataSource1);
        System.out.println(myDataSource2);
    }

输出

MyDataSource1{properties={password=root, driver=com.mysql.cj.jdbc.Driver, url=jdbc:mysql://localhost:3306/spring6, username=root}}
MyDataSource2{properties={password=root, driver=com.mysql.cj.jdbc.Driver, url=jdbc:mysql://localhost:3306/spring6, username=root}}

7 基于XML的自动装配

Spring还可以完成自动化的注入,自动化注入又被称为自动装配。它可以根据名字进行自动装配,也可以根据类型进行自动装配。

7.1 根据名称自动装配

package com.powernode.spring6.dao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class OrderDao {
    private static final Logger logger = LoggerFactory.getLogger(OrderDao.class);

    public void insert(){
        logger.info("订单正在生成...");
    }
}
package com.powernode.spring6.service;
import com.powernode.spring6.dao.OrderDao;
public class OrderService {
    private OrderDao orderDao;

    // 通过set方法给属性赋值
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
    /**
     * 生成订单的业务方法
     */
    public void generate(){
        orderDao.insert();
    }
}
<?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">

    <!--根据名字进行自动装配-->
    <!--自动装配也是基于set方法实现的-->
    <bean id="orderService" class="com.powernode.spring6.service.OrderService" autowire="byName"/>
    <!--id也叫做bean的名称-->
    <!--根据名字进行自动装配的时候,被注入的对象的bean的id不能随便写,set方法的方法名去掉set,剩下单词首字母小写-->
    <bean id="orderDao" class="com.powernode.spring6.dao.OrderDao"/>
</beans>

如果根据名称装配(byName),底层会调用set方法进行注入。
例如:setOrderDao() 对应的名字是orderDao,setPassword()对应的名字是password

7.2 根据类型自动装配

<!--根据类型进行自动装配-->
<!--自动装配是基于set方法实现的-->
<bean id="orderService" class="com.powernode.spring6.service.OrderService" autowire="byType"/>
<!--根据类型进行自动装配的时候,在有效得到配置文件中,某种类型的实例只能有一个-->
<bean class="com.powernode.spring6.dao.OrderDao"/>

无论是byName还是byType,在装配的时候都是基于set方法的。所以set方法是必须要提供的。提供构造方法是不行的

8 Spring引入外部属性配置文件

在类路径下新建jdbc.properties文件,并配置信息。

jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring6
jdbc.username=root
jdbc.password=root

写一个数据源类,提供相关属性。

package com.powernode.spring6.jdbc;
public class MyDataSource implements DataSource {
    // 把数据源交给Spring容器来管理
    private String driver;
    private String url;
    private String username;
    private String password;
    // 省略set、toString方法和接口方法

在spring配置文件中引入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>
    <!--引入外部properties文件
        引入context命名空间
        使用context:property-placeholder标签的location属性来指定属性配置文件的路径
            location默认从类的根路径下开始加载资源
    -->
    <context:property-placeholder location="jdbc.properties"/>
    <!--配置数据源-->
    <bean id="myDataSource" class="com.powernode.spring6.jdbc.MyDataSource">
        <!--取值:使用${key}-->
        <property name="driver" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

测试程序

@Test
public void testProperties(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-properties.xml");
    MyDataSource myDataSource = applicationContext.getBean("myDataSource", MyDataSource.class);
    System.out.println(myDataSource);
}

输出

MyDataSource{driver='com.mysql.cj.jdbc.Driver', url='jdbc:mysql://localhost:3306/spring6', username='root', password='root'}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值