OFBIZ:启动之StartupLoader

时间:2022-06-18 06:45:28

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