我们在部署应用程序时遇到了问题,经过一段时间的研究后,我们发现了问题来源,但我们不知道为什么会这样。
应用程序尝试在Spring上下文初始化中连接bean'foo'上的bean'bar'。 'bar'bean实现了ApplicationListener接口,并且还有一个@Cacheable方法。由于某种原因,我们不知道,豆类创建出现了崩溃。删除@Cacheable或使bean不是ApplicationListener的实例会使应用程序运行正常。
可能是对ApplicationListener和/或@Cacheable的误解,但是出现此错误的原因是什么?为什么'酒吧'豆'非法'? Spring版本是3.2.9。
Spring上下文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd">
<bean id="applicationContextProvder" class="com.mycompany.ApplicationContextProvider"/>
<!-- CACHE -->
<cache:annotation-driven cache-manager="springEhCacheManager"/>
<bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="/WEB-INF/conf/ehcache.xml"/>
</bean>
<bean id="springEhCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<constructor-arg ref="ehCacheManager"/>
</bean>
<bean id="cacheProvider" class="org.springmodules.cache.provider.ehcache.EhCacheFacade">
<property name="cacheManager" ref="ehCacheManager"/>
</bean>
<bean id="cacheService" class="com.myapp.cache.DefaultEHCacheServiceImp">
<constructor-arg index="0" ref="ehCacheManager"/>
</bean>
<!-- ALIVE -->
<bean id="voldemortAlive"
class="com.myapp.voldemort.VoldemortAliveImp">
</bean>
<bean id="atlasAlive"
class="com.myapp.atlas.AtlasAliveImp">
</bean>
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>
<!-- custom beans defined -->
<bean id="updatersSynchronizedTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"/>
<bean id="updatersSynchronizedTaskExporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false"/>
Foo class
package com.foo
@Service
public class Foo {
@Autowired
private Bar bar;
... lots of stuff here ...
@PostConstruct
protected void init() {
... method body ...
}
... more logic ...
}
酒吧课
package com.bar
@Repository
public class Bar extends BarParent implements ApplicationListener<BarEvent> {
... more stuff ...
@Cacheable("cache_name")
public List<Baz> cachedMethod(final Integer code) {
... some logic here ...
}
...
}
给出例外
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bar.Bar com.foo.Foo.bar; nested exception is java.lang.IllegalArgumentException: Can not set com.bar.Bar field com.foo.Foo.bar to $Proxy86
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:517)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286)
... 63 more
Caused by: java.lang.IllegalArgumentException: Can not set com.bar.Bar field com.foo.Foo.bar to $Proxy86
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
at java.lang.reflect.Field.set(Field.java:657)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:513)
... 65 more
提前谢谢。
答案 0 :(得分:2)
更改
<cache:annotation-driven cache-manager="springEhCacheManager"/>
到
<cache:annotation-driven cache-manager="springEhCacheManager" proxy-target-class="true"/>
由于其中一个方法是@Cacheable
,Spring会为Bar
生成一个代理。由于默认代理生成策略基于Java动态代理,Bar
实现接口ApplicationListener
,因此生成的代理是ApplicationListener
的子类型而不是Bar
。因此,当遇到@Autowired Bar
时,Spring会尝试注入不是Bar
子类型的代理实例,因此会出错。
通过将proxy-target-class
设置为true
,Spring将被迫使用CGLIB生成基于类的代理,@Autowired Bar
将注入Bar
实例。