I’m participating in nuggets Creators Camp # 4, click here to learn more and learn together!

Before because of

Recently, the development of the project has entered the second half, and there is still an integral module that has not been realized, and the specific consumption rules of the integral have not been determined, so the development of this functional module has been put on hold. Seeing that the time is getting closer and closer, it is not a matter of such delay, but we still need to solve it quickly.

Based on the above reasons, the first hastily drawn a flow chart.

The general payment process is like this, in which the billing module needs to be processed through the two preconditions of discount module and integral module before the cost calculation. Since only one or two kinds of integral rules have been confirmed for the time being, and a variety of new rules will be added later, the leader above requires that the module should realize the function of dynamically expanding rules, and not stop operation every time it is updated. Therefore, the design of this module adopts the template method mode to implement, and obtains the corresponding implementation class by passing in different rule names to implement the function.

The general idea is determined, and then gradually refined and realized.

Function implementation

Base rules module base

For the implementation of the rule, a basic module is defined here, which defines an interface to define the method that the rule needs to implement, and at the same time, it is convenient for the subsequent logical invocation, so that there is no need to add redundant judgment because of the naming problem of the developer.

public interface BaseService {

    /** * Run logic **@paramParam parameter *@returnResults *@author unidentifiable
     * @date2022/2/17 he * /
    String run(String param);
}
Copy the code

Specific function module service

Function implementation module, used to implement the specific processing logic, in this module, we need to introduce the above mentioned basic rules module, implementation of the interface specified methods.

Each module is only responsible for the implementation of a rule logic, which can be converted into Jar packages.

<dependencies>
    <! -- Introducing basic rules -->
    <dependency>
        <groupId>org.example</groupId>
        <artifactId>base</artifactId>
        <version>1.0 the SNAPSHOT</version>
    </dependency>
</dependencies>
Copy the code

The following two classes are used to simulate different deduction rules.

public class MyService1 implements BaseService {

    @Override
    public String run(String param) {
        return "Run deduction rule 1:, parameter {" + param + "}"; }}Copy the code
public class MyService2 implements BaseService {

    @Override
    public String run(String param) {
        return "Run deduction rule 2:, parameter {" + param + "}"; }}Copy the code

The Jar package nameTo maintain andThe name of the classConsistent.

Use Case Demo

The Jar package of the rule logic implementation is ready, and the next step is to see how we use it. Here we need to implement two functions:

  1. loadingJarpackage
  2. Call the method that implements the class

At the same time, the basic rule module needs to be referenced here, otherwise there will be an exception when the corresponding logical Jar package is loaded later, and the corresponding interface cannot be found.

<dependencies>
    <dependency>
        <groupId>org.example</groupId>
        <artifactId>base</artifactId>
        <version>1.0 the SNAPSHOT</version>
    </dependency>
</dependencies>
Copy the code

Load the Jar package


There are several ways to load, I only wrote here one of them, there are shortcomings, but also hope you point out in the comments area, common learning success through progress! _{loading methods have several kinds, I only wrote here one of them, there are shortcomings, but also hope you point out in the comments area, common learning success through progress! }

/** * Load the Jar package **@paramJarPath Jar package directory *@author unidentifiable
 * @date2022/2/17 15:33 the * /
public static void loadJar(String jarPath) throws Exception {
    // Specify the directory where the Jar package is stored
    File files = new File(jarPath);
    // Find all files ending in.jar
    File[] fileArray = files.listFiles(f -> f.getName().endsWith(".jar"));

    URLClassLoader: supports fetching classes from jar packages or folder path links.
    Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
    URLClassLoader classLoader = null;
    try {
        // Obtain the method access permission
        method.setAccessible(true);
        classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        for (File file : fileArray) {
            // Add the current classpath to the classloadermethod.invoke(classLoader, file.toURI().toURL()); }}finally {
        method.setAccessible(false); }}Copy the code

A method is called

/** * Run Jar package internal logic **@paramName Jar package name *@paramParam parameter *@author unidentifiable
 * @date2022/2/17 15:33 the * /
public static String run(String name, String param) throws Exception {
    // The full path of the class
    String packagePath = "org.example.unidentifiable.service.impl."; Class<? > aClass =null;
    try {
        // Get the implementation class
        aClass = Class.forName(packagePath + name);
    } catch (ClassNotFoundException e) {
        return "Not found {" + name + } rule, please check and resubmit!;
    }

    Object run = null;
    try {
        // Call the rule method
        run = aClass.getDeclaredMethod("run", String.class).invoke(aClass.newInstance(), param);
    } catch (NoSuchMethodException e) {
        return "Rule processing exception, please check the related resource bundle: {" + name + "}";
    }
    // Return the result
    return run.toString();
}
Copy the code

test

public static void main(String[] args) throws Exception {
    loadJar("F:\"); System.out.println(run("MyService1","score")); System.out.println("------------------------------------"); System.out.println(run("MyService2","Present integral")); System.out.println("------------------------------------"); System.out.println(run("MyService3","The unknown"));
}
Copy the code

Test, Jar package inside the method can be called normally, to here, a basic version of the dynamic loading function has been implemented, the first throw up and the leadership of the cross, and can be happy to touch fish!

PS: Some articles on the Internet mentioned that it is necessary to close the classLoader after using it. After testing, if the classLoader is closed, it will cause the exception that the loaded class cannot be found.