Amoeba源码分析一:启动过程分析

网络上相关的资料很少,我又恰好要做这个,索性就把它写出来,我也是在摸索中,理解的不正确的地方这里道个歉,欢迎指正。也算是为amoeba的推广做的一点微不足道的贡献吧!


下图是我的eclipse的Amoeba工程(怎么导入的请看上篇文章)的目录的一部分:


图中的红色标记的就是Amoeba的启动文件。这里需要说明的是,amoeba使用的批处理的方式启动的,批处理里面首先是找到classword,然后加载类,而加载的第一个类就是上述那个类了。

下面打开AmoebaProxyServer.java文件,我为重要的语句加上了注释,请详细查看。


public class AmoebaProxyServer {
	private static Logger log = Logger.getLogger(AmoebaProxyServer.class); 
	private static Logger repoterLog = Logger.getLogger("report");
	//定义两个Logger文件,这是Log4j的用法,不是重点
	/** Used to generate "state of server" reports. */
	protected static ArrayList<Reporter> reporters = new ArrayList<Reporter>();
	/** The time at which the server was started. */
	protected static long serverStartTime = System.currentTimeMillis();

	/** The last time at which {@link #generateReport} was run. */
	protected static long lastReportStamp = serverStartTime;

	public static void registerReporter(Reporter reporter) {
		reporters.add(reporter);
	}

	/**
	 * Generates a report for all system services registered as a
	 * {@link Reporter}.
	 */
	public static String generateReport() {
		return generateReport(System.currentTimeMillis(), false);
	}

	/**
	 * Generates and logs a "state of server" report.
	 */
	protected static String generateReport(long now, boolean reset) {
		long sinceLast = now - lastReportStamp;
		long uptime = now - serverStartTime;
		StringBuilder report = new StringBuilder(" State of server report:"+StringUtil.LINE_SEPARATOR);

		report.append("- Uptime: ").append(StringUtil.intervalToString(uptime)).append(StringUtil.LINE_SEPARATOR);
		report.append("- Report period: ").append(StringUtil.intervalToString(sinceLast)).append(StringUtil.LINE_SEPARATOR);

		// report on the state of memory
		Runtime rt = Runtime.getRuntime();
		long total = rt.totalMemory(), max = rt.maxMemory();
		long used = (total - rt.freeMemory());
		report.append("- Memory: ").append(used / 1024).append("k used, ");
		report.append(total / 1024).append("k total, ");
		report.append(max / 1024).append("k max").append(StringUtil.LINE_SEPARATOR);
		
		for (int ii = 0; ii < reporters.size(); ii++) {
			Reporter rptr = reporters.get(ii);
			try {
				rptr.appendReport(report, now, sinceLast, reset,repoterLog.getLevel());
			} catch (Throwable t) {
				log.error("Reporter choked [rptr=" + rptr + "].", t);
			}
		}

		// only reset the last report time if this is a periodic report
		if (reset) {
			lastReportStamp = now;
		}

		return report.toString();
	}

	protected static void logReport(String report) {
		repoterLog.info(report);
	}

	//上面都是与日志文件有关的操作,这些我们可以根据自己的需求进行修改
	/**
	 * @param args
	 * @throws IOException
	 * @throws Exception 
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 */
	//下面进入main开始开始执行
	public static void main(String[] args) throws Exception {
		String level = System.getProperty("benchmark.level", "warn");
		System.setProperty("benchmark.level", level);
		if(args.length>=1){
			ShutdownClient client = new ShutdownClient(MonitorConstant.APPLICATION_NAME);
			/**
			 * APPLICATION_NAME是一个常量,这个常量定义在MonitorConstant.java文件中,这个文件在Amoeba/src/java/com/meidusa/amoeba/monitoer中
			 * ShutdownClient是一个监视类,由它的run函数负责获取网络数据包并对其进行分析建立连接等。
			 * ShutdownClient的对象client在下面的第二个if中调用了run函数,这个run函数执行成功的话,则输出amoeba server is running with ...的信息
			 * 这样就是我们看到的amoeba启动时显示的原因了。
			 *
			 */
			MonitorCommandPacket packet = new MonitorCommandPacket();
			if("start".equalsIgnoreCase(args[0])){
				packet.funType = MonitorCommandPacket.FUN_TYPE_PING;
				if(client.run(packet)){					
					/**
					 * 根据上一个注释可以知道关键及时这个client的run函数了。
					 * 分析run函数之前,先关注它的参数packet,packet的类型是MonitorCommandPacket。
					 * 从MonitorCommandPacket.java可以知道这个类继承了AbstractPacket类。
					 * AbstractPacket类在src/amoeba/src/java/net/packet中。看它的源码知道,这个类是抽象类
					 * Packet的派生类。
					 * 进入client的run函数后,请转到run函数继续看分析
					 */
					System.out.println("amoeba server is running with port="+client.getPort());
					System.exit(-1);
				}
			}else{
				packet.funType = MonitorCommandPacket.FUN_TYPE_AMOEBA_SHUTDOWN;
				if(client.run(packet)){
					System.out.println("amoeba server shutting down with port="+client.getPort());
				}else{
					System.out.println("amoeba server not running with port="+client.getPort());
				}
				System.exit(0);
			}
		}else{
			System.out.println("amoeba start|stop");
			System.exit(0);
		}
		//执行完上面的if块后到这里继续执行。
		String log4jConf = System.getProperty("log4j.conf","${amoeba.home}/conf/log4j.xml");
		log4jConf = ConfigUtil.filter(log4jConf);
		File logconf = new File(log4jConf);
		if(logconf.exists() && logconf.isFile()){
			DOMConfigurator.configureAndWatch(logconf.getAbsolutePath(), System.getProperties());
		}
		
		final Logger logger = Logger.getLogger(AmoebaProxyServer.class);
		String config = System.getProperty("amoeba.conf","${amoeba.home}/conf/amoeba.xml");
		String contextClass = System.getProperty("amoeba.context.class",ProxyRuntimeContext.class.getName());
		
		if(contextClass != null){
			ProxyRuntimeContext context = (ProxyRuntimeContext)Class.forName(contextClass).newInstance();
			ProxyRuntimeContext.setInstance(context);
		}

		config = ConfigUtil.filter(config);
		File configFile = new File(config);
		
		if(config == null || !configFile.exists()){
			logger.error("could not find config file:"+configFile.getAbsolutePath());
			System.exit(-1);
		}else{
			ProxyRuntimeContext.getInstance().init(configFile.getAbsolutePath());
		}
		
		registerReporter(ProxyRuntimeContext.getInstance());
		for(ConnectionManager connMgr :ProxyRuntimeContext.getInstance().getConnectionManagerList().values()){
			registerReporter(connMgr);
		}
		
		Map<String,Object> context = new HashMap<String,Object>();
		context.putAll(ProxyRuntimeContext.getInstance().getConnectionManagerList());
		
		List<BeanObjectEntityConfig> serviceConfigList = ProxyRuntimeContext.getInstance().getConfig().getServiceConfigList();
		
		for(BeanObjectEntityConfig serverConfig : serviceConfigList){
			Service service = (Service)serverConfig.createBeanObject(false,context);
			
			service.init();
			service.start();
			PriorityShutdownHook.addShutdowner(service);
			registerReporter(service);
		}
		//一直到这里进入线程,每六十秒一次循环
		new Thread(){
			{
				this.setDaemon(true);
				this.setName("Amoeba Report Thread");
			}
			public void run(){
				while(true){
					try {
						Thread.sleep(60*1000);
					} catch (InterruptedException e) {
					}
					try{
					logReport(generateReport());
					}catch(Exception e){
						logger.error("report error",e);
					}
				}
			}
		}.start();
	}
}

上述代码从client.run(packet)函数开始就进入到了类ShutdownClient.java文件的run函数执行了。run函数的片断注释如下:

public boolean run(MonitorCommandPacket command) {
		//从AmoebaProxyServer类的main函数转到这里继续执行
		//可以看到正常启动Amoeba的情况下(因为没有连接建立)这个if都能成立的
		if(port <=0){
			socketInfoFile = new File(ConfigUtil.filter("${amoeba.home}"),appplicationName+".shutdown.port");
			if(!socketInfoFile.exists()){
				System.out.println("b");//所以这个输出是可以得到的,然后返回false,又回到main函数中去了
				return false;
			}
			//当有连接建立时,上面的if块就不执行,而是执行下面的块
			try {
				BufferedReader reader = new BufferedReader(new FileReader(socketInfoFile));
				String sport = reader.readLine();
				String tmp[] = StringUtil.split(sport, ":");
				if(tmp.length <=1){
					System.out.println("c");
					return false;
				}
				this.port = Integer.parseInt(tmp[1]);
				this.host = tmp[0];
				reader.close();
			}catch (Exception e) {
				e.printStackTrace();
				System.out.println("d");
				return false;
			}
		}
启动过程中,上面的run函数会返回false,回到main函数中去。根据main的代码知道下面代码:

if(client.run(packet)){					
					/**
					 * 根据上一个注释可以知道关键及时这个client的run函数了。
					 * 分析run函数之前,先关注它的参数packet,packet的类型是MonitorCommandPacket。
					 * 从MonitorCommandPacket.java可以知道这个类继承了AbstractPacket类。
					 * AbstractPacket类在src/amoeba/src/java/net/packet中。看它的源码知道,这个类是抽象类
					 * Packet的派生类。
					 * 进入client的run函数后,请转到run函数继续看分析
					 */
					System.out.println("amoeba server is running with port="+client.getPort());
					System.exit(-1);
				}
会跳出这个if,然后跳到main函数的下列代码处执行:

//执行完上面的if块后到这里继续执行。
		String log4jConf = System.getProperty("log4j.conf","${amoeba.home}/conf/log4j.xml");
		log4jConf = ConfigUtil.filter(log4jConf);
		File logconf = new File(log4jConf);
		if(logconf.exists() && logconf.isFile()){
			DOMConfigurator.configureAndWatch(logconf.getAbsolutePath(), System.getProperties());
		}
		
		final Logger logger = Logge
最后进入while循环,到此amoeba的启动算是完成了,然后就是一直的监听了。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值