關於依賴性管理我們要介紹的第一個策略就是依賴查找(dependency lookup)。這種策略是JavaEE中傳統形式的依賴性管理,這裏可以看到JavaEE規範中的JNDI(Java Naming andDirectoryInterface)的身影。從名字就可以看出來這裏解決依賴性是通過查找的方式。
就像上篇文章提到的,所要引用的資源是通過一對name與target對應的註解標識的。name用來表明此資源被依賴時候的名字,所以當資源註解放在類定義之上的時候需要爲其起個名字。但是如果資源註解放在一個字段或者一個setter方法之上那麼將不需要爲其起名字。一般情況下當使用依賴查找時,註解是放在類上的,並且顯式的指定名稱。將註解放置在一個字段或者setter方法上的使用方式下一篇博客再討論。
指定name的作用是爲調用者動態的解析引用提供便利。因爲JNDI是JavaEE的規範所以所有的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方法中查找並得到了相應的資源,其中Context和IitialContext接口都是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();
}
// ...
}
儘管網上很多人說相比JNDIAPI,EJBContext lookup()方法有優勢。首先方法的參數恰好是在資源引用中指定的名稱,不用再寫第一部分代碼中奇怪的字符串了。其次是關於異常的處理,顯而易見第二種方式中異常已經不用我們手動處理了,因爲第二種方法直接拋出運行時異常。其實在容器內部還是會像第一種方法那樣去調用JNDI API去查找,但是容易已經爲我們處理了異常,這就導致第二種方式看上去好像不用處理以上了似的。在筆者看來這兩種方式都不是最適合我們的方式,就如同上面的舉得例子,着火了纔想着去買消防器材,爲什麼不提前買好呢?這就是我們下一篇博客要介紹的另一種解決依賴性的策略——依賴性注入。