`
dingtao
  • 浏览: 56263 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

在 JBoss Seam 使用 AOP 作 logging / auditing

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

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

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

FundHome.java
@Name("fundHome")
public class FundHome extends EntityHome<Fund> {
    public String update() {
        String result = null;
        try {
            // update data
            // ....
        } finally {
            audit.log("update user account: #0, #1, #2", currentUser, oldFund, newFund);
        }
        return result;
    }
    // ...
}
雖然這可以解決問題,然而這樣有關 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")
public class AuditInterceptor {
    protected static Log log = Logging.getLog(AuditInterceptor.class);
    @AroundInvoke
    public Object audit(InvocationContext context) throws Exception {
        Object result = 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());
        }
        return result;
    }
}


FundHome.java
@Name("fundHome")
public class FundHome extends EntityHome<Fund> {
    @Interceptors(AuditInterceptor.class)
    public String update() {
        // 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
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="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 @interface Auditor {}
FundHome.java
@Name("fundHome")
@Auditor
public class FundHome extends EntityHome<Fund> {
    @Interceptors(AuditInterceptor.class)
    public String update() {
        // original update data
        // ....
    }
}

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

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

AuditableAction.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuditableAction {    
    String description() default "";
    String module() default "Unknown";
    String action() default "Unknown";    
}

更新後的 AuditInterceptor.audit() 方法
@AroundInvoke
public Object audit(InvocationContext context) throws Exception {
    Object result = 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");
            String module = StringUtils.left(auditableAction.module(), 64);
            String action = StringUtils.left(auditableAction.action(), 64);                    
            if (StringUtils.isNotEmpty(auditableAction.details())){
                String details = interpolator.interpolate(auditableAction.details());
                actionLog.setDetails(details);
            }
            actionLog.setModule(module);
            actionLog.setAction(action);
            actionLog.setUser(user);
            actionLogHome.persist();
       }
    }
    return result;
}

ActionLog 是個 Entity Bean。
ActionLogHome 是標源的 EntityHome ,是生產 ActionLog 的地方。
Interpolator 是 Seam 的標準組件,可以 evaluate Seam 的 EL Expression。
FundHome.java
@Name("fundHome")
@Auditor
public class FundHome extends EntityHome<Fund> {
    @AuditableAction(module="Fund", 
            action="Update", 
            details="fund.id=#{fundHome.instance.id}")    
    public String update() {
        // ... update logic ...
    }
}

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

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

相关推荐

    java.lang.NoClassDefFoundError: org/jboss/logging/

    Java编程中的`java.lang.NoClassDefFoundError: org/jboss/logging/`是一个常见的运行时错误,通常发生在尝试执行一个类时,JVM无法找到在编译时已经存在的类定义。这个错误并不意味着类在编译期间不存在,而是表明...

    jbossseam eclipse安装 例子学习.doc

    本文将详细介绍如何在 Windows XP 系统环境下,使用 Eclipse IDE 进行 JBoss Seam 的开发准备工作及环境配置。JBoss Seam 是一款基于 Java 的企业级应用框架,它简化了应用程序的开发过程,使得开发者能够更专注于...

    JBoss Seam

    总之,本书是JBoss Seam框架领域的一部经典之作,不仅提供了深入的技术解析,还包含了丰富的实战案例和最佳实践。对于希望深入了解并掌握JBoss Seam框架的开发者来说,这无疑是一本不可或缺的宝典。

    Jboss seam3 实战

    标题中的“Jboss seam3 实战”表明,本文将重点介绍JBoss Seam框架的第三个版本的实际应用。JBoss Seam是一个开源的Java EE框架,它通过依赖注入和会话模型,简化了基于Java EE的企业级应用开发。Seam框架为开发者...

    JBoss Seam入门介绍

    标题:JBoss Seam入门介绍 描述:本文将详细介绍JBoss Seam框架的核心概念、关键特性以及如何构建基于Seam的应用程序。Seam作为一个企业级Java Web应用框架,它将Java EE和JSF无缝集成,旨在填补Java EE 5.0中缺失...

    JBOSS SEAM组件中文手册

    它将多种技术如JavaServer Faces (JSF),Java Persistence API (JPA),EJB 3,Inversion of Control (IoC)和Aspect-Oriented Programming (AOP)等融合在一起,提供了一种统一的开发模型。Seam的主要目标是减少开发中...

    jboss seam 中文文档集合

    **JBoss Seam 中文文档集合概述** JBoss Seam 是一个开源的应用框架,它结合了JavaServer Faces (JSF)、Java Persistence API (JPA)、Enterprise JavaBeans (EJB) 3.0 和其他Java EE组件,旨在简化企业级开发。这个...

    jboss seam 2.0 中文手册

    整理自jboss seam 中文站,压缩为chm格式,便于广大jboss seam爱好者阅读,所有版权归jboss seam中文站所有。

    Jboss Seam中文版

    7. **在JBoss 4.0下使用Seam**:由于JBoss 4.0版本较老,因此需要特别注意兼容性问题。 #### 第三章:上下文相关的组件模型 这一章深入探讨了Seam中的核心概念——组件模型,以及各种不同的上下文环境。 1. **...

    深入浅出JBoss Seam.pdf

    JBoss Seam被称为是“Java EE 5.0的一个轻量级的框架”,这个表述意味着Seam是建立在Java EE 5.0之上的一层,为开发者提供了一个更加统一且易于理解的编程模型。Seam的目标是简化企业级Web应用的开发,特别是对于...

    Jboss Seam 三本最受欢迎的教材

    【JBoss Seam】是Java企业级应用开发框架,它整合了JSF(JavaServer Faces)、EJB(Enterprise JavaBeans)3.0、JPA(Java Persistence API)以及一系列其他技术,为开发人员提供了一个强大的全栈式解决方案。Seam...

    [JBoss] JSF & Facelets & JBoss Seam 核心技术 (英文版)

    [TipTec Development] JSF & Facelets & JBoss Seam 核心技术 (英文版) [TipTec Development] Essential JSF, Facelets & JBoss Seam (E-Book) ☆ 出版信息:☆ [作者信息] Kent Ka Iok Tong [出版机构] TipTec ...

    Beginning JSF2 APIs and JBoss Seam

    ### 关于《Beginning JSF2 APIs and JBoss Seam》的知识点总结 #### 一、书籍简介与背景 《Beginning JSF2 APIs and JBoss Seam》是一本深入介绍JavaServer Faces 2(简称JSF2)及其相关API以及JBoss Seam框架的...

    jboss seam 2.01GA REF DOC

    在开始之前,可以通过运行一些简单的示例来熟悉 JBoss Seam。这些示例覆盖了 Seam 的基本功能和工作流程。 **1.1.1 在 JBoss AS 上运行示例** - **准备环境**:确保已安装 JBoss AS 并配置好环境变量。 - **构建...

    jboss seam 教程

    - **使用JSF 1.2 RI**:提供了如何在JBoss平台上使用JSF 1.2参考实现来部署和运行Seam应用的具体步骤。 #### 三、结语 通过以上内容的学习,读者可以全面了解JBoss Seam框架的核心功能和技术特点,掌握如何使用...

    Seam全称是Jboss Seam,是一个Java EE 5框架

    Seam全称是Jboss Seam,是一个Java EE 5框架。它通过把JSF与EJB3.0组件合并在一起,以及利用JDK5.0的Annotation技术,从而为开发基于Web的企业应用程序提供一个最新的模式。Seam可以让你把EJB组件直接绑定到JSF页面...

    深入浅出JBoss Seam

    作为Hibernate的创造者Gavin King的作品,Seam在设计之初就考虑到了ORM的最佳实践,它在整个Web交互生命周期中管理持久上下文,避免了DTO等技术的使用,提高了代码的整洁性和可维护性。 总的来说,JBoss Seam是一个...

    Practical JBoss Seam projects

    《实用JBoss Seam项目》是一本专注于介绍JBoss Seam框架及其在实际项目中应用的专业书籍。本书由Jim Farley编写,出版于2007年,是Java技术领域内的权威指南之一。JBoss Seam是一个开源敏捷的企业级JSF(JavaServer ...

    jboss-seam-selectitems

    java jboss seam jboss-seam-selectitems

Global site tag (gtag.js) - Google Analytics