西元2006年07月17日

Struts Action get Resource by Injection

http://www.codecomments.com/archive419-2006-6-954408.html

Craig McClanahan:

A couple of possibilities come to mind ...

* Inject the resource into a container-instantiated object
(like a servlet), and modify your framework to copy values
in when it creates, say, an Action instance in the Struts case.
BIG PROBLEM: thread safety ... the servlet instance is shared
across all threads, so the variable would get stomped on if there
was more than one simultaneous request.

* Modify your framework to scan for the injection annotations itself
when it creates new object instances, and perform the same kinds
of injection that the container can do.

* Use a dependency injection framework that knows how to initialize
properties from JNDI lookups, and configure it to look up the
corresponding resources.

* Use the managed beans portion of JSF (even if you are not using
the rest of it) as a dependency injection framework, and let the
container go ahead and do the injection for you. (If you're using
an additional framework, it would need to be modified to use
managed beans to create object instances, instead of doing
Class.newInstance() things itself).

Craig



換句話說, Application Server 決定了是否可以 inject 相關的 Resource 到你的系統之中,
如果該 Application Server 並沒有支援 Struts Action 或其他 Framework,
就等於即使你的系統也在 Java EE 5.0 的環境中執行 ~~
也得使用 JNDI lookup 去取得相關的 Resource,

假設仍然使用習慣的 Framework, 就不會修改相關原始碼去掃描 Annotations.
應該也不會另外找個 DI Framework 來增加 Framework 的複雜度吧..
難道 大家都要被迫學習 JSF ?!

看來.. 在 Web-tier 利用 InjectionFilter or InjectionInitServlet 先取得相關資源
例如 DataSources, EntityManager 放到 SessionScope 或 ApplicationScope ?
應該是比較可行的方案了..

西元2006年07月16日

Interceptor 與 inv.proceed() 的關係

寫了一個小程式測試了一下, @Interceptors 他的操作方式

@Stateless
@Interceptors({AuditInterceptor.class, SecurityInterceptor.class})




public class AuditInterceptor {
@AroundInvoke public Object auditOperation(InvocationContext inv)
throws Exception {
try {
System.out.println("audit "+inv.getMethod().getName());
Object result = inv.proceed();
System.out.println("test after proceed");
return result;
} catch ( Exception ex ) {
throw ex;
} finally {
System.out.println("finally end message");
}

}
}




import javax.interceptor.*;
public class SecurityInterceptor {
@AroundInvoke public Object securitySome(InvocationContext inv)
throws Exception {
try {
System.out.println("security"+inv.getMethod().getName());
Object result = inv.proceed();
System.out.println("test after proceed in security");
return result;
} catch ( Exception ex ) {
throw ex;
} finally {
System.out.println("Final in security");
}

}

}




執行的結果是


audit getHello|#]

securitygetHello|#]

Hello in getHello()|#]

test after proceed in security|#]

Final in security|#]

test after proceed|#]

finally end message|#]

換句話說, 當我們透過 InvocationContext proceed 之後,
會將 process 指到下一個 Interceptor
當沒有下一個 Interceptor 的時候

就會到了 Bean Method() 的操作

等到 Bean Method() 結束之後
才會開始處理 proceed 之後的功能
一直等到你執行 reutnr Object ( inv.proceed() ) .

雖然 return 該 Object ( inv.proceed() ) 之後,
我們也可以利用 finally 來處理最後的相關事務

11:25 發表於 EJB3 | 永久網址 | 留言 (0) | Email this

西元2006年07月10日

Interceptor 攔截 basic concept



EJB3 為了可以支援 AOP ( swanky : AOP Presentation - http://www.ice.ntnu.edu.tw/~swanky/presentation/PL_AOP.pdf )
所以建立了Interceptors 的觀念.

不過, 雖然是放在 ejb3 api 的製作之中, 但是他的 package 為 javax.interceptor.*, 換句話說, 未來有機會可能會移出 ejb-api .

其實, 熟稔 AOP 概念的人 ( AspectJ, AspectWerkz ) 通常會對於 EJB3 目前僅提供 Interceptor 實作的方法, 覺得比較陽春.
但是, 也可以這麼思考, 利用 Interceptor 應該就可以達到一般人的需求 !

在 Interceptor, 只有 InvocationContext Interface, 以及 四個 Annotation Types.
* AroundInvoke
* ExcludeClassInterceptors
* ExcludeDefaultInterceptors
* Interceptors

我們在呼叫任何一個 EJB Bean Class 的時候, 可以利用 @Interceptors 來設定

@Interceptors(MyCallbackHandler.class)
public class MyEJB {
....
}


或是利用 deployment descriptor ( ejb-jar.xml ) 來定義 interceptors


<ejb-jar>
<sessions>
...
</sessions>
<interceptors>
<interceptor>
<interceptor-class>com.softleader.interceptors.MyCallbackHandler</interceptor-class>
<pre-destroy>
<lifecycle-callback-method>someInteceptorMethod</lifecycle-callback-method>
</pre-destroy>
</interceptor>
</interceptors>
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>com.softleader.interceptors.MyCallbackHandler</interceptor-class>
</interceptor-binding>
<interceptor-binding>
<ejb-name>SlessEJB</ejb-name>
<exclude-default-interceptors>true</exclude-default-interceptors>
</interceptor-binding>
<interceptor-binding>
<ejb-name>SlessEJB2</ejb-name>
<exclude-default-interceptors>true</exclude-default-interceptors>
</interceptor-binding>
</assembly-descriptor>
</ejb-jar>

非常明顯的, 我們可以看到, 我們需要利用 interceptor-binding 將 interceptor-class 指向到所有(*) 或單一(EJBName) 的結合.
以及是否去除 ( exclude-default-interceptors ) 預設的 binding 原則.


一個簡單的 Interceptor 的撰寫方式

import javax.interceptor.InvocationContext;
public class MyCallbackHandler {
public void someInteceptorMethod(InvocationContext invCtx) {
System.out.println("Hello Inteceptor in pre-destroy callback methods ");
try {
invCtx.proceed();
} catch(Exception e) {
e.printStackTrace();
}
}
}


當呼叫 InvocationContext.proceed() 之後, 將會進行下一個 interceptor 的作業.

所以我們必須利用 InvocationContext 來取得我們攔截下來取得相關的資訊, 進行相關的處理.

Map getContextData()
Method getMethod()
Object[] getParameters()
Object getTarget()
Object proceed()
void setParameters()

除了控制生命週期的攔截之外, 我們可以利用 ArroundInvoke() 進行相關的攔截

@AroundInvoke

Object aroundInvoke(InvocationContext ctx) throws Exception {

Common.aroundInvokeCalled(ctx, "testArroundInvoke");

Object instance = ctx.getTarget();

if( instance instanceof SomeEJB) {

((SomeEJB) instance).aroundInvokeCalled = true;

}

return ctx.proceed();

}

這樣就可以建立基本的 AOP 實作了

07:00 發表於 EJB3 | 永久網址 | 留言 (0) | Email this