跟老杜手撕Spring6教程(八)Spring对IoC的实现

本文介绍了Spring框架如何实现IoC(控制反转)和DI(依赖注入)以降低程序耦合度。Spring通过依赖注入管理Bean的创建和属性赋值,详细阐述了set注入的实现方式,包括反射机制在其中的作用。文章还提供了相关的代码示例和Maven配置,以及测试用例展示了注入过程。
摘要由CSDN通过智能技术生成

Spring对IoC的实现

本篇文章说说Spring对IoC的实现,上篇说了Spring6启用Log4j2日志框架

跟老杜手撕Spring6教程(七)Spring6启用Log4j2日志框架_ewertyucf的博客-CSDN博客

配合视频教程观看,更易理解吸收,动力节点老杜的Spring6教程采用难度逐步递进的方式,从入门的第一个程序到手写Spring框架,真正的能够让小白成为老手。如果你是老程序员不妨看看手写Spring框架,也会让你受益颇多。

相关的学习资料也给大家备好了

https://www.bilibili.com/video/BV1Ft4y1g7Fb/

1. IoC 控制反转

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

2. 依赖注入

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

Spring通过依赖注入的方式来完成Bean管理的。

Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。

依赖注入:

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

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

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

新建模块:spring6-002-dependency-injection

2.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最简单的一种装配方式。装配指的是:创建系统组件之间关联的动作)

可以把set方法注释掉,再测试一下:

通过测试得知,底层实际上调用了setUserDao()方法。所以需要确保这个方法的存在。

我们现在把属性名修改一下,但方法名还是setUserDao(),我们来测试一下:

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 aaa;



    // 使用set方式注入,必须提供set方法。

    // 反射机制要调用这个方法给属性赋值的。

    public void setUserDao(UserDao userDao) {

        this.aaa = userDao;

    }



    public void save(){

        aaa.insert();

    }

}

运行测试程序:

通过测试看到程序仍然可以正常执行,说明property标签的name是:setUserDao()方法名演变得到的。演变的规律是:

  • setUsername() 演变为 username
  • setPassword() 演变为 password
  • setUserDao() 演变为 userDao
  • setUserService() 演变为 userService

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

<bean id="userServiceBean" class="com.powernode.spring6.service.UserService">

  <property name="userDao">

    <ref bean="userDaoBean"/>

  </property>

</bean>

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值