Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1670062
  • 博文数量: 695
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 4027
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-20 21:22
文章分类

全部博文(695)

文章存档

2018年(18)

2017年(74)

2016年(170)

2015年(102)

2014年(276)

2013年(55)

分类: Java

2017-11-12 21:26:23

自己实现了一个简单的java应用热部署,步骤如下:
1、定义一个对外提供的服务类接口,并实现之
2、实现一个Monitor,监控指定路径下指定的服务的class文件是否被修改(这里实现的方式是,启动一个线程定时的去获得相应class文件的句柄,通过file.lastModified(),判断文件是否修改,当修改时要重新加载)
3、这里说下重新加载一个类class,每个类加载器都维护了一个namespace,同一个命名空间里不能出现两个同名的类。所以要想重新加载class,就得为每次生成一个classloader,然后再去加载类对象。
所以这里我继承了一个类加载器,重写了findclass方法,还有一点要注意的是:因为要加载的类对象在classpath目录下,所以要保证自己定义的类加载器的父类 appclassloader不能加载所监控的类对象,通过将ExtendClassLoader设置成给自己定义的类加载的父加载器,这样myClassLoader的父加载器无法加载classpath目录下的class,会调用自己的findclass方法将byte字节码转成class
代码如下:

点击(此处)折叠或打开

  1. package com.slg.hotdeployment;

  2. public interface Service {
  3.     public void say(String word);
  4. }
  5. ********************************************
  6. package com.slg.hotdeployment;

  7. public class ServiceImpl implements Service {

  8.     @Override
  9.     public void say(String word) {
  10.         // TODO Auto-generated method stub
  11.         System.out.println("3"+word);
  12.     }

  13. }
  14. *********************************************
  15. package com.slg.hotdeployment;

  16. public interface Monitor {
  17.     public void timeMoniter(long t,String fileName);
  18.     public void callBack();

  19. }
  20. **********************************************
  21. package com.slg.hotdeployment;

  22. import java.io.File;
  23. import java.lang.reflect.InvocationTargetException;
  24. import java.lang.reflect.Method;
  25. import java.net.URL;
  26. import java.util.concurrent.Executors;
  27. import java.util.concurrent.ScheduledExecutorService;
  28. import java.util.concurrent.TimeUnit;

  29. public class MonitorImpl implements Monitor {
  30.     private Class<?> claz = null;
  31.     long lastModified = 0;
  32.     String rootPath = null;

  33.     public Class<?> getClaz() {
  34.         return claz;
  35.     }

  36.     public void setClaz(Class<?> claz) {
  37.         this.claz = claz;
  38.     }

  39.     @Override
  40.     public void timeMoniter(long t, String fileName) {
  41.         Runnable r = new Runnable() {

  42.             @Override
  43.             public void run() {
  44.                 System.out.println("Monitor is play!!");
  45.                 if (isClassModified())
  46.                     callBack();

  47.             }
  48.         };
  49.         ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
  50.         // 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间
  51.         service.scheduleAtFixedRate(r, 0, t, TimeUnit.SECONDS);

  52.     }

  53.     public boolean isClassModified() {
  54.         boolean returnValue = false;
  55.         // ClassLoader classLoader = getClass().getClassLoader();
  56.         /**
  57.          * getResource()方法会去classpath下找这个文件,获取到url resource,
  58.          * 得到这个资源后,调用url.getFile获取到 文件 的绝对路径
  59.          */
  60.         URL url = this.getClass().getResource("ServiceImpl.class");

  61.         /**
  62.          * url.getFile() 得到这个文件的绝对路径
  63.          */
  64.         // System.out.println(url.getFile());
  65.         rootPath = url.getFile().replaceAll("%20", " ");
  66.         File file = new File(rootPath);

  67.         /*
  68.          * if(file.exists()) System.out.println("fiel is exist");
  69.          */
  70.         long modify = file.lastModified();
  71.         if (modify > lastModified) {
  72.             this.lastModified = file.lastModified();

  73.             returnValue = true;
  74.         }
  75.         return returnValue;

  76.     }

  77.     @Override
  78.     public void callBack() {
  79.         System.out.println("class file is modify");
  80.         try {
  81.             
  82.             //这样写不行,因为类加载是有缓存机制的,这样还是得到的之前的class对象,所以要重新定义一个类加载器来加载
  83.             //this.claz = Class.forName("com.slg.hotdeployment.ServiceImpl");
  84.             //设定自定义类加载的器为 extendClassLoader这样父加载器就加载失败,然后就会使用子加载器了,或者将
  85.             //要加载的class文件移出classpath路径外,这样父加载器加载失败后,就会调用自己实现的findClass方法了
  86.             this.getClass().getClassLoader();
  87.             DynamicClassLoader classloader = new DynamicClassLoader(this.getClass().getClassLoader().getParent(),"myclassloader");//这里每次发现class文件修改后都会重新new一个新的类加载器对象
  88.             classloader.setPath("E://java workspace//Test//bin//");
  89.             this.claz = classloader.loadClass("com.slg.hotdeployment.ServiceImpl");
  90.         } catch (ClassNotFoundException e) {
  91.             // TODO Auto-generated catch block
  92.             e.printStackTrace();
  93.         }

  94.     }

  95.     public static void main(String[] args) throws InterruptedException, InstantiationException, IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
  96.         MonitorImpl m = new MonitorImpl();
  97.         m.timeMoniter(5, "");
  98.         Thread.sleep(6000);
  99.         while (true) {            
  100.          Class s = m.getClaz();
  101.             //因为不是同一个类加载器加载的class所以不能强制类型转换 这一句会报错
  102.          //ServiceImpl sm = (ServiceImpl) s.newInstance();
  103.         
  104.          @SuppressWarnings("unchecked")
  105.             Method method = s.getMethod("say", String.class);
  106.          // String [] paramaters = {"asdf"};
  107.          method.invoke(s.newInstance(), "aasdf");
  108.             
  109.         }
  110.     }

  111. }
  112. ********************************************
  113. package com.slg.hotdeployment;

  114. import java.io.BufferedInputStream;
  115. import java.io.ByteArrayOutputStream;
  116. import java.io.File;
  117. import java.io.FileInputStream;
  118. import java.io.IOException;
  119. import java.io.InputStream;

  120. public class DynamicClassLoader extends ClassLoader {
  121.  

  122.         private String name; // 类加载器的名字

  123.         private String path = "d://"; // 加载类的路径

  124.         private final String fileType = ".class"; // .class文件扩展名
  125.         public DynamicClassLoader(){
  126.             super();// 让系统加载器成为该类的加载器的父类加载器
  127.         }
  128.         public DynamicClassLoader(String name) {
  129.             super();// 让系统加载器成为该类的加载器的父类加载器

  130.             this.name = name;
  131.         }

  132.         public DynamicClassLoader(ClassLoader parent, String name) {
  133.             super(parent); // 显示指定该类加载器的父加载器
  134.             this.name = name;
  135.         }

  136.         @Override
  137.         public String toString() {
  138.             return this.name;
  139.         }

  140.         public String getPath() {
  141.             return path;
  142.         }

  143.         public void setPath(String path) {
  144.             this.path = path;
  145.         }
  146.         
  147.         /**
  148.          * 读取class文件作为二进制流放入到byte数组中去
  149.          * @param name
  150.          * @return
  151.          */
  152.         private byte[] loadClassData(String name) {
  153.             InputStream in = null;
  154.             byte[] data = null;
  155.             ByteArrayOutputStream baos = null;

  156.             try {
  157.                 name = name.replace(".", "\\");
  158.                 in = new BufferedInputStream(new FileInputStream(new File(path
  159.                         + name + fileType)));
  160.                 baos = new ByteArrayOutputStream();
  161.                 int ch = 0;
  162.                 while (-1 != (ch = in.read())) {
  163.                     baos.write(ch);
  164.                 }
  165.                 data = baos.toByteArray();
  166.             } catch (Exception e) {

  167.                 e.printStackTrace();
  168.             } finally {
  169.                 try {
  170.                     in.close();
  171.                 } catch (IOException e) {
  172.                     e.printStackTrace();
  173.                 } finally {
  174.                     try {
  175.                         baos.close();
  176.                     } catch (IOException e) {
  177.                         e.printStackTrace();
  178.                     }
  179.                 }
  180.             }
  181.             return data;
  182.         }
  183.         
  184.         /**
  185.          * JVM调用的加载器的方法
  186.          */

  187.         @Override
  188.         protected Class<?> findClass(String name) throws ClassNotFoundException {
  189.             byte[] data = this.loadClassData(name);
  190.             return this.defineClass(name, data, 0, data.length);
  191.         }
  192.         
  193.         
  194.         
  195.         public static void main(String[] args) throws Exception {
  196.             DynamicClassLoader loader1 = new DynamicClassLoader("loader1");
  197.             loader1.setPath("d://");
  198.             test(loader1);
  199.         }
  200.         
  201.         public static void test(ClassLoader loader) throws Exception{
  202.             Class<?> clazz = loader.loadClass("com.bird.classLoad.Simple");
  203.             Object object = clazz.newInstance();
  204.         }
  205.  


  206. }
参考:
http://m.blog.csdn.net/xiangbq/article/details/49678869
http://blog.csdn.net/a352193394/article/details/7343385

阅读(887) | 评论(0) | 转发(0) |
0

上一篇:java获取classpath下的文件

下一篇:Java异常

给主人留下些什么吧!~~