Spring's dynamic proxy but was actually of type 'com.sun.proxy. $ Proxy14 Exception

Today in writing Springof introducing the agent when a reported error:

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'

Probably means that type conversion error.

Source code is as follows:

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

inter1.say1();

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

Later, googlea little way into the agent found the CGLIBline.

We all know the JDKonly agent interface, for a class of non-agent interfaces, it should be used CGLIB.

Because CGLIBa proxy class through inheritance to achieve, and JDKis achieved by interface.

But I am here Inter1clearly is an interface. Later, double-check code, in fact, found that the use of Javaa proxy is also OK, as long as the change the following line of code:

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

In other words, needs to be converted into type should be Inter1.classand can not be specific class Inter1Impl.


Why Javaproxy only supports interface agent , here we come Grilled deep look:

First, we define an interface:

public interface People {
    void eat();
}

Then define an implementation class:

public class Student implements People{

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

We then define a proxy class:

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;
    }
}

Next, through a proxy to callStudent


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();
}

Can be seen, Javathe agency is very simple, but the bottom is how to achieve it?

Referring to elaborate JDK dynamic proxy implementation principle , we mainset about the JVMproperty

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();
}

After the run, the project can be found in the root directory of the com/sun/proxy/$Proxy0.classfile, which is the proxy Studentobjects generated .classfiles:

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());
        }
    }
}

Through the above file we can find:

  • Generated proxy class inherits Proxyrealized Peopleinterfaces

    This is why JDKthe proxy can only proxy interface, not proxy the specific class, because Javanot multiple inheritance, it can only implement the interface

  • Because the interface is achieved, thus generating a proxy object forproxy

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

This is the beginning of the root cause of the problems we encountered, proxyjust to achieve the Peopleinterface is not inherited from Studentclass, so you can not proxyobject to a Studenttype, it was reported fault.

Understand the problem, the underlying future use as JDKa proxy class, it will not make another mistake.


If you thought that it was good, welcome to scan the following QR code concern micro-channel public number: Yat tour Java, from time to time publish articles related to Java advanced every day, thanks to attention

Guess you like

Origin www.cnblogs.com/dengchengchao/p/11823687.html