0


【Spring6】| Spring对IoC的实现(核心重点)

一:Spring对IoC的实现

前面我们已经学会了如何用spring创建管理对象,接下来就要学习如何让对象和对象产生关系,使用依赖注入!

1. IoC 控制反转

(1)控制反转是一种思想,一种新型的设计模式!

(2)控制反转是为了降低程序耦合度,提高程序扩展力,达到OCP原则,达到DIP原则。

(3)控制反转,反转的是什么?

①将对象的创建权利交出去,交给第三方容器负责。

②将对象和对象之间关系的维护权交出去,交给第三方容器负责。

(4)控制反转这种思想如何实现呢?

DI(Dependency Injection):依赖注入

2. 依赖注入

依赖注入实现了控制反转的思想!

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

依赖注入:

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

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

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

2.1 set注入

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

pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.bjpowernode</groupId>
    <artifactId>spring6-002-dependency-injection</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <!--配置多个仓库-->
    <repositories>
        <!--spring6里程碑的仓库-->
        <repository>
            <id>repository.spring.milestone</id>
            <name>Spring Milestone Repository</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

    <dependencies>
        <!--spring context依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.0-M2</version>
        </dependency>
        <!--单元测试依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--log4j2的依赖-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.19.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j2-impl</artifactId>
            <version>2.19.0</version>
        </dependency>
    </dependencies>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

</project>

log4j2.xml日志配置

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <loggers>
        <root level="DEBUG">
            <appender-ref ref="spring6log"/>
        </root>
    </loggers>

    <appenders>
        <console name="spring6log" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
        </console>
    </appenders>

</configuration>

UserDao类:连接数据库的操作

package com.bjpowernode.spring6.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserDao {
    // 一般声明为常量
   private static final Logger logger = LoggerFactory.getLogger(UserDao.class);
    // 使用日志进行打印,用System.out.println也可以
    public void insert(){
        logger.info("数据库正在保存用户信息!");
    }
}

UserService类:调用UserDao中的方法

①set注入的话,必须提供一个set方法;Spring容器会调用这个set方法,来给userDao属性赋值。

②这个set方法不符合javabean规范也可以,但是必须以set开头,例如:setUD也是可以的;这里我使用的是IDEA自动生成的符合javabean规范的。

package com.bjpowernode.spring6.service;

import com.bjpowernode.spring6.dao.UserDao;

public class UserService {
    private UserDao userDao;

    // set注入,必须提供一个set方法
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void saveUser(){
        // 调用UserDao保存用户信息
        userDao.insert();
    }
}

spring.xml配置

①配置userDaoBean和UserService,让spring管理这两个类。

②对于UserService,想让Spring调用对应的set方法,需要配置property标签

name属性值:set方法的方法名,去掉set,然后把剩下的单词首字母变小写
ref属性值:翻译为引用,英语单词references,后面指定的是要注入的bean的id

<?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 https://www.springframework.org/schema/util/spring-util.xsd">

     <!--配置dao-->
    <bean id="userDaoBean" class="com.bjpowernode.spring6.dao.UserDao"/>
     <!--配置service-->
    <bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService">
        <property name="userDao" ref="userDaoBean" />
    </bean>
</beans>

③另外,对于property标签来说,ref属性也可以采用标签的方式,但使用ref属性是多数的:

<bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
  <property name="userDao">
    <ref bean="userDaoBean"/>
  </property>
</bean>

编写测试类

package com.bjpowernode.spring6.test;

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

public class DITest {
    @Test
    public void testSetDI(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userServiceBean = applicationContext.getBean("userServiceBean", UserService.class);
        userServiceBean.saveUser();
    }
}

执行结果:

正常输出日志信息了,说明两个问题:

①spring正常创建UserDao和UserService对象了!

②spring关联了对象与对象之间的关系了!

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

2.2 构造注入

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

①set注入:是先创建对象,才能执行set方法,给属性赋值。

②构造注入:是在创建对象的同时,给属性赋值,时机是不同的。

在定义一个VipDao类

package com.bjpowernode.spring6.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class VipDao {
    private static final Logger logger = LoggerFactory.getLogger(VipDao.class);
    public void delete(){
        logger.info("正在删除信息!");
    }
}

ConstructService类

构造方法注入,必须要提供一个构造方法!

package com.bjpowernode.spring6.service;

import com.bjpowernode.spring6.dao.UserDao;
import com.bjpowernode.spring6.dao.VipDao;

public class ConstructService {
    private UserDao userDao;
    private VipDao vipDao;

    // 构造注入,必须有构造方法
    public ConstructService(UserDao userDao, VipDao vipDao) {
        this.userDao = userDao;
        this.vipDao = vipDao;
    }
    
    public void save(){
        userDao.insert();
        vipDao.delete();
    }
}

bean.xml配置

访问的方式有三种:使用的是constructor-arg标签

①第一种方式是根据下标index的方式,下标的顺序是构造方法参数的顺序。

②第二种方式是根据构造方法参数的名字name的方式。

③第三种方式是根据类型进行注入,不指定,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">

     <bean id="userDaoBean" class="com.bjpowernode.spring6.dao.UserDao"/>
     <bean id="vipDaoBean" class="com.bjpowernode.spring6.dao.VipDao"/>
     <bean id="constructServiceBean" class="com.bjpowernode.spring6.service.ConstructService">
         <!--第一种方式-->
          <constructor-arg index="0" ref="userDaoBean"/>
          <constructor-arg index="1" ref="vipDaoBean" />
          <!--第二种方式-->
          <constructor-arg name="userDao" ref="userDaoBean"/>
          <constructor-arg name="vipDao" ref="vipDaoBean"/>
          <!--第三种方式-->
          <constructor-arg ref="userDaoBean"/>
          <constructor-arg ref="vipDaoBean" />
     </bean>

</beans>

编写测试

package com.bjpowernode.spring6.test;

import com.bjpowernode.spring6.service.ConstructService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ConstructTest {
    @Test
    public void testConstructDI(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        ConstructService constructServiceBean = applicationContext.getBean("constructServiceBean", ConstructService.class);
        constructServiceBean.save();
    }
}

执行结果:

3. set注入专题

set注入和构造注入中,set注入用的比较多,所以下面就学习一下set注入的专题!

3.1 注入外部Bean

(1)在之前我们使用的案例一直就是注入外部Bean的方式!

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

<?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 https://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="userDaoBean" class="com.bjpowernode.spring6.dao.UserDao"/>
    <bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService">
        <property name="userDao" ref="userDaoBean" />
    </bean>
</beans>

3.2 注入内部Bean

内部Bean的方式:在bean标签中直接嵌套bean标签,不需要ref属性引入。

<?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 https://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService">
        <property name="userDao">
            <bean class="com.bjpowernode.spring6.dao.UserDao"/>
        </property>
    </bean>
</beans>

3.3 注入简单类型

(1)之前在进行注入的时候,对象的属性都是另一个对象;那如果对象的属性是int类型呢?也可以通过set注入的方式给该属性赋值,实际上只要能够调用set方法就可以给属性赋值。

(2)重点:如果给简单类型赋值,就不能使用ref属性,需要使用value属性

User类:定义了两个简单类型,写上set方法

package com.bjpowernode.spring6.bean;

public class User {
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

set-di.xm配置

注:既可以使用value标签的方式,也可以使用value属性的方式(常用)

<?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="userBean" class="com.bjpowernode.spring6.bean.User">
        <property name="age" value="18"/>
        <property name="name" value="张三"/>
    </bean>
</beans>

编写测试

package com.bjpowernode.spring6.test;

import com.bjpowernode.spring6.bean.User;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SetDITest {
    @Test
    public void testSimpleTypeSet(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");
        User user = applicationContext.getBean("userBean", User.class);
        System.out.println(user);
    }
}

执行结果:默认会调用toString方法

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

(3)那么简单类型包括哪些呢?可以通过Spring的源码来分析一下!

双击shift搜索BeanUtils类,ctrl+F12搜索isSimpleValueType方法,里面都是简单类型:

(4)这里重点说一下Date类型,如果硬要把Date类型当做简单类型,使用value赋值的话,这个日期的格式有要求:Thu Jan 12 21:05:49 CST 2023 ,所以在实际的开发中,我们一般采用ref属性的方式给Date类型的属性赋值!

(5)简单类型注入的经典案例:给数据源的属性注入值:

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

数据源MyDataSource

package com.bjpowernode.spring6.jdbc;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

public class MyDateSource implements DataSource {
    private String driver;
    private String url;
    private String username;
    private String password;

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "MyDateSource{" +
                "driver='" + driver + '\'' +
                ", url='" + url + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    @Override
    public Connection getConnection() throws SQLException {
        return null;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

spring-datasource.xml:使用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">
        
    <bean name="myDataSource" class="com.bjpowernode.spring6.jdbc.MyDateSource">
        <property name="driver" value="com.mysql.jdbc.driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring6"/>
        <property name="username" value="root"/>
        <property name="password" value="123"/>
    </bean>
</beans>

编写测试

package com.bjpowernode.spring6.test;

import com.bjpowernode.spring6.bean.User;
import com.bjpowernode.spring6.jdbc.MyDateSource;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SetDITest {
    @Test
    public void testMyDataSource(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-datasource.xml");
        MyDateSource myDataSource = applicationContext.getBean("myDataSource", MyDateSource.class);
        System.out.println(myDataSource);
    }

}

测试结果:成功注入连接数据库的信息

3.4 级联属性赋值(了解)

我们先回顾一下原来使用的注入方式,然后在使用级联属性赋值,进行对比!

clazz班级类

package com.bjpowernode.spring6.bean;

public class Clazz {
    // 班级名称
    private String name;

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

    @Override
    public String toString() {
        return "Clazz{" +
                "name='" + name + '\'' +
                '}';
    }
}

Student学生类

package com.bjpowernode.spring6.bean;

public class Student {
    // 学生姓名
    private String name;
    // 班级
    private Clazz clazz;

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

    public void setClazz(Clazz clazz) {
        this.clazz = clazz;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", clazz=" + clazz +
                '}';
    }
}

第一种:原来的注入方式

<?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 name="clazzBean" class="com.bjpowernode.spring6.bean.Clazz">
        <property name="name" value="高三一班"/>
    </bean>
    <bean name="studentBean" class="com.bjpowernode.spring6.bean.Student">
        <property name="name" value="张三"/>
        <property name="clazz" ref="clazzBean"/>
    </bean>
</beans>

第二种方式:级联注入方式

使用级联属性赋值需要注意两点:

①配置的顺序不能颠倒,先配置student在配置clazz

clazz属性必须提供getClazz()方法(所以要在Student类当中要增加getter方法)

<?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 name="studentBean" class="com.bjpowernode.spring6.bean.Student">
        <property name="name" value="张三"/>
        <property name="clazz" ref="clazzBean"/>
        <!--级联属性赋值-->
        <property name="clazz.name" value="高三一班"/>
    </bean>
    <bean name="clazzBean" class="com.bjpowernode.spring6.bean.Clazz" />
</beans>

执行结果:

3.5 注入数组

这里主要学习两种情况:数组中的元素是简单类型和当数组中的元素是非简单类型!

Woman类,作为非简单类型

package com.bjpowernode.spring6.bean;

public class Woman {
    private String name;

    @Override
    public String toString() {
        return "Woman{" +
                "name='" + name + '\'' +
                '}';
    }

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

QY类,里面包含简单类型和非简单类型的数组属性

package com.bjpowernode.spring6.bean;

import java.util.Arrays;

public class QY {
    // 简单类型的数组
    private String[] loves;
    // 非简单类型的数组
    private Woman[] women;

    @Override
    public String toString() {
        return "QY{" +
                "loves=" + Arrays.toString(loves) +
                ", women=" + Arrays.toString(women) +
                '}';
    }

    public void setLoves(String[] loves) {
        this.loves = loves;
    }

    public void setWomen(Woman[] women) {
        this.women = women;
    }
}

spring-array.xml配置

当属性是数组时,需要先使用一下array标签,在array标签中再写value和ref标签进行赋值!

<?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="w1" class="com.bjpowernode.spring6.bean.Woman">
        <property name="name" value="小花"/>
    </bean>
    <bean id="w2" class="com.bjpowernode.spring6.bean.Woman">
        <property name="name" value="小红"/>
    </bean>

    <!--简单类型-->
    <bean id="yqBean" class="com.bjpowernode.spring6.bean.QY">
        <!-- 注入简单类型-->
        <property name="loves">
            <array>
                <value>抽烟</value>
                <value>喝酒</value>
                <value>烫头</value>
            </array>
        </property>
        <!--注入非简单类型-->
        <property name="women" >
            <array>
               <ref bean="w1"/>
               <ref bean="w2"/>
            </array>
        </property>
    </bean>

</beans>

编写测试

package com.bjpowernode.spring6.test;

import com.bjpowernode.spring6.bean.Clazz;
import com.bjpowernode.spring6.bean.QY;
import com.bjpowernode.spring6.bean.Student;
import com.bjpowernode.spring6.bean.User;
import com.bjpowernode.spring6.jdbc.MyDateSource;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SetDITest {
    @Test
    public void testArraySet(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-array.xml");
        QY yqBean = applicationContext.getBean("yqBean", QY.class);
        System.out.println(yqBean);
    }

}

执行结果:

要点:

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

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

3.6 注入List集合和Set集合

Person类

package com.bjpowernode.spring6.bean;

import java.util.List;
import java.util.Set;

public class Person {
    // 注入List
    private List<String> names;
    // 注入Set集合
    private Set<String> addrs;

    @Override
    public String toString() {
        return "Person{" +
                "names=" + names +
                ", addrs=" + addrs +
                '}';
    }

    public void setNames(List<String> names) {
        this.names = names;
    }

    public void setAddrs(Set<String> addrs) {
        this.addrs = addrs;
    }
}

spring-collection.xml配置

如果是List集合或者Set集合的属性,需要先使用<list>标签和<set>标签,标签中再写value和ref标签进行赋值!

<?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="personBean" class="com.bjpowernode.spring6.bean.Person">
         <!--List集合-->
         <property name="names">
             <list>
                 <value>张三</value>
                 <value>李四</value>
                 <value>张三</value>
                 <value>王五</value>
             </list>
         </property>
         <!--Set集合-->
         <property name="addrs">
             <set>
                 <value>张三</value>
                 <value>李四</value>
                 <value>张三</value>
                 <value>王五</value>
             </set>
         </property>
     </bean>
</beans>

编写测试

package com.bjpowernode.spring6.test;

import com.bjpowernode.spring6.bean.*;
import com.bjpowernode.spring6.jdbc.MyDateSource;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SetDITest {
    @Test
    public void testCollectionSet(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-collection.xml");
        Person personBean = applicationContext.getBean("personBean", Person.class);
        System.out.println(personBean);
    }

}

执行结果:

从执行结果上看,可以得出:List集合是有序可重复、Set集合是无序不可重复!

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

3.7 注入Map和Properties集合

Properties集合本质上也是一个Map集合,但是Properties集合的key和value只能是String类型,并且注入的方式也是与Map集合不同的!

Man类

package com.bjpowernode.spring6.bean;

import java.util.Map;
import java.util.Properties;

public class Man {
    // 注入Map集合
    private Map<String,Integer> phones;
    // 注入Properties
    private Properties properties;

    @Override
    public String toString() {
        return "Man{" +
                "phones=" + phones +
                ", properties=" + properties +
                '}';
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public void setPhones(Map<String, Integer> phones) {
        this.phones = phones;
    }
}

spring-collection.xml配置

如果是Map集合的属性,使用map标签嵌套entry子标签(不使用ref和value标签了)

如果是Map集合的属性,使用props标签嵌套pro标签

<?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="manBean" class="com.bjpowernode.spring6.bean.Man">
        <!--Map集合-->
        <property name="phones">
            <map>
                <entry key="张三" value="123"/>
                <entry key="李四" value="456"/>
                <entry key="王五" value="789"/>
            </map>
        </property>
       <!-- Properties集合-->
        <property name="properties">
            <props>
                <prop key="driver">com.mysql.jdbc.driver</prop>
                <prop key="url">jdbc:mysql://localhost:3306/spring6</prop>
            </props>
        </property>
    </bean>

</beans>

执行结果:

要点:

对于Map集合使用<map>标签,对于Properties使用<props>标签嵌套<prop>标签完成。

如果key是简单类型,使用 key 属性,反之使用 key-ref 属性。

如果value是简单类型,使用 value 属性,反之使用 value-ref 属性。

3.8 注入null和空字符串

Cat类

package com.bjpowernode.spring6.bean;

public class Cat {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

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

    public void setAge(int age) {
        this.age = age;
    }
}

set-di.xml配置

①注入空字符串使用:<value/> 或者 value=""。

②注入null使用:<null/> 或者 不为该属性赋值。

<?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="carBean" class="com.bjpowernode.spring6.bean.Cat">
        <!--注入null-->
        <!--第一种方法:不为该属性赋值-->
        <property name="name" value="张三"/>
        <!--第二种方法:使用null标签,手动注入null-->
        <property name="name">
            <null/>
        </property>
        <property name="age" value="18"/>

       <!-- 注入空字符串-->
        <!--第一种方法-->
        <property name="name" value=""/>
        <!--第二种方法-->
        <property name="name">
            <value/>
        </property>
        <property name="age" value="20"/>
    </bean>

</beans>

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

(1)XML中有5个特殊字符,分别是:<、>、'、"、&

(2)以上5个特殊符号在XML中会被特殊对待,会被当做XML语法的一部分进行解析,如果这些特殊符号直接出现在注入的字符串当中,会报错。

Math类

package com.bjpowernode.spring6.bean;

public class Math {
    private String result;

    @Override
    public String toString() {
        return "Math{" +
                "result='" + result + '\'' +
                '}';
    }

    public void setResult(String result) {
        this.result = result;
    }
}

math.xml配置

解决方案包括两种:

第一种:特殊符号使用转义字符代替。

第二种:将含有特殊符号的字符串放到:<![CDATA[]]> 当中。因为放在CDATA区中的数据不会被XML文件解析器解析。

注:使用<![CDATA[]]>的方式只能使用value标签的形式,不能使用value属性!

注:<![CDATA[]]>是XML的语法,放在这里面的东西不会被XML解析器解析!

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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="mathBean" class="com.bjpowernode.spring6.bean.Math">
            <!--直接写2<3会报错-->
           <!-- <property name="result" value="2<3"/>-->
            <!--第一种解决方案:使用实体符号代替特殊符号-->
            <property name="result" value="2 &lt; 3"/>
            <!--第二种解决方案:<![CDATA[]]>-->
            <property name="result">
                <!--只能使用value标签-->
                <value><![CDATA[2<3]]></value>
            </property>

        </bean>
</beans>

4. p命名空间注入

(1)p命名空间是简化set方法注入的。

(2)使用p命名空间注入的前提条件包括两个:

第一:在XML头部信息中添加p命名空间的配置信息:xmlns:p="http://www.springframework.org/schema/p"

第二:p命名空间注入还是基于set注入的,只不过p命名空间注入可以让spring配置变的更加简单;所以需要对应的属性提供setter方法。

Dog类:提供了setter方法

package com.bjpowernode.spring6.bean;

import java.util.Date;

public class Dog {
    private String name;
    private int age;
    // 虽然简单类型,但是一般都是当做非简单类型对待
    private Date date;

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", date=" + date +
                '}';
    }
    
    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setDate(Date date) {
        this.date = date;
    }
}

spring-p.xml配置

①在spring的配置文件头部添加p命名空间。
②使用:在<bean>标签中的class属性后面直接使用,对于简单类型属性赋值 **p:属性名 = "属性值";对于非简单类型属性赋值p:属性名-ref = "属性值"**。

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

    <!--原来注入的方式-->
   <bean id="dogBean" class="com.bjpowernode.spring6.bean.Dog">
        <property name="name" value="大黄"/>
        <property name="age" value="3"/>
        <property name="date" ref="nowDate"/>
    </bean>
    <!--p命名注入方式-->
    <bean id="dogBean" class="com.bjpowernode.spring6.bean.Dog" p:name="大黄" p:age="3" p:date-ref="nowDate"/>
    <bean id="nowDate" class="java.util.Date"/>
</beans>

测试程序

package com.bjpowernode.spring6.test;

import com.bjpowernode.spring6.bean.Dog;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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

执行结果:

如果把setter方法注释掉,会报错

5. c命名空间注入

(1)c命名空间是简化构造方法注入的。

(2)使用c命名空间的两个前提条件:

①第一:需要在xml配置文件头部添加信息: xmlns:c="http://www.springframework.org/schema/c"

②第二:需要提供构造方法。

MyTime类:提供了构造方法

package com.bjpowernode.spring6.bean;

public class MyTime {
    private int year;
    private int month;
    private int day;

    public MyTime(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    @Override
    public String toString() {
        return "MyTime{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }
}

spring-c.xml配置

①在spring的配置文件头部添加c命名空间。
使用:c:_0 下标方式或者c:name 参数名方式。

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

    <!--原来注入的方式-->
    <bean id="myTimeBean" class="com.bjpowernode.spring6.bean.MyTime">
        <constructor-arg index="0" value="2022"/>
        <constructor-arg index="1" value="1"/>
        <constructor-arg index="2" value="14"/>
    </bean>

    <!--c命名注入方式-->
    <bean id="myTimeBean" class="com.bjpowernode.spring6.bean.MyTime" c:_0="2022" c:_1="1" c:_2="14" />

</beans>

测试程序

package com.bjpowernode.spring6.test;

import com.bjpowernode.spring6.bean.MyTime;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CTest {
    @Test
    public void testCDI(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-c.xml");
        MyTime myTimeBean = applicationContext.getBean("myTimeBean", MyTime.class);
        System.out.println(myTimeBean);

    }
}

执行结果:

如果把构造方法注释掉

注意:不管是p命名空间还是c命名空间,注入的时候都可以注入简单类型以及非简单类型。

6. util命名空间

(1)使用util命名空间可以让配置复用。

(2)使用util命名空间的前提是:在spring配置文件头部添加配置信息。如下:

(3)假设系统集成不同厂家的连接池,这里用自己写的数据源来代替;里面的连接数据库的配置实际上是相同的,所以我们就可以使用util命名空间进行配置复用!

数据源MyDataSource1

package com.bjpowernode.spring6.jdbc;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Properties;
import java.util.logging.Logger;

public class MyDateSource1 implements DataSource {
    // 连接数据库的信息,放到成员变量里
    /*private String driver;
    private String url;
    private String username;
    private String password;*/
    
    // 当然也可以放到一个Properties集合当中
    private Properties properties;

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "MyDateSource1{" +
                "properties=" + properties +
                '}';
    }

    @Override
    public Connection getConnection() throws SQLException {
        return null;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

spring-util.xml配置:未使用util命名空间

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

    <!--数据源1-->
    <bean id="ds1" class="com.bjpowernode.spring6.jdbc.MyDateSource1">
        <property name="properties">
            <props>
                <prop key="dirver">com.mysql.jdbc.Driver</prop>
                <prop key="url">jdbc:mysql://localhost:3306/spring6</prop>
                <prop key="username">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>
    <!--数据源2-->
    <bean id="ds2" class="com.bjpowernode.spring6.jdbc.MyDateSource2">
        <property name="properties">
            <props>
                <prop key="dirver">com.mysql.jdbc.Driver</prop>
                <prop key="url">jdbc:mysql://localhost:3306/spring6</prop>
                <prop key="username">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>
</beans>

spring-util.xml配置:使用util命名空间,把公共的配置使用util命名

使用util命名空间后,把重复的配置放到util:properties标签里面,并设置唯一标识id;后面如果想使用,直接使用ref属性直接引入id即可。

<?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命名-->
    <util:properties id="prop">
        <prop key="dirver">com.mysql.jdbc.Driver</prop>
        <prop key="url">jdbc:mysql://localhost:3306/spring6</prop>
        <prop key="username">root</prop>
        <prop key="password">123456</prop>
    </util:properties>

    <!--数据源1-->
    <bean id="ds1" class="com.bjpowernode.spring6.jdbc.MyDateSource1">
        <property name="properties" ref="prop" />
    </bean>
    <!--数据源2-->
    <bean id="ds2" class="com.bjpowernode.spring6.jdbc.MyDateSource2">
        <property name="properties" ref="prop"/>
    </bean>
</beans>

测试代码

package com.bjpowernode.spring6.test;

import com.bjpowernode.spring6.jdbc.MyDateSource1;
import com.bjpowernode.spring6.jdbc.MyDateSource2;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UtilTest {
    @Test
    public void testUtilTest(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-util.xml");
        MyDateSource1 ds1 = applicationContext.getBean("ds1", MyDateSource1.class);
        MyDateSource2 ds2 = applicationContext.getBean("ds2", MyDateSource2.class);
        System.out.println(ds1);
        System.out.println(ds2);
    }
}

执行结果:

实际上util命名空间主要是针对集合的:

7. 基于XML的自动装配(byName & byType)

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

UserDao类

package com.bjpowernode.spring6.dao;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UserDao {
   
   private static final Logger logger = LoggerFactory.getLogger(UserDao.class);

    public void insert(){
        logger.info("数据库正在保存用户信息!");
    }
}

UserDaoService类

package com.bjpowernode.spring6.service;

import com.bjpowernode.spring6.dao.UserDao;

public class UserService {
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void saveUser(){
        // 调用UserDao保存用户信息
        userDao.insert();
    }
}

7.1 根据名称(byName)自动装配

下面这个配置起到关键作用:

(1)UserService Bean中需要添加autowire="byName",表示通过名称进行装配。

(2)如果是正常的装配,UserDao的id随便写,只要和上面ref的值对应着就行!

(3)如果是自动装配,UserDao的id必须是UserService类中的UserDao属性对应的setUserDao(set方法)方法去掉前面的set,后面首字母变成小写的值:userDao!

(4)所以根据名称自动配置本质上也是set注入!

spring-autowire.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="userServiceBean" class="com.bjpowernode.spring6.service.UserService">
        <property name="userDao" ref="userDaoBean"/>
    </bean>
    <bean id="userDaoBean" class="com.bjpowernode.spring6.dao.UserDao"/>

    <!--根据名称自动装配-->
    <bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService" autowire="byName"/>
    <bean id="userDao" class="com.bjpowernode.spring6.dao.UserDao"/>
</beans>

编写测试

package com.bjpowernode.spring6.test;

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

public class AutowireTest {
    @Test
    public void testAutowireTest(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-autowire.xml");
        UserService userServiceBean = applicationContext.getBean("userServiceBean", UserService.class);
        userServiceBean.saveUser();
    }
}

执行结果:

正常执行,说明如果根据名称装配(byName),底层会调用set方法进行注入!例如:setAge() 对应的名字是age,setPassword()对应的名字是password,setEmail()对应的名字是email。

7.2 根据类型(byType)自动装配

(1)其实无论是根据名称自动装备byName还是根据类型制动装备byType,在装配的时候都是基于set方法的,所以set方法是必须要提供的!

(2)根据byType自动装配时,对于被注入的对象,只需要使用bean标签指定要注入的类型,不需要再指定id。

spring-autowire.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="userServiceBean" class="com.bjpowernode.spring6.service.UserService" autowire="byType"/>
    <bean class="com.bjpowernode.spring6.dao.UserDao"/>
</beans>

执行结果:

如果byType根据类型装配时,如果配置文件中有两个类型一样的bean会出现什么问题呢?

<?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-->
    <bean id="x" class="com.bjpowernode.spring6.dao.UserDao"/>
    <bean id="y" class="com.bjpowernode.spring6.dao.UserDao"/>
    <bean id="userServiceBean" class="com.bjpowernode.spring6.service.UserService" autowire="byType"/>
</beans>

执行结果:

测试结果说明了,当byType进行自动装配的时候,配置文件中某种类型的Bean必须是唯一的,不能出现多个!

8. Spring引入外部属性配置文件(使用context命名空间)

我们都知道编写数据源的时候是需要连接数据库的信息的,例如:driver、url、username password等信息。这些信息可以单独写到一个属性配置文件中吗?这样用户修改起来会更加的方便,当然是可以的,使用context命名空间!

第一步:写一个数据源类,提供相关属性

package com.bjpowernode.spring6.jdbc;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;

public class MyDateSource implements DataSource {
    private String driver;
    private String url;
    private String username;
    private String password;

    public void setDriver(String driver) {
        this.driver = driver;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "MyDateSource{" +
                "driver='" + driver + '\'' +
                ", url='" + url + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    @Override
    public Connection getConnection() throws SQLException {
        return null;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

第二步:在类路径下新建jdbc.properties文件,并配置信息

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/spring6
username=root
password=123456

第三步:在spring-properties.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>

第四步:在spring中配置使用jdbc.properties文件

第一步:引入context命名空间,前面已经引过了。

第二步:使用**context:property-placeholder标签的location**属性来指定属性配置文件的路径。 location默认从类的根路径下开始加载资源。

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

    <!--引入外部的properties文件-->
    <context:property-placeholder location="jdbc.properties"/>

    <bean id="dataSource" class="com.bjpowernode.spring6.jdbc.MyDateSource">
        <!--使用$元符号,${key}-->
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>
</beans>

测试程序:

package com.bjpowernode.spring6.test;

import com.bjpowernode.spring6.jdbc.MyDateSource;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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

执行结果:

这里username怎么不是我们配置文件里的?spring通过${}加载,默认是是先加载windows系统的环境变量!

怎么解决?一般在所有配置前面加上jdbc前缀

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring6
jdbc.username=root
jdbc.password=123456

执行结果:

标签: spring java 后端

本文转载自: https://blog.csdn.net/m0_61933976/article/details/128658072
版权归原作者 @每天都要敲代码 所有, 如有侵权,请联系我们删除。

“【Spring6】| Spring对IoC的实现(核心重点)”的评论:

还没有评论