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上找到。