Java EE中是否允许以下内容?
我有一个@Singleton
会话bean作为注册表工作,并自动发现整个应用程序中使用的某些策略,如下所示:
public interface Strategy {
Class<?> supportedType();
}
@Singleton
public class StrategyRegistry {
@Inject
private Instance<Strategy> strategies;
private Map<Class<?>, Strategy> registry = new HashMap<>();
@PostConstruct
public void startup() {
Iterator<Strategy> it = strategies;
while (it.hasNext()) {
Strategy s = it.next();
registry.put(s.supportedType(), s);
}
}
// return provided strategy to caller
public Strategy strategyFor(Class<?> clz) {
return registry.get(clz);
}
}
现在我的问题是,是否允许将@Inject
CDI bean分享给其他客户(通过#strategyFor(...)
),或者是否会导致意外行为或副作用?
策略是无状态和线程安全的,因此通常应该可以同时使用它们。
请注意,上面的CDI bean的所有者是@Singleton
,而CDI bean当前是@Dependent
,所以如果我正确地阅读了规范,那么它们应该在整个生命周期内可用。应用
最初我们使用了EJB无状态bean,strategyFor(...)
只将代理返回给实际的bean,我认为这是合理安全的。使用最近的WELD版本的Wildfly 8不再可能这样,因此我们切换到CDI bean。但是,对于CDI bean,将返回实际的bean,而不是代理。
如果不允许,以下是安全的选择吗?
@Inject private BeanManager beanManager;
public Strategy strategyFor(Class<?> clz) {
Strategy s = registry.get(clz);
if (s == null) return null;
return beanManager.getReference(s.getClass());
}
答案 0 :(得分:1)
请参阅以下
@Qualifier
@Retention(RUNTIME)
@Target({FIELD,METHOD,TYPE,PARAMETER})
public interface StrategyContext {
//Nonbinding and default so that you can have one producer method for all strategies
@NonBinding
Class<?> supportedType() default Object.class;
}
@Singleton
public class StrategyRegistry {
private Map<Class<?>, Strategy> registry = new HashMap<>();
@Inject
void startup(@Any final Instance<Strategy> strategies) {
for(Strategy strategy:strategies)
registry.put(Strategy.supportedType(), Strategy);
}
}
@Produces
@StrategyContext
@ApplicationScoped
public Strategy strategyFor(final InjectionPoint ip) {
final StrategyContext sc = ip.getAnnotated().getAnnotation(StrategyContext.class);
final Class<?> supportedType = sc.supportedType();
return registry.get(supportedType);
}
}
然后你想在哪里使用它。
@Stateless
public class MyService {
@Inject
@StrategyContext(supportedType=MySupportedType.class)
private Strategy strategy;
}
关于生产者和注射点:
请注意 如果在运行时,策略可能不存在,因此该方法可能返回null,然后使用@Dependent注释生产者,而不是@ApplicationScope,因此在注入点,不要注入原始策略,但是:
@Inject
@StrategyContext(supportedtype=MySupportedType.class)
private Instance<Strategy> strategy
...
if(!strategy.isUnsatisfied()) { strategy.get().doSomething();}
答案 1 :(得分:1)
我不明白为什么不这样做,因为@Depend(默认范围)是伪范围,因此bean管理器不再对bean感兴趣。它的生命周期完全取决于外部bean或其他直接引用它的类 - 它是一个普通的旧POJO