#Java 動態代理java
##1.代理模式 首先了解下設計模式中的代理模式 定義:爲其餘對象提供一種代理以控制對這個對象的訪問。在某些狀況下,一個對象不適合或者不能直接引用另外一個對象,而代理對象能夠在客戶端和目標對象之間起到中介的做用。 UML類圖: 設計模式
代碼:緩存
//Subject public abstract class Subject { public void methodA() { } public void methodB() { } } //RealSubject public class RealSubject extends Subject{ @Override public void methodA() { System.out.println("this is methodA"); } @Override public void methodB() { System.out.println("this is methodB"); } } //Proxy public class Proxy extends Subject{ private Subject subject; public Proxy(Subject subject){ this.subject=subject; } @Override public void methodA() { System.out.println("before this methodA"); subject.methodA(); } @Override public void methodB() { System.out.println("before this methodB"); subject.methodB(); } } //Main public class Main { public static void main(String[] args){ Proxy proxy =new Proxy(new RealSubject()); proxy.methodA(); proxy.methodB(); } }
輸出爲: before this methodA安全
this is methodAapp
before this methodBide
this is methodBui
##2.JDK動態代理this
###2.1瞭解 java.lang.reflect.Proxy類設計
//代理類,它提供了一組靜態方法來爲一組接口動態地生成代理類及其對象。 //靜態變量 //代理緩存 private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); // newProxyInstance 該方法用於爲指定類裝載器、一組接口及調用處理器生成動態代理類實例 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ //生成代理class的地方 Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ //利用反射,使用實現的InvocationHandler做爲參數調用構造方法來得到代理類的實例 try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } } // getProxyClass 該方法用於得到Proxy的Class對象 public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces) throws IllegalArgumentException { //接口clone final Class<?>[] intfs = interfaces.clone(); //安全管理器 final SecurityManager sm = System.getSecurityManager(); //檢查可否獲取Class對象 if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } //調用 getProxyClass0方法 return getProxyClass0(loader, intfs); } // getProxyClass0 private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) { //首先接口的數目不能超過 65535 if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } // If the proxy class defined by the given loader implementing // the given interfaces exists, this will simply return the cached copy; // otherwise, it will create the proxy class via the ProxyClassFactory //JDK對代理進行了緩存,若是已經存在相應的代理類,則直接返回,不然纔會經過ProxyClassFactory來建立代理 return proxyClassCache.get(loader, interfaces); } //靜態內部類 //ProxyClassFactory private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>> { // 全部代理類名字的前綴 private static final String proxyClassNamePrefix = "$Proxy"; // 用於生成代理類名字的計數器 private static final AtomicLong nextUniqueNumber = new AtomicLong(); @Override public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) { Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { Class<?> interfaceClass = null; try { interfaceClass = Class.forName(intf.getName(), false, loader); } catch (ClassNotFoundException e) { } if (interfaceClass != intf) { throw new IllegalArgumentException( intf + " is not visible from class loader"); } if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; // 對於非公共接口,代理類的包名與接口的相同 for (Class<?> intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { accessFlags = Modifier.FINAL; String name = intf.getName(); int n = name.lastIndexOf('.'); String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxyPkg == null) { proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) { throw new IllegalArgumentException( "non-public interfaces from different packages"); } } } // 對於公共接口的包名,默認爲com.sun.proxy if (proxyPkg == null) { proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; // 真正的生成代理類的字節碼的地方 byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { // 根據二進制字節碼返回相應的Class實例 return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) throw new IllegalArgumentException(e.toString()); } } }
###2.2瞭解java.lang.reflect.InvocationHandler類代理
//處理器接口,自定義invoke方法,集中處理在動態代理對象上的調用,一般在該方法中實現對委託類的代理訪問。 //第一個參數爲動態代理對象,第二個參數爲委託對象,第三個對象爲調用參數。 public Object invoke(Object proxy, Method method, Object[] args)
###2.3代碼實現
//HelloWord public interface HelloWord { public void sayHelloWorld(); } //HelloWordImpl public class HelloWordImpl implements HelloWord { public void sayHelloWorld() { System.out.println("HelloWorld!"); } } //HelloWorldHandler public class HelloWorldHandler implements InvocationHandler { // 要代理的原始對象 private Object obj; public HelloWorldHandler(Object obj) { super(); this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; // 調用以前 doBefore(); // 調用原始對象的方法 result = method.invoke(obj, args); // 調用以後 doAfter(); return result; } private void doBefore() { System.out.println("before method invoke"); } private void doAfter() { System.out.println("after method invoke"); } } //Client public class HelloWorldTest { public static void main(String[] args) { HelloWord helloWorld=new HelloWordImpl(); InvocationHandler handler=newHelloWorldHandler(helloWorld); //建立動態代理對象 HelloWord proxy=(HelloWord)Proxy.newProxyInstance( helloWorld.getClass().getClassLoader(), helloWorld.getClass().getInterfaces(), handler); proxy.sayHelloWorld(); } }
輸出結果爲:before method invoke
HelloWorld!
after method invoke
##3.CGLib動態代理
###3.1介紹: CGLib是經過生成java字節碼從而動態的產生代理對象,所以須要字節碼解析處理的依賴asm類庫,字節碼動態生成的代理對象其實是繼承了真實委託類的。這種實現方式須要導入cglib和asm的類庫。 ###3.2原理: 經過字節碼技術爲一個類建立子類,並在子類中採用方法攔截的技術攔截全部父類方法的調用。 ###3.2代碼實現:
//Tiger public class Tiger{ public void run() { System.out.println("Tiger is running"); } } //CglibProxy import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class CglibProxy implements MethodInterceptor { public Object getProxyInstance(Class target) { // 聲明加強類實例 Enhancer enhancer = new Enhancer(); // 設置須要建立子類的類 enhancer.setSuperclass(target); enhancer.setCallback(this); // 經過字節碼技術動態建立子類實例 return enhancer.create(); } public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before"); proxy.invokeSuper(obj, args); System.out.println("after"); return null; } } //Client public class Client { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Tiger tiger = (Tiger)proxy.getProxyInstance(Tiger.class); tiger.run(); } }
輸出爲:before
Tiger is running
after
##4.JDK動態代理和CgLib動態代理比較
* JDK動態代理對有實現接口的對象作代理 * CgLib動態代理對對沒有實現接口的普通類作代理