Servlet3.0規範的新特性主要是爲了3個目的: html
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屬性是必須指定的。
例如咱們能夠象下面的例子這樣定義:java
1. @WebServlet(name = "GetQuoteServlet", urlPatterns = {"/getquote"} )web
2. public class GetQuoteServlet extends HttpServlet {數據庫
3. @Override編程
4. protected void doGet(HttpServletRequest request, HttpServletResponse response)安全
5. throws ServletException, IOException {cookie
6. PrintWriter out = response.getWriter();app
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)