Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Исправление BeanNotOfRequiredTypeException на прокси-сервере Spring, не являющемся одноэлементным компонентом?

Автор вопроса: James McMahonОтветов: 9

У меня проблема с извлечением bean-компонента Spring из контекста приложения.

Когда я пытаюсь;

InnerThread instance = (InnerThread) SpringContextFactory.getApplicationContext().getBean("innerThread", InnerThread.class);

Я получил;

org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'innerThread' must be of type [com.generic.InnerThread], but was actually of type [$Proxy26]

Без указанного класса в вызове getBean () я получаю ClassCastException (подробности которого вы можете увидеть ниже).

Bean-компонент InnerThread инициализируется как не-синглтон, потому что мне нужно несколько экземпляров. Класс InnerThread также является расширением Thread. Интересно то, что эта ошибка появляется в OuterThread, который настроен точно так же, как InnerThread.

Я попытался включить все соответствующие листинги кода / трассировки стека ниже. Может ли кто-нибудь с большим опытом Spring сказать мне, что здесь происходит?


Листинг кода / конфигурации

Фрагмент OuterThread.java:

public class OuterThread extends Thread {
    private Queue<InnerThread> createInnerThreads() {
        Queue<InnerThread> threads = new ArrayBlockingQueue();

        ApplicationContext ctx = SpringContextFactory.getApplicationContext();
        int i = 0;
        for (SearchRule search : searches) {
            logger.debug("Number of times looped " + i++);
            //Seprated lines to get a better sense of what is going on
            Object proxy = ctx.getBean("innerThread", InnerThread.class);
            logger.debug(ReflectionToStringBuilder.toString(proxy));
            logger.debug("proxy.getClass(): " + proxy.getClass());
            logger.debug("proxy.getClass().getClassLoader(): " + proxy.getClass().getClassLoader());
            logger.debug("proxy.getClass().getDeclaringClass(): " + proxy.getClass().getDeclaringClass());
            logger.debug("InnerThread.class.getClassLoader(): " + InnerThread.class.getClassLoader());

            //---Exception here---
            InnerThread cst = (InnerThread) proxy;

            threads.add(cst);
        }
        return threads;
    }

    public static void main(String[] args) throws Exception {
        try {
            OuterThread instance = (OuterThread) SpringContextFactory.getApplicationContext().getBean("outerThread", OuterThread.class);
            instance.run();
        } catch (Exception ex) {
            logger.error("Fatal exception.", ex);
            throw ex;
        }
    }
}

SpringContextFactory.java:

public class SpringContextFactory {
    static final Logger logger = LoggerFactory.getLogger(SpringContextFactory.class);
    private static ApplicationContext ctx;
    private static final String DEFAULT_PATH = "META-INF/app-context.xml";

    public static ApplicationContext getApplicationContext() {
        return getApplicationContext(DEFAULT_PATH);
    }

    public static synchronized ApplicationContext getApplicationContext(String path) {
        if (ctx == null) return createApplicationContext(path);
        else return ctx;
    }

    private static ApplicationContext createApplicationContext(String path) {
        if (logger.isDebugEnabled()) logger.debug("Loading Spring Context...");
        ctx = new ClassPathXmlApplicationContext(path);
        if (logger.isDebugEnabled()) logger.debug("Spring Context Loaded");
        return ctx;
    }
}

app-context.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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <!-- persistence context from separate jar -->
    <import resource="persistence-context.xml"/>

    <bean id="outerThread" class="com.generic.OuterThread" scope="prototype"/>
    <bean id="innerThread" class="com.generic.InnerThread" scope="prototype"/>

</beans>

Трассировки стека

2009-05-08 14:34:37,341 [main] DEBUG com.generic.OuterThread.init(OuterThread.java:59) - Initializing OuterThread object, com.generic.OuterThread@1c8fb4b[em=org.hibernate.ejb.EntityManagerImpl@e2892b,currentTime=java.util.GregorianCalendar[time=1241634874841,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2009,MONTH=4,WEEK_OF_YEAR=19,WEEK_OF_MONTH=2,DAY_OF_MONTH=6,DAY_OF_YEAR=126,DAY_OF_WEEK=4,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=2,HOUR_OF_DAY=14,MINUTE=34,SECOND=34,MILLISECOND=841,ZONE_OFFSET=-18000000,DST_OFFSET=3600000],maxConcurrentThreads=5,reconId=3,reportUsername=TEST,useOffset=false,username=removed,uuid=bf61494d-ff96-431c-a41f-1e292d0c9fbe,name={T,h,r,e,a,d,-,1},priority=5,threadQ=<null>,eetop=0,single_step=false,daemon=false,stillborn=false,target=<null>,group=java.lang.ThreadGroup[name=main,maxpri=10],contextClassLoader=sun.misc.Launcher$AppClassLoader@11b86e7,inheritedAccessControlContext=java.security.AccessControlContext@1524d43,threadLocals=<null>,inheritableThreadLocals=java.lang.ThreadLocal$ThreadLocalMap@2cbc86,stackSize=0,nativeParkEventPointer=0,tid=9,threadStatus=0,parkBlocker=<null>,blocker=<null>,blockerLock=java.lang.Object@a68fd8,stopBeforeStart=false,throwableFromStop=<null>,uncaughtExceptionHandler=<null>]
2009-05-08 14:34:37,341 [main] DEBUG org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.doJoinTransaction(ExtendedEntityManagerCreator.java:385) - No local transaction to join
2009-05-08 14:34:37,529 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:139) - Number of times looped 0
2009-05-08 14:34:37,529 [main] DEBUG org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:458) - Creating instance of bean 'searchThread' with merged definition [Root bean: class [com.generic.InnerThread]; scope=prototype; abstract=false; lazyInit=false; autowireCandidate=true; autowireMode=0; dependencyCheck=0; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [META-INF/app-context.xml]]
2009-05-08 14:34:37,545 [main] DEBUG com.generic.InnerThread.<init>(InnerThread.java:50) - Constructing InnerThread object, com.generic.InnerThread@1080876[em=<null>,coolScheme=<null>,coolUrl=<null>,date=<null>,error=<null>,millisecondsTaken=0,thresholdMet=false,reconId=0,result=-2,searchId=0,username=<null>,uuid=<null>,name={T,h,r,e,a,d,-,2},priority=5,threadQ=<null>,eetop=0,single_step=false,daemon=false,stillborn=false,target=<null>,group=java.lang.ThreadGroup[name=main,maxpri=10],contextClassLoader=sun.misc.Launcher$AppClassLoader@11b86e7,inheritedAccessControlContext=java.security.AccessControlContext@1524d43,threadLocals=<null>,inheritableThreadLocals=java.lang.ThreadLocal$ThreadLocalMap@3aef16,stackSize=0,nativeParkEventPointer=0,tid=10,threadStatus=0,parkBlocker=<null>,blocker=<null>,blockerLock=java.lang.Object@126c6ea,stopBeforeStart=false,throwableFromStop=<null>,uncaughtExceptionHandler=<null>]
2009-05-08 14:34:37,545 [main] DEBUG org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:203) - Returning cached instance of singleton bean 'entityManagerFactory'
2009-05-08 14:34:37,545 [main] DEBUG org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:203) - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
2009-05-08 14:34:37,560 [main] DEBUG org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.getTransactionAttribute(AbstractFallbackTransactionAttributeSource.java:108) - Adding transactional method [report] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT]
2009-05-08 14:34:37,560 [main] DEBUG org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.buildAdvisors(AbstractAutoProxyCreator.java:494) - Creating implicit proxy for bean 'searchThread' with 0 common interceptors and 1 specific interceptors
2009-05-08 14:34:37,560 [main] DEBUG org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:113) - Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.generic.InnerThread@1080876]
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:141) - $Proxy26@1594a88[h=org.springframework.aop.framework.JdkDynamicAopProxy@1f0cf51]
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:142) - proxy.getClass(): class $Proxy26
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:143) - proxy.getClass().getClassLoader(): sun.misc.Launcher$AppClassLoader@11b86e7
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:144) - proxy.getClass().getDeclaringClass(): null
2009-05-08 14:34:37,591 [main] DEBUG com.generic.OuterThread.createInnerThreads(OuterThread.java:145) - InnerThread.class.getClassLoader(): sun.misc.Launcher$AppClassLoader@11b86e7
2009-05-08 14:34:37,591 [main] ERROR com.generic.OuterThread.run(OuterThread.java:101) - Exception in OuterThread, ending reconciliation.
java.lang.ClassCastException: $Proxy26 cannot be cast to com.generic.InnerThread
    at com.generic.OuterThread.createInnerThreads(OuterThread.java:148)
    at com.generic.OuterThread.run(OuterThread.java:65)
    at com.generic.OuterThread.main(OuterThread.java:170)

Подобные вопросы, которые не отвечают на мой вопрос

javaspringcastingaopproxy-classes

Ответы

Ответ 1 · рейтинг 39 · thSoft

Добавьте аннотации к вашему @Configuration классу с помощью

@EnableAspectJAutoProxy(proxyTargetClass = true)

Вам также необходимо добавить следующую зависимость:

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.2</version>
</dependency>

Ответ 2 · рейтинг 25 · James McMahon

Еще раз, потратив часы на отладку, я нахожу ответ сразу после публикации в StackOverflow.

Ключевым моментом, который я не упомянул в своем вопросе, является то, что InnerThread имеет транзакционный метод (извините, что это не имеет значения). Это важное различие между OuterThread и InnerThread.

Из документации Spring:

Примечание

Во время выполнения несколько разделов сворачиваются в единую унифицированную программу создания автопрокси, которая применяет самые строгие настройки прокси, указанные в любом из разделов (обычно из разных файлов определения компонентов XML). Это также относится к элементам и.

Чтобы было ясно: использование 'proxy-target-class = "true"' on, иначе элементы заставят использовать прокси CGLIB для всех трех из них.

Добавление приведенной выше строки в мою конфигурацию (на основе persistance-context.xml, которую вы можете видеть загруженной выше), похоже, решает проблему. Однако я думаю, что это может быть быстрое решение, а не реальное решение.

Я думаю, у меня есть несколько более глубоких проблем, во-первых, то, что я считаю Spring столь же запутанной, как и удаление ругательств. Во-вторых, мне, вероятно, следует использовать TaskExecutor Spring, чтобы начать мои обсуждения. В-третьих, мои потоки должны реализовывать Runnable вместо расширения Thread (см. Вопрос SO ниже).

См. также

  • BeanNotOfRequiredTypeException с использованием ServiceLocatorFactoryBean и @Transactional (нет ничего лучше, чем найти ветку вне Google после часов поиска, чтобы получить ответ, в котором говорится: "На этот вопрос уже ответили миллион раз").
  • Раздел 6.6 в документации Spring.
  • Java: "реализует Runnable" против "расширяет поток"

Ответ 3 · рейтинг 3 · tom

Один из способов решить эту проблему - расширить исполняемый интерфейс и создать свой собственный:

public interface MyInterface extends Runnable {
  // your own method declarations here
  void doSomething();
  ...
}

Затем вы должны реализовать свой интерфейс вместо исполняемого:

@Component("myInterface")
@Scope("prototype")
     public class MyInterfaceImpl implements MyInterface {

          // your own method declarations here
          public void doSomething(){
          ...
          }


          // implement run from Runnable Interface
          @Transactional
          public void run(){
                .....
          }

             ...
        }

Это будет нормально работать:

...
    MyInterface mynterface = SpringApplicationContext.getBean("myInterface", MyInterface.class);

    myInterface.doSomething();
  ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.submit(myInterface);
...

Ответ 4 · рейтинг 2 · egaga

Это всего лишь предположение, но попробуйте создать интерфейс InnerThreadInterface, а затем позвольте классу InnerThread расширить его.

После этого вы сможете:

InnerThreadInterface inner = ctx.getBean ("innerThread", InnerThread.class);

Ответ 5 · рейтинг 1 · Community

У меня была эта проблема, хотя я ссылался на CGLIB и использовал настройку proxy-target-class = "true". Я решил, что виноват тег ehcache: annotation ... Удаление следующей конфигурации решило эту проблему. К счастью, я смог использовать кеширование уровня гибернации 2 вместо декларативного кеширования ehcache.

<ehcache:annotations>
    <ehcache:caching id="myCacheModel" cacheName="myCache"/>
    <ehcache:flushing id="myFlushModel" cacheNames="myCache" when="after"/>
</ehcache:annotations>

Ответ 6 · рейтинг 1 · Nathan Feger

Другой способ справиться с этой проблемой - реализовать интерфейс и запросить интерфейс из spring, прокси-сервер полностью реализует интерфейс, и при приведении не должно возникнуть проблем.

Ответ 7 · рейтинг 1 · Boechi

У меня такая же проблема:

Это всего лишь предположение, но попробуйте создать интерфейс InnerThreadInterface, а затем позвольте классу InnerThread расширить его. После этого вы сможете:

Я использую этот способ вместо того, что опубликовано выше, и он работал нормально. Не было необходимости устанавливать для proxy-target-class значение true, для этого требовалось больше библиотек, которых не было в моем пути к классам.

InnerThreadInterface inner = (InnerThreadInterface)ctx.getBean("innerThread");

Ответ 8 · рейтинг -1 · czarabid

создать интерфейс DAO и реализовать интерфейс DAO для класса SERVICE и предоставить подробные сведения о конфигурации класса SERVICE в файле applicationContext.xml, то есть в файле конфигурации spring, и получить доступ к компоненту с использованием идентификатора компонента и ссылаться на экземпляр созданного таким образом прокси объект интерфейса DAO ... он будет работать отлично ....

Ответ 9 · рейтинг -2 · Roman

Эта проблема была до тех пор, пока я просто не перезапустил Idea и не пересобирал проект Maven.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы