JavaEE中的依赖性——依赖查找

关于依赖性管理我们要介绍的第一个策略就是依赖查找(dependency lookup)。这种策略是JavaEE中传统形式的依赖性管理,这里可以看到JavaEE规范中的JNDIJava Naming andDirectoryInterface)的身影。从名字就可以看出来这里解决依赖性是通过查找的方式。

就像上篇文章提到的,所要引用的资源是通过一对nametarget对应的注解标识的。name用来表明此资源被依赖时候的名字,所以当资源注解放在类定义之上的时候需要为其起个名字。但是如果资源注解放在一个字段或者一个setter方法之上那么将不需要为其起名字。一般情况下当使用依赖查找时,注解是放在类上的,并且显式的指定名称。将注解放置在一个字段或者setter方法上的使用方式下一篇博客再讨论。

指定name的作用是为调用者动态的解析引用提供便利。因为JNDIJavaEE的规范所以所有的JavaEE应用服务器都会支持JNDI,而且对于每个组件来说都有其自己局部范围的JNDI命名上下文,称为环境命名上下文。当通过JNDI查找某个资源的时候就是在其环境命名上下文中根据预先定义好的名称进行查找。下面代码就掩饰了如何运用依赖查找为一个EJB组件进行服务的。

@Stateless
@EJB(name="audit", beanInterface=AuditService.class)
public class DepartmentServiceBean implements DepartmentService {
    private AuditService audit;
    
    @PostConstruct
    public void init() {
        try {
            Context ctx = new InitialContext();
            audit = (AuditService) ctx.lookup("java:comp/env/audit");
        } catch (NamingException e) {
            throw new EJBException(e);
        }
    }

    public void performAudit() {
        audit.audit();
    }
    
    // ...
}

可以看到DeptServiceBean是一个会话bean。它使用@EJB注解声明了一个会话bean的依赖性,并把其命名为“audit”。@EJB注解的beanInterface元素引用了这个会话bean中需要的业务接口(AuditService)。在init方法中查找并得到了相应的资源,其中ContextIitialContext接口都是JNDI所定义的。Context接口的lookup()方法是用于从JNDI上下文检索对象的主要方法。为了找到命名为“audit”的引用,应用程序将查找名称“java:comp/env/audit”,并把结果转换到AuditService业务接口。添加到引用名称的前缀“java:comp/env”指示服务器应该使用环境命名上下问来搜索和发现引用。如果制定了错误的名称,那么当查询失败时将会抛出一个异常。

JNDI这种方式解决依赖性问题是通用的,只要符合JavaEE标准那么就可以使用这种查找的方式找到自己关心的接口(其实最终干活的是实现)但是这种查找资源的方法有些繁琐,类似于家里着火了再去买消防器材(为什么不提前买好呢?这是我们下一篇博客要说的)。

除了上面代码中使用Context接口的lookup方法,EJB还可以使用EJBContext接口(以及它的子接口)的lookup方法。这样就可以在程序运行时访问其中的服务(计时服务?)下面的代码就演示了这种方式的lookup方法。

@Stateless
@EJB(name="audit310", beanInterface=AuditService310.class)
public class DepartmentServiceBean310 implements DepartmentService310 {
    // use of resource dependency injection is covered later in the chapter
    @Resource SessionContext context;
    AuditService310 audit;

    public void setSessionContext(SessionContext context) {
        this.context = context;
    }
    
    @PostConstruct
    public void init() {
        audit = (AuditService310) context.lookup("audit310");
    }

    public void performAudit() {
        audit.audit();
    }
    
    // ...
}

尽管网上很多人说相比JNDIAPIEJBContext lookup()方法有优势。首先方法的参数恰好是在资源引用中指定的名称,不用再写第一部分代码中奇怪的字符串了。其次是关于异常的处理,显而易见第二种方式中异常已经不用我们手动处理了,因为第二种方法直接抛出运行时异常。其实在容器内部还是会像第一种方法那样去调用JNDI API去查找,但是容易已经为我们处理了异常,这就导致第二种方式看上去好像不用处理以上了似的。在笔者看来这两种方式都不是最适合我们的方式,就如同上面的举得例子,着火了才想着去买消防器材,为什么不提前买好呢?这就是我们下一篇博客要介绍的另一种解决依赖性的策略——依赖性注入。

阅读更多
换一批

没有更多推荐了,返回首页