• classloader 热部署


    这两天一直在学习一些classloader的相关知识,看了一些文章,了解到classloader的作用之一就是实现热部署功能。于是就看了一个网络上的一个例子,然后自己实现了一个应用。虽然作出来了,但是说实话:不满意。因为在这个例子当中,只要热部署一次,就要重新new一个classloader,这样会引发什么问题我也不清楚,并且,classloader究竟实现了什么,以及一些底层的东西我还不是很了解,还要继续研究,目前的版本就是一个中间版本。以后还要优化,或者在我读完tomcat的classloader之后我在去仿照着写一个。

    1,使用CLass.forName()可以动态的得到一个.class的类。

    2,Thread.currentThread().getContextClassLoader())得到当前的classloader。然后就可以得到classpath下面任何包中的类


    好了,下面介绍这个工程的构思、以及实现方式,设计思想:首先来说:这个工程至少需要是需要2个线程,一个是类似tomcat的服务线程,另外一个就是检测线程,检测变化,重新加载Class对象。我猜tomcat是采取了检测类,检测加载了的类文件变化。我没有那么实现,因为这种实现方式相对复杂,并且我的想集中解决热部署问题,而不是如何实现监控文件,所以我就采取了相对简单的方式:socket通知方式。也就是,在我重新编译一个class之后,利用socket通知检测线程,监测监测在监测到socket命令之后会自动的加载。

    Java代码 复制代码
    1. Java代码    
    2. package com.cxz.classloader;      
    3.      
    4. import com.cxz.jiangyou.Say;      
    5.      
    6. import java.io.ByteArrayOutputStream;      
    7. import java.io.File;      
    8. import java.io.FileInputStream;      
    9. import java.io.IOException;      
    10.      
    11. /**    
    12.  * This classloader is like a template    
    13.  * which includes pre-loadClass and after-loadClass    
    14.  * @author Bernard    
    15.  *    
    16.  */     
    17. public class ComplexClassLoader extends ClassLoader {      
    18.      
    19.     public ComplexClassLoader() {      
    20.     }      
    21.      
    22.     public ComplexClassLoader(String defaultTargetDir) {      
    23.         this.defaultTargetDir = defaultTargetDir;      
    24.     }      
    25.      
    26.     private String defaultTargetDir = "D://hotdeploys//";      
    27.      
    28.     public Class<?> findClass(String className) throws ClassNotFoundException {      
    29.         byte[] classBytes = null;      
    30.         try {      
    31.             classBytes = loadByteCode(className);      
    32.         } catch (IOException e) {      
    33.             // TODO Auto-generated catch block      
    34.             e.printStackTrace();      
    35.         }      
    36.         return super.defineClass(className, classBytes, 0, classBytes.length);      
    37.     }      
    38.      
    39.     private byte[] loadByteCode(String className) throws IOException {      
    40.         int ch = 0;      
    41.         className = className.replaceAll("//.""////") + ".class";      
    42.         //The two slashes represent for meaning changing      
    43.         File file = new File(defaultTargetDir + className);      
    44.         FileInputStream in = null;      
    45.         in = new FileInputStream(file);      
    46.         ByteArrayOutputStream buffer = new ByteArrayOutputStream();      
    47.         while ((ch = in.read()) != -1) {      
    48.             buffer.write(ch);      
    49.         }      
    50.         in.close();      
    51.         return buffer.toByteArray();      
    52.     }      
    53.      
    54.     public String getDefaultTargetDir() {      
    55.         return defaultTargetDir;      
    56.     }      
    57.      
    58.     public void setDefaultTargetDir(String defaultTargetDir) {      
    59.         this.defaultTargetDir = defaultTargetDir;      
    60.     }         
    61. }     
    62.   
    63. package com.cxz.classloader;   
    64.   
    65. import com.cxz.jiangyou.Say;   
    66.   
    67. import java.io.ByteArrayOutputStream;   
    68. import java.io.File;   
    69. import java.io.FileInputStream;   
    70. import java.io.IOException;   
    71.   
    72. /**  
    73.  * This classloader is like a template  
    74.  * which includes pre-loadClass and after-loadClass  
    75.  * @author Bernard  
    76.  *  
    77.  */  
    78. public class ComplexClassLoader extends ClassLoader {   
    79.   
    80.     public ComplexClassLoader() {   
    81.     }   
    82.   
    83.     public ComplexClassLoader(String defaultTargetDir) {   
    84.         this.defaultTargetDir = defaultTargetDir;   
    85.     }   
    86.   
    87.     private String defaultTargetDir = "D://hotdeploys//";   
    88.   
    89.     public Class<?> findClass(String className) throws ClassNotFoundException {   
    90.         byte[] classBytes = null;   
    91.         try {   
    92.             classBytes = loadByteCode(className);   
    93.         } catch (IOException e) {   
    94.             // TODO Auto-generated catch block   
    95.             e.printStackTrace();   
    96.         }   
    97.         return super.defineClass(className, classBytes, 0, classBytes.length);   
    98.     }   
    99.   
    100.     private byte[] loadByteCode(String className) throws IOException {   
    101.         int ch = 0;   
    102.         className = className.replaceAll("//.""////") + ".class";   
    103.         //The two slashes represent for meaning changing   
    104.         File file = new File(defaultTargetDir + className);   
    105.         FileInputStream in = null;   
    106.         in = new FileInputStream(file);   
    107.         ByteArrayOutputStream buffer = new ByteArrayOutputStream();   
    108.         while ((ch = in.read()) != -1) {   
    109.             buffer.write(ch);   
    110.         }   
    111.         in.close();   
    112.         return buffer.toByteArray();   
    113.     }   
    114.   
    115.     public String getDefaultTargetDir() {   
    116.         return defaultTargetDir;   
    117.     }   
    118.   
    119.     public void setDefaultTargetDir(String defaultTargetDir) {   
    120.         this.defaultTargetDir = defaultTargetDir;   
    121.     }      
    122. }  
    Java代码 
    package com.cxz.classloader;   
      
    import com.cxz.jiangyou.Say;   
      
    import java.io.ByteArrayOutputStream;   
    import java.io.File;   
    import java.io.FileInputStream;   
    import java.io.IOException;   
      
    /**  
     * This classloader is like a template  
     * which includes pre-loadClass and after-loadClass  
     * @author Bernard  
     *  
     */  
    public class ComplexClassLoader extends ClassLoader {   
      
        public ComplexClassLoader() {   
        }   
      
        public ComplexClassLoader(String defaultTargetDir) {   
            this.defaultTargetDir = defaultTargetDir;   
        }   
      
        private String defaultTargetDir = "D://hotdeploys//";   
      
        public Class<?> findClass(String className) throws ClassNotFoundException {   
            byte[] classBytes = null;   
            try {   
                classBytes = loadByteCode(className);   
            } catch (IOException e) {   
                // TODO Auto-generated catch block   
                e.printStackTrace();   
            }   
            return super.defineClass(className, classBytes, 0, classBytes.length);   
        }   
      
        private byte[] loadByteCode(String className) throws IOException {   
            int ch = 0;   
            className = className.replaceAll("//.", "////") + ".class";   
            //The two slashes represent for meaning changing   
            File file = new File(defaultTargetDir + className);   
            FileInputStream in = null;   
            in = new FileInputStream(file);   
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();   
            while ((ch = in.read()) != -1) {   
                buffer.write(ch);   
            }   
            in.close();   
            return buffer.toByteArray();   
        }   
      
        public String getDefaultTargetDir() {   
            return defaultTargetDir;   
        }   
      
        public void setDefaultTargetDir(String defaultTargetDir) {   
            this.defaultTargetDir = defaultTargetDir;   
        }      
    }  
    
    package com.cxz.classloader;
    
    import com.cxz.jiangyou.Say;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    /**
     * This classloader is like a template
     * which includes pre-loadClass and after-loadClass
     * @author Bernard
     *
     */
    public class ComplexClassLoader extends ClassLoader {
    
    	public ComplexClassLoader() {
    	}
    
    	public ComplexClassLoader(String defaultTargetDir) {
    		this.defaultTargetDir = defaultTargetDir;
    	}
    
    	private String defaultTargetDir = "D://hotdeploys//";
    
    	public Class<?> findClass(String className) throws ClassNotFoundException {
    		byte[] classBytes = null;
    		try {
    			classBytes = loadByteCode(className);
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		return super.defineClass(className, classBytes, 0, classBytes.length);
    	}
    
    	private byte[] loadByteCode(String className) throws IOException {
    		int ch = 0;
    		className = className.replaceAll("//.", "////") + ".class";
    		//The two slashes represent for meaning changing
    		File file = new File(defaultTargetDir + className);
    		FileInputStream in = null;
    		in = new FileInputStream(file);
    		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    		while ((ch = in.read()) != -1) {
    			buffer.write(ch);
    		}
    		in.close();
    		return buffer.toByteArray();
    	}
    
    	public String getDefaultTargetDir() {
    		return defaultTargetDir;
    	}
    
    	public void setDefaultTargetDir(String defaultTargetDir) {
    		this.defaultTargetDir = defaultTargetDir;
    	}	
    }



    该类会自动加载d:/hotdeploys下的类文件.

    下面这个就是测试类
    Java代码

    Java代码 复制代码
    1. package com.cxz.classloader;      
    2.      
    3. import java.io.IOException;      
    4. import java.net.ServerSocket;      
    5. import java.net.Socket;      
    6.      
    7. import com.cxz.jiangyou.Say;      
    8.      
    9. public class MultiThreadTest implements Runnable {      
    10.      
    11.     private static final int portNum = 9090;      
    12.      
    13.     private static final int sleepCycle = 3000;      
    14.      
    15.     private Say sayer = null;      
    16.      
    17.     private ComplexClassLoader loader = new ComplexClassLoader();      
    18.      
    19.     private String delpoyee = "com.cxz.jiangyou.Sample";      
    20.      
    21.     public MultiThreadTest() {      
    22.         hotDeploy(delpoyee);      
    23.     }      
    24.      
    25.     public void startService() {      
    26.         while (true) {      
    27.             synchronized (sayer) {      
    28.                 sayer.say();      
    29.             }      
    30.             try {      
    31.                 Thread.sleep(sleepCycle);      
    32.             } catch (InterruptedException e) {      
    33.                 // TODO Auto-generated catch block      
    34.                 e.printStackTrace();      
    35.             }      
    36.         }      
    37.     }      
    38.      
    39.     public void hotDeploy(String name) {      
    40.         try {      
    41.             if (sayer != null) {      
    42.                 synchronized (sayer) {      
    43.                     loader = new ComplexClassLoader();      
    44.                     sayer = (Say) loader.loadClass(name).newInstance();      
    45.                 }      
    46.                 System.out.println("-------------->Hot deployment finished!");      
    47.             } else {      
    48.                 sayer = (Say) loader.loadClass(name).newInstance();      
    49.                 System.out.println("-------------->Initialization finished!");      
    50.             }      
    51.      
    52.         } catch (InstantiationException e) {      
    53.             // TODO Auto-generated catch block      
    54.             e.printStackTrace();      
    55.         } catch (IllegalAccessException e) {      
    56.             // TODO Auto-generated catch block      
    57.             e.printStackTrace();      
    58.         } catch (ClassNotFoundException e) {      
    59.             // TODO Auto-generated catch block      
    60.             e.printStackTrace();      
    61.         }      
    62.     }      
    63.      
    64.     @Override     
    65.     public void run() {      
    66.         ServerSocket server = null;      
    67.         Socket socket = null;      
    68.         try {      
    69.             server = new ServerSocket(portNum);      
    70.             while (true) {      
    71.                 socket = server.accept();      
    72.                 socket.close();      
    73.                 hotDeploy(delpoyee);      
    74.             }      
    75.         } catch (IOException e) {      
    76.             // TODO Auto-generated catch block      
    77.             e.printStackTrace();      
    78.         }      
    79.     }      
    80.      
    81.     public static void main(String[] args) {      
    82.         // new MultiThreadTest().startService();      
    83.         // new MultiThreadTest().run();      
    84.         MultiThreadTest test = new MultiThreadTest();      
    85.         Thread thread = new Thread(test);      
    86.         thread.start();      
    87.         try {      
    88.             thread.sleep(sleepCycle);      
    89.             //Waiting for the deployment Thread deploy the say obj.      
    90.         } catch (InterruptedException e) {      
    91.             // TODO Auto-generated catch block      
    92.             e.printStackTrace();      
    93.         }      
    94.         test.startService();      
    95.     }      
    96.      
    97. }     
    98.   
    99. package com.cxz.classloader;   
    100.   
    101. import java.io.IOException;   
    102. import java.net.ServerSocket;   
    103. import java.net.Socket;   
    104.   
    105. import com.cxz.jiangyou.Say;   
    106.   
    107. public class MultiThreadTest implements Runnable {   
    108.   
    109.     private static final int portNum = 9090;   
    110.   
    111.     private static final int sleepCycle = 3000;   
    112.   
    113.     private Say sayer = null;   
    114.   
    115.     private ComplexClassLoader loader = new ComplexClassLoader();   
    116.   
    117.     private String delpoyee = "com.cxz.jiangyou.Sample";   
    118.   
    119.     public MultiThreadTest() {   
    120.         hotDeploy(delpoyee);   
    121.     }   
    122.   
    123.     public void startService() {   
    124.         while (true) {   
    125.             synchronized (sayer) {   
    126.                 sayer.say();   
    127.             }   
    128.             try {   
    129.                 Thread.sleep(sleepCycle);   
    130.             } catch (InterruptedException e) {   
    131.                 // TODO Auto-generated catch block   
    132.                 e.printStackTrace();   
    133.             }   
    134.         }   
    135.     }   
    136.   
    137.     public void hotDeploy(String name) {   
    138.         try {   
    139.             if (sayer != null) {   
    140.                 synchronized (sayer) {   
    141.                     loader = new ComplexClassLoader();   
    142.                     sayer = (Say) loader.loadClass(name).newInstance();   
    143.                 }   
    144.                 System.out.println("-------------->Hot deployment finished!");   
    145.             } else {   
    146.                 sayer = (Say) loader.loadClass(name).newInstance();   
    147.                 System.out.println("-------------->Initialization finished!");   
    148.             }   
    149.   
    150.         } catch (InstantiationException e) {   
    151.             // TODO Auto-generated catch block   
    152.             e.printStackTrace();   
    153.         } catch (IllegalAccessException e) {   
    154.             // TODO Auto-generated catch block   
    155.             e.printStackTrace();   
    156.         } catch (ClassNotFoundException e) {   
    157.             // TODO Auto-generated catch block   
    158.             e.printStackTrace();   
    159.         }   
    160.     }   
    161.   
    162.     @Override  
    163.     public void run() {   
    164.         ServerSocket server = null;   
    165.         Socket socket = null;   
    166.         try {   
    167.             server = new ServerSocket(portNum);   
    168.             while (true) {   
    169.                 socket = server.accept();   
    170.                 socket.close();   
    171.                 hotDeploy(delpoyee);   
    172.             }   
    173.         } catch (IOException e) {   
    174.             // TODO Auto-generated catch block   
    175.             e.printStackTrace();   
    176.         }   
    177.     }   
    178.   
    179.     public static void main(String[] args) {   
    180.         // new MultiThreadTest().startService();   
    181.         // new MultiThreadTest().run();   
    182.         MultiThreadTest test = new MultiThreadTest();   
    183.         Thread thread = new Thread(test);   
    184.         thread.start();   
    185.         try {   
    186.             thread.sleep(sleepCycle);   
    187.             //Waiting for the deployment Thread deploy the say obj.   
    188.         } catch (InterruptedException e) {   
    189.             // TODO Auto-generated catch block   
    190.             e.printStackTrace();   
    191.         }   
    192.         test.startService();   
    193.     }   
    194.   
    195. }  
    package com.cxz.classloader;   
      
    import java.io.IOException;   
    import java.net.ServerSocket;   
    import java.net.Socket;   
      
    import com.cxz.jiangyou.Say;   
      
    public class MultiThreadTest implements Runnable {   
      
        private static final int portNum = 9090;   
      
        private static final int sleepCycle = 3000;   
      
        private Say sayer = null;   
      
        private ComplexClassLoader loader = new ComplexClassLoader();   
      
        private String delpoyee = "com.cxz.jiangyou.Sample";   
      
        public MultiThreadTest() {   
            hotDeploy(delpoyee);   
        }   
      
        public void startService() {   
            while (true) {   
                synchronized (sayer) {   
                    sayer.say();   
                }   
                try {   
                    Thread.sleep(sleepCycle);   
                } catch (InterruptedException e) {   
                    // TODO Auto-generated catch block   
                    e.printStackTrace();   
                }   
            }   
        }   
      
        public void hotDeploy(String name) {   
            try {   
                if (sayer != null) {   
                    synchronized (sayer) {   
                        loader = new ComplexClassLoader();   
                        sayer = (Say) loader.loadClass(name).newInstance();   
                    }   
                    System.out.println("-------------->Hot deployment finished!");   
                } else {   
                    sayer = (Say) loader.loadClass(name).newInstance();   
                    System.out.println("-------------->Initialization finished!");   
                }   
      
            } catch (InstantiationException e) {   
                // TODO Auto-generated catch block   
                e.printStackTrace();   
            } catch (IllegalAccessException e) {   
                // TODO Auto-generated catch block   
                e.printStackTrace();   
            } catch (ClassNotFoundException e) {   
                // TODO Auto-generated catch block   
                e.printStackTrace();   
            }   
        }   
      
        @Override  
        public void run() {   
            ServerSocket server = null;   
            Socket socket = null;   
            try {   
                server = new ServerSocket(portNum);   
                while (true) {   
                    socket = server.accept();   
                    socket.close();   
                    hotDeploy(delpoyee);   
                }   
            } catch (IOException e) {   
                // TODO Auto-generated catch block   
                e.printStackTrace();   
            }   
        }   
      
        public static void main(String[] args) {   
            // new MultiThreadTest().startService();   
            // new MultiThreadTest().run();   
            MultiThreadTest test = new MultiThreadTest();   
            Thread thread = new Thread(test);   
            thread.start();   
            try {   
                thread.sleep(sleepCycle);   
                //Waiting for the deployment Thread deploy the say obj.   
            } catch (InterruptedException e) {   
                // TODO Auto-generated catch block   
                e.printStackTrace();   
            }   
            test.startService();   
        }   
      
    }  
    
    package com.cxz.classloader;
    
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    import com.cxz.jiangyou.Say;
    
    public class MultiThreadTest implements Runnable {
    
    	private static final int portNum = 9090;
    
    	private static final int sleepCycle = 3000;
    
    	private Say sayer = null;
    
    	private ComplexClassLoader loader = new ComplexClassLoader();
    
    	private String delpoyee = "com.cxz.jiangyou.Sample";
    
    	public MultiThreadTest() {
    		hotDeploy(delpoyee);
    	}
    
    	public void startService() {
    		while (true) {
    			synchronized (sayer) {
    				sayer.say();
    			}
    			try {
    				Thread.sleep(sleepCycle);
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    		}
    	}
    
    	public void hotDeploy(String name) {
    		try {
    			if (sayer != null) {
    				synchronized (sayer) {
    					loader = new ComplexClassLoader();
    					sayer = (Say) loader.loadClass(name).newInstance();
    				}
    				System.out.println("-------------->Hot deployment finished!");
    			} else {
    				sayer = (Say) loader.loadClass(name).newInstance();
    				System.out.println("-------------->Initialization finished!");
    			}
    
    		} catch (InstantiationException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} catch (ClassNotFoundException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    
    	@Override
    	public void run() {
    		ServerSocket server = null;
    		Socket socket = null;
    		try {
    			server = new ServerSocket(portNum);
    			while (true) {
    				socket = server.accept();
    				socket.close();
    				hotDeploy(delpoyee);
    			}
    		} catch (IOException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	}
    
    	public static void main(String[] args) {
    		// new MultiThreadTest().startService();
    		// new MultiThreadTest().run();
    		MultiThreadTest test = new MultiThreadTest();
    		Thread thread = new Thread(test);
    		thread.start();
    		try {
    			thread.sleep(sleepCycle);
    			//Waiting for the deployment Thread deploy the say obj.
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		test.startService();
    	}
    
    }


    main线程主要是服务线程,通过调用startService()不停的通过system.out来打印。支线程负责监听端口(9090),当有连接信号后就重新加载类。
    服务接口很简单,如下

    Java代码 复制代码
    1. Java代码    
    2. package com.cxz.jiangyou;      
    3. public interface Say{      
    4.     public void say();      
    5. }     
    6.   
    7. package com.cxz.jiangyou;   
    8. public interface Say{   
    9.     public void say();   
    10. }  
    Java代码 
    package com.cxz.jiangyou;   
    public interface Say{   
        public void say();   
    }  
    
    package com.cxz.jiangyou;
    public interface Say{
    	public void say();
    }




    总结:所有的customerClassLoader都要加载与之相关的类(比如:父类、包含的类)。如果你需要override loadclass(string, boolean)绕过findLoadedClass()检测,只能引发java.lang.LinkageError:duplicate class definition for name: "com/cxz/jiangyou/Sample"因此,比较通用的重新加载方式应该就是new一个用户定义的classloader

  • 相关阅读:
    idea打包jar的多种方式,用IDEA自带的打包形式,用IDEA自带的打包形式 用Maven插件maven-shade-plugin打包,用Maven插件maven-assembly-plugin打包
    SSH Secure Shell 无法登录:server responded "algorithm negotiation failed”
    redis.clients.jedis.HostAndPort
    spring boot jar 进程自动停止,自动终止,不能后台持续运行
    剑指Offer_46_孩子们的游戏(圆圈中最后剩下的数)
    剑指Offer_45_扑克牌顺子
    剑指Offer_44_翻转单词顺序列
    剑指Offer_43_左旋转字符串
    剑指Offer_42_和为S的两个数字
    剑指Offer_41_和为S的连续正数序列
  • 原文地址:https://www.cnblogs.com/liaomin416100569/p/9331833.html
Copyright © 2020-2023  润新知