在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...
。我们理解异常,并尝试生成像
@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>
进行注射。
@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来确认这一点。所以我们将继续我们的第一种方法似乎没问题。
答案 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;
// ...
}