'How to register bean programatically in Quarkus?
I am trying to find a way how to programatically create bean in quarkus DI, but without success. Is it possible in this framework? It seems that BeanManager does not implement the needed method yet.
Solution 1:[1]
First, we should clarify what "programatically create bean" exactly means.
But first of all, we should define what "bean" means. In CDI, we talk about beans in two meanings:
- Component metadata - this one describes the component attributes and how a component instance is created; the SPI is
javax.enterprise.inject.spi.Bean - Component instance - the real instance used in application; in the spec we call it "contextual reference".
The metadata is usually derived from the application classes. Such metadata are "backed by a class". By "backed by a class" I mean all the kinds described in the spec. That is class beans, producer methods and producer fields.
Now, if you want to programatically obtain a component instance (option 2), you can:
- Inject
javax.enterprise.inject.Instance; see for example the Weld docs - Make use of
CDI.current().select(Foo.class).get() - Make use of quarkus-specific
Arc.container().instance(Foo.class).get()
However, if you want to add/register a component metadata that is not backed by a class (option 2), you need to add an extension that makes use of quarkus-specific SPIs, such as BeanRegistrar.
Solution 2:[2]
If you are looking for Quarkus equivalent of Spring @Configuration then you want "bean producer" (as mentioned in comments above)
Here is an example(koltin) of how to manually register a clock:
import java.time.Clock
import javax.enterprise.context.ApplicationScoped
import javax.enterprise.inject.Produces
@ApplicationScoped
class AppConfig {
@Produces
@ApplicationScoped
fun utcClock(): Clock {
return Clock.systemUTC()
}
}
@Producesis actually not required if method is already annotated with@ApplicationScoped@ApplicationScopedat class level ofAppConfigis also not required
Although, I find those extra annotations useful, especially if are used to Spring.
Solution 3:[3]
You can inject your beans using Instance:
@Inject
public TestExecutorService(final ManagedExecutor managedExecutor,
final Instance<YourTask> YourTask) {
this.managedExecutor = managedExecutor;
this.YourTask= YourTask;
}
And if you need to create more than one Instance you can use the managed executor:
tasks.forEach(task -> managedExecutor.submit(task::execute));
Keep in mind that depending on the way you start the bean you may need to destroy it and only the "creator class" has its reference, meaning you have to create and destroy the bean in the same classe (you can use something like events to handle that).
For more information please check: CDI Documentation
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Martin Kouba |
| Solution 2 | rozky |
| Solution 3 |
