早期 J2EE (EJB 2.x) 以**重量級**著稱:
Rod Johnson 在《Expert One-on-One J2EE Design and Development》中展示**輕量級容器原型**,後演進為 Spring Framework:**非侵入式、基於 POJO、IoC + AOP 雙引擎驅動**。
// 1. 接口定義業務契約
public interface Action {
String execute(String input);
}
// 2. POJO 實現,無任何 Spring 依賴
public class UpperAction implements Action {
private String message; // 可注入配置
public void setMessage(String message) { this.message = message; }
public String execute(String input) {
return (message + input).toUpperCase();
}
}
// 3. XML 配置 (早期風格)
<beans>
<bean id="theAction" class="com.example.UpperAction">
<property name="message" value="HeLLo"/>
</bean>
</beans>
// 4. 啟動容器獲取 Bean
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
Action action = ctx.getBean("theAction", Action.class);
System.out.println(action.execute("Rod Johnson")); // HELLO ROD JOHNSON
@Configuration
@ComponentScan("com.example")
public class AppConfig {
@Bean
public Action theAction() {
UpperAction action = new UpperAction();
action.setMessage("HeLLo");
return action;
}
}
// 或組件掃描 + 注入
@Component
public class UpperAction implements Action {
@Value("${app.message:HeLLo}")
private String message;
// ...
}
@Service
public class BusinessService {
private final Action action; // 構造器注入,不可變、最終字段
public BusinessService(Action action) { this.action = action; }
}
@PostConstruct/@PreDestroy)。@SpringBootTest 載入完整上下文,@MockBean 替換依賴。| 術語 | 含義 | 例子 |
|---|---|---|
| Joinpoint (連接點) | 程序執行中可插入切面的點 | 方法調用、異常拋出、字段訪問 |
| Pointcut (切入點) | 匹配連接點的條件表達式 | execution(* com.example.service.*.*(..)) |
| Advice (通知/增強) | 在切入點執行的具體邏輯 | 事務開啟、日志記錄、性能計時 |
| Aspect (切面) | Pointcut + Advice 的模塊化封裝 | @Aspect 類 |
| Weaving (織入) | 將切面應用到目標對象的過程 | 編譯期/類加載期/運行期 (Spring 用運行期代理) |
@Aspect
@Component
public class TxAspect {
@Around("@annotation(Transactional)") // 環繞通知:最強大,可控制是否執行目標、捕獲異常、修改返回值
public Object manageTransaction(ProceedingJoinPoint pjp) throws Throwable {
TransactionStatus tx = txManager.getTransaction(new DefaultTransactionDefinition());
try {
Object result = pjp.proceed(); // 執行目標方法
txManager.commit(tx);
return result;
} catch (Exception e) {
txManager.rollback(tx);
throw e;
}
}
@Before("execution(* *.save*(..))") // 前置通知:目標方法前
public void logBefore(JoinPoint jp) { log.info("Saving: {}", jp.getSignature()); }
@AfterReturning(pointcut = "execution(* *.find*(..))", returning = "result")
public void logAfterReturning(Object result) { log.debug("Found: {}", result); }
@AfterThrowing(pointcut = "execution(* *.delete*(..))", throwing = "ex")
public void logAfterThrowing(Exception ex) { log.error("Delete failed", ex); }
@After("execution(* *.update*(..))") // 後置通知:finally 語義,無論正常/異常
public void cleanup() { /* 釋放資源 */ }
}
@Service
public class AccountService {
@Transactional(rollbackFor = Exception.class)
public void transfer(Long from, Long to, BigDecimal amount) {
accountDao.debit(from, amount);
accountDao.credit(to, amount);
}
}
// 無需手動 try-catch-commit/rollback,AOP 透明織入
沒有 IoC 的 AOP 不完善:切面本身是 Bean,需容器管理生命週期、注入依賴 (如 PlatformTransactionManager)。
沒有 AOP 的 IoC 不健壯:事務、安全、緩存等企業級服務無法以聲明式方式應用於 POJO,將退化為樣板代碼散落業務邏輯。
| 維度 | EJB 2.x/3.x | Spring |
|---|---|---|
| 組件模型 | 重組件 (Session/Entity/Message Bean) | POJO + 註解 |
| 容器依賴 | 強綁定應用服務器 | 可嵌入 Tomcat/Jetty/Undertow,無容器也能跑 |
| 事務管理 | CMT/BMT,僅限 EJB 方法 | 聲明式 @Transactional,任意 POJO 方法 |
| 測試性 | 需容器內測試 (Arquillian) 慢 | 單元測試毫秒級,集成測試秒級 |
| 配置方式 | XML 描述符 (ejb-jar.xml 等) | JavaConfig + 註解 + YAML,類型安全 |
| 生態擴展 | 標準規範內 | Spring Boot/Data/Cloud/Security/Batch... 豐富生態 |
Spring 以 **IoC 容器管理對象圖、AOP 織入橫切關注點** 為雙核心,將**企業級基礎設施服務 (事務、安全、緩存、消息) 以聲明式方式應用於純 POJO**。它證明了:輕量級不等於功能輕,而是架構輕、耦合輕、認知輕。從 Rod Johnson 的原型到今日雲原生生態霸主,Spring 始終踐行一個信念:**讓開發者專注業務領域,基礎設施交給框架**。