Java 基于反射的即插即用 热替换

使用场景
热替换(hot-replacement)是一种模仿硬件的即插即用(hot-plugging)的方式,不需要让机器停下来再更换部件,更换的部件不影响其他功能模块的运转。想象一下在软件行业在不停机,不重新编译的情况下可以更换软件模块而不影响程序运行是件多么美好的事情。但是目前没有大规模采用这种方式是因为这种系统效率和安全性比较低,在线升级Web应用是很有意义的。
原理分析
想要实现在不知不觉中更换组件,就的实现动态的加载模块就是在程序中显示的加载类。比如一个男的想要换女朋友啦,这个男的和女的构成一个整体。就相当于两个接口规范,一个接口规定了男的(符合这个规约的就是男的),另一个接口规定了女的(符合这个规约的就是女的)。一个类实现了男人接口(public class man implements Man,这个接口规定男人必须有的一些东西,有这些东西的才算男人)他就是男人,另一个类实现了女人接口(public class woman implements Woman,这个接口规定女人必须有的一些东西,有这些东西的才算女人)她就是女人。男人和女人在一起就能很好的协同工作。突然有一天男的有外遇啦,他去和别的女人协同工作啦。他就在不知不觉中更换了女友。就这样他就实现了即插即用(热替换)。
Java提供了显示的类加载ClassLoader。有了显示类加载就不只是JVM才可以进行类加载,指令执行什么的啦。JVM会控制BootstrapClassLoader来加载j2sdk1.4.1_01\jre\lib目录下的类。
ClassLoader extClassloader=ClassLoader.getSystemClassLoader().getParent();执行这个你会发现extClassloader.getParent()为null,就表示BootstrapClassLoader是顶层的类加载而且他是独立于ClassLoader的由JVM自己实现负责加载系统类。ExtClassLoader会去加载j2sdk1.4.1_01\jre\lib\ext目录下的类。AppClassLoader主要负责在java –classpath 下加载类。
CustomClassLoader负责加载用户自定义类。整个类加载体系采用双亲委托的方式加载类。


用一个类加载器,如果用多个类加载器加载类每个加载器维护这一个要加载的类的引用的缓存,这样同一个类就被加载了多次,JVM会认为被多个类加载器加载的类不同,即使他们是同一个类。用类加载器来加载要调用的类,通过反射机制来调用类的函数,从而实现动态加载类。当需要更新一个加载的类是只需要更新class文件就可以完成模块升级,系统的其他部分不需要更改,程序的调用模块在调用到更新的模块时才会被加载执行,这样就实现了热替换。
用两个类man和woman来简单演示下热替换。这里采用系统类加载器SystemClassLoader来加载类。需要注意几个问题:首先最好只用一个类加载器,因为用多个类加载器加载同一个类的话会在内存创建多个对象,并且JVM会认为这些对象是不同的,当然系统的那些类除外。其次由于双亲委托机制,如果你写的类和系统的类名称相同那加载的类就不是你写的类,你可以设置ClassLoader的Parent为null,但是这样的话一些Java本身提供的类你将无法使用,当你想要使用java提供的类就用ClassLoader.getSystemClassLoader去加载。

代码示例
1)分别编译以下几个文件。

Man.java
public interface Man
{
public byte littleTwoBrother();

public byte loveWoman(Class<?> class_) throws Exception;
}

Woman.java
public interface Woman
{
public byte beautifulFace();

public byte Breast();

public byte niceBottom();

public byte beautifulLegs();
}

man_.java
import java.lang.reflect.*;
public class man_ implements Man
{

ClassLoader CL = ClassLoader.getSystemClassLoader();

@Override
public byte littleTwoBrother()
{
System.out.print("二弟");
return 1;
}

@Override
public byte loveWoman(Class<?> class_) throws Exception
{
Object WObject = class_.newInstance();
Field[] fields = class_.getDeclaredFields();
for(int i=0 ; i<fields.length ; i++)
{
String methodName = fields[i].getName().substring(0, 1).toUpperCase()+ fields[i].getName().substring(1);
Method getNationMethod = class_.getMethod(methodName, new Class[]{});
System.out.print(getNationMethod.invoke(WObject, new Object[]{}));
}
Method[] methods = class_.getMethods();
for(int i=0 ; i<methods.length ; i++)
{
methods[i].invoke(WObject, new Object[]{});
}
return 1;
}

private byte chaseWoman(String classPath)
{
try
{
Class<?> class_ = CL.loadClass(classPath);
loveWoman(class_);
return 1;
}
catch(Exception e)
{
//e.printStackTrace();
return 0;
}
}

public static void main(String[] args)
{
man_ man = new man_();
System.out.print("男人爱");
man.chaseWoman("woman_");
}
}

woman_.java(其中一个woman类)

public class woman_ implements Woman
{

public String nation = "中国";

public String Nation()
{
return nation;
}

@Override
public byte beautifulFace()
{
System.out.print("女人的"+"漂亮的脸");
return 1;
}

@Override
public byte Breast()
{
System.out.print(",丰胸");
return 1;
}

@Override
public byte niceBottom()
{
System.out.print(",翘臀");
return 1;
}

@Override
public byte beautifulLegs()
{
System.out.print(",美腿");
return 1;
}

}



woman_.java(另一个woman类)

public class woman_ implements Woman
{

public String nation = "美国";

public String Nation()
{
return nation;
}

@Override
public byte beautifulFace()
{
System.out.print("女人的"+"漂亮的脸");
return 1;
}

@Override
public byte Breast()
{
System.out.print(",丰胸");
return 1;
}

@Override
public byte niceBottom()
{
System.out.print(",翘臀");
return 1;
}

@Override
public byte beautifulLegs()
{
System.out.print(",美腿");
return 1;
}

}




2) 执行命令java man_   。
3) 更换woman_.class 文件 就跟换女人啦。
4) 再执行命令java man_   发现更换女人成功。

你可能感兴趣的:(java,jvm,工作,ext)