摘要: 原創出處 https://peijie-sh.gitgub.io 歡迎轉載,保留摘要,謝謝!java
代理是Java經常使用的設計模式,代理類經過調用被代理類的相關方法,實現對相關方法加強。好比加入事務、日誌、報警發郵件等操做。git
靜態代理,就是由程序員手動編寫代理類或者用工具生成代理類的代碼,再進行編譯生成class文件,實現代理。好比簡單工廠模式。程序員
用法:spring
缺點: 靜態代理要爲每一個目標類建立一個代理類,當須要代理的對象太多,那麼代理類也變得不少。代理類違背了可重複代理只寫一次的原則。編程
爲了解決靜態代理的缺點,因而引入了動態代理。 它有一個好處,那就是不用寫不少代理類,生成的代理類數量是固定的。 通常動態代理分爲2種:設計模式
JDK動態代理是JDK自帶的,不依賴第三方框架。 它的實現原理,就是利用Java的反射機制,建立一個實現接口的代理類。框架
用法:dom
下面貼個例子ide
接口類:函數
public interface Subject {
public void doSomething();
}
複製代碼
實現類:
public class RealSubject implements Subject {
public void doSomething() {
System.out.println("do 了 some thing ...");
}
}
複製代碼
代理工廠:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyHandler implements InvocationHandler {
private Object target;
//綁定委託對象,並返回代理類
public Object bind(Object target) {
this.target = target;
//綁定該類實現的全部接口,取得代理類
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy , Method method , Object[] args)throws Throwable {
Object result = null;
//這裏就能夠進行所謂的AOP編程了
//在調用具體函數方法前,執行功能處理
result = method.invoke(target, args);
//在調用具體函數方法後,執行功能處理
return result;
}
}
複製代碼
測試類:
public class TestProxy {
public static void main(String args[]) {
ProxyHandler proxy = new ProxyHandler();
//綁定該類實現的全部接口
Subject sub = (Subject) proxy.bind(new RealSubject());
sub.doSomething();
}
}
複製代碼
使用CGLIB代理須要引入CGLIB庫,它使用字節碼技術實現代理。
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 {
private Object targetObject;// CGLib須要代理的目標對象
public Object createProxyObject(Object obj) {
this.targetObject = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
Object proxyObj = enhancer.create();
return proxyObj;// 返回代理對象
}
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object obj = null;
if ("addUser".equals(method.getName())) {// 過濾方法
checkPopedom();// 檢查權限
}
obj = method.invoke(targetObject, args);
return obj;
}
private void checkPopedom() {
System.out.println("檢查權限 checkPopedom()!");
}
}
複製代碼
public class Test {
public static void main(String[] args) {
Subject sub = (Subject) new CGLibProxy().createProxyObject(new RealSubject());
sub.doSomething();
}
複製代碼
JDK動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。 而CGLIB動態代理是利用asm開源包,加載代理對象類的class文件,修改其字節碼生成子類來處理。
在 Spring 中,
如何強制使用CGLIB實現AOP?
<aop:aspectj-autoproxy proxy-target-class="true"/>
spring.aop.proxy-target-class=true
JDK動態代理和CGLIB字節碼生成的區別?