`
Aga
  • 浏览: 218501 次
  • 性别: Icon_minigender_1
  • 来自: 天津
社区版块
存档分类
最新评论

classloader做的一个热部署

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

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

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下的类文件.

下面这个就是测试类
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),当有连接信号后就重新加载类。
服务接口很简单,如下
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

另一个例子

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

public class TestSuite {

	private static final String dir = "D:\\depot\\dev\\";
	
	public static Test suite() {
		TestSuite suite = new TestSuite();
		Class clz = loadClass("com.cxz.test.bs.XXXXTest");
		suite.addTestSuite(clz);
		return suite;
	}

	public static void bootstrap(String[] args) {
		junit.textui.TestRunner.run(suite());
	}

	public static Class loadClass(String name) {
		File file = new File(dir);
		ClassLoader loader = null;
		Class clz = null;
		try {
			loader = new URLClassLoader(new URL[] { file.toURL() });
			clz = loader.loadClass(name);
		} catch (MalformedURLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// 
		return clz;
	}

	/**
	 * For test
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		loadClass("");
	}
}

  • Research.rar (9.4 KB)
  • 描述: eclipse工程格式
  • 下载次数: 68
6
1
分享到:
评论

相关推荐

    classloader 热部署

    博文链接:https://kuangbaoxu.iteye.com/blog/206472

    美团IDEA插件实现Java应用的热部署实践

    热部署插件的实现原理主要是通过Agent字节码增强、Javassist、Classloader等技术来实现的。Agent字节码增强是指在Java字节码中插入一些用于热部署的代码,以便在运行时可以实现热部署。Javassist是一个Java库,提供...

    支持Java热部署的插件

    Java热部署技术是一种提高开发效率的重要工具,它允许开发者在运行时修改代码并立即生效,无需重新启动应用程序服务器。在传统的开发过程中,每次修改代码后都需要重新编译、打包,然后重启服务器才能看到更改的效果...

    JAVA类加载器分析--热部署的缺陷(有代码示例,及分析)

    另一个问题是类的静态初始化器只会在类首次加载时执行,如果热部署过程中重新加载了类,静态初始化器不会再次执行,这可能会影响到依赖静态变量的逻辑。 解决这些问题的方法包括使用特殊的热部署插件,如JRebel,它...

    深入探索 Java 热部署

    ASM 是一个强大的 Java 字节码操控和分析框架,允许开发者动态生成类或修改已存在的类。ASM 首先读取 .class 文件,解析其中的元数据,然后允许开发者插入、删除或修改字节码指令,最后生成新的 .class 文件。通过 ...

    关于java热部署知识.doc

    上述代码展示了如何创建一个动态ClassLoader来实现热部署的基本思想。ManageClassLoader会检查类文件的修改时间,如果发现变化,就使用DynamicClassLoader加载新的字节码。 尽管Java标准版(J2SE)没有内置的热部署...

    STS热部署方法(springboot).docx

    这是一个可选依赖,不会传递到依赖于你的项目的其他模块。在`pom.xml`中添加如下代码: ```xml &lt;groupId&gt;org.springframework.boot &lt;artifactId&gt;spring-boot-devtools &lt;optional&gt;true ``` 接着,在`...

    Java类热替换(热部署)源码

    1. **JRebel**:这是一个商业工具,它可以实时更新类、资源和配置文件,而无需重新部署应用。JRebel通过代理ClassLoader实现这一功能,但其核心原理并不开源。 2. **JVM工具JIT编译器**:Java虚拟机(JVM)的Just-...

    ClassLoader 案例

    自定义ClassLoader允许开发者根据特定需求加载类,比如动态加载或更新类文件,这在某些高级应用场景中非常有用,如插件系统、热部署等。本案例将深入探讨如何创建一个自定义的ClassLoader,利用Java反射和注解技术...

    ClassLoader 详解.doc

    自定义ClassLoader是Java平台的一大特色,开发人员可以根据需要创建自己的类加载器,例如实现模块化、热部署或者加密解密类等高级功能。自定义ClassLoader通常需要重写findClass()或loadClass()方法,以控制类的加载...

    ClassLoader的 一些测试

    自定义ClassLoader是一种常见的需求,例如在插件系统、热部署等场景。自定义加载器通常需要重写`loadClass(String className)`方法,通过URL读取类的字节流并转换为Class对象。在这个过程中,我们需要注意类的缓存,...

Global site tag (gtag.js) - Google Analytics