概念
兩個特點:
- IOC控制反轉
- AOP主要用來處理公共的代碼
例如一個案例就是添加用戶,重復的代碼包含了記錄日志、事務提交和事務回滾等,都是重復的,為了簡單,交給AOP來做。
- 即將復雜的需求分解出不同方面,將散布在系統中的公共功能集中解決。(例如有關security,persistence,logging等不同方面的代碼,)
- 采用代理機制組裝起來運行,在不改變原程序的基礎上對代碼段進行增強處理,增加新的功能。
回到添加用戶的案例,把不同面的代碼單獨抽出去,當程序運行到方法時,例如方法前,可以動態將該面的程序動態的切進去,方法運行完也可以動態的切進去。
通過代理對象調用原來對象的方法。代理對象方法前后都可插入代碼,這些代碼就是增強處理。動態代理的經典實現。
所謂面向切面編程,即一種通過預編譯和運行期動態代理的方式,實現在不修改源代碼的情況下給程序動態添加功能的技術。
相關術語
增強處理:
- 前置增強
- 后置增強
- 環繞增強、異常拋出增強、最終增強等類型
切入點Pointcut : 往哪里切
連接點 Join Point:切的地方會產生連接點,根據連接點獲得一些參數
切面 Aspect:
目標對象 Target object:切的是誰
AOP代理:指代增強
織入 Weaving:動態切入
案例
例如下面的,插入AOP
public class UserServiceImpl implements UserServie{private UserDao userDao;@Overridepublic void show() {userDao.show();}}
想在show方法之前打印日志,show方法之后也打印日志。不建議System.out.println()
。在打印日志的時候,用到log,輸出打印的信息并會帶上確定的時間,方便排查錯誤。
import org.apache.log4j.Logger;public class Log {private Logger logger = Logger.getLogger(Log.class);public static void main(String[] args){logger.info("打印日志, info");logger.debug("打印日志, debug");logger.warn("打印日志, warn");logger.error("打印日志, error");}}
如何在show方法執行結束后運行呢?
添加切點。
<aop:pointcut expression="execution( * com.kgc.service.. * . * (..))" id="point"/>
然后進行增強處理。
又例如權限攔截器中的示例:
使用Spring AOP實現權限攔截器,用于在方法執行前或執行過程中進行權限校驗,例如角色檢查。
@Around("@annotation(authCheck)")public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {// 獲取注解中的權限要求String mustRole = authCheck.mustRole();// 怎么拿到當前用戶的登陸信息呢?RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();// 轉換為servletHttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();User loginUser = userService.getLoginUser(request);// 獲取用戶的權限類型UserRoleEnum mustRoleEnum = UserRoleEnum.getEnumByValue(mustRole);// 如果權限要求為空,則繼續執行原來的方法if (mustRoleEnum == null){return joinPoint.proceed();}// 反之,以下的代碼就是必須有權限才會通過// 也要將獲取到當前用戶的角色轉換成枚舉類,方便使用UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(loginUser.getUserRole());// 如果為空則異常if (userRoleEnum == null){throw new BusinessException(ErrorCode.NOT_AUTH_ERROR);}// 要對必須有管理員權限,即mustRoleEnum為ADMIN,但是用戶的權限不是管理員權限,則異常if (UserRoleEnum.ADMIN.equals(mustRoleEnum) && !UserRoleEnum.ADMIN.equals(userRoleEnum)){throw new BusinessException(ErrorCode.NOT_AUTH_ERROR);}// 其他情況就是通過權限校驗的return joinPoint.proceed();}
參考
AOP切面的實現