jdkダイナミックエージェントとCGLIBダイナミックエージェントの実現と区別
30904 ワード
前回は静的エージェント設計モードのエージェントモード【1】静的エージェント今日javaの動的エージェントについて述べた.
一、なぜ動的エージェントを使用するのか
実際、動的エージェントは静的エージェントを補うショートボードであり、静的エージェントは各被エージェントオブジェクトにエージェントクラスを書く必要がある.これは大量の冗長コードを書く必要があるが、動的エージェントは、1つのエージェントクラスを書くだけで、複数の異なるオブジェクトをエージェントすることができ、同じインタフェースを実現することを前提として、重複コードを大幅に減らすことができる.エージェントの主な目的は、ターゲットオブジェクトへのアクセスを制御することであり、ターゲットオブジェクトの機能を強化することではありません.アクセス制御には、同期、認証、リモートアクセス(RPC)、怠惰インスタンス化(Hibernate、Mybatis)、AOP(トランザクション)が含まれます.
二、動的代理実現方式
2.1 jdkダイナミックエージェント
まず、お見合いデートに行くシーンを設定します.デート相手は小花ですが、私は直接小花に連絡することができません.私は仲人の紹介を通じて小花とデートする必要があります.この时、小花は代理対象で、仲人は代理対象で、私はプログラムの発起人です.
デートインタフェース:2つの機能、映画を見ることと昼食を食べること
小花:デートインタフェースの実装
エージェントオブジェクト(メディア)コア:InvocationHandlerインタフェースを実装し、invokメソッドを再書き込みし、反射によってオブジェクトメソッドを呼び出し、コンテキストを再拡張することができます.
テストプライマリクラス:被エージェントをエージェントオブジェクトに初期化し、インタフェースオブジェクトに直接戻り、メソッドを呼び出す必要があります.
実行結果:
エージェントが実装され、強化が完了しました.
もし私と小花双方が満足していなければ、仲人さんはまた私に新しい女の子を紹介してくれました.静さん.この时、私たちは再び静のために代理クラスを書く必要はありません.静がデートインタフェースを実現するだけでいいです.
同じエージェントオブジェクトは、異なるオブジェクトを複数回エージェントできます.
結果:
はい、後ろに何人の女の子がいても、美ちゃん、芳ちゃん、仲人が一人で十分です.
2.2 CGLIBエージェント
JDKで動的エージェントを行うクラスは,1つのインタフェースを実現しなければならない,すなわち,そのクラスが実現するインタフェースで定義された方法のみをエージェントすることができ,これは実際のプログラミングにおいて一定の限界があり,反射を用いる効率もそれほど高くない.
CGLibを使用して動的エージェントを実装することは、エージェントクラスがインタフェースを実装しなければならないという制限を全く受けず、CGLibの下位層はASMバイトコード生成フレームワークを採用し、バイトコード技術を使用してエージェントクラスを生成し、Java反射を使用するよりも効率的である.唯一注意すべきことは、CGLibは、CGLib原理が被エージェントクラスのサブクラスを動的に生成するため、finalとして宣言されたメソッドをエージェントすることができないことである.
対象小美:ここにはインタフェースがありますか.
エージェントクラス:MethodInterceptorインタフェースを実装し、Enhancerによって新しいクラスを作成し、ターゲットクラスを継承し、interceptメソッドによって親クラスのメソッドを書き換え、動的エージェントの効果も実現します.
結果:
エージェントを実装することもできます.
注意:CGLIBエージェントはメソッドレベルでエージェントを行い、エージェントオブジェクトの属性を取得できません.例:
私たちは美ちゃんの中のmovieメソッドにname属性を追加して取得し、美ちゃんを初期化します.1回呼び出す:
名前の値がnullであることが判明したのは,CGLIB動的エージェントであり,ターゲットオブジェクトの属性をエージェントできないことを示している.
一、なぜ動的エージェントを使用するのか
実際、動的エージェントは静的エージェントを補うショートボードであり、静的エージェントは各被エージェントオブジェクトにエージェントクラスを書く必要がある.これは大量の冗長コードを書く必要があるが、動的エージェントは、1つのエージェントクラスを書くだけで、複数の異なるオブジェクトをエージェントすることができ、同じインタフェースを実現することを前提として、重複コードを大幅に減らすことができる.エージェントの主な目的は、ターゲットオブジェクトへのアクセスを制御することであり、ターゲットオブジェクトの機能を強化することではありません.アクセス制御には、同期、認証、リモートアクセス(RPC)、怠惰インスタンス化(Hibernate、Mybatis)、AOP(トランザクション)が含まれます.
二、動的代理実現方式
2.1 jdkダイナミックエージェント
まず、お見合いデートに行くシーンを設定します.デート相手は小花ですが、私は直接小花に連絡することができません.私は仲人の紹介を通じて小花とデートする必要があります.この时、小花は代理対象で、仲人は代理対象で、私はプログラムの発起人です.
デートインタフェース:2つの機能、映画を見ることと昼食を食べること
package com.example.demo1.Dynamic;
//
public interface YueHui {
//
void movie();
//
void lunch();
}
小花:デートインタフェースの実装
/**
*
*
* create by c-pown on 2020-06-29
*/
public class XiaoHua implements YueHui {
@Override
public void movie() {
System.out.println(" ");
}
@Override
public void lunch() {
System.out.println(" ");
}
}
エージェントオブジェクト(メディア)コア:InvocationHandlerインタフェースを実装し、invokメソッドを再書き込みし、反射によってオブジェクトメソッドを呼び出し、コンテキストを再拡張することができます.
getObj()
メソッドは、インタフェース実装オブジェクトを返すことができる./**
*
* InvocationHandler
* create by c-pown on 2020-06-29
*/
public class ProxyPerson implements InvocationHandler {
// ( )
private Object object;
//
public ProxyPerson(Object object) {
this.object = object;
}
// :
// proxy: ( method()
// method:
// args:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// : ,
System.out.println(" ");
method.invoke(object,args);
System.out.println(" ");
return null;
}
//
// this::invok this, invok
public Object getObj(){
return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this::invok);
}
}
テストプライマリクラス:被エージェントをエージェントオブジェクトに初期化し、インタフェースオブジェクトに直接戻り、メソッドを呼び出す必要があります.
/**
*
* create by c-pown on 2020-06-29
*/
public class TestDynamicProx {
public static void main(String[] args) {
//
XiaoHua xiaoHua = new XiaoHua();
// ,
ProxyPerson proxyPerson = new ProxyPerson(xiaoHua);
//
YueHui yueHui = (YueHui)proxyPerson.getObj();
yueHui.lunch();
yueHui.movie();
}
}
実行結果:
エージェントが実装され、強化が完了しました.
もし私と小花双方が満足していなければ、仲人さんはまた私に新しい女の子を紹介してくれました.静さん.この时、私たちは再び静のために代理クラスを書く必要はありません.静がデートインタフェースを実現するだけでいいです.
/**
*
*
* create by c-pown on 2020-06-29
*/
public class XiaoJing implements YueHui {
@Override
public void movie() {
System.out.println(" ");
}
@Override
public void lunch() {
System.out.println(" ");
}
}
同じエージェントオブジェクトは、異なるオブジェクトを複数回エージェントできます.
package com.example.demo1.Dynamic;
/**
*
* create by c-pown on 2020-06-29
*/
public class TestDynamicProx {
public static void main(String[] args) {
//
XiaoHua xiaoHua = new XiaoHua();
// ,
ProxyPerson proxyPerson = new ProxyPerson(xiaoHua);
//
YueHui yueHui = (YueHui)proxyPerson.getObj();
yueHui.lunch();
yueHui.movie();
System.out.println("------------- -------------");
//
XiaoJing xiaoJing = new XiaoJing();
// ,
ProxyPerson proxyPerson1 = new ProxyPerson(xiaoJing);
//
YueHui yueHui1 = (YueHui)proxyPerson1.getObj();
yueHui1.lunch();
yueHui1.movie();
}
}
結果:
------------- -------------
はい、後ろに何人の女の子がいても、美ちゃん、芳ちゃん、仲人が一人で十分です.
2.2 CGLIBエージェント
JDKで動的エージェントを行うクラスは,1つのインタフェースを実現しなければならない,すなわち,そのクラスが実現するインタフェースで定義された方法のみをエージェントすることができ,これは実際のプログラミングにおいて一定の限界があり,反射を用いる効率もそれほど高くない.
CGLibを使用して動的エージェントを実装することは、エージェントクラスがインタフェースを実装しなければならないという制限を全く受けず、CGLibの下位層はASMバイトコード生成フレームワークを採用し、バイトコード技術を使用してエージェントクラスを生成し、Java反射を使用するよりも効率的である.唯一注意すべきことは、CGLibは、CGLib原理が被エージェントクラスのサブクラスを動的に生成するため、finalとして宣言されたメソッドをエージェントすることができないことである.
対象小美:ここにはインタフェースがありますか.
/**
*
* create by c-pown on 2020-06-29
*/
public class XiaoMei {
public String name;
public XiaoMei() {
}
public XiaoMei(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void movie(){
System.out.println(" ");
}
}
エージェントクラス:MethodInterceptorインタフェースを実装し、Enhancerによって新しいクラスを作成し、ターゲットクラスを継承し、interceptメソッドによって親クラスのメソッドを書き換え、動的エージェントの効果も実現します.
package com.example.demo1.Dynamic;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* cglib
* create by c-pown on 2020-06-29
*/
public class CglibInterceptor implements MethodInterceptor {
//
private Object object;
public CglibInterceptor(Object object) {
this.object = object;
}
public Object getObj(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.object.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(" ");
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println(" ");
return o1;
}
}
XiaoMei xiaoMei = new XiaoMei(" ");
System.out.println(xiaoMei.getName());
CglibInterceptor cglibInterceptor = new CglibInterceptor(xiaoMei);
XiaoMei obj = (XiaoMei)cglibInterceptor.getObj();
obj.movie();
結果:
エージェントを実装することもできます.
注意:CGLIBエージェントはメソッドレベルでエージェントを行い、エージェントオブジェクトの属性を取得できません.例:
/**
*
* create by c-pown on 2020-06-29
*/
public class XiaoMei {
public String name;
public XiaoMei() {
}
public XiaoMei(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void movie(){
System.out.println(" "+name+" ");
}
}
私たちは美ちゃんの中のmovieメソッドにname属性を追加して取得し、美ちゃんを初期化します.1回呼び出す:
null
名前の値がnullであることが判明したのは,CGLIB動的エージェントであり,ターゲットオブジェクトの属性をエージェントできないことを示している.