国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

Play framework源碼解析 Part1:Play framework 介紹、項(xiàng)目構(gòu)成及啟動(dòng)

Riddler / 1219人閱讀

摘要:注本系列文章所用版本為介紹是個(gè)輕量級(jí)的框架,致力于讓程序員實(shí)現(xiàn)快速高效開(kāi)發(fā),它具有以下幾個(gè)方面的優(yōu)勢(shì)熱加載。在調(diào)試模式下,所有修改會(huì)及時(shí)生效。拋棄配置文件。約定大于配置。

</>復(fù)制代碼

  1. 注:本系列文章所用play版本為1.2.6
介紹

Play framework是個(gè)輕量級(jí)的RESTful框架,致力于讓java程序員實(shí)現(xiàn)快速高效開(kāi)發(fā),它具有以下幾個(gè)方面的優(yōu)勢(shì):

熱加載。在調(diào)試模式下,所有修改會(huì)及時(shí)生效。

拋棄xml配置文件。約定大于配置。

支持異步編程

無(wú)狀態(tài)mvc框架,拓展性良好

簡(jiǎn)單的路由設(shè)置

這里附上Play framework的文檔地址,官方有更為詳盡的功能敘述。Play framework文檔

項(xiàng)目構(gòu)成

play framework的初始化非常簡(jiǎn)單,只要下載了play的軟件包后,在命令行中運(yùn)行play new xxx即可初始化一個(gè)項(xiàng)目。
自動(dòng)生成的項(xiàng)目結(jié)構(gòu)如下:

運(yùn)行play程序也非常簡(jiǎn)單,在項(xiàng)目目錄下使用play run即可運(yùn)行。

啟動(dòng)腳本解析 play framework軟件包目錄

為了更好的了解play framework的運(yùn)作原理,我們來(lái)從play framework的啟動(dòng)腳本開(kāi)始分析,分析啟動(dòng)腳本有助于我們了解play framework的運(yùn)行過(guò)程。
play framework1.2.6軟件包解壓后的文件如下:

play的啟動(dòng)腳本是使用python編寫(xiě)的,腳本的入口為play軟件包根目錄下的play文件,下面我們將從play這個(gè)腳本的主入口開(kāi)始分析。

play腳本解析

play腳本在開(kāi)頭引入了3個(gè)類(lèi),分別為play.cmdloader,play.application,play.utils,從添加的系統(tǒng)參數(shù)中可以看出play啟動(dòng)腳本的存放路徑為 framework/pym
cmdloader.py的主要作用為加載framework/pym/commands下的各個(gè)腳本文件,用于之后對(duì)命令參數(shù)的解釋運(yùn)行
application.py的主要作用為解析項(xiàng)目路徑下conf/中的配置文件、加載模塊、拼接最后運(yùn)行的java命令

</>復(fù)制代碼

  1. sys.path.append(os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), "framework", "pym"))
  2. from play.cmdloader import CommandLoader
  3. from play.application import PlayApplication
  4. from play.utils import *

在腳本的開(kāi)頭,有這么一段代碼,意味著只要在play主程序根目錄下創(chuàng)建一個(gè)名為id的文件,即可設(shè)置默認(rèn)的框架id

</>復(fù)制代碼

  1. play_env["id_file"] = os.path.join(play_env["basedir"], "id")
  2. if os.path.exists(play_env["id_file"]):
  3. play_env["id"] = open(play_env["id_file"]).readline().strip()
  4. else:
  5. play_env["id"] = ""

命令參數(shù)的分隔由以下代碼完成,例如使用了play run --%test,那么參數(shù)列表就是["xxxxplay","run","--%test"],這段代碼也說(shuō)明了,play的命令格式為 play cmd [app_path] [--options]

</>復(fù)制代碼

  1. application_path = None
  2. remaining_args = []
  3. if len(sys.argv) == 1:
  4. application_path = os.getcwd()
  5. if len(sys.argv) == 2:
  6. application_path = os.getcwd()
  7. remaining_args = sys.argv[2:]
  8. if len(sys.argv) > 2:
  9. if sys.argv[2].startswith("-"):
  10. application_path = os.getcwd()
  11. remaining_args = sys.argv[2:]
  12. else:
  13. application_path = os.path.normpath(os.path.abspath(sys.argv[2]))
  14. remaining_args = sys.argv[3:]

在play參數(shù)中,有一個(gè)ignoreMissing,這個(gè)參數(shù)的全稱(chēng)其實(shí)是ignoreMissingModules,作用就是在當(dāng)配置文件中配置有模塊但是在play目錄下并沒(méi)有找到時(shí)是否忽略,如需忽略那么在啟動(dòng)時(shí)需要加入--force

</>復(fù)制代碼

  1. ignoreMissing = False
  2. if remaining_args.count("--force") == 1:
  3. remaining_args.remove("--force")
  4. ignoreMissing = True

腳本通過(guò)play_app = PlayApplication(application_path, play_env, ignoreMissing)cmdloader = CommandLoader(play_env["basedir"])來(lái)進(jìn)行PlayApplication類(lèi)和CommandLoader類(lèi)的初始化。
在PlayApplication類(lèi)的初始化過(guò)程中,它創(chuàng)建了PlayConfParser類(lèi)用來(lái)解析配置文件,這也就是說(shuō)play的配置文件解析是在腳本啟動(dòng)階段進(jìn)行的,這也是為什么修改配置文件無(wú)法實(shí)時(shí)生效需要重啟的原因
在PlayConfParser中有一個(gè)常量DEFAULTS儲(chǔ)存了默認(rèn)的http端口和jpda調(diào)試端口,分別為9000和8000,需要添加默認(rèn)值可以修改DEFAULTS,DEFAULTS內(nèi)的值只有當(dāng)配置文件中找不到時(shí)才會(huì)生效。

</>復(fù)制代碼

  1. DEFAULTS = {
  2. "http.port": "9000",
  3. "jpda.port": "8000"
  4. }

值得一提的是,配置文件中的http.port的優(yōu)先級(jí)是小于命令參數(shù)中的http.port的

</>復(fù)制代碼

  1. #env為命令參數(shù)
  2. if env.has_key("http.port"):
  3. self.entries["http.port"] = env["http.port"]

CommandLoader類(lèi)的功能很簡(jiǎn)單,就是遍歷framework/pym/commands下的.py文件,依次加載然后讀取他的全局變量COMMANDS和MODULE儲(chǔ)存用于之后的命令處理和模塊加載。

回到play腳本中,在PlayApplication類(lèi)和CommandLoader類(lèi)初始化完成之后,play進(jìn)行"--deps"參數(shù)的檢查,如果存在--deps,則調(diào)用play.deps.DependenciesManager類(lèi)來(lái)進(jìn)行依賴的檢查、更新。DependenciesManager的解析將放到后話詳解。

</>復(fù)制代碼

  1. if remaining_args.count("--deps") == 1:
  2. cmdloader.commands["dependencies"].execute(command="dependencies", app=play_app, args=["--sync"], env=play_env, cmdloader=cmdloader)
  3. remaining_args.remove("--deps")

接下來(lái),play便正式進(jìn)行啟動(dòng)過(guò)程,play按照以下的順序進(jìn)行加載:

加載配置文件中記錄的模塊的命令信息

加載參數(shù)中指定的模塊的命令信息

運(yùn)行各模塊中的before函數(shù)

執(zhí)行play_command,play_command即為run,test,war等play需要的執(zhí)行的命令

運(yùn)行各模塊中的after函數(shù)

結(jié)束腳本

</>復(fù)制代碼

  1. if play_command in cmdloader.commands:
  2. for name in cmdloader.modules:
  3. module = cmdloader.modules[name]
  4. if "before" in dir(module):
  5. module.before(command=play_command, app=play_app, args=remaining_args, env=play_env)
  6. status = cmdloader.commands[play_command].execute(command=play_command, app=play_app, args=remaining_args, env=play_env, cmdloader=cmdloader)
  7. for name in cmdloader.modules:
  8. module = cmdloader.modules[name]
  9. if "after" in dir(module):
  10. module.after(command=play_command, app=play_app, args=remaining_args, env=play_env)
  11. sys.exit(status)

下面,我們來(lái)看看play常用命令的運(yùn)行過(guò)程...

Play常用運(yùn)行命令解析

在本節(jié)的一開(kāi)始,我決定先把play所有的可用命令先列舉一下,以便讀者可以選擇性閱讀。

命令名稱(chēng) 命令所在文件 作用
antify ant.py 初始化ant構(gòu)建工具的build.xml文件
run base.py 運(yùn)行程序
new base.py 新建play應(yīng)用
clean base.py 刪除臨時(shí)文件,即清空tmp文件夾
test base.py 運(yùn)行測(cè)試程序
autotest、auto-test base.py 自動(dòng)運(yùn)行所有測(cè)試項(xiàng)目
id base.py 設(shè)置項(xiàng)目id
new,run base.py 新建play應(yīng)用并啟動(dòng)
clean,run base.py 刪除臨時(shí)文件并運(yùn)行
modules base.py 顯示項(xiàng)目用到的模塊,注:這里顯示的模塊只是在項(xiàng)目配置文件中引用的模塊,命令參數(shù)中添加的模塊不會(huì)顯示
check check.py 檢查play更新
classpath、cp classpath.py 顯示應(yīng)用的classpath
start daemon.py 在后臺(tái)運(yùn)行play程序
stop daemon.py 停止正在運(yùn)行的程序
restart daemon.py 重啟正在運(yùn)行的程序
pid daemon.py 顯示運(yùn)行中的程序的pid
out daemon.py 顯示輸出
dependencies、deps deps.py 運(yùn)行DependenciesManager更新依賴
eclipsify、ec eclipse.py 創(chuàng)建eclipse配置文件
evolutions evolutions.py 運(yùn)行play.db.Evolutions進(jìn)行數(shù)據(jù)庫(kù)演變檢查
help help.py 輸出所有play的可用命令
idealize、idea intellij.py 生成idea配置文件
javadoc javadoc.py 生成javadoc
new-module、nm modulesrepo.py 創(chuàng)建新模塊
list-modules、lm modulesrepo.py 顯示play社區(qū)中的模塊
build-module、bm modulesrepo.py 打包模塊
add modulesrepo.py 將模塊添加至項(xiàng)目
install modulesrepo.py 安裝模塊
netbeansify netbeans.py 生成netbeans配置文件
precompile precompile.py 預(yù)編譯
secret secret.py 生成secret key
status status.py 顯示運(yùn)行中項(xiàng)目的狀態(tài)
version version.py 顯示play framework的版本號(hào)
war war.py 將項(xiàng)目打包為war文件
run與start

run應(yīng)該是我們平時(shí)用的最多的命令了,run命令的作用其實(shí)很簡(jiǎn)單,就是根據(jù)命令參數(shù)拼接java參數(shù),然后調(diào)用java來(lái)運(yùn)行play.server.Server,run函數(shù)的代碼如下:

</>復(fù)制代碼

  1. def run(app, args):
  2. #app即為play腳本中創(chuàng)建的PlayApplication類(lèi)
  3. global process
  4. #這里檢查是否存在conf/routes和conf/application.conf
  5. app.check()
  6. print "~ Ctrl+C to stop"
  7. print "~ "
  8. java_cmd = app.java_cmd(args)
  9. try:
  10. process = subprocess.Popen (java_cmd, env=os.environ)
  11. signal.signal(signal.SIGTERM, handle_sigterm)
  12. return_code = process.wait()
  13. signal.signal(signal.SIGINT, handle_sigint)
  14. if 0 != return_code:
  15. sys.exit(return_code)
  16. except OSError:
  17. print "Could not execute the java executable, please make sure the JAVA_HOME environment variable is set properly (the java executable should reside at JAVA_HOME/bin/java). "
  18. sys.exit(-1)
  19. print

app.java_cmd(args)的實(shí)現(xiàn)代碼如下:

</>復(fù)制代碼

  1. def java_cmd(self, java_args, cp_args=None, className="play.server.Server", args = None):
  2. if args is None:
  3. args = [""]
  4. memory_in_args=False
  5. #檢查java參數(shù)中是否有jvm內(nèi)存設(shè)置
  6. for arg in java_args:
  7. if arg.startswith("-Xm"):
  8. memory_in_args=True
  9. #如果參數(shù)中無(wú)jvm內(nèi)存設(shè)置,那么在配置文件中找是否有jvm內(nèi)存設(shè)置,若還是沒(méi)有則在環(huán)境變量中找是否有JAVA_OPTS
  10. #這里其實(shí)有個(gè)問(wèn)題,這里假定的是JAVA_OPTS變量里只存了jvm內(nèi)存設(shè)置,如果JAVA_OPTS還存了其他選項(xiàng),那對(duì)運(yùn)行可能有影響
  11. if not memory_in_args:
  12. memory = self.readConf("jvm.memory")
  13. if memory:
  14. java_args = java_args + memory.split(" ")
  15. elif "JAVA_OPTS" in os.environ:
  16. java_args = java_args + os.environ["JAVA_OPTS"].split(" ")
  17. #獲取程序的classpath
  18. if cp_args is None:
  19. cp_args = self.cp_args()
  20. #讀取配置文件中的jpda端口
  21. self.jpda_port = self.readConf("jpda.port")
  22. #讀取配置文件中的運(yùn)行模式
  23. application_mode = self.readConf("application.mode").lower()
  24. #如果模式是prod,則用server模式編譯
  25. if application_mode == "prod":
  26. java_args.append("-server")
  27. # JDK 7 compat
  28. # 使用新class校驗(yàn)器 (不知道作用)
  29. java_args.append("-XX:-UseSplitVerifier")
  30. #查找配置文件中是否有java安全配置,如果有則加入java參數(shù)中
  31. java_policy = self.readConf("java.policy")
  32. if java_policy != "":
  33. policyFile = os.path.join(self.path, "conf", java_policy)
  34. if os.path.exists(policyFile):
  35. print "~ using policy file "%s"" % policyFile
  36. java_args.append("-Djava.security.manager")
  37. java_args.append("-Djava.security.policy==%s" % policyFile)
  38. #加入http端口設(shè)置
  39. if self.play_env.has_key("http.port"):
  40. args += ["--http.port=%s" % self.play_env["http.port"]]
  41. #加入https端口設(shè)置
  42. if self.play_env.has_key("https.port"):
  43. args += ["--https.port=%s" % self.play_env["https.port"]]
  44. #設(shè)置文件編碼
  45. java_args.append("-Dfile.encoding=utf-8")
  46. #設(shè)置編譯命令 (這邊使用了jregex/Pretokenizer類(lèi)的next方法,不知道有什么用)
  47. java_args.append("-XX:CompileCommand=exclude,jregex/Pretokenizer,next")
  48. #如果程序模式在dev,則添加jpda調(diào)試器參數(shù)
  49. if self.readConf("application.mode").lower() == "dev":
  50. if not self.play_env["disable_check_jpda"]: self.check_jpda()
  51. java_args.append("-Xdebug")
  52. java_args.append("-Xrunjdwp:transport=dt_socket,address=%s,server=y,suspend=n" % self.jpda_port)
  53. java_args.append("-Dplay.debug=yes")
  54. #拼接java參數(shù)
  55. java_cmd = [self.java_path(), "-javaagent:%s" % self.agent_path()] + java_args + ["-classpath", cp_args, "-Dapplication.path=%s" % self.path, "-Dplay.id=%s" % self.play_env["id"], className] + args
  56. return java_cmd

start命令與run命令很類(lèi)似,執(zhí)行步驟為:

依次查找play變量pid_file、系統(tǒng)環(huán)境變量PLAY_PID_PATH、項(xiàng)目根目錄下server.pid,查找是否存在指定pid

若第一步找到pid,查找當(dāng)前進(jìn)程列表中是否存在此pid進(jìn)程,存在則試圖關(guān)閉進(jìn)程。(如果此pid不是play的進(jìn)程呢。。。)

在配置文件中找application.log.system.out看是否關(guān)閉了系統(tǒng)輸出

啟動(dòng)程序,這里與run命令唯一的區(qū)別就是他指定了stdout位置,這樣就變成了后臺(tái)程序

將啟動(dòng)后的程序的pid寫(xiě)入server.pid

stop命令即關(guān)閉當(dāng)前進(jìn)程,這里要提一下,play有個(gè)注解叫OnApplicationStop,即會(huì)在程序停止時(shí)觸發(fā),而OnApplicationStop的實(shí)現(xiàn)主要是調(diào)用了Runtime.getRuntime().addShutdownHook();來(lái)完成

test與autotest

使用play test命令可以讓程序進(jìn)入測(cè)試模式,test命令和run命令其實(shí)差別不大,唯一的區(qū)別就在于使用test命令時(shí),腳本會(huì)將play id自動(dòng)替換為test,當(dāng)play id為test時(shí)會(huì)自動(dòng)引入testrunner模塊,testrunner模塊主要功能為添加@tests路由并實(shí)現(xiàn)了test測(cè)試頁(yè)面,他的具體實(shí)現(xiàn)過(guò)程后續(xù)再談。
autotest命令的作用是自動(dòng)測(cè)試所有的測(cè)試用例,他的執(zhí)行順序是這樣的:

檢查是否存在tmp文件夾,存在即刪除

檢查是否有程序正在運(yùn)行,如存在則關(guān)閉程序

檢查程序是否配置了ssl但是沒(méi)有指定證書(shū)

檢查是否存在test-result文件夾,存在即刪除

使用test作為id重啟程序

調(diào)用play.modules.testrunner.FirePhoque來(lái)進(jìn)行自動(dòng)化測(cè)試

關(guān)閉程序

autotest的腳本的步驟1和2我覺(jué)得是有問(wèn)題的,應(yīng)該換下順序,不然如果程序正在向tmp文件夾插入臨時(shí)文件,那么tmp文件夾就刪除失敗了。
關(guān)閉程序的代碼調(diào)用了http://localhost:%http_port/@kill進(jìn)行關(guān)閉,@kill的實(shí)現(xiàn)方法在play.CorePlugin下,注意,@kill在prod模式下無(wú)效(這是廢話)
由于使用了python作為啟動(dòng)腳本,無(wú)法通過(guò)java內(nèi)部變量值判斷程序是否開(kāi)啟,只能查看控制臺(tái)的輸出日志,所以在使用test作為id重啟后,腳本使用下面的代碼判斷程序是否完全啟動(dòng):

</>復(fù)制代碼

  1. try:
  2. #這里啟動(dòng)程序
  3. play_process = subprocess.Popen(java_cmd, env=os.environ, stdout=sout)
  4. except OSError:
  5. print "Could not execute the java executable, please make sure the JAVA_HOME environment variable is set properly (the java executable should reside at JAVA_HOME/bin/java). "
  6. sys.exit(-1)
  7. #打開(kāi)日志輸出文件
  8. soutint = open(os.path.join(app.log_path(), "system.out"), "r")
  9. while True:
  10. if play_process.poll():
  11. print "~"
  12. print "~ Oops, application has not started?"
  13. print "~"
  14. sys.exit(-1)
  15. line = soutint.readline().strip()
  16. if line:
  17. print line
  18. #若出現(xiàn)"Server is up and running"則正常啟動(dòng)
  19. if line.find("Server is up and running") > -1: # This line is written out by Server.java to system.out and is not log file dependent
  20. soutint.close()
  21. break

firephoque類(lèi)的實(shí)現(xiàn)過(guò)程我們之后再詳解。

new與clean

我們使用new來(lái)創(chuàng)建一個(gè)新項(xiàng)目,play new的使用方法為play new project-name [--with] [--name]。
with參數(shù)為項(xiàng)目所使用的模塊。
name為項(xiàng)目名,這里要注意一點(diǎn),projectname和--name的參數(shù)可以設(shè)置為不同值,projectname是項(xiàng)目建立的文件夾名,--name的值為項(xiàng)目配置文件中的application.name。
如果不加--name,腳本會(huì)提示你是否使用projectname作為名字,在確認(rèn)之后,腳本會(huì)將resources/application-skel中的所有文件拷貝到projectname文件夾下,然后用輸入的name替換項(xiàng)目配置文件下的application.name,并生成一個(gè)64位的secretKey替換配置文件中的secretKey。
接著,腳本會(huì)查找使用的模塊中是否存在dependencies.yml,并將dependencies.yml中的內(nèi)容加入項(xiàng)目的dependencies.yml中,并調(diào)用DependenciesManager檢查依賴狀態(tài)。

new函數(shù)的主要代碼如下:

</>復(fù)制代碼

  1. print "~ The new application will be created in %s" % os.path.normpath(app.path)
  2. if application_name is None:
  3. application_name = raw_input("~ What is the application name? [%s] " % os.path.basename(app.path))
  4. if application_name == "":
  5. application_name = os.path.basename(app.path)
  6. copy_directory(os.path.join(env["basedir"], "resources/application-skel"), app.path)
  7. os.mkdir(os.path.join(app.path, "app/models"))
  8. os.mkdir(os.path.join(app.path, "lib"))
  9. app.check()
  10. replaceAll(os.path.join(app.path, "conf/application.conf"), r"%APPLICATION_NAME%", application_name)
  11. replaceAll(os.path.join(app.path, "conf/application.conf"), r"%SECRET_KEY%", secretKey())
  12. print "~"

clean命令非常簡(jiǎn)單,就是刪除整個(gè)tmp文件夾

war與precompile

很多時(shí)候,我們需要使用tomcat等服務(wù)器容器作為服務(wù)載體,這時(shí)候就需要將play應(yīng)用打包為war
war的使用參數(shù)是play war project-name [-o/--output][filename] [--zip] [--exclude][exclude-directories]
使用-o或--output來(lái)指定輸出文件夾,使用--zip壓縮為war格式,使用--exclude來(lái)包含另外需要打包的文件夾
要注意的是,必須在項(xiàng)目目錄外進(jìn)行操作,不然會(huì)失敗
在參數(shù)處理完畢后,腳本正式開(kāi)始打包過(guò)程,分為2個(gè)步驟:1.預(yù)編譯。2:打包
預(yù)編譯即用到了precompile命令,precompile命令與run命令幾乎一樣,只是在java參數(shù)中加入了precompile=yes,這里要注意下,這里加入的precompile值是yes,不是true,所以Play類(lèi)中的usePrecompiled是false這里搞錯(cuò)了,Play類(lèi)中的usePrecompiled檢查的參數(shù)是precompiled,而不是precompile
讓我們來(lái)看一下加入了這個(gè)java參數(shù)對(duì)程序的影響。
與預(yù)編譯有關(guān)的代碼主要是下面2段:

</>復(fù)制代碼

  1. static boolean preCompile() {
  2. if (usePrecompiled) {
  3. if (Play.getFile("precompiled").exists()) {
  4. classloader.getAllClasses();
  5. Logger.info("Application is precompiled");
  6. return true;
  7. }
  8. Logger.error("Precompiled classes are missing!!");
  9. fatalServerErrorOccurred();
  10. return false;
  11. }
  12. //這里開(kāi)始預(yù)編譯
  13. try {
  14. Logger.info("Precompiling ...");
  15. Thread.currentThread().setContextClassLoader(Play.classloader);
  16. long start = System.currentTimeMillis();
  17. //getAllClasses方法較長(zhǎng),就不貼了,下面一段代碼在getAllClasses方法中進(jìn)入
  18. classloader.getAllClasses();
  19. if (Logger.isTraceEnabled()) {
  20. Logger.trace("%sms to precompile the Java stuff", System.currentTimeMillis() - start);
  21. }
  22. if (!lazyLoadTemplates) {
  23. start = System.currentTimeMillis();
  24. //編譯模板
  25. TemplateLoader.getAllTemplate();
  26. if (Logger.isTraceEnabled()) {
  27. Logger.trace("%sms to precompile the templates", System.currentTimeMillis() - start);
  28. }
  29. }
  30. return true;
  31. } catch (Throwable e) {
  32. Logger.error(e, "Cannot start in PROD mode with errors");
  33. fatalServerErrorOccurred();
  34. return false;
  35. }
  36. }

</>復(fù)制代碼

  1. public byte[] enhance() {
  2. this.enhancedByteCode = this.javaByteCode;
  3. if (isClass()) {
  4. // before we can start enhancing this class we must make sure it is not a PlayPlugin.
  5. // PlayPlugins can be included as regular java files in a Play-application.
  6. // If a PlayPlugin is present in the application, it is loaded when other plugins are loaded.
  7. // All plugins must be loaded before we can start enhancing.
  8. // This is a problem when loading PlayPlugins bundled as regular app-class since it uses the same classloader
  9. // as the other (soon to be) enhanched play-app-classes.
  10. boolean shouldEnhance = true;
  11. try {
  12. CtClass ctClass = enhanceChecker_classPool.makeClass(new ByteArrayInputStream(this.enhancedByteCode));
  13. if (ctClass.subclassOf(ctPlayPluginClass)) {
  14. shouldEnhance = false;
  15. }
  16. } catch( Exception e) {
  17. // nop
  18. }
  19. if (shouldEnhance) {
  20. Play.pluginCollection.enhance(this);
  21. }
  22. }
  23. //主要是這一段,他將增強(qiáng)處理后的字節(jié)碼寫(xiě)入了文件,增強(qiáng)處理在之后會(huì)深入展開(kāi)
  24. if (System.getProperty("precompile") != null) {
  25. try {
  26. // emit bytecode to standard class layout as well
  27. File f = Play.getFile("precompiled/java/" + (name.replace(".", "/")) + ".class");
  28. f.getParentFile().mkdirs();
  29. FileOutputStream fos = new FileOutputStream(f);
  30. fos.write(this.enhancedByteCode);
  31. fos.close();
  32. } catch (Exception e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. return this.enhancedByteCode;
  37. }

預(yù)編譯過(guò)程結(jié)束后,腳本正式開(kāi)始打包過(guò)程,打包過(guò)程比較簡(jiǎn)單,就是講預(yù)編譯后的字節(jié)碼文件、模板文件、配置文件、使用的類(lèi)庫(kù)、使用的模塊類(lèi)庫(kù)等移動(dòng)至WEB-INF文件夾中,如果使用了--zip,那么腳本會(huì)將生成的文件夾用zip格式打包。

secret和status

secret命令能生成一個(gè)新的secret key
status命令是用于實(shí)時(shí)顯示程序的運(yùn)行狀態(tài),腳本的運(yùn)作十分簡(jiǎn)單,步驟如下:

檢查是否有--url參數(shù),有則在他之后添加@status

檢查是否存在--secret

如果沒(méi)有--url,則使用http://localhost:%http_port/@status;如果沒(méi)有 --secret,則從配置文件中讀取secret key

將secret_key、"@status"使用sha加密,并加入Authorization請(qǐng)求頭

發(fā)送請(qǐng)求

@status的實(shí)現(xiàn)和@kill一樣在CorePlugin類(lèi)中,這在之后再進(jìn)行詳解。

總結(jié)

Play的啟動(dòng)腳本分析至此就結(jié)束了,從腳本的分析過(guò)程中我們可以稍微探究下Play在腳本啟動(dòng)階段有何行為,這對(duì)我們進(jìn)行腳本改造或者啟動(dòng)優(yōu)化還是非常有幫助的。
下一篇,我們來(lái)看看Play的啟動(dòng)類(lèi)是如何運(yùn)作的。。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/68304.html

相關(guān)文章

  • Play framework源碼解析 Part3:Play的初始化與啟動(dòng)

    摘要:使用自建的類(lèi)加載器主要是為了便于處理預(yù)編譯后的字節(jié)碼以及方便在模式下進(jìn)行即時(shí)的熱更新。 注:本系列文章所用play版本為1.2.6 在上一篇中,我們分析了play的2種啟動(dòng)方式,這一篇,我們來(lái)看看Play類(lèi)的初始化過(guò)程 Play類(lèi) 無(wú)論是Server還是ServletWrapper方式運(yùn)行,在他們的入口中都會(huì)運(yùn)行Play.init()來(lái)對(duì)Play類(lèi)進(jìn)行初始化。那在解析初始化之前,我們先...

    xuxueli 評(píng)論0 收藏0
  • Play framework源碼解析 Part2:Server與ServletWrapper

    摘要:是一個(gè)抽象類(lèi),繼承了接口,它的方法是這個(gè)類(lèi)的核心。因?yàn)榭赡苄枰粋€(gè)返回值,所以它同時(shí)繼承了接口來(lái)提供返回值。 注:本系列文章所用play版本為1.2.6 在上一篇中我們剖析了Play framework的啟動(dòng)原理,很容易就能發(fā)現(xiàn)Play framework的啟動(dòng)主入口在play.server.Server中,在本節(jié),我們來(lái)一起看看Server類(lèi)中主要發(fā)生了什么。 Server類(lèi) 既然是...

    JiaXinYi 評(píng)論0 收藏0
  • 如何使用 Docker 部署一個(gè)基于 Play Framework 的 Scala Web 應(yīng)用?

    摘要:本文將著重介紹使用來(lái)部署一個(gè)基于的應(yīng)用程序會(huì)多么便捷,當(dāng)然這個(gè)過(guò)程主要基于插件。如你所見(jiàn),這是一個(gè)基于的應(yīng)用程序。這個(gè)基于的應(yīng)用程序?qū)o(wú)法被訪問(wèn)。總結(jié)可以如此簡(jiǎn)單地給一個(gè)基于的應(yīng)用程序建立,相信很多人都會(huì)像筆者一樣離不開(kāi)它。 本文作者 Jacek Laskowski 擁有近20年的應(yīng)用程序開(kāi)發(fā)經(jīng)驗(yàn),現(xiàn) CodiLime 的軟件開(kāi)發(fā)團(tuán)隊(duì) Leader,曾從 IBM 取得多種資格認(rèn)證。在這...

    2501207950 評(píng)論0 收藏0
  • Play Framework升級(jí)到2.6.x的填坑記錄

    摘要:為了使用最新的,升級(jí)到配置修改根據(jù)官網(wǎng)的升級(jí)指南,修改文件,更改插件版本號(hào)文件中,把和單獨(dú)加入。此文件為首頁(yè)的模板。推測(cè)可能是版本和版本的首頁(yè)模板不同,于是到官網(wǎng)下載版本的,找到并覆蓋項(xiàng)目的相應(yīng)文件。添加插件的語(yǔ)句至此,升級(jí)成功完成。 為了使用最新的Play WS Api,升級(jí)到play 2.6.21 1.配置修改 根據(jù)官網(wǎng)的升級(jí)指南,修改plugins.sbt文件,更改插件版本號(hào):a...

    voidking 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<