jdk動態代理和cglib代理技術在框架中使用非常頻繁,spring框架的AOP技術就使用二者代理技術進行切面編程,通過了解二者的代理機制來對Aop開發更深的理解。在這我分別對兩者代理技術分別做出演示!
jdk動態代理
使用jdk動態代理只需要有jdk環境即可,是基於接口的代理技術,因此目標對象必須實現一個接口。
接口類UserService
package com.it.jdkProxy;
public interface UserService {
void find();
void get();
void udpate();
void delete();
}
目標對象UserServiceImpl
public class UserServiceImpl implements UserService {
@Override
public void find() {
System.out.println("查詢用戶");
}
@Override
public void get() {
System.out.println("保存用戶");
}
@Override
public void udpate() {
System.out.println("更新用戶");
}
@Override
public void delete() {
System.out.println("刪除用戶");
}
private void prov(){
System.out.println("測試private修飾");
}
protected void prot(){
System.out.println("測試protected修飾");
}
}
代理類UserServiceProxyFactory
package com.itcast.jdkProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class UserServiceProxyFactory implements InvocationHandler{
private UserServiceImpl target;
//通過構造傳入目標對象
public UserServiceProxyFactory(UserServiceImpl target) {
super();
this.target = target;
}
//獲取動態代理對象
public UserService getProxyUserService(){
return (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
target.getClass().getInterfaces(),
this);
}
//代理對象的增強方法(核心方法)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//預處理
System.out.println("開啓事務");
//執行目標對象的方法(對所有public方法)
Object invoke = method.invoke(target, args);
//後處理
System.out.println("提交事務");
return invoke;
}
}
測試類TestJdkProxy
package com.itcast.jdkProxy;
import org.junit.Test;
public class TestJdkProxy {
@Test
public void test(){
//創建目標對象
UserServiceImpl target = new UserServiceImpl();
long currentTimeMillis1 = System.currentTimeMillis();
//創建代理工廠
UserServiceProxyFactory proxyFactory = new UserServiceProxyFactory(target);
//得到代理對象
UserService proxyUserService = proxyFactory.getProxyUserService();
long currentTimeMillis2 = System.currentTimeMillis();
//測試增強方法
proxyUserService.find();
proxyUserService.delete();
proxyUserService.get();
proxyUserService.udpate();
System.out.println(currentTimeMillis2-currentTimeMillis1);
}
}
測試結果
cglib代理
cglib代理是基於繼承的代理技術,目標對象必須繼承某個類,所以目標類不應該被final修飾
需要導包
目標對象UserServiceImpl(與jdk演示的目標對象時同一個)
代理類UserServiceImplProxyFactory
package com.itcast.cglibProxy;
import java.lang.reflect.Method;
import com.itcast.jdkProxy.UserServiceImpl;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class UserServiceImplProxyFactory implements MethodInterceptor{
//持有要增強的對象
private UserServiceImpl target;
//持有增強器(手動創建)
private Enhancer enhancer = new Enhancer();
//代理對象的get方法
public UserServiceImpl getProxy(UserServiceImpl target){
//參數傳入要增強的對象
this.target = target;
//設置父類
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
//通過字節碼技術創建實例
return (UserServiceImpl) enhancer.create();
}
/**
* 所有方法都會被這個方法攔截。該類實現了創建子類的方法與代理的方法。
* getProxy方法用過參數傳入父類的字節碼,用過擴展
* 父類的class來創建代理對象。intercapter方法攔截所有目標類方法的調用,
* obj代表目標類的實例,method爲目標類方法的放射對象
* ,args爲方法的動態參數,proxy爲代理類實例
*/
@Override
public Object intercept(Object obj, Method method, Object[] arg , MethodProxy methodProxy)
throws Throwable {
System.out.println("cglib實現事務開始");
Object result = methodProxy.invokeSuper(obj, arg);
System.out.println("cglib實現事務提交!");
return result;
}
}
測試類TestCglibProxy
package com.itcast.cglibProxy;
import java.awt.SystemColor;
import org.junit.Test;
import com.itcast.jdkProxy.UserServiceImpl;
public class TestCglibProxy {
@Test
public void test(){
//創建代理類對象
UserServiceImplProxyFactory proxyFactory = new UserServiceImplProxyFactory();
//得到子類實例
long currentTimeMillis1 = System.currentTimeMillis();
UserServiceImpl proxy = proxyFactory.getProxy(new UserServiceImpl());
long currentTimeMillis2 = System.currentTimeMillis();
//測試增強類的方法
proxy.find();
proxy.delete();
proxy.get();
proxy.udpate();
//查看對象創建耗費的時間
System.out.println("創建對象耗費時間:"+(currentTimeMillis2-currentTimeMillis1));
}
}
測試結果:
總結:
兩者的代理方式有區別.
一是jdk代理的目標對象需要實現一個接口,對pojo類沒有實現任何接口是不能被代理的,cglib代理需要的目標對象需要繼承一個父類,這個條件對於任何類來說都是可以被代理的,因爲所有類的父類都是Object類。
二是jdk動態代理創建代理對象耗費時間非常短,大家可以從測試結果上看出,相比較cglib代理很節省時間資源。所以在創鍵多例對象的代理對象時應該用jdk代理,cglib代理可以用在單例的代理對象創建。
三是動態代理只能對public修飾的方法進行調用,測試中分別寫了protected和private方法,並不能調用。