Java 修复 BeanNotOfRequiredTypeException 在非单例 bean 上投射的 Spring 代理上的异常?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/841231/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Fixing BeanNotOfRequiredTypeException on Spring proxy cast on a non-singleton bean?
提问by James McMahon
I'm having an issue with pulling a Spring bean from an application context.
我在从应用程序上下文中提取 Spring bean 时遇到问题。
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).
如果没有在 getBean() 调用中指定的类,我会得到一个 ClassCastException(您可以在下面详细了解)。
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.
InnerThread bean 被初始化为非单例,因为我需要多个实例。InnerThread 类也扩展了 Thread。有趣的是,这个错误出现在 OuterThread 中,它的设置方式与 InnerThread 完全相同。
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?
我试图在下面包含所有相关的代码清单/堆栈跟踪。有更多 Spring 经验的人可以告诉我这里发生了什么吗?
Code/Configuration Listing
代码/配置清单
OuterThread.java snippet:
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:
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:
<?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.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
类似的问题没有回答我的问题
采纳答案by James McMahon
Once again, after spending hours trying to debug this I find the answer right after posting on StackOverflow.
再一次,在花了几个小时尝试调试之后,我在 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.
我从我的问题中遗漏的一个关键点是 InnerThread 有一个事务方法(抱歉,认为这无关紧要)。这是 OuterThread 和 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 proxiesfor all three of them.
笔记
多个部分在运行时合并为一个统一的自动代理创建者,它应用任何部分(通常来自不同的 XML bean 定义文件)指定的最强代理设置。这也适用于 和 元素。
需要明确的是:在 , or 元素上使用 'proxy-target-class="true"'将强制对所有三个元素使用CGLIB 代理。
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.
将上述内容添加到我的配置(基于persistance-context.xml,您可以在上面看到加载)行似乎可以解决问题。但是,我认为这可能是一种快速解决方法,而不是真正的解决方案。
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 TaskExecutorto kick off my threads. Third my threads should implement Runnable instead of extending Thread (See SO question below).
我想我在这里遇到了一些更深层次的问题,第一个问题是我发现 Spring 就像删除了咒骂一样令人困惑。其次,我可能应该使用Spring 的 TaskExecutor来启动我的线程。第三,我的线程应该实现 Runnable 而不是扩展 Thread (请参阅下面的 SO 问题)。
See Also
也可以看看
- BeanNotOfRequiredTypeException using ServiceLocatorFactoryBean and @Transactional(Nothing better then finding a thread off Google after hours of searching to have a response that says "This has already been answered a million times.")
- Section 6.6 in the Spring Docs.
- Java: “implements Runnable” vs. “extends Thread”
- BeanNotOfRequiredTypeException 使用 ServiceLocatorFactoryBean 和 @Transactional(没有什么比在经过数小时的搜索后在 Google 上找到一个线程以得到“这已经被回答了一百万次”的回复更好了。)
- Spring 文档中的第 6.6 节。
- Java:“实现可运行”与“扩展线程”
回答by egaga
This is just a guess, but try making an interface InnerThreadInterface, then let InnerThread class extend it.
这只是一个猜测,但尝试制作一个接口 InnerThreadInterface,然后让 InnerThread 类扩展它。
After that you should be able to do:
之后你应该能够做到:
InnerThreadInterface inner = ctx.getBean("innerThread", InnerThread.class);
InnerThreadInterface 内部 = ctx.getBean("innerThread", InnerThread.class);
回答by James McMahon
I had this issue even though I referenced CGLIB and used the proxy-target-class="true" setting. I determined ehcache:annotation tag was to blame... Removing the following configuration solved this for me. Fortunately, I was able to use hibernate level 2 caching instead of having to use ehcache declarative caching.
即使我引用了 CGLIB 并使用了 proxy-target-class="true" 设置,我也遇到了这个问题。我确定 ehcache:annotation 标签是罪魁祸首......删除以下配置为我解决了这个问题。幸运的是,我能够使用 hibernate 2 级缓存,而不必使用 ehcache 声明性缓存。
<ehcache:annotations>
<ehcache:caching id="myCacheModel" cacheName="myCache"/>
<ehcache:flushing id="myFlushModel" cacheNames="myCache" when="after"/>
</ehcache:annotations>
回答by Nathan Feger
Another way to handle this problem would be to implement an interface and request the interface from spring, the proxy would fully implement the interface, and the cast shouldn't have a problem.
处理这个问题的另一种方法是实现一个接口并从 spring 请求该接口,代理将完全实现该接口,并且转换应该没有问题。
回答by Boechi
I had the same problem:
我有同样的问题:
This is just a guess, but try making an interface InnerThreadInterface, then let InnerThread class extend it. After that you should be able to do:
这只是一个猜测,但尝试制作一个接口 InnerThreadInterface,然后让 InnerThread 类扩展它。之后你应该能够做到:
I use this way instead of what is posted above and it worked fine. There was no need of setting the proxy-target-class to true, this required more libraries that wasn't on my classpath.
我使用这种方式而不是上面发布的方式,并且效果很好。不需要将 proxy-target-class 设置为 true,这需要更多不在我的类路径中的库。
InnerThreadInterface inner = (InnerThreadInterface)ctx.getBean("innerThread");
回答by tom
One way to solve this issue is by extending the runnable interface and creating your own:
解决此问题的一种方法是扩展可运行接口并创建自己的接口:
public interface MyInterface extends Runnable {
// your own method declarations here
void doSomething();
...
}
Then you should implement your interface instead of the runnable:
然后你应该实现你的接口而不是可运行的:
@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(){
.....
}
...
}
This will work fine:
这将正常工作:
...
MyInterface mynterface = SpringApplicationContext.getBean("myInterface", MyInterface.class);
myInterface.doSomething();
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(myInterface);
...
回答by thSoft
Annotate your @Configuration
class with
注释你的@Configuration
类
@EnableAspectJAutoProxy(proxyTargetClass = true)
You also have to add the following dependency:
您还必须添加以下依赖项:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.2</version>
</dependency>
回答by czarabid
create a DAO interface and implement the DAO interface to the SERVICE class and provide the config details of SERVICE class in the applicationContext.xml file i.e., the spring config file and access the bean using the bean id and reference the instance of the so instantiated proxy object to the DAO interface ... it will work perfectly fine ....
创建一个 DAO 接口并将 DAO 接口实现到 SERVICE 类,并在 applicationContext.xml 文件(即 spring 配置文件)中提供 SERVICE 类的配置详细信息,并使用 bean id 访问 bean 并引用如此实例化的代理的实例对象到 DAO 接口......它会工作得很好......