0

我可以在 for 循环中注入带有参数的 Bean 吗?我不想TheService在以下示例中手动初始化:

@Singelton
public class Scheduler {
    @Inject
    private UserQueryService userQueryService;

    @Schedule(hour = "*", minute = "*", second = "*/30", persistent = false)
    public void execute() {
        final List<User> users = userQueryService.findAll();
        for (final User user : users) {
            final TheService service = new TheService(user.getName(), user.getAge());
            service.doSomething();
        }
    }
}

例如,运行时是否可以将值从 for 循环注入到生产者的方法并使用 CDI 注入服务?我知道,不能注入 String 和原始值,但也许你可以帮助我并提出一些解决方案。

@ApplicationScoped
public class TheServiceFactory {
    @Produces
    @RequestScoped
    public TheService createTheService(final String name, final int age) {
        ...
    }
}

更新: 有其他带有注释的TheService字段。@Inject

4

2 回答 2

1

我明白你想做什么。

在任何给定时刻,您都希望获得User系统中所有 s 的快照。然后,对于每一个,你都希望存在一个RequestScoped TheService,然后它会被用来做某事。

正如所写,这对于 CDI 来说是不可能的。

我假设您想生成一个TheService实例并使用 CDI 的依赖机制,因为TheService有一些带@Inject注释的字段?我只是猜测。

如果是这样,您可以像这样伪造它:

final Unmanaged<TheService> unmanagedService = new Unmanaged<TheService>(TheService.class);
final UnmanagedInstance<TheService> serviceInstance = unmanagedService.newInstance();
final TheService service = serviceInstance.produce().inject().postConstruct().get();
// Any @Inject-annotated fields in service will now be "filled" if possible; that's
// what the inject() call above does; any @PostConstruct methods it has will have been
// invoked, etc.
// You'll have to manually set its user and age properties:
service.setUser(user.getName());
service.setAge(user.getAge());
service.doSomething();
// The TheService instance is NOT in request scope; *you* are fully in control
// of its lifecycle, so don't forget to dispose it when you're done.  You may
// need to put this in a finally block to ensure it happens:
serviceInstance.preDestroy().dispose();

CDI bean 在设计上是“静态的”。您想要做的是动态的,即它在运行时发生变化(也许查询服务User在每次调用时返回完全不同的实例)。所以注入一个完全托管TheService的并不是你真正想要做的,因为你无法预测它们中有多少或者它们将如何构建。

CDI 中的Unmanaged构造适用于当您想要管理自己本来是 CDI bean 的东西的生命周期时。

我希望这有帮助。

于 2020-01-15T02:00:30.937 回答
1

有效地TheService具有doSomething()作用于用户名和年龄的方法。TheService也有其他依赖项(@Injected 字段/构造函数参数)。

为什么不通过在上创建TheService @ApplicationScoped和定义参数来明确这一点doSomething(),即:

@ApplicationScoped
public class TheService {
    @Inject DependencyOne dependencyOne;
    @Inject DependencyTwo dependencyTwo;

    public void doSomething(String userName, int age) {
        // use dependencies
    }
}

如果doSomething()实际上需要为每个循环迭代保持状态,例如您真正想要的是:

@Schedule(hour = "*", minute = "*", second = "*/30", persistent = false)
public void execute() {
    final List<User> users = userQueryService.findAll();
    for (final User user : users) {
        final TheService service = new TheService(user.getName(), user.getAge());
        service.doSomething();
        // ...
        service.doSomethingElse();
    }
}

然后您可以将每次迭代的状态封装在另一个对象中,例如(假设 Java >= 8):

// TheServiceWorker.java
public interface TheServiceWorker {
    void doSomething();
    void doSomethingElse();
}

// TheService.java
@ApplicationScoped
public class TheService {
    @Inject DependencyOne dependencyOne;
    @Inject DependencyTwo dependencyTwo;

    public TheServiceWorker makeWorker(String userName, int age) {
        return new TheServiceWorker() {
            public void doSomething() {
                // you can access dependencyOne, dependencyTwo
                // AND userName, age here!
            }

            public void doSomethingElse() {
                // you can access dependencyOne, dependencyTwo
                // AND userName, age here!
            }
        };
    }
}
于 2020-01-15T19:57:52.267 回答