【Spring】注入专题

根据 【动力节点】最新Spring框架教程,全网首套Spring6教程,跟老杜从零学spring入门到高级 以及老杜的原版笔记 https://www.yuque.com/docs/share/866abad4-7106-45e7-afcd-245a733b073f?# 《Spring6》 进行整理, 文档密码:mg9b


Spring 相关文章整理汇总归纳于:https://www.yuque.com/u27599042/zuisie


set注入专题

注入外部Bean

  • 外部Bean:要进行注入的bean定义到需要被注入的Bean的外面
  • 对于外部Bean,在property标签中使用ref属性进行注入,或者使用ref标签进行注入,其中通过ref属性进行注入是常用。

<bean id="orderDaoBean" class="com.powernode.spring6.dao.OrderDao">bean>

<bean id="orderServiceBean" class="com.powernode.spring6.service.OrderService">
    
    <property name="orderDao" ref="orderDaoBean"/>
bean>

注入内部Bean

  • 内部Bean:在bean标签中嵌套bean标签,即需要进行注入的Bean通过Bean标签声明在需要被注入的Bean中,然后直接注入到需要被注入的Bean中。
<bean id="orderServiceBean2" class="com.powernode.spring6.service.OrderService">
    <property name="orderDao">
        
        <bean class="com.powernode.spring6.dao.OrderDao">bean>
    property>
bean>

注入简单类型

  • 如果给简单类型赋值,即给属性注入简单类型,使用value属性或value标签,而不是ref。
public class User {
    private String username; // String是简单类型
    private String password;
    private int age; // int是简单类型

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

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

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

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

<bean id="userBean" class="com.powernode.spring6.bean.User">
    
    <property name="username" value="张三"/>
    <property name="password" value="123"/>
    <property name="age" value="20"/>
bean>

Spring 中的简单类型

  • 通过BeanUtils类的源码分析得知,简单类型包括:
    • 基本数据类型
    • 基本数据类型对应的包装类
    • String或其他的CharSequence子类
    • Number子类
    • Date子类,java.util.Date是简单类型
    • Enum子类
    • URI
    • URL
    • Temporal子类,Temporal是Java8提供的时间和时区类型
    • Locale,Locale是语言类,也是简单类型。
    • Class
    • 另外还包括以上简单值类型对应的数组类型。
public class BeanUtils{
    
    //.......
    
    /**
	 * Check if the given type represents a "simple" property: a simple value
	 * type or an array of simple value types.
	 * 

See {@link #isSimpleValueType(Class)} for the definition of simple * value type. *

Used to determine properties to check for a "simple" dependency-check. * @param type the type to check * @return whether the given type represents a "simple" property * @see org.springframework.beans.factory.support.RootBeanDefinition#DEPENDENCY_CHECK_SIMPLE * @see org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#checkDependencies * @see #isSimpleValueType(Class) */ public static boolean isSimpleProperty(Class<?> type) { Assert.notNull(type, "'type' must not be null"); return isSimpleValueType(type) || (type.isArray() && isSimpleValueType(type.getComponentType())); } /** * Check if the given type represents a "simple" value type: a primitive or * primitive wrapper, an enum, a String or other CharSequence, a Number, a * Date, a Temporal, a URI, a URL, a Locale, or a Class. *

{@code Void} and {@code void} are not considered simple value types. * @param type the type to check * @return whether the given type represents a "simple" value type * @see #isSimpleProperty(Class) */ 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)); } //........ }

测试所有的简单类型

  • 编写一个程序,把所有的简单类型全部测试一遍:
package com.powernode.spring6.beans;

import java.net.URI;
import java.net.URL;
import java.time.LocalDate;
import java.util.Date;
import java.util.Locale;

public class A {
    private byte b;
    private short s;
    private int i;
    private long l;
    private float f;
    private double d;
    private boolean flag;
    private char c;

    private Byte b1;
    private Short s1;
    private Integer i1;
    private Long l1;
    private Float f1;
    private Double d1;
    private Boolean flag1;
    private Character c1;

    private String str;

    private Date date;

    private Season season;

    private URI uri;

    private URL url;

    private LocalDate localDate;

    private Locale locale;

    private Class clazz;
    
    // 生成setter方法
    // 生成toString方法
}

enum Season {
    SPRING, SUMMER, AUTUMN, WINTER
}
  • 需要注意的是:
    • 如果把Date当做简单类型的话,日期字符串格式不能随便写,格式必须符合Date的toString()方法格式。显然这就比较鸡肋了。如果我们提供一个这样的日期字符串:2010-10-11,在这里是无法赋值给Date类型的属性的。
    • spring6之后,当注入的是URL,那么这个url字符串是会进行有效性检测的。如果是一个存在的url,那就没问题。如果不存在则报错。

注入简单类型经典案例

  • 经典案例:给数据源的属性注入值:
  • 假设我们现在要自己手写一个数据源,我们都知道所有的数据源都要实现javax.sql.DataSource接口,并且数据源中应该有连接数据库的信息,例如:driver、url、username、password 等。
  • 数据源:能够给你提供Connection对象的,都是数据源
/**
 * 所有的数据源都要实现java规范:javax.sql.DataSource
 **/
public class MyDataSource implements DataSource { // 可以把数据源交给Spring容器来管理。

    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 "MyDataSource{" +
                "driver='" + driver + '\'' +
                ", url='" + url + '\'' +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    @Override
    public Connection getConnection() throws SQLException {
        // 获取数据库连接对象的时候需要4个信息:driver url username password
        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;
    }
}

<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="123456"/>
bean>
@Test
public void testDataSource(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-datasource.xml");
    MyDataSource dataSource = applicationContext.getBean("dataSource", MyDataSource.class);
    System.out.println(dataSource);
}

级联属性赋值

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

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

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

    // 学生属于哪个班级
    private Clazz clazz;

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

    // 使用级联属性赋值,这个需要这个get方法。
    // 因为级联给学生所在的班级属性赋值会调用学生的getClazz()方法
    public Clazz getClazz() {
        return clazz;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", clazz=" + clazz +
                '}';
    }
}
  • 原先的注入方法
<bean id="studentBean" class="com.powernode.spring6.bean.Student">
    
    <property name="name" value="张三"/>
    
    <property name="clazz" ref="clazzBean"/>
bean>

<bean id="clazzBean" class="com.powernode.spring6.bean.Clazz">
    <property name="name" value="高三一班"/>
bean>
  • 级联注入:
  • 注意:级联属性赋值,对于对其他对象引用的成员变量,一定要提供get方法,因为进行级联属性赋值时,需要先调用get方法获取对其他对象引用的成员变量,然后再调用该成员变量属性的set方法进行属性赋值

<bean id="studentBean" class="com.powernode.spring6.bean.Student">
    
    <property name="name" value="张三"/>
    
		
    <property name="clazz" ref="clazzBean"/>
    
    
    <property name="clazz.name" value="高三二班"/>
bean>


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

注入数组

数组中的元素是简单类型

public class QianDaYe {
    private String[] aiHaos;

    public void setAiHaos(String[] aiHaos) {
        this.aiHaos = aiHaos;
    }

    @Override
    public String toString() {
        return "QianDaYe{" +
                "aiHaos=" + Arrays.toString(aiHaos) +
                '}';
    }
}
<bean id="yuQian" class="com.powernode.spring6.bean.QianDaYe">

    
    <property name="aiHaos">
        <array>
            <value>抽烟value>
            <value>喝酒value>
            <value>烫头value>
        array>
    property>

bean>

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

public class Woman {
    private String name;

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

    @Override
    public String toString() {
        return "Woman{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class QianDaYe {
    private String[] aiHaos;

    // 多个女性朋友
    private Woman[] womens;

    public void setWomens(Woman[] womens) {
        this.womens = womens;
    }

    public void setAiHaos(String[] aiHaos) {
        this.aiHaos = aiHaos;
    }

    @Override
    public String toString() {
        return "QianDaYe{" +
                "aiHaos=" + Arrays.toString(aiHaos) +
                ", womens=" + Arrays.toString(womens) +
                '}';
    }
}
<bean id="w1" class="com.powernode.spring6.bean.Woman">
    <property name="name" value="小花"/>
bean>

<bean id="w2" class="com.powernode.spring6.bean.Woman">
    <property name="name" value="小亮"/>
bean>

<bean id="w3" class="com.powernode.spring6.bean.Woman">
    <property name="name" value="小明"/>
bean>

<bean id="yuQian" class="com.powernode.spring6.bean.QianDaYe">

    
    <property name="aiHaos">
        <array>
            <value>抽烟value>
            <value>喝酒value>
            <value>烫头value>
        array>
    property>

    
    <property name="womens">
        <array>
            <ref bean="w1"/>
            <ref bean="w2"/>
            <ref bean="w3"/>
        array>
    property>

bean>

注入数组小结

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

注入List集合与Set集合

  • List集合:有序可重复
    • 注意:注入List集合的时候使用list标签,如果List集合中是简单类型使用value标签,反之使用ref标签。
  • Set集合:无序不可重复
    • 要点: 注入set集合的时候使用标签,如果set集合中元素是简单类型的使用value标签,反之使用ref标签。
public class Person {

    // 注入List集合
    private List<String> names;

    // 注入Set集合
    private Set<String> addrs;

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

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

    @Override
    public String toString() {
        return "Person{" +
                "names=" + names +
                ", addrs=" + addrs +
                '}';
    }
}
<bean id="personBean" class="com.powernode.spring6.bean.Person">

    <property name="names">
        
        <list>
            <value>张三value>
            <value>李四value>
            <value>王五value>
            <value>张三value>
            <value>张三value>
            <value>张三value>
            <value>张三value>
        list>
    property>

    <property name="addrs">
        
        <set>
            <value>北京大兴区value>
            <value>北京大兴区value>
            <value>北京海淀区value>
            <value>北京海淀区value>
            <value>北京大兴区value>
        set>
    property>
bean>

注入Map集合与注入Properties

  • Map集合:
    • 使用标签
    • 如果key是简单类型,使用 key 属性,反之使用 key-ref 属性。
    • 如果value是简单类型,使用 value 属性,反之使用 value-ref 属性。
  • java.util.Properties继承java.util.Hashtable,所以Properties也是一个Map集合。
    • Properties使用标签嵌套标签完成。
    • 在Properties中,key和value的类型都是String类型
public class Person {

    // 注入Map集合
    // 多个电话
    private Map<Integer, String> phones;

    // 注入属性类对象
    // Properties本质上也是一个Map集合。
    // Properties的父类Hashtable,Hashtable实现了Map接口。
    // 虽然这个也是一个Map集合,但是和Map的注入方式有点像,但是不同。
    // Properties的key和value只能是String类型。
    private Properties properties;

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

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

    @Override
    public String toString() {
        return "Person{" +
                "phones=" + phones +
                ", properties=" + properties +
                '}';
    }
}
<bean id="personBean" class="com.powernode.spring6.bean.Person">
    
    <property name="properties">
        
        <props>
            <prop key="driver">com.mysql.cj.jdbc.Driverprop>
            <prop key="url">jdbc:mysql://localhost:3306/spring6prop>
            <prop key="username">rootprop>
            <prop key="password">123456prop>
        props>
    property>

    <property name="phones">
        
        <map>
            
            
            
            <entry key="1" value="110"/>
            <entry key="2" value="120"/>
            <entry key="3" value="119"/>
        map>
    property>
bean>

注入null和空字符串

  • 注入空字符串使用: 或者 value=“”
  • 注入null使用: 或者不为该属性赋值
public class Cat {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
<bean id="catBean" class="com.powernode.spring6.bean.Cat">
    
    
    
    
    
    

    
    
    
    <property name="name">
        <value/>
    property>

    <property name="age" value="3">property>
bean>

注入的值中含有特殊符号

  • XML中有5个特殊字符,分别是:<、>、'、"、&
  • 以上5个特殊符号在XML中会被特殊对待,会被当做XML语法的一部分进行解析,如果这些特殊符号直接出现在注入的字符串当中,会报错。
    【Spring】注入专题_第1张图片
  • 解决方案包括两种:
    • 第一种:特殊符号使用转义字符代替。
    • 第二种:将含有特殊符号的字符串放到: 当中。放在CDATA区中的数据不会被XML文件解析器解析。使用CDATA时,不能使用value属性,只能使用value标签。
  • 5个特殊字符对应的转义字符分别是:
    【Spring】注入专题_第2张图片
public class MathBean {
    private String result;

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

    @Override
    public String toString() {
        return "MathBean{" +
                "result='" + result + '\'' +
                '}';
    }
}
    <bean id="mathBean" class="com.powernode.spring6.bean.MathBean">
        
        

        
        <property name="result">
            
            <value>value>
        property>

    bean>

p命名空间注入

  • 目的:简化配置。
  • p命名空间实际上是对set注入的简化。
  • 使用p命名空间注入的前提条件包括两个:
    • 第一:在XML头部信息中添加p命名空间的配置信息:xmlns:p="http://www.springframework.org/schema/p"
    • 第二:p命名空间注入是基于setter方法的,所以需要对应的属性提供setter方法。
public class Dog {
    // 简单类型
    private String name;
    private int age;
    // 非简单类型
    private Date birth;

    // p命名空间注入底层还是set注入,只不过p命名空间注入可以让spring配置变的更加简单。
    public void setName(String name) {
        this.name = name;
    }

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

    public void setBirth(Date birth) {
        this.birth = birth;
    }

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

<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.powernode.spring6.bean.Dog" p:name="小花" p:age="3" p:birth-ref="birthBean"/>

    
    <bean id="birthBean" class="java.util.Date"/>

beans>

c命名空间注入

  • c命名空间是简化构造方法注入的。
  • 使用c命名空间的两个前提条件:
    • 第一:需要在xml配置文件头部添加c命名空间的配置信息:xmlns:c="http://www.springframework.org/schema/c"
    • 第二:需要提供构造方法。
  • c命名空间是依靠构造方法的。
  • 注意:不管是p命名空间还是c命名空间,注入的时候都可以注入简单类型以及非简单类型。
public class People {
    private String name;
    private int age;
    private boolean sex;

    // c命名空间是简化构造注入的。
    // c命名空间注入办法是基于构造方法的。
    public People(String name, int age, boolean sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

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

<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="peopleBean" class="com.powernode.spring6.bean.People" c:name="jack" c:age="30" c:sex="true">bean>

beans>

util命名空间

  • 使用util命名空间可以让配置复用。
  • 使用util命名空间的前提是:在spring配置文件头部添加配置信息。
  • 如下:

<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">
package com.powernode.spring6.beans;

import java.util.Properties;

public class MyDataSource1 {
	// Properties属性类对象,这是一个Map集合,
    // key和value都是String类型。
    private Properties properties;

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

    @Override
    public String toString() {
        return "MyDataSource1{" +
                "properties=" + properties +
                '}';
    }
}
package com.powernode.spring6.beans;

import java.util.Properties;

public class MyDataSource2 {
    private Properties properties;

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

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

<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:properties id="prop">
        <prop key="driver">com.mysql.cj.jdbc.Driverprop>
        <prop key="url">jdbc:mysql://localhost:3306/spring6prop>
        <prop key="username">rootprop>
        <prop key="password">123prop>
    util:properties>

    
    <bean id="ds1" class="com.powernode.spring6.jdbc.MyDataSource1">
        <property name="properties" ref="prop"/>
    bean>

    
    <bean id="ds2" class="com.powernode.spring6.jdbc.MyDataSource2">
        <property name="properties" ref="prop"/>
    bean>

beans>

基于 XML 的自动装配

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

根据名称自动装配

  • 如果根据名称装配(byName),底层会调用set方法进行注入。
  • 例如:setAge() 对应的名字是age,setPassword()对应的名字是password,setEmail()对应的名字是email。
public class OrderDao {

    private static final Logger logger = LoggerFactory.getLogger(OrderDao.class);

    public void insert(){
        logger.info("订单正在生成....");
    }
}
public class OrderService {

    private OrderDao orderDao;

    // 通过set方法给属性赋值。
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }

    /**
     * 生成订单的业务方法。。。
     */
    public void generate(){
        orderDao.insert();
    }
}


<bean id="orderService" class="com.powernode.spring6.service.OrderService" autowire="byName">bean>



<bean id="orderDao" class="com.powernode.spring6.dao.OrderDao"/>
  • OrderService Bean中需要添加autowire=“byName”,表示通过名称自动进行装配。
  • OrderService 类中有一个OrderDao属性,而OrderDao属性的名字是orderDao,对应的set方法是setOrderDao(),正好和OrderDao Bean的id是一样的,可以根据名称自动装配。

根据类型自动装配

  • 无论是byName还是byType,在装配的时候都是基于set方法的,所以set方法是必须要提供的,提供构造方法是不行的
  • 如果byType,根据类型装配时,如果配置文件中有两个类型一样的bean会报错
  • 当byType进行自动装配的时候,配置文件中某种类型的Bean必须是唯一的,不能出现多个。
    • 如果存在多个类型一样的Bean,则Spring会不知道使用那个Bean进行注入
public class CustomerService {

    private UserDao userDao;
    private VipDao vipDao;

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

    public void setVipDao(VipDao vipDao) {
        this.vipDao = vipDao;
    }

    public void save(){
        userDao.insert();
        vipDao.insert();
    }

}
    
    
    
    <bean class="com.powernode.spring6.dao.VipDao">bean>
    <bean id="x" class="com.powernode.spring6.dao.UserDao">bean>
    
    
    <bean id="cs" class="com.powernode.spring6.service.CustomerService" autowire="byType">bean>

Spring引入外部属性配置文件

  • 我们都知道编写数据源的时候是需要连接数据库的信息的,例如:driver url username password等信息。这些信息可以单独写到一个属性配置文件中吗,这样用户修改起来会更加的方便
jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring6
jdbc.username=root
jdbc.password=123

<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="ds" class="com.powernode.spring6.jdbc.MyDataSource">
        
        <property name="driver" value="${jdbc.driverClass}">property>
        <property name="url" value="${jdbc.url}">property>
        
        <property name="username" value="${jdbc.username}">property>
        <property name="password" value="${jdbc.password}">property>
    bean>

beans>

你可能感兴趣的:(Spring,spring,java,数据库,后端,javaee)