봄의 동적 프록시가 실제로 형이었다 '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프록시는 확인도 한 변경 다음 코드 줄과 같은 :

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당신이 할 수 있도록, 클래스 proxyA와 객체 Student,이 오류를보고 유형입니다.

문제를 이해로서 기본이 향후 사용 JDK프록시 클래스는, 그것은 또 다른 실수를하지 않습니다.


관심에 감사야만 투어 자바, 자바 관련 기사가 매일 고급 게시 때때로 : 당신은 좋았다 다음 QR 코드 관심사 마이크로 채널 공용 수를 스캔에 오신 것을 환영 생각하는 경우

추천

출처www.cnblogs.com/dengchengchao/p/11823687.html