LoggerProducer.java是一个用于生成要在CDI bean中注入的Logger的类:
- @Inject
- Logger LOG;
完整代码:
- import javax.ejb.Singleton;
- /**
- * @author rveldpau
- */
- @Singleton
- public class LoggerProducer {
- private Map<String,Logger> loggers = new HashMap<>();
- @Produces
- public Logger getProducer(InjectionPoint ip) {
- String key = getKeyFromIp(ip);
- if (!loggers.containsKey(key)) {
- loggers.put(key,Logger.getLogger(key));
- }
- return loggers.get(key);
- }
- private String getKeyFromIp(InjectionPoint ip) {
- return ip.getMember().getDeclaringClass().getCanonicalName();
- }
- }
问题:@Singleton可以安全地变成@ApplicationScoped吗?
我的意思是,为什么有人想在这里使用EJB?是否存在技术原因,因为不涉及任何交易,而且(AFAIK)无论如何都是线程安全的?
我显然是指javax.enterprise.context.ApplicationScoped,而不是javax.faces.bean.ApplicationScoped.
解决方法
@Singleton注释默认情况下不仅提供事务,还提供线程安全.因此,如果您将其替换为@ApplicationScoped,您将失去同步.所以为了使它正确,你需要这样做:
- @ApplicationScoped
- public class LoggerProducer {
- private final ConcurrentMap<String,Logger> loggers = new ConcurrentHashMap<>();
- @Produces
- public Logger getProducer(InjectionPoint ip) {
- String key = getKeyFromIp(ip);
- loggers.putIfAbsent(key,Logger.getLogger(key));
- return loggers.get(key);
- }
- private String getKeyFromIp(InjectionPoint ip) {
- return ip.getMember().getDeclaringClass().getCanonicalName();
- }
- }
如果将地图设置为静态,也可以完全没有任何范围