#java #spring #proxy #classcastexception #cglib
#java #spring #прокси #classcastexception #cglib
Вопрос:
Вот сценарий, который сводит меня с ума.
- У меня есть класс, в котором есть метод поиска — createOther()
- createOther должен создать объект типа Other. Other реализует OtherInterface и, кроме того, имеет метод doSomething, помеченный как @Async
- Поскольку Other реализует OtherInterface, Spring предоставляет мне прокси JDK, который я не могу использовать как Other.
- Документы Spring предлагают использовать
<aop:config proxy-target-class="true">
— но я новичок в этом, и использование этого, похоже, не помогает.
Вопрос: как мне сообщить Spring, что мне нужен прокси CGLib, предназначенный для другого класса?
Приведенный ниже код завершается ошибкой с classcastexception.
Exception in thread "main" java.lang.ClassCastException: $Proxy4 cannot be cast to scratch.Other
at scratch.App$$EnhancerByCGLIB$$82d16307.createOther(<generated>)
at scratch.App.main(App.java:19)
App.java:
public class App {
public Other createOther() {
throw new UnsupportedOperationException();
}
public static void main(final String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml");
App app = (App) context.getBean("app");
Other oth = app.createOther();
oth.doSomething();
System.out.println("Other created");
}
}
** Other.java **
public interface OtherInterface {
}
class Other implements OtherInterface {
@Async
public void doSomething() {
System.out.println("did something");
}
}
** appcontext.xml **
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:config proxy-target-class="true"></aop:config>
<bean name="app" class="scratch.App">
<lookup-method bean="otherBean" name="createOther" />
</bean>
<bean name="otherBean" class="scratch.Other" scope="prototype">
</bean>
<task:executor id="workflowExecutorSvcPool" pool-size="5-50"
queue-capacity="1000" keep-alive="60" />
<task:annotation-driven executor="workflowExecutorSvcPool" />
</beans>
Комментарии:
1. каково точное сообщение об исключении. И трассировка стека.
Ответ №1:
Кажется, все в порядке — это правильный способ сообщить spring использовать cglib прокси. Фактически, в документации указано, что по умолчанию будут созданы cglib прокси. Единственное требование — иметь cglib в вашем classpath. Убедитесь, что у вас есть cglib jar.
Комментарии:
1. Да — cglib-nodep находится в пути к классу. Фактически, класс App подразделяется на подклассы с использованием CGLIB, как показано в stacktrace.
2. @Raghu — это именно тот
Other
класс, который вы используете? Если нет, можете ли вы показать реальный класс, как он есть.3. да — это точный
Other
класс. Я просто написал приложение и другие классы, чтобы изолировать isuse.4. ничего не меняет — spring по-прежнему видит, что класс реализует ‘OtherInterface’ и выдает мне JDKDynamicProxy
Ответ №2:
task:annotation-driven
Элемент должен поддерживать proxy-target-class
собственный атрибут, для которого необходимо установить значение true, например, для cglib прокси
Ответ №3:
Other oth = app.createOther();
Проблема в этой строке. Поскольку возвращаемый объект на самом деле является прокси, метод createOther()
должен возвращать OtherInterface
, который будет реализован прокси.
Он пытается привести версию прокси-сервера OtherInterface
к Other
классу и терпит неудачу.