使用 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编程中的`java.lang.NoClassDefFoundError: org/jboss/logging/`是一个常见的运行时错误,通常发生在尝试执行一个类时,JVM无法找到在编译时已经存在的类定义。这个错误并不意味着类在编译期间不存在,而是表明...
本文将详细介绍如何在 Windows XP 系统环境下,使用 Eclipse IDE 进行 JBoss Seam 的开发准备工作及环境配置。JBoss Seam 是一款基于 Java 的企业级应用框架,它简化了应用程序的开发过程,使得开发者能够更专注于...
总之,本书是JBoss Seam框架领域的一部经典之作,不仅提供了深入的技术解析,还包含了丰富的实战案例和最佳实践。对于希望深入了解并掌握JBoss Seam框架的开发者来说,这无疑是一本不可或缺的宝典。
标题中的“Jboss seam3 实战”表明,本文将重点介绍JBoss Seam框架的第三个版本的实际应用。JBoss Seam是一个开源的Java EE框架,它通过依赖注入和会话模型,简化了基于Java EE的企业级应用开发。Seam框架为开发者...
标题:JBoss Seam入门介绍 描述:本文将详细介绍JBoss Seam框架的核心概念、关键特性以及如何构建基于Seam的应用程序。Seam作为一个企业级Java Web应用框架,它将Java EE和JSF无缝集成,旨在填补Java EE 5.0中缺失...
它将多种技术如JavaServer Faces (JSF),Java Persistence API (JPA),EJB 3,Inversion of Control (IoC)和Aspect-Oriented Programming (AOP)等融合在一起,提供了一种统一的开发模型。Seam的主要目标是减少开发中...
**JBoss Seam 中文文档集合概述** JBoss Seam 是一个开源的应用框架,它结合了JavaServer Faces (JSF)、Java Persistence API (JPA)、Enterprise JavaBeans (EJB) 3.0 和其他Java EE组件,旨在简化企业级开发。这个...
整理自jboss seam 中文站,压缩为chm格式,便于广大jboss seam爱好者阅读,所有版权归jboss seam中文站所有。
7. **在JBoss 4.0下使用Seam**:由于JBoss 4.0版本较老,因此需要特别注意兼容性问题。 #### 第三章:上下文相关的组件模型 这一章深入探讨了Seam中的核心概念——组件模型,以及各种不同的上下文环境。 1. **...
JBoss Seam被称为是“Java EE 5.0的一个轻量级的框架”,这个表述意味着Seam是建立在Java EE 5.0之上的一层,为开发者提供了一个更加统一且易于理解的编程模型。Seam的目标是简化企业级Web应用的开发,特别是对于...
【JBoss Seam】是Java企业级应用开发框架,它整合了JSF(JavaServer Faces)、EJB(Enterprise JavaBeans)3.0、JPA(Java Persistence API)以及一系列其他技术,为开发人员提供了一个强大的全栈式解决方案。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》是一本深入介绍JavaServer Faces 2(简称JSF2)及其相关API以及JBoss Seam框架的...
在开始之前,可以通过运行一些简单的示例来熟悉 JBoss Seam。这些示例覆盖了 Seam 的基本功能和工作流程。 **1.1.1 在 JBoss AS 上运行示例** - **准备环境**:确保已安装 JBoss AS 并配置好环境变量。 - **构建...
- **使用JSF 1.2 RI**:提供了如何在JBoss平台上使用JSF 1.2参考实现来部署和运行Seam应用的具体步骤。 #### 三、结语 通过以上内容的学习,读者可以全面了解JBoss Seam框架的核心功能和技术特点,掌握如何使用...
Seam全称是Jboss Seam,是一个Java EE 5框架。它通过把JSF与EJB3.0组件合并在一起,以及利用JDK5.0的Annotation技术,从而为开发基于Web的企业应用程序提供一个最新的模式。Seam可以让你把EJB组件直接绑定到JSF页面...
作为Hibernate的创造者Gavin King的作品,Seam在设计之初就考虑到了ORM的最佳实践,它在整个Web交互生命周期中管理持久上下文,避免了DTO等技术的使用,提高了代码的整洁性和可维护性。 总的来说,JBoss Seam是一个...
《实用JBoss Seam项目》是一本专注于介绍JBoss Seam框架及其在实际项目中应用的专业书籍。本书由Jim Farley编写,出版于2007年,是Java技术领域内的权威指南之一。JBoss Seam是一个开源敏捷的企业级JSF(JavaServer ...
java jboss seam jboss-seam-selectitems