本文將帶你完整走一遍 Spring 基於註解的 AOP 開發流程,涵蓋 Maven 依賴管理、核心業務類編寫、切面定義、XML 配置啟用以及 JUnit 測試驗證。適合初學者快速掌握 Spring AOP 核心概念與實踐。
使用 Maven 管理專案,核心依賴包含 Spring Context、AspectJ、AOP Alliance 及 JUnit:
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dzg</groupId>
<artifactId>spring_study</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
<dependencies>
<!-- Spring 核心容器 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- AspectJ 運行時與織入器 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!-- AOP Alliance 標準介面 -->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!-- 測試框架 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>
package com.dzg.spring.model;
public class User {
private int id;
private String username;
private String password;
// 省略 getter/setter
}
// UserDAO.java
package com.dzg.spring.dao;
import com.dzg.spring.model.User;
public interface UserDAO {
void save(User user);
}
// UserDAOImpl.java
package com.dzg.spring.dao.impl;
import org.springframework.stereotype.Component;
import com.dzg.spring.dao.UserDAO;
import com.dzg.spring.model.User;
@Component("u")
public class UserDAOImpl implements UserDAO {
@Override
public void save(User user) {
System.out.println("user saved!");
}
}
package com.dzg.spring.service;
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
import com.dzg.spring.dao.UserDAO;
import com.dzg.spring.model.User;
@Component
public class UserService {
private UserDAO userDAO;
public void add(User user) {
userDAO.save(user);
}
@Resource(name = "u")
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
}
使用 @Aspect 標識切面,@Before 定義前置通知,針對 UserDAOImpl.save 方法切入:
package com.dzg.spring.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component("log")
public class LogInterceptor {
@Before("execution(public void com.dzg.spring.dao.impl.UserDAOImpl.save(com.dzg.spring.model.User))")
public void beforeMethod() {
System.out.println("save start!");
}
}
啟用註解掃描與 AspectJ 自動代理:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:aop="https://www.springframework.org/schema/aop"
xsi:schemaLocation="
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.dzg.spring"/>
<aop:aspectj-autoproxy/>
</beans>
package com.dzg.spring.service;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.dzg.spring.model.User;
public class UserServiceTest {
@Test
public void testAdd() throws Exception {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService service = (UserService) ctx.getBean("userService");
System.out.println(service.getClass()); // 觀察代理類類型
User u = new User();
u.setUsername("zhangsan");
u.setPassword("zhangsan");
service.add(u);
ctx.close();
}
}
class com.dzg.spring.service.UserService$$EnhancerBySpringCGLIB$$21c652e7 save start! user saved!
控制台輸出顯示 Spring 使用 CGLIB 為 UserService 生成了代理類,切面邏輯 save start! 在目標方法執行前成功織入,驗證 AOP 配置生效。
aspectjweaver 是啟用 @AspectJ 註解的關鍵。<aop:aspectj-autoproxy/> 開啟自動代理,容器會掃描 @Aspect Bean 並生成代理。完整示例代碼結構清晰,可直接作為 Spring AOP 註解開發的參考模板。