java利用classloader实现热部署

老早之前已经写过几篇classload的文章了,由于我们现在的java 框架里面用到了热部署,所以在回味下吧。先看下之前的文章
http://blog.csdn.net/chaofanwei/article/details/12858523


1、classloader介绍

热部署,即需要jvm释放之前加载的业务class,且重新加载最新的业务class,并释放之前的class(卸载),其实类和普通对象一样都是对象,即如果从gc root除非,没有引用此类的别的对象存在,即会被jvm自动回收。


class文件在加载时,会把二进制文件放在内存中,并会在堆取new出一个表示此class的class对象,然后若new 类对象,则再把此new出来的对象的class对象指向刚才创建的class对象.



------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

类加载卸载图:



2、jdk自带classload介绍

还是直接看图吧

2.1类图


2.2 Classloader.loadClass(String name,boolean resolve)流程图


2.3 URLClassLoader.findClass(String name)流程图


3、实战

先贴代码:

两个项目,项目一用于搭建框架,实现热部署,项目二编写业务逻辑

项目一:



3.1、业务接口类

[java]  view plain  copy
  1. package cn.myroute.server.service;  
  2.   
  3. public interface BusService {  
  4.     String doIt(String name);  
  5.     void  close();  
  6. }  

3.2、自定义classload

继承自URLClassLoader,从指定的url加载class

[java]  view plain  copy
  1. package cn.myroute.server;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.MalformedURLException;  
  5. import java.net.URL;  
  6. import java.net.URLClassLoader;  
  7. import java.util.Date;  
  8.   
  9. public class MyClassLoader extends URLClassLoader {  
  10.   
  11.     private  MyClassLoader loader = null;  
  12.     Date startDate = new Date();  
  13.     public MyClassLoader(URL[] urls) {  
  14.         super(urls);  
  15.     }  
  16.   
  17.     public MyClassLoader(ClassLoader parent) {  
  18.         super(new URL[0], parent);  
  19.     }  
  20.   
  21.     @Override  
  22.     public void close() throws IOException {  
  23.         // TODO Auto-generated method stub  
  24.         super.close();  
  25.     }  
  26.     /** 
  27.      * Adds a jar file from the filesystems into the jar loader list. 
  28.      *  
  29.      * @param jarfile 
  30.      *            The full path to the jar file. 
  31.      * @throws MalformedURLException 
  32.      */  
  33.     public void addJarFile(String jarfile) throws MalformedURLException {  
  34.         URL url = new URL("file:" + jarfile);  
  35.         addURL(url);  
  36.     }  
  37.       
  38.     public void addDir(String path) throws MalformedURLException{  
  39.         path= "file:"+path;  
  40.         URL url = new URL(path);  
  41.         addURL(url);  
  42.     }  
  43.   
  44.   
  45.       
  46.     @Override  
  47.     public String toString() {  
  48.         // TODO Auto-generated method stub  
  49.         return super.toString() + ",time:"+startDate.toLocaleString();  
  50.     }  
  51.       
  52. }  

3.3、热部署框架类

[java]  view plain  copy
  1. package cn.myroute.server;  
  2.   
  3. import java.io.File;  
  4. import java.net.URL;  
  5. import java.net.URLClassLoader;  
  6. import java.util.Date;  
  7.   
  8. import cn.myroute.server.service.BusService;  
  9.   
  10.   
  11. public class Server {  
  12.   
  13.     String codePath = "D:\\java\\workspace\\busservice\\bin\\";  
  14.     String busServiceClass="cn.myroute.server.impl.BusServiceImpl";  
  15.     BusService busService;  
  16.     public String doWork(String name){  
  17.         if(null != busService){  
  18.             return busService.doIt(name);  
  19.         }  
  20.           
  21.         return "default";  
  22.     }  
  23.       
  24.     public void init(){  
  25.         new Thread(){  
  26.             long lastTime=0;  
  27.             public void run() {  
  28.                 File f = new File(codePath+"version.txt");  
  29.                 while(true){  
  30.                     if(lastTime != f.lastModified()){  
  31.                         lastTime = f.lastModified();  
  32.                           
  33.                         ClassLoader cl = this.getClass().getClassLoader();  
  34.                         System.out.println(cl);  
  35.                         MyClassLoader myLoader = new MyClassLoader(new URL[0]);  
  36.                         try {  
  37.                             myLoader.addDir(codePath);  
  38.                             Class<BusService> clazz = (Class<BusService>) myLoader.loadClass(busServiceClass);  
  39.                             BusService busService2 = clazz.newInstance();  
  40.                             BusService temp = busService;  
  41.                             busService = busService2;  
  42.                             temp.close();//释放资源,尤其是线程,若线程不关闭的话,则类不会卸载,且会一直运行  
  43.                             ClassLoader c = temp.getClass().getClassLoader();  
  44.                             if(c instanceof URLClassLoader) ((URLClassLoader) c).close();//释放资源  
  45.                             System.out.println("busService:"+busService + "  ,classloader:"+busService.getClass().getClassLoader());  
  46.                             System.out.println("end test "new Date().toLocaleString());  
  47.                         } catch (Exception e) {  
  48.                             // TODO Auto-generated catch block  
  49.                             e.printStackTrace();  
  50.                         }  
  51.                     }  
  52.                     try {  
  53.                         Thread.sleep(1000);  
  54.                     } catch (InterruptedException e) {  
  55.                         // TODO Auto-generated catch block  
  56.                         e.printStackTrace();  
  57.                     }  
  58.                 }  
  59.             };  
  60.         }.start();  
  61.           
  62.         //myLoader.close();  
  63.     }  
  64. }  

只要codePath+"version.txt" 文件的修改时间发生变化,就会自动加载最新的业务类,并释放旧的类。

特别注意的是,释放旧类时,若旧类里面启动新的线程的话,一定要关闭,否则既不会释放旧类,而且线程会一直运行。虽然加载了最新的类,但旧类并没有释放,会导致内存占用和一些别的不可预估的问题。


3.4、客户端调用类

[java]  view plain  copy
  1. package cn.myroute.client;  
  2.   
  3. import cn.myroute.server.Server;  
  4.   
  5. public class Client {  
  6.   
  7.     public static void main(String[] args) {  
  8.         Server server = new Server();  
  9.         server.init();  
  10.         int i=0;  
  11.         while(true){  
  12.             i++;  
  13.             String name="name"+i;  
  14.             String result=server.doWork(name);  
  15.             System.out.println(result);  
  16.             try {  
  17.                 Thread.sleep(10005);  
  18.             } catch (InterruptedException e) {  
  19.                 // TODO Auto-generated catch block  
  20.                 e.printStackTrace();  
  21.             }  
  22.               
  23.         }  
  24.   
  25.     }  
  26.   
  27. }  


3.5业务实现类

项目二:业务类


依赖项目一,因为需要业务接口类

[java]  view plain  copy
  1. package cn.myroute.server.impl;  
  2.   
  3. import java.util.Date;  
  4.   
  5. import cn.myroute.server.service.BusService;  
  6.   
  7. public class BusServiceImpl implements BusService{  
  8.   
  9.     boolean close = false;  
  10.     Date date= new Date();  
  11.     String version ="5.0";  
  12.     {  
  13.         Thread thread = new Thread(){  
  14.             public void run() {  
  15.                 setName("buserviceimplThread:"+date.toLocaleString());  
  16.                 System.out.println(this.toString() + ",time:"+date.toLocaleString());  
  17.                 while(!close){  
  18.                     doIt("");  
  19.                     try {  
  20.                         System.out.println(getName() + ",org time:"+date.toLocaleString() + "  ,curtime:"new Date().toLocaleString());  
  21.                         Thread.sleep(5000);  
  22.                     } catch (InterruptedException e) {  
  23.                         // TODO Auto-generated catch block  
  24.                         e.printStackTrace();  
  25.                     }  
  26.                 }  
  27.                   
  28.             };  
  29.         };  
  30.         thread.start();  
  31.     }  
  32.     @Override  
  33.     public String doIt(String name) {  
  34.         String res = version + name+",hello";  
  35.   
  36.         return res;  
  37.     }  
  38.     @Override  
  39.     public void close() {  
  40.         close = true;  
  41.         System.out.println("close invoked !,"+this.toString() + ",time:"+date.toLocaleString());  
  42.     }  
  43.   
  44. }  

运行时给jvm加 -verbose:class参数可以 打印类加载卸载信息

日志:

[html]  view plain  copy
  1. buserviceimplThread:2016-5-2 21:45:17,org time:2016-5-2 21:45:17  ,curtime:2016-5-2 21:46:22  
  2.   
  3. 4.0name22,hello  
  4.   
  5. buserviceimplThread:2016-5-2 21:45:17,org time:2016-5-2 21:45:17  ,curtime:2016-5-2 21:46:27  
  6.   
  7. 4.0name23,hello  
  8.   
  9. buserviceimplThread:2016-5-2 21:45:17,org time:2016-5-2 21:45:17  ,curtime:2016-5-2 21:46:32  
  10.   
  11. sun.misc.Launcher$AppClassLoader@5c4e9b7d  
  12.   
  13. [Loaded cn.myroute.server.impl.BusServiceImpl from file:D:/java/workspace/busservice/bin/]  
  14. [Loaded cn.myroute.server.impl.BusServiceImpl$1 from file:D:/java/workspace/busservice/bin/]  
  15. close invoked !,cn.myroute.server.impl.BusServiceImpl@4f03a2d8,time:2016-5-2 21:45:17  
  16.   
  17. busService:cn.myroute.server.impl.BusServiceImpl@6010cc19  ,classloader:cn.myroute.server.MyClassLoader@68a124e5,time:2016-5-2 21:46:33  
  18.   
  19. end test 2016-5-2 21:46:33  
  20.   
  21. Thread[buserviceimplThread:2016-5-2 21:46:33,5,main],time:2016-5-2 21:46:33  
  22.   
  23. buserviceimplThread:2016-5-2 21:46:33,org time:2016-5-2 21:46:33  ,curtime:2016-5-2 21:46:33  
  24.   
  25. 5.0name24,hello  
  26.   
  27. buserviceimplThread:2016-5-2 21:46:33,org time:2016-5-2 21:46:33  ,curtime:2016-5-2 21:46:38  
  28.   
  29. buserviceimplThread:2016-5-2 21:46:33,org time:2016-5-2 21:46:33  ,curtime:2016-5-2 21:47:13  
  30.   
  31. 5.0name32,hello  
  32.   
  33. buserviceimplThread:2016-5-2 21:46:33,org time:2016-5-2 21:46:33  ,curtime:2016-5-2 21:47:18  
  34.   
  35. [Loaded sun.reflect.GeneratedMethodAccessor41 from __JVM_DefineClass__]  
  36. <span style="color:#ff0000;">[Unloading class cn.myroute.server.impl.BusServiceImpl$1]  
  37. [Unloading class cn.myroute.server.impl.BusServiceImpl]  
  38. [Unloading class cn.myroute.server.impl.BusServiceImpl]  
  39. [Unloading class cn.myroute.server.impl.BusServiceImpl$1]</span>  

当内存占用很少的时候,需要手动通过工具如jconsole调用进程的gc,进行垃圾回收,才会打印出类卸载信息。


转载于:https://blog.csdn.net/chaofanwei2/article/details/51298818


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值