日期:2014-05-16  浏览次数:20555 次

amoeba源码分析(一)-AmoebaProxyServer入口类分析

本系列以Amoeba 997版本分支源码(目前最新版本分支)作为分析源,amoeba源码SVN地址:http://amoeba.googlecode.com/svn/trunk。在分析源码前,需要将源码导入到Eclipse工程里面。amoeba共分为amoeba、amoeba-mysql、amoeba-memcached、amoeba-aladdin、amoeba-mongodb、amoeba-manager、amoeba-geteway七个子工程。本系列主要分析amoeba、amoeba-mysql源码,其他子工程会根据需要分析说明

 

AmoebaProxyServer作为Amoeba的入口类存在于amoeba子工程的com.meidusa.amoeba.server包下。AmoebaProxyServer的main方法提供了完整的启动流程和方法。

AmoebaProxyServer提供了两个日志记录对象,一个用于基本的日志记录,一个用于对报告进行日志记录。

1  首先来看main方法的第一段代码(用于判断并处理启动或停止命令)。代码中加入少量注释,便于理解:

		String level = System.getProperty("benchmark.level", "warn");
		System.setProperty("benchmark.level", level);
		if(args.length>=1){
			ShutdownClient client = new ShutdownClient(MonitorConstant.APPLICATION_NAME);
			MonitorCommandPacket packet = new MonitorCommandPacket();	//监控命令报文对象
			//通过第一个命令行参数进行处理判断
			if("start".equalsIgnoreCase(args[0])){
				//处理启动amoeba命令
				packet.funType = MonitorCommandPacket.FUN_TYPE_PING;
				if(client.run(packet)){
					//如果已经启动,则提示amoeba server启动信息,并异常退出
					System.out.println("amoeba server is running with port="+client.getPort());
					System.exit(-1);
				}
			}else{
				//处理停止amoeba命令
				packet.funType = MonitorCommandPacket.FUN_TYPE_AMOEBA_SHUTDOWN;
				if(client.run(packet)){
					//停止成功提示
					System.out.println("amoeba server shutting down with port="+client.getPort());
				}else{
					//停止失败提示(原因为amoeba server并未启动)
					System.out.println("amoeba server not running with port="+client.getPort());
				}
				System.exit(0);
			}
		}else{
			//没有传入参数,则提示amoeba命令行用法
			System.out.println("amoeba start|stop");
			System.exit(0);
		}

以上代码中处理命令的功能主要通过ShutdownClient.run()方法来执行处理。作者在方法注释里提示“return false if server not running”,不管命令是start或者stop均可利用该含义返回值进行统一处理。如果为start命令,返回false表示之前未启动,返回true表示amoeba已经启动过;如果为stop命令,返回false表示amoeba并未启动,无法停止,返回true则表示停止成功。ShutsownClient.run()方法完整代码(加注释)如下所示:

	/**
	 * 第一次启动时,由于监控服务并未启动,程序将在socket建立时抛出异常返回false
	 * @param command
	 * @return false if server not running
	 */
	public boolean run(MonitorCommandPacket command) {
		if(port <=0){
			//加载.Amoeba.shutdown.port(文件内容形如127.0.0.1:22334),从文件中获取监控IP和端口
			socketInfoFile = new File(ConfigUtil.filter("${amoeba.home}"),appplicationName+".shutdown.port");
			if(!socketInfoFile.exists()){
				return false;
			}
			
			try {
				BufferedReader reader = new BufferedReader(new FileReader(socketInfoFile));
				String sport = reader.readLine();
				String tmp[] = StringUtil.split(sport, ":");
				if(tmp.length <=1){
					return false;
				}
				this.port = Integer.parseInt(tmp[1]);
				this.host = tmp[0];
				reader.close();
			}catch (Exception e) {
				e.printStackTrace();
				return false;
			}
		}
		
		try {
			//访问监听端口。如果监控服务已经启动,则socket会成功建立,否则建立失败,返回false。
			//amoeba在初次启动时,监控服务并未启动,流程进入异常,返回false
			Socket socket = null;
			try{
				if(host == null){
					//无配置,则读取localhost地址
					socket = new Socket(InetAddress.getLocalHost(),port);
				}else{
					if("0.0.0.0".equals(host)){
						//配置为全零网络(默认网络),则读取localhost地址
						socket = new Socket(InetAddress.getLocalHost(),port);
					}else{
						socket = new Socket(host, port);
					}
				}
			}catch(IOException e){
				//第一次启动,将进入异常,返回false
				return false;
			}
			socket.getOutputStream().write(command.toByteBuffer(null).array());
			socket.getOutputStream().flush();
			PacketInputStream pis = new MonitorPacketInputStream();
			
			byte[] message = pis.readPacket(socket.getInputStream());
			MonitorCommandPacket response = new MonitorCommandPacket();
			response.init(message, null);
			if(response.funType == MonitorConstant.FUN_TYPE_OK){
				System.out.println("remote application= "+ appplicationName+":"+port+" response OK");
			}
			
			socket.close();
			return t