代理模式

一 代理模式java

定義:在訪問目標對象的時候,提供一種間接訪問的方法,經過代理對象去訪問目標對象,達到客戶端的目的。api

好處:保護目標對象;在目標對象的行爲基礎上,代理對象能夠增長本身的處理,使得同一個目標對象能夠知足不一樣的客戶端的目的。app

代理模式的模型:ide

image.png

涉及三個角色:函數

RealSubject:目標對象,也是真正要作事情的人。ui

Proxy:代理對象,持有對目標對象的引用,暴露給客戶端,經過操做目標對象來完成客戶端的目的。而且,代理對象能夠在操做目標對象的先後作一些自定義的行爲,靈活擴展了目標對象。this

Subject:目標對象和代理對象的抽象,以便在任何使用目標對象的地方均可以使用代理對象。Subject能夠是一個接口也能夠是一個抽象類。spa

二 靜態代理代理

以最簡單的形式實現上述模型code

public interface Subject {
    void doRequst();
}
public class RealSubject implements Subject {

    @Override
    public void doRequst() {
        System.out.println("it's the thing i really want to do");
    }
}
public class Proxy implements Subject {
    private Subject subject;

    public Proxy(Subject subject){
        this.subject = subject;
    }

    @Override
    public void doRequst() {
        System.out.println("before do the real thing");
        subject.doRequst();
        System.out.println("after do the real thing");
    }
}
public class Client {
    public static void main(String[] args) {
        Proxy proxy = new Proxy(new RealSubject());
        proxy.doRequst();
    }
}
/**
before do the real thing
it's the thing i really want to do
after do the real thing
**/

這種實現方式即常說的靜態代理,有幾個方面的約束:

1 代理對象和目標對象須要實現共同的接口,接口有變更,目標對象和代理對象都須要維護。

2 想要代理其餘的目標對象,須要新增代理類。

三 動態代理

先看java實現動態代理的幾個主要角色

1  Proxy :java.lang.reflect.Proxy,jdk api提供的代理類的主類,該類提供方法動態生成代理類,生成的時候須要指定一組接口(即代理類和目標對象要實現哪些接口)

public static Object newProxyInstance(ClassLoader var0, Class<?>[] var1, final InvocationHandler var2) throws IllegalArgumentException 
/**
提供了這個靜態方法用於動態生成代理類
var0:   目標對象的類加載器
var1:  代理類要實現哪些接口,即目標對象實現的接口
var2:  處理器,代理類具體要作什麼寫在處理器中
**/

2 InvocationHandler :java.lang.reflect.InvocationHandler

/**
@param  proxy the proxy instance that the method was invoked on
代理對象,執行invoke的時候實際上是在替這個proxy執行

@param  method the {@code Method} instance corresponding to
the interface method invoked on the proxy instance.  The declaring
class of the {@code Method} object will be the interface that
the method was declared in, which may be a superinterface of the
proxy interface that the proxy class inherits the method through.
目標對象要執行的方法

@param  args an array of objects containing the values of the
arguments passed in the method invocation on the proxy instance,
or {@code null} if interface method takes no arguments.
Arguments of primitive types are wrapped in instances of the
appropriate primitive wrapper class, such as
{@code java.lang.Integer} or {@code java.lang.Boolean}.
執行方法須要的參數
**/
 
public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable
 

java動態代理實例

public interface Subject {
    void doRequest();
}
public class RealSubject1 implements Subject {

    @Override
    public void doRequest() {
        System.out.println("RealSubject1 want to sing");
    }
}
public class RealSubject2 implements Subject {

    @Override
    public void doRequest() {
        System.out.println("RealSubject2 want to dance");
    }
}
public class RealInvocationHandler implements InvocationHandler {
    private Object subject;

    public RealInvocationHandler(Object subject){
        this.subject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before process");
        Object result = method.invoke(subject,args);
        System.out.println("after process");
        return result;
    }
}
public class Client {
    public static void main(String[] args) {
        Subject realSubject1 = new RealSubject1();
        InvocationHandler handler1 = new RealInvocationHandler(realSubject1);
        Subject subject1 = (Subject) Proxy.newProxyInstance(realSubject1.getClass().getClassLoader(),realSubject1.getClass().getInterfaces(),handler1);
        subject1.doRequest();
        System.out.println("-----------------------");
        Subject realSubject2 = new RealSubject2();
        InvocationHandler handler2 = new RealInvocationHandler(realSubject2);
        Subject subject2 = (Subject)Proxy.newProxyInstance(realSubject2.getClass().getClassLoader(),realSubject2.getClass().getInterfaces(),handler2);
        subject2.doRequest();
    }
}
/**
before process
RealSubject1 want to sing
after process
-----------------------
before process
RealSubject2 want to dance
after process
**/

與靜態代理作個比較:

不須要挨個寫代理類,想代理其餘的,動態new一個代理類

相關源碼解析

Proxy.newProxyInstance生成的代理具有什麼以及爲何能夠轉換成目標對象

protected InvocationHandler h;  
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    // 校驗handler
    if (h == null) {
        throw new NullPointerException();
    }

    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
     * Proxy維護了一個proxyClassCache,若是想要的代理類已經有實現了指定接口的loader定義好了,直接返回cache的備份
     * 不然,經過ProxyClassFactory 生成一個代理類,實現指定的intfs
     */
    Class<?> cl = getProxyClass0(loader, intfs);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        //獲取構造函數,將傳進來的h賦給proxy內部持有的Invokerhanler對象
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
            // create proxy instance with doPrivilege as the proxy class may
            // implement non-public interfaces that requires a special permission
            return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    return newInstance(cons, ih);
                }
            });
        } else {
            return newInstance(cons, ih);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString());
    }
}

因此,Proxy生成的代理對象具有一個invokehandler對象的引用;而且實現了目標對象實現的接口,由於能夠轉換爲目標對象的抽象

InvokeHandler爲何能夠完成目標對象方法的執行

如上述例子中目標對象RealSubject1要執行doRequest方法,Proxy生成的代理類也會實現這個方法,大概以下:

public final void doRequest()
 
    {
        //這個會調用invokehandler的invoke方法,這裏的h便是父類Proxy的h,經過newProxyInstance傳進來的
        try {
            this.h.invoke(this, m3, null);
            return;
        } catch (RuntimeException localRuntimeException) {
            throw localRuntimeException;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
 
    }

有了InvocationHandler 可使Proxy從具體的代碼邏輯抽離出來,更方便統一的生成代理類。

後續todo:

Proxy生成的代理對象的具體剖析

method.invoke具體作了什麼

相關文章
相關標籤/搜索