中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何用Play源代碼分析Server啟動過程

發布時間:2021-10-29 10:33:27 來源:億速云 閱讀:136 作者:柒染 欄目:編程語言

這期內容當中小編將會給大家帶來有關如何用Play源代碼分析Server啟動過程,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

Play是個Rails風格的Java Web框架。

如何調試請看此處。以下進入正題^_^

Server啟動過程主要涉及三個地方:

  1. play.Play類:代表Play本身業務模型。

  2. play.server.Server類:負責服務器啟動。

  3. play.classloading包:負責.java文件讀取、編譯和加載。

總體流程:

如何用Play源代碼分析Server啟動過程

Server.main為入口方法:

public static void main(String[] args) throws Exception {          …          Play.init(root, System.getProperty("play.id", ""));          if (System.getProperty("precompile") == null) {              new Server();          } else {              Logger.info("Done.");          }      }

做兩件事:

  1. Play.init

  2. 然后創建Server對象。

Play.init

public static void init(File root, String id) {   &hellip;   readConfiguration();            Play.classes = new ApplicationClasses();           &hellip;           // Build basic java source path          VirtualFile appRoot = VirtualFile.open(applicationPath);          roots.add(appRoot);          javaPath = new ArrayList<VirtualFile>(2);          javaPath.add(appRoot.child("app"));          javaPath.add(appRoot.child("conf"));           // Build basic templates path          templatesPath = new ArrayList<VirtualFile>(2);          templatesPath.add(appRoot.child("app/views"));           // Main route file          routes = appRoot.child("conf/routes");           &hellip;           // Load modules          loadModules();           &hellip;           // Enable a first classloader          classloader = new ApplicationClassloader();           // Plugins          loadPlugins();           // Done !          if (mode == Mode.PROD ||preCompile() ) {                  start();              }           &hellip;      }

主要做:

  1. 加載配置

  2. new ApplicationClasses();加載app、views和conf路徑到VirtualFile中,VirtualFile是Play內部的統一文件訪問接口,方便后續讀取文件

  3. 加載route

  4. 加載Module,Play的應用擴展組件。

  5. 加載Plugin,Play框架自身的擴展組件。

  6. 工作在產品模式則啟動Play.

關鍵步驟為new ApplicationClasses(),執行computeCodeHashe(),后者觸發目錄掃描,搜索.java文件。相關過程簡化代碼如下:

public ApplicationClassloader() {          super(ApplicationClassloader.class.getClassLoader());          // Clean the existing classes          for (ApplicationClass applicationClass : Play.classes.all()) {              applicationClass.uncompile();          }          pathHash = computePathHash();         &hellip;      }
int computePathHash() {          StringBuffer buf = new StringBuffer();          for (VirtualFile virtualFile : Play.javaPath) {              scan(buf, virtualFile);          }          return buf.toString().hashCode();      }
void scan(StringBuffer buf, VirtualFile current) {          if (!current.isDirectory()) {              if (current.getName().endsWith(".java")) {                  Matcher matcher = Pattern.compile("\\s+class\\s([a-zA-Z0-9_]+)\\s+").matcher(current.contentAsString());                  buf.append(current.getName());                  buf.append("(");                  while (matcher.find()) {                      buf.append(matcher.group(1));                      buf.append(",");                  }                  buf.append(")");              }          } else if (!current.getName().startsWith(".")) {              for (VirtualFile virtualFile : current.list()) {                  scan(buf, virtualFile);              }          }      }

Start流程

如何用Play源代碼分析Server啟動過程

簡化代碼如下:

public static synchronized void start() {          try {                          ...              // Reload configuration              readConfiguration();                           ...                            // Try to load all classes              Play.classloader.getAllClasses();               // Routes              Router.detectChanges(ctxPath);               // Cache              Cache.init();               // Plugins              for (PlayPlugin plugin : plugins) {                  try {                      plugin.onApplicationStart();                  } catch(Exception e) {                      if(Play.mode.isProd()) {                          Logger.error(e, "Can't start in PROD mode with errors");                      }                      if(e instanceof RuntimeException) {                          throw (RuntimeException)e;                      }                      throw new UnexpectedException(e);                  }              }               ...               // Plugins              for (PlayPlugin plugin : plugins) {                  plugin.afterApplicationStart();              }           } catch (PlayException e) {              started = false;              throw e;          } catch (Exception e) {              started = false;              throw new UnexpectedException(e);          }      }

關鍵步驟為執行Play.classloader.getAllClasses()加載app目錄中的類型。簡化代碼如下:

public List<Class> getAllClasses() {          if (allClasses == null) {              allClasses = new ArrayList<Class>();               if (Play.usePrecompiled) {                  ...              } else {                  List<ApplicationClass> all = new ArrayList<ApplicationClass>();                   // Let's plugins play                  for (PlayPlugin plugin : Play.plugins) {                      plugin.compileAll(all);                  }                   for (VirtualFile virtualFile : Play.javaPath) {                      all.addAll(getAllClasses(virtualFile));                  }                  List<String> classNames = new ArrayList<String>();                  for (int i = 0; i < all.size(); i++) {                      if (all.get(i) != null && !all.get(i).compiled) {                          classNames.add(all.get(i).name);                      }                  }                   Play.classes.compiler.compile(classNames.toArray(new String[classNames.size()]));                   for (ApplicationClass applicationClass : Play.classes.all()) {                      Class clazz = loadApplicationClass(applicationClass.name);                      if (clazz != null) {                          allClasses.add(clazz);                      }                  }                                  ...              }          }          return allClasses;      }

主要步驟:

  1. plugin.compileAll,給所有plugin一次機會進行自定義編譯。

  2. Play.classes.compiler.compile(classNames.toArray(new String[classNames.size()]));編譯所有.java文件。編譯后的.class存儲在ApplicationClass中。內部使用了eclipse的JDT編譯器。

  3. loadApplicationClass,取出ApplicationClass中的.class加入List<Class>中返回。

到此完成.java的加載。相關對象關系如下圖:

如何用Play源代碼分析Server啟動過程

接著new Server()啟動HTTP服務,監聽請求

簡化代碼如下:

public Server() {               ...          if (httpPort == -1 && httpsPort == -1) {              httpPort = 9000;          }          ...          InetAddress address = null;          try {              if (p.getProperty("http.address") != null) {                  address = InetAddress.getByName(p.getProperty("http.address"));              } else if (System.getProperties().containsKey("http.address")) {                  address = InetAddress.getByName(System.getProperty("http.address"));              }           } catch (Exception e) {              Logger.error(e, "Could not understand http.address");              System.exit(-1);          }                    ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(                  Executors.newCachedThreadPool(), Executors.newCachedThreadPool())          );          try {              if (httpPort != -1) {                  bootstrap.setPipelineFactory(new HttpServerPipelineFactory());                  bootstrap.bind(new InetSocketAddress(address, httpPort));                  bootstrap.setOption("child.tcpNoDelay", true);                   if (Play.mode == Mode.DEV) {                      if (address == null) {                          Logger.info("Listening for HTTP on port %s (Waiting a first request to start) ...", httpPort);                      } else {                          Logger.info("Listening for HTTP at %2$s:%1$s (Waiting a first request to start) ...", httpPort, address);                      }                  } else {                      if (address == null) {                          Logger.info("Listening for HTTP on port %s ...", httpPort);                      } else {                          Logger.info("Listening for HTTP at %2$s:%1$s  ...", httpPort, address);                      }                  }               }           } catch (ChannelException e) {              Logger.error("Could not bind on port " + httpPort, e);              System.exit(-1);          }          ...      }

主要步驟:

  1. 設置端口,地址

  2. new ServerBootstrap,創建jboss netty服務器。Play1.1.1使用了netty作為底層通訊服務器。

  3. new HttpServerPipelineFactory(),設置netty所需的請求處理管道工廠。它負責當請求到達時提供處理者。

  4. bootstrap.bind(new InetSocketAddress(address, httpPort),綁定地址,端口。

上述就是小編為大家分享的如何用Play源代碼分析Server啟動過程了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

克什克腾旗| 商南县| 大兴区| 伊川县| 册亨县| 永德县| 武鸣县| 巴彦淖尔市| 乐东| 天峨县| 郓城县| 马鞍山市| 泰州市| 巴林右旗| 巴彦淖尔市| 浦城县| 普兰店市| 蕲春县| 兴和县| 曲松县| 合肥市| 贵州省| 台东市| 崇明县| 诸暨市| 长武县| 宜都市| 喀喇沁旗| 棋牌| 福海县| 湘阴县| 奉化市| 高阳县| 鹤庆县| 独山县| 石嘴山市| 德钦县| 荣昌县| 安吉县| 英吉沙县| 萨嘎县|