当前位置:   article > 正文

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

amoeba 源码

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


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


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

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

  1. public class AmoebaProxyServer {
  2. private static Logger log = Logger.getLogger(AmoebaProxyServer.class);
  3. private static Logger repoterLog = Logger.getLogger("report");
  4. //定义两个Logger文件,这是Log4j的用法,不是重点
  5. /** Used to generate "state of server" reports. */
  6. protected static ArrayList<Reporter> reporters = new ArrayList<Reporter>();
  7. /** The time at which the server was started. */
  8. protected static long serverStartTime = System.currentTimeMillis();
  9. /** The last time at which {@link #generateReport} was run. */
  10. protected static long lastReportStamp = serverStartTime;
  11. public static void registerReporter(Reporter reporter) {
  12. reporters.add(reporter);
  13. }
  14. /**
  15. * Generates a report for all system services registered as a
  16. * {@link Reporter}.
  17. */
  18. public static String generateReport() {
  19. return generateReport(System.currentTimeMillis(), false);
  20. }
  21. /**
  22. * Generates and logs a "state of server" report.
  23. */
  24. protected static String generateReport(long now, boolean reset) {
  25. long sinceLast = now - lastReportStamp;
  26. long uptime = now - serverStartTime;
  27. StringBuilder report = new StringBuilder(" State of server report:"+StringUtil.LINE_SEPARATOR);
  28. report.append("- Uptime: ").append(StringUtil.intervalToString(uptime)).append(StringUtil.LINE_SEPARATOR);
  29. report.append("- Report period: ").append(StringUtil.intervalToString(sinceLast)).append(StringUtil.LINE_SEPARATOR);
  30. // report on the state of memory
  31. Runtime rt = Runtime.getRuntime();
  32. long total = rt.totalMemory(), max = rt.maxMemory();
  33. long used = (total - rt.freeMemory());
  34. report.append("- Memory: ").append(used / 1024).append("k used, ");
  35. report.append(total / 1024).append("k total, ");
  36. report.append(max / 1024).append("k max").append(StringUtil.LINE_SEPARATOR);
  37. for (int ii = 0; ii < reporters.size(); ii++) {
  38. Reporter rptr = reporters.get(ii);
  39. try {
  40. rptr.appendReport(report, now, sinceLast, reset,repoterLog.getLevel());
  41. } catch (Throwable t) {
  42. log.error("Reporter choked [rptr=" + rptr + "].", t);
  43. }
  44. }
  45. // only reset the last report time if this is a periodic report
  46. if (reset) {
  47. lastReportStamp = now;
  48. }
  49. return report.toString();
  50. }
  51. protected static void logReport(String report) {
  52. repoterLog.info(report);
  53. }
  54. //上面都是与日志文件有关的操作,这些我们可以根据自己的需求进行修改
  55. /**
  56. * @param args
  57. * @throws IOException
  58. * @throws Exception
  59. * @throws IllegalAccessException
  60. * @throws InstantiationException
  61. */
  62. //下面进入main开始开始执行
  63. public static void main(String[] args) throws Exception {
  64. String level = System.getProperty("benchmark.level", "warn");
  65. System.setProperty("benchmark.level", level);
  66. if(args.length>=1){
  67. ShutdownClient client = new ShutdownClient(MonitorConstant.APPLICATION_NAME);
  68. /**
  69. * APPLICATION_NAME是一个常量,这个常量定义在MonitorConstant.java文件中,这个文件在Amoeba/src/java/com/meidusa/amoeba/monitoer中
  70. * ShutdownClient是一个监视类,由它的run函数负责获取网络数据包并对其进行分析建立连接等。
  71. * ShutdownClient的对象client在下面的第二个if中调用了run函数,这个run函数执行成功的话,则输出amoeba server is running with ...的信息
  72. * 这样就是我们看到的amoeba启动时显示的原因了。
  73. *
  74. */
  75. MonitorCommandPacket packet = new MonitorCommandPacket();
  76. if("start".equalsIgnoreCase(args[0])){
  77. packet.funType = MonitorCommandPacket.FUN_TYPE_PING;
  78. if(client.run(packet)){
  79. /**
  80. * 根据上一个注释可以知道关键及时这个client的run函数了。
  81. * 分析run函数之前,先关注它的参数packet,packet的类型是MonitorCommandPacket。
  82. * 从MonitorCommandPacket.java可以知道这个类继承了AbstractPacket类。
  83. * AbstractPacket类在src/amoeba/src/java/net/packet中。看它的源码知道,这个类是抽象类
  84. * Packet的派生类。
  85. * 进入client的run函数后,请转到run函数继续看分析
  86. */
  87. System.out.println("amoeba server is running with port="+client.getPort());
  88. System.exit(-1);
  89. }
  90. }else{
  91. packet.funType = MonitorCommandPacket.FUN_TYPE_AMOEBA_SHUTDOWN;
  92. if(client.run(packet)){
  93. System.out.println("amoeba server shutting down with port="+client.getPort());
  94. }else{
  95. System.out.println("amoeba server not running with port="+client.getPort());
  96. }
  97. System.exit(0);
  98. }
  99. }else{
  100. System.out.println("amoeba start|stop");
  101. System.exit(0);
  102. }
  103. //执行完上面的if块后到这里继续执行。
  104. String log4jConf = System.getProperty("log4j.conf","${amoeba.home}/conf/log4j.xml");
  105. log4jConf = ConfigUtil.filter(log4jConf);
  106. File logconf = new File(log4jConf);
  107. if(logconf.exists() && logconf.isFile()){
  108. DOMConfigurator.configureAndWatch(logconf.getAbsolutePath(), System.getProperties());
  109. }
  110. final Logger logger = Logger.getLogger(AmoebaProxyServer.class);
  111. String config = System.getProperty("amoeba.conf","${amoeba.home}/conf/amoeba.xml");
  112. String contextClass = System.getProperty("amoeba.context.class",ProxyRuntimeContext.class.getName());
  113. if(contextClass != null){
  114. ProxyRuntimeContext context = (ProxyRuntimeContext)Class.forName(contextClass).newInstance();
  115. ProxyRuntimeContext.setInstance(context);
  116. }
  117. config = ConfigUtil.filter(config);
  118. File configFile = new File(config);
  119. if(config == null || !configFile.exists()){
  120. logger.error("could not find config file:"+configFile.getAbsolutePath());
  121. System.exit(-1);
  122. }else{
  123. ProxyRuntimeContext.getInstance().init(configFile.getAbsolutePath());
  124. }
  125. registerReporter(ProxyRuntimeContext.getInstance());
  126. for(ConnectionManager connMgr :ProxyRuntimeContext.getInstance().getConnectionManagerList().values()){
  127. registerReporter(connMgr);
  128. }
  129. Map<String,Object> context = new HashMap<String,Object>();
  130. context.putAll(ProxyRuntimeContext.getInstance().getConnectionManagerList());
  131. List<BeanObjectEntityConfig> serviceConfigList = ProxyRuntimeContext.getInstance().getConfig().getServiceConfigList();
  132. for(BeanObjectEntityConfig serverConfig : serviceConfigList){
  133. Service service = (Service)serverConfig.createBeanObject(false,context);
  134. service.init();
  135. service.start();
  136. PriorityShutdownHook.addShutdowner(service);
  137. registerReporter(service);
  138. }
  139. //一直到这里进入线程,每六十秒一次循环
  140. new Thread(){
  141. {
  142. this.setDaemon(true);
  143. this.setName("Amoeba Report Thread");
  144. }
  145. public void run(){
  146. while(true){
  147. try {
  148. Thread.sleep(60*1000);
  149. } catch (InterruptedException e) {
  150. }
  151. try{
  152. logReport(generateReport());
  153. }catch(Exception e){
  154. logger.error("report error",e);
  155. }
  156. }
  157. }
  158. }.start();
  159. }
  160. }

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

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

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

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


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/191988
推荐阅读
相关标签
  

闽ICP备14008679号