動態代理是為了實現Aop編程(不修改類源碼,類方法執行前后,自定義增強處理, 日志 攔截等等),代理的是類對象
一、jdk動態代理
被代理的類需要實現接口,針對接口的代理,通過生成一個實現了接口的動態類實現代理
- ServiceImpl是被代理類,實現接口ServiceInterface
- JDKProxy是代理處理方法類,實現接口InvocationHandler
- 通過JDKProxy.bind()得到jdk【動態生成】代理類ServiceProxy (ServiceInterface),當你調用ServiceProxy.doService()會執行JDKProxy的invoke()方法,實現代理
public interface ServiceInterface {public void doService();
}
public class ServiceImpl implements ServiceInterface {public void doService() {System.out
.println("ServiceImpl");}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class JDKProxy implements InvocationHandler {private Object target
= null;public Object bind(Object target
) {this.target
= target
;return Proxy.newProxyInstance(target
.getClass().getClassLoader(),target
.getClass().getInterfaces(),this);}public Object invoke(Object proxy
, Method method
, Object[] args
) throws Throwable {System.out
.println("before method:"+method
.getName());Object res
= method
.invoke(target
,args
);System.out
.println("after method");return res
;}public static void main(String[] args
) {ServiceInterface service
= (ServiceInterface) new JDKProxy().bind(new ServiceImpl());service
.doService();}}
二、cglib動態代理
通過生成被代理類的【子類】實現代理,所以 Cglib是無法代理final修飾的方法或類
- ServiceImpl是被代理類
- ServiceProxy是代理處理類,實現接口MethodInterceptor
- 通過ServiceProxy.getProxy()動態生成被代理類子類ServiceImpl_SubClass (ServiceImpl)當你調ServiceImpl_SubClass.doService()會執行ServiceProxy.Intercept()方法,實現代理
public interface ServiceInterface {public void doService();
}
public class ServiceImpl implements ServiceInterface{public void doService() {System.out
.println("ServiceImpl");}
}
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class ServiceProxy implements MethodInterceptor {private Enhancer enhancer
= new Enhancer();public Object getProxy(Class clazz
) {enhancer
.setSuperclass(clazz
);enhancer
.setCallback(this);return enhancer
.create();}public Object intercept(Object o
, Method method
, Object[] objects
, MethodProxy methodProxy
) throws Throwable {System.out
.println("before method:" + method
.getName());Object res
= methodProxy
.invokeSuper(o
, objects
);System.out
.println("after method");return res
;}public static void main(String[] args
) {ServiceInterface service
= (ServiceImpl) new ServiceProxy().getProxy(ServiceImpl.class);service
.doService();}
}
//pom.xml
<dependency><groupId>cglib
</groupId><artifactId>cglib
</artifactId><version>2.2.2
</version></dependency>
上面的jdk與cglib動態代理例子,沒有改變ServiceInterface接口與ServiceImpl實現類代碼,通過一個代理處理類實現動態對ServiceImpl的代理,方法執行前后增強處理,打印日志,也可以通過try catch捕獲方法中的異常實現事務控制等等
三、兩者的切換
JDK動態代理 Proxy.newProxyInstance() 通過接口創建代理的實現類Cglib動態代理 Enhancer 通過繼承父類創建的代理類 (沒有實現接口的話spring底層就切換成CGLib的方式)
四、Spring動態代理用JDK還是用CGLIB
動態代理又有兩種實現方式:
- 一種方法是直接實現JDK中的InvocationHandler接口
- 另一種方法是繼承CGLIB。
那么問題來了,這兩種方法有啥區別呢,分別適用于什么情況呢?
首先如果不是很清楚兩者的區別的話,記住一般情況下InvocationHandler要比CGLIB要好就行了。
如果目標對象的代理至少實現了一個接口,那么就用JDK動態代理,所有由目標對象實現的接口將全部都被代理。如果目標對象沒有實現任何接口,那么就用CGLIB代理。
但是如果非要使用CGLIB的話,那么CGLIB可能有下面的問題:
剛才提到了,InvocationHandler是實現的接口,而CGLIB則是繼承的父類,那么由于繼承的限制,如果父類中有final的成員,那么是繼承不到的。
還有從Spring 3.2以后不再將CGLIB放在項目的classpath下,而是將CGLIB類打包放在spring-core下面的org.springframework中。這個就意味著基于CGLIB的動態代理與JDK的動態代理在支持“just works”就一樣了。
在Spring 4.0中,因為CGLIB代理實例是通過Objenesis創建的,所以代理對象的構造器不再有兩次調用。
想要強制使用CGLIB,那么就設置aop:config下面的proxy-target-class屬性為true:
<aop
:config proxy
-target
-class="true"><!-- other beans defined here
... -->
</aop
:config
>
要是使用@AspectJ強制使用CGLIB的話,可以配置aop:aspectj-autoproxy下的proxy-target-class屬性為true:
<aop
:aspectj
-autoproxy proxy
-target
-class="true"/>
注意: Spring AOP 代理默認實現 JDK SpringBOOT AOP 代理默認實現 Cglib
參考文章1
參考文章2
總結
以上是生活随笔為你收集整理的jdk动态代理与cglib动态代理--InvocationHandler--MethodInterceptor的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。