导航

OFBIZ:启动之StartupLoader

Posted on 2016-03-28 10:31  eastson  阅读(922)  评论(0编辑  收藏  举报

任意一个JAVA程序都是从main()开始启动的,OFBIZ也不例外。OFBIZ的main()位于framework/start/src/org/ofbiz/base/start/Start.java:

public final class Start {

    private static final Start instance = new Start();

    public static void main(String[] args) throws StartupException {
        ... ...
        
        instance.init(args, command == Command.COMMAND);
        try {
            if (command == Command.STATUS) {
                System.out.println("Current Status : " + instance.status());
            } else if (command == Command.SHUTDOWN) {
                System.out.println("Shutting down server : " + instance.shutdown());
            } else {
                // general start
                instance.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(99);
        }
    }
    
    void init(String[] args, boolean fullInit) throws StartupException {
        ... ...

        // initialize the startup loaders
        initStartLoaders();
    }

    private void initStartLoaders() throws StartupException {
        ClassLoader classloader = Thread.currentThread().getContextClassLoader();
        synchronized (this.loaders) {
            // initialize the loaders
            for (Map<String, String> loaderMap : config.loaders) {
                if (this.serverState.get() == ServerState.STOPPING) {
                    return;
                }
                try {
                    String loaderClassName = loaderMap.get("class");
                    Class<?> loaderClass = classloader.loadClass(loaderClassName);
                    StartupLoader loader = (StartupLoader) loaderClass.newInstance();
                    loader.load(config, loaderArgs.toArray(new String[loaderArgs.size()]));
                    loaders.add(loader);
                } catch (ClassNotFoundException e) {
                    throw (StartupException) new StartupException(e.getMessage()).initCause(e);
                } catch (InstantiationException e) {
                    throw (StartupException) new StartupException(e.getMessage()).initCause(e);
                } catch (IllegalAccessException e) {
                    throw (StartupException) new StartupException(e.getMessage()).initCause(e);
                }
            }
            this.loaders.trimToSize();
        }
        return;
    }

    void start() throws Exception {
        if (!startStartLoaders()) {
            if (this.serverState.get() == ServerState.STOPPING) {
                return;
            } else {
                throw new Exception("Error during start.");
            }
        }
        if (config.shutdownAfterLoad) {
            stopServer();
        }
    }
    
    boolean startStartLoaders() {
        synchronized (this.loaders) {
            // start the loaders
            for (StartupLoader loader : this.loaders) {
                if (this.serverState.get() == ServerState.STOPPING) {
                    return false;
                }
                try {
                    loader.start();
                } catch (StartupException e) {
                    e.printStackTrace();
                    return false;
                }
            }
        }
        return this.serverState.compareAndSet(ServerState.STARTING, ServerState.RUNNING);
    }
}

 

OFBIZ的main()过程可以简单理解为两个步骤:init()和start()。init()初始化StartupLoader,通过initStartLoaders()实现。start()启动StartupLoader,通过startStartLoaders()实现。
StartupLoader是一个接口,实现载入器的整个生命周期。

/**
 * An object that loads server startup classes.
 * <p>
 * When OFBiz starts, the main thread will create the <code>StartupLoader</code> instance and
 * then call the loader's <code>load</code> method. If the method returns without
 * throwing an exception the loader will be added to a list of initialized loaders.
 * After all instances have been created and initialized, the main thread will call the
 * <code>start</code> method of each loader in the list. When OFBiz shuts down, a
 * separate shutdown thread will call the <code>unload</code> method of each loader.
 * Implementations should anticipate asynchronous calls to the methods by different
 * threads.
 * </p>
 * 
 */
public interface StartupLoader {

    /**
     * Load a startup class.
     *
     * @param config Startup config.
     * @param args Command-line arguments.
     * @throws StartupException If an error was encountered. Throwing this exception
     * will halt loader loading, so it should be thrown only when OFBiz can't
     * operate without it.
     */
    public void load(Config config, String args[]) throws StartupException;

    /**
     * Start the startup class. This method must not block - implementations
     * that require thread blocking must create a separate thread and then return.
     * 
     * @throws StartupException If an error was encountered.
     */
    public void start() throws StartupException;

    /**
     * Stop the startup class. This method must not block.
     *
     * @throws StartupException If an error was encountered.
     */
    public void unload() throws StartupException;
}

 

initStartLoaders()从config.loaders获取可用的载入器信息,然后创建StartupLoader实例,调用load()方法。

private void initStartLoaders() throws StartupException {
    ClassLoader classloader = Thread.currentThread().getContextClassLoader();
    synchronized (this.loaders) {
        // initialize the loaders
        for (Map<String, String> loaderMap : config.loaders) {
            if (this.serverState.get() == ServerState.STOPPING) {
                return;
            }
            try {
                String loaderClassName = loaderMap.get("class");
                Class<?> loaderClass = classloader.loadClass(loaderClassName);
                StartupLoader loader = (StartupLoader) loaderClass.newInstance();
                loader.load(config, loaderArgs.toArray(new String[loaderArgs.size()]));
                loaders.add(loader);
            } catch (ClassNotFoundException e) {
                throw (StartupException) new StartupException(e.getMessage()).initCause(e);
            } catch (InstantiationException e) {
                throw (StartupException) new StartupException(e.getMessage()).initCause(e);
            } catch (IllegalAccessException e) {
                throw (StartupException) new StartupException(e.getMessage()).initCause(e);
            }
        }
        this.loaders.trimToSize();
    }
    return;
}


config.loaders来源于配置文件framework/start/src/org/ofbiz/base/start/start.properties。

# --- StartupLoader implementations to load (in order)
ofbiz.start.loader1=org.ofbiz.base.container.ContainerLoader
ofbiz.start.loader1.loaders=main,rmi


config是framework/start/src/org/ofbiz/base/start/Config.java的一个实例。Config类调用readConfig()过程读取start.properties中的配置信息。

public class Config {

    public List<Map<String, String>> loaders;

    public static Config getInstance(String[] args) throws IOException {
        String firstArg = args.length > 0 ? args[0] : "";
        // Needed when portoffset is used with these commands, start.properties fits for all of them
        if ("start-batch".equalsIgnoreCase(firstArg) 
                || "start-debug".equalsIgnoreCase(firstArg) 
                || "stop".equalsIgnoreCase(firstArg) 
                || "-shutdown".equalsIgnoreCase(firstArg)
                || "-status".equalsIgnoreCase(firstArg)) {
            firstArg = "start";
        }
        String configFileName = getConfigFileName(firstArg);
        Config result = new Config();
        result.readConfig(configFileName, args);
        return result;
    }

    private static String getConfigFileName(String command) {
        // default command is "start"
        if (command == null || command.trim().length() == 0) {
            command = "start";
        }
        return "org/ofbiz/base/start/" + command + ".properties";
    }
    
    public void readConfig(String config, String[] args) throws IOException {
        ... ...
        
        // loader classes
        loaders = new ArrayList<Map<String, String>>();
        int currentPosition = 1;
        Map<String, String> loader = null;
        while (true) {
            loader = new HashMap<String, String>();
            String loaderClass = props.getProperty("ofbiz.start.loader" + currentPosition);
            if (loaderClass == null || loaderClass.length() == 0) {
                break;
            } else {
                loader.put("class", loaderClass);
                loader.put("profiles", props.getProperty("ofbiz.start.loader" + currentPosition + ".loaders"));
                loaders.add(loader);
                currentPosition++;
            }
        }
    }
}