學而時習之,不亦說乎!
--《論語》
AOP是spring的一個重要組成部分,而AOP通過代理實現。這兒寫下JDK代理和CGLIB代理兩種動態代理,為接下來的Spring AOP做准備。
JDK代理:
1)項目整體結構如下:
2)創建maven項目,pom.xml如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zby</groupId> <artifactId>aop</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency> </dependencies> </project>
這個依賴主要是給CGLIB用的,JDK代理並不需要。
3)創建UserService接口:
package com.zby.service; public interface UserService { void saveUser(String username, String password); }
4)創建UserService接口實現類UserServiceImpl:
package com.zby.service.impl; import com.zby.service.UserService; public class UserServiceImpl implements UserService { public void saveUser(String username, String password) { System.out.println("save user[username=" + username + ",password=" + password + "]"); } }
5)創建CustomAspect切面類:
package com.zby.aspect; public class CustomAspect { public void startTransaction() { System.out.println("I get datasource here and start transaction"); } public void endTrasaction() { System.out.println("I get datasource here and end transaction"); } }
6)創建JDKProxy代理工廠:
package com.zby.factory; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.zby.aspect.CustomAspect; public class JDKProxy { public static Object createProxy(final Object targetObj, final CustomAspect customAspect) { // 使用JDK的Proxy類為目標類創建代理對象 return Proxy.newProxyInstance( // 目標類使用的類加載器 targetObj.getClass().getClassLoader(), // 目標類實現的接口 targetObj.getClass().getInterfaces(), // 執行處理器,代理我們的業務邏輯 new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 執行切面方法 customAspect.startTransaction(); // 具體邏輯代碼執行,返回值為方法執行結果 Object result = method.invoke(targetObj, args); // 執行切面方法 customAspect.endTrasaction(); // 返回方法執行結果 return result; } }); } }
7)編寫測試代碼:
package com.zby.test; import org.junit.Test; import com.zby.aspect.CustomAspect; import com.zby.factory.JDKProxy; import com.zby.service.UserService; import com.zby.service.impl.UserServiceImpl; public class JDKProxyTest { @Test public void testJDKProxy() { System.out.println("before Proxy......"); UserService userService = new UserServiceImpl(); userService.saveUser("zby", "1234567890"); System.out.println("After Proxy......"); UserService proxyUserService = (UserService)JDKProxy.createProxy(userService, new CustomAspect()); proxyUserService.saveUser("zby", "1234567890"); } }
8)控制台打印結果:
before Proxy...... save user[username=zby,password=1234567890] After Proxy...... I get datasource here and start transaction save user[username=zby,password=1234567890] I get datasource here and end transaction
CGLIB代理:
1)使用JDK代理創建的UserService接口,UserServiceImpl實現類和CustomAspect切面類。
2)創建CGLIB的代理類CGLIBProxy:
package com.zby.factory; import java.lang.reflect.Method; import com.zby.aspect.CustomAspect; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CGLIBProxy { public static Object createProxy(final Object targetObj, final CustomAspect customAspect) { Enhancer enhancer = new Enhancer(); // 設置需要代理的父類 enhancer.setSuperclass(targetObj.getClass()); // 設置回調 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { // 執行切面方法 customAspect.startTransaction(); // 具體邏輯代碼執行,返回值為方法執行結果 Object result = methodProxy.invokeSuper(proxy, args); // 執行切面方法 customAspect.endTrasaction(); // 返回方法執行結果 return result; } }); // 3.4 創建代理 return enhancer.create(); } }
3)編寫測試類:
package com.zby.test; import org.junit.Test; import com.zby.aspect.CustomAspect; import com.zby.factory.CGLIBProxy; import com.zby.service.UserService; import com.zby.service.impl.UserServiceImpl; public class CGLIBProxyTest { @Test public void testJDKProxy() { System.out.println("before Proxy......"); UserService userService = new UserServiceImpl(); userService.saveUser("zby", "1234567890"); System.out.println("After Proxy......"); UserService proxyUserService = (UserService) CGLIBProxy.createProxy(userService, new CustomAspect()); proxyUserService.saveUser("zby", "1234567890"); } }
4)控制台打印結果:
before Proxy...... save user[username=zby,password=1234567890] After Proxy...... I get datasource here and start transaction save user[username=zby,password=1234567890] I get datasource here and end transaction
5)CGLIB代理和JDK代理最大的區別就是:CGLIB代理的對象不需要實現任何接口,它使用的字節碼子類代理方式,但是JDK代理的對象必須實現接口。這兒使用CGLIB代理的時候,可以將UserService刪除,使用UserServiceImpl接收代理結果,效果完全一樣。
6)JDK代理的實質是生成一個實現我們傳入的接口,並且繼承Proxy的類;Cglib代理實質是繼承我們傳入的類。