热部署:WatchService监控+调用maven接口替换ClassLoader

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36688143/article/details/85160574

1、调用maven接口的maven-invoker.jar

<dependency>
      <groupId>org.apache.maven.shared</groupId>
      <artifactId>maven-invoker</artifactId>
      <version>3.0.1</version>
</dependency>

2、代码功能主要实现类Main

注意:代码中出现的路径需要改动,代码不理解的请点击这里或者点击这里

package Main;

import org.apache.maven.shared.invoker.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class Main {

    /**
     * 这里使用接口的实现方式,因为我们只是加载实现类,接口类一直使用旧的ClassLoader
     * 这样就不会存在类型转换的报错
     */
    static Target obj = new TargetImpl();

    public static void main(String[] args) throws Exception {

        WatchService watchService = FileSystems.getDefault().newWatchService();
        // 监控的文件目录,需要改
        String filePath = "D:\\work\\MyWordSpace\\HotSwap\\src\\main\\java\\Main";
        Paths.get(filePath).register(watchService,StandardWatchEventKinds.ENTRY_MODIFY);

        WatchKey key=null;

        /**
         *  调用watchService.take(); 获取监控目录文件的变化的WatchKey。
         *  该方法是阻塞方法,如果没有文件修改,则一直阻塞。
         *
         *  遍历所有的修改事件,并做相应处理。
         *  完成一次监控就需要重置监控器。
         */

        while ((key = watchService.take())!=null) {
            for (WatchEvent<?> event : key.pollEvents()) {

                if(StandardWatchEventKinds.ENTRY_MODIFY == event.kind()){
                    System.out.println( event.context()+"文件已修改,正在重新编译。。。");

                    // 调用maven api重新编译,热部署自动实现
                    InvocationRequest request = new DefaultInvocationRequest();
                    request.setPomFile(new File("pom.xml"));
                    request.setGoals(Collections.singletonList("compile"));

                    Invoker invoker = new DefaultInvoker();
                    // maven安装位置需要改
                    invoker.setMavenHome(new File("D:/work/environment/Maven/apache-maven-3.3.9"));

                    invoker.setLogger(new PrintStreamLogger(System.err, InvokerLogger.ERROR) {

                    });

                    invoker.setOutputHandler(new InvocationOutputHandler() {
                        @Override
                        public void consumeLine(String s) throws IOException {

                        }
                    });

                    try {
                        invoker.execute(request);
                    } catch (MavenInvocationException e) {
                        e.printStackTrace();
                    }

                    // 更换classloader路径需要改
                    String pathClass = "D:\\work\\MyWordSpace\\HotSwap\\target\\classes\\Main\\TargetImpl.class";
                    byte[] b = getBytes(pathClass);
                    Class c = new DynamicClassLoader().findClass(b);
                    obj = (Target) c.newInstance();
                    System.err.println(obj.name());
                }
            }

            // 完成一次监控就需要重置监控器
            key.reset();
        }
    }

    // 从本地读取文件
    private static byte[] getBytes(String filename) throws IOException {
        File file = new File(filename);
        long len = file.length();
        byte raw[] = new byte[(int) len];
        FileInputStream fin = new FileInputStream(file);
        fin.read(raw);
        fin.close();
        return raw;
    }

}

3、DynamicClassLoader

package Main;

public class DynamicClassLoader extends ClassLoader {

    public Class<?> findClass(byte[] b) throws ClassNotFoundException {
        return defineClass(null, b, 0, b.length);
    }

}

4、Target接口

package Main;

public interface Target {
    String name();
}

5、TargetImpl实现类

package Main;

public class TargetImpl implements Target {

    public String name() {
        System.out.printf("666");
        return "bbb";
    }

}

猜你喜欢

转载自blog.csdn.net/qq_36688143/article/details/85160574