DEV Community

Ryu Xin
Ryu Xin

Posted on

Dynamic Loading of Business Customization Packages in Lattice Framework

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:

  • Dynamic loading example of business plug-in package
  • 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.11.2</version>
</dependency>
<dependency>
    <groupId>org.hiforce.lattice</groupId>
    <artifactId>lattice-runtime</artifactId>
    <version>1.0.11.2</version>
</dependency>
<dependency>
    <groupId>org.hiforce.lattice</groupId>
    <artifactId>lattice-dynamic-loading</artifactId>
    <version>1.0.11.2</version>
</dependency>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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();
    }
Enter fullscreen mode Exit fullscreen mode

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();
}
Enter fullscreen mode Exit fullscreen mode

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();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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

Lattice Framework Introduction

Lattice is a powerful, lightweight business extension invoke framework. By using the Lattice framework, complex business customization can be efficiently organized and managed.

The main ideas of Lattice's architecture design are:

  • The plug-in architecture that separates the business package from the platform: The platform provides a plug-in package registration mechanism to realize the registration of the business-side plug-in package during runtime. The business code is only allowed to exist in the plugin package and is strictly separated from the platform code. The code configuration library of the business package is also separated from the code library of the platform, and is provided to the container for loading through the second-party package.
  • Unified business identity across the full-chain: The platform needs to have the ability to logically isolate business from business according to "business identity", rather than the traditional SPI architecture that does not distinguish between business identities and simply filters. How to design this business identity has also become the key to the isolation architecture between businesses.
  • Separation of management domain and running domain: Business logic cannot rely on dynamic calculation at run time, but can be defined and visualized at static time. The rules that appear in the business definition are superimposed and conflicted, and conflict decisions are also made in the static device. During the runtime, it is executed strictly according to the business rules and conflict decision policies defined by the static device.

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

Top comments (0)