1.简介

可以说现代软件设计最重要的发展原则之一是依赖注入(DI),它源于另一个至关重要的原则:模块化。

本文将探讨在Spring中称为基于构造函数的依赖注入的特定类型的DI技术。

简单地说,这意味着在实例化时将所需的组件传递到类中。

首先,我们需要在pom.xml中导入spring-context依赖项:

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

然后我们需要设置一个配置文件。此文件可以是POJO,也可以是XML文件。

2.基于注释的配置

Java配置文件看起来非常像一个普通的Java对象,带有一些额外的注释:

@Configuration
@ComponentScan("com.ripjava.constructordi")
public class Config {

    @Bean
    public Engine engine() {
        return new Engine("v8", 5);
    }

    @Bean
    public Transmission transmission() {
        return new Transmission("sliding");
    }
}

这里我们使用注释来通知Spring运行时该类是bean定义的提供者(@Bean注释),并且需要在com.ripjava.constructordi包中执行其他bean的上下文扫描。

接下来,我们定义一个Car类:

@Component
public class Car {

    private Engine engine;
    private Transmission transmission;

    @Autowired
    public Car(Engine engine, Transmission transmission) {
        this.engine = engine;
        this.transmission = transmission;
    }

    @Override
    public String toString() {
        return String.format("Engine: %s Transmission: %s", engine, transmission);
    }
}

Spring 在进行包扫描时会遇到我们的Car类,并会通过调用*@Autowired带*注释的构造函数来初始化它的实例。

Engine和Transmission实例将通过调用Config类的*@Bean*注释方法获得。

最后,我们需要使用POJO配置来引导ApplicationContext

private static Car getCarFromJavaConfig() {
  ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);

  return context.getBean(Car.class);
}

3.隐式构造函数注入

从Spring 4.3开始,具有单个构造函数的类可以省略*@Autowired*注释。

最重要的是,从4.3开始,基于构造函数的注入可以在*@Configuration*注释类中使用。

如果这样的类只有一个构造函数,那么*@Autowired*注释也可以省略。

@Component
public class Car {

    private Engine engine;
    private Transmission transmission;

    // @Autowired 4.3 之后可以省略
    public Car(Engine engine, Transmission transmission) {
        this.engine = engine;
        this.transmission = transmission;
    }

    @Override
    public String toString() {
        return String.format("Engine: %s Transmission: %s", engine, transmission);
    }
}

4.基于XML的配置

使用基于构造函数的依赖注入配置Spring运行时的另一种方法是使用xml配置文件:

<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="toyota" class="com.ripjava.constructordi.domain.Car">
        <constructor-arg index="0" ref="engine" />
        <constructor-arg index="1" ref="transmission" />
    </bean>
    
    <bean id="engine"
          class="com.ripjava.constructordi.domain.Engine">
        <constructor-arg index="0" value="v4" />
        <constructor-arg index="1" value="2" />
    </bean>
    
    <bean id="transmission"
          class="com.ripjava.constructordi.domain.Transmission">
        <constructor-arg value="sliding" />
    </bean>

</beans>

请注意,constructor-arg可以接受文字值或对另一个bean的引用,并且可以提供可选的显式索引类型类型索引属性可用于解决歧义(例如,如果构造函数采用相同类型的多个参数)。

在这种情况下,Spring应用程序上下文需要使用ClassPathXmlApplicationContext进行引导:

private static Car getCarFromXml() {
  ApplicationContext context = new ClassPathXmlApplicationContext("constructordi.xml");

  return context.getBean(Car.class);
}

5.结论

本快速教程展示了使用Spring框架使用基于构造函数的依赖注入的两种不同方法的基础知识。

最后,往常一样,代码可以在Github上找到。