当前位置: 首页 > 知识库问答 >
问题:

Java:方法链接和依赖注入

董洲
2023-03-14

使用依赖注入框架(比如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
    }
}

在这里,服务被注入到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();
    }
}

共有3个答案

林子石
2023-03-14

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

  • 该服务被标记为@PerLookup,因为@Singleton是默认值。(谢谢@M.Deinum)

按照这种方法,我可以使用方法链接,返回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);
    }
}

资源:

@Path('pizza')
public class PizzaResource {

    @Inject
    PizzaService pizzaService;

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

        return Response.ok(pizza).build();
    }
}

Unittest(通过javax.inject.提供程序注入的示例):

@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
    }

}
景河
2023-03-14

这取决于JAX-RS资源的范围和服务的无状态。

通常,每次请求时都会创建每个JAX-RS资源实例。

默认情况下,将为对该资源的每个请求创建一个新的资源类实例。首先调用构造函数(参见第3.1.2节),然后注入任何请求的依赖项(参见第3.2节),然后调用适当的方法(参见第3.3节),最后使对象可用于垃圾收集。

对于以下HTTP请求,

GET /pizza HTTP/1.1

创建了一个新的PizzaResources实例,并在其中注入了一个可用的PizzaService实例。

现在,您要寻找的答案取决于容器可能维护的PizzaService的无状态性和生命周期。

希望我现在找不到规范,但是,即使PizzaService@无状态的,容器也不会为不同的会话同时共享实例。

我将使用生命周期侦听器方法重置服务。

@Path("/pizza")
public class PizzaResource {

    @PostConstruct
    private void resetPizzaService() { // invoked after the injection
        pizzaService.reset();
    }

    @Inject
    private PizzaService pizzaService;
}

其中重置()将执行

public void reset() {
    peperoni = false;
    cheese = false;
    bacon = false;
}

我刚刚为@Service找到了一个好的线程,它似乎是Spring框架的一部分。单例Bean如何处理并发请求?

仲孙小云
2023-03-14

您所做的对服务的所有其他用户都有副作用。它们都共享同一个服务实例,因此如果您使用peperoni调用,它将为所有引用该服务的用户更改该布尔值。

您似乎想要的是使用Builder。也许你的服务可以实例化一个新的建设者,负责为你打造完美的比萨饼。这样可以避免所有可能的副作用:

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

    return Response.ok(pizza).build();
}

和比萨饼制造商:

public class PizzaBuilder {

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

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

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

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

    public Pizza bake() {
        // create the instance and return it
    }
}

和比萨服务:

@Service
public class PizzaService {

    public PizzaBuilder newPizzaBuilder() {
        return new PizzaBuilder();
    }
}

这个解决方案并不完美,因为只实例化构建器的服务没有太多用处,但是它至少可以防止您的解决方案会遇到的副作用。

 类似资料:
  • 问题内容: 在Java 8中,类型推断已扩展到目标类型,从而可以编写: 无需使用类型见证()。但是,下面的最后一条语句无法编译。有什么原因吗?有解决方法吗? 问题答案: 该问题已通过内部版本129修复(但直到内部版本128才出现)。

  • 在之前的所有JUnit版本中,测试构造函数或方法都不允许有参数(至少不能使用标准的Runner实现)。作为JUnit Jupiter的主要变化之一,测试构造函数和方法现在都允许有参数。这带来了更大的灵活性,并为构造函数和方法启用依赖注入。 ParameterResolver定义了测试扩展的API,希望在运行时动态解析参数。如果测试构造函数或@Test, @TestFactory, @BeforeE

  • 同事们,你们好!是可能注入bean类内创建通过'new'运算符?例如: “TestClass”是从另一个类创建的: 我对此有异议,因为“存储库”。TestClass内部的anyMethods()创建“NullPointer”异常TestClassRepository'标记有“@ApplicationScoped”和“@Startup”注释。

  • 到现在为止,我们使用是硬编码的三条手机记录数据集。现在我们使用AngularJS一个内置服务$http来获取一个更大的手机记录数据集。我们将使用AngularJS的 依赖注入(dependency injection (DI))功能来为PhoneListCtrl控制器提供这个AngularJS服务。 请重置工作目录: git checkout -f step-5 刷新浏览器,你现在应该能看到一个2

  • 容器和依赖注入 5.1版本正式引入了容器的概念,用来更方便的管理类依赖及运行依赖注入。 5.0版本已经支持依赖注入的,依赖注入和容器没有必然关系 容器类的工作由think\Container类完成,但大多数情况我们只需要通过app助手函数即可完成大部分操作。 依赖注入其实本质上是指对类的依赖通过构造器完成自动注入,例如在控制器架构方法和操作方法中一旦对参数进行对象类型约束则会自动触发依赖注入,由于

  • 我想从基于xml的Spring配置切换到基于java的配置。对于构造函数类型注入,这很容易。我正在使用的示例: 但是,当我想通过setter方法注入时,我是这样做的: 我不确定这是否是注入基于Java的配置和setter方法的可能方法。不幸的是,我找不到任何示例(对于构造函数依赖项,存在很多示例)。另外,我不确定在基于Java的配置的情况下,我应该何时使用构造函数,何时使用setter。在Spri