LoggerProducer.java是用于生成记录器的类,该记录器将通过以下方式注入(inject)到CDI bean中:

@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();
  }
}

如果将 map 设为静态,也可以完全没有任何范围

10-01 03:18