Java:方法链接和依赖注入

Han*_*ank 5 java dependency-injection hk2

在使用由依赖注入框架(比如HK2)管理的服务时,使用方法链是否可以接受?

我不确定是否允许"缓存"实例,即使它仅在注入范围内.

示例服务创建披萨:

@Service
public class PizzaService {

    private boolean peperoni = false;
    private boolean cheese = false;
    private boolean bacon = false;

    public PizzaService withPeperoni() {
        peperoni = true;
        return this;
    }

    public PizzaService withCheese() {
        cheese = true;
        return this;
    }

    public PizzaService withBacon() {
        bacon = true;
        return this;
    }

    public Pizza bake() {
        // create the instance and return it
    }
}
Run Code Online (Sandbox Code Playgroud)

这里将服务注入JAX-RS资源:

@Path('pizza')
public class PizzaResource {

    @Inject
    PizzaService pizzaService;

    @GET
    public Response getPizza() {
        Pizza pizza = pizzaService
            .withPeperoni()
            .withCheese()
            .bake();

        return Response.ok(pizza).build();
    }
}
Run Code Online (Sandbox Code Playgroud)

Han*_*ank 0

基于@JinKwon 的答案及其评论,这是我的解决方案:

  • 该服务被标记为@PerLookup,因为@Singleton这是默认值。(感谢@M. Deinum)
  • 根据原始类的生命周期,我通过Provider注入服务。这在 JAX-RS 资源中并不是什么大问题,因为它们已经是@RequestScoped默认的了。但其他代码(后台进程、单元测试等)可能具有不同的范围,并且Provider每次都会创建单独的新实例,从而产生差异。

按照这种方法,我可以使用方法链接,返回this. 另外,这对我来说很重要,该实例由 DI 内核管理,并且可以访问依赖注入本身。

服务:

@Service
@PerLookup
public class PizzaService {

    Pizza pizza = new Pizza(); // naked pizza by default

    @Inject
    OvenService    oven; // just to show that I can use @Inject here

    public PizzaService withPeperoni() {
        pizza.peperoni = true;
        return this;
    }

    public PizzaService withCheese() {
        pizza.cheese = true;
        return this;
    }

    public PizzaService withBacon() {
        pizza.bacon = true;
        return this;
    }

    public Pizza bake() {
        return oven.bake(pizza);
    }
}
Run Code Online (Sandbox Code Playgroud)

资源:

@Path('pizza')
public class PizzaResource {

    @Inject
    PizzaService pizzaService;

    @GET
    public Response getPizza() {
        Pizza pizza = pizzaService
            .withPeperoni()
            .withCheese()
            .bake();

        return Response.ok(pizza).build();
    }
}
Run Code Online (Sandbox Code Playgroud)

单元测试(通过 a 注入的示例javax.inject.Provider):

@HK2
@Test
public class PizzaServiceNGTest {

    @Inject
    PizzaService pizzaService;

    @Inject
    Provider<PizzaService> pizzaServiceProvider;

    public void testProviderInjection() {
        Pizza pizza;

        // pizza with the works
        pizza = pizzaServiceProvider.get()
            .withPeperoni()
            .withBacon()
            .withCheese()
            .bake();

        assertTrue(pizza.peperoni);
        assertTrue(pizza.bacon);
        assertTrue(pizza.cheese);

        // naked pizza
        pizza = pizzaServiceProvider.get()
            .bake();

        assertFalse(pizza.peperoni);
        assertFalse(pizza.bacon);
        assertFalse(pizza.cheese);
    }

    public void testDirectInjection() {
        Pizza pizza;

        // pizza with the works
        pizza = pizzaService
            .withPeperoni()
            .withBacon()
            .withCheese()
            .bake();

        assertTrue(pizza.peperoni);
        assertTrue(pizza.bacon);
        assertTrue(pizza.cheese);

        // naked pizza
        pizza = pizzaService
            .bake();

        // this is where it goes wrong: the pizzaService hasn't been reset and
        // is messing up the order!
        assertFalse(pizza.peperoni);    // will fail
        assertFalse(pizza.bacon);   // will fail
        assertFalse(pizza.cheese);  // will fail
    }

}
Run Code Online (Sandbox Code Playgroud)