先思考一下,什么是代理憨颠? 為什么要代理胳徽?
代理 或稱為 proxy 自己不用去做,別人代替你去做烙心。
為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn)膜廊。
它在程序中起著非常重要的作用,比如傳說(shuō)中AOP,就是針對(duì)代理的一種應(yīng)用淫茵,此外爪瓜,在設(shè)計(jì)模式中有一個(gè) “代理模式”。在公司上外網(wǎng)匙瘪,要在瀏覽器里設(shè)置一個(gè)HTTP代理铆铆,可見(jiàn)代理無(wú)處不見(jiàn)。
凡事由淺入深丹喻,我們先來(lái)看看demo:
靜態(tài)代理
接口的定義
package com.coderpwh.demo;
/**
* Created by coderpwh on 2017/8/23.
*/
public interface Hello {
void say(String name);
}
實(shí)現(xiàn)類
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);
}
}
我們?cè)趤?lái)看看代理類
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");
}
}
運(yùn)行結(jié)果:
這樣就是實(shí)現(xiàn)了一個(gè)代理薄货,在網(wǎng)上教程或者設(shè)計(jì)模式書上看到 ,這個(gè)HelloProxy 就是代理設(shè)計(jì)模式
當(dāng)然這也只是靜態(tài)的代理模式 碍论,當(dāng)然隨著業(yè)務(wù)需要 如果都去寫 HelloProxy 類似這樣的代理模式谅猾,垃圾代碼會(huì)越來(lái)越多,此時(shí)我么需要?jiǎng)討B(tài)代理鳍悠,將這些垃圾Proxy 重構(gòu)成動(dòng)態(tài)代理税娜。
JDK動(dòng)態(tài)代理
看栗子:
package com.coderpwh.demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK 動(dòng)態(tài)代理類
* Created by coderpwh on 2017/8/23.
*/
public class DynamicProxy implements InvocationHandler {
private Object target; // 代理的目標(biāo)對(duì)象
public DynamicProxy(Object target){ // 構(gòu)造方法
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 目標(biāo)對(duì)象實(shí)現(xiàn)的接口
* this 目標(biāo)對(duì)象
* @param <T>
* @return
*/
// <T> 是定義泛型 ,后面的T就是泛型
public <T> T getProxy(){
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
}
DynamicProxy implements InvocationHandler ,DynamictProxy 實(shí)現(xiàn)了InvocationHandler 接口 當(dāng)然要實(shí)現(xiàn)它的invoke方法,在該方法中是通過(guò)反射的方式去執(zhí)行 method.invoke 的藏研。
注意 Proxy.newProxyInstance 方法中參數(shù)敬矩,
ClassLoader 類加載器
Interface 實(shí)現(xiàn)類所有接口
this 代理對(duì)象
測(cè)試類
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()); // 有參構(gòu)造
Hello helloProxy = dynamicProxy.getProxy();
helloProxy.say("jack");
}
}
運(yùn)行結(jié)果:
此時(shí)思考一下JDK動(dòng)態(tài)代理比靜態(tài)代理好在哪里?
在靜態(tài)代理中蠢挡,接口變了弧岳,實(shí)現(xiàn)類也要變,代理類也要變业踏,而在動(dòng)態(tài)代理中禽炬,接口變了,代理類不用改變勤家。
接著思考瞎抛,怎樣代理沒(méi)有接口的類?
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 {
/**
* 構(gòu)造函數(shù)私有,成員變量私有
*/
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");
}
}
測(cè)試類
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");
}
}
運(yùn)行結(jié)果:
實(shí)現(xiàn)CGLib代理 却紧,要實(shí)現(xiàn) MethodInterceptor 接口(要導(dǎo)入CGLib jar包或者依賴) 填充intercept方法桐臊,
注意 intercept方法的最后一個(gè)參數(shù)
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy)
proxy ,有了這個(gè)參數(shù)我們就可以直接調(diào)用 invokeSuper(Object obj, Object[] args) 了,CGLib代理是方法級(jí)別的代理晓殊。仔細(xì)看上面的代碼断凶,CGLibDynamicProxy 類的構(gòu)造方法是私有的,這是什么設(shè)計(jì)模式巫俺?用private 來(lái)修飾這個(gè)構(gòu)造方法是為了不讓外界new 它了认烁。
最近在復(fù)習(xí)Spring ,把靜態(tài)代理介汹,JDK代理却嗡,CGLib代理 簡(jiǎn)單復(fù)習(xí)了一下。當(dāng)然代理的世界遠(yuǎn)比折磨大嘹承。后面會(huì)逐漸深入研究代理窗价,研究Spring AOP底層實(shí)現(xiàn)。