動的プロキシ
動的プロキシは、プログラム操作中にプロキシオブジェクトを動的に構築し、プロキシメソッドを動的に呼び出すためのメカニズムです。
ビジネスでの動的エージェントの使用は、通常、実装する必要のあるメソッドに前処理または後続の操作を追加することですが、実装クラスの通常のビジネスに干渉することはなく、一部の基本的なビジネスをメインのビジネスロジックから分離します。私たちが一般的に知っているSpringAOPの原則は、動的プロキシの実装に基づいています。
動的プロキシの一般的な実装はリフレクションです。リフレクションメカニズムとは、操作中に自身の状態または動作にアクセス、検出、および変更するプログラムの機能を指します。リフレクションを使用すると、クラスオブジェクト、およびクラスオブジェクトに含まれるプロパティとメソッドを呼び出すことができます。
ただし、動的プロキシは単なるリフレクションではありません。たとえば、動的プロキシはCGLibで実装でき、CGLibはリフレクションではなくASM(Javaバイトコード操作フレームワーク)に基づいています。簡単に言えば、動的プロキシは動作の方法であり、リフレクションまたはASMはその実現の手段にすぎません。
JDKプロキシとCGLibの違い
JDKプロキシ
-
JDKプロキシはJava言語の組み込み関数であり、サードパーティのクラスをロードして実装する必要はありません。
-
JavaはJDKプロキシの安定したサポートを提供し、JDKプロキシのアップグレードと更新を継続します。たとえば、Java8バージョンのJDKプロキシのパフォーマンスは以前のバージョンと比較して大幅に改善されています。
-
JDKプロキシは、インターセプターとリフレクションによって実装されます。
-
JDKプロキシは、インターフェースを継承するクラスのみをプロキシできます。
-
JDKプロキシは、実装と呼び出しが比較的簡単です。
-
CGLibは、サードパーティが提供するツールであり、ASMに基づいて実装されており、比較的高いパフォーマンスを発揮します。
-
CGLibは、インターフェイスを介して実装する必要はありません。サブクラスを実装することによって呼び出されます。
JDKプロキシコードのウォークスルー
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxyLearn {
static interface Car{
void running();
}
static class Bus implements Car{
@Override
public void running() {
System.out.println("The Bus is running");
}
}
static class Taxi implements Car{
@Override
public void running() {
System.out.println("The Taxi is running");
}
}
//使用JDK Proxy
static class JDKProxy implements InvocationHandler{
private Object target;
public Object getInstance(Object target){
this.target=target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
//target.getClass().getClassLoader() 代理类的类加载器
//target.getClass().getInterfaces()被代理类的接口,如果有多个就是数组形式传入。
// 代理类实例
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理之前的业务处理");
Object result=method.invoke(target,args);//利用反射调用类里面的实际方法
return result;//方法的返回值,没有就是null
}
}
public static void main(String[] args) {
JDKProxy jdkProxy=new JDKProxy();
Car carInstance =(Car) jdkProxy.getInstance(new Taxi());
carInstance.running();
}
}
JDKプロキシの動的プロキシの実装の中核は、呼び出しインターフェイスを1つだけ持つ呼び出しインターフェイスを実装することです。
InvocationHanderはプロキシであり、invoke()メソッドはトリガーされた実行メソッドであり、Innovationインターフェイスを実装することで動的プロキシの機能を備えています。
CGLibコードのウォークスルー
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLibLearn {
static class Car{
public void running()
{
System.out.println("The car is running");
}
}
/*CGLib 代理类*/
static class CGLibProxy implements MethodInterceptor{
private Object target;
public Object getInstance(Object target)
{
this.target=target;
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CGlib---方法调用前调用方法");
Object result = methodProxy.invokeSuper(o, objects);
return result;
}
}
public static void main(String[] args) {
CGLibProxy proxy=new CGLibProxy();
Car car = (Car) proxy.getInstance(new Car());
car.running();
}
}
CGLibはプロキシクラスを初期化するときに、エンハンサーオブジェクトを介してプロキシクラスのサブクラスとしてプロキシオブジェクトを設定することにより、動的プロキシを実装します。したがって、プロキシクラスをキーワードfinalで変更することはできません。finalで変更すると、エンハンサーを使用して親クラスを設定するときにエラーが報告され、動的プロキシの構築に失敗します。
動的エージェントナレッジポイントの拡張
動的プロキシと静的プロキシの違いは何ですか?静的プロキシは実際には事前に作成されたプロキシクラスであり、ツールで手動で作成または生成できますが、各ビジネスクラスがプロキシクラスに対応する必要があるという欠点があります。これは特に柔軟性がなく不便であるため、動的なプロキシがあります。プロキシ。
動的プロキシの一般的な使用シナリオには、RPCフレームワークのカプセル化、AOP(アスペクト指向プログラミング)の実装、JDBC接続などがあります。
Springフレームワークでは2つの動的プロキシJDKProxyとCGLibが同時に使用されます。Beanがインターフェースを実装する場合、SpringはJDKプロキシを使用します。インターフェースが実装されていない場合、CGLibを使用します。必須を指定することもできます。構成でのCGLibの使用。Spring構成に<aop:aspectj-autoproxy proxy-target-class =“ true” />を追加するだけです。
ロンボク
Lombokの実装は、リフレクションとは何の関係もありません。Lombokの実装はコンパイラで完了します
実際、Lombokは、Java1.6によって実装されたJSR269:Pluggable Annotation Processing APIに基づいて実装されています。これは、コンパイル時にアノテーションプロセッサをカスタマイズすることによって実装されます。その実行手順は次のとおりです。
フローチャートから、コンパイル段階でJavaソースコードが構文ツリー(AST)に抽象化されると、Lombokは独自のアノテーションプロセッサに従ってASTを動的に変更し、新しいコード(ノード)を追加し、その後、Lombokの実行原理である最終的なバイトコード(.class)ファイルが生成されます。