Spring:IOC容器的依赖注入(DI)之自动装配Bean

郎家岭伯爵 2022年01月19日 504次浏览

前言

Spring中IOC容器的实现方式——依赖注入(DI)在前一篇博文中已讲述过,但是那篇是显式的在beans.xml文件中定义的。

本文用于讲述Spring中IOC容器依赖注入(DI)的第二种方式,即:自动装配bean

环境搭建

pom.xml

注:

  • 需要引入spring-context依赖。

spring-context的dependency引入:

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.13</version>
</dependency>

完整的pom.xml文件:

<?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>org.example</groupId>
    <artifactId>Spring-DI-Autowired</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.13</version>
        </dependency>
    </dependencies>
    <properties>
        <maven.compiler.source>15</maven.compiler.source>
        <maven.compiler.target>15</maven.compiler.target>
    </properties>


</project>

pojo

Dog.java

package com.langjialing;

public class Dog {
    public void shout(){
        System.out.println("汪……");
    }
}

Cat.java

package com.langjialing;

public class Cat {

    public void shout(){
        System.out.println("喵……");
    }
}

Person.java

package com.langjialing;

public class Person {

    private Cat cat;
    private Dog dog;
    private String name;

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

beans.xml

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="cat" class="com.langjialing.Cat" />
    <bean id="dog" class="com.langjialing.Dog" />

    <bean id="person" class="com.langjialing.Person">
        <property name="name" value="langjialing"/>
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    </bean>

</beans>

Test测试类

import com.langjialing.Person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        Person person = context.getBean("person", Person.class);
        person.getDog().shout();
        person.getCat().shout();
    }
}

测试结果

目录结构

目录结构

自动装配实现一:基于beans.xml上下文实现

注:

  • 只需修改beans.xml文件即可。
  • autowire="byName":会自动在容器上下文中查找和自己对象set方法后面的值对应的bean的id。
  • autowire="byType":会自动在容器上下文中查找和自己对象class相同的bean。

修改beans.xml

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="cat" class="com.langjialing.Cat" />
    <bean id="dog" class="com.langjialing.Dog" />

<!--    <bean id="person" class="com.langjialing.Person">-->
<!--        <property name="name" value="langjialing"/>-->
<!--        <property name="cat" ref="cat"/>-->
<!--        <property name="dog" ref="dog"/>-->
<!--    </bean>-->

    <!--
    autowire="byName":会自动在容器上下文中查找和自己对象set方法后面的值对应的bean的id。
    autowire="byType":会自动在容器上下文中查找和自己对象class相同的bean。
    -->
    <bean id="person" class="com.langjialing.Person" autowire="byName">
        <property name="name" value="langjialing"/>
    </bean>

</beans>

修改beans.xml后进行测试

注:

  • 测试类无需变动。

自动装配测试结果

自动装配实现二:注解实现自动装配(官方推荐)

注:

  • 注解实现自动装配的方式为Spring官方推荐的方式。
  • 此种方式比beans.xml的方式更简洁。

官方简介文档截图

@Autowired注解对应的beans.xml文件

官方简介:需导入context约束,并配置注解的支持

注:

  • 此内容来自Spring官方;
  • 注解支持的关键代码<context:annotation-config/>,否则即会报错。
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

项目实际的beans.xml文件实现

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <!--开启注解支持-->
    <context:annotation-config/>

    <bean id="cat" class="com.langjialing.Cat"/>
    <bean id="dog" class="com.langjialing.Dog"/>
    <bean id="person" class="com.langjialing.Person"/>

</beans>

@Autowire注解实现自动装配(修改Person.java)

注:

  • @Autowired注解的属性,setter方法可省略,getter方法不可省略。
package com.langjialing;

import org.springframework.beans.factory.annotation.Autowired;

public class Person {

    @Autowired
    private Cat cat;
    @Autowired
    private Dog dog;
    private String name;

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}

Test测试类

注:

  • Test测试类使用上文的即可。
import com.langjialing.Person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        Person person = context.getBean("person", Person.class);
        person.getDog().shout();
        person.getCat().shout();
    }
}

@Autowired自动装配测试结果

多个相同Bean时应当如何使用@Autowired注解呢?

在本例中,如果IOC容器中有多个相同类型bean时,直接使用@Autowired注解会报错。那么应当如何注入呢?

例如:

注入相同类型的Bean

Person类报错

Junit单元测试失败

解决:@Qualifier("dog1")

使用@Qualifier("dog1")注解进行区分。

IDEA智能提示解决了解决方案

@Autowired与@Qualifier("dog1")配合使用

添加@Qualifier("dog1")注解后测试通过

自动装配实现三:Java原生注解@Resource实现

注:

  • 使用方式与 @Autowired 注解基本一致。
  • @Resource注解先匹配beans.xml中的id值,匹配不到id值时继而匹配class值。两者都无法匹配到时报错。
  • 此注解相对于@Autowired注解使用较少,一般情况下使用@Autowired注解。

pom.xml中导入依赖

<dependency>
     <groupId>jakarta.annotation</groupId>
     <artifactId>jakarta.annotation-api</artifactId>
     <version>1.3.5</version>
     <scope>compile</scope>
</dependency>

注解使用

注:

  • 在Person.java中引入import javax.annotation.Resource;

@Resource注解

Junit单元测试

@Resource测试通过