先思考一下,什么是代理? 為什么要代理?
代理 或稱為 proxy 自己不用去做,別人代替你去做。
為其他對象提供一種代理以控制對這個對象的訪問。
它在程序中起著非常重要的作用,比如傳說中AOP,就是針對代理的一種應用,此外,在設計模式中有一個 “代理模式”。在公司上外網,要在瀏覽器里設置一個HTTP代理,可見代理無處不見。
凡事由淺入深,我們先來看看demo:
靜態代理
接口的定義
package com.coderpwh.demo;
/**
* Created by coderpwh on 2017/8/23.
*/
public interface Hello {
void say(String name);
}
實現類
package com.coderpwh.demo;
/**
* Created by coderpwh on 2017/8/23.
*/
public class HelloImpl implements Hello {
@Override
public void say(String name) {
System.out.println("hello!"+name);
}
}
我們在來看看代理類
package com.coderpwh.demo;
/**
* Created by coderpwh on 2017/8/23.
*/
public class HelloProxy implements Hello{
private Hello hello;
public HelloProxy() {
hello = new HelloImpl();
}
@Override
public void say(String name) {
before();
hello.say(name);
after();
}
public void before(){
System.out.println("Before");
}
public void after(){
System.out.println("After");
}
}
運行結果:
這樣就是實現了一個代理,在網上教程或者設計模式書上看到 ,這個HelloProxy 就是代理設計模式
當然這也只是靜態的代理模式 ,當然隨著業務需要 如果都去寫 HelloProxy 類似這樣的代理模式,垃圾代碼會越來越多,此時我么需要動態代理,將這些垃圾Proxy 重構成動態代理。
JDK動態代理
看栗子:
package com.coderpwh.demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK 動態代理類
* Created by coderpwh on 2017/8/23.
*/
public class DynamicProxy implements InvocationHandler {
private Object target; // 代理的目標對象
public DynamicProxy(Object target){ // 構造方法
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target,args);
after();
return result;
}
private void before() {
System.out.println("before");
}
private void after(){
System.out.println("After");
}
// 注: <T> 是定義泛型,T 是使用泛型.
/**
* ClassLoader 類加載器
* Interface 目標對象實現的接口
* this 目標對象
* @param <T>
* @return
*/
// <T> 是定義泛型 ,后面的T就是泛型
public <T> T getProxy(){
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
}
DynamicProxy implements InvocationHandler ,DynamictProxy 實現了InvocationHandler 接口 當然要實現它的invoke方法,在該方法中是通過反射的方式去執行 method.invoke 的。
注意 Proxy.newProxyInstance 方法中參數,
ClassLoader 類加載器
Interface 實現類所有接口
this 代理對象
測試類
package com.coderpwh.demo;
/**
* Created by coderpwh on 2017/8/23.
*/
public class DynamicTest {
public static void main(String[] args) {
DynamicProxy dynamicProxy = new DynamicProxy(new HelloProxy()); // 有參構造
Hello helloProxy = dynamicProxy.getProxy();
helloProxy.say("jack");
}
}
運行結果:
此時思考一下JDK動態代理比靜態代理好在哪里?
在靜態代理中,接口變了,實現類也要變,代理類也要變,而在動態代理中,接口變了,代理類不用改變。
接著思考,怎樣代理沒有接口的類?
CGLib代理
CGLib代理類:
package com.coderpwh.demo;
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 CGLibDynamicProxy implements MethodInterceptor {
/**
* 構造函數私有,成員變量私有
*/
private static CGLibDynamicProxy instance = new CGLibDynamicProxy();
private CGLibDynamicProxy() {
}
public static CGLibDynamicProxy getInstance() {
return instance;
}
// <T> 定義泛型 而后面的T 就是表示泛型 如:String ,Integer
@SuppressWarnings("unchecked")
public <T> T getProxy(Class<T> cls) {
return (T) Enhancer.create(cls, this);
}
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
before();
Object result = proxy.invokeSuper(target, args);
after();
return result;
}
private void after() {
System.out.println("After");
}
private void before() {
System.out.println("Before");
}
}
測試類
package com.coderpwh.demo;
/**
* Created by hello world on 2017/8/25.
*/
public class CGLibTest {
public static void main(String[] args) {
Hello helloProxy = CGLibDynamicProxy.getInstance().getProxy(HelloImpl.class);
helloProxy.say("jack");
}
}
運行結果:
實現CGLib代理 ,要實現 MethodInterceptor 接口(要導入CGLib jar包或者依賴) 填充intercept方法,
注意 intercept方法的最后一個參數
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)
proxy ,有了這個參數我們就可以直接調用 invokeSuper(Object obj, Object[] args) 了,CGLib代理是方法級別的代理。仔細看上面的代碼,CGLibDynamicProxy 類的構造方法是私有的,這是什么設計模式?用private 來修飾這個構造方法是為了不讓外界new 它了。
最近在復習Spring ,把靜態代理,JDK代理,CGLib代理 簡單復習了一下。當然代理的世界遠比折磨大。后面會逐漸深入研究代理,研究Spring AOP底層實現。