Java geek

Related reading:

JAVA Basics (1) Simple and complete understanding of inner classes and static inner classes JAVA Basics (2) Memory optimization – Using JAVA references for caching JAVA Basics (4) Enumerations (enum) and constant definitions, factory class use comparison JAVA Basics (5) Functional interfaces – reuse JAVA programming idea (1) Increase extensibility through dependency Injection (2) How to programming JAVA programming idea (3) Remove awkward if, self-registration strategy pattern elegant to meet the open closed principle JAVA programming idea (4) Builder pattern classic paradigm and how to choose and factory pattern? HikariPool source code (two) design ideas for reference in the workplace (a) IT factory survival rules


1. Application scenario

  1. Fix bugs, do not need to restart the service, dynamically load the modified bug class.
  2. Dynamic upgrade: In The Android operating system, you can dynamically load APK to bypass the upgrade policy in the application market and customize the upgrade policy.

Example 2.

Online a lot of articles describe this loading, here no longer described in detail, it is important to note: will need to be dynamically loaded classes in a separate jar file, load by dynamic load from the start, not on the main process of jar package, it will be the default loader loads, lead to can’t reload after update.

2.1. Main project code/module

This module places classes that do not need to be loaded dynamically.

2.1.1. HotClassLoader. Java

Used to achieve dynamic recording function.

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

// Hot loader
public class HotClassLoader {
    private static final long LOADER_INTERVAL = 3;
    // Point to the JAR file that dynamically loads the Module
    private static final String HOT_UPDATE_JAR_PATH = "D: \ \ ClassLoaderDemo - Service \ \ target \ \ ClassLoaderDemo - Service - 1.0 - the SNAPSHOT. Jar";

    static URLClassLoader classLoader;         // Class loader
    private static long lastModifiedTime = 0;  // Last update time of jar file

    // Start listening for jar files for updates
    public void startListening(a) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        scheduledExecutorService.scheduleAtFixedRate(()->{
            if(isHotUpdate()) { reload(); }},0, LOADER_INTERVAL, TimeUnit.SECONDS);
    }

    // Get the new instance dynamically. Note that the return value may be null, and the caller must add a judgment
    public static Object newInstance(String className) {
        if(classLoader ! =null) {
            try {
                synchronized (HotClassLoader.class) {
                    Object newInstance = Class.forName(className, true, classLoader).newInstance();
                    returnnewInstance; }}catch(ClassNotFoundException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); }}return null;
    }

    // Check whether there is an update
    private boolean isHotUpdate(a) {
        File hotLoaderFile = new File(HOT_UPDATE_JAR_PATH);
        boolean isHotUpdate = false;
        if (hotLoaderFile.exists()) {
            longnewModifiedTime = hotLoaderFile.lastModified(); isHotUpdate = lastModifiedTime ! = newModifiedTime; lastModifiedTime = newModifiedTime; }else {
            System.out.println(hotLoaderFile.getAbsolutePath() + " is not found.");
        }

        System.out.println("isHotUpdate:" + isHotUpdate);
        return isHotUpdate;
    }

    // Reload the JAR file
    private void reload(a) {
        File jarPath = new File(HOT_UPDATE_JAR_PATH);
        System.out.println("jar lastModified xxxxxxxxxxxxxxxxxx: " + jarPath.lastModified());

        if (jarPath.exists()) {
            try {
                synchronized (HotClassLoader.class) {
                    classLoader = new URLClassLoader(newURL[]{jarPath.toURI().toURL()}); }}catch(Exception e) { e.printStackTrace(); }}else {
            System.out.println("Hot update jar is not found."); }}}Copy the code

2.1.2. Service. Java

Simulated dynamically loaded class interface.

package com.javageektour.classloaderdemo;

public interface Service {
    void printVersion(a);
}
Copy the code

2.1.3. HotLoadTest. Java

The test class.

package com.javageektour.classloaderdemo;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class HotLoadTest {
    public static void main(String[] args) {
        HotClassLoader hotClassLoader = new HotClassLoader();
        hotClassLoader.startListening();

        // Sleep for a while and wait for the load to finish
        sleep(3000);
        mockCaller();
        sleep(50000000);
    }

    // Simulate the caller
    private static void mockCaller(a) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
        scheduledExecutorService.scheduleAtFixedRate(()->{
            try {
                Service mockService = (Service) HotClassLoader.newInstance("com.javageektour.classloaderdemo.MockService");
                mockService.printVersion();
            } catch(Exception e) { e.printStackTrace(); }},0.5, TimeUnit.SECONDS);
    }

    private static void sleep(long timeMillis) {
        try {
            Thread.sleep(timeMillis);
        } catch(InterruptedException e) { Thread.currentThread().interrupt(); }}}Copy the code

2.2. Dynamic loading of projects/modules

Classes that need to be loaded dynamically are placed in this module, and you can even divide modules by business.

Note that this module needs to compile the interface classes that depend on the main module.

2.2.1. MockService. Java

package com.javageektour.classloaderdemo;

public class MockService implements Service {
    @Override
    public void printVersion(a) {
        System.out.println("11.0"); }}Copy the code

2.3. Verification process

1. Compile the dynamic loading module, generate the JAR file, and modify the JAR file path of the test program in the main module. 2. Start the test demo. After printing and publishing the version number, change the version number in mockService. Java to regenerate the JAR file. 3. Wait for the new version number to be printed.

Output logs:

IsHotUpdate:true
jar lastModified xxxxxxxxxxxxxxxxxx: 1587832288706IsHotUpdate:false
1.0IsHotUpdate:false
1.0IsHotUpdate:falseIsHotUpdate:true
jar lastModified xxxxxxxxxxxxxxxxxx: 1587832303617
2.0IsHotUpdate:false
Copy the code

3. Summary

  1. ClassLoader is a basic Java knowledge and should be understood and mastered.
  2. In some scenarios where SLA requirements are high and services cannot be stopped, hot-loading patches is also a solution, but planning and design should be done in advance.
  3. Android dynamic loading APK logic is actually quite complex, to consider the download, installation, loading, dotting analysis and so on a series of operations, hot loading is only a small step, really to do a good job, there are many problems to consider and solve.

.end


<– read left mark, left point like!