自己实现了一个简单的java应用热部署,步骤如下:
1、定义一个对外提供的服务类接口,并实现之
2、实现一个Monitor,监控指定路径下指定的服务的class文件是否被修改(这里实现的方式是,启动一个线程定时的去获得相应class文件的句柄,通过file.lastModified(),判断文件是否修改,当修改时要重新加载)
3、这里说下重新加载一个类class,每个类加载器都维护了一个namespace,同一个命名空间里不能出现两个同名的类。所以要想重新加载class,就得为每次生成一个classloader,然后再去加载类对象。
所以这里我继承了一个类加载器,重写了findclass方法,还有一点要注意的是:因为要加载的类对象在classpath目录下,所以要保证自己定义的类加载器的父类 appclassloader不能加载所监控的类对象,通过将ExtendClassLoader设置成给自己定义的类加载的父加载器,这样myClassLoader的父加载器无法加载classpath目录下的class,会调用自己的findclass方法将byte字节码转成class
代码如下:
-
package com.slg.hotdeployment;
-
-
public interface Service {
-
public void say(String word);
-
}
-
********************************************
-
package com.slg.hotdeployment;
-
-
public class ServiceImpl implements Service {
-
-
@Override
-
public void say(String word) {
-
// TODO Auto-generated method stub
-
System.out.println("3"+word);
-
}
-
-
}
-
*********************************************
-
package com.slg.hotdeployment;
-
-
public interface Monitor {
-
public void timeMoniter(long t,String fileName);
-
public void callBack();
-
-
}
-
**********************************************
-
package com.slg.hotdeployment;
-
-
import java.io.File;
-
import java.lang.reflect.InvocationTargetException;
-
import java.lang.reflect.Method;
-
import java.net.URL;
-
import java.util.concurrent.Executors;
-
import java.util.concurrent.ScheduledExecutorService;
-
import java.util.concurrent.TimeUnit;
-
-
public class MonitorImpl implements Monitor {
-
private Class<?> claz = null;
-
long lastModified = 0;
-
String rootPath = null;
-
-
public Class<?> getClaz() {
-
return claz;
-
}
-
-
public void setClaz(Class<?> claz) {
-
this.claz = claz;
-
}
-
-
@Override
-
public void timeMoniter(long t, String fileName) {
-
Runnable r = new Runnable() {
-
-
@Override
-
public void run() {
-
System.out.println("Monitor is play!!");
-
if (isClassModified())
-
callBack();
-
-
}
-
};
-
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
-
// 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间
-
service.scheduleAtFixedRate(r, 0, t, TimeUnit.SECONDS);
-
-
}
-
-
public boolean isClassModified() {
-
boolean returnValue = false;
-
// ClassLoader classLoader = getClass().getClassLoader();
-
/**
-
* getResource()方法会去classpath下找这个文件,获取到url resource,
-
* 得到这个资源后,调用url.getFile获取到 文件 的绝对路径
-
*/
-
URL url = this.getClass().getResource("ServiceImpl.class");
-
-
/**
-
* url.getFile() 得到这个文件的绝对路径
-
*/
-
// System.out.println(url.getFile());
-
rootPath = url.getFile().replaceAll("%20", " ");
-
File file = new File(rootPath);
-
-
/*
-
* if(file.exists()) System.out.println("fiel is exist");
-
*/
-
long modify = file.lastModified();
-
if (modify > lastModified) {
-
this.lastModified = file.lastModified();
-
-
returnValue = true;
-
}
-
return returnValue;
-
-
}
-
-
@Override
-
public void callBack() {
-
System.out.println("class file is modify");
-
try {
-
-
//这样写不行,因为类加载是有缓存机制的,这样还是得到的之前的class对象,所以要重新定义一个类加载器来加载
-
//this.claz = Class.forName("com.slg.hotdeployment.ServiceImpl");
-
//设定自定义类加载的器为 extendClassLoader这样父加载器就加载失败,然后就会使用子加载器了,或者将
-
//要加载的class文件移出classpath路径外,这样父加载器加载失败后,就会调用自己实现的findClass方法了
-
this.getClass().getClassLoader();
-
DynamicClassLoader classloader = new DynamicClassLoader(this.getClass().getClassLoader().getParent(),"myclassloader");//这里每次发现class文件修改后都会重新new一个新的类加载器对象
-
classloader.setPath("E://java workspace//Test//bin//");
-
this.claz = classloader.loadClass("com.slg.hotdeployment.ServiceImpl");
-
} catch (ClassNotFoundException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
}
-
-
}
-
-
public static void main(String[] args) throws InterruptedException, InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
-
MonitorImpl m = new MonitorImpl();
-
m.timeMoniter(5, "");
-
Thread.sleep(6000);
-
while (true) {
-
Class s = m.getClaz();
-
//因为不是同一个类加载器加载的class所以不能强制类型转换 这一句会报错
-
//ServiceImpl sm = (ServiceImpl) s.newInstance();
-
-
@SuppressWarnings("unchecked")
-
Method method = s.getMethod("say", String.class);
-
// String [] paramaters = {"asdf"};
-
method.invoke(s.newInstance(), "aasdf");
-
-
}
-
}
-
-
}
-
********************************************
-
package com.slg.hotdeployment;
-
-
import java.io.BufferedInputStream;
-
import java.io.ByteArrayOutputStream;
-
import java.io.File;
-
import java.io.FileInputStream;
-
import java.io.IOException;
-
import java.io.InputStream;
-
-
public class DynamicClassLoader extends ClassLoader {
-
-
-
private String name; // 类加载器的名字
-
-
private String path = "d://"; // 加载类的路径
-
-
private final String fileType = ".class"; // .class文件扩展名
-
public DynamicClassLoader(){
-
super();// 让系统加载器成为该类的加载器的父类加载器
-
}
-
public DynamicClassLoader(String name) {
-
super();// 让系统加载器成为该类的加载器的父类加载器
-
-
this.name = name;
-
}
-
-
public DynamicClassLoader(ClassLoader parent, String name) {
-
super(parent); // 显示指定该类加载器的父加载器
-
this.name = name;
-
}
-
-
@Override
-
public String toString() {
-
return this.name;
-
}
-
-
public String getPath() {
-
return path;
-
}
-
-
public void setPath(String path) {
-
this.path = path;
-
}
-
-
/**
-
* 读取class文件作为二进制流放入到byte数组中去
-
* @param name
-
* @return
-
*/
-
private byte[] loadClassData(String name) {
-
InputStream in = null;
-
byte[] data = null;
-
ByteArrayOutputStream baos = null;
-
-
try {
-
name = name.replace(".", "\\");
-
in = new BufferedInputStream(new FileInputStream(new File(path
-
+ name + fileType)));
-
baos = new ByteArrayOutputStream();
-
int ch = 0;
-
while (-1 != (ch = in.read())) {
-
baos.write(ch);
-
}
-
data = baos.toByteArray();
-
} catch (Exception e) {
-
-
e.printStackTrace();
-
} finally {
-
try {
-
in.close();
-
} catch (IOException e) {
-
e.printStackTrace();
-
} finally {
-
try {
-
baos.close();
-
} catch (IOException e) {
-
e.printStackTrace();
-
}
-
}
-
}
-
return data;
-
}
-
-
/**
-
* JVM调用的加载器的方法
-
*/
-
-
@Override
-
protected Class<?> findClass(String name) throws ClassNotFoundException {
-
byte[] data = this.loadClassData(name);
-
return this.defineClass(name, data, 0, data.length);
-
}
-
-
-
-
public static void main(String[] args) throws Exception {
-
DynamicClassLoader loader1 = new DynamicClassLoader("loader1");
-
loader1.setPath("d://");
-
test(loader1);
-
}
-
-
public static void test(ClassLoader loader) throws Exception{
-
Class<?> clazz = loader.loadClass("com.bird.classLoad.Simple");
-
Object object = clazz.newInstance();
-
}
-
-
-
-
}
参考:
http://m.blog.csdn.net/xiangbq/article/details/49678869
http://blog.csdn.net/a352193394/article/details/7343385
阅读(887) | 评论(0) | 转发(0) |