ContainerLoader类实现StartupLoader接口,目的是装入各种Container容器。
/** * An OFBiz container. A container can be thought of as a background process. * * <p> * When OFBiz starts, the main thread will create the <code>Container</code> instance and * then call the container's <code>init</code> method. If the method returns without * throwing an exception the container will be added to a list of initialized containers. * After all instances have been created and initialized, the main thread will call the * <code>start</code> method of each container in the list. When OFBiz shuts down, a * separate shutdown thread will call the <code>stop</code> method of each container. * Implementations should anticipate asynchronous calls to the methods by different * threads. * </p> * * <p>Containers might be loaded more than once (have more than one instance).<p> */ public interface Container { /** Initialize the container. This method must not block - implementations * should initialize internal structures and then return. * * @param args Command-line arguments. * @param name Unique name of the container's instance. * @param configFile Location of the configuration file used to load this container. * @throws ContainerException If an error was encountered. Throwing this exception * will halt container loading, so it should be thrown only when other containers * might depend on this one. */ public void init(String[] args, String name, String configFile) throws ContainerException; /** * Start the container process. This method must not block - implementations * that require thread blocking must create a separate thread and then return. * * @return <code>true</code> if the process started. * @throws ContainerException If an error was encountered. */ public boolean start() throws ContainerException; /** * Stop the container process. This method must not block. * * @throws ContainerException If an error was encountered. */ public void stop() throws ContainerException; /** * Return the container name. * * @return Name of the container's instance. */ public String getName(); }
ContainerLoader会以三种方式寻找Container。第一种方式从配置文件中找,默认的配置文件是framework/base/config/ofbiz-containers.xml。第二种方式找组件Component总定义的容器。第三种方式找hot-deploy容器,这也是一个配置文件hot-deploy-containers.xml。
ofbiz-containers.xml定义了整个OFBIZ最重要的ComponentContainer容器,该容器载入所有的Component。
<ofbiz-containers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/ofbiz-containers.xsd"> <!-- load the ofbiz component container (always first) --> <container name="component-container" loaders="main,rmi,pos,install" class="org.ofbiz.base.container.ComponentContainer"/> <container name="component-container-test" loaders="test" class="org.ofbiz.base.container.ComponentContainer"> <property name="ofbiz.instrumenterClassName" value="org.ofbiz.base.config.CoberturaInstrumenter"/> <property name="ofbiz.instrumenterFile" value="runtime/logs/cobertura-components.dat"/> </container> <container name="component-container-limited" loaders="limited" class="org.ofbiz.base.container.ComponentContainer"> <property name="update-classpath" value="false"/> </container> <container name="component-container" loaders="testlist" class="org.ofbiz.base.container.JustLoadComponentsContainer"/> </ofbiz-containers>
ContainerLoader首先载入ofbiz-containers.xml中的容器:
this.loadedContainers.clear(); // get this loader's configuration file // default: framework/base/config/ofbiz-containers.xml this.configFile = config.containerConfig; Collection<ContainerConfig.Container> containers = null; try { containers = ContainerConfig.getContainers(configFile); } catch (ContainerException e) { throw new StartupException(e); } for (ContainerConfig.Container containerCfg : containers) { if (this.unloading) { return; } boolean matchingLoaderFound = false; if (UtilValidate.isEmpty(containerCfg.loaders) && UtilValidate.isEmpty(loaders)) { matchingLoaderFound = true; } else { for (String loader: loaders) { if (UtilValidate.isEmpty(containerCfg.loaders) || containerCfg.loaders.contains(loader)) { matchingLoaderFound = true; break; } } } if (matchingLoaderFound) { Debug.logInfo("Loading container: " + containerCfg.name, module); Container tmpContainer = loadContainer(containerCfg, args); this.loadedContainers.add(tmpContainer); Debug.logInfo("Loaded container: " + containerCfg.name, module); } } private Container loadContainer(ContainerConfig.Container containerCfg, String[] args) throws StartupException { // load the container class ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader == null) { Debug.logWarning("Unable to get context classloader; using system", module); loader = ClassLoader.getSystemClassLoader(); } Class<?> containerClass = null; try { containerClass = loader.loadClass(containerCfg.className); } catch (ClassNotFoundException e) { throw new StartupException("Cannot locate container class", e); } if (containerClass == null) { throw new StartupException("Component container class not loaded"); } // create a new instance of the container object Container containerObj = null; try { containerObj = (Container) containerClass.newInstance(); } catch (InstantiationException e) { throw new StartupException("Cannot create " + containerCfg.name, e); } catch (IllegalAccessException e) { throw new StartupException("Cannot create " + containerCfg.name, e); } catch (ClassCastException e) { throw new StartupException("Cannot create " + containerCfg.name, e); } if (containerObj == null) { throw new StartupException("Unable to create instance of component container"); } // initialize the container object try { containerObj.init(args, containerCfg.name, configFile); } catch (ContainerException e) { throw new StartupException("Cannot init() " + containerCfg.name, e); } catch (java.lang.AbstractMethodError e) { throw new StartupException("Cannot init() " + containerCfg.name, e); } return containerObj; }
然后载入Component中定义的容器:
List<ContainerConfig.Container> containersDefinedInComponents = ComponentConfig.getAllContainers(); for (ContainerConfig.Container containerCfg: containersDefinedInComponents) { boolean matchingLoaderFound = false; if (UtilValidate.isEmpty(containerCfg.loaders) && UtilValidate.isEmpty(loaders)) { matchingLoaderFound = true; } else { for (String loader: loaders) { if (UtilValidate.isEmpty(containerCfg.loaders) || containerCfg.loaders.contains(loader)) { matchingLoaderFound = true; break; } } } if (matchingLoaderFound) { Debug.logInfo("Loading component's container: " + containerCfg.name, module); Container tmpContainer = loadContainer(containerCfg, args); this.loadedContainers.add(tmpContainer); Debug.logInfo("Loaded component's container: " + containerCfg.name, module); } }
第三步载入hot-deploy容器:
ClassLoader loader = Thread.currentThread().getContextClassLoader(); Enumeration<URL> resources; try { resources = loader.getResources("hot-deploy-containers.xml"); while (resources.hasMoreElements() && !this.unloading) { URL xmlUrl = resources.nextElement(); Debug.logInfo("Loading hot-deploy containers from " + xmlUrl, module); Collection<ContainerConfig.Container> hotDeployContainers = ContainerConfig.getContainers(xmlUrl); for (ContainerConfig.Container containerCfg : hotDeployContainers) { if (this.unloading) { return; } Container tmpContainer = loadContainer(containerCfg, args); this.loadedContainers.add(tmpContainer); } } } catch (Exception e) { Debug.logError(e, "Could not load hot-deploy-containers.xml", module); throw new StartupException(e); }
最后ContainerLoader启动时,执行所有Container的start()方法。
public synchronized void start() throws StartupException { if (!this.loaded || this.unloading) { throw new IllegalStateException("start() called on unloaded containers"); } Debug.logInfo("[Startup] Starting containers...", module); // start each container object for (Container container: this.loadedContainers) { if (this.unloading) { return; } Debug.logInfo("Starting container " + container.getName(), module); try { container.start(); } catch (ContainerException e) { throw new StartupException("Cannot start() " + container.getClass().getName(), e); } catch (java.lang.AbstractMethodError e) { throw new StartupException("Cannot start() " + container.getClass().getName(), e); } Debug.logInfo("Started container " + container.getName(), module); } }