classloader 热部署

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

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

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代码
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代码 
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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值