Java EE6 Weld(1): 上下文、依赖注入和限定词

 一、Weld简介

    Java EE 6.0 的核心:JSR-299规范,提供了如下功能:

        1. 类型安全的依赖注入
        2. 注入对象的上下文生存周期管理
        3. 事件提醒模型
        4. 绑定拦截器通过用户自定义的注解(Annotation)
        5. 类型安全的装饰器
        6. 为整合第三方框架提供了完整的 SPI 支持
        7. 与 JSF,Servlet / JSP 进行了整合
        8. 对 JSF 提供长会话(Conversation)上下文支持

    Weld 是一个实现了 JSR-299 的框架。主要由JBoss完成其实现,项目主页: http://www.seamframework.org/Weld 。最新发布了  Weld 2.0.0.Alpha1 版本。

    Weld 工程的搭建是非常简单的, 这里介绍一下 Weld+JSF 在 Tomcat 7.x 中的工程搭建的方法:
    1)通过Eclipse 直接建立一个 Dynamic Web Project , Runtime 选择 tomcat7 , Servlet 版本选择3.0 。
    2)添加所需jar文件:由于 tomcat 是非 servlet 容器,所以要加入  weld-servlet.jar 。   还有JSF 的  jsf-api.jar  , jsf-imp.jar  和 jstl-1.2.jar 
    3)在web.xml 添加监听器来启动weld
    

      org.jboss.weld.environment.servlet.Listener
   
    4)在META-INF下,添加context.xml 为tomcat容器JNDI绑定 BeanManager。 
 
    
         auth="Container"
      type="javax.enterprise.inject.spi.BeanManager"
      factory="org.jboss.weld.resources.ManagerObjectFactory"/>
   
   
    5)在web.xml中,声明注册这个绑定
 
      Object factory for the CDI Bean Manager
      BeanManager
      javax.enterprise.inject.spi.BeanManager
   
    6)在WEB-INF下面,放一个空的bean.xml

    在非jee6 或者 非servlet容器下,都需要这样配置的。在Jboss as7中就要简单的多,只需要加入 cdi-api.jar 跟一个 bean.xml  其他的地方就是jsf的一些配置。

    

二、上下文(Context)

    
    Weld 中有5个上下文范围的容器:Request、Session、Application、Dependent 和 Conversation。前面3个就不再介绍了,他们的注解分别为@RequestScoped @SessionScoped @ApplicationScoped 。JSR299中参照了Seam,加入了一个新的会话范围 Conversation
    @Dependent  默认范围,所有没有定义的上下文范围的Class或者Interface 具有这个默认的注解。用EL表达式每次应用一个Dependent范围的bean容器都会重新实例化一个。所以不要用EL应用Dependent范围的bean。每次注入这个范围的bean的时候,容器都会new一个新的实例给注入点。
    @Conversation 可以叫它对话范围,它的范围比Request大,一个Conversation里面可以包含多个Request,比Session范围小。 需要注意的一点,Conversation范围和Session范围的bean会被持久化到你的磁盘上,从而节省你的内存,所以在使用这两个范围的bean的时候需要实现序列化接口(Serializable)。
    在实际应用中,Conversation一般用于使用多个页面来做一件事情,相关的对象不会丢失。但是,Conversation范围并不是它的对象放在Session中,只是在HttpSession这个对象中存放了一个id。
    Conversation 可以分为短对话和长对话两种情况。对于一般的Conversation,它的持续时间是跟Request一样的,并没有太大的区别。下面的方式就可以把一个短对话变成长对话。

1 @Inject
2 Conversation conversation;
3 public void start(){
4     conversation.start();
5     conversation.setTimeout(30000);//5分钟,默认10分钟
6 }
    

三、依赖注入 @Inject

    JSR299 借鉴了现在很流行的依赖注入,自己通过注解也实现了依赖注入,无需像Spring那么多的配置文件。

    weld 的三个注入点:
        1. 构造方法参数:如果在一个bean的构造函数上加上@Inject注解,那么它的参数都是通过依赖注入传入的。也可以把@Inject放在形参的前面。
        2. 初始化方法参数:如果一个方法上有@Inject注解,它不是构造函数的话,上面这中情况,那么这个方法就是 初始化方法  。初始化方法总是会在构造函数之后执行,注入他的参数。
        3. 类属性: 这也是最常用的一种方法,类似与seam2中 @in 。

    下面分别给出这3中情况的例子
@Inject
public HelloAction(CurrentUser user){
}
@Inject
public void sayHello(CurrentUser user){
   System.out.println("Hello, "+user.getName());
}
@Inject
Logger logger;

四、限定词 @Qualifier

    
     我们一般在注入service层的bean的时候,一般会直接注入一个接口,而不是它的实现类。限定词的作用主要用于区分一个接口的不同实现。
    weld 中有两个默认的限定词 @Default 和 @Any:  
        @Default  : 默认限定词,如果一个注入点没指定特定的限定词,那么它就默认使用@Default这个限定词。
        @Any: 如果你一个接口有多个实现类,不同的实现类你使用了不同的限定词来区分,那么 @Any 就可以修饰所有的实现。
   一般情况,需要我们自己定义个注解:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE,Element.METHOD,ElementType.FIEID,ElementType.PARAMENTER)
public @interface Morning{}
    @Qualifier 说明这个新定义的注解是一个限定词。
    @Retention 表明这个注解什么时候作用,一般都是写 RUNTIME
    @Target 表明这个注解可以在什么地方使用,上面的定义分别是 类名上,方法上,属性,参数
    
@Inject @Morning HelloAction helloAction;

    如果一个接口有很多个实现类的话,我们也不需要为每个实现类定义一个注解。我们可以给一个注解加个参数,通过这个参数来指定注入哪个实现类。 
    只需要在个实现类之前加上这个限定词,那么在注入这个接口的时候,就会自动注入这个实现类了。   
@Morning
public class MorningHelloAction Implements HelloAction{
    ...
}
    一个bean如果实现了多个接口,那么只要添加多个限定词就可以了。
    使用了限定词,这样在使用一个接口的时候,我现在不需要关心这个接口实现类的类名,只要你的实现类加了这个限定词,在注入的时候就会自动找到这个类注入进来。这样可以大大的降低了耦合性。


 



Rogue 2012-02-23 23:26 发表评论

你可能感兴趣的:(java,ee6,weld)