Servlet3.0规范的新特性主要是为了3个目的: 1.简化开发 2.便于布署 3.支持Web2.0原则 为了简化开发流程,Servlet3.0引入了注解(annotation),这使得web布署描述符web.xml不在是必须的选择。 Pluggability可插入性 当使用任何第三方的框架,如Struts,JSF或Spring,咱们都须要在web.xml中添加对应的Servlet的入口。这使得web描述符笨重而难以维护。Servlet3.0的新的可插入特性使得web应用程序模块化而易于维护。经过web fragment实现的可插入性减轻了开发人员的负担,不须要再在web.xml中配置不少的Servlet入口。 Asynchronous Processing 异步处理 另一个显著的改变就是Servlet3.0支持异步处理,这对AJAX应用程序很是有用。当一个Servlet建立一个线程来建立某些请求的时候,如查询数据库或消息链接,这个线程要等待直到得到所须要的资源才可以执行其余的操做。异步处理经过运行线程执行其余的操做来避免了这种阻塞。 Apart from the features mentioned here, several other enhancements have been made to the existing API. The sections towards the end of the article will explore these features one by one in detail. 除了这些新特性以外, Servlet3.0对已有的API也作了一些改进,在本文的最后咱们会作介绍。 Annotations in Servlet Servlet中使用注解 Servlet3.0的一个主要的改变就是支持注解。使用注解来定义Servlet和filter使得咱们不用在web.xml中定义相应的入口。 @WebServlet @WebServlet用来定义web应用程序中的一个Servlet。这个注解能够应用于继承了HttpServlet。这个注解有多个属性,例如name,urlPattern, initParams,咱们可使用者的属性来定义Servlet的行为。urlPattern属性是必须指定的。 例如咱们能够象下面的例子这样定义: 1. @WebServlet(name = "GetQuoteServlet", urlPatterns = {"/getquote"} ) 2. public class GetQuoteServlet extends HttpServlet { 3. @Override 4. protected void doGet(HttpServletRequest request, HttpServletResponse response) 5. throws ServletException, IOException { 6. PrintWriter out = response.getWriter(); 7. try { 8. String symbol = request.getParameter("symbol"); 9. out.println("<h1>Stock Price is</h1>" + StockQuoteBean.getPrice(symbol); 10. } finally { 11. out.close(); 12. } 13. } 14. } 15. 16. public class StockQuoteBean { 17. private StockQuoteServiceEntity serviceEntity = new StockQuoteServiceEntity(); 18. public double getPrice(String symbol) { 19. if(symbol !=null ) { 20. return serviceEntity.getPrice(symbol); 21. } else { 22. return 0.0; 23. } 24. } 25. } 复制代码 在上面的例子中,一个Servlet只对应了一个urlPattern。实际上一个Servlet能够对应多个urlPattern,咱们能够这样定义: 1. @WebServlet(name = "GetQuoteServlet", urlPatterns = {"/getquote", "/stockquote"} ) 2. public class GetQuoteServlet extends HttpServlet { 3. @Override 4. protected void doGet(HttpServletRequest request, HttpServletResponse response) 5. throws ServletException, IOException { 6. PrintWriter out = response.getWriter(); 7. try { 8. String symbol = request.getParameter("symbol"); 9. out.println("<h1>Stock Price is</h1>" + StockQuoteBean.getPrice(symbol); 10. } finally { 11. out.close(); 12. } 13. } 14. } 复制代码 @WebFilter 咱们可使用@WebFilter注解来定义filter。这个注解能够被应用在实现了javax.servlet.Filter接口的类上。一样的,urlPattern属性是必须指定的。下面就是一个例子。 1. @WebFilter(filterName = "AuthenticateFilter", urlPatterns = {"/stock.jsp", "/getquote"}) 2. public class AuthenticateFilter implements Filter { 3. 4. public void doFilter(ServletRequest request, ServletResponse response, 5. FilterChain chain) throws IOException, ServletException { 6. String username = ((HttpServletRequest) request).getParameter("uname"); 7. String password = ((HttpServletRequest) request).getParameter("password"); 8. if (username == null || password == null) { 9. ((HttpServletResponse) response).sendRedirect("index.jsp"); } 10. if (username.equals("admin") && password.equals("admin")) { 11. chain.doFilter(request, response); } 12. else { 13. ((HttpServletResponse) response).sendRedirect("index.jsp"); } 14. } 15. 16. public void destroy() { 17. } 18. public void init(FilterConfig filterConfig) { 19. } 20. } 复制代码 @WebInitParam 可使用@WebInitParam注解来制定Servlet或filter的初始参数。固然咱们也可使用@WebServlet或@WebFileter的initParam属性来指定初始参数。下面是使用@WebInitParam的例子: 1. @WebServlet(name = "GetQuoteServlet", urlPatterns = {"/getquote"}) 2. @WebInitParam(name = "default_market", value = "NASDAQ") 3. public class GetQuoteServlet extends HttpServlet { 4. @Override 5. protected void doGet(HttpServletRequest request, HttpServletResponse response) 6. throws ServletException, IOException { 7. response.setContentType("text/html;charset=UTF-8"); 8. PrintWriter out = response.getWriter(); 9. try { 10. String market = getInitParameter("default_market"); 11. String symbol = request.getParameter("symbol"); 12. out.println("<h1>Stock Price in " + market + " is</h1>" + StockQuoteBean.getPrice(symbol, market)); 13. } finally { 14. out.close(); 15. } 16. } 17. } 复制代码 下面是使用initParam属性的例子: 1. @WebServlet(name = "GetQuoteServlet", 2. urlPatterns = {"/getquote"}, 3. initParams={@WebInitParam(name="default_market", value="NASDAQ")} 4. ) 5. public class GetQuoteServlet extends HttpServlet { 6. @Override 7. protected void doGet(HttpServletRequest request, HttpServletResponse response) 8. throws ServletException, IOException { 9. response.setContentType("text/html;charset=UTF-8"); 10. PrintWriter out = response.getWriter(); 11. try { 12. String market = getInitParameter("default_market"); 13. String symbol = request.getParameter("symbol"); 14. out.println("<h1>Stock Price in " + market + " is</h1>" + StockQuoteBean.getPrice(symbol, market)); 15. } finally { 16. out.close(); 17. } 18. } 19. } 复制代码 @WebListener @WebListener注解被应用在做为listener监听web应用程序事件的类上,因此@WebListener可以被应用在实现了ServletContextListener,ServletContextAttributeListener,ServletRequestListener,ServletRequestAttributeListener,HttpSessionListener和HttpSessionAttributeListener接口的类上。在下面的例子中,该类实现了ServletContextListener接口。 1. @WebListener 2. public class QuoteServletContextListener implements ServletContextListener { 3. public void contextInitialized(ServletContextEvent sce) { 4. ServletContext context = sce.getServletContext(); 5. context.setInitParameter(“default_market”, “NASDAQ”); 6. } 7. public void contextDestroyed(ServletContextEvent sce) { 8. } 9. } 复制代码 @MultipartConfig 使用@MultipartConfig注解来指定Servlet要求的multipart MIME类型。这种类型的MIME附件将从request对象中读取。 The Metadata and Common Annotations元数据与通用的注解 除了以上的Servlet特定的注解以外,Servlet3.0还支持JSR175(Java元数据规范)和JSR250(Java平台通用注解)所规定的注解,包括: * 安全相关的注解,如 @DeclareRoles 和 @RolesAllowed * 使用EJB的注解,如 @EJB 和 @EJBs * 资源注入相关的注解,如 @Resource 和 @Resources * 使用JPA的注解,如 @PersistenceContext, @PersistenceContexts, @PersistenceUnit, 和 @PersistenceUnits * 生命周期的注解,如 @PostConstruct和 @PreDestroy * 提供WebService引用的注解,如 @WebServiceRef and @WebServiceRefs 注解和web.xml哪一个会生效 注解的引入使得web.xml变成可选的了。可是,咱们仍是可使用web.xml。容器会根据web.xml中的metadata-complete元素的值来决定使用web.xml仍是使用注解。若是该元素的值是true,那么容器不处理注解,web.xml是全部信息的来源。若是该元素不存在或者其值不为true,容器才会处理注解。 Web框架的可插入性 咱们前面说过了Servlet3.0的改进之一就是使得咱们可以将框架和库插入到web应用程序中。这种可插入性减小了配置,而且提升了web应用程序的模块化。Servlet3.0是经过web模块布署描述片断(简称web片断)来实现插入性的。 一个web片断就是web.xml文件的一部分,被包含在框架特定的Jar包的META-INF目录中。Web片断使得该框架组件逻辑上就是web应用程序的一部分,不须要编辑web布署描述文件。 Web片断中使用的元素和布署文件中使用的元素基本相同,除了根元素不同。Web片断的根元素是<web-fragment>,并且文件名必须叫作web-fragment.xml。容器只会在放在WEB-INF\lib目录下的Jar包中查找web-fragment.xml文件。若是这些Jar包含有web-fragment.xml文件,容器就会装载须要的类来处理他们。 在web.xml中,咱们要求Servlet的name必须惟一。一样的,在web.xml和全部的web片断中,Servlet的name也必须惟一。 下面就是一个web-fragment的例子: web-fragment.xml 1. <web-fragment> 2. <servlet> 3. <servlet-name>ControllerServlet</servlet-name> 4. <servlet-class>com.app.control.ControllerServlet</servlet-class> 5. </servlet> 6. <listener> 7. <listener-class>com.listener.AppServletContextListener</listener-class> 8. </listener> 9. </web-fragment> 复制代码 框架的Jar包是放在WEB-INF\lib目录下的,可是Servlet3.0提供两种方法指定多个web片断之间的顺序: 1. 绝对顺序 2. 相对顺序 咱们经过web.xml文件中的<absolute-ordering>元素来指定绝对顺序。这个元素有之元素name,name的值是各个web片断的name元素的值。这样就指定了web片断的顺序。若是多个web片断有相同的名字,容器会忽略后出现的web片断。下面是一个指定绝对顺序的例子: web.xml 1. <web-app> 2. <name>DemoApp</name> 3. <absolute-ordering> 4. <name>WebFragment1</name> 5. <name>WebFragment2</name> 6. </absolute-ordering> 7. ... 8. </web-app> 复制代码 相对顺序经过web-fragment.xml中的<ordering>元素来肯定。Web片断的顺序由<ordering>的子元素<before>,<after>和<others>来决定。当前的web片断会放在全部的<before>元素中的片断以前。一样的,会放在全部的<after>元素中的片断以后。<others>用来代替全部的其余片断。注意只有当web.xml中没有<absolute-ordering>时,容器才会使用web片断中定义的相对顺序。 下面是一个帮助理解相对顺序的例子: web-fragment.xml 1. <web-fragment> 2. <name>WebFragment1</name> 3. <ordering><after>WebFragment2</after></ordering> 4. ... 5. </web-fragment> 复制代码 web-fragment.xml 1. <web-fragment> 2. <name>WebFragment2</name> 3. .. 4. </web-fragment> 复制代码 web-fragment.xml 1. <web-fragment> 2. <name>WebFragment3</name> 3. <ordering><before><others/></before></ordering> 复制代码 .. </web-fragment> 这些文件将会按照下面的顺序被处理: 1. WebFragment3 2. WebFragment2 3. WebFragment1 包含WebFragment3的Jar文件被最早处理,包含WebFragment2的文件被第二个处理,包含WebFragment1的文件被最后处理。 若是既没有定义绝对顺序,也没有定义相对顺序,那么容器就认为全部的web片断间没有顺序上的依赖关系。 Servlet中的异步处理 不少时候Servlet要和其余的资源进行互动,例如访问数据库,调用web service。在和这些资源互动的时候,Servlet不得不等待数据返回,而后才可以继续执行。这使得Servlet调用这些资源的时候阻塞。Servlet3.0经过引入异步处理解决了这个问题。异步处理容许线程调用资源的时候不被阻塞,而是直接返回。AsyncContext负责管理从资源来的回应。AsyncContext决定该回应是应该被原来的线程处理仍是应该分发给容器中其余的资源。AsyncContext有一些方法如start,dispatch和complete来执行异步处理。 要想使用Servlet3.0的异步处理,咱们须要设置@Webservlet和@WebFilter注解的asyncSupport属性。这个属性是布尔值,缺省值是false。 Servlet3.0的异步处理能够很好的和AJAX配合。在Servlet的init方法中,咱们可以访问数据库或从JMS读取消息。在doGet或doPost方法中,咱们可以启动异步处理,AsyncContext会经过AsyncEvent和AsyncListener来管理线程和数据库操做/JMS操做本身的关系。 已有API的改进 除了这些新特性以外,Servlet3.0还对以往已经存在的API作了一些改进。 HttpServletRequest To support the multipart/form-data MIME type, the following methods have been added to the HttpServletRequest interface: 为了支持multipart/form-data MIME类型,在HttpServletRequest接口中添加了项目的方法: * Iterable<Part> getParts() * Part getPart(String name) Cookies 为了不一些跨站点***,Servlet3.0支持HttpOnly的cookie。HttpOnly cookie不想客户端暴露script代码。Servlet3.0在Cookie类中添加了以下的方法来支持HttpOnly cookie: * void setHttpOnly(boolean isHttpOnly) * boolean isHttpOnly() ServletContext 经过在ServletContext中添加下面的方法,Servlet3.0容许Servlet或filter被编程的加入到context中: * addServlet(String servletName, String className) * addServlet(String servletName, Servlet servlet) * addServlet(String servletName, Class<? extends Servlet> servletClass) * addFilter(String filterName, String className) * addFilter(String filterName, Filter filter) * addFilter(String filterName, Class<? extends Filter>filterClass) * setInitParameter (String name, String Value) Servlet3.0新功能: 异步处理 J2EE 6和Glassfish 3V正式发布了,J2EE 6正式发布了Servlet3.0, 为了能更好的对WEB2.0提供支持, 3.0添加了异步处理的机制. HTTP1.1相对于HTTP1.0的影响. HTTP1.1最大的一个改变就是提供了长链接,这样HTTP再也不是一次请求,一次链接的协议了,只要HTTP的connection不关闭,一次HTTP链接能够支持任意屡次request/reponse处理. 当WEB Client与WEB Server创建链接时,客户端能够采用长链接,也就是说Client会一直保持对WEB Server的链接(例如:Browser对一个网站保持当链接,知道Browser关闭或最终退出该网站). 旧的WEB Server会为每个Http链接分配一个active的Thread,这样当Client的数量增大时,Server端Thread Pool的最大容量也须要相应增大,但Thread是至关耗内存的,一个不当心就会致使Server端NotEnoughMemory... 基于HTTP1.1,大部分支持Servlet2.X的WEB容器都采用的NIO去接收和处理请求. 当Client和Server端创建链接时,Server端并不分配一个Thread给HTTP链接.直到Server端收到Client端发送的Request时, Server才开始为该Request分配Thread(注意:这里不是为HTTP链接分配Thread). 这样当大量的Client创建长链接与Server进行交互时,Server无需维持一个Thread给inactive的HTTP长链接, 每一个Servlet在doReceived()时其实对应的是一个active Request,而不是HTTPConnection自己. 这样Server端所需的最大Thread数大大地减小了. AJAX的影响 1. Request的数量爆炸性增长增长 过去WEB Browser打开一个Web page,只须要和Web Server端创建一个HTTP链接.但AJAX技术出现之后,一个Web page上可能有多个与Web Server的链接,并且Ajax request一般是十分频繁的,Server接收到的Request数量大大增加了, 这样原先NIO的技术已经不能很好的支持基于Ajax的服务了. Servlet 3.0的异步处理就可以解决上面的问题. Servlet3.0的solution: 当request发送到Server端时,servlet的doReceived()将request放进一个queue里,而后doReceived结束.这个时候server并无关闭response,Client端一直在等server端response的内容. Server端维护本身的ThreadPool,当ThreadPool里有idle的Thread,就从queue里取出一个request,分配idle的Thread给request,并进行处理. Java代码 1. @WebServlet("/test" asyncSupported=true) 2. public class MyServlet extends HttpServlet { 3. ScheduledThreadPoolExecutor executor = null; 4. 5. public void init(ServletConfig arg0) throws ServletException { 6. executor = new ThreadPoolExecutor(10);//独立的线程池处理请求 7. } 8. public void doGet(HttpServletRequest req, HttpServletResponse res) { 9. ... 10. AsyncContext aCtx = request.startAsync(req, res); 11. executor.execute(new AsyncWebService(aCtx));//异步处理 12. } 13. } 14. 15. public class AsyncWebService implements Runnable { 16. AsyncContext ctx; 17. public AsyncWebService(AsyncContext ctx) { 18. this.ctx = ctx; 19. } 20. public void run() {//处理请求 21. //Do something here ... 22. 23. // Dispatch the request to render the result to a JSP. 24. ctx.dispatch("/render.jsp"); 25. } 26.} @WebServlet("/test" asyncSupported=true) public class MyServlet extends HttpServlet { ScheduledThreadPoolExecutor executor = null; public void init(ServletConfig arg0) throws ServletException { executor = new ThreadPoolExecutor(10);//独立的线程池处理请求 } public void doGet(HttpServletRequest req, HttpServletResponse res) { ... AsyncContext aCtx = request.startAsync(req, res); executor.execute(new AsyncWebService(aCtx));//异步处理 } } public class AsyncWebService implements Runnable { AsyncContext ctx; public AsyncWebService(AsyncContext ctx) { this.ctx = ctx; } public void run() {//处理请求 //Do something here ... // Dispatch the request to render the result to a JSP. ctx.dispatch("/render.jsp"); }} 以上的例子能够用于处理对Ajax的请求,由于一般Ajax的请求多,但对响应速度的要求并不过高. 对于正常的页面请求,要求必定的响应速度,能够沿用之前Servlet同步的实现. 2. Server端推送信息 在Web2.0的应用中, Ajax可用经过不断的发送Request来获取Server端某种信息的变化,但这种实现会产生大量的Client请求. 当前推荐的方法是,让Server端本身推送信息变化给Client. 由于Servlet3.0提供了异步处理的方式, Request提交给Server之后, Server能够为Request注册一个Listener,由Listener去monitor信息的变化,当信息发生变化时,由Listener负责把信息变化发送给Cient(Listener关闭HTTP response).