自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Play源代碼分析:Server啟動(dòng)過程

開發(fā) 后端
Play!是一個(gè)full-stack(全棧的)Java Web應(yīng)用框架,包括一個(gè)簡單的無狀態(tài)MVC模型,具有Hibernate的對象持續(xù),一個(gè)基于Groovy的模板引擎,以及建立一個(gè)現(xiàn)代Web應(yīng)用所需的所有東西。

Play是個(gè)Rails風(fēng)格的Java Web框架,需要了解背景請看:

  1. Play Framework介紹1--主要概念
  2. Play Framework介紹2—Helloworld

如何調(diào)試請看此處。以下進(jìn)入正題^_^

Server啟動(dòng)過程主要涉及三個(gè)地方:

  1. play.Play類:代表Play本身業(yè)務(wù)模型。
  2. play.server.Server類:負(fù)責(zé)服務(wù)器啟動(dòng)。
  3. play.classloading包:負(fù)責(zé).java文件讀取、編譯和加載。

總體流程:

Play代碼分析-Server.Main

Server.main為入口方法:

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

做兩件事:

  1. Play.init
  2. 然后創(chuàng)建Server對象。

Play.init

  1. public static void init(File root, String id) {  
  2.  
  3. …  
  4.  
  5. readConfiguration();  
  6.  
  7.          Play.classes = new ApplicationClasses();  
  8.  
  9.         …  
  10.  
  11.         // Build basic java source path  
  12.         VirtualFile appRoot = VirtualFile.open(applicationPath);  
  13.         roots.add(appRoot);  
  14.         javaPath = new ArrayList<VirtualFile>(2);  
  15.         javaPath.add(appRoot.child("app"));  
  16.         javaPath.add(appRoot.child("conf"));  
  17.  
  18.         // Build basic templates path  
  19.         templatesPath = new ArrayList<VirtualFile>(2);  
  20.         templatesPath.add(appRoot.child("app/views"));  
  21.  
  22.         // Main route file  
  23.         routes = appRoot.child("conf/routes");  
  24.  
  25.         …  
  26.  
  27.         // Load modules  
  28.         loadModules();  
  29.  
  30.         …  
  31.  
  32.         // Enable a first classloader  
  33.         classloader = new ApplicationClassloader();  
  34.  
  35.         // Plugins  
  36.         loadPlugins();  
  37.  
  38.         // Done !  
  39.         if (mode == Mode.PROD ||preCompile() ) {  
  40.                 start();  
  41.             }  
  42.  
  43.         …  
  44.     } 

主要做:

  1. 加載配置
  2. new ApplicationClasses();加載app、views和conf路徑到VirtualFile中,VirtualFile是Play內(nèi)部的統(tǒng)一文件訪問接口,方便后續(xù)讀取文件
  3. 加載route
  4. 加載Module,Play的應(yīng)用擴(kuò)展組件。
  5. 加載Plugin,Play框架自身的擴(kuò)展組件。
  6. 工作在產(chǎn)品模式則啟動(dòng)Play.

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

  1. public ApplicationClassloader() {  
  2.         super(ApplicationClassloader.class.getClassLoader());  
  3.         // Clean the existing classes  
  4.         for (ApplicationClass applicationClass : Play.classes.all()) {  
  5.             applicationClass.uncompile();  
  6.         }  
  7.         pathHash = computePathHash();  
  8.        …  
  9.     } 
  1. int computePathHash() {  
  2.         StringBuffer buf = new StringBuffer();  
  3.         for (VirtualFile virtualFile : Play.javaPath) {  
  4.             scan(buf, virtualFile);  
  5.         }  
  6.         return buf.toString().hashCode();  
  7.     } 
  1. void scan(StringBuffer buf, VirtualFile current) {  
  2.         if (!current.isDirectory()) {  
  3.             if (current.getName().endsWith(".java")) {  
  4.                 Matcher matcher = Pattern.compile("\\s+class\\s([a-zA-Z0-9_]+)\\s+").matcher(current.contentAsString());  
  5.                 buf.append(current.getName());  
  6.                 buf.append("(");  
  7.                 while (matcher.find()) {  
  8.                     buf.append(matcher.group(1));  
  9.                     buf.append(",");  
  10.                 }  
  11.                 buf.append(")");  
  12.             }  
  13.         } else if (!current.getName().startsWith(".")) {  
  14.             for (VirtualFile virtualFile : current.list()) {  
  15.                 scan(buf, virtualFile);  
  16.             }  
  17.         }  
  18.     } 
Start流程

Play.Start過程

簡化代碼如下:

  1. public static synchronized void start() {  
  2.         try {  
  3.                         ...  
  4.             // Reload configuration  
  5.             readConfiguration();  
  6.  
  7.                         ...  
  8.               
  9.             // Try to load all classes  
  10.             Play.classloader.getAllClasses();  
  11.  
  12.             // Routes  
  13.             Router.detectChanges(ctxPath);  
  14.  
  15.             // Cache  
  16.             Cache.init();  
  17.  
  18.             // Plugins  
  19.             for (PlayPlugin plugin : plugins) {  
  20.                 try {  
  21.                     plugin.onApplicationStart();  
  22.                 } catch(Exception e) {  
  23.                     if(Play.mode.isProd()) {  
  24.                         Logger.error(e, "Can't start in PROD mode with errors");  
  25.                     }  
  26.                     if(e instanceof RuntimeException) {  
  27.                         throw (RuntimeException)e;  
  28.                     }  
  29.                     throw new UnexpectedException(e);  
  30.                 }  
  31.             }  
  32.  
  33.             ...  
  34.  
  35.             // Plugins  
  36.             for (PlayPlugin plugin : plugins) {  
  37.                 plugin.afterApplicationStart();  
  38.             }  
  39.  
  40.         } catch (PlayException e) {  
  41.             started = false;  
  42.             throw e;  
  43.         } catch (Exception e) {  
  44.             started = false;  
  45.             throw new UnexpectedException(e);  
  46.         }  
  47.     } 

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

  1. public List<Class> getAllClasses() {  
  2.         if (allClasses == null) {  
  3.             allClasses = new ArrayList<Class>();  
  4.  
  5.             if (Play.usePrecompiled) {  
  6.                 ...  
  7.             } else {  
  8.                 List<ApplicationClass> all = new ArrayList<ApplicationClass>();  
  9.  
  10.                 // Let's plugins play  
  11.                 for (PlayPlugin plugin : Play.plugins) {  
  12.                     plugin.compileAll(all);  
  13.                 }  
  14.  
  15.                 for (VirtualFile virtualFile : Play.javaPath) {  
  16.                     all.addAll(getAllClasses(virtualFile));  
  17.                 }  
  18.                 List<String> classNames = new ArrayList<String>();  
  19.                 for (int i = 0; i < all.size(); i++) {  
  20.                     if (all.get(i) != null && !all.get(i).compiled) {  
  21.                         classNames.add(all.get(i).name);  
  22.                     }  
  23.                 }  
  24.  
  25.                 Play.classes.compiler.compile(classNames.toArray(new String[classNames.size()]));  
  26.  
  27.                 for (ApplicationClass applicationClass : Play.classes.all()) {  
  28.                     Class clazz = loadApplicationClass(applicationClass.name);  
  29.                     if (clazz != null) {  
  30.                         allClasses.add(clazz);  
  31.                     }  
  32.                 }  
  33.                                 ...  
  34.             }  
  35.         }  
  36.         return allClasses;  
  37.     } 

主要步驟:

  1. plugin.compileAll,給所有plugin一次機(jī)會(huì)進(jìn)行自定義編譯。
  2. Play.classes.compiler.compile(classNames.toArray(new String[classNames.size()]));編譯所有.java文件。編譯后的.class存儲(chǔ)在ApplicationClass中。內(nèi)部使用了eclipse的JDT編譯器。
  3. loadApplicationClass,取出ApplicationClass中的.class加入List<Class>中返回。

到此完成.java的加載。相關(guān)對象關(guān)系如下圖:

Play代碼分析

接著new Server()啟動(dòng)HTTP服務(wù),監(jiān)聽請求

簡化代碼如下:

  1. public Server() {  
  2.              ...  
  3.         if (httpPort == -1 && httpsPort == -1) {  
  4.             httpPort = 9000;  
  5.         }  
  6.         ...  
  7.         InetAddress address = null;  
  8.         try {  
  9.             if (p.getProperty("http.address") != null) {  
  10.                 address = InetAddress.getByName(p.getProperty("http.address"));  
  11.             } else if (System.getProperties().containsKey("http.address")) {  
  12.                 address = InetAddress.getByName(System.getProperty("http.address"));  
  13.             }  
  14.  
  15.         } catch (Exception e) {  
  16.             Logger.error(e, "Could not understand http.address");  
  17.             System.exit(-1);  
  18.         }  
  19.           
  20.         ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(  
  21.                 Executors.newCachedThreadPool(), Executors.newCachedThreadPool())  
  22.         );  
  23.         try {  
  24.             if (httpPort != -1) {  
  25.                 bootstrap.setPipelineFactory(new HttpServerPipelineFactory());  
  26.                 bootstrap.bind(new InetSocketAddress(address, httpPort));  
  27.                 bootstrap.setOption("child.tcpNoDelay"true);  
  28.  
  29.                 if (Play.mode == Mode.DEV) {  
  30.                     if (address == null) {  
  31.                         Logger.info("Listening for HTTP on port %s (Waiting a first request to start) ...", httpPort);  
  32.                     } else {  
  33.                         Logger.info("Listening for HTTP at %2$s:%1$s (Waiting a first request to start) ...", httpPort, address);  
  34.                     }  
  35.                 } else {  
  36.                     if (address == null) {  
  37.                         Logger.info("Listening for HTTP on port %s ...", httpPort);  
  38.                     } else {  
  39.                         Logger.info("Listening for HTTP at %2$s:%1$s  ...", httpPort, address);  
  40.                     }  
  41.                 }  
  42.  
  43.             }  
  44.  
  45.         } catch (ChannelException e) {  
  46.             Logger.error("Could not bind on port " + httpPort, e);  
  47.             System.exit(-1);  
  48.         }  
  49.         ...  
  50.     } 

主要步驟:

  1. 設(shè)置端口,地址
  2. new ServerBootstrap,創(chuàng)建jboss netty服務(wù)器。Play1.1.1使用了netty作為底層通訊服務(wù)器。
  3. new HttpServerPipelineFactory(),設(shè)置netty所需的請求處理管道工廠。它負(fù)責(zé)當(dāng)請求到達(dá)時(shí)提供處理者。
  4. bootstrap.bind(new InetSocketAddress(address, httpPort),綁定地址,端口。

到此萬事具備,只等東風(fēng)了…

原文鏈接:http://www.cnblogs.com/Chaos/archive/2011/04/17/2018500.html

【編輯推薦】

  1. Play Framework介紹:使用Eclipse開發(fā)和調(diào)試
  2. Play Framework介紹:Hello World
  3. Play Framework介紹:主要概念
  4. Java堆內(nèi)存的10個(gè)要點(diǎn)
  5. “Java已死”簡史
責(zé)任編輯:林師授 來源: Chaos的博客
相關(guān)推薦

2014-06-20 11:05:56

Android應(yīng)用程序進(jìn)程啟動(dòng)

2014-06-20 11:09:35

Android應(yīng)用程序進(jìn)程啟動(dòng)

2014-06-19 14:25:04

Android應(yīng)用程序進(jìn)程啟動(dòng)

2014-06-20 11:24:34

Android應(yīng)用程序進(jìn)程啟動(dòng)

2014-06-20 11:20:37

Android應(yīng)用程序進(jìn)程啟動(dòng)

2014-06-19 14:30:28

Android應(yīng)用程序進(jìn)程啟動(dòng)

2014-06-19 14:59:40

Android應(yīng)用程序進(jìn)程啟動(dòng)

2014-06-19 14:54:11

Android應(yīng)用程序進(jìn)程啟動(dòng)

2011-06-28 13:27:13

ARM Linux

2012-08-16 09:07:57

Erlang

2018-03-13 13:00:03

Linux運(yùn)維啟動(dòng)分析

2024-09-11 09:25:03

Tomcat組件PREP

2011-07-28 10:34:38

Cocoa 程序 啟動(dòng)

2014-06-23 10:31:09

Android啟動(dòng)過程

2011-09-05 17:35:18

MTK啟動(dòng)過程RTOS

2009-12-03 10:00:46

Linux系統(tǒng)啟動(dòng)

2010-09-17 13:32:22

JVM.dll

2010-05-06 14:05:15

Unix系統(tǒng)

2021-07-02 06:34:53

Go語言sysmon

2009-07-08 11:25:36

jvm.dll
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)