如何处理单例模式中的异常处理?

时间:2017-02-19 01:00:57

标签: java design-patterns exception-handling singleton

我试图了解如何处理异常处理。我有我的下面的Singleton类连接到cassandra,初始化第一次调用的所有元数据,然后启动一个定期的后台线程,每15分钟更新一次我们的元数据。

public class CassUtils {
  private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
  private final CassSession cassSession;

  private static class Holder {
    private static final CassUtils INSTANCE = new CassUtils();
  }

  public static CassUtils getInstance() {
    return Holder.INSTANCE;
  }

  private CassUtils() {
    CassConfig config = Utils.getConfig();
    try {
      this.cassSession = new CassSession(config);
      initializeMetadata(); // initializes metadata on the very first call
    } catch (Exception ex) {
      // log error
      throw new IllegalStateException("cannot initialize metadata: " + ex.getMessage());
    }
  }

  private void startScheduleTask() {
    scheduler.scheduleAtFixedRate(new Runnable() {
      public void run() {
        try {
          List<ProcessMetadata> processMetadata = getProcessMeta();
          List<ClientMetadata> clientMetadata = getClientMeta();
          List<ProcMetadata> procMetadata = getProcMeta();
          if (!processMetadata.isEmpty() && !clientMetadata.isEmpty())
            MetadataManager.setMetadata(processMetadata, clientMetadata, procMetadata);
        } catch (Exception ex) {
            // log error
        }
      }
    }, 30, 15, TimeUnit.MINUTES);
  }

  private void initializeMetadata() {
    List<ProcessMetadata> processMetadata = getProcessMeta(true);
    List<ClientMetadata> clientMetadata = getClientMeta();
    List<ProcMetadata> procMetadata = getProcMeta();
    if (processMetadata.isEmpty() || clientMetadata.isEmpty() || procMetadata.isEmpty()) {
      throw new IllegalStateException(); // is it ok to throw exception without any message here?
    }
    MetadataManager.setMetadata(processMetadata, clientMetadata, procMetadata);
    startScheduleTask();
  }

如果有任何问题,我需要通知正在调用此单例的调用方。

  • 现在无论出于何种原因,如果CassSession抛出异常,因为这是连接到cassandra的类,并且由于某种原因它无法连接到cassandra(大多数情况下它永远不会发生),那么我在{中捕获异常{1}}在catch类中阻止并向用户发送CassUtils,并在其中显示消息。
  • 还可以说,如果我们能够通过IllegalStateException(我们将永远)连接到cassandra,但在CassSession方法中,我们所有的元数据都是空的,那么我就不会# 39;我想继续前进,所以我扔了initializeMetadata而没有任何消息。这可以吗?因为最终它会被IllegalStateException类的catch块捕获,这会给调用用户抛出异常。

如何在单例情况下处理异常处理,以便我们可以通知正在调用此单例的呼叫者。 CassUtils是被抛到这里的正确例外吗?上述情况将在初始化时的第一次调用期间发生。还有更好的方法吗?

1 个答案:

答案 0 :(得分:1)

您正在使用静态/类初始化来创建ClassUtils实例。作为一般规则:

  • 必须捕获在类初始化中引发的所有已检查异常。编译器坚持认为。
  • 从类静态初始化传播出来的任何未经检查的异常最终都会导致Error被抛出。即使在您能够捕获此错误的上下文中,您也会遇到初始化失败的类。 JVM不会重试初始化,并且类......以及依赖它的任何其他类都将无法使用。

因此,如果您要处理此问题,则需要在静态初始化期间捕获并(适当地)处理异常

接下来的问题是,如果要向CassUtils单例的用户报告失败,那么getInstance()必须返回CassUtils(或者可能是子类)的实例能够:

  1. 记住异常或任何报告失败的内容,
  2. 将其重新抛出到CassUtils API上的实例方法的调用者。
  3. 这是可能的,但很复杂。

    IMO是不受欢迎的。我认为你最好不要试图恢复。将Casandra会话初始化失败视为致命错误。如果你不能这样做,那么getInstance()方法应该是抛出/重新抛出“我们被破坏”的异常的方法。至少,这避免了任何CassUtils方法的任何调用者都需要处理“我们被破坏”的异常。

    有没有人提到过单身人士是个坏主意?请考虑使用依赖注入。