Javaにおける静的プロキシと動的プロキシの4つの実装方法の紹介
この記事では、Java での静的エージェントと動的エージェントの 4 つの実装方法を紹介します。必要な方は参考にしていただければ幸いです。
インタビューの質問: Java のプロキシ デザイン パターンには実装メソッドがいくつありますか?この質問は、Kong Yiji の質問「フェンネル豆をフェンネルと書くにはどうすればよいですか?」とよく似ています。
いわゆるプロキシ モードとは、クライアントが実際のオブジェクト ( 1 つは下の図の右下隅にあります) RealSubject) ですが、プロキシ (Proxy) を呼び出すことで実際のオブジェクトを間接的に呼び出します。
プロキシ モードが使用されるのは、クライアントが実際のオブジェクトに直接アクセスしたくない場合、または実際のオブジェクトにアクセスするのに技術的な障害があるため、プロキシ オブジェクトが間接アクセスを完了するためのブリッジとして使用される場合です。
#実装方法 1: 静的プロキシ
メソッド writeCode を含むインターフェイス IDeveloper を開発します。コードを書きます。public interface IDeveloper { public void writeCode(); }
public class Developer implements IDeveloper{ private String name; public Developer(String name){ this.name = name; } @Override public void writeCode() { System.out.println("Developer " + name + " writes code"); } }
public class DeveloperTest { public static void main(String[] args) { IDeveloper jerry = new Developer("Jerry"); jerry.writeCode(); } }
public class DeveloperProxy implements IDeveloper{ private IDeveloper developer; public DeveloperProxy(IDeveloper developer){ this.developer = developer; } @Override public void writeCode() { System.out.println("Write documentation..."); this.developer.writeCode(); } }
静的プロキシ方式の利点
1. 簡単です。理解と実装2. プロキシ クラスと実際のクラスの関係は、コンパイル中に静的に決定されます。すぐ下で紹介する動的プロキシと比較して、実行中に追加のオーバーヘッドはありません。静的プロキシ メソッドの欠点
すべての実際のクラスでは、新しいプロキシ クラスを作成する必要があります。上記のドキュメントの更新を例として、上司がテスト エンジニアに対して新しい要件も提示し、バグを検出するたびに対応するテスト ドキュメントをタイムリーに更新するようテスト エンジニアに要求したとします。次に、静的プロキシ メソッドを使用して、テスト エンジニアの実装クラス ITester も、対応する ITesterProxy クラスを作成する必要があります。public interface ITester { public void doTesting(); } Original tester implementation class: public class Tester implements ITester { private String name; public Tester(String name){ this.name = name; } @Override public void doTesting() { System.out.println("Tester " + name + " is testing code"); } } public class TesterProxy implements ITester{ private ITester tester; public TesterProxy(ITester tester){ this.tester = tester; } @Override public void doTesting() { System.out.println("Tester is preparing test documentation..."); tester.doTesting(); } }
Java ダイナミック プロキシの実装方法 1: InvocationHandler
InvocationHandler の原理を紹介する記事を書きました: Java ダイナミック プロキシ InvocationHandler の最も簡単な入門チュートリアルInvocationHandler を通じて、EnginnerProxy プロキシ クラスを使用して、開発者とテスターの動作を同時にプロキシできます。
public class EnginnerProxy implements InvocationHandler { Object obj; public Object bind(Object obj) { this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Enginner writes document"); Object res = method.invoke(obj, args); return res; } }
InvocationHandler による動的プロキシ実装の制限
プロダクト マネージャー クラスがあると仮定します。 (ProductOwner) はインターフェイスを実装していません。
public class ProductOwner { private String name; public ProductOwner(String name){ this.name = name; } public void defineBackLog(){ System.out.println("PO: " + name + " defines Backlog."); } }
プロキシには引き続き EnginnerProxy プロキシ クラスを使用します。コンパイル中にエラーは発生しません。実行時に何が起こるのでしょうか?
ProductOwner po = new ProductOwner("Ross"); ProductOwner poProxy = (ProductOwner) new EnginnerProxy().bind(po); poProxy.defineBackLog();
実行時にエラーが発生します。したがって、制限は次のとおりです。プロキシされたクラスがインターフェイスを実装していない場合、InvocationHandler 動的プロキシを介してその動作をプロキシすることはできません。
CGLIB は Java バイトコード生成ライブラリであり、以下を提供します。 Java バイトコードを作成および変更するための使いやすい API。このオープン ソース ライブラリの詳細については、github の CGLIB のリポジトリを参照してください: https://github.com/cglib/cglib
現在、InvocationHandler を使用する前に CGLIB を使用してプロキシを試みていますが、成功しません。クラス (このクラスはインターフェイスを実装しません)。
ここでは、代わりに CGLIB API を使用してプロキシ クラスを作成します:
public class EnginnerCGLibProxy { Object obj; public Object bind(final Object target) { this.obj = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(obj.getClass()); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Enginner 2 writes document"); Object res = method.invoke(target, args); return res; } } ); return enhancer.create(); } }
テスト コード:
ProductOwner ross = new ProductOwner("Ross"); ProductOwner rossProxy = (ProductOwner) new EnginnerCGLibProxy().bind(ross); rossProxy.defineBackLog();
尽管ProductOwner未实现任何代码,但它也成功被代理了:
用CGLIB实现Java动态代理的局限性
如果我们了解了CGLIB创建代理类的原理,那么其局限性也就一目了然。我们现在做个实验,将ProductOwner类加上final修饰符,使其不可被继承:
再次执行测试代码,这次就报错了: Cannot subclass final class XXXX。
所以通过CGLIB成功创建的动态代理,实际是被代理类的一个子类。那么如果被代理类被标记成final,也就无法通过CGLIB去创建动态代理。
Java动态代理实现方式三:通过编译期提供的API动态创建代理类
假设我们确实需要给一个既是final,又未实现任何接口的ProductOwner类创建动态代码。除了InvocationHandler和CGLIB外,我们还有最后一招:
我直接把一个代理类的源代码用字符串拼出来,然后基于这个字符串调用JDK的Compiler(编译期)API,动态的创建一个新的.java文件,然后动态编译这个.java文件,这样也能得到一个新的代理类。
测试成功:
我拼好了代码类的源代码,动态创建了代理类的.java文件,能够在Eclipse里打开这个用代码创建的.java文件,
下图是如何动态创建ProductPwnerSCProxy.java文件:
下图是如何用JavaCompiler API动态编译前一步动态创建出的.java文件,生成.class文件:
下图是如何用类加载器加载编译好的.class文件到内存:
如果您想试试这篇文章介绍的这四种代理模式(Proxy Design Pattern), 请参考我的github仓库,全部代码都在上面。感谢阅读。
https://github.com/i042416/Ja...
以上がJavaにおける静的プロキシと動的プロキシの4つの実装方法の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

Java は、初心者と経験豊富な開発者の両方が学習できる人気のあるプログラミング言語です。このチュートリアルは基本的な概念から始まり、高度なトピックに進みます。 Java Development Kit をインストールしたら、簡単な「Hello, World!」プログラムを作成してプログラミングを練習できます。コードを理解したら、コマンド プロンプトを使用してプログラムをコンパイルして実行すると、コンソールに「Hello, World!」と出力されます。 Java の学習はプログラミングの旅の始まりであり、習熟が深まるにつれて、より複雑なアプリケーションを作成できるようになります。
