Исключение Spring — Classcast как CGLIB прокси не может быть принудительно

#java #spring #proxy #classcastexception #cglib

#java #spring #прокси #classcastexception #cglib

Вопрос:

Вот сценарий, который сводит меня с ума.

  1. У меня есть класс, в котором есть метод поиска — createOther()
  2. createOther должен создать объект типа Other. Other реализует OtherInterface и, кроме того, имеет метод doSomething, помеченный как @Async
  3. Поскольку Other реализует OtherInterface, Spring предоставляет мне прокси JDK, который я не могу использовать как Other.
  4. Документы 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 классу и терпит неудачу.