接着 上篇在python的辅助下,理理输入启动命令之后,play框架进行的初始化工作。 application.py中的java_cmd方法中就有play.server.Server。
def java_cmd(self, java_args, cp_args=None, className='play.server.Server', args = None):
在这个类中可以看到亲切的main方法,就是框架的入口了。
1public class Server { 2 ... 3 public static void main(String[] args) throws Exception { 4 File root = new File(System.getProperty("application.path")); 5 if (System.getProperty("precompiled", "false").equals("true")) { 6 Play.usePrecompiled = true; 7 } 8 if (System.getProperty("writepid", "false").equals("true")) { 9 writePID(root); 10 } 11 Play.init(root, System.getProperty("play.id", "")); 12 if (System.getProperty("precompile") == null) { 13 new Server(args); 14 } else { 15 Logger.info("Done."); 16 } 17 } 18 ... 19}
其中对play.Play:init()方法对框架进行了初始化,包括应用的状态、应用java代码、模板、路由的位置、cookie域名称等。
1public class Play { 2 ... 3 public static void init(File root, String id) { 4 ... 5 // Main route file 6 routes = appRoot.child("conf/routes"); 7 8 // Plugin route files 9 modulesRoutes = new HashMap<String, VirtualFile>(16); 10 11 // Load modules 12 loadModules(appRoot); 13 14 // Load the templates from the framework after the one from the modules 15 templatesPath.add(VirtualFile.open(new File(frameworkPath, "framework/templates"))); 16 17 // Enable a first classloader 18 classloader = new ApplicationClassloader(); 19 20 // Fix ctxPath 21 if ("/".equals(Play.ctxPath)) { 22 Play.ctxPath = ""; 23 } 24 25 // Default cookie domain 26 Http.Cookie.defaultDomain = configuration.getProperty("application.defaultCookieDomain", null); 27 if (Http.Cookie.defaultDomain!=null) { 28 Logger.info("Using default cookie domain: " + Http.Cookie.defaultDomain); 29 } 30 31 // Plugins 32 pluginCollection.loadPlugins(); 33 ... 34 } 35 ... 36}
其中最关键的是对play插件的读入。play.plugins.PluginCollection:loadPlugins()方法,play的应用每个事件,如应用启动、访问到达、访问结束、代码变动、应用停止等等,都会逐一交给各个插件处理。 在play源码中已经定义一些plugins,并有顺序。
10:play.CorePlugin 2100:play.data.parsing.TempFilePlugin 3200:play.data.validation.ValidationPlugin 4300:play.db.DBPlugin 5400:play.db.jpa.JPAPlugin 6450:play.db.Evolutions 7500:play.i18n.MessagesPlugin 8600:play.libs.WS 9700:play.jobs.JobsPlugin 10100000:play.plugins.ConfigurablePluginDisablingPlugin
我们也可以定义自己的Plugins继承PlayPlugins,然后在应用app目录下如框架中一样,建立play.plugins文件,就也能接受play事件的推送了。
在Server的构造方法中,准备一些netty启动需要的参数之后,就开启了netty,其中重要的是 设定了HttpServerPipelineFactory
1public class Server { 2 ... 3 public Server(String[] args) { 4 ... 5 ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory( 6 Executors.newCachedThreadPool(), Executors.newCachedThreadPool()) 7 ); 8 try { 9 if (httpPort != -1) { 10 bootstrap.setPipelineFactory(new HttpServerPipelineFactory()); 11 12 bootstrap.bind(new InetSocketAddress(address, httpPort)); 13 bootstrap.setOption("child.tcpNoDelay", true); 14 ... 15 } 16 ... 17}
当第一次访问到时,netty将请求转到play.server.HttpServerPipelineFactory中。其中配置了play.server.PlayHandler处理类。netty会用PlayHandler来处理请求。
private String pipelineConfig = Play.configuration.getProperty("play.netty.pipeline", "play.server.FlashPolicyHandler,org.jboss.netty.handler.codec.http.HttpRequestDecoder,play.server.StreamChunkAggregator,org.jboss.netty.handler.codec.http.HttpResponseEncoder,org.jboss.netty.handler.stream.ChunkedWriteHandler,play.server.PlayHandler");
在往后,就进入了下一篇文章。
