プロキシモード(プロキシ)
プロキシモードの基本的な紹介
-
プロキシモード:オブジェクトにプロキシモードを提供します代替このオブジェクトへのアクセスを制御します。ターゲットオブジェクトには、プロキシオブジェクトを介してアクセスしますこれの利点は次のとおりです。ターゲットオブジェクトの実現に基づいて、追加の機能操作を拡張できます。つまり、ターゲットオブジェクトの機能を拡張できます。。
-
プロキシされるオブジェクトはリモートオブジェクト、高価なオブジェクトまたはセキュリティ制御が必要なオブジェクトを作成する
-
エージェンシーモードにはさまざまな形式があり、主に3つのタイプがあります静的プロキシ、動的プロキシ(JDKプロキシ、インターフェイスプロキシ)、およびCglibプロキシ(インターフェイスを実装せずにメモリ内にオブジェクトを動的に作成できます。これは動的エージェントのカテゴリに属します)。
-
プロキシモードの概略図
静的プロキシ
静的コードモードの基本的な紹介
静的プロキシを使用する場合は、インターフェイスまたは親クラスを定義する必要があります。プロキシオブジェクト(つまり、ターゲットオブジェクト)とプロキシオブジェクトは、同じインターフェイスを実装するか、同じ親クラスを継承します。
アプリケーション
- 特定の要件
-
インターフェイスを定義します:ITeacherDao
-
ターゲットオブジェクトTeacherDAOは、インターフェイスITeacherDAOを実装します
-
静的プロキシモードを使用して、プロキシオブジェクトTeacherDAOProxyにITeacherDAOを実装する必要があります
-
呼び出すとき、ターゲットオブジェクトはプロキシオブジェクトのメソッドを呼び出すことによって呼び出されます。
-
特別なリマインダー:プロキシオブジェクトとターゲットオブジェクトを実現する必要があります同じインターフェースそして、同じ方法ターゲットオブジェクトのメソッドを呼び出すには
-
アイデア分析図(クラス図)
TeacherDao(ターゲットクラス)は、インターフェイスを介してプロキシクラス(TeacherDaoProxy)に集約されます -
コード
クライアント.java:クライアント
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建目标对象(被代理对象)
TeacherDao teacherDao = new TeacherDao();
//创建代理对象, 同时将被代理对象传递给代理对象
TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
//通过代理对象,调用到被代理对象的方法
//即:执行的是代理对象的方法,代理对象再去调用目标对象的方法
teacherDaoProxy.teach();
}
}
ITeacherDao.java:プロキシインターフェース
//接口
public interface ITeacherDao {
void teach(); // 授课的方法
}
TeacherDao.java:ターゲットクラス
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
// TODO Auto-generated method stub
System.out.println(" 老师授课中 。。。。。");
}
}
TeacherDaoProxy.java:プロキシクラス
//代理对象,静态代理
public class TeacherDaoProxy implements ITeacherDao{
private ITeacherDao target; // 目标对象,通过接口来聚合
//构造器
public TeacherDaoProxy(ITeacherDao target) {
this.target = target;
}
@Override
public void teach() {
// TODO Auto-generated method stub
System.out.println("开始代理 完成某些操作。。。。。 ");//方法
target.teach();
System.out.println("提交。。。。。");//方法
}
}
静的プロキシの長所と短所
-
利点:ターゲットオブジェクトの機能を変更せずに、プロキシオブジェクトを介してターゲット機能を拡張できます。
-
短所:プロキシオブジェクトはターゲットオブジェクトと同じインターフェイスを実装する必要があるため、多くのプロキシクラスが存在します
-
インターフェイスがメソッドを追加したら、ターゲットオブジェクトとプロキシオブジェクトを維持する必要があります
動的プロキシ
ダイナミックプロキシモードの基本的な紹介
-
プロキシオブジェクトはインターフェイスを実装する必要はありませんが、ターゲットオブジェクトはインターフェイスを実装する必要があります、それ以外の場合は動的プロキシを使用できません
-
プロキシオブジェクトの生成、JDKAPIを使用します、メモリ内にプロキシオブジェクトを動的に構築する
-
動的プロキシは、JDKプロキシ、インターフェイスプロキシとも呼ばれます。
JDKでプロキシオブジェクトを生成するためのAPI
-
プロキシクラスのパッケージ:java.lang.reflect.Proxy
-
プロキシのJDK実装では、newProxyInstanceメソッドのみを使用する必要がありますが、メソッドは3つのパラメーターを受け取る必要があります。完全な記述は次のとおりです。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
動的プロキシアプリケーションの例
- アプリケーション例の要件
以前の静的プロキシを動的プロキシモード(つまり、JDKプロキシモード)に改善します。
- アイデア図(クラス図)
- コード
クライアント
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建目标对象
ITeacherDao target = new TeacherDao();
//给目标对象,创建代理对象, 可以转成 ITeacherDao
ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
// proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
System.out.println("proxyInstance=" + proxyInstance.getClass());
//通过代理对象,调用目标对象的方法
//proxyInstance.teach();
proxyInstance.sayHello(" tom ");
}
}
インターフェース:
//接口
public interface ITeacherDao {
void teach(); // 授课方法
void sayHello(String name);
}
ターゲットクラス
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
// TODO Auto-generated method stub
System.out.println(" 老师授课中.... ");
}
@Override
public void sayHello(String name) {
// TODO Auto-generated method stub
System.out.println("hello " + name);
}
}
プロキシクラス
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory {
//维护一个目标对象 , Object
private Object target;
//构造器 , 对target 进行初始化
public ProxyFactory(Object target) {
this.target = target;
}
//给目标对象 生成一个代理对象
public Object getProxyInstance() {
//说明
/*
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
//1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
//2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
//3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("JDK代理开始~~");
//反射机制调用目标对象的方法
Object returnVal = method.invoke(target, args);
System.out.println("JDK代理提交");
return returnVal;
}
});
}
}
Cglibプロキシ
Cglibプロキシモードの基本的な紹介
-
静的プロキシモードとJDKプロキシモードはどちらも、ターゲットオブジェクトがインターフェイスを実装する必要がありますが、場合によってはターゲットオブジェクトは単一のオブジェクトです、およびインターフェイスを実装していません。現時点では、ターゲットオブジェクトサブクラスを使用してプロキシを実装できます。これはCglibプロキシです。
-
Cglibエージェントは、サブクラスエージェントとも呼ばれ、メモリ内にサブクラスオブジェクトを構築して、ターゲットオブジェクトの機能を拡張します。 一部の本はまた、Cglibエージェントを動的エージェントに帰する。
-
Cglibは、実行時にJavaクラスを拡張してJavaインターフェイスを実装できる強力な高性能コード生成パッケージです。SpringAOPなどの多くのAOPフレームワークで、メソッドインターセプトを実装するために広く使用されています。
-
AOPプログラミングでプロキシモードを選択する方法:
4.1。ターゲットオブジェクトはインターフェイスを実装する必要があります。JDKを
使用してプロキシします。4.2。ターゲットオブジェクトはインターフェイスを実装する必要はありません。Cglibを使用してプロキシします。 -
Cglibパッケージの最下層は、バイトコード処理フレームワークASMを使用して、バイトコードを変換し、新しいクラスを生成することです。
Cglibプロキシモードの実装手順
-
cglibのjarファイルを導入する必要があります
-
メモリ内にサブクラスを動的に構築します。プロキシクラスをfinalにすることはできません。そうしないと、エラー
java.lang.IllegalArgumentException: -
ターゲットオブジェクトのメソッドがfinal / staticの場合、インターセプトされません。つまり、ターゲットオブジェクトの追加のビジネスメソッドは実行されません。
Cglibプロキシモードのアプリケーション例
アプリケーション例の要件
Cglibプロキシモードで前のケースを実現します
アイデア図(クラス図)
コードの実現+デバッグソースコード[デバッグ予定]
クライアント:
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建目标对象
TeacherDao target = new TeacherDao();
//获取到代理对象,并且将目标对象传递给代理对象
TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(target).getProxyInstance();
//执行代理对象的方法,触发intecept 方法,从而实现 对目标对象的调用
String res = proxyInstance.teach();
System.out.println("res=" + res);
}
}
プロキシクラス
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class ProxyFactory implements MethodInterceptor {
//维护一个目标对象
private Object target;
//构造器,传入一个被代理的对象
public ProxyFactory(Object target) {
this.target = target;
}
//返回一个代理对象: 是 target 对象的代理对象
public Object getProxyInstance() {
//1. 创建一个工具类
Enhancer enhancer = new Enhancer();
//2. 设置父类
enhancer.setSuperclass(target.getClass());
//3. 设置回调函数
enhancer.setCallback(this);
//4. 创建子类对象,即代理对象
return enhancer.create();
}
//重写 intercept 方法,会调用目标对象的方法
@Override
public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println("Cglib代理模式 ~~ 开始");
Object returnVal = method.invoke(target, args);
System.out.println("Cglib代理模式 ~~ 提交");
return returnVal;
}
}
ターゲットクラス
public class TeacherDao {
public String teach() {
System.out.println(" 老师授课中 , 我是cglib代理,不需要实现接口 ");
return "hello";
}
}
いくつかの一般的なプロキシモードの概要-いくつかのバリエーション
-
ファイアウォールプロキシ
内部ネットワークは、プロキシを介してファイアウォールに侵入し、パブリックネットワークへのアクセスを実現します。 -
キャッシングプロキシ
例:画像ファイルなどのリソースをリクエストする場合、最初にキャッシングプロキシに移動して、リソースがフェッチされている場合はフェッチし、リソースがフェッチされていない場合はOK、次にパブリックネットワークまたはデータベースからフェッチします。次にキャッシュします。 -
リモートエージェント
リモートオブジェクトのローカル代表、リモートオブジェクトをローカルオブジェクトとして呼び出すことができます。リモートエージェントは、ネットワークを介して実際のリモートオブジェクトと情報を通信します。 -
同期エージェント:主にマルチスレッドプログラミングで使用され、複数のスレッド間の同期作業を完了します
同期エージェント:主にマルチスレッドプログラミングで使用され、複数のスレッド間の同期作業を完了します