Java EE 6 之 Servlet 3.0

sulong 于 2010-02-27 没有评论 »

Servlet之所以没有像之前的ejb那样被受到那么多的诟病,是因为servlet的设计确实非常好。在最新的Java EE6版本里,这么多年都没有多少重大改动的Servlet终于添加了很多新的功能。下面我们一个一个来看

1. 基于annotation的配置

自从java 5增加了annotation后,现在annotation已经广范用于各种框架,确实减少了很多的编写配置文件的工作。现在终于可以不用写web.xml,只要通过WebServlet, WebFilter, WebListener这几个annotation就可以轻易的配置Servlet, filter和listener了。而且, web.xml已经是可选的了,就算没有它,也一样运行。

2. 异步请求处理

Servlet 3.0 新添加了一个类AsyncContext,可以通过ServletRequest活得。如果调用了ServletRequest的startAsync(),那么这个请求将会被异步处理,这意味着即使当前的线程执行结束,也不会给发送会响应,而是要等到AsyncContext的complete()方法被调用。通过AsyncContext,一样可以取到ServletRequest,和ServletResponse对象,这意味着即使最初Servlet执行的线程执行结束,也一样可以取到那次请求数据和返回客户端数据。

在通常的Servlet设计中,servlet容器会为每个客户端的请求分配一个线程,如果处理请求的过程中需要等待某种很慢的资源,在访问量大的时候,可能导致servlet容器的线程池耗光,从而无法响应后续的请求。有了异步处理的servlet之后,可以将这些线程解放出来,把它们放到一个队列里等待。比起线程,普通的对象还是要占用较少资源的。

3. Web Fragments

Web容器加载的时候,会扫描WEB-INF/lib下的jar, 如果这个jar的有META-INF/web-fragment.xml,那这这个web-fragment.xml内的配置信息也会被使用。这个功能对做web框架很有用。很多web框架都是通过自定义自己的servlet, filter或listener实现的,现在,框架的开发者可以将默认的配置放到自己的jar里,使用者只要把jar丢到WEB-INF/lib/目录下就可以使用框架了,更加方便。通过web-fragment, 可以更容易的对一个war实现部署上的模块化。

4. 动态注册Web application组件

这个功能的意思是指,应用程序可以在运行时注册servlet, filter和listener。ServletContext里多了addFilter(), addServlet()等方法,来给用户调用。很奇怪的是,我只看到注册组件的,没有看到注销组件的,如果只能加不能减的话,那这一功能估计只能看作是通过xml配置的另一种方法。

5. 容器启动回调

如果WEB-INF/lib下有某个jar文件包含META-INF/services/javax.servlet.ServletContainerInitializer文件,且该文本文件内的类名所对应的类实现了javax.servlet.ServletContainerInitializer接口,那么这个类所实现的该接口方法会在容器启动时被调用。 这个接口方法是onStartup(java.util.Set> c, ServletContext ctx) , 其中c是一个类的集合。你必须在这个方法上使用HandlesTypes annation,这个annotation会指定一些类,而所有实现了,集成了或标注了这个些类的类会做成一个结合作为参数传给onStartup方法。说起来复杂,写起来简单:

@HandlesTypes({A.class})
public void onStartup(Set<Class<?>> c, ServletContext ctx){
   //
}

对于上面的例子,c集合里的类要么实现了A,要么集成了A,要么标注了A。
看来这个功能还是为了自定义框架用的。

6. 自定义session cookie

以前Session cookie的名字一般固定为JSESSIONID,现在通过ServletContext可以获得SessionCookieConfig对象,而该对象可以让我们自定义session cookie的名字等属性。

7. multipart支持

编写接受上传文件的程序更容易了,通过HttpServletRequest对象可以获得Part对象,每一个Part代表了上传的一个文件。调用Part.write(String)方法,可以很轻松的把上传的文件保存为参数指定的文件名。

结论

可以看出,这些更改,都无疑使Servlet编程更容易更灵活了。所以还是很期待能在项目中使用Servlet 3.0 。

  • Share/Bookmark

为什么POST比GET安全?

sulong 于 2010-02-24 2 篇评论 »

如果不通过SSL加密,GET和POST方法都会把数据以明文方式发送到服务器上,安全性相差无几。

说POST比GET安全,有如下几点理由:
1, GET请求的数据会被浏览器作为URL的一部分而保存
2, 服务器端的访问日志等一般都会记下URL
3, HTTP头部的referer里会记下URL里请求数据

总之一般人都认为URL里不会包含敏感数据的,所以你最好也不要把敏感数据放到URL里,这种场合自然不适合使用GET。

  • Share/Bookmark

用hibernate映射时遇到的问题

sulong 于 2010-01-21 3 篇评论 »

对象和关系型数据库之间存在着根本不同, ORM(对象/关系映射)试图把对象映射到关系型数据库的表结构上,从而简化存储对象到数据库及从数据库中恢复对象的复杂性,让操作数据库就像操作对象一样简单。Hibernate估计是众多ORM框架中最成熟的了,但是在处理类的继承关系时还是会有一些问题。

延迟加载与继承
先看如下的代码, 演示这一映射关系:

@Entity
@Table(name = "a")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
        name = "disc",
        columnDefinition = "varchar(4)",
        discriminatorType = DiscriminatorType.STRING)
public abstract class A {
 @Id
 private int oid;
 private String name;
}

@Entity
@DiscriminatorValue("b")
public class B extends A {
private String age;
}

@Entity
@DiscriminatorValue("c")
public class C extends B {
private String sex;
}

@Entity
@Table(name = "d")
public class D {
  @Id
  private int oid;
  @ManyToOne(fetch = FetchType.LAZY)
  private A a;
  public A getA() {return a}
}

当查询 D类时,应为 D.a 是延迟加载的,所以没有查询过 a表,自然就不知道该记录对应的disc为什么值,也不知道A具体是哪种子类类型。但是查询出的d对象,如果 d.a != null d.a必须有值。Hibernate会生成一个A的子类,并用它的实例作为 d.a 当你真的要访问 d.a 的方法或域时,hibernate才会真正的去查询 a 表。 这其实就是hibernate实现延迟加载的原理。但在本例中,如果你执行如下代码就会遇到 ClassCastException,

D d = session.load(D.class, 1);
C c = (C) d.getA(); //即使d.getA()确实是C类型,也会ClassCastException

hibernate生成的是A的子类,而不是B或C的子类,所以在类型转换的时候出错了。要解决这一问题,要么不要用延迟加载, 但是性能上面很可能出问题;要么不要用继承,向下面这样:

@Entity
@Table(name = "a")
public abstract class A {
 @Id
 private int oid;

 private String name;
 private String age;
 private String sex;
}

@Entity
@Table(name = "d")
public class D {
  @Id
  private int oid;
  @ManyToOne(fetch = FetchType.LAZY)
  private A a;
  public A getA() {return a}
}

这样实际上是限制OO的能力;要么每次都显示的重新查询改对象,向这样:

D d = session.load(D.class, 1);
C c = session.load(C.class, d.getA().getOid()) //重新查,指明类型

这样做既不方便,又不OO。

看来要想让hibernate的映射类保持对象的特性,还是有些困难的。很多时候,这些映射类最终就变成了只负责映射功能的数据库表对象了

  • Share/Bookmark

让JAXB生成序列化的类

sulong 于 2009-11-20 没有评论 »

默认jaxb生成的类是没有序列化的,但是我们经常需要他们序列化。jaxb ri有生成序列化的类的这样的功能,但由于这不属于标准的功能,所以需要手动的开启。开启的方法是在用来生成java类的xml schema文件头添加如下内容:

<annotation>
    <appinfo>
        <jaxb:globalBindings generateIsSetMethod="true">
            <xjc:serializable uid="1"/>
        </jaxb:globalBindings>
    </appinfo>
</annotation>

另外,在使用jaxb的 xjc 编译器时,要加上 -extension 的参数。

  • Share/Bookmark