Skip to content

Dynamic Loading

Ryu Xin edited this page Oct 17, 2022 · 9 revisions

The dynamic loading mechanism of the business package can download and install the application plug-ins in the cloud market into the current container in some scenarios. Cloud market example:

What you’ll learn

This example mainly demonstrates how to dynamically load a business package based on Lattice, but does not include the construction of the cloud market itself.

With this sample, you can learn:

  1. Dynamic loading example of business plug-in package
  2. The extension mechanism of custom ClassLoader

What you’ll need

  1. An Integrated Developer Environment (IDE). Popular choices include IntelliJ IDEA, Spring Tools, Visual Studio Code, or Eclipse, and many more.
  2. A Java™ Development Kit (JDK). We recommend BellSoft Liberica JDK version 8 or version 11.

Maven dependency

<dependency>
    <groupId>org.hiforce.lattice</groupId>
    <artifactId>lattice-model</artifactId>
    <version>1.0.12</version>
</dependency>
<dependency>
    <groupId>org.hiforce.lattice</groupId>
    <artifactId>lattice-runtime</artifactId>
    <version>1.0.12</version>
</dependency>
<dependency>
    <groupId>org.hiforce.lattice</groupId>
    <artifactId>lattice-dynamic-loading</artifactId>
    <version>1.0.12</version>
</dependency>

Dynamic Loading of Business Package Demo

In lattice-sample, you can refer to the demo of lattice-dynamic-load-apps, the configuration Lattice plugin loading directory is defined, in application.properties, as follows:

lattice.plugin.dirs=/Users/rocky/code/plugins

Then we start the Starter org.hiforce.lattice.dynamic.LatticeDynamicStarter. In your browser, open http://localhost:8080/business/install/1 and you will see the following input:

Next, we continue to enter http://localhost:8080/business/install/2 , we can see the following results:

It can be seen that the dynamic loading of the business package has been replaced with a new version. The corresponding Controller code is as follows:

    @RequestMapping("/business/install/1")
    public String installBusinessPlugin_1() {
        clear();
        String urlStr = "/apps/lattice-business-cloth-1.0.0-SNAPSHOT.jar";
        URL url = DynamicLoadTestController.class.getResource(urlStr);
        if (null != url) {
            File file = new File(url.getPath());
            LatticeDynamic.getInstance().installPlugin(new PluginFileInfo(file));
        }
        return invokeBusinessPlugin();
    }

    @RequestMapping("/business/install/2")
    public String installBusinessPlugin_2() {
        clear();
        String urlStr = "/apps/lattice-business-cloth-1.0.1-SNAPSHOT.jar";
        URL url = DynamicLoadTestController.class.getResource(urlStr);
        if (null != url) {
            File file = new File(url.getPath());
            LatticeDynamic.getInstance().installPlugin(new PluginFileInfo(file));
        }
        return invokeBusinessPlugin();
    }

Lattice custom ClassLoader

In the Lattice framework, the SPI of the custom ClassLoader is provided, which is defined as follows:

public interface CustomClassLoaderSpi {

    ClassLoader getCustomClassLoader();
}

In this example, I provide a very simple loading scheme based on URLClassLoader in the framework in Lattice. In lattice-dynamic-loading, LatticeDynamicClassLoaderBuilder is defined, which can realize the loading of plug-in packages in the specified directory, as follows:

@AutoService(CustomClassLoaderSpi.class)
public class LatticeDynamicClassLoaderBuilder implements CustomClassLoaderSpi {

    @Override
    public ClassLoader getCustomClassLoader() {
        String[] dirs = LatticeDynamicProperties.getInstance().getPluginDirs();
        List<URL> urls = Lists.newArrayList();
        for (String dir : dirs) {
            urls.addAll(buildJarURLList(dir));
        }
        URL[] urlArrays = urls.toArray(new URL[0]);
        return new URLClassLoader(urlArrays, LatticeDynamicClassLoaderBuilder.class.getClassLoader());
    }

    private List<URL> buildJarURLList(String dirStr) {
        List<URL> urls = Lists.newArrayList();
        try {
            File dir = new File(dirStr);
            if (!dir.exists() || !dir.isDirectory()) {
                return Lists.newArrayList();
            }
            File[] jars = dir.listFiles(pathname -> pathname.getPath().endsWith(".jar"));
            if (null == jars) {
                return urls;
            }
            for (File file : jars) {
                urls.add(new URL("file:" + file.getPath()));
            }
            return urls;
        } catch (Exception ex) {
            return Lists.newArrayList();
        }
    }
}

Lattice framework users can write more complex plugin loading schemes based on this mechanism. for example:

  • It can be further enhanced to isolate the loading mechanism for different business identities
  • Business plugins can be packaged into flat-jar, and each business can even introduce other third-party packages by itself

These, will not be available in the official Lattice framework.

This sample code: https://github.com/hiforce/lattice-sample/tree/main/lattice-dynamic-load-apps


中文版:https://www.ryu.xin/2022/10/11/lattice-dynamic-loading/