我可以在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
批注。
我知道您要做什么。
在任何给定时刻,您都希望获得系统中所有User
的快照。然后,对于每个人,您都希望存在一个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的事物的lifespan。
我希望这会有所帮助。
有效地,TheService
具有作用于用户名和年龄的doSomething()
方法。 TheService
也具有其他依赖项(@Inject
个字段/构造函数参数)。
为什么不通过使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!
}
};
}
}