1、调用maven接口的maven-invoker.jar
<dependency>
<groupId>org.apache.maven.shared</groupId>
<artifactId>maven-invoker</artifactId>
<version>3.0.1</version>
</dependency>
2、代码功能主要实现类Main
注意:代码中出现的路径需要改动,代码不理解的请
点击查看java代码执行maven命令:调用maven接口或者控制台两种方式
点击查看解释热更新Demo:java底层及agentmain()三种实现方式
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";
}
}