如何在带参数的for循环内注入bean

问题描述 投票:0回答:2

我可以在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批注。

java cdi javabeans java-ee-8
2个回答
1
投票

我知道您要做什么。

在任何给定时刻,您都希望获得系统中所有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

我希望这会有所帮助。


1
投票

有效地,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!
            }
        };
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.