Servlet3.0新特性剖析

jopen 11年前

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应用程序模块化而易于维护。通过webfragment实现的可插入性减轻了开发人员的负担,不需要再在web.xml中配置很多的Servlet入口。


Asynchronous Processing 异步处理
另外一个显著的改变就是Servlet3.0支持异步处理,这对AJAX应用程序非常有用。当一个Servlet创建一个线程来创建某些请求的时候,如查询数据库或消息连接,这个线程要等待直到获得所需要的资源才能够执行其他的操作。异步处理通过运行线程执行其他的操作来避免了这种阻塞。


Apart from the features mentioned here, several other enhancementshave been made to the existing API. The sections towards the end ofthe 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属性是必须指定的。
例如我们可以象下面的例子这样定义:

    @WebServlet(name = "GetQuoteServlet", urlPatterns = {"/getquote"})        public class GetQuoteServlet extends HttpServlet {        @Override        protected void doGet(HttpServletRequest request,HttpServletResponse response)        throws ServletException, IOException {        PrintWriter out = response.getWriter();        try {        String symbol = request.getParameter("symbol");        out.println("<h1>Stock Priceis</h1>" +StockQuoteBean.getPrice(symbol);        } finally {        out.close();        }        }        }                public class StockQuoteBean {        private StockQuoteServiceEntity serviceEntity = newStockQuoteServiceEntity();        public double getPrice(String symbol) {        if(symbol !=null ) {        return serviceEntity.getPrice(symbol);        } else {        return 0.0;        }        }        }  
在上面的例子中,一个Servlet只对应了一个urlPattern。实际上一个Servlet可以对应多个urlPattern,我们可以这样定义:
    @WebServlet(name = "GetQuoteServlet", urlPatterns = {"/getquote","/stockquote"} )        public class GetQuoteServlet extends HttpServlet {        @Override        protected void doGet(HttpServletRequest request,HttpServletResponse response)        throws ServletException, IOException {        PrintWriter out = response.getWriter();        try {        String symbol = request.getParameter("symbol");        out.println("<h1>Stock Priceis</h1>" +StockQuoteBean.getPrice(symbol);        } finally {        out.close();        }        }        }                        @WebFilter        我们可以使用@WebFilter注解来定义filter。这个注解可以被应用在实现了javax.servlet.Filter接口的类上。同样的,urlPattern属性是必须指定的。下面就是一个例子。                @WebFilter(filterName = "AuthenticateFilter", urlPatterns ={"/stock.jsp", "/getquote"})        public class AuthenticateFilter implements Filter {                public void doFilter(ServletRequest request, ServletResponseresponse,        FilterChain chain) throws IOException, ServletException {        String username = ((HttpServletRequest)request).getParameter("uname");        String password = ((HttpServletRequest)request).getParameter("password");        if (username == null || password == null) {        ((HttpServletResponse) response).sendRedirect("index.jsp"); }        if (username.equals("admin") && password.equals("admin")){        chain.doFilter(request, response); }        else {        ((HttpServletResponse) response).sendRedirect("index.jsp"); }        }                public void destroy() {        }        public void init(FilterConfig filterConfig) {        }        }  
@WebInitParam
可以使用@WebInitParam注解来制定Servlet或filter的初始参数。当然我们也可以使用@WebServlet或@WebFileter的initParam属性来指定初始参数。下面是使用@WebInitParam的例子:
    @WebServlet(name = "GetQuoteServlet", urlPatterns ={"/getquote"})        @WebInitParam(name = "default_market", value = "NASDAQ")        public class GetQuoteServlet extends HttpServlet {        @Override        protected void doGet(HttpServletRequest request,HttpServletResponse response)        throws ServletException, IOException {        response.setContentType("text/html;charset=UTF-8");        PrintWriter out = response.getWriter();        try {        String market = getInitParameter("default_market");        String symbol = request.getParameter("symbol");        out.println("<h1>Stock Price in " +market + " is</h1>" +StockQuoteBean.getPrice(symbol, market));        } finally {        out.close();        }        }        }  
下面是使用initParam属性的例子:
    @WebServlet(name = "GetQuoteServlet",        urlPatterns = {"/getquote"},        initParams={@WebInitParam(name="default_market",value="NASDAQ")}        )        public class GetQuoteServlet extends HttpServlet {        @Override        protected void doGet(HttpServletRequest request,HttpServletResponse response)        throws ServletException, IOException {        response.setContentType("text/html;charset=UTF-8");        PrintWriter out = response.getWriter();        try {        String market = getInitParameter("default_market");        String symbol = request.getParameter("symbol");        out.println("<h1>Stock Price in " +market + " is</h1>" +StockQuoteBean.getPrice(symbol, market));        } finally {        out.close();        }        }        }  
@WebListener
@WebListener注解被应用在作为listener监听web应用程序事件的类上,所以@WebListener能够被应用在实现了ServletContextListener,ServletContextAttributeL
istener,ServletRequestListener,ServletRequestAttributeListener,HttpSessionListener和HttpSessionAttributeListener接口的类上。在下面的例子中,该类实现了ServletContextListener接口。
    @WebListener        public class QuoteServletContextListener implementsServletContextListener {        public void contextInitialized(ServletContextEvent sce) {        ServletContext context = sce.getServletContext();        context.setInitParameter(“default_market”, “NASDAQ”);        }        public void contextDestroyed(ServletContextEvent sce) {        }        }  
@MultipartConfig
使用@MultipartConfig注解来指定Servlet要求的multipartMIME类型。这种类型的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,容器才会处理注解。