Play Framework分析1-与Servlet API的调整
Play Framework分析1-与Servlet API的整合
Play是标准的Request-Response型框架,类似于Struts。
Play把HTTP请求封装为4个类:Header,Cookie,Request,Response。
和Servlet类似的是,他也是通过处理Request和Response两个对象来完成一次访问的处理。
和Servlet不同的是,在Servlet中你想获得ServletRequest/ServletResponse,你必须通过HttpServlet set到你的Object中。
而Play不这样做,通过Threadlocal机制,可以在程序的任何地方通过调用静态方法
Request.current.get()方法获得当前线程正在处理的Request.
这就相当于你不需要写set方法,你就可以在任何地方都取到当前的Request.
这是非常巧妙的做法,能做到这一点也和服务器本身的处理机制有关。
如果我们只用一个线程来处理所有的请求,那么Play这样的做法就行不通了。
Play整合Servlet API是这样的:
他有一个类叫做ServletWapper,ServletWapper继承了HTTPServlet.当一次请求进来,它首先把HttpServletRequest的内容拷贝到当前的Request中,等Play框架处理完以后,再把Response的内容拷贝到HttpServletResponse中。
这样Play和Servlet API就整合到一起了,非常的简单

可以发现,Play对Servlet API的入侵性很小,可以说它就是一个Servlet.
这只是一个Play的冰山一角,它的代码还有很多有趣的地方,可以用非主流来形容。
比如它使用抛异常的方式返回执行的结果等等,Play的代码阅读起来很简单,推荐有兴趣的朋友可以阅读。
这就是ServletWapper的service方法
不对。。。上面他的论述没有讨论到server的问题。
因为整个Play都是对Request和Reponse进行操作的(它内部的Server也是);而Servlet是HttpServletRequest和HttpServletResponse,为了统一两种接口,所以有了ServletWapper这个类。
Tomcat或者其他Container接收到Http的请求,会首先激活HttpServlet,也就是ServletWapper的service方法,Play在这里把HttpServletRequest和HttpServletResponse转成Request和Reponse,往框架内塞。那这就和用自己的server的接口一样了。。。
不对。。。上面他的论述没有讨论到server的问题。
因为整个Play都是对Request和Reponse进行操作的(它内部的Server也是);而Servlet是HttpServletRequest和HttpServletResponse,为了统一两种接口,所以有了ServletWapper这个类。
Tomcat或者其他Container接收到Http的请求,会首先激活HttpServlet,也就是ServletWapper的service方法,Play在这里把HttpServletRequest和HttpServletResponse转成Request和Reponse,往框架内塞。那这就和用自己的server的接口一样了。。。
我以前准备使用play!来开发GAE,访问了一下play!自己带的那个GAE的例子,发现第一次访问非常的慢。
后来在play!的google group上看到,play的作者说,由于GAE的运行机制的原因,如果一段时间内没有访问,那么你的GAE应用会停掉,当有新的请求来的时候,GAE会重新装在你的应用。这个过程会重新启动play(看他的ServletWapper就是调用play.init方法),而这个过程比较耗时,所以第一次请求会慢一些。
看play的init方法主要是初始化配置,预编译,加载类等操作...不知道是那一块比较耗费时间?如果打成war包后,可以对init精简一些的话,我想对在GAE上的app来说,可以大大减少第一次响应的时间的。
我以前准备使用play!来开发GAE,访问了一下play!自己带的那个GAE的例子,发现第一次访问非常的慢。
后来在play!的google group上看到,play的作者说,由于GAE的运行机制的原因,如果一段时间内没有访问,那么你的GAE应用会停掉,当有新的请求来的时候,GAE会重新装在你的应用。这个过程会重新启动play(看他的ServletWapper就是调用play.init方法),而这个过程比较耗时,所以第一次请求会慢一些。
看play的init方法主要是初始化配置,预编译,加载类等操作...不知道是那一块比较耗费时间?如果打成war包后,可以对init精简一些的话,我想对在GAE上的app来说,可以大大减少第一次响应的时间的。
你理解错了。你部署在GAE上面的程序,如果连续5分钟不被访问的话,GAE会把他停掉;等再有访问来的时候,会重新load整个GAE的java运行context/container。
一般很少网站会5分钟每人访问吧?如果是开发环境或者只是个人Blog的话,我教你个诀窍:
用GAE提供的Cron,每3分钟访问一次你程序的某一个servlet。。。
我以前准备使用play!来开发GAE,访问了一下play!自己带的那个GAE的例子,发现第一次访问非常的慢。
后来在play!的google group上看到,play的作者说,由于GAE的运行机制的原因,如果一段时间内没有访问,那么你的GAE应用会停掉,当有新的请求来的时候,GAE会重新装在你的应用。这个过程会重新启动play(看他的ServletWapper就是调用play.init方法),而这个过程比较耗时,所以第一次请求会慢一些。
看play的init方法主要是初始化配置,预编译,加载类等操作...不知道是那一块比较耗费时间?如果打成war包后,可以对init精简一些的话,我想对在GAE上的app来说,可以大大减少第一次响应的时间的。
你理解错了。你部署在GAE上面的程序,如果连续5分钟不被访问的话,GAE会把他停掉;等再有访问来的时候,会重新load整个GAE的java运行context/container。
一般很少网站会5分钟每人访问吧?如果是开发环境或者只是个人Blog的话,我教你个诀窍:
用GAE提供的Cron,每3分钟访问一次你程序的某一个servlet。。。
哦,谢谢。
我现在还费事的把play的router和ActionInvoker等抽取出来,然后使用velocity作为模板,搞了个GAE定制版的play!...
哦,谢谢。
我现在还费事的把play的router和ActionInvoker等抽取出来,然后使用velocity作为模板,搞了个GAE定制版的play!...
这样修改应该改进不大。。。在GAE的Group上面有人直接用servlet,在第一次访问的时候都喊慢。。。
瓶颈出现在GAE的运行环境初始化而不是你的程序的初始化。。。
Play是标准的Request-Response型框架,类似于Struts。
Play把HTTP请求封装为4个类:Header,Cookie,Request,Response。
和Servlet类似的是,他也是通过处理Request和Response两个对象来完成一次访问的处理。
和Servlet不同的是,在Servlet中你想获得ServletRequest/ServletResponse,你必须通过HttpServlet set到你的Object中。
而Play不这样做,通过Threadlocal机制,可以在程序的任何地方通过调用静态方法
Request.current.get()方法获得当前线程正在处理的Request.
这就相当于你不需要写set方法,你就可以在任何地方都取到当前的Request.
这是非常巧妙的做法,能做到这一点也和服务器本身的处理机制有关。
如果我们只用一个线程来处理所有的请求,那么Play这样的做法就行不通了。
Play整合Servlet API是这样的:
他有一个类叫做ServletWapper,ServletWapper继承了HTTPServlet.当一次请求进来,它首先把HttpServletRequest的内容拷贝到当前的Request中,等Play框架处理完以后,再把Response的内容拷贝到HttpServletResponse中。
这样Play和Servlet API就整合到一起了,非常的简单
可以发现,Play对Servlet API的入侵性很小,可以说它就是一个Servlet.
这只是一个Play的冰山一角,它的代码还有很多有趣的地方,可以用非主流来形容。
比如它使用抛异常的方式返回执行的结果等等,Play的代码阅读起来很简单,推荐有兴趣的朋友可以阅读。
这就是ServletWapper的service方法
@Override protected void service(HttpServletRequest httpServletRequest, HttpServletResponse httpServletRespo nse) throws ServletException, IOException { Logger.trace("ServletWrapper>service " + httpServletRequest.getRequestURI()); Request request = null; try { request = parseRequest(httpServletRequest); Logger.trace("ServletWrapper>service, request: " + request); Response response = new Response(); Response.current.set(response); response.out = new ByteArrayOutputStream(); boolean raw = false; for (PlayPlugin plugin : Play.plugins) { if (plugin.rawInvocation(request, response)) { raw = true; break; } } if (raw) { copyResponse(Request.current(), Response.current(), httpServletRequest, httpServletResponse); } else { Invoker.invokeInThread(new ServletInvocation(request, response, httpServletRequest, httpServletResponse)); } } catch (NotFound e) { Logger.trace("ServletWrapper>service, NotFound: " + e); serve404(httpServletRequest, httpServletResponse, e); return; } catch (RenderStatic e) { Logger.trace("ServletWrapper>service, RenderStatic: " + e); serveStatic(httpServletResponse, httpServletRequest, e); return; } catch (Throwable e) { throw new ServletException(e); } }
1 楼
container
2009-12-06
如果没有理解错误的话,play!生成war包,部署到jee容器中,真正起作用的还是他内置的Server。
对不?
对不?
2 楼
Laynepeng
2009-12-06
container 写道
如果没有理解错误的话,play!生成war包,部署到jee容器中,真正起作用的还是他内置的Server。
对不?
对不?
不对。。。上面他的论述没有讨论到server的问题。
因为整个Play都是对Request和Reponse进行操作的(它内部的Server也是);而Servlet是HttpServletRequest和HttpServletResponse,为了统一两种接口,所以有了ServletWapper这个类。
Tomcat或者其他Container接收到Http的请求,会首先激活HttpServlet,也就是ServletWapper的service方法,Play在这里把HttpServletRequest和HttpServletResponse转成Request和Reponse,往框架内塞。那这就和用自己的server的接口一样了。。。
3 楼
container
2009-12-06
Laynepeng 写道
container 写道
如果没有理解错误的话,play!生成war包,部署到jee容器中,真正起作用的还是他内置的Server。
对不?
对不?
不对。。。上面他的论述没有讨论到server的问题。
因为整个Play都是对Request和Reponse进行操作的(它内部的Server也是);而Servlet是HttpServletRequest和HttpServletResponse,为了统一两种接口,所以有了ServletWapper这个类。
Tomcat或者其他Container接收到Http的请求,会首先激活HttpServlet,也就是ServletWapper的service方法,Play在这里把HttpServletRequest和HttpServletResponse转成Request和Reponse,往框架内塞。那这就和用自己的server的接口一样了。。。
我以前准备使用play!来开发GAE,访问了一下play!自己带的那个GAE的例子,发现第一次访问非常的慢。
后来在play!的google group上看到,play的作者说,由于GAE的运行机制的原因,如果一段时间内没有访问,那么你的GAE应用会停掉,当有新的请求来的时候,GAE会重新装在你的应用。这个过程会重新启动play(看他的ServletWapper就是调用play.init方法),而这个过程比较耗时,所以第一次请求会慢一些。
看play的init方法主要是初始化配置,预编译,加载类等操作...不知道是那一块比较耗费时间?如果打成war包后,可以对init精简一些的话,我想对在GAE上的app来说,可以大大减少第一次响应的时间的。
4 楼
Laynepeng
2009-12-07
container 写道
我以前准备使用play!来开发GAE,访问了一下play!自己带的那个GAE的例子,发现第一次访问非常的慢。
后来在play!的google group上看到,play的作者说,由于GAE的运行机制的原因,如果一段时间内没有访问,那么你的GAE应用会停掉,当有新的请求来的时候,GAE会重新装在你的应用。这个过程会重新启动play(看他的ServletWapper就是调用play.init方法),而这个过程比较耗时,所以第一次请求会慢一些。
看play的init方法主要是初始化配置,预编译,加载类等操作...不知道是那一块比较耗费时间?如果打成war包后,可以对init精简一些的话,我想对在GAE上的app来说,可以大大减少第一次响应的时间的。
你理解错了。你部署在GAE上面的程序,如果连续5分钟不被访问的话,GAE会把他停掉;等再有访问来的时候,会重新load整个GAE的java运行context/container。
一般很少网站会5分钟每人访问吧?如果是开发环境或者只是个人Blog的话,我教你个诀窍:
用GAE提供的Cron,每3分钟访问一次你程序的某一个servlet。。。
5 楼
container
2009-12-07
Laynepeng 写道
container 写道
我以前准备使用play!来开发GAE,访问了一下play!自己带的那个GAE的例子,发现第一次访问非常的慢。
后来在play!的google group上看到,play的作者说,由于GAE的运行机制的原因,如果一段时间内没有访问,那么你的GAE应用会停掉,当有新的请求来的时候,GAE会重新装在你的应用。这个过程会重新启动play(看他的ServletWapper就是调用play.init方法),而这个过程比较耗时,所以第一次请求会慢一些。
看play的init方法主要是初始化配置,预编译,加载类等操作...不知道是那一块比较耗费时间?如果打成war包后,可以对init精简一些的话,我想对在GAE上的app来说,可以大大减少第一次响应的时间的。
你理解错了。你部署在GAE上面的程序,如果连续5分钟不被访问的话,GAE会把他停掉;等再有访问来的时候,会重新load整个GAE的java运行context/container。
一般很少网站会5分钟每人访问吧?如果是开发环境或者只是个人Blog的话,我教你个诀窍:
用GAE提供的Cron,每3分钟访问一次你程序的某一个servlet。。。
哦,谢谢。
我现在还费事的把play的router和ActionInvoker等抽取出来,然后使用velocity作为模板,搞了个GAE定制版的play!...
6 楼
Laynepeng
2009-12-07
container 写道
哦,谢谢。
我现在还费事的把play的router和ActionInvoker等抽取出来,然后使用velocity作为模板,搞了个GAE定制版的play!...
这样修改应该改进不大。。。在GAE的Group上面有人直接用servlet,在第一次访问的时候都喊慢。。。
瓶颈出现在GAE的运行环境初始化而不是你的程序的初始化。。。
7 楼
依山傍水
2011-08-04
还是不太懂,不知道怎么转换过去,你能再指教一下吗?
8 楼
依山傍水
2011-08-04
因为我要用多个文件上传,要用到
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(4096); // 超出这个大小放磁盘,否则放在内存中
ServletFileUpload upload = new ServletFileUpload(factory); upload.setSizeMax(MAXFILESIZE);
List fileItems = upload.parseRequest(request);
但这里的request应该是HttpServletRequest,但是怎么得到servletRequest呢?
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setSizeThreshold(4096); // 超出这个大小放磁盘,否则放在内存中
ServletFileUpload upload = new ServletFileUpload(factory); upload.setSizeMax(MAXFILESIZE);
List fileItems = upload.parseRequest(request);
但这里的request应该是HttpServletRequest,但是怎么得到servletRequest呢?