[心缘地方]同学录
首页 | 功能说明 | 站长通知 | 最近更新 | 编码查看转换 | 代码下载 | 常见问题及讨论 | 《深入解析ASP核心技术》 | 王小鸭自动发工资条VBA版
登录系统:用户名: 密码: 如果要讨论问题,请先注册。

[转载]Seam Interceptor 拦截器

上一篇:[疑问]JavaMail的mail.smtp.sendpartial不起作用?
下一篇:[整理]seam Interceptor 拦截器小范例

添加日期:2009-3-31 16:56:10 快速返回   返回列表 阅读3481次
简单来说,
EBJ3有自己的拦截器,
Seam框架进行了扩展,普通的JavaBean也可以成为拦截器,只是要间接的使用到JavaBean上。

可以继承org.jboss.seam.intercept.AbstractInterceptor这个类来写。

几个类的import路径:
java.lang.annotation.Retention
java.lang.annotation.Target
java.lang.annotation.RetentionPolicy
java.lang.annotation.ElementType

以下转载:
================================================
在 JBoss Seam 使用 AOP 作 logging / auditing

使用JBoss Seam2.0 ,我們可以利用 Annotation 和 Interceptor 去作 AOP 去減低組件間的耦合。最適合用來處理一些非核心、但容易分佈各處的功能。

目標
我們的軟件需要記錄登入用戶後的工作以作審計用途。系統有很多的組件,每個組件有若干的功能。當用戶使用某功能的時候,我們希望可以記錄該用戶的資料、使用時間、哪一個功能、影響了甚麼資料等等。

第一個答案
最簡單的作法就是寫一個獨立的 Audit 組件,再在每個功能之後使用它:

FundHome.java


@Name("fundHome")
publicclassFundHomeextendsEntityHome<Fund>{
   publicStringupdate(){
       Stringresult =null;
       try{
           // update data
           // ....
       }finally{
            audit.log("update user account: #0, #1, #2", currentUser, oldFund, newFund);
       }
       returnresult;
   }
   // ...
}


雖然這可以解決問題,然而這樣有關 Audit 的邏輯就混在業務邏輯之中。如果有六十個這種要記錄的功能,就要重覆這種沒個性的代碼 60 次,真痛苦,更別說當中可能有人為出錯和其後果了。本著 DRY (Dont Repeat Yourself) 的精神,我們可以用 Seam 的 Interceptor 去簡化這工作。


Seam Interceptor
EJB 3.0 有 interceptor 的標準。任何 class 只要在其 method 上加上 @AroundInvoke 的標記,Container 就會知道這是個 interceptor。想在執行某動作的前後執行這 interceptor,只需在目標方法前加入 @Interceptors 標記以及 interceptor 的 class。

AuditInterceptor.java


@Name("auditInterceptor")
publicclassAuditInterceptor{
   protectedstaticLog log = Logging.getLog(AuditInterceptor.class);
    @AroundInvoke
   publicObjectaudit(InvocationContext context)throwsException{
       Objectresult =null;
       try{
            result = context.proceed();
       }finally{
            User user =(User)Contexts.getSessionContext().get("user");
            log.info("[#0][#1][#2]",
                context.getClass().getName(),
                context.getMethod().getName(),
                user==null?
                   "not logged in":
                    user.getLogin());
       }
       returnresult;
   }
}


FundHome.java


@Name("fundHome")
publicclassFundHomeextendsEntityHome<Fund>{
    @Interceptors(AuditInterceptor.class)
   publicStringupdate(){
       // original update data
       // ....
   }
}


注意 Contexts.getSessionContext().get(”user”),這是 Seam 去存取 Session Context 的方法。。Interceptor 可以直接存取所有目標的 context,這已足夠處理大部份的應用了。就這樣只需加一個 annotation 就可以做到原本的效果,是否比較漂亮?

EJB3.0 還支援用在 ejb-jar.xml 中定義 Interceptors,JBoss Seam 本身就是用 Interceptor 去運作的:

ejb-jar.xml


<?xmlversion="1.0"encoding="UTF-8"?>
<ejb-jarxmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
         version="3.0">
         
   <interceptors>
     <interceptor>
         <interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
     </interceptor>
   </interceptors>
   
   <assembly-descriptor>
     <interceptor-binding>
         <ejb-name>*</ejb-name>
         <interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>
     </interceptor-binding>
   </assembly-descriptor>   
</ejb-jar>



Meta-Annotation as Interceptor
Seam Interceptors 基於 EJB3 之上再加了一些改良。首先你不單可以在 EJB3 中用 Seam Interceptor,Seam 讓普通的 JavaBean 也可以有同樣功能。
其次,進一步 DRY ,Seam 支援用 meta-annotation 去定義 class level interceptor:

Auditor.java


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Interceptors(AuditInterceptor.class)
public@interfaceAuditor{}



FundHome.java


@Name("fundHome")
@Auditor
publicclassFundHomeextendsEntityHome<Fund>{
    @Interceptors(AuditInterceptor.class)
   publicStringupdate(){
       // original update data
       // ....
   }
}


這就等於在 FundHome 中加入 class level interceptor: @Interceptors(AuditInterceptor.class),除了省了打幾個字外,這還讓源碼更加易讀。(注:這個似乎只在 EJB3 才行,在 JavaBean 中要稍為改動,詳情請參考這篇。http://www.seamframework.org/12534.lace)

加入更多自定的資料
由於 Audit 需要監察很多不同功能,怎樣用一個 Interceptor 處理和記錄不同的資料呢?比如新增用戶時我想知道新增的帳戶名稱、轉賬時想知道過數的銀碼等等。按 Seam 的思路,我會用另一個 Annotation 去定義這些資料:

AuditableAction.java


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public@interfaceAuditableAction{   
   Stringdescription()default"";
   Stringmodule()default"Unknown";
   Stringaction()default"Unknown";   
}



更新後的 AuditInterceptor.audit() 方法


@AroundInvoke
publicObjectaudit(InvocationContext context)throwsException{
   Objectresult =null;
   try{
        result = context.proceed();
   }finally{
       if(context.getMethod().isAnnotationPresent(AuditableAction.class)){
            ActionLogHome actionLogHome =(ActionLogHome)Component.getInstance("actionLogHome");
            AuditableAction auditableAction = context.getMethod().getAnnotation(AuditableAction.class);               
            Interpolator interpolator =(Interpolator)Component.getInstance("org.jboss.seam.core.interpolator");
            ActionLog actionLog = actionLogHome.getInstance();

            User user =(User)Contexts.getSessionContext().get("user");
            Stringmodule = StringUtils.left(auditableAction.module(),64);
            Stringaction = StringUtils.left(auditableAction.action(),64);                   
            if(StringUtils.isNotEmpty(auditableAction.details())){
                Stringdetails = interpolator.interpolate(auditableAction.details());
                actionLog.setDetails(details);
            }
            actionLog.setModule(module);
            actionLog.setAction(action);
            actionLog.setUser(user);
            actionLogHome.persist();
       }
   }
   returnresult;
}



ActionLog 是個 Entity Bean。
ActionLogHome 是標源的 EntityHome ,是生產 ActionLog 的地方。

Interpolator 是 Seam 的標準組件,可以 evaluate Seam 的 EL Expression。
FundHome.java


@Name("fundHome")
@Auditor
publicclassFundHomeextendsEntityHome<Fund>{
    @AuditableAction(module="Fund",
            action="Update",
            details="fund.id=#{fundHome.instance.id}")   
   publicStringupdate(){
       // ... update logic ...
   }
}


利用 annotation 我們可以定義任何的資料,包括 EL Expression。以上的例子就讓我們可以讓 log 記錄獨立的訊息,在 log 前會把 EL Expression 解讀回我們想要的資料。

結語
剛才我們利用 Seam Interceptor 去處理分佈各處的非核心功能。比起用 AspectJ 用另一個檔案和另一種語法去改動程式, Seam Interceptor 較易使用和維護。然而要注意的是 Interceptor 有相當的開銷,要小心過度使用帶來的性能問題。
 

评论 COMMENTS
没有评论 No Comments.

添加评论 Add new comment.
昵称 Name:
评论内容 Comment:
验证码(不区分大小写)
Validation Code:
(not case sensitive)
看不清?点这里换一张!(Change it here!)
 
评论由管理员查看后才能显示。the comment will be showed after it is checked by admin.
CopyRight © 心缘地方 2005-2999. All Rights Reserved