Javaの3つのプロキシモード、プロキシ待機、動的プロキシ、Cglibプロキシ
エージェンシーモデル
プロキシは、ターゲットオブジェクトに間接的にアクセスする方法、つまりプロキシオブジェクトを介してターゲットオブジェクトにアクセスする方法を提供するデザインパターンです。これの利点は、ターゲットオブジェクトによって実装される機能に機能の補足を追加できることです。ターゲットオブジェクトの機能を拡張することです。
これは、既存のコードを変更せずに関数を拡張するというデザインパターンの開閉原理に準拠しています。
代理店の役割を説明する例を挙げてください。有名人とエージェントの関係は、エージェントとエージェントの関係です。有名人がイベントでプレイするときは、有名人がターゲットになります。彼は、イベントのプログラム、および他の些細な事柄が渡されます。彼のエージェント(ブローカー)に
解決するためにこれは実際のエージェンシー思考の例です。
静的プロキシ
静的プロキシを使用する場合、プロキシオブジェクトとプロキシオブジェクトは同じインターフェイスを実装するか、同じ親クラスを継承する必要があるため、インターフェイスまたは抽象クラスを定義する必要があります。
コードケース:
コードをコピーする
// 接口
interface IStar {
void sing();
}
// 真实对象
class LDHStar implements IStar {
@Override
public void sing() {
System.out.println("刘德华唱歌");
}
}
// 代理类需要有真实对象的控制权 (引用)
class ProxyManger implements IStar {
// 真实对象的引用
private IStar star;
public ProxyManger() {
super();
}
public ProxyManger(IStar star) {
super();
this.star = star;
}
@Override
public void sing() {
System.out.println("唱歌前准备");
star.sing();
System.out.println("善后工作"); }
}
class Test{
public static void main(String[] args) {
// 创建明星对象
IStar ldh = new LDHStar();
ProxyManger proxy = new ProxyManger(ldh);
proxy.sing();
}
}
静的プロキシの概要:
- 利点:ターゲットオブジェクトの機能を変更せずに、ターゲット機能を拡張できます。
- 短所:プロキシオブジェクトはターゲットオブジェクトと同じインターフェイスを実装する必要があるため、プロキシクラスが多く、クラスが多すぎます。同時に、インターフェイスがメソッドを追加したら、ターゲットオブジェクトとプロキシオブジェクトを維持する必要があります。
動的プロキシ方式は、上記の問題を解決できます
動的プロキシ
動的プロキシの主な機能は、プログラムの実行時に、JVMがプロキシオブジェクトのプロキシオブジェクトを生成できることです。
よく言われる動的プロキシは、JDKプロキシとも呼ばれ、一種のインターフェイスプロキシでもあります。JDKでプロキシオブジェクトを生成するプロキシクラスはProxyであり、パッケージはjava.lang.reflectです。
//目标类接口
interface IDog{
void run();
}
//目标类
class GunDog implements IDog{
@Override
public void run() {
System.out.println("猎狗在跑");
}
}
class DogUtils{
public static void method1() {
System.out.println("增强方式一");
}
public static void method2() {
System.out.println("增强方式二");
}
}
class MyInvocationHandle implements InvocationHandler{
private Object target;
public void setTarget(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
DogUtils.method1();
method.invoke(target, args);
DogUtils.method2();
return null;
}
}
//生产代理对象的工厂
class MyProxyFactory{
public static Object getProxy(Object target) {
MyInvocationHandle handle = new MyInvocationHandle();
handle.setTarget(target);
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handle);
return proxy;
}
}
public class ProxyDemo {
public static void main(String[] args) {
IDog dog = new GunDog();
IDog proxy =(IDog) MyProxyFactory.getProxy(dog);
proxy.run();
}
}
総括する:
プロキシオブジェクトはインターフェイスを実装する必要はありませんが、ターゲットオブジェクトはインターフェイスを実装する必要があります。そうしないと、動的プロキシを使用できないため、これもこのアプローチの欠点です。
Cglibプロキシ
上記の静的プロキシモードと動的プロキシモードは、どちらもターゲットオブジェクトがインターフェイスを実装するオブジェクトである必要があるという同じ点を持っていますが、インターフェイスを実装するオブジェクトはなく、インターフェイスを実装しないオブジェクトもあります。
このとき、継承されたターゲットクラスを使用して、ターゲットオブジェクトサブクラスの方法でプロキシを実装できます。このメソッドは次のように呼ばれます。Cglibプロキシ、サブクラスプロキシとも呼ばれ、メモリ内にサブクラスオブジェクトを構築して、ターゲットオブジェクト機能を実現します。拡張。
JDK動的プロキシを使用する場合の1つの制限は、プロキシされるオブジェクトが1つ以上のインターフェースを実装する必要があることです。インターフェースを実装しないクラスをプロキシする場合は、Cglibを使用して実装する必要があります。
Cglibはサードパーティによって提供されているため、使用する場合は関連するjarパッケージをインポートする必要があります。図に示すように、2つのパッケージがあります。
コードケース:
public class CglibProxy {
public static void main(String[] args) {
int[] arr = new int[100000];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) (Math.random() * 1000);
}
//实例化一个增强器,也就是cglib中的一个class generator
Enhancer enhancer = new Enhancer();
//设置目标类
enhancer.setSuperclass(ArraySort2.class);
//设置拦截对象,这里直接使用匿名内部类写法
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object object , Method method, Object[] args, MethodProxy proxy) throws Throwable {
String sortName = method.getName();
switch (sortName) {
case "bubbleSort":
sortName = "冒泡排序";
break;
case "selectSort":
sortName = "选择排序";
break;
case "quickSort":
sortName = "快速排序";
break;
default:
break;
}
long start = System.currentTimeMillis();
//此处一定要使用proxy的invokeSuper方法来调用目标类的方法
proxy.invokeSuper(object, args);
long end = System.currentTimeMillis();
System.out.println("本次" + sortName + "的执行时间为: " + (end -start) + "ms");
return null;
}
});
//生成代理类并返回一个实例
ArraySort2 arraySort = (ArraySort2) enhancer.create();
arraySort.bubbleSort(arr);
arraySort.selectSort(arr);
arraySort.quickSort(arr);
}
}
class ArraySort2{
public void quickSort(int[] arr) {
Arrays.sort(arr);
}
public void selectSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = i+1; j < arr.length; j++) {
if (arr[i] > arr[j]) {
int temp = 0;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
public void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = 0;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}
総括する:
SpringのAOPプログラミングでは:
-
コンテナに追加されたターゲットオブジェクトに実装インターフェイスがある場合は、JDKプロキシを使用します
-
ターゲットオブジェクトがインターフェイスを実装していない場合は、Cglibプロキシを使用します。
タグ:静的プロキシ、動的プロキシ、cglib動的プロキシ