AOP簡介java
AOP(Aspect-Oriented Programming, 面向切面編程): 是一種新的方法論, 是對傳統 OOP(Object-Oriented Programming, 面向對象編程) 的補充.。
AOP 的主要編程對象是 切面(aspect), 而切面模塊化橫切關注點.。
在應用 AOP 編程時, 仍然須要定義通用的系統功能, 但能夠明確的定義這個功能在哪裏, 以什麼方式應用, 而且沒必要修改受影響的類. 這樣一來橫切關注點就被模塊化到特殊的對象(切面)裏。
AOP的優勢:web
AOP 中的專業術語spring
AOP的兩種底層實現方式express
代理:apache
代理設計模式的原理: 使用一個代理對象將原始對象包裝起來, 而後用該代理對象取代原始對象. 任何對原始對象的調用都要經過代理對象. 代理對象決定是否以及什麼時候將方法調用轉到原始對象上。編程
爲每個目標對象建立一個代理實現類的方式能夠認爲就是靜態代理。設計模式
靜態代理的實現很簡單,可是會形成代理類的快速膨脹,每個目標類,都須要建立一個代理類api
1 //靜態代理 2 public class StaticProxyUserService implements UserService { 3 //原始對象 4 private UserService userService; 5 6 public StaticProxyUserService(UserService userService) { 7 this.userService = userService; 8 } 9 @Override 10 public User getById(String userId) { 11 System.out.println("執行權限校驗,日誌記錄......."); 12 return userService.getById(userId); 13 } 14 @Override 15 public boolean add(User user) { 16 System.out.println("執行權限校驗,日誌記錄......."); 17 return userService.add(user); 18 } 19 20 @Override 21 public boolean delete(String userId) { 22 System.out.println("執行權限校驗,日誌記錄......."); 23 return userService.delete(userId); 24 } 25 @Override 26 public boolean update(User user) { 27 System.out.println("執行權限校驗,日誌記錄......."); 28 return userService.update(user); 29 } 30 }
爲了解決靜態代理的缺點,就產生了動態代理:在系統運行時,動態生成一個持有原始對象,並實現代理接口的Proxy,同時 「植入」通用邏輯(日誌、權限等)。maven
動態代理能夠實現靜態代理相同的功能,惟一的區別這些Proxy的建立都是自動的而且在系統運行時生成的。這樣就不須要對每個原始對象來建立一個代理了。ide
JDK內置的Proxy動態代理能夠在運行時動態生成字節碼,而不必針對每一個類編寫代理類。中間主要使用到了一個接口InvocationHandler與Proxy.newProxyInstance靜態方法。 使用內置的Proxy(JDK動態代理)實現動態代理有一個問題:被代理的類必須實現接口,未實現接口則沒辦法完成動態代理。 若是項目中有些類沒有實現接口,則不該該爲了實現動態代理而刻意去抽出一些沒有實例意義的接口,經過cglib能夠解決該問題。 |
1. 建立maven工程並解決jdk版本及web.xml問題
2. 導入jar包
<properties> <spring-version>4.2.4.RELEASE</spring-version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring-version}</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance --> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.8</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring-version}</version> </dependency> </dependencies> <build> <plugins> <!-- 設置jdk的編譯版本 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf-8</encoding> </configuration> </plugin> </plugins> </build>
3. 編寫切面類(封裝加強邏輯)
1 //切面:定義了加強的業務邏輯(權限驗證) 2 public class SecurityAspect { 3 //權限校驗的系統邏輯 4 public void checkPrivilege(){ 5 System.out.println("我是權限校驗的方法,我須要在方法執行前進行執行"); 6 } 7 }
4. 建立代理對象
1 public class ProxyFactory implements InvocationHandler{ 2 //目標類 3 private Object target; 4 5 //傳遞目標對象 6 public ProxyFactory(Object target) { 7 super(); 8 this.target = target; 9 } 10 11 public Object getProxy(){ 12 /** 13 * loader:類加載器 14 * interfaces:目標實現類接口(jdk動態代理必須有接口) 15 * h:實現了InvocationHandle接口的類 16 */ 17 return Proxy.newProxyInstance(target.getClass().getClassLoader(), 18 target.getClass().getInterfaces(), this); 19 } 20 21 @Override 22 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 23 //添加校驗權限的邏輯 24 SecurityAspect securityAspect = new SecurityAspect(); 25 //添加檢驗權限 26 securityAspect.checkPrivilege(); 27 //反射調用業務邏輯方法(目標類,參數) 28 Object result = method.invoke(target, args); 29 return result; 30 } 31 }
5. 測試
1 public static void main(String[] args) { 2 //測試動態代理的執行 3 UserService target = new UserServiceImpl(); 4 //產生代理對象 5 UserService proxy = (UserService) new ProxyFactory(target).getProxy(); 6 //調用代理對象的業務方法 7 proxy.add(); 8 }
CGLIB(Code Generation Library)是一個開源項目,是一個強大的,高性能,高質量的Code生成類庫,它能夠在運行期擴展Java類與實現Java接口,通俗說cglib能夠在運行時動態生成字節碼。 使用cglib完成動態代理,大概的原理是:cglib繼承被代理的類(UserServiceImpl),重寫方法,織入通知,動態生成字節碼並運行,由於是繼承因此final類是沒有辦法動態代理的。
|
1. 定義目標類(不須要實現接口)
1 /** 2 * cglib的目標類 3 * 沒有實現接口,只是一個業務類 4 */ 5 public class UserServiceCglib { 6 //切入點 7 //業務邏輯方法 8 public void add(){ 9 System.out.println("cglib的add方法被調用..."); 10 } 11 }
2. 定義切面類(加強邏輯類)
1 /** 2 * 加強邏輯類:日誌記錄切面 3 */ 4 public class LogAspect { 5 //通知 6 //加強的業務邏輯 7 public void log(){ 8 System.out.println("日誌記錄... ..."); 9 } 10 }
3. 定義cglib動態代理生成器
1 /** 2 * cglib動態代理類生成器 3 */ 4 public class CglibProxyFactory implements MethodInterceptor{ 5 //目標對象 6 private Object target; 7 8 //有參構造器 9 public CglibProxyFactory(Object target) { 10 super(); 11 this.target = target; 12 } 13 14 //獲取代理類的方法 15 public Object getProxy(){ 16 //調用cglib產生代理對象 17 Enhancer enhancer = new Enhancer(); 18 //設置父類的類型 19 enhancer.setSuperclass(target.getClass()); 20 //設置回調方法 21 enhancer.setCallback(this); 22 23 //產生代理對象 24 Object proxy = enhancer.create(); 25 return proxy; 26 } 27 28 //攔截業務方法的執行 29 @Override 30 public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 31 //添加加強邏輯 32 //添加日誌 33 LogAspect logAspect = new LogAspect(); 34 logAspect.log(); 35 36 //執行業務邏輯方法 37 Object result = methodProxy.invokeSuper(o, args); 38 return result; 39 } 40 }
4. 測試
1 public static void main(String[] args) { 2 //建立目標對象 3 UserServiceCglib target = new UserServiceCglib(); 4 //獲取目標對象的代理對象 5 UserServiceCglib proxy = (UserServiceCglib) new CglibProxyFactory(target).getProxy(); 6 proxy.add(); 7 }