通过ClassLoader说明容器热部署实现机制
2013-07-23 08:44
609 查看
在J2EE的项目中,容器给我们提供的热部署功能使得我们不用重启动容器而修改我们的代码。比如使用Weblogic,我们可以在Weblogic-application.xml中配置是否支持热部署Servlet。查阅Weblogc 文档,其实在Weblogic中,EJB组件也是可以热部署的,但如何要热部署EJB组件,Weblogc要求必须自定义ClassLoder。
JVM规范中没有指定JVM支持动态加载修改过的类。类的加载,卸载对于程序员是透明的。如果我们要实现类的动态加载我们就要理解JVM本身类的加载与卸载的原理,实现热部署。对于JVM加载类方面的资料在网上很多的,在这里我做简单概述:
(1)JVM加载时通过ClassLoader加载的。
(2)JVM有3层继承关系的ClassLoder 分别是:
-----BootStrap类加载器
加载JRE/lib
-----------------ExtClassLoader 加载 JRE/lib/ext
----------AppClassLoader 加载ClassPath/
(3)为了安全性,JVM加载采用了双亲委派机制,如何理解呢,就是当需要加载一个类时,当前的ClassLoader先请求父ClassLoader,依次
类推,直到父类的ClassLoader无法加载时,才通过当前的ClassLoser加载,这就保证了像String这样的类型必须使用JRE里面的, 使得
JRE lib 下类不会被修改。同时避免了ClassCaseException。
(4)在JVM中,一个实例是通过本身的类名+加载它的ClassLoader识别的,也就是说 不同的ClassLoader 加载同一个类在JVM是不同的。
(5)同一个ClassLoader是不允许多次加载一个类的,否则会报java.lang.LinkageError。attempted duplicate class definition for
name XXX,在下面的例子中会指出。
既然JVM不支持热部署,那么要实现热部署,就必须自定义ClassLoader,当类被修改过后,加载该类。下面通过代码说明:
package classloader;
/**
* @author vma
*/
// 自定义一个类加载器
public class DynamicClassLoader extends ClassLoader {
public Class<?> findClass(byte[] b) throws ClassNotFoundException {
return defineClass(null, b, 0, b.length);
}
package classloader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @author vma
*/
public class ManageClassLoader {
DynamicClassLoader dc =null;
Long lastModified = 0l;
Class c = null;
//加载类, 如果类文件修改过加载,如果没有修改,返回当前的
public Class loadClass(String name) throws ClassNotFoundException, IOException{
if (isClassModified(name)){
dc = new DynamicClassLoader();
return c = dc.findClass(getBytes(name));
}
return c;
}
//判断是否被修改过
private boolean isClassModified(String filename) {
boolean returnValue = false;
File file = new File(filename);
if (file.lastModified() > lastModified) {
returnValue = true;
}
return returnValue;
}
// 从本地读取文件
private byte[] getBytes(String filename) throws IOException {
File file = new File(filename);
long len = file.length();
lastModified = file.lastModified();
byte raw[] = new byte[(int) len];
FileInputStream fin = new FileInputStream(file);
int r = fin.read(raw);
if (r != len) {
throw new IOException("Can't read all, " + r + " != " + len);
}
fin.close();
return raw;
}
}
测试类;Main 每隔 5s 加载一次
package classloader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
*
* @author vma
*/
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws ClassNotFoundException, IOException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, InterruptedException {
String path = "D:\\deploy\\JDBC\\ClassLoader\\build\\classes\\classloader\\LocalClass.class";
ManageClassLoader mc = new ManageClassLoader();
while(true){
Class c = mc.loadClass(path);
Object o = c.newInstance();
Method m = c.getMethod("getName");
m.invoke(o);
System.out.println(c.getClassLoader());
Thread.sleep(5000);
}
}
被加载的类
/**
*
* @author vma
*/
public class LocalClass {
public void getName() {
System.out.println("hahaha ");
}
}
运行时,每隔5s 输出:
hahaha
classloader.DynamicClassLoader@61de33
当我们修改 System.out.println("hahaha ");
---> System.out.println("changed "); 编译LocalClass后
输出变为:
changed
classloader.DynamicClassLoader@173a10f
在loadClass中,
我们必须重新初始化一个ClassLoader,负责就会违背同一个ClassLoader是不允许多次加载一个类的。
public Class loadClass(String name) throws ClassNotFoundException, IOException{
if (isClassModified(name)){
dc = new DynamicClassLoader();
return c = dc.findClass(getBytes(name));
}
return c;
}
当然,容器的实现机制肯定及其完善,不可能周期性的加载,可能回通过监听机制,动态加载修改过的类。但它的实现机制肯定也是重新
实例化一个ClassLoder,加载需要加载的类。
JVM规范中没有指定JVM支持动态加载修改过的类。类的加载,卸载对于程序员是透明的。如果我们要实现类的动态加载我们就要理解JVM本身类的加载与卸载的原理,实现热部署。对于JVM加载类方面的资料在网上很多的,在这里我做简单概述:
(1)JVM加载时通过ClassLoader加载的。
(2)JVM有3层继承关系的ClassLoder 分别是:
-----BootStrap类加载器
加载JRE/lib
-----------------ExtClassLoader 加载 JRE/lib/ext
----------AppClassLoader 加载ClassPath/
(3)为了安全性,JVM加载采用了双亲委派机制,如何理解呢,就是当需要加载一个类时,当前的ClassLoader先请求父ClassLoader,依次
类推,直到父类的ClassLoader无法加载时,才通过当前的ClassLoser加载,这就保证了像String这样的类型必须使用JRE里面的, 使得
JRE lib 下类不会被修改。同时避免了ClassCaseException。
(4)在JVM中,一个实例是通过本身的类名+加载它的ClassLoader识别的,也就是说 不同的ClassLoader 加载同一个类在JVM是不同的。
(5)同一个ClassLoader是不允许多次加载一个类的,否则会报java.lang.LinkageError。attempted duplicate class definition for
name XXX,在下面的例子中会指出。
既然JVM不支持热部署,那么要实现热部署,就必须自定义ClassLoader,当类被修改过后,加载该类。下面通过代码说明:
package classloader;
/**
* @author vma
*/
// 自定义一个类加载器
public class DynamicClassLoader extends ClassLoader {
public Class<?> findClass(byte[] b) throws ClassNotFoundException {
return defineClass(null, b, 0, b.length);
}
package classloader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @author vma
*/
public class ManageClassLoader {
DynamicClassLoader dc =null;
Long lastModified = 0l;
Class c = null;
//加载类, 如果类文件修改过加载,如果没有修改,返回当前的
public Class loadClass(String name) throws ClassNotFoundException, IOException{
if (isClassModified(name)){
dc = new DynamicClassLoader();
return c = dc.findClass(getBytes(name));
}
return c;
}
//判断是否被修改过
private boolean isClassModified(String filename) {
boolean returnValue = false;
File file = new File(filename);
if (file.lastModified() > lastModified) {
returnValue = true;
}
return returnValue;
}
// 从本地读取文件
private byte[] getBytes(String filename) throws IOException {
File file = new File(filename);
long len = file.length();
lastModified = file.lastModified();
byte raw[] = new byte[(int) len];
FileInputStream fin = new FileInputStream(file);
int r = fin.read(raw);
if (r != len) {
throw new IOException("Can't read all, " + r + " != " + len);
}
fin.close();
return raw;
}
}
测试类;Main 每隔 5s 加载一次
package classloader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
*
* @author vma
*/
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws ClassNotFoundException, IOException, NoSuchMethodException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, InterruptedException {
String path = "D:\\deploy\\JDBC\\ClassLoader\\build\\classes\\classloader\\LocalClass.class";
ManageClassLoader mc = new ManageClassLoader();
while(true){
Class c = mc.loadClass(path);
Object o = c.newInstance();
Method m = c.getMethod("getName");
m.invoke(o);
System.out.println(c.getClassLoader());
Thread.sleep(5000);
}
}
被加载的类
/**
*
* @author vma
*/
public class LocalClass {
public void getName() {
System.out.println("hahaha ");
}
}
运行时,每隔5s 输出:
hahaha
classloader.DynamicClassLoader@61de33
当我们修改 System.out.println("hahaha ");
---> System.out.println("changed "); 编译LocalClass后
输出变为:
changed
classloader.DynamicClassLoader@173a10f
在loadClass中,
我们必须重新初始化一个ClassLoader,负责就会违背同一个ClassLoader是不允许多次加载一个类的。
public Class loadClass(String name) throws ClassNotFoundException, IOException{
if (isClassModified(name)){
dc = new DynamicClassLoader();
return c = dc.findClass(getBytes(name));
}
return c;
}
当然,容器的实现机制肯定及其完善,不可能周期性的加载,可能回通过监听机制,动态加载修改过的类。但它的实现机制肯定也是重新
实例化一个ClassLoder,加载需要加载的类。
相关文章推荐
- 通过ClassLoader说明容器热部署实现机制
- 通过ClassLoader说明容器热部署实现机制
- 通过ClassLoader说明容器热部署实现机制
- 通过ClassLoader实现容器热部署
- 通过代码及流程图说明Google在Android上的Push机制的实现
- 怎样用Docker实现DevOps?谈通过容器进行持续部署
- WinForm枚举容器中的控件,实现控件统一事件处理机制
- activeMQ指南针_forwarding bridge的实现机制、使用说明
- 通过curl的并发机制实现php批量网络请求
- 通过代码生成机制实现强类型编程-CodeSimth版
- 源码:通过鼠标停靠,取鼠标所在位置的控件类名的示范实例。附源码与实现说明
- 一起谈.NET技术,从数据到代码—通过代码生成机制实现强类型编程[上篇]
- Android应用中通过AIDL机制实现进程间的通讯实例
- 番外 01:Spring IoC 实现原理简析,Java的反射机制,通过类名创建对象
- 通过websocket 实现与容器的交互
- Wordpress主题与插件实现机制以及部分主题插件用途配置说明
- 通过组策略实现的域内基本的三个常见部署实践
- 混合架构下的docker-tomcat容器协同部署JAVA WEB服务,内嵌ICE中间件服务的技术实现
- 持续交付:通过自动化构建、测试、部署流水线实现可靠的软件发布
- 通过代码生成机制实现强类型编程-CodeSimth版