在EJB中注入字符串值:如何处理修改后的值?

时间:2015-11-26 14:48:27

标签: java-ee dependency-injection ejb cdi java-ee-6

在JavaEE 6环境(glassfish和WLS)中,我们使用CDI生产者将配置信息注入像这样的无状态EJB

@Stateless
public class MyBusinessEJB {

    @Inject @MyConfigurationQualifier
    private String configValue;

    public void someBusinessMethod() {
        LOG.log( Level.INFO, "current config: {0}", configValue );
    }
}

@Stateless
public class MyProducerEJB {

    @Produces @MyConfigurationQualifier
    public String getConfigurationFromDB() {
        return ...;
    }
}

现在,配置信息可能会在数据库中不时发生变化。但是这些更改并未反映在EJB中注入的String中。我认为这很好,因为EJB生命周期,EJB实例长期为大量客户服务。配置是在EJB生命的最初阶段注入的,之后不会更新。

作为第一个解决方法,我们尝试将@RequestScoped添加到producer方法,这会导致异常WELD-001435: ...String... is not proxyable...。我们理解异常,并尝试生成像

这样的Wrapper-Bean
@Produces @MyConfigurationQualifier @RequestScoped
public Wrapper getConfigurationFromDB() {
   return new Wrapper( originalStringValue );
}

public class Wrapper {
    private String configValue;
    public Wrapper() {} // needed for CDI proxying
    public Wrapper( String configValue ) { this.configValue = configValue; }
    public String get() { return configValue; }
}

这样做很好 - 但是使用wrapper.get()一直感到不方便。

作为第二种解决方法,我们使用Instance<String>进行注射。 @RequestScoped,也不再需要包装器。

@Stateless
public class MyBusinessEJB {

    @Inject @MyConfigurationQualifier
    private Instance<String> configValue;

    public void someBusinessMethod() {
        LOG.log( Level.INFO, "current config: {0}", configValue.get() );
    }
}

@Stateless
public class MyProducerEJB {

    @Produces @MyConfigurationQualifier
    public String getConfigurationFromDB() {
        return ...;
    }
}

这也有效。但是我们必须再次在业务EJB中调用instance.get()。当然Instance也是某种包装。

现在的问题是:

是否指定Instance.get()将始终返回更新的对象,即使没有使用@RequestScoped注释生产者方法?我无法在javadoc或规范中找到提示。

是否有一种更方便的方法可以在不使用包装类的情况下将String直接注入EJB,但每次调用EJB业务方法时都可以使用更新的数据(或者可能针对每个事务或某些定义的时间) ?

更新

感谢John的评论,我发现了this错误报告和this常见问题解答。如果我理解正确,我们的第二个解决方法将导致内存泄漏,因为每次调用Instance.get()都会将新的String实例放入EJB范围,这与@ApplicationScope完全相同。我可以通过查看应用程序的heapdump来确认这一点。所以我们将继续我们的第一种方法似乎没问题。

1 个答案:

答案 0 :(得分:1)

抱歉,我没有回答你的问题,因为恕我直言你想要达到的目标并没有多大意义。

从我的角度来看,你应该写得像:

@ApplicationScoped
public class AppConfig {

    public String getConfigValue(String key) {
        // ...
        return value;
    }

    // launched by some scheduler from time to time
    public synchronized void refreshConfigurationFromDB() {
        // ...
    }
}

然后仅注入AppConfig实例:

@Stateless
public class MyBusinessEJB {

    @Inject
    private AppConfig config;

    // ...
}