1. ホーム
  2. Java

Java JDKのダイナミックプロキシ(AOP)の使用と実装の原理分析

2022-02-20 10:49:42

内容

I. プロキシとは何ですか?

II. Java 動的プロキシ・クラス 

III. JDKの動的プロキシはどのように動作するのですか?

IV. ダイナミックプロキシはどのように実装されているのですか?

V. おわりに


I. 代理人とは?

プロキシとは、あるオブジェクトへのアクセスを制御するために、他のオブジェクトに代理人を提供することを目的とした一般的なデザインパターンである。プロキシ・クラスは、デリゲート・クラスのためにメッセージを前処理し、フィルタリングして転送し、デリゲート・クラスによって実行された後に後続の処理を行う役割を担っています。

プロキシパターンのUML図。

シンプルな構造概略図。

一貫した動作を維持するために、プロキシクラスとデリゲートクラスは通常同じインターフェイスを実装しており、訪問者の目には両者に違いが見えません。プロキシクラスは、デリゲートクラスのオブジェクトへの直接アクセスを効果的に制御する中間層であり、またデリゲートオブジェクトをうまく隠して保護しながら、異なる制御戦略を実装する余地を残し、設計上の柔軟性を獲得します。Javaダイナミックプロキシ機構は、Proxyパターンの設計哲学を巧妙かつほぼ完璧に実装したものです。

II. Java動的プロキシクラス 

Java動的プロキシクラスはjava.lang.reflectパッケージの下にあり、一般に次の2つの主要なクラスが含まれます。

(1) インターフェース InvocationHandler: このインターフェースには、1つのメソッドのみが定義されています。

public object invoke(Object obj,Method method, Object[] args)

実際の使用では 最初の引数 obj は一般にプロキシクラス、method は上の例の request() のようにプロキシされるメソッド、args はそのメソッドの引数の配列です。 この抽象メソッドはプロキシクラスに動的に実装されます。

(2) プロキシ このクラスは、動的プロキシクラス であり、以下の主要な要素を含む。

protected Proxy( InvocationHandler h) : コンストラクタで、内部の h アサインメント

静的クラス getProxyClass ( クラスローダー loader, Class[] interfaces) : プロキシクラスを取得します。 ローダー は、クラスローダーが インターフェース は、実際のクラスが所有するすべてのインターフェースの配列です。

静的オブジェクト newProxyInstance ( クラスローダー loader、Class[] インターフェース。 インボケーションハンドラ h) <スパン : は プロキシクラスのインスタンスを返します。 返されたプロキシ・クラスは、プロキシ・クラスとして使用することができる ( でプロキシされたクラス'を使用することができます。 件名 インターフェイスで宣言されたメソッド )

いわゆる DynamicProxy はそのような クラス : 実行時に生成される クラス は、その 生成する際には インターフェース を追加し、それに クラス これらを実装していると主張するだけです。 インターフェース . を置くと確実に クラス のインスタンスは、これらのインスタンスとして扱われます。 インターフェース を使えば、どれでも使えるようになります。もちろん DynamicProxy は、実は プロキシ 実質的な作業を行わないもの。 そのインスタンスを生成する際には ハンドラ 実際の作業を引き継ぐ .

ダイナミックプロキシクラスを使用する場合は InvocationHandler インターフェース

このように、プロキシされるオブジェクトは ( リアルサブジェクト ) 実行時に動的に変更される可能性があり、制御が必要なインターフェース (対象 インターフェース ) 実行時に変更可能な、コントロールの方法 ( DynamicSubject クラス ) は動的に変更することもできるので、非常に柔軟な動的プロキシ関係を実現することができます。

ダイナミックプロキシー手順 : は
1. インターフェースInvocationHandlerを実装したクラスを作成し、invokeメソッドを実装する必要があります。
2. プロキシされるクラスとインターフェイスを作成します。
3. プロキシのスタティックメソッドを渡す
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h) でプロキシを作成します.
4. プロキシ経由のメソッド呼び出し

3. JDKの動的プロキシはどのように機能するのですか?

1. 動的プロキシが必要なインターフェース

package jiankunking;

/**
 * Interface that requires a dynamic proxy
 */
public interface Subject
{
    /**
     * Hello
     *
     * @param name
     * @return
     */
    public String SayHello(String name);

    /**
     * Bye
     *
     * @return
     */
    public String SayGoodBye();
}

2, プロキシされる必要のある実際のオブジェクト

package jiankunking;

/**
 * The actual object
 */
public class RealSubject implements Subject
{

    /**
     * Hello
     *
     * @param name
     * @return
     */
    public String SayHello(String name)
    {
        return "hello " + name;
    }

    /**
     * Bye
     *
     * @return
     */
    public String SayGoodBye()
    {
        return " good bye ";
    }
}

3. プロセッサの実装クラスを呼び出す(ここは伝説のAOPって感じ?)

package jiankunking;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect;


/**
 * Invoke the processor implementation class
 * Each time a dynamic proxy class object is generated, you need to specify an invocation handler object that implements the interface
 */
public class InvocationHandlerImpl implements InvocationHandler
{

    /**
     * This is the real object that we want to proxy
     */
    private Object subject;

    private Object; /**
     * Constructor to assign an initial value to the real object we want to proxy
     *private
     * @param subject
     */
    public InvocationHandlerImpl(Object subject)
    {
        this.subject = subject;
    }

    /**
     * This method is responsible for centralizing all method calls on the dynamic proxy class.
     * The call handler is preprocessed or assigned to reflect execution on the delegate class instance based on the three parameters
     *
     * @param proxy Proxy class instance
     * @param method The method object to be called.
     * @param args call argument
     * @return
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
        // We can add some operations of our own before we proxy the real object
        System.out.println("Before invoking, what do I have to do? ");

        System.out.println("Method:" + method);

        // When the proxy object calls the method of the real object, it will automatically jump to the invoke method of the handler object associated with the proxy object to make the call
        Object returnValue = method.invoke(subject, args);

        // We can also add some of our own operations after proxying the real object
        System.out.println("After the call, what do I have to do? ");

        return returnValue;
    }
}


4.テスト

package jiankunking;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * Dynamic proxy demo
 */
public class DynamicProxyDemonstration
{
    public static void main(String[] args)
    {
        // The real object of the proxy
        Subject realSubject = new RealSubject();
        
        /**
         * InvocationHandlerImpl implements the InvocationHandler interface and enables method calls to be forwarded from the proxy class to the delegate class.
         * It usually contains an internal reference to the delegate class instance that is used to actually perform the method calls forwarded by the assignment.
         * i.e., which real object you want to proxy, you pass that object in and end up calling its methods through that real object
         */
        InvocationHandler handler = new InvocationHandlerImpl(realSubject);

        ClassLoader loader = realSubject.getClass().getClassLoader();
        Class[] interfaces = realSubject.getClass().getInterfaces();
        /**
         * This method is used to generate dynamic proxy class instances for a given class loader, set of interfaces and call handler
         */
        Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);

        System.out.println("Type of dynamic proxy object: "+subject.getClass().getName());

        String hello = subject.SayHello("jiankunking");
        System.out.println(hello);
// String goodbye = subject.SayGoodBye();
// System.out.println(goodbye);
    }

}

5. 出力は次のようになります。

デモ音源は以下からダウンロードできます。 http://download.csdn.net/detail/xunzaosiyecao/9597388

IV. ダイナミックプロキシはどのように実装されているのですか?

使用されているコードからわかるように、重要なポイントは入っています。

Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);

プロンプトコードをトレースすると プロキシオブジェクトがリアルオブジェクトのメソッドを呼び出すと、自動的にプロキシオブジェクトに関連付けられたハンドラオブジェクトのinvokeメソッドにジャンプして呼び出しを行います。

つまり、コードが実行されると、になります。

subject.SayHello( をご覧ください。 ) この記述がなされると、InvocationHandlerImplのinvokeメソッドが自動的に呼び出されます。これはなぜでしょうか?

横線の間にあるのがコードと解析過程なので、見たくない人は結論だけ見てください ======================================================================================================================================

以下のコードは、JDK1.8.0_92のものです。

プロキシオブジェクトは Proxy クラスの static 側である newProxyInstance を使って生成されているので、そのソースコードを見て、実際に何をしているのかを見てみましょう。 

/**
 * Returns an instance of a proxy class for the specified interfaces
 * that dispatches method invocations to the specified invocation
 * handler.
 *
 * <p>{@code Proxy.newProxyInstance} throws
 * {@code IllegalArgumentException} for the same reason that
 * {@code Proxy.getProxyClass} does.
 *
 * @param loader the class loader to define the proxy class
 * @param interfaces the list of interfaces for the proxy class
 * to implement
 * @param h the invocation handler to dispatch method invocations to
 * @return a proxy instance with the specified invocation handler of a
 @return a proxy instance with the specified invocation handler of a * proxy class that is defined by the specified class loader
 * and that implements the specified interfaces
 * @throws IllegalArgumentException if any of the restrictions on the
 * parameters that may be passed to {@code getProxyClass}
 @throws SecurityException if any of the restrictions on the * parameters that may be passed to
 * @throws SecurityException if a security manager, <em>s</em>, is present
 * and any of the following conditions is met:
 * <ul>
 * <li> the given {@code loader} is {@code null} and
 * the caller's class loader is not {@code null} and the
 * invocation of {@link SecurityManager#checkPermission
 * s.checkPermission} with
 * {@code RuntimePermission("getClassLoader")} permission
 * denies access;</li>
 * <li> for each proxy interface, {@code intf},
 * the caller's class loader is not the same as or an
 * ancestor of the class loader for {@code intf} and
 * invocation of {@link SecurityManager#checkPackageAccess
 * s.checkPackageAccess()} denies access to {@code intf};</li>
 * <li> any of the given proxy interfaces is non-public and the
 * caller class is not in the same {@linkplain Package runtime package}
 * as the non-public interface and the invocation of
 * {@link SecurityManager#checkPermission s.checkPermission} with
 * {@code ReflectPermission("newProxyInPackage.{package name}")}
 * permission denies access.</li>
 * </ul>
 * @throws NullPointerException if the {@code interfaces} array
 * argument or any of its elements are {@code null}, or
 * if the invocation handler, {@code h}, is
 * {@code null}
 */
@CallerSensitive 
public static Object newProxyInstance(ClassLoader loader,
                                          Class<? >[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
		//check that h is not null, otherwise throw an exception
        Objects.requireNonNull(h);

        final Class<? >[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm ! = null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Get the proxy class type object associated with the specified class loader and set of interfaces
         */
        Class<? > cl = getProxyClass0(loader, intfs);

        /*
         * Get the constructor object and generate the proxy class instance through reflection
         */
        try {
            if (sm ! = null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
			// Get the constructor of the proxy object (i.e. $Proxy0(InvocationHandler h)) 
            final Constructor<? > cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                A

getProxyClass0メソッドに戻り、見てみましょう。

 /* Generate a proxy class.
     * Must call the checkProxyAccess method
     Must call the checkProxyAccess method * to perform permission checks before calling this.
     */private
    private static Class<? > getProxyClass0(ClassLoader loader,
                                           Class<? >... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

真実はまだここにないので、先にプロキシClassCacheを見ます。

/**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<? >[], Class<? >>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

あ、ちょっとだけキャッシュを使うんですねー。

では、それに対応するgetメソッドはどのようなものなのでしょうか?

 /**
     * Look-up the value through the cache. This always evaluates the
     * {@code subKeyFactory} function and optionally evaluates
     * {@code valueFactory} function if there is no entry in the cache for given
     This always evaluates the * {@code subKeyFactory} function and optionally evaluates * {@code valueFactory} function if there is no entry in the cache for given pair of (key, subKey) or the entry has already been cleared.
     * @param key possibly null
     * @param key possibly null key
     * @param parameter parameter used together with key to create sub-key and
     * value (should not be null)
     * @return the cached value (never null)
     * @throws NullPointerException if {@code parameter} passed in or
     * {@code sub-key} calculated by
     * {@code subKeyFactory} or {@code value}
     * calculated by {@code valueFactory} is null.
     */
    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
			//putIfAbsent This method adds a value when the key does not exist, and does not put it in if the key exists
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap ! = null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            if (supplier ! = null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                if (value ! = null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // lazily construct a Factory
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {				
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) { if (supplier == null)
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }


supplier.get(); を呼び出し、ダイナミックプロキシクラスを取得していることがわかります。

getの内部で何が起こっているのか見てみましょう。

 public synchronized V get() { // serialize access
            // re-check
            Supplier<V> supplier = valuesMap.get(subKey);
            if (supplier ! = this) {
                // something changed while we were waiting:
                // might be that we were replaced by a CacheValue
                // or were removed because of failure ->
                // return null to signal WeakCache.get() to retry
                // the loop
                return null;
            }
            // else still us (supplier == this)

            // create new value
            V value = null;
            try {
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { // remove us on failure
                    valuesMap.remove(subKey, this);
                }
            }
            // the only path to reach here is with non-null value
            assert value ! = null;

            // wrap value with CacheValue (WeakReference)
            CacheValue<V> cacheValue = new CacheValue<>(value);

            // try replacing us with CacheValue (this should always succeed)
            if (valuesMap.replace(subKey, this, cacheValue)) {
                // put also in reverseMap
                reverseMap.put(cacheValue, Boolean.TRUE);
            } else {
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            return value;
        }
    }

フォーカスはまだありませんが、valueFactory.apply(key, parameter)メソッドを呼び出していることがわかります。

 /**
     * A factory function that generates, defines and returns the proxy class given
     * the ClassLoader and array of interfaces.
     */private static final class ProxyClassFactory
    private static final class ProxyClassFactory
        implements BiFunction<ClassLoader, Class<? >[], Class<? >>
    {
        // prefix for all proxy class names
        private static final String proxyClassNamePrefix = "$Proxy";

        // next number to use for generation of unique proxy class names
        private static final AtomicLong nextUniqueNumber = new AtomicLong();

        @Override
        public Class<? > apply(ClassLoader loader, Class<? >[] interfaces) {

            Map<Class<? >, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<? > intf : interfaces) {
                /*
                 * Verify that the class loader resolves the name of this
                 * interface to the same Class object.
                 /* */
                Class<? > interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass ! = intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * Verify that the Class object actually represents an
                 * interface.
                 /* If (!
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * Verify that this interface is not a duplicate.
                 /* */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) ! = null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null; // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*PUBLIC | Modifier.
             * Record the package of a non-public proxy interface so that the
             Verify that * all non-public proxy interfaces are defined in the same package.
             Verify that * all non-public proxy interfaces are in the same package.
             Verify that * all non-public proxy interfaces are in the same package. */
            for (Class<? > intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.') ;
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ". ";
            }

            /*
             * Choose a name for the proxy class to generate.
             /* */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 /* A ClassFormatError here means that (barring bugs in the proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }


コードを見てようやくポイントにたどり着いたのが、この

//generate byte code
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);

では、この方法を使って生成されたバイトコードがどのようなものであるかについてもテストしてみましょう。

package jiankunking;

import sun.misc;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
Proxy; import java.lang.reflect;

/**
 * Dynamic proxy demo
 */
public class DynamicProxyDemonstration
{
    public static void main(String[] args)
    {
        // The real object of the proxy
        Subject realSubject = new RealSubject();

        /**
         * InvocationHandlerImpl implements the InvocationHandler interface and enables method calls to be forwarded from the proxy class to the delegate class.
         * It usually contains an internal reference to the delegate class instance that is used to actually perform the method calls forwarded by the assignment.
         * i.e., which real object you want to proxy, you pass that object in and end up invoking its methods through that real object
         */
        InvocationHandler handler = new InvocationHandlerImpl(realSubject);

        ClassLoader loader = handler.getClass().getClassLoader();
        Class[] interfaces = realSubject.getClass().getInterfaces();
        /**
         * This method is used to generate dynamic proxy class instances for a given class loader, set of interfaces and call handler
         */
        Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);

        System.out.println("Type of dynamic proxy object: "+subject.getClass().getName());

        String hello = subject.SayHello("jiankunking");
        System.out.println(hello);
        // save the generated bytecode locally.
        createProxyClassFile();
    }
    private static void createProxyClassFile(){
        String name = "ProxySubject";
        byte[] data = ProxyGenerator.generateProxyClass(name,new Class[]{Subject.class});
        FileOutputStream out =null;
        try {
            out = new FileOutputStream(name+".class");
            System.out.println((new File("hello")).getAbsolutePath());
            out.write(data);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(null!=out) try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

ここで、プロキシオブジェクトの種類を見ることができます。

生成されたバイトコードを jd-jui ツールでデコンパイルします。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import jiankunking.Subject;

public final class ProxySubject
  extends Proxy
  implements Subject
private
  private static Method m1;
  private static Method m3;
  private static Method m4;
  private static Method m2;
  private static Method m0;
  
  public ProxySubject(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String SayGoodBye()
  {
    try
    {
      return (String)this.h.invoke(this, m3, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String SayHello(String paramString)
  {
    try
    {
      return (String)this.h.invoke(this, m4, new Object[] { paramString });
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("jiankunking.Subject").getMethod("SayGoodBye", new Class[0]);
      m4 = Class.forName("jiankunking.Subject").getMethod("SayHello", new Class[] { Class.forName("java.lang.String& quot;) });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}


これが最後の本物のプロキシクラスで、Proxyを継承し、定義したSubjectインタフェースを実装しています、つまり

Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);

ここでは、その 件名 が実際にこのクラスのインスタンスである場合、それを with で呼び出します。

public final String SayHello(String paramString)

定義したInvocationHandlerImplのinvokeメソッドです。

<スパン あなたがそれを見たくない場合は、直接結論を見ることができます===========================横線の間に===================コードと解析のプロセスであり、============================================================================================。

V. 結論

この時点で、ようやく答えが出たことになります。
subject.SayHello("jiankunking") 文が呼ばれると、InvocationHandlerImplのinvokeメソッドが自動的に呼び出されるのはなぜですか?
なぜなら、JDKは最終的に本物のプロキシ・クラスを生成するからです。このクラスはProxyを継承し、私たちが定義したSubjectインタフェースを実装しています。
Subjectインタフェースを実装したメソッドの内部で、InvocationHandlerImplのinvokeメソッドがリフレクションによって呼び出されています。
ネイティブクラスファイルを生成するデモを収録しています。
http://download.csdn.net/detail/xunzaosiyecao/9597474
https://github.com/JianKunKing/DynamicProxyDemo
コードを解析すると、以下の4つのステップからなるJavaダイナミックプロキシーであることがわかる。

  1. InvocationHandlerインタフェースを実装し、独自のコールハンドラを作成する。
  2. ClassLoaderオブジェクトとProxyクラスのインターフェースのセットを指定して、ダイナミックプロキシクラスを作成する。
  3. リフレクション機構によってダイナミックプロキシクラスのコンストラクタを取得する。
  4. コンストラクタで動的プロキシクラスのインスタンスを生成し、呼び出し元のプロセッサ・オブジェクトを構築時にパラメータとして渡します。

個人的なWeChat。

著者:jiankunking From. http://blog.csdn.net/jiankunking

この記事はで参照されています。

http://www.2cto.com/kf/201608/533663.html

http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html