成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

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

Riddler / 1234人閱讀

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

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

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

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

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

支持異步編程

無狀態(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)作原理,我們來從play framework的啟動(dòng)腳本開始分析,分析啟動(dòng)腳本有助于我們了解play framework的運(yùn)行過程。
play framework1.2.6軟件包解壓后的文件如下:

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

play腳本解析

play腳本在開頭引入了3個(gè)類,分別為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命令

sys.path.append(os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), "framework", "pym"))

from play.cmdloader import CommandLoader
from play.application import PlayApplication
from play.utils import *

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

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

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

    application_path = None
    remaining_args = []
    if len(sys.argv) == 1:
        application_path = os.getcwd()
    if len(sys.argv) == 2:
        application_path = os.getcwd()
        remaining_args = sys.argv[2:]
    if len(sys.argv) > 2:
        if sys.argv[2].startswith("-"):
            application_path = os.getcwd()
            remaining_args = sys.argv[2:]
        else:
            application_path = os.path.normpath(os.path.abspath(sys.argv[2]))
            remaining_args = sys.argv[3:]

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

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

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

    DEFAULTS = {
        "http.port": "9000",
        "jpda.port": "8000"
    }

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

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

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

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

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

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

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

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

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

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

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

結(jié)束腳本

    if play_command in cmdloader.commands:
        for name in cmdloader.modules:
            module = cmdloader.modules[name]
            if "before" in dir(module):
                module.before(command=play_command, app=play_app, args=remaining_args, env=play_env)
        status = cmdloader.commands[play_command].execute(command=play_command, app=play_app, args=remaining_args, env=play_env, cmdloader=cmdloader)
        for name in cmdloader.modules:
            module = cmdloader.modules[name]
            if "after" in dir(module):
                module.after(command=play_command, app=play_app, args=remaining_args, env=play_env)
        sys.exit(status)

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

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

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

命令名稱 命令所在文件 作用
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來運(yùn)行play.server.Server,run函數(shù)的代碼如下:

def run(app, args):
    #app即為play腳本中創(chuàng)建的PlayApplication類
    global process
    #這里檢查是否存在conf/routes和conf/application.conf
    app.check()

    print "~ Ctrl+C to stop"
    print "~ "
    java_cmd = app.java_cmd(args)
    try:
        process = subprocess.Popen (java_cmd, env=os.environ)
        signal.signal(signal.SIGTERM, handle_sigterm)
        return_code = process.wait()
    signal.signal(signal.SIGINT, handle_sigint)
        if 0 != return_code:
            sys.exit(return_code)
    except OSError:
        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). "
        sys.exit(-1)
    print

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

def java_cmd(self, java_args, cp_args=None, className="play.server.Server", args = None):
    if args is None:
        args = [""]
    memory_in_args=False

    #檢查java參數(shù)中是否有jvm內(nèi)存設(shè)置
    for arg in java_args:
        if arg.startswith("-Xm"):
            memory_in_args=True
    #如果參數(shù)中無jvm內(nèi)存設(shè)置,那么在配置文件中找是否有jvm內(nèi)存設(shè)置,若還是沒有則在環(huán)境變量中找是否有JAVA_OPTS
    #這里其實(shí)有個(gè)問題,這里假定的是JAVA_OPTS變量里只存了jvm內(nèi)存設(shè)置,如果JAVA_OPTS還存了其他選項(xiàng),那對(duì)運(yùn)行可能有影響
    if not memory_in_args:
        memory = self.readConf("jvm.memory")
        if memory:
            java_args = java_args + memory.split(" ")
        elif "JAVA_OPTS" in os.environ:
            java_args = java_args + os.environ["JAVA_OPTS"].split(" ")
    #獲取程序的classpath
    if cp_args is None:
        cp_args = self.cp_args()
    #讀取配置文件中的jpda端口
    self.jpda_port = self.readConf("jpda.port")
    #讀取配置文件中的運(yùn)行模式
    application_mode = self.readConf("application.mode").lower()
    #如果模式是prod,則用server模式編譯
    if application_mode == "prod":
        java_args.append("-server")
    # JDK 7 compat
    # 使用新class校驗(yàn)器 (不知道作用)
    java_args.append("-XX:-UseSplitVerifier")
    #查找配置文件中是否有java安全配置,如果有則加入java參數(shù)中
    java_policy = self.readConf("java.policy")
    if java_policy != "":
        policyFile = os.path.join(self.path, "conf", java_policy)
        if os.path.exists(policyFile):
            print "~ using policy file "%s"" % policyFile
            java_args.append("-Djava.security.manager")
            java_args.append("-Djava.security.policy==%s" % policyFile)
    #加入http端口設(shè)置
    if self.play_env.has_key("http.port"):
        args += ["--http.port=%s" % self.play_env["http.port"]]
    #加入https端口設(shè)置
    if self.play_env.has_key("https.port"):
        args += ["--https.port=%s" % self.play_env["https.port"]]

    #設(shè)置文件編碼
    java_args.append("-Dfile.encoding=utf-8")
    #設(shè)置編譯命令 (這邊使用了jregex/Pretokenizer類的next方法,不知道有什么用)
    java_args.append("-XX:CompileCommand=exclude,jregex/Pretokenizer,next")

    #如果程序模式在dev,則添加jpda調(diào)試器參數(shù)
    if self.readConf("application.mode").lower() == "dev":
        if not self.play_env["disable_check_jpda"]: self.check_jpda()
        java_args.append("-Xdebug")
        java_args.append("-Xrunjdwp:transport=dt_socket,address=%s,server=y,suspend=n" % self.jpda_port)
        java_args.append("-Dplay.debug=yes")
    #拼接java參數(shù)
    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
    return java_cmd

start命令與run命令很類似,執(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寫入server.pid

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

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)過程后續(xù)再談。
autotest命令的作用是自動(dòng)測(cè)試所有的測(cè)試用例,他的執(zhí)行順序是這樣的:

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

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

檢查程序是否配置了ssl但是沒有指定證書

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

使用test作為id重啟程序

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

關(guān)閉程序

autotest的腳本的步驟1和2我覺得是有問題的,應(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模式下無效(這是廢話)
由于使用了python作為啟動(dòng)腳本,無法通過java內(nèi)部變量值判斷程序是否開啟,只能查看控制臺(tái)的輸出日志,所以在使用test作為id重啟后,腳本使用下面的代碼判斷程序是否完全啟動(dòng):

try:
    #這里啟動(dòng)程序
    play_process = subprocess.Popen(java_cmd, env=os.environ, stdout=sout)
    except OSError:
        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). "
        sys.exit(-1)
    #打開日志輸出文件
    soutint = open(os.path.join(app.log_path(), "system.out"), "r")
    while True:
        if play_process.poll():
            print "~"
            print "~ Oops, application has not started?"
            print "~"
            sys.exit(-1)
        line = soutint.readline().strip()
        if line:
            print line
            #若出現(xiàn)"Server is up and running"則正常啟動(dòng)
            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
                soutint.close()
                break

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

new與clean

我們使用new來創(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ù)的主要代碼如下:

    print "~ The new application will be created in %s" % os.path.normpath(app.path)
    if application_name is None:
        application_name = raw_input("~ What is the application name? [%s] " % os.path.basename(app.path))
    if application_name == "":
        application_name = os.path.basename(app.path)
    copy_directory(os.path.join(env["basedir"], "resources/application-skel"), app.path)
    os.mkdir(os.path.join(app.path, "app/models"))
    os.mkdir(os.path.join(app.path, "lib"))
    app.check()
    replaceAll(os.path.join(app.path, "conf/application.conf"), r"%APPLICATION_NAME%", application_name)
    replaceAll(os.path.join(app.path, "conf/application.conf"), r"%SECRET_KEY%", secretKey())
    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來指定輸出文件夾,使用--zip壓縮為war格式,使用--exclude來包含另外需要打包的文件夾
要注意的是,必須在項(xiàng)目目錄外進(jìn)行操作,不然會(huì)失敗
在參數(shù)處理完畢后,腳本正式開始打包過程,分為2個(gè)步驟:1.預(yù)編譯。2:打包
預(yù)編譯即用到了precompile命令,precompile命令與run命令幾乎一樣,只是在java參數(shù)中加入了precompile=yes,這里要注意下,這里加入的precompile值是yes,不是true,所以Play類中的usePrecompiled是false這里搞錯(cuò)了,Play類中的usePrecompiled檢查的參數(shù)是precompiled,而不是precompile
讓我們來看一下加入了這個(gè)java參數(shù)對(duì)程序的影響。
與預(yù)編譯有關(guān)的代碼主要是下面2段:

    static boolean preCompile() {
        if (usePrecompiled) {
            if (Play.getFile("precompiled").exists()) {
                classloader.getAllClasses();
                Logger.info("Application is precompiled");
                return true;
            }
            Logger.error("Precompiled classes are missing!!");
            fatalServerErrorOccurred();
            return false;
        }
        //這里開始預(yù)編譯
        try {
            Logger.info("Precompiling ...");
            Thread.currentThread().setContextClassLoader(Play.classloader);
            long start = System.currentTimeMillis();
            //getAllClasses方法較長(zhǎng),就不貼了,下面一段代碼在getAllClasses方法中進(jìn)入
            classloader.getAllClasses();

            if (Logger.isTraceEnabled()) {
                Logger.trace("%sms to precompile the Java stuff", System.currentTimeMillis() - start);
            }

            if (!lazyLoadTemplates) {
                start = System.currentTimeMillis();
                //編譯模板
                TemplateLoader.getAllTemplate();

                if (Logger.isTraceEnabled()) {
                    Logger.trace("%sms to precompile the templates", System.currentTimeMillis() - start);
                }
            }
            return true;
        } catch (Throwable e) {
            Logger.error(e, "Cannot start in PROD mode with errors");
            fatalServerErrorOccurred();
            return false;
        }
    }
    public byte[] enhance() {
        this.enhancedByteCode = this.javaByteCode;
        if (isClass()) {

            // before we can start enhancing this class we must make sure it is not a PlayPlugin.
            // PlayPlugins can be included as regular java files in a Play-application.
            // If a PlayPlugin is present in the application, it is loaded when other plugins are loaded.
            // All plugins must be loaded before we can start enhancing.
            // This is a problem when loading PlayPlugins bundled as regular app-class since it uses the same classloader
            // as the other (soon to be) enhanched play-app-classes.
            boolean shouldEnhance = true;
            try {
                CtClass ctClass = enhanceChecker_classPool.makeClass(new ByteArrayInputStream(this.enhancedByteCode));
                if (ctClass.subclassOf(ctPlayPluginClass)) {
                    shouldEnhance = false;
                }
            } catch( Exception e) {
                // nop
            }

            if (shouldEnhance) {
                Play.pluginCollection.enhance(this);
            }
        }

        //主要是這一段,他將增強(qiáng)處理后的字節(jié)碼寫入了文件,增強(qiáng)處理在之后會(huì)深入展開
        if (System.getProperty("precompile") != null) {
            try {
                // emit bytecode to standard class layout as well
                File f = Play.getFile("precompiled/java/" + (name.replace(".", "/")) + ".class");
                f.getParentFile().mkdirs();
                FileOutputStream fos = new FileOutputStream(f);
                fos.write(this.enhancedByteCode);
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return this.enhancedByteCode;
    }

預(yù)編譯過程結(jié)束后,腳本正式開始打包過程,打包過程比較簡(jiǎn)單,就是講預(yù)編譯后的字節(jié)碼文件、模板文件、配置文件、使用的類庫(kù)、使用的模塊類庫(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

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

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

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

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

總結(jié)

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

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

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

相關(guān)文章

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

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

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

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

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

    摘要:本文將著重介紹使用來部署一個(gè)基于的應(yīng)用程序會(huì)多么便捷,當(dāng)然這個(gè)過程主要基于插件。如你所見,這是一個(gè)基于的應(yīng)用程序。這個(gè)基于的應(yīng)用程序?qū)o法被訪問??偨Y(jié)可以如此簡(jiǎn)單地給一個(gè)基于的應(yīng)用程序建立,相信很多人都會(huì)像筆者一樣離不開它。 本文作者 Jacek Laskowski 擁有近20年的應(yīng)用程序開發(fā)經(jīng)驗(yàn),現(xiàn) CodiLime 的軟件開發(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元查看
<