【Spring】Spring的IOC依赖注入的四种方式

img

  • 作者简介:大家好,我是五度鱼,一个普通的Java领域博主,不停输出Java技术博客和干货。

  • 座右铭:锲而不舍,金石可镂。

  • 个人主页:五度鱼学Java的主页


前言

  这几天学了Spring6,感觉到了Spring的强大和便捷。其中的IOC设计原则对对象的处理真的是达到了出神入化的地步,省去了不停的创建对象的过程。写此篇文章是为了总结一下IOC的四种属性注入方式,也是为了以后可以翻看,每日温习一遍,孔子说过:“温故而知新,可以为师矣”。各位朋友们在浏览此篇博客时可以温习一下IOC的知识。

在这里插入图片描述


1. set注入

  set注入是基于set方法注入的,它的底层是通过反射机制调用属性对应的set方法给属性赋值,这种方式必须要求属性对外提供set方法,让两个对象之间产生关系。

<?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.powernode</groupId>
    <artifactId>spring6-002-dependency-injection</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <repositories>
        <repository>
            <id>repository.spring.milestone</id>
            <name>Spring Milestone Repository</name>
            <url>https://repo.spring.io/milestone</url>
        </repository>
    </repositories>

    <dependencies>
        <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.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

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

</project>
package com.powernode.spring6.dao;

/**
 * @author 五度鱼
 * @version 1.0
 * @className UserDao
 * @since 1.0
 **/
public class UserDao {
    
    

    public void insert(){
    
    
        System.out.println("正在保存用户数据。");
    }
}
package com.powernode.spring6.service;

import com.powernode.spring6.dao.UserDao;

/**
 * @author 五度鱼
 * @version 1.0
 * @className UserService
 * @since 1.0
 **/
public class UserService {
    
    

    private UserDao userDao;

    // 使用set方式注入,必须提供set方法。
    // 反射机制要调用这个方法给属性赋值的。
    public void setUserDao(UserDao userDao) {
    
    
        this.userDao = userDao;
    }

    public void save(){
    
    
        userDao.insert();
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>

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

</beans>
package com.powernode.spring6.test;

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

/**
 * @author 五度鱼
 * @version 1.0
 * @className DITest
 * @since 1.0
 **/
public class DITest {
    
    

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

运行结果:

在这里插入图片描述

实现原理:

  • <?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.powernode.spring6.dao.UserDao"/>
    
        <bean id="userServiceBean" class="com.powernode.spring6.service.UserService">
            <property name="userDao" ref="userDaoBean"/>
        </bean>
    
    </beans>
    
  • 通过property标签获取到属性名:userDao

    通过属性名推断出set方法名:setUserDao

    通过反射机制调用setUserDao()方法给属性赋值

    property标签的name是属性名。

    property标签的ref是要注入的bean对象的id

    (通过ref属性来完成bean的装配,这是bean最简单的一种装配方式。装配指的是:创建系统组件之间关联的动作)

    (1)setUsername() 演变为 username

    (2)setPassword() 演变为 password

    (3)setUserDao() 演变为 userDao

    (4)setUserService() 演变为 userService

2. 构造注入

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

package com.powernode.spring6.dao;

/**
 * @author 五度鱼
 * @version 1.0
 * @className OrderDao
 * @since 1.0
 **/
public class OrderDao {
    
    
    public void deleteById(){
    
    
        System.out.println("正在删除订单。。。");
    }
}
package com.powernode.spring6.service;

import com.powernode.spring6.dao.OrderDao;

/**
 * @author 五度鱼
 * @version 1.0
 * @className OrderService
 * @since 1.0
 **/
public class OrderService {
    
    
    private OrderDao orderDao;

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

    public void delete(){
    
    
        orderDao.deleteById();
    }
}
<bean id="orderDaoBean" class="com.powernode.spring6.dao.OrderDao"/>
<bean id="orderServiceBean" class="com.powernode.spring6.service.OrderService">
  <!--index="0"表示构造方法的第一个参数,将orderDaoBean对象传递给构造方法的第一个参数。-->
  <constructor-arg index="0" ref="orderDaoBean"/>
</bean>
@Test
public void testConstructorDI(){
    
    
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    OrderService orderServiceBean = applicationContext.getBean("orderServiceBean", OrderService.class);
    orderServiceBean.delete();
}

运行结果如下:

在这里插入图片描述

如果构造方法有两个参数:

package com.powernode.spring6.service;

import com.powernode.spring6.dao.OrderDao;
import com.powernode.spring6.dao.UserDao;

/**
 * @author 五度鱼
 * @version 1.0
 * @className OrderService
 * @since 1.0
 **/
public class OrderService {
    
    
    private OrderDao orderDao;
    private UserDao userDao;

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

    public void delete(){
    
    
        orderDao.deleteById();
        userDao.insert();
    }
}

Spring配置文件:

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

<bean id="orderServiceBean" class="com.powernode.spring6.service.OrderService">
  <!--第一个参数下标是0-->
  <constructor-arg index="0" ref="orderDaoBean"/>
  <!--第二个参数下标是1-->
  <constructor-arg index="1" ref="userDaoBean"/>
</bean>

<bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>

执行测试程序:

在这里插入图片描述

不使用参数下标,使用参数的名字可以吗?

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

<bean id="orderServiceBean" class="com.powernode.spring6.service.OrderService">
  <!--这里使用了构造方法上参数的名字-->
  <constructor-arg name="orderDao" ref="orderDaoBean"/>
  <constructor-arg name="userDao" ref="userDaoBean"/>
</bean>

<bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>

执行测试程序:

在这里插入图片描述

不指定参数下标,不指定参数名字,可以吗?

<bean id="orderDaoBean" class="com.powernode.spring6.dao.OrderDao"/>
<bean id="orderServiceBean" class="com.powernode.spring6.service.OrderService">
  <!--没有指定下标,也没有指定参数名字-->
  <constructor-arg ref="orderDaoBean"/>
  <constructor-arg ref="userDaoBean"/>
</bean>

<bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>

执行测试程序:

在这里插入图片描述

配置文件中构造方法参数的类型顺序和构造方法参数的类型顺序不一致呢?

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

<bean id="orderServiceBean" class="com.powernode.spring6.service.OrderService">
  <!--顺序已经和构造方法的参数顺序不同了-->
  <constructor-arg ref="userDaoBean"/>
  <constructor-arg ref="orderDaoBean"/>
</bean>

<bean id="userDaoBean" class="com.powernode.spring6.dao.UserDao"/>

执行测试程序:

在这里插入图片描述

通过测试得知,通过构造方法注入的时候:

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

Spring在装配方面做的比较健壮。

3. p命名空间注入

目的:简化配置。

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

  • 第一:在XML头部信息中添加p命名空间的配置信息:xmlns:p="http://www.springframework.org/schema/p"
  • 第二:p命名空间注入是基于setter方法的,所以需要对应的属性提供setter方法。
package com.powernode.spring6.beans;

/**
 * @author 五度鱼
 * @version 1.0
 * @className Customer
 * @since 1.0
 **/
public class Customer {
    
    
    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 "Customer{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       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="customerBean" class="com.powernode.spring6.beans.Customer" p:name="zhangsan" p:age="20"/>

</beans>
@Test
public void testP(){
    
    
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-p.xml");
    Customer customerBean = applicationContext.getBean("customerBean", Customer.class);
    System.out.println(customerBean);
}

执行结果:

在这里插入图片描述

4. c命名空间注入

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

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

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

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

package com.powernode.spring6.beans;

/**
 * @author 五度鱼
 * @version 1.0
 * @className MyTime
 * @since 1.0
 **/
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 +
                '}';
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       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="myTimeBean" class="com.powernode.spring6.beans.MyTime" c:year="1970" c:month="1" c:day="1"/>-->

    <bean id="myTimeBean" class="com.powernode.spring6.beans.MyTime" c:_0="2008" c:_1="8" c:_2="8"/>

</beans>
@Test
public void testC(){
    
    
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-c.xml");
    MyTime myTimeBean = applicationContext.getBean("myTimeBean", MyTime.class);
    System.out.println(myTimeBean);
}

执行结果:

在这里插入图片描述


最后求个关注点赞收藏,谢谢!

猜你喜欢

转载自blog.csdn.net/qq_46096136/article/details/128777533