构造函数注入

将依赖项注入类的常见情况是使用构造函数注入。这涉及使用 @Inject 在类上注释构造函数。在创建类的实例时,CDI 管理器将查找带有 @Inject 批注的构造函数。当它找到 @Inject-annotated 构造函数时,它将使用反射来查找构造函数所需的参数,构造或获取这些依赖项的实例,然后使用这些依赖项调用构造函数。

public class Spaceship {

    private final PropulsionSystem propulsionSystem;
    private final NavigationSystem navigationSystem;

    @Inject
    public Spaceship(PropulsionSystem propulsionSystem, NavigationSystem navigationSystem) {
        this.propulsionSystem = propulsionSystem;
        this.navigationSystem = navigationSystem;
    }

    public void launch() throws FlightUnavailableException {
        if (propulsionSystem.hasFuel()) {
            propulsionSystem.engageThrust();
        } else {
            throw new FlightUnavailableException("Launch requirements not met. Ship needs fuel.");
        }
    }

}

每当以这种方式定义的 Spaceship 实例由 CDI 创建时,它将接收 PropulsionSystem 和 NavigationSystem 作为其构造函数的参数。因为这些依赖项是通过构造函数添加的,所以我们有一种简单的方法可以在单元测试时在测试工具中提供备用依赖项:

public class SpaceshipTest {

    private Spaceship systemUnderTest;
    private TestPropulsionSystem testPropulsionSystem;
    private TestNavigationSystem testNavigationSystem;

    @Before
    public void setup() {
        setupCollaborators();
        systemUnderTest = new Spaceship(testPropulsionSystem, testNavigationSystem);
    }

    @Test
    public void launchSequenceEngagesThrustIfFueled() {
        //given
        testPropulsionSystem.simulateHavingFuel();

        //when
        systemUnderTest.launch();

        //then
        testPropulsionSystem.ensureThrustWasEngaged();
    }

}