分享
 
 
 

避免重启你的应用程序 二

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

三:如果更新的功能包括应用逻辑,也就是class改变了,那就稍微麻烦点,你需要了解ClassLoader的原理。使用你定制的ClassLoader重新Load 已经编译好的class,就好比你重启应用一样。下面将简单介绍ClassLoader原理,以及举出一个例子来说明如何避免重启应用程序。

虚拟机通过Classloader来转载类。bootstrap loader 负责load jdk的class(java.*,javax.*), system class loader是bootstrap的子类,负责load 所有在chasspath指定的变量。ClassLoader将字节流转化为Class类,这些字节流可能来源文件,也可能来源于网络或者数据库。转化方法是调用ClassLoader提供的final defineClass(className, classBytes, 0, classBytes.length)方法来实现。需要记住的是虚拟机里一个类的唯一标识是通过类的包名+类名+装载此类的ClassLoader。同一个ClassLoader实例只能装载Class一次,重复装载将抛出重复类定义异常。

如下自定义ClassLoader将从classpath里转载指定的类,来说明如上对ClassLoader的介绍,同时,我们用此ClassLoader演示如何避免重启动应用程序

public class DyLoader extends ClassLoader

{

public DyLoader()

{

super(DyLoader.class.getClassLoader());

}

public Class loadFromCustomRepository(String className) {

/**取环境变量*/

String classPath = System.getProperty("java.class.path");

List classRepository = new ArrayList();

/**取得该路径下的所有文件夹 */

if ( (classPath != null) && ! (classPath.equals(""))) {

StringTokenizer tokenizer = new StringTokenizer(classPath,

File.pathSeparator);

while (tokenizer.hasMoreTokens()) {

classRepository.add(tokenizer.nextToken());

}

}

Iterator dirs = classRepository.iterator();

byte[] classBytes = null;

/**在类路径上查找该名称的类是否存在,如果不存在继续查找*/

while (dirs.hasNext()) {

String dir = (String) dirs.next();

//replace '.' in the class name with File.separatorChar & append .class to the name

String classFileName = className.replace('.', File.separatorChar);

classFileName += ".class";

try {

File file = new File(dir + File.separatorChar + classFileName);

if (file.exists()) {

InputStream is = new FileInputStream(file);

/**把文件读到字节文件*/

classBytes = new byte[is.available()];

is.read(classBytes);

break;

}

}

catch (IOException ex) {

System.out.println("IOException raised while reading class file data");

ex.printStackTrace();

return null;

}

}

return this.defineClass(className, classBytes, 0, classBytes.length);//加载类

}

}

如下调用

DyLoader loader = new DyLoader();

Class a = loader.loadFromCustomRepository("com.lijz.SampleDyService");

Class b = loader.loadFromCustomRepository("com.lijz.SampleDyService");

第三行代码将会抛出

java.lang.LinkageError: duplicate class definition: com/lijz/SampleDyService

如果如下调用,则一切正常,这是因为你使用新的ClassLoader实例来装载com.lijz.SampleDyService"

DyLoader loader= new DyLoader();

Class a loader.loadFromCustomRepository("com.lijz.SampleDyService");

DyLoader newLoader = new DyLoader();

Class b = newLoader.loadFromCustomRepository("com.lijz.SampleDyService");

言归正传,停止介绍Classloader,回到利用Classloader来避免重新启动你的应用程序

首先定义业务逻辑处理模块接口

public interface IDyService

{

public void start();

public void close();

public void doBusiness();

}

start方法用于初始化,close用于清除此服务。doBusiness用来模拟处理业务

一个实现的例子如下:

public class SampleDyService implements IDyService

{

public SampleDyService()

{

}

public void doBusiness()

{

System.out.println("hello boy");

}

public void start()

{

System.out.println("Start SampleDyService:");

System.out.println(SampleDyService.class.getClassLoader());

}

public void close()

{

System.out.println("close SampleDyService:");

}

start方法 close方法仅打印出提示信息。doBuinsess输出"hello boy"。主程序将循环调用doBusiness方法

public class Main()

{

private IDyService service = null;

public Main()

throws Exception

{

DyLoader loader = new DyLoader();

service = (IDyService) loader.loadFromCustomRepository(

"com.gctech.service.test.dyloader.SampleDyService").newInstance();

service.start();

while (true)

{

service.doBusiness();

Thread.sleep(1000 * 3);

}

}

public static void main(String[] args)

throws Exception

{

Main main = new Main();

}

}

假设业务逻辑改变,要求SampleDyService的doBusiness打印出"hello girl"。新编译好的SampleDyService已经覆盖了原来的类。在不启动应用程序前提条件下如何更新新的业务逻辑呢?

分俩部来完成

第一步,在Main类里添加notifyReLoad方法,用新的classloader重新生成SampleDyService实例

public void notifyReLoad()

throws Exception

{

service.close();

DyLoader loader = new DyLoader();

service = (IDyService) loader.loadFromCustomRepository(

"com.gctech.service.test.dyloader.SampleDyService").newInstance();

service.start();

}

第二步:使用某种机制检测来检测SampleDyService.class已经改变,如可以通过上面的例子启动一个线程检测SampleDyService.class是否被改变,如果改变则调用Main.notifyReLoad().也可以采用主动通知方式,如web应用中,提供这样的界面调用。在此例子中提供一个检测线程。

public class DyServciceChecker extends Thread

{

Main main = null;

public DyServciceChecker()

{

}

public void setMain(Main main)

{

this.main = main;

}

public void run()

{

while(!interrupted())

{

try

{

boolean isChanged = check();

if(isChanged)

{

main.notifyReLoad();

}

else

{

Thread.sleep(1000*50);

}

}

catch (Exception ex)

{

ex.printStackTrace();

}

}

}

}

修改Main类的构造函数成如下

public Main()

throws Exception

{

DyLoader loader = new DyLoader();

service = (IDyService) loader.loadFromCustomRepository(

"com.gctech.service.test.dyloader.SampleDyService").newInstance();

service.start();

//添加检测线程

DyServciceChecker checker = new DyServciceChecker();

checker.setMain(this);

checker.start();

while (true)

{

service.doBusiness();

Thread.sleep(1000 * 3);

}

}

好了,运行Main类。并在运行过程中用新的SampleDyService.class覆盖旧的SampleDyService.class。控制台输出信息如下:

Start SampleDyService:

com.gctech.service.test.dyloader.DyLoader@108786b

hello boy

hello boy

hello boy

...............

close SampleDyService:

Start SampleDyService:

com.gctech.service.test.dyloader.DyLoader@c1cd1f

hello girl

hello girl

总结:

如果应用程序不可避免的在运行中要重启动,你首先要做好的工作是采取合理的设计,保证用户的请求和对用户的相应不丢失。否则,只能等到用户访问量最少的时候去启动。还有你在写你的业务逻辑的时候,即使当时你很肯定你的代码写死也没关系也不要这么做,尽量采用配置文件的方法,并提供如上的检测线程,现在的web container都提供检测web.xml文件是否改变来确定是否需要重新部署web。最后Classloader能帮助你动态加载类,从而在不停止应用程序的情况下动态更新类

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有