代理模式分爲兩種,靜態代理 和 動態代理,靜態代理簡單易懂,對於新手來說便於理解,但實際運用到項目中代碼量以及維護量都是非常大的,在企業級項目中不推薦使用這種方式,用於學習或者做畢設還是可以的,本文中只闡述動態代理模式,記錄在這用於加深自身理解,同時希望能對您有所幫助。
JDK 動態代理
這種方式,只能對實現了接口的類生成代理,JDK動態代理採用委託機制,動態實現接口類,在動態生成的實現類中委託hanlder去調用原始實現類方法,但對於沒有實現接口的類來說,就不適用了
/**
* 接口
*/
public interface Person {
void say();
}
/**
* 實現類
* 對於JDK 動態代理來說,只有 實現了接口的類纔可以使用這種代理方式
*/
public class Children implements Person {
@Override
public void say() {
System.out.println("你好,世界。");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK 動態代理
*/
public class JDKProxy implements InvocationHandler {
private Object targetObject;
public Object newProxy(Object targetObject){
this.targetObject = targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("練習發音");
// 這裏切勿 使用 proxy 傳參變量,會報錯喲
// 在newProxy 方法 接收的參數targetObject,目的是在這裏被運用
Object result = method.invoke(targetObject, args);
System.out.println("恭喜成功");
return result;
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
Person person = (Person) new JDKProxy().newProxy(new Children());
person.say();
// 報錯信息:Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to Children
// at Main.main(Main.java:12)
// JDK 動態代理,動態生成的實現類 和 Children 並無關係,所以這裏強轉會報錯
// 這種方式,採用委託機制,在動態生成的實現類裏,委託Handler去調用原始實現類中的方法
/*
Children children = (Children) new JDKProxy().newProxy(new Children());
children.say();
*/
}
}
CGlib 動態代理
這種方式,不限制類是否實現了接口,相對於JDK 動態代理改進不少,同時又比JDK動態代理具備更高效的執行效率。
/**
* 沒有實現接口的類,用於Cglib 動態代理
*/
public class User {
public void shopping(){
System.out.println("去海吉星採購");
}
}
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 CglibProxy implements MethodInterceptor {
private Object targetObject;
public Object newProxy(Object targetObject){
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetObject.getClass());
enhancer.setCallback(this);
Object object = enhancer.create();
return object;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("開始處理……");
Object result = method.invoke(targetObject, args);
System.out.println("結束活動");
return result;
}
}
public class Main {
public static void main(String[] args) {
User user = (User) new CglibProxy().newProxy(new User());
user.shopping();
}
}
Cglib方式,上面的代碼如要運行成功,還需 額外引入 cglib-2.2.jar 和 asm-3.1jar,這兩個包,特別注意的事,cglib-3.1.jar,引入會報錯,由於時間關係,沒有特別深入的瞭解原因,換成 2.2版本即可