Springの動的プロキシが、型「com.sun.proxyの実際ました。$ Proxy14例外

書面で今日Springエージェントを導入する際に報告されたエラー:

Exception in thread "main" org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'inter1' is expected to be of type 'com.dengchengchao.springtest.intertest.Inter1Impl' but was actually of type 'com.sun.proxy.$Proxy14'

おそらくその型変換エラーを意味します。

次のようにソースコードは次のとおりです。

ApplicationContext  ctx = new AnnotationConfigApplicationContext(Conf.class);
Inter1 inter1 = ctx.getBean("inter1", Inter1Impl.class);

inter1.say1();

Inter2 inter2=(Inter2) inter1;
inter2.say2();

その後、googleエージェントへの少しの方法が見つかりました。CGLIBラインを。

我々は、すべて知っているJDK非エージェント・インターフェースのクラスのために、それが使用されるべきである、唯一のエージェントインターフェイスをCGLIB

のでCGLIB、継承を通じてプロキシクラスを達成するために、およびJDKインタフェースによって達成されます。

しかし、私はここにInter1はっきりとインタフェースです。その後、ダブルチェックコードは、実際には、使用することを見つけJava、プロキシが限り変化として、OKまた、次のコード行です。

Inter1 inter1 = ctx.getBean("inter1", Inter1.class);

言い換えれば、あるべき形に変換する必要があるInter1.classと、特定のクラスにはできませんInter1Impl


なぜJavaプロキシのみサポートエージェントインターフェースは、ここで我々は焼き深い表情を来ります:

まず、インタフェースを定義します。

public interface People {
    void eat();
}

そして、実装クラスを定義します。

public class Student implements People{

    @Override
    public void eat() {
        System.out.println("用手吃");
    }
}

私たちは、プロキシクラスを定義します。

public class StudentInvokeHandler implements InvocationHandler {

    private Object target;

    public StudentInvokeHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable    {

        System.out.println("饭前洗手");
        Object retVal = method.invoke(target, args);
        System.out.println("饭后吃水果");
        return retVal;
    }
}

コールへのプロキシ経由次に、Student


public static void main(String[] args) {
    //初始化Student
    Student student = new Student();
    //初始化Student代理类
    StudentInvokeHandler studentInvokeHandler = new StudentInvokeHandler(student);
    //通过代理获取代理独享
    People studentProxy = (People) Proxy.newProxyInstance(StudentInvokeHandler.class.getClassLoader(), new Class[]{People.class}, studentInvokeHandler);
    //通过代理对象调用eat方法
    studentProxy.eat();
}

見ることができ、Java代理店は非常にシンプルですが、一番下には、それを達成する方法ですか?

参照すると、JDKの動的プロキシ実装原理を詳しく説明し、我々はmain約設定JVMプロパティ

public static void main(String[] args) {
    //将生成的代理类文件保存
    System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
    Student student = new Student();
    StudentInvokeHandler studentInvokeHandler = new StudentInvokeHandler(student);
    People studentProxy = (People) Proxy.newProxyInstance(StudentInvokeHandler.class.getClassLoader(), new Class[]{People.class}, studentInvokeHandler);
    studentProxy.eat();
}

実行した後、プロジェクトはのルートディレクトリに見つけることができるcom/sun/proxy/$Proxy0.classプロキシでファイル、Student生成されたオブジェクト.classファイル:

public final class $Proxy0 extends Proxy implements People {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void eat() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.dengchengchao.springtest.proxy.People").getMethod("eat");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

上記のファイルを通して、私たちは見つけることができます:

  • 生成されたプロキシクラスの継承Proxyを実現Peopleインターフェース

    理由はここにありJDK、プロキシが唯一のプロキシインタフェースは、プロキシではない特定のクラスは、ためができJava、複数のない継承、それが唯一のインターフェイスを実装することができます

  • インターフェイスが達成されるので、このようにプロキシオブジェクトを生成しますproxy

    proxy instanceof People  //true
    proxy instanceof Student //false

これは、私たちが遭遇した問題の根本的な原因の始まりであるproxyだけで達成するためPeopleのインタフェースから継承されていないStudentあなたがすることはできませんので、クラスproxyに反対しStudent、それは障害を報告したタイプ。

問題を理解し、基盤となる将来の使用のJDKプロキシクラスが、それは別のミスをすることはありません。


あなたはそれが良かったと思った場合は、懸念のマイクロチャネル公共数以下のQRコードをスキャンする歓迎:随時ヤットツアーのJava、Javaへの関連記事を公開し、毎日を進めた、注目のおかげで

おすすめ

転載: www.cnblogs.com/dengchengchao/p/11823687.html