1.什麼是AOP, 什麼是AspectJ,spring
2. 什麼是Spring AOP數據庫
3. Spring AOP註解版實現原理編程
4. Spring AOP切面原理解析安全
aop是面向切面編程,相比傳統oop,aop可以在方法的前置,中置,後置中插入邏輯代碼,對於項目中大量邏輯重複的代碼,使用aop能很好的收口邏輯,將邏輯獨立於業務代碼以外,一處編寫,多處使用。ide
AOP是Object Oriented Programming(OOP)的補充.函數
OOP可以很好地解決對象的數據和封裝的問題,卻不能很好的解決Aspect("方面")分離的問題。下面舉例具體說明。oop
好比,咱們有一個Bank(銀行)類。Bank有兩個方法,save(存錢)和withdraw(取錢)。gradle
類和方法的定義以下:ui
package com.lxl.www.aop; public class Bank { /** * 存錢 */ public Float save(Account account, float money) { // 增長account帳戶的錢數,返回帳戶裏當前的錢數 return null; } /** * 取錢 */ public Float withdraw(Account account, float money) { // 減小account帳戶的錢數,返回取出的錢數 return null; } };
這兩個方法涉及到用戶的帳戶資金等重要信息,必需要很是當心,因此編寫完上面的商業邏輯以後,項目負責人又提出了新的要求--給Bank類的每一個重要方法加上安全認證特性。spa
因而, 咱們在兩個方法上增長安全代碼
改後的類和方法以下:
public class Bank { /** * 存錢 */ public Float save(Account account, float money) { // 驗證account是否爲合法用戶 // 增長account帳戶的錢數,返回帳戶裏當前的錢數 return null; } /** * 取錢 */ public Float withdraw(Account account, float money) { // 驗證account是否爲合法用戶 // 減小account帳戶的錢數,返回取出的錢數 return null; } };
這兩個方法都須要操做數據庫,爲了保持數據完整性,項目負責人又提出了新的要求--給Bank類的每一個操做數據庫的方法加上事務控制。
因而,咱們不得不分別在上面的兩個方法中加入安全認證的代碼。
類和方法的定義以下:
package com.lxl.www.aop; public class Bank { /** * 存錢 */ public Float save(Account account, float money) { // 驗證account是否爲合法用戶 // begin Transaction // 增長account帳戶的錢數,返回帳戶裏當前的錢數 // end Transaction return null; } /** * 取錢 */ public Float withdraw(Account account, float money) { // 驗證account是否爲合法用戶 // begin Transaction // 減小account帳戶的錢數,返回取出的錢數 // end Transaction return null; } };
咱們看到,這些與商業邏輯無關的重複代碼遍及在整個程序中。實際的工程項目中涉及到的類和函數,遠遠不止兩個。如何解決這種問題?
AOP就是爲了解決這種問題而出現的。在不修改代碼的狀況下達到加強的效果
對照上圖, 來對應每個區域,看看其具體含義
package com.lxl.www.aop.bank; public interface Bank { /** * 存錢 */ Float save(Account account, float money) ; /** * 取錢 */ Float withdraw(Account account, float money); };
package com.lxl.www.aop.bank; import org.springframework.stereotype.Service; /** * 工商銀行 * * * DATE 2020/12/6. * * @author lxl. */ @Service public class IcbcBank implements Bank{ @Override public Float save(Account account, float money) {
// 主業務邏輯: 增長account帳戶的錢數,返回帳戶裏當前的錢數 System.out.println(account.getName() + "帳戶存入" + money); return null; } @Override public Float withdraw(Account account, float money) {
// 主業務邏輯: 減小account帳戶的錢數,返回取出的錢數 System.out.println(account.getName() + "帳戶取出" + money); return null; } }
package com.lxl.www.aop.bank; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.DeclareParents; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * 切面 */ @Aspect // 標記這是一個切面 @Order @Component // 將其放到ioc容器管理 public class BankLogAspect { /** * 引入 * * 這段話能夠理解爲, 爲com.lxl.www.aop.bank.IcbcBank 引入了一個接口 EnhanceFunctionOfBank, * 同時, 引入了默認的實現類 IcbcEnhanceFunctionOfBank */ @DeclareParents(value = "com.lxl.www.aop.bank.IcbcBank", // 引入的目標類. 也就是須要引入動態實現的類 defaultImpl = IcbcEnhanceFunctionOfBank.class) // 引入的接口的默認實現 public static EnhanceFunctionOfBank enhanceFunctionOfBank; // 引入的接口 /** * 定義一個切點 */ @Pointcut("execution(* com.lxl.www.aop.bank.IcbcBank.*(..))") public void pointCut() {} /** * 定義一個前置通知 * @param joinPoint */ @Before(value = "pointCut()") public void beforeAdvice(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("執行目標方法"+methodName+"的前置通知"); } /** * 定義了一個後置通知 */ @After(value = "pointCut()") public void afterAdvice(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("執行目標方法"+methodName+"的後置通知"); } /** * 定義了一個返回通知 */ @AfterReturning(value = "pointCut()", returning = "result") public void returningAdvice(JoinPoint joinPoint, Object result) { String methodName = joinPoint.getSignature().getName(); System.out.println("執行目標方法"+methodName+"的返回通知"); } /** * 定義了一個異常通知 */ @AfterThrowing(value = "pointCut()") public void throwingAdvice(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("執行目標方法"+methodName+"的異常通知"); } }
那麼這裏的目標對象是誰呢? 就是咱們的IcbcBank類. 這裏須要注意的是引入: 引入的概念是將一個接口動態的讓另外一個類實現了. 這樣實現了接口的類, 就能夠動態的擁有接口實現類的功能.
package com.lxl.www.aop.bank; /** * 加強的功能 */ public interface EnhanceFunctionOfBank { void Financialanagement(Account account); }
package com.lxl.www.aop.bank; import org.springframework.stereotype.Service; /** * Description */ @Service public class IcbcEnhanceFunctionOfBank implements EnhanceFunctionOfBank { /** * 理財功能 * @param account */ @Override public void Financialanagement(Account account) { System.out.println(account.getName() +"的帳戶 增長 理財功能"); } }
這個功能咱們能夠經過引入,動態增長到IcbcBank類中, 本來IcbcBank只有存錢和取錢的功能. 這樣, 就能夠增長理財功能了. 這就是引入.
package com.lxl.www.aop.bank; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configurable // 使用註解的方式引入AOP @EnableAspectJAutoProxy @ComponentScan("com.lxl.www.aop.bank") public class BankMainConfig { }
使用aop,須要引入AOP, 這裏使用的註解的方式引入的.
package com.lxl.www.aop.bank; import com.lxl.www.aop.Calculate; import com.lxl.www.aop.MainConfig; import com.lxl.www.aop.ProgramCalculate; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class BankMainClass { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BankMainConfig.class); Account account = new Account("張三"); Bank bank = (Bank) ctx.getBean("icbcBank"); bank.save(account, 100); System.out.println(); EnhanceFunctionOfBank enhanceFunctionOfBank = (EnhanceFunctionOfBank) ctx.getBean("icbcBank"); enhanceFunctionOfBank.Financialanagement(account); } }
如上, 運行結果:
最後咱們還須要引入到指定的項目中
以上就是對整個AOP的理解. 接下來, 分析AOP的源碼.
詳見第二篇文章
as