自学内容网 自学内容网

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

1. 依赖注入概述

依赖注入(DIDependency Injection

控制 反转 指的是将对象 (Bean) 交给 Spring 容器创建
依赖 注入 通过 Spring 容器 动态地为 对象 (Bean ) 属性 赋值,也 可理解 属性注入
控制 反转的 实现方式有多种,依赖注入是其中之一
Spring容器支持如下 两种属性 注入方式
基于 XML 配置的注入
基于注解的注入

 2.基于XML配置的注入

通常有两种注入方式

一种是使用属性的 setter 方法 注入
另一种是使用 构造方法 注入

案例1:在Spring容器中配置Bean,利用setter方法,完成该对象属性的初始化注入

setter方法注入Spring框架中最主流的注入方式灵活且可读性高。通过<property>标签来完成注入配置

打开上节的项目spring6,新增模块spring-di-xml

 

修改模块spring-di-xmlpom.xml,导入以下依赖 

 

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.flowerfog</groupId>
        <artifactId>Spring6</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath> <!-- 确认父项目路径 -->
    </parent>

    <artifactId>spring-di-xml</artifactId>
    <packaging>war</packaging>
    <name>spring-di-xml Maven Webapp</name>

    <url>http://maven.apache.org</url>
    <dependencies>
        <!--spring context依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.2</version>
        </dependency>
        <!--junit5测试-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.3.1</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>
    <build>
        <finalName>spring-di-xml</finalName>
    </build>
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

实体类的属性如下 :

利用自动代码生成机制,编写全部属性的 getter setter 方法
利用自动代码生成机制,编写 toString 方法
package org.flowerfog.pojo;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Customer {
    private String id; // 主键
        private String name; // 姓名
        private List<String> addrList; // 收货地址
        private Map<String, String> collectGoodsMap; //收藏商品
        private Set<String> contactInfoSet; // 联系方式
        private String[] hisQryGoodsTypeArray; // 历史搜索商品类型
        public String getId() {
        return id;
        }
        public void setId(String id) {
        this.id = id;
        }
        public String getName() {
        return name;
        }
        public void setName(String name) {
        this.name = name;
        }
        public List<String> getAddrList() {
        return addrList;
        }
        public void setAddrList(List<String> addrList) {
        this.addrList = addrList;
        }
        public Map<String, String> getCollectGoodsMap() {
        return collectGoodsMap;
        }
        public void setCollectGoodsMap(Map<String, String> collectGoodsMap) {
        this.collectGoodsMap = collectGoodsMap;
        }
        public Set<String> getContactInfoSet() {
        return contactInfoSet;
        }
        public void setContactInfoSet(Set<String> contactInfoSet) {
        this.contactInfoSet = contactInfoSet;
        }
        public String[] getHisQryGoodsTypeArray() {
        return hisQryGoodsTypeArray;
        }
        public void setHisQryGoodsTypeArray(String[] hisQryGoodsTypeArray) {
        this.hisQryGoodsTypeArray = hisQryGoodsTypeArray;
        }
        @Override    public String toString() {
        return "Customer{" +
        "id='" + id + '\'' +
        ", name='" + name + '\'' +
        ", addrList=" + addrList +
        ", collectGoodsMap=" + collectGoodsMap +
        ", contactInfoSet=" + contactInfoSet +
        ", hisQryGoodsTypeArray=" + Arrays.toString(hisQryGoodsTypeArray) +
        '}';
        }

}

 添加Spring核心配置文件

注册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 id="customerBean" class="org.flowerfog.pojo.Customer">
        <property name="id" value="1" />
        <property name="name" value="张三" />
        <property name="addrList">
            <list>
                <value>重庆市xxxx</value>
                <value>重庆市xxxxx</value>
</list>
</property>
    <property name="collectGoodsMap">
        <map>
            <entry key="c1" value="G002" />
            <entry key="c2" value="G006" />
        </map>
    </property>
    <property name="contactInfoSet">
        <set>
            <value>15223025311</value>
            <value>023-62846626</value>
        </set>
    </property>
    <property name="hisQryGoodsTypeArray">
        <array>
            <value>电子书</value>
            <value>笔记本电脑</value>
        </array>
    </property>
</bean>
        </beans>

测试属性注入效果 

import org.flowerfog.pojo.Customer;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CustomerTest {
    @Test
    public void getEntity(){
        // 加载Spring核心配置文件
        ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
        // 获取bean对象
        Customer customerBean = (Customer) ctx.getBean("customerBean");
        // 输出
        System.out.println(customerBean);
    }
}

运行结果:

2.2、使用构造方法注入 

Spring 框架可以采用 Java 反射机制,通过 构造方法 完成依赖注入
构造方法注入是通过 <constructor- arg > 标签 来完成注入配置

修改Customer类,新增构造方法 

public Customer(String id, String name, List<String> addrList, Map<String, String> collectGoodsMap, Set<String> contactInfoSet, String[] hisQryGoodsTypeArray) {
        this.id = id;
        this.name = name;
        this.addrList = addrList;
        this.collectGoodsMap = collectGoodsMap;
        this.contactInfoSet = contactInfoSet;
        this.hisQryGoodsTypeArray = hisQryGoodsTypeArray;
    }

配置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 id="customerBean" class="org.flowerfog.pojo.Customer">
        <property name="id" value="1" />
        <property name="name" value="张三" />
        <property name="addrList">
            <list>
                <value>重庆市xxxxx</value>
                <value>重庆市xxxxx</value>
            </list>
        </property>
        <property name="collectGoodsMap">
            <map>
                <entry key="c1" value="G002" />
                <entry key="c2" value="G006" />
            </map>
        </property>
        <property name="contactInfoSet">
            <set>
                <value>15223025311</value>
                <value>023-62846626</value>
            </set>
        </property>
        <property name="hisQryGoodsTypeArray">
            <array>
                <value>电子书</value>
                <value>笔记本电脑</value>
            </array>
        </property>
    </bean>

    <bean id="customerBean2" class="org.flowerfog.pojo.Customer">
        <constructor-arg index="0" value="1"/>
        <constructor-arg index="1" value="张三" />
        <constructor-arg index="2">
            <list>
                <value>重庆市xxxxxx</value>
                <value>重庆市xxxxxx</value>
            </list>
        </constructor-arg>
        <constructor-arg index="3">
            <map>
                <entry key="c1" value="G002" />
                <entry key="c2" value="G006" />
            </map>
        </constructor-arg>
        <constructor-arg index="4">
            <set>
                <value>15223025311</value>
                <value>023-62846626</value>
            </set>
        </constructor-arg>
        <constructor-arg index="5">
            <array>
                <value>电子书</value>
                <value>笔记本电脑</value>
            </array>
        </constructor-arg>
    </bean>
</beans>

测试属性注入效果 

import org.flowerfog.pojo.Customer;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class CustomerTest {
    @Test
    public void getEntity(){
        // 加载Spring核心配置文件
        ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
        // 获取bean对象
        Customer customerBean = (Customer) ctx.getBean("customerBean2");
        // 输出
        System.out.println(customerBean);
    }
}

 运行结果:

 

3、基于XML配置的注入

通过案例 1 ,我们了解了基于 XML 配置属性注入时如何将静态值的注入到属性
Spring 框架在属性注入时,还可引用 bean ,实现依赖注入

案例2某游戏程序中有三个类

Fighter(战士)

Weapon(武器)

Skill(技能)

每个战士有一个武器属性与一个技能列表属性

使用Spring IOC配置一名战士并完成属性注入 

根据题目要求,三个类的依赖关系如下:

编写武器类 

package org.flowerfog.pojo;

public class Weapon {
    private String name; // 武器名称
    private int attack; // 攻击力

    public String getName() {
        return name;
    }

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

    public int getAttack() {
        return attack;
    }

    public void setAttack(int attack) {
        this.attack = attack;
    }

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

 编写技能类

package org.flowerfog.pojo;

public class Skill {
    private String name; // 技能名称
    private String desc; // 技能描述

    public String getName() {
        return name;
    }

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

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

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

编写战士类

package org.flowerfog.pojo;

import java.util.List;

public class Fighter {
    private String name; // 战士名称
    private Weapon weapon; // 武器
    private List<Skill> skills; // 技能包

    public String getName() {
        return name;
    }

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

    public Weapon getWeapon() {
        return weapon;
    }

    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }

    public List<Skill> getSkills() {
        return skills;
    }

    public void setSkills(List<Skill> skills) {
        this.skills = skills;
    }

    @Override
    public String toString() {
        return "Fighter{" +
                "name='" + name + '\'' +
                ", weapon=" + weapon +
                ", skills=" + skills +
                '}';
    }
}

配置Bean:武器对象、技能对象 

Spring.xml 文件中配置以下三个 bean

<bean id="weaponBean-GreenDragonCrescentBlade" class="org.flowerfog.pojo.Weapon">
        <property name="name" value="青龙偃月刀" />
        <property name="attack" value="1500" />
    </bean>

    <bean id="skillBean-RidingFirst" class="org.flowerfog.pojo.Skill">
        <property name="name" value="一骑当先" />
        <property name=“desc" value="获得加速" />
    </bean>

    <bean id="skillBean-StartASoloRun" class="org.flowerfog.pojo.Skill">
        <property name="name" value="单刀赴会" />
        <property name=“desc" value="获得攻击" />
    </bean>

步骤3 Spring容器中配置1名战士并完成属性注入 

 

<bean id="fighterBean" class="org.flowerfog.pojo.Fighter">
        <property name="name" value="青龙偃月刀" />
        <property name="weapon" ref="weaponBean-GreenDragonCrescentBlade" />
        <property name="skills">
            <list>
                <ref bean="skillBean-RidingFirst" />
                <ref bean="skillBean-StartASoloRun" />
            </list>
        </property>
    </bean>

测试属性注入效果 

import org.flowerfog.pojo.Fighter;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FighterTest {
    @Test
    public void getEntity(){
        // 加载Spring核心配置文件
        ApplicationContext ctx=new ClassPathXmlApplicationContext("spring.xml");
        // 获取bean对象
        Fighter fighterBean = (Fighter) ctx.getBean("fighterBean");
        // 输出
        System.out.println(fighterBean);
    }
}

 运行结果:

 

4.基于注解的配置

基于 XML 配置 的依赖注入 曾经 是最主要的配置方式
但是如果有大量的 Bean 需要装配,会导致 XML 配置文件过大,不便维护

 现在更青睐使用注解(annotation)的方式去装配Bean

Spring框架中定义了一系列注解

1.配置Bean的注解

  • @Component:可以作用在任何层次上
  • @Repository:用于数据访问层(DAO)
  • @Service:用于业务逻辑层(Service)
  • @Controller:用于控制器层(Controller)
  • @Configure:用于配置作用的类

以上注解的作用是一样的,都可以将加了注解的类配置到容器中,只是习惯性的应用于不同的层次中

2.完成依赖注入的注解

  • @Autowired:通过该注解可以消除setter和getter方法,默认按照Bean的类型进行装配
  • @Resource:和@Autowired功能是一样的,区别在于该注解默认是按照名称来装配注入的,通过name来指定Bean实例名称
  • @Qualifier:该注解与@Autowired注解配合使用,当@Autowired注解需要按照名称来装配注入时,使用该注解指定Bean实例名称

项目中有类 UserController UserService UserDao
UserController 定义属性 userService ,依赖 UserService
UserService定义属性 userDao , 依赖 UserDao

 文件架构:

UserDao

UserService 

 UserController

Spring.xml:

 

 步骤1:为每个类添加对应的注解

步骤2:配置注解自动扫描的范围

需要研究的内容 

经测试,jdk22环境下,无法正常运行,提示加载类异常

调整为jdk17后程序正常(演示调整jdk版本)

需研究jdk22下spring6的兼容性问题


原文地址:https://blog.csdn.net/m0_73302939/article/details/143475292

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!