java - 有没有办法重新注入(inject)/更新注入(inject)的 bean 字段?

标签 java jakarta-ee dependency-injection cdi weld

我有一些 bean(多种类型,CDI、@Stateless@Singleton bean)。他们的一些字段应该从数据库值中注入(inject)。

public class MyBean {

    @Inject
    @DbConfigValue(MyConfig.HOST)
    String host;
}

所以我添加了一个自定义 @Qualifier ( DbConfigValue ) 由生产者使用。生产者从数据库中读取并缓存配置值并将它们注入(inject)到 bean 中。
@Singleton
@Lock(LockType.READ)
public class Configuration {

    @Produces
    @Dependent
    @DbConfigValue
    public String getDbConfigValue(InjectionPoint point) {
        // get key for the config-value from qualifier-annotation of the injected field
        String key = point.getAnnotated().getAnnotation(DbConfigValue.class).value();
        // i have read+cached database config values in @PostConstruct before
        return cachedConfigValues.get(key);
    }
}

这适用于初始注入(inject)/bean 构造。一些网络教程建议使用这种方法。

现在,我认为假设配置值(如果存储在 DB 中)可能会在运行时发生变化是合理的。因此,每当管理员更改数据库配置值时,我目前都会触发 CDI 事件。

问题 : 有没有办法将值重新注入(inject)到已经初始化的 bean 实例的字段中?或者注入(inject)总是只与实例创建有关?

例如。我有……与此类似:
public class MyEventListener {

    @Inject
    BeanManager beanManager;

    @Asynchronous
    public void onDbConfigValueChangedEvent (@Observes(during = TransactionPhase.AFTER_SUCCESS) DbConfigValueChangedEvent event) {
        try {
            // could be filtered by custom qualifier:
            Set<Bean<?>> beans = beanManager.getBeans(Object.class,new AnnotationLiteral<Any>() {});

            for (Bean<?> bean : beans) {
                Set<InjectionPoint> points = bean.getInjectionPoints();
                // What now? javax.enterprise.inject.spi.Bean is the 
                // bean-representation only. 
                // Can I somehow resolve the actual bean-instances here?
                // Then update Field via Reflection?
            }
        }
        catch(Exception e){
            // ...
        }
    }
}

我也考虑过DeltaSpike其中有一些注入(inject)控制方法。但是,我确实只找到了注入(inject)新 bean 实例的方法,甚至是使用新的或空的CreationalContexts (之后的 bean 不是 CDI 管理的)

请注意:我知道我可以通过注入(inject)配置并显式获取每个请求的当前值来解决这个特定的用例,如下所示:
public class MyBean {

    @Inject
    Configuration config;

    public void someMethod(){
        String host = config.getConfig(MyConfig.HOST);
        // ...
    }
}

但是,我想知道一般的问题:是否支持重新注入(inject)?或者如果没有,规范(CDI 或 Java EE)是否禁止它?

最佳答案

根据您的数据库的快/慢,这可能会很昂贵。您可能会在生产者方法中利用一些缓存机制。
利用 Instance注入(inject)机制,延迟加载实际注入(inject)的 bean。

你的生产者(可能利用一些缓存来避免数据库调用所有的书)

@Singleton
@Lock(LockType.READ)
public class Configuration {

    @Produces
    @RequestScoped //May fail if not in a request-context, but for ejb-calls, it is guaranteed to work as CDI has EJB Request Context
    @DbConfigValue
    public String getDbConfigValue(InjectionPoint point) {
        // get key for the config-value from qualifier-annotation of the injected field
        String key = point.getAnnotated().getAnnotation(DbConfigValue.class).value();
        // i have read+cached database config values in @PostConstruct before
        return cachedConfigValues.get(key);
    }
}

以及注入(inject)点:
@SessionScoped
public class MyBean {

    @Inject
    @DbConfigValue(MyConfig.HOST)
    private Instance<String> host;

    public void doSomething() {
        String myHost = host.get(); // of course will throw exception if value is failing. It will be resolved with every request.
    }
}

关于java - 有没有办法重新注入(inject)/更新注入(inject)的 bean 字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37993435/

相关文章:

java - 我总是得到父类的实例。但我需要一个子类

java - Servlet 未应用更改

c# - 将依赖项注入(inject)类库中的 AuthorizeAttribute

java - 将二维 ArrayList 转换为二维数组

java - 根据 SWT 所做的选择修改列表

java - 加密在唯一文件中附加字节的文件 - 异常 : Given final block not properly padded

jakarta-ee - 在哪里可以下载 Java EE 6 教程示例?

java - 如何仅将 XMLGregorianCalendar 与日期部分(日、月、年)进行比较?

java - Spring 值注入(inject)无法从属性中获取值

android - 在 WorkManager 的 Worker 中注入(inject) Repository