AOP(Aspect Oriented Programming,面向切面編程)在不修改原有業務代碼前提下,為方法增加橫切關注點(日誌、事務、權限、效能監控等)。
| 術語 | 說明 |
|---|---|
| Join Point(連接點) | 可插入增強的點,如方法呼叫、例外拋出 |
| Pointcut(切入點) | 匹配 Join Point 的條件表達式 |
| Advice(增強/通知) | 在切入點執行的具體邏輯 |
| Aspect(切面) | Pointcut + Advice 的模組化封裝 |
| Weaving(織入) | 將 Aspect 應用到目標物件的過程 |
public interface UserService {
void addUser(User user);
List<User> getAll();
}
public class UserServiceImpl implements UserService {
private UserDao dao;
public void setDao(UserDao dao) { this.dao = dao; }
// 實作方法...
}
public class ServiceLogging {
private Log log = LogFactory.getLog(getClass());
public void beforeService() { log.info("AOP 方法被呼叫!"); }
}
<beans xmlns:aop="https://www.springframework.org/schema/aop" ...>
<bean id="userDao" class="...UserDaoImpl"/>
<bean id="userService" class="...UserServiceImpl">
<property name="dao" ref="userDao"/>
</bean>
<bean id="serviceLogging" class="...ServiceLogging"/>
<aop:config>
<aop:pointcut id="servicePointcut"
expression="execution(public void addUser(..))"/>
<aop:aspect ref="serviceLogging">
<aop:before method="beforeService" pointcut-ref="servicePointcut"/>
</aop:aspect>
</aop:config>
</beans>
| 類型 | 標籤 | 執行時機 | 典型用途 |
|---|---|---|---|
| 前置增強 | <aop:before> | 目標方法前 | 權限檢查、日誌記錄 |
| 後置增強 | <aop:after-returning> | 正常返回後 | 結果處理、快取更新 |
| 異常增強 | <aop:after-throwing> | 拋出異常時 | 異常日誌、告警通知 |
| 最終增強 | <aop:after> | 最後執行(類 finally) | 資源清理、釋放鎖 |
| 環繞增強 | <aop:around> | 前後皆可控制 | 事務管理、效能計時、快取攔截 |
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed(); // 執行目標方法
System.out.println("耗時:" + (System.currentTimeMillis() - start) + "ms");
return result;
}
execution(public * com.pkg..*.*(..)):com.pkg 及子包所有公共方法execution(* set*(..)):所有 setter 方法execution(* com.pkg.Service.*(..)):Service 介面所有方法@annotation(com.pkg.Loggable):標註特定註解的方法@Aspect
public class AspectTest {
@Before("execution(* com.jbit.ssh.service..*.*(..))")
public void before() { System.out.println("前置增強"); }
@After("execution(* com.jbit.ssh.service..*.*(..))")
public void after() { System.out.println("最終增強"); }
@AfterReturning(pointcut = "execution(* com.jbit.ssh.service..*.*(..))", returning = "ret")
public void afterReturning(Object ret) { System.out.println("返回值:" + ret); }
@AfterThrowing(pointcut = "execution(* com.jbit.ssh.service..*.*(..))", throwing = "ex")
public void afterThrowing(Exception ex) { System.out.println("異常:" + ex.getMessage()); }
@Around("execution(* com.jbit.ssh.service..*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
return pjp.proceed();
}
}
<aop:aspectj-autoproxy/> <bean class="com.jbit.ssh.aop.AspectTest"/>
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService service = ac.getBean("userService", UserService.class);
service.addUser(new User());