【Spring】注入专题

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 【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-->
<bean id="orderDaoBean" class="com.powernode.spring6.dao.OrderDao"></bean>
<bean id="orderServiceBean" class="com.powernode.spring6.service.OrderService">
    <!--使用ref属性来引入外部Bean,这就是注入外部Bean-->
    <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">
        <!--在property标签中使用嵌套的bean标签,这就是内部Bean-->
        <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">
    <!--重点:如果是给简单类型赋值,就不能使用ref了。就需要使用value了。-->
    <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.
   * <p>See {@link #isSimpleValueType(Class)} for the definition of <em>simple
   * value type</em>.
   * <p>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.
   * <p>{@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;
    }
}
<!--让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="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">
    <!--简单类型,使用value-->
    <property name="name" value="张三"/>
    <!--这不是简单类型,使用ref-->
    <property name="clazz" ref="clazzBean"/>
</bean>
<bean id="clazzBean" class="com.powernode.spring6.bean.Clazz">
    <property name="name" value="高三一班"/>
</bean>
  • 级联注入:
  • 注意:级联属性赋值,对于对其他对象引用的成员变量,一定要提供get方法,因为进行级联属性赋值时,需要先调用get方法获取对其他对象引用的成员变量,然后再调用该成员变量属性的set方法进行属性赋值
<!--使用级联属性赋值需要注意两点:
        1. 配置的顺序不能颠倒,必须如下顺序。
        2. clazz属性必须提供getter方法。
-->
<bean id="studentBean" class="com.powernode.spring6.bean.Student">
    <!--简单类型,使用value-->
    <property name="name" value="张三"/>
    <!--这不是简单类型,使用ref-->
    <!-- 因为后面要对该对象的属性赋值,所以必须先有该对象 -->
    <property name="clazz" ref="clazzBean"/>
    <!--级联属性赋值-->
    <!-- name="clazz.name" 会调用学生的getClazz()方法,
        所以学生类必须提供getClazz()方法,然后调用set方法给班级的name赋值 
    -->
    <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">
    <!-- 这个数组属性当中的元素类型是String,是简单类型 -->
    <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">
    <!-- 这个数组属性当中的元素类型是String简单类型 -->
    <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>标签,如果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集合有序可重复-->
        <list>
            <value>张三</value>
            <value>李四</value>
            <value>王五</value>
            <value>张三</value>
            <value>张三</value>
            <value>张三</value>
            <value>张三</value>
        </list>
    </property>
    <property name="addrs">
        <!--set集合无序不可重复-->
        <set>
            <value>北京大兴区</value>
            <value>北京大兴区</value>
            <value>北京海淀区</value>
            <value>北京海淀区</value>
            <value>北京大兴区</value>
        </set>
    </property>
</bean>

注入Map集合与注入Properties

  • Map集合:
  • 使用<map>标签
  • 如果key是简单类型,使用 key 属性,反之使用 key-ref 属性。
  • 如果value是简单类型,使用 value 属性,反之使用 value-ref 属性。
  • java.util.Properties继承java.util.Hashtable,所以Properties也是一个Map集合。
  • Properties使用<props>标签嵌套<prop>标签完成。
  • 在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">
        <!--注入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">123456</prop>
        </props>
    </property>
    <property name="phones">
        <!--注入Map集合-->
        <map>
            <!--如果key和value不是简单类型就用这个配置。-->
            <!--<entry key-ref="" value-ref=""/>-->
            <!--如果是简单类型就是key和value-->
            <entry key="1" value="110"/>
            <entry key="2" value="120"/>
            <entry key="3" value="119"/>
        </map>
    </property>
</bean>

注入null和空字符串

  • 注入空字符串使用:<value/> 或者 value=“”
  • 注入null使用:<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">
    <!--不给属性注入,属性的默认值就是null-->
    <!--<property name="name" value="tom"></property>-->
    <!-- 这不是注入null,这只是注入了一个"null"字符串-->
    <!--<property name="name" value="null"/>-->
    <!--这种方式是手动注入null-->
    <!--<property name="name">
        <null/>
    </property>-->
    <!--注入空字符串第一种方式-->
    <!--<property name="name" value=""/>-->
    <!--注入空字符串第二种方式-->
    <property name="name">
        <value/>
    </property>
    <property name="age" value="3"></property>
</bean>

注入的值中含有特殊符号

  • XML中有5个特殊字符,分别是:<、>、'、"、&
  • 以上5个特殊符号在XML中会被特殊对待,会被当做XML语法的一部分进行解析,如果这些特殊符号直接出现在注入的字符串当中,会报错。
  • 解决方案包括两种:
  • 第一种:特殊符号使用转义字符代替。
  • 第二种:将含有特殊符号的字符串放到: <![CDATA[]]> 当中。放在CDATA区中的数据不会被XML文件解析器解析。使用CDATA时,不能使用value属性,只能使用value标签。
  • 5个特殊字符对应的转义字符分别是:
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="2 &lt; 3" />-->
        <!--第二种方案:使用<![CDATA[]]>-->
        <property name="result">
            <!--只能使用value标签-->
            <value><![CDATA[2 < 3]]></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 +
                '}';
    }
}
<?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>

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 +
                '}';
    }
}
<?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的配置文件头部添加: 
            xmlns:c="http://www.springframework.org/schema/c"
        第二步:使用
            c:_0 下标方式
            c:name 参数名方式
    -->
    <!--<bean id="peopleBean" class="com.powernode.spring6.bean.People" c:_0="zhangsan" c:_1="30" c:_2="true"></bean>-->
    <bean id="peopleBean" class="com.powernode.spring6.bean.People" c:name="jack" c:age="30" c:sex="true"></bean>
</beans>

util命名空间

  • 使用util命名空间可以让配置复用。
  • 使用util命名空间的前提是:在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"
       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 +
                '}';
    }
}
<?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">123</prop>
    </util:properties>
    <!--数据源1-->
    <bean id="ds1" class="com.powernode.spring6.jdbc.MyDataSource1">
        <property name="properties" ref="prop"/>
    </bean>
    <!--数据源2-->
    <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();
    }
}
<!--根据名字进行自动装配-->
<!--注意:自动装配也是基于set方式实现的。-->
<bean id="orderService" class="com.powernode.spring6.service.OrderService" autowire="byName"></bean>
<!--id一般也叫作bean的名称。-->
<!--根据名字进行自动装配的时候,被注入的对象的bean的id不能随便写,
    set方法的方法名去掉set,剩下单词首字母小写。-->
<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();
    }
}
<!--根据类型进行自动装配-->
    <!--自动装配是基于set方法的-->
    <!--根据类型进行自动装配的时候,在有效的配置文件当中,某种类型的实例只能有一个。-->
    <bean class="com.powernode.spring6.dao.VipDao"></bean>
    <bean id="x" class="com.powernode.spring6.dao.UserDao"></bean>
    <!--如果byType,根据类型装配时,如果配置文件中有两个类型一样的bean会报错-->
    <!--<bean id="y" 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
<?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命名空间。
          xmlns:context="http://www.springframework.org/schema/context"
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        第二步:使用标签context:property-placeholder的location属性来指定属性配置文件的路径。
                    location默认从类的根路径下开始加载资源。
    -->
    <context:property-placeholder location="jdbc.properties"/>
    <!--配置数据源-->
    <bean id="ds" class="com.powernode.spring6.jdbc.MyDataSource">
        <!--怎么取值呢?第三步:${key}-->
        <property name="driver" value="${jdbc.driverClass}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <!--加前缀是由于spring加载变量是优先从系统变量中进行加载,username系统变量已经存在-->
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
</beans>


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7月前
|
XML Java 开发者
Spring Boot中的bean注入方式和原理
Spring Boot中的bean注入方式和原理
740 0
|
2月前
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
137 3
|
2月前
|
Java 测试技术 程序员
为什么Spring不推荐@Autowired用于字段注入?
作为Java程序员,Spring框架在日常开发中使用频繁,其依赖注入机制带来了极大的便利。然而,尽管@Autowired注解简化了依赖注入,Spring官方却不推荐在字段上使用它。本文将探讨字段注入的现状及其存在的问题,如难以进行单元测试、违反单一职责原则及易引发NPE等,并介绍为何Spring推荐构造器注入,包括增强代码可读性和维护性、方便单元测试以及避免NPE等问题。通过示例代码展示如何将字段注入重构为构造器注入,提高代码质量。
107 1
|
13天前
|
Java Spring
一键注入 Spring 成员变量,顺序编程
介绍了一款针对Spring框架开发的插件,旨在解决开发中频繁滚动查找成员变量注入位置的问题。通过一键操作(如Ctrl+1),该插件可自动在类顶部添加`@Autowired`注解及其成员变量声明,同时保持光标位置不变,有效提升开发效率和代码编写流畅度。适用于IntelliJ IDEA 2023及以上版本。
一键注入 Spring 成员变量,顺序编程
|
7月前
|
XML Java 程序员
Spring6框架中依赖注入的多种方式(推荐构造器注入)
依赖注入(DI)是一种过程,对象通过构造函数参数、工厂方法的参数或在对象实例构建后设置的属性来定义它们的依赖关系(即与其一起工作的其他对象)。
108 3
|
2月前
|
缓存 Java Spring
源码解读:Spring如何解决构造器注入的循环依赖?
本文详细探讨了Spring框架中的循环依赖问题,包括构造器注入和字段注入两种情况,并重点分析了构造器注入循环依赖的解决方案。文章通过具体示例展示了循环依赖的错误信息及常见场景,提出了三种解决方法:重构代码、使用字段依赖注入以及使用`@Lazy`注解。其中,`@Lazy`注解通过延迟初始化和动态代理机制有效解决了循环依赖问题。作者建议优先使用`@Lazy`注解,并提供了详细的源码解析和调试截图,帮助读者深入理解其实现机制。
71 1
|
4月前
|
XML Java 数据格式
Spring5入门到实战------4、IOC容器-Bean管理XML方式、集合的注入(二)
这篇文章是Spring5框架的实战教程,主题是IOC容器中Bean的集合属性注入,通过XML配置方式。文章详细讲解了如何在Spring中注入数组、List、Map和Set类型的集合属性,并提供了相应的XML配置示例和Java类定义。此外,还介绍了如何在集合中注入对象类型值,以及如何使用Spring的util命名空间来实现集合的复用。最后,通过测试代码和结果展示了注入效果。
Spring5入门到实战------4、IOC容器-Bean管理XML方式、集合的注入(二)
|
4月前
|
缓存 Java 数据库连接
Spring Boot 资源文件属性配置,紧跟技术热点,为你的应用注入灵动活力!
【8月更文挑战第29天】在Spring Boot开发中,资源文件属性配置至关重要,它让开发者能灵活定制应用行为而不改动代码,极大提升了可维护性和扩展性。Spring Boot支持多种配置文件类型,如`application.properties`和`application.yml`,分别位于项目的resources目录下。`.properties`文件采用键值对形式,而`yml`文件则具有更清晰的层次结构,适合复杂配置。此外,Spring Boot还支持占位符引用和其他外部来源的属性值,便于不同环境下覆盖默认配置。通过合理配置,应用能快速适应各种环境与需求变化。
55 0
|
4月前
|
安全 Java 开发者
开发者必看!@Resource与private final的较量,Spring Boot注入技巧大揭秘,你不可不知的细节!
【8月更文挑战第29天】Spring Boot作为热门Java框架,其依赖注入机制备受关注。本文通过对比@Resource(JSR-250规范)和@Autowired(Spring特有),并结合private final声明的字段注入,详细探讨了两者的区别与应用场景。通过示例代码展示了@Resource按名称注入及@Autowired按类型注入的特点,并分析了它们在注入时机、依赖性、线程安全性和单一职责原则方面的差异,帮助开发者根据具体需求选择最合适的注入策略。
188 0
|
5月前
|
Java Spring
spring注入的几种方式
spring注入的几种方式
29 0