修复 BeanNotOfRequiredTypeException 在非单例 bean 上投射的 Spring 代理上的异常? [英] Fixing BeanNotOfRequiredTypeException on Spring proxy cast on a non-singleton bean?

查看:25
本文介绍了修复 BeanNotOfRequiredTypeException 在非单例 bean 上投射的 Spring 代理上的异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在从应用程序上下文中提取 Spring bean 时遇到问题.

当我尝试时;

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

我明白了;

org.springframework.beans.factory.BeanNotOfRequiredTypeException:名为innerThread"的 Bean 必须是 [com.generic.InnerThread] 类型,但实际上是 [$Proxy26] 类型

如果没有在 getBean() 调用中指定的类,我会得到一个 ClassCastException(您可以在下面详细了解).

InnerThread bean 被初始化为非单例,因为我需要多个实例.InnerThread 类也扩展了 Thread.有趣的是,这个错误出现在 OuterThread 中,它的设置方式与 InnerThread 完全相同.

我尝试在下面包含所有相关的代码清单/堆栈跟踪.有更多 Spring 经验的人能告诉我这里发生了什么吗?

<小时>

代码/配置清单

OuterThread.java 片段:

public class OuterThread extends Thread {私有队列createInnerThreads() {队列<内线程>线程 = 新的 ArrayBlockingQueue();ApplicationContext ctx = SpringContextFactory.getApplicationContext();int i = 0;对于(搜索规则搜索:搜索){logger.debug("循环次数" + i++);//分隔线以更好地了解正在发生的事情对象代理 = 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());//---这里的异常---InnerThread cst = (InnerThread) 代理;线程.添加(cst);}返回线程;}public static void main(String[] args) 抛出异常 {尝试 {OuterThread 实例 = (OuterThread) SpringContextFactory.getApplicationContext().getBean("outerThread", OuterThread.class);实例运行();} 捕捉(异常前){logger.error("致命异常.", ex);扔前;}}}

SpringContextFactory.java:

公共类 SpringContextFactory {静态最终记录器记录器 = LoggerFactory.getLogger(SpringContextFactory.class);私有静态 ApplicationContext ctx;private static final String DEFAULT_PATH = "META-INF/app-context.xml";公共静态 ApplicationContext getApplicationContext() {返回 getApplicationContext(DEFAULT_PATH);}公共静态同步 ApplicationContext getApplicationContext(String path) {if (ctx == null) 返回 createApplicationContext(path);否则返回ctx;}私有静态 ApplicationContext createApplicationContext(字符串路径){if (logger.isDebugEnabled()) logger.debug("Loading Spring Context...");ctx = new ClassPathXmlApplicationContext(path);if (logger.isDebugEnabled()) logger.debug("Spring Context Loaded");返回ctx;}}

app-context.xml:

<!-- 来自单独 jar 的持久化上下文 --><import resource="persistence-context.xml"/><bean id="outerThread" class="com.generic.OuterThread" scope="prototype"/><bean id="innerThread" class="com.generic.InnerThread" scope="prototype"/></豆类>

堆栈跟踪

2009-05-08 14:34:37,341 [main] DEBUG com.generic.OuterThread.init(OuterThread.java:59) - 初始化 OuterThread 对象,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=36000000,ystartModestart=true,=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,HOUR_PM2,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=,eetop=0,single_step=false,daemon=false,stillborn=false,target=,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$ThreadLocalMap6,2cbc0=,nativeParkEventPointer=0,tid=9,threadStatus=0,parkBlocker=,blocker=,blockerLock=java.lang.Object@a68fd8,stopBeforeStart=false,throwableFromStop=,uncaughtExceptionHandler=<空>]2009-05-08 14:34:37,341 [main] DEBUG org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.doJoinTransaction(ExtendedEntityManagerCreator.java:385)-没有要加入的本地事务2009-05-08 14:34:37,529 [main] 调试 com.generic.OuterThread.createInnerThreads(OuterThread.java:139) - 循环次数 02009-05-08 14:34:37,529 [main] DEBUG org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:458) - 用合并的定义创建 bean 'searchThread' 的实例 [Root bean:类 [com.generic.InnerThread];范围=原型;抽象=假;懒惰初始化=假;autowireCandidate=真;autowireMode=0;依赖检查=0;factoryBeanName=null;工厂方法名=空;initMethodName=null;destroyMethodName=null;在类路径资源中定义 [META-INF/app-context.xml]]2009-05-08 14:34:37,545 [main] DEBUG com.generic.InnerThread.<init>(InnerThread.java:50) - 构造 InnerThread 对象,com.generic.InnerThread@1080876[em=<null>,coolScheme=,coolUrl=,date=,error=,millisecondsTaken=0,thresholdMet=false,reconId=0,result=-2,searchId=0,username=,uuid=,name={T,h,r,e,a,d,-,2},priority=5,threadQ=,eetop=0,single_step=false,daemon=false,stillborn=false,target=,group=java.lang.ThreadGroup[name=main,maxpri=10],contextClassLoader=sun.misc.Launcher$AppClassLoader@11b86e7,inheritedAccessControlContext=java.security.AccessControlContext@1524d43,threadLocals=,inheritableThreadLocals=java.lang.ThreadLocal$ThreadLocalMap@3aef16,stackSize=0,nativeParkEventPointer=0,tid=10,threadStatus=0,parkBlocker=,blocker=<null>,blockerLock=java.lang.Object@126c6ea,stopBeforeStart=false,throwableFromStop=<null>,uncaughtExceptionHandler=<空>]2009-05-08 14:34:37,545 [main] 调试 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:203) - 返回单例 bean 'entityManagerFactory' 的缓存实例2009-05-08 14:34:37,545 [main] 调试 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:203) - 返回单例 bean 'org.springframework.transaction.config 的缓存实例.内部交易顾问'2009-05-08 14:34:37,560 [main] 调试 org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.getTransactionAttribute(AbstractFallbackTransactionAttributeSource.java:108) - 添加事务方法 [report] 与属性 [PROPAGATION_ISOL]REQUIRED,2009-05-08 14:34:37,560 [main] DEBUG org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.buildAdvisors(AbstractAutoProxyCreator.java:494) - 使用 0 个通用拦截器和 1 个特定的 bean 创建隐式代理拦截器2009-05-08 14:34:37,560 [main] DEBUG org.springframework.aop.framework.JdkDynamicAopProxy.getProxy(JdkDynamicAopProxy.java:113) - 创建 JDK 动态代理:目标源是目标对象 [com.generic.内线@1080876]2009-05-08 14:34:37,591 [主要]调试com.generic.OuterThread.createInnerThreads(OuterThread.java:141)-$Proxy26@1594a88[h=org.springframework.aop.framework.JdkDynamicAop55@1f0cfProxy@1f0c2009 年 5 月 8 日 14:34:37,591 [主]调试 com.generic.OuterThread.createInnerThreads(OuterThread.java:142)-proxy.getClass():类 $Proxy262009-05-08 14:34:37,591 [main] 调试 com.generic.OuterThread.createInnerThreads(OuterThread.java:143) - proxy.getClass().getClassLoader(): sun.misc.Launcher$AppClassLoader@11b86e72009-05-08 14:34:37,591 [main] 调试 com.generic.OuterThread.createInnerThreads(OuterThread.java:144)-proxy.getClass().getDeclaringClass(): null2009-05-08 14:34:37,591 [main] 调试 com.generic.OuterThread.createInnerThreads(OuterThread.java:145) - InnerThread.class.getClassLoader(): sun.misc.Launcher$AppClassLoader@11b86e72009-05-08 14:34:37,591 [main] 错误 com.generic.OuterThread.run(OuterThread.java:101) - OuterThread 中的异常,结束协调.java.lang.ClassCastException: $Proxy26 不能转换为 com.generic.InnerThread在 com.generic.OuterThread.createInnerThreads(OuterThread.java:148)在 com.generic.OuterThread.run(OuterThread.java:65)在 com.generic.OuterThread.main(OuterThread.java:170)

<小时>

没有回答我的问题的类似问题

解决方案

再一次,在花了几个小时试图调试这个问题之后,我在 StackOverflow 上发帖后立即找到了答案.

我从问题中遗漏的一个关键点是 InnerThread 有一个事务方法(抱歉,认为这无关紧要).这是 OuterThread 和 InnerThread 的重要区别.

来自 Spring 文档:><块引用>

注意

多个部分在运行时合并为一个统一的自动代理创建者,它应用任何部分(通常来自不同的 XML bean 定义文件)指定的最强代理设置.这也适用于 和 元素.

要明确:在 , or 元素上使用 'proxy-target-class="true"' 将强制使用 CGLIB 代理,适用于所有三个.

将上述内容添加到我的配置(基于persistance-context.xml,您可以在上面看到加载)行似乎可以解决问题.但是,我认为这可能是一种快速解决方法,而不是真正的解决方案.

我想我在这里遇到了一些更深层次的问题,第一是我发现 Spring 就像删除了咒骂一样令人困惑.其次,我可能应该使用 Spring 的 TaskExecutor 开始我的话题.第三,我的线程应该实现 Runnable 而不是扩展 Thread(请参阅下面的 SO 问题).

另见

I'm having an issue with pulling a Spring bean from an application context.

When I try;

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

I get;

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

Without the specified class in the getBean() call I get a ClassCastException (which you can see in detail below).

The InnerThread bean is being initialized as a non-singleton, because I need multiple instances. The InnerThread class also extends Thread. The interesting thing is that this error shows up within OuterThread, which is set up in the exact same way the InnerThread is.

I've tried to include all relevant code listings/stack traces below. Could someone with more Spring experience tell me what is going on here?


Code/Configuration Listing

OuterThread.java snippet:

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>

Stack Trace

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)


Similar questions that do not answer my question

解决方案

Once again, after spending hours trying to debug this I find the answer right after posting on StackOverflow.

A key point that I left out from my question is that InnerThread has a transactional method (sorry thought this was irrelevant). This is the important difference between OuterThread and InnerThread.

From the Spring documentation:

Note

Multiple sections are collapsed into a single unified auto-proxy creator at runtime, which applies the strongest proxy settings that any of the sections (typically from different XML bean definition files) specified. This also applies to the and elements.

To be clear: using 'proxy-target-class="true"' on , or elements will force the use of CGLIB proxies for all three of them.

Adding the above to my configuration (based in persistance-context.xml, which you can see loaded above) line seems to fix the problem. However, I think this may be a quick fix workaround as opposed to real solution.

I think I've got a few deeper issues here, number one being that I find Spring as confusing as expletive deleted. Second I should probably be using Spring's TaskExecutor to kick off my threads. Third my threads should implement Runnable instead of extending Thread (See SO question below).

See Also

这篇关于修复 BeanNotOfRequiredTypeException 在非单例 bean 上投射的 Spring 代理上的异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆