Java EE(原 J2EE)功能強大卻因過度複雜令人卻步。三年來,開源社區、JCP、主流廠商共同推動簡化:POJO 服務、服務攔截器、依賴注入、Hibernate、AOP、Spring 等成果湧現。簡化 ≠ 功能減少,而是將複雜邏輯下沉框架,對應用開發者隱形。研究表明:將示例應用從 EJB 2.1 遷移至 3.0,**代碼量減少 50%+**。Java 註解是核心鑰匙,將 POJO 服務、POJO 持久化、依賴注入綁定為完整中間件方案。
| 維度 | XML 部署描述符 | Java 註解 |
|---|---|---|
| 冗長度 | 極高(大量重復類名/方法名) | 低(代碼內嵌,無額外引用) |
| 健壯性 | 運行時才發現錯誤(拼寫、簽名不匹配) | 編譯期檢查,與代碼同步處理 |
| 靈活性 | 高(部署期修改,不動代碼,運維友好) | 相對固化(需重編譯) |
EJB 3.0 策略:註解配置 90% 應用,XML 覆蓋默認註解、配置外部資源(數據源等),兩全其美。
至少一個業務接口,其他組件通過接口獲取服務。實現類僅需 @Stateless 或 @Stateful 註解。
// 業務接口
public interface Calculator {
double calculate(int startAge, int endAge, double growthRate, double monthlySaving);
}
// 實現類:POJO + @Stateless
@Stateless
public class CalculatorBean implements Calculator {
public double calculate(int start, int end, double growthRate, double saving) {
double factor = Math.pow(1 + growthRate/12, 12*(end-start)+1);
return saving * 12 * (factor - 1) / growthRate;
}
}
@Stateless
@Local(Calculator.class)
@Remote(RemoteCalculator.class)
public class CalculatorBean implements Calculator, RemoteCalculator {
// 實現兩個接口方法...
}
無註解默認為本地接口。
InitialContext ctx = new InitialContext();
Calculator cal = (Calculator) ctx.lookup(Calculator.class.getName());
double result = cal.calculate(start, end, growthRate, saving);
Stateful Bean 必須客戶端緩存 Stub,後續調用復用同一實例。
創建、緩存、銷毀全權容器管理(IoC)。應用僅與業務接口交互。若需掛鉤生命週期,聲明回調方法並標註註解:
| 註解 | 觸發時機 | 適用類型 |
|---|---|---|
@PostConstruct | 實例化完成、依賴注入後 | Stateful / Stateless |
@PreDestroy | 實例從池移除前 | Stateful / Stateless |
@PrePassivate | Stateful 實例閒置超時將被鈍化前 | Stateful |
@PostActivate | Stateful 實例激活完成後 | Stateful |
@Init | Stateful 實例初始化(可多個,按創建方式匹配) | Stateful |
@Remove | 調用此方法後容器移除實例,終止會話 | Stateful |
@Stateful
public class CalculatorBean implements Calculator, Serializable {
@PostConstruct
public void initialize() {
// 載入歷史記錄、初始化數據庫連接...
}
@PreDestroy
public void exit() {
// 保存歷史記錄至數據庫...
}
@Remove
public void stopSession() {
// 方法體可為空,調用即通知容器移除實例
}
}
處理基於消息的異步請求(Email、JMS)。實現 MessageListener,onMessage() 為入口。註解配置監聽隊列:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination", propertyValue="queue/mdb")
})
public class CalculatorMDB implements MessageListener {
public void onMessage(Message msg) {
try {
TextMessage tmsg = (TextMessage) msg;
// 解析參數、計算、記錄...
} catch (Exception e) { e.printStackTrace(); }
}
}
JNDI 查找痛點:字符串名稱無編譯檢查、類型轉換運行時風險、樣板代碼繁瑣。EJB 3.0 提供 @EJB、@Resource 註解聲明式注入:
// 字段注入
public class CalculatorMDB implements MessageListener {
@EJB Calculator cal; // 容器首次訪問前自動賦值
// 使用 cal...
}
// Setter 注入
public class CalculatorMDB implements MessageListener {
private Calculator cal;
@EJB
public void setCal(Calculator cal) { this.cal = cal; }
}
@Resource TimerService timerService;
@Resource SessionContext sessionContext;
@Resource(name="DefaultDS") DataSource myDb;
@Resource(name="ConnectionFactory") QueueConnectionFactory factory;
@Resource(name="queue/A") Queue queue;
@PersistenceContext EntityManager em; // 類似 Hibernate Session
@Stateless
public class CalculatorBean implements Calculator {
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void updateExchangeRate(double newRate) throws Exception {
// 循環更新數據庫,全成功或全回滾
}
}
容器在合適事務上下文運行方法,方法內所有調用共享事務(除非另有聲明)。
@Stateless
@SecurityDomain("other") // 指向 classpath 下 users.properties/roles.properties
public class CalculatorBean implements Calculator {
@RolesAllowed("AdminUser")
public void addFund(String name, double rate) { ... }
@RolesAllowed("AdminUser")
public void addInvestor(String name, int start, int end) { ... }
@PermitAll
public Collection getFunds() { ... }
@RolesAllowed("AdminUser")
public double calculate(int fundId, int investorId, double saving) { ... }
}
容器攔截調用,認證用戶,授權檢查,失敗拋出安全異常。
事務、安全本質是容器管理的運行時攔截器。EJB 3.0 允許自定義攔截器:
@AroundInvoke
public Object log(InvocationContext ctx) throws Exception {
long start = System.currentTimeMillis();
try {
return ctx.proceed(); // 執行目標方法
} finally {
System.out.println(ctx.getMethod() + " 耗時: " + (System.currentTimeMillis()-start) + "ms");
}
}
攔截器方法可定義在 Bean 類、單獨攔截器類、或通過 XML 配置默認攔截器。
EJB 3.0 以註解驅動、POJO 化、依賴注入、聲明式服務四大支柱,重塑了 Java 企業級開發體驗。開發者回歸業務邏輯,容器托管基礎設施,鬆耦合組件靈活組裝。這不僅是 EJB 的勝利,更是Spring 等開源創新回饋標準化的里程碑。