Ice.Application 类

参考《Ice 分布式程序设计》 马维达 译ydogg博客

    在编写Ice相关应用时,无论是Client还是Server端,都必须进行一些必要的动作,如:Ice通信器初始化、异常捕获,以及应用终止后的销毁。鉴于每个应用都需要,Ice运行时库提供了Ice.Application类来简化我们的应用编程,避免重复劳动,消除繁琐的初始化和销毁细节。

一、main函数

    Ice run time 的主要进入点main函数的主体结构如下:

package Demo;

public class Server {

	public static void main(String[] args) {
		int status = 0;
		Ice.Communicator ic = null;
		try {
			ic = Ice.Util.initialize(args);
			// ...
		} catch (Ice.LocalException e) {
			e.printStackTrace();
			status = 1;
		} catch (Exception e) {
			System.err.println(e.getMessage());
			status = 1;
		}
		if (ic != null) {
			try {
				ic.destroy();
			} catch (Exception e) {
				System.err.println(e.getMessage());
				status = 1;
			}
		}
		System.exit(status);
	}
}

    初始化函数Ice.Util.initialize 接受的参数向量是由操作系统传给main 的。这个函数扫描参数向量,查找任何与Ice run time 有关的命令行选项,但不会移除这些选项。 如果在初始化过程中出了任何问题, initialize 会抛出异常。

    在离开main 函数之前,必须调用Communicator.destroy()。destroy 操作负责结束Ice run time。特别地,destroy 会等待任何还在运行的操作调用完成。此外, destroy 还会确保任何还未完成的线程都得以汇合,并收回一些操作系统资源,比如文件描述符和内存。决不要让main 函数不先调用destroy 就终止;这样做会导致不确定的行为。

    注意,这段代码把对Ice.initialize 的调用放在了try 块中,并且会负责把正确的退出状态返回给操作系统。还要注意,只有在初始化曾经成功的情况下,代码才会尝试销毁通信器。

二、Ice.Application 

    前面的main 函数所用的结构很常用,所以Ice 提供Ice.Application 类,封装了所有正确的初始化和结束活动。下面是这个类的概况(省略了一些细节):

package Ice;

public abstract class Application {

	public Application();
	
	public final int main(String appName, String[] args);
	
	public final int main(String appName, String[] args, String configFile);
	
	public abstract int run(String[] args);
	
	public static String appName();
	
	public static Communicator communicator();
	
	// ...
}

    这个类的意图是,你对Ice.Application 进行特化,在你的派生类中实现run 抽象方法。你通常会放在main 中的代码,都要放进run 方法。使用Ice.Application,我们的程序看起来像这样:

public class Server extends Ice.Application {

	public int run(String[] args) {
		// ......
		return 0;
	}

	public static void main(String[] args) {
		Server app = new Server();
		int status = app.main("Server", args);
		System.exit(status);
	}
}

    Application.main 函数会做这样一些事情:

1.针对java.lang.Exception 安装一个异常处理器。如果你的代码没有处理某个Ice 异常, Application.main 会先在System.err上打印异常的名字和栈踪迹,然后返回非零的返回值。

2.初始化(通过调用Ice.Util.initialize)和结束(通过调用Communicator.destroy)通信器。你可以调用静态的communicator 访问器,访问你的服务器的通信器。

3.扫描参数向量,查找与Ice run time 有关的选项,并移除这样的选项。因此,在传给你的run 方法的参数向量中,不再有与Ice 有关的选项,而只有针对你的应用的选项和参数。

4.通过静态的appName 成员函数,提供你的应用的名字。这个调用的返回值是调用Application.main 时用的第一个参数,所以,你可以在你的代码的任何地方调用Ice.Application.appName,从而获得这个名字(通常在打印错误消息时需要这一信息)。

5.安装一个关闭挂钩,适当地关闭通信器。

    Ice.Application 能够确保你的程序适当地结束Ice run time,不管你的服务器是正常终止的,还是因为对异常或信号作出响应而终止的。建议在所有程序中都使用这个类。此外, Ice.Application 还提供了信号处理以及配置特性,当你使用这个类时,你无需自己实现这些特性。

    Ice.Application在客户端和服务器的使用相同。只需从Ice.Application 派生一个类,把客户代码放进它的run 方法,就可以了。这种做法带来的好处是在发生异常的情况下, Ice.Application 也能确保正确销毁通信器。

三、捕捉信号

    服务器在终止之前必须进行一些清理工作,比如刷出数据库缓冲区,或者关闭网络连接。要想在收到信号或键盘中断时,防止数据库文件或其他持久数据损坏,这样的清理工作特别重要。

    Java 没有提供对信号的直接支持,但它允许应用注册关闭挂钩,当JVM 关闭时会调用这样的关闭挂钩。有若干事件能够触发JVM 关闭,比如调用System.exit或者操作系统发出了中断信号,但关闭挂钩不会收到对关闭原因的说明。

    在缺省情况下, Ice.Application 会注册一个关闭挂钩,从而允许JVM 关闭之前干净地终止应用:

package Ice;

public abstract class Application {
	
	// ...
	
	synchronized public static void shutdownOnInterrupt();
	
	synchronized public static void defaultInterrupt();
	
	synchronized public static boolean interrupted();
}
 

    下面是Ice.Application各成员函数的行为:

shutdownOnInterrupt

    这个函数安装一个关闭挂钩,它会调用通信器的shutdown 干净地关闭你的应用。这是缺省行为。

defaultInterrupt

    这个函数移除关闭挂钩。

interrupted

    如果此前是信号造成了通信器的关闭,这个函数返回真,否则返回假。据此,我们可以区分有意的关闭和JVM 造成的被迫关闭。例如,这可以用于日志记录。在缺省情况下, Ice.Application 的表现就好像shutdownOnInterrupt 被调用过一样,因此,要确保程序在JVM 关闭时干净地终止,我们的服务器的main 函数不需要变动。但我们增加了一个诊断功能,报告这件事情的发生,所以我们的main 函数现在看起来像这样:

public class Server extends Ice.Application {

	public int run(String[] args) {
		// Server code here...
		if (interrupted())
			System.err.println(appName() + ": terminating");
		return 0;
	}

	public static void main(String[] args) {
		Server app = new Server();
		int status = app.main("Server", args);
		System.exit(status);
	}
}

四、Ice.Application 和属性

Ice.Application 还负责用属性值初始化Ice run time。通过属性,能够用两种方式配置run time。方式一,用属性控制线程池尺寸或服务器端口号。

package test;

import Ice.Properties;

public class Test extends Ice.Application {

	public int run(String[] args) {
		Ice.ObjectAdapter adapter = communicator()
		.createObjectAdapterWithEndpoints("SimpleFilesystem",
		"default -h 127.0.0.1 -p 10000");
		// 获取命令行传入的参数集
		Properties properties = communicator().getProperties();
		// 通过属性名称获取属性值
		String serverThreadPool = properties.getProperty("Ice.ThreadPool.Server.Size");
		System.out.println("serverThreadPool = " + serverThreadPool);
		return 0;
	}

	public static void main(String[] args) {
		Test app = new Test();
		System.exit(app.main("Server", args));
	}
}

    在命令行中运行:

Java test.Test --Ice.ThreadPool.Server.Size=100

输出结果:serverThreadPool = 100

Ice.Application 的main函数是重载的

public final int main(String appNameString args[], String configFile);

所以方式二允许你指定一个配置文件名,这个文件将在初始化过程中被处理,所有的参数可以直接放在配置文件中

五、Ice.Application 的局限

Ice.Application 是一个单体类,会创建单个通信器。如果你要使用多个通信器,你不能使用Ice.Application。相反,你必须像下面这样安排你的代码结构(一定要记得销毁通信器)。

public class Server {

	public static void main(String[] args) {
		int status = 0;
		Ice.Communicator ic = null;
		try {
			// Server implementation here...
		} catch (Ice.LocalException e) {
			e.printStackTrace();
			status = 1;
		} catch (Exception e) {
			System.err.println(e.getMessage());
			status = 1;
		} finally {
			if (ic != null)
				ic.destroy();
		}
		System.exit(status);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值