面向對象,你們都聽過。那面向切面是個啥?面向切面是對面向對象的延伸。那就先從面向對象開始提及。java
在面向對象中, 對重複的邏輯代碼會抽取出來,在須要用到的地方繼承便可。這就是縱向抽取
。git
可是,縱向抽取需求並不能知足全部的抽取場景,好比在不一樣的方法有着一些重複的代碼邏輯,經過縱向抽取是沒辦法抽取使用的,代碼以下:github
因此咱們須要使用橫向切面的方式來對重複的邏輯代碼進行抽取複用,這就是面向切面編程:web
將分散在各個業務邏輯代碼中相同的代碼經過橫向切割的方式抽取到一個獨立的模塊中spring
在平常的開發中,代碼分爲主業務和系統級業務,上圖中的左側的就是主業務邏輯,右側就是系統級業務。系統級業務都應該用切面的方式抽取到獨立的模塊中,不和主業務代碼耦合,真正實現寫代碼時只需關注主業務的實現。編程
相關概念bash
經過定義一個權限檢查切面,來對全部的接口進行權限校驗。app
一個添加接口,一個刪除接口,刪除接口須要userType爲admin纔有權限刪除。dom
@RestController
public class WebController {
@GetMapping("add")
public String add(@RequestParam("userType") String userType){
System.out.println("add:添加用戶...");
return "ok";
}
@GetMapping(value = "del")
public String del(@RequestParam("userType") String userType){
System.out.println("add:刪除用戶...");
return "ok";
}
}
複製代碼
/**
* 定義一個切點
*
* 經過匹配註解的方式切進來,全部被GetMapping 註解的方法都會經過這個切點進來
*
*/
@Pointcut(value = "@annotation(org.springframework.web.bind.annotation.GetMapping)")
public void permissionCut(){}
複製代碼
@Around(value = "permissionCut()")
public Object checkPermission(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("@Around:開始校驗權限...");
Signature sig = joinPoint.getSignature();
MethodSignature msig = null;
if (!(sig instanceof MethodSignature)) {
throw new IllegalArgumentException("該註解只能用於方法");
}
msig = (MethodSignature) sig;
Method currentMethod = msig.getMethod();
//獲取GetMapping註解中的路徑
String methodMapping = null;
GetMapping methodGetMapping = currentMethod.getAnnotation(GetMapping.class);
if(methodGetMapping!=null&&methodGetMapping.value()!=null&&methodGetMapping.value().length>0) {
methodMapping = methodGetMapping.value()[0];
}
//訪問目標方法的參數:
String userType = "";
Object[] args = joinPoint.getArgs();
if (args != null && args.length > 0 && args[0].getClass() == String.class) {
userType = (String) args[0];
}
//刪除接口須要驗證管理員權限
if ("del".equals(methodMapping)){
if (userType.equals("admin")) {
//執行目標方法
joinPoint.proceed();
System.out.println("@Around:知足權限...");
return "ok";
}else {
System.out.println("@Around:不知足權限...");
return "無權限訪問";
}
}
return joinPoint.proceed();
}
複製代碼
@Before("permissionCut()")
public void permissionCheck(JoinPoint point) {
System.out.println("@Before:開始權限檢查...");
System.out.println("@Before:目標方法爲:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println("@Before:參數爲:" + Arrays.toString(point.getArgs()));
System.out.println("@Before:被織入的目標對象爲:" + point.getTarget());
}
@AfterReturning(pointcut="permissionCut()",
returning="returnValue")
public void log(JoinPoint point, Object returnValue) {
System.out.println("@AfterReturning:開始記錄返回值...");
System.out.println("@AfterReturning:目標方法爲:" +
point.getSignature().getDeclaringTypeName() +
"." + point.getSignature().getName());
System.out.println("@AfterReturning:參數爲:" +
Arrays.toString(point.getArgs()));
System.out.println("@AfterReturning:返回值爲:" + returnValue);
System.out.println("@AfterReturning:被織入的目標對象爲:" + point.getTarget());
}
@After("permissionCut()")
public void releaseResource(JoinPoint point) {
System.out.println("@Before:結束權限檢查...");
}
複製代碼