Servlet3.0新规范(JSR-135)沉思(一) by Roy van Rijn

rel="File-List" href="file:///C:%5CDOCUME%7E1%5CFANZHE%7E1.MEN%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C05%5Cclip_filelist.xml">

介绍

所有的Java Web应用都在使用Servlets 和 Filters,因为它们是连接www网的大门,是Java EE的基础设施,也可以说是Java EE的骨架。

新规范Servlet3.0(JSR-315)马上就要出台了。规范的起草方案中确实包含了一些非常显眼的特性,但以我看来,有些似乎是错误。下面的内容我将依次介绍这些有利于编程的特性,对它们进行评论,并试着改进它门。

Servlets

自从有了Servlet2.3规范,我们就一直使用Servlet提供的接口创建自己的Servlet类。接口提供了像service()这样的重要方法,当然还有ServletRequest 和ServletResponse对象。而抽象类HttpServlet提供了对HTTP协议的支持,它含有像doGet和doPost这样的方法。

创建一个一般的Servlet,只需继承HttpServlet类,并重写你自己的doGet或doPost方法就可以了。下面是实现时的代码片段。

public class GetPostServlet extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)

    throws ServletException, IOException {

     ....

        }

}

当然,你需要在一个叫做web.xml的文件中,添加对这个Servlet的描述,来通知容器你新增加了一个Servlet。web.xml中包含了URL与Servlet间的映射,所以当有用户请求URL的时候,Servlet将会被调用,用来对请求做出响应。

JSR-315

Servlet 3.0 有几个提议性的改动。最大的改变就是增加了“内建”(continuations)的支持。可以通过调用新Servlet3.0API中的request.suspend()方法悬挂请求,稍后调用request.resume()方法在另一个线程接着处理请求。

第二个重要的特征是,支持即插即用的特性,Servlets能在容器运行期间,动态地被添加到容器中。 容器运行期间,你可以通过创建了一个ServletContextListener实例,调用servletContext.addServlet()和servletContext.addServletMapping()方法将Servlets动态添加到容器中。当然,这会带来一些安全隐患,因为工程里被包含的JARS可能会创建一些你不想定义的Servlets。但是新规范注意到了这些问题,并解决了它们。(比如,新规范提供了关闭自动Servlets注册的开关。)

新增加了注解是Servlet3.0的第三个特征。下面展示了新注解的使用:

@Servlet(urlMapping={"/myServlet"}, name="MyServlet")

public class PojoServlet() {

  @GET

  public void handleGet(HttpServletRequest req, HttpServletResponse resp) {

     ....

  }

}

正如你看到的,新规范确实添加了些新的东西。首先现在的Servlet是简单的POJO,省去了接口和抽象类。其次,注意到@Servlet注解中的url属性了没,这样就不用在web.xml对Servlet做映射了。

接下来我们看看过滤器的例子:

@ServletFilter

@FilterMapping(urlPatter="/myFilter")

public class PojoFilter() {

  public void doFilter(HttpServletRequest req, HttpServletResponse resp) {

     ....

  }

}

过滤器也使用了新的注解,又一次在注解中做映射,省去了web.xml中的配置,POJO实现方式,没有接口没有抽象类。

问题在那里?

也许你会问,这些有利于开发的提议有什么错误呢?呵呵,也许存在一些问题。不管怎么说,首先让我们来看看有这些新注解带来了什么改变。

  • 映射信息写在了Servlet中
  • Servlet变成了POJO’s
  • 可以定义某些方法来捕捉GET和PUT请求

好吧,首先说在Servlet中做映射是个不错的想法,尽管注解的命名有些出乎意料。 但是,为什么@Servlet注解自包含了映射信息,而@ServletFilter注解与@FilterMapping 注解分开使用?用一种统一的方式声明映射信息,恐怕要更清晰一些吧。

第二、三个改变只是提供了一点编程的便利,可以用@GET、@POST、@HEAD、@PUT声明式地描述GET和POST.一些人可以用注解声明的方式编写Servlet了而不是用以前的方法:

public class GetPostServlet extends HttpServlet {

  public void doGet(HttpServletRequest req, HttpServletResponse res)

    throws ServletException, IOException {

    handleRequest(req,res);

  }

  public void doPost(HttpServletRequest req, HttpServletResponse res)

    throws ServletException, IOException {

    handleRequest(req,res);

  }

 

  /* Handle GET and POST */

  public void handleRequest(HttpServletRequest req, HttpServletResponse res)

    throws ServletException, IOException {

    ....

  }

}

用上注解可以省去一些代码,编程变的容易了些:

@Servlet

public class GetPostServlet {

  @GET

  @POST

  public void handleRequest(HttpServletRequest req, HttpServletResponse res)

    throws ServletException, IOException {

    ....

  }

}

是的,这里没有什么不对的。但是,我会问是否能将两个注解同时应用在一个方法上呢?这样做也许违背了规范的初衷。还有,这也给编码带来了一些问题,例如,如果按我下面这样编码:

@Servlet

public class GetPostServlet {

  @GET

  public void requestOne(HttpServletRequest req, HttpServletResponse res)

    throws ServletException, IOException {

    ....

  }

  @GET

  public void requestTwo(HttpServletRequest req, HttpServletResponse res)

    throws ServletException, IOException {

    ....

  }

}

这样那个方法会被调用,我不知道!这些都没有在规范里面做相应的说明,类似地问题,两个不同的Servlet映射在同一个URL上。不能预测这样做会发生什么,如何操作将依赖于容器。

这些新注解本意是方便开发者做开发,现在看来,却存在一些问题。集成开发工具不会因为POJO中添加了@Servlet注解,而意识到你在创建一个Servlet,所以它不会自动生成相应的东西。当我们使用接口或者抽象类的时候,我们只需实现或重载一些方法就可以了,有相当一部分代码是自动生成的。而这种便利性将会随着我们应用了注解而消失。

如果你仔细的观察@ServletFilter注解,会发现更糟糕的事情。当你把@ServletFilter应用于某个POJO的时候,它只是把这个POJO变成了一个过滤器,但是并没有检查是否实现了过滤器的doFilter()方法。还有,很有可能把doFilter意外地写错成别的什么东西。

@ServletListenerContext注解也会发生同样的事情,看看下面的例子吧:

@ServletContextListener

public class MyListener {

  public void contextInitialized(ServletContextEvent sce) {

     ....

  }

}

又一次,“contextInitialized“(一个非常不好写的单词,每次不检查拼写错误保证输入正确显的有些困难)不会被检查是否拼写错误,你必须人工地双击选中检查。我宁愿实现ServletContextListener让集成开发环境帮我生成要实现的方法,而不会去使用@ServletListenerContext注解。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值