デザインパターンプロキシモード(ジャワ)

簡単な紹介

利益を見ては、依然として高いので、プロキシモード率直な外観は非常に高く、ほとんど例外なく、すべてのフレームワークは、代理店モデルを使用していました。

プロキシモードとは何ですか

プロキシモードを記述するために言葉を使用する場合:

あるプロキシオブジェクト、へのアクセスを制御するプロキシを提供するために、プロキシモードでは、私たちはしばしば、仲介が別のオブジェクトであると言います

開発や生活の中で、多くの場合、フォワードプロキシ、リバースプロキシなどの単語、イラストを聞きます

  • フォワードプロキシ

    我々はグーグル、私たちは私たちがグーグルを訪問するためのはしごを見つける必要があり、この時、私たちはこのプロキシはしごを返すために必要な情報にアクセスすることはできませんネットワーク上の理由として、

  • リバースプロキシ

    セキュリティ用のサーバーとして、我々は、サーバーへの実際の情報を公開したくない、それは無法の要素の攻撃を防ぐためになっている、私たちは私がユーザの要求を受け入れる統一プロキシを必要とし、ユーザーに役立ちます。この時間は、バックエンドユーザーがユーザーに返される要求します

アクションのプロキシモード

一言で言えばが切り離されて、私達の使用のためのアクセスオブジェクトでき​​ませんが、それはパッケージを破壊しないように、我々は開閉の原則を満たすために、プロキシオブジェクト内のいくつかの追加機能を追加することができますプロキシを作成

UML

眠っている動物の行動があり、ほとんどの人はホッキョクグマを見ていない(RealSubject)メソッドは、我々は唯一の私たちはホッキョクグマを参照してください絵から返された北極にカメラマン(プロキシ)のプログラムグループを介して、動物の世界を撮影することができますそのデンで眠っている、とも「ここを見て、唯一のホッキョクグマが冬眠している!」、画面上のキャプションを追加しました

練習

いくつかの方法を達成するためのエージェントモデルは、静的および動的エージェントプロキシに分けることができます

帯電防止剤

  • 主題
public interface LifeService {
    String sleep();
}
  • RealSubject
public class WhiteBear implements LifeService {
    @Override
    public String sleep() {
        return "Zzzzzzz";
    }
}
  • 代理
public class Proxy implements LifeService {

    // 被代理对象
    private LifeService target;

    public Proxy(LifeService target) {
        this.target = target;
    }

    @Override
    public String sleep() {
        // 拿到被代理对象行为的返回值,加上辅助功能,一起返回
        return "快看这里有只冬眠的北极熊! \n" + this.target.sleep();
    }
}
  • 工場では、工場は、直接新しいクライアントを行うことができます
public class ProxyFactory {

    public static Proxy getLifeServiceProxy(Class clz) throws IllegalAccessException, InstantiationException {
        LifeService target = (LifeService) clz.newInstance();
        return new Proxy(target);
    }
}
  • クライアント
public class Test {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Proxy proxy = ProxyFactory.getLifeServiceProxy(WhiteBear.class);
        System.out.println(proxy.sleep());
    }

    /**
     * 输出:
     * 快看这里有只冬眠的北极熊!
     * Zzzzzzz
     */
}

あなたは、いわゆる静的なバイトコードファイルが既に実行する前に、プロキシクラスに存在している、2つのクラスのバイトコードファイルを生成し、我々はエージェントとエージェントクラスが書かれていることを静的エージェント実際には非常によく理解して見ることができます

不十分な

  • プロキシ多くの方法にしたい場合は、インターフェイスプロキシオブジェクトは、各メソッドのためのエージェントを実行しているにバインドされ、対象物の一種類のみを提供するために、プログラムの少し大きめのサイズの帯電防止剤は、有能実行することはできません。
  • インターフェイスは、メソッドを追加する場合は、このメソッドを実装するために、すべての実装クラスのニーズに加えて、すべてのプロキシクラスも、このメソッドを実装する必要があります。これは、コードの保守の複雑さを増します

動的プロキシ

JDKが来ます

一般的な考え方は、実行中のプロセスにある JVMの 監視を、指定された挙動の発生が、プロキシオブジェクトの反射を介してアクセスするときに作成されたダイナミックエージェンシー
  • 主題
public interface LifeService {
    String sleep();
    String wake();
}
  • RealSubject
public class Person implements LifeService {
    @Override
    public String sleep() {
        return "晚安晚安";
    }

    @Override
    public String wake() {
        return "早鸭";
    }
}
  • 代理

    私たちは、このインタフェースは、メソッドInvokeプロキシ動作を実行するためのInvocationHandlerを実現します

public class InvocationProxy implements InvocationHandler {

    // 被监控的对象(此例中为Person类实例)
    private LifeService lifeService;

    // 监控启动拿到需要被监控的对象
    public InvocationProxy(LifeService lifeService) {
        this.lifeService = lifeService;
    }

    /**
     * 监控的行为发生时,JVM会拦截到行为执行invoke
     *
     * @param proxy  监控对象:监控行为是否发生
     * @param method 被监控的行为方法
     * @param args   被监控行为方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 因为我们拦截了行为,并且加了一些辅助行为,完成之后我们要替被拦截行为把值返回
        Object result = null;
        String methodName = method.getName();
        if ("sleep".equals(methodName)) {
            result = getTime();
            result += (String) method.invoke(this.lifeService, args);
        } else if ("wake".equals(methodName)) {
            result = getTime();
            result += (String) method.invoke(this.lifeService, args);
        }
        return result;
    }

    // 辅助方法
    private String getTime() {
        return Clock.systemDefaultZone().instant().toString() + "\n";
    }

}
  • 工場では、工場は、直接新しいクライアントを行うことができます
public class ProxyFactory {

    public static LifeService getLifeServiceProxyInstance(Class clz) throws IllegalAccessException, InstantiationException {
        // 创建被代理对象
        LifeService target = (LifeService) clz.newInstance();
        // 绑定到代理执行器中
        InvocationHandler handler = new InvocationProxy(target);
        // JVM层面对被代理对象进行监控,行为发生就动态创建代理对象处理
        LifeService $proxy = (LifeService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                handler);
        return $proxy;
    }
}
  • クライアント
public class Test {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, InterruptedException {
        LifeService zhang = ProxyFactory.getLifeServiceProxyInstance(Person.class);
        System.out.println(zhang.sleep());
        System.out.println(zhang.wake());
    }

    /**
     * 输出:
     * 2019-11-10T05:24:16.932Z
     * 晚安晚安
     * 2019-11-10T05:24:16.942Z
     * 早鸭
     */
}

私たちは、動的プロキシエージェントは、この動作のすべてが実行するメソッドを呼び出すために集中し、コードテンプレートをたくさん書いていない、と私たちは実際のInvocationHandlerに複数のインタフェースを表すことができます達成するために必要な使用します

不十分

  • プロキシのInvocationHandler二つのインターフェース場合、2つのインターフェイスが、完全に同一の2つのメソッドがあり区別することができません
  • エージェントがインターフェイスに基づいている必要があり、インタフェースを実装していないクラスがプロキシすることができません

三者ライブラリCGLIB

CGLIBは、私たちが必要としているプロキシ対象を生成するために、ASMバイトコード操作フレームワークのヘルプをベースにしており、インタフェースを実装する必要はありません

依存参加

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
  • RealSubject

    私たちは、特定のインターフェイスを実装する必要はありません

public class Person {

    public String sleep() {
        return "晚安晚安";
    }

    public String wake() {
        return "早鸭";
    }
}
  • 代理

    当社のロジックとJDKのダイナミックプロキシが付属していますが同じです

public class CglibProxy implements MethodInterceptor {
    //需要代理的目标对象
    private Object target;

    public CglibProxy(Object target) {
        this.target = target;
    }

    /**
     *
     * @param o 监控对象:监控行为是否发生
     * @param method 被监控的行为方法
     * @param objects 被监控行为方法的参数
     * @param methodProxy 代理中生成的方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Object result = null;

        String methodName = method.getName();
        if ("sleep".equals(methodName)) {
            result = getTime();
            result += (String) method.invoke(this.target, objects);
        } else if ("wake".equals(methodName)) {
            result = getTime();
            result += (String) method.invoke(this.target, objects);
        }
        return result;
    }

    // 辅助行为
    private String getTime() {
        return Clock.systemDefaultZone().instant().toString() + "\n";
    }
}
  • 工場では、工場は、直接新しいクライアントを行うことができます
public class ProxyFactory {

    public static Object getCglibProxyInstance(Class clz) throws IllegalAccessException, InstantiationException {
        // Enhancer类是CGLib中的一个字节码增强器
        Enhancer enhancer=new Enhancer();
        // 设置被代理类的字节码文件,这里我们关注的不再是接口
        enhancer.setSuperclass(clz);
        // 创建被代理对象
        Object target = clz.newInstance();
        // 绑定到代理执行器中
        CglibProxy proxy = new CglibProxy(target);
        // 设置回调这个代理对象
        enhancer.setCallback(proxy);
        // 生成返回代理对象
        return enhancer.create();
    }
}
  • クライアント
public class Test {

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
        Person zhang = (Person) ProxyFactory.getCglibProxyInstance(Person.class);
        System.out.println(zhang.sleep());
        System.out.println(zhang.wake());
    }

    /**
     * 输出:
     * 2019-11-10T06:01:13.105Z
     * 晚安晚安
     * 2019-11-10T06:01:13.115Z
     * 早鸭
     */
}

インターフェイスを実装する必要がまた、本当に、あなたの動的プロキシになることはできません素晴らしいです

不十分

  • 依存三者ライブラリー
  • 最終クラスやメソッドのプロキシではないすべてのメソッドCGLIBプロキシクラスのニーズを生成されたプロキシクラスが書き換えすることができるので、

おすすめ

転載: www.cnblogs.com/xyy2019/p/11830852.html