Large java projects can have problems with static initialization in classes.  This is usually caused by static initializers that take a long time to execute or have circular dependencies with other static initializer classes.  Worse, these static code sections are not part of normal program flow and programmers tend to forget to catch exceptions in them.  Such problems are very difficult to debug because the objects are half constructed, almost as if the constructors themselves are not working properly.

public class DatabaseManager
{
    /** analysis data for each table */
    private static TableMapping mapping;

    // Load all the table information
    static
    {
        mapping = new MappingHandler();
        mapping.loadTables();  // this method call takes almost a minute.
  
        // About to do another method call that takes a minute or so
        mapping.setClasses(ClassManager.getClasses());   
        :
        :
    }
}

There are a few other problems with this real world example. The call to mapping.loadTables() can fail if the database is not ready, yet no exceptions are caught or logged, there is no way to retry, and mapping will be instantiated but invalid.  The program should still start if the database is temporarily unavailable.  But it gets worse when you look into ClassManager:

public class ClassManager
{
    // Load all the model class types to set their database mapping link
    static
    {
        ArrayList loadedTables = DatabaseManager.getMapping().getLoadedTables();
        // Circular dependency!
        // DatabaseManager hasn't finished its static initialization!
        :

ClassManager has a static initializer too which has a circular dependency back on the static initializer in DatabaseManager.  If DatabaseManager has not finished its static initialization, the call back will be invalid.

Tip: If the code in a static initializer takes more than an instant to execute, it should be elsewhere.  Don't load files or connect to external resources such as databases in a static initializer.

Code in static initializers invariably ends up having a dependency on other static code being initialized and the startup order cannot easily be determined.

Perhaps there's no time to refactor all the static initializers in a maintenance project.  One quick fix is to do all static initialization in one class that runs first when the application loads, referencing each class in the special order you need them to be initialized:

public class InitialServlet
{
    static
    {
        Class notUsed;

        // run static initializers of DbManager
        notUsed = DbManager.class;     

        // run static initializers of IntegrationManager
        notUsed = IntegrationManager.class;   
        :
    }
}

But it's still pretty ugly and won't solve circular dependencies. Far better to use singletons.

public class DatabaseManager
{
private static DatabaseManager instance;
private boolean initialized = false;

public static DatabaseManager getInstance()
{
if (instance == null)
{
               instance = new DatabaseManager();
}
           if (!instance.initialized)
           {
               instance.loadTables();
           }
return instance;
}


     /** Private so only obtainable through getInstance() */
    private DatabaseManager()
    {
        :
    }

    private static synchronized void loadTables()
    {
        if (initialized) return;
        :
    }
    :
}

Problems with dependency loading order generally means a flawed package structure or design.

Do classes really need to wait for others to finish before they can be fully constructed? They should be robust enough to wait politely until all the information they need is ready.

Tip: Spring does not tend to have startup order dependency problems, because all dependencies are injected and it sorts out which classes should be instantiated first.  It even provides singleton support through configuration

Spring even provides singleton support through configuration:

<bean class="com.xyz.timesheet.service.holiday.DefaultHolidayService"
      id="holidayService"  
      scope="singleton" />

  

blog comments powered by Disqus