任意一个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++; } } } }