Сегодня в письменной форме 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
класса, так что вы не можете proxy
возражать против Student
типа, было сообщена неисправностью.
Понять проблему, лежащая в основе использования в будущем в качестве JDK
прокси - класса, он не будет делать еще одну ошибку.
Если вы думали, что это хорошо, добро пожаловать отсканировать следующий QR-код относятся микро-канал общедоступный номер: Ят тур Java, время от времени публиковать статьи, связанные с Java расширенный каждый день, благодаря вниманию