我的一个集成测试使用多个Spring上下文文件。似乎Spring只在第一个上下文而不是第二个上下文中自动装配bean。有谁知道我做错了什么或如何解决这个问题?
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:/META-INF/spring/applicationContext.xml", "classpath:/META-INF/spring/applicationContext-security.xml"}) @Configurable public class UserDetailsServiceImplIntegrationTest { @Autowired UserDataOnDemand dod; // @Autowired does not work for this bean from applicationContext-security.xml UserDetailsService userDetailsService; @Before public void setup() { dod.init(); // workaround for autowiring problem userDetailsService = (UserDetailsService)ctx.getBean("userDetailsService"); } @Test public void testLoadUser() { UserDetails ud = userDetailsService.loadUserByUsername("david@somewhere.co.za"); Assert.assertEquals("david@somewhere.co.za", ud.getUsername()); } }
我正在使用Spring 3.0.3。
当我取消注释UserDetailsService的@Autowired行时,这是堆栈跟踪:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'za.co.acme.app.security.UserDetailsServiceImplIntegrationTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.security.core.userdetails.UserDetailsService za.co.acme.app.security.UserDetailsServiceImplIntegrationTest.userDetailsService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.springframework.security.core.userdetails.UserDetailsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1064) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:374) at org.springframework.beans.factory.wiring.BeanConfigurerSupport.configureBean(BeanConfigurerSupport.java:140) at org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect.configureBean(AnnotationBeanConfigurerAspect.aj:59) at org.springframework.beans.factory.aspectj.AbstractDependencyInjectionAspect.ajc$afterReturning$org_springframework_beans_factory_aspectj_AbstractDependencyInjectionAspect$2$1ea6722c(AbstractDependencyInjectionAspect.aj:89) at za.co.acme.app.security.UserDetailsServiceImplIntegrationTest.(UserDetailsServiceImplIntegrationTest.java:25) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:202)
bean肯定存在,因为“按名称”查找工作,并且它的类型正确。
答案 0 :(得分:7)
解决方法是创建一个新的单个配置文件(我们称之为“test-configuration.xml”),该文件包括applicationContext.xml和applicationContext-security.xml。然后,您可以在测试中使用这些配置。
测试-configuration.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<import resource="classpath:/META-INF/spring/applicationContext.xml"/>
<import resource="classpath:/META-INF/spring/applicationContext-security.xml"/>
</beans>
UserDetailsServiceImplIntegrationTest.java:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/test-configuration.xml")
@Configurable
public class UserDetailsServiceImplIntegrationTest {
...
}
答案 1 :(得分:4)
我有类似的设置,它对我来说很好。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/applicationContext-struts.xml", "classpath:/applicationContext.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
@Transactional
public abstract class BaseTests {
我的猜测是问题在于你的项目设置。你用Eclipse吗?它是从/ bin文件夹还是从/ src文件夹加载上下文文件?您是否从构建中排除了“applicationContext-security.xml”?
答案 2 :(得分:4)
我有同样的问题,解决方案修复了我的问题是通过Interface切换bean暴露。 (即)您的引用Bean类型应该是接口而不是其实现类
在您的情况下,使用其界面更改具体的类UserDetailsService
引用。
例如:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/META-INF/spring/applicationContext.xml",
"classpath:/META-INF/spring/applicationContext-security.xml"})
@Configurable
public class UserDetailsServiceImplIntegrationTest {
//modified code
@Autowired
IUserDetailsService userDetailsService;
//your test cases follows
}
注意:我知道这不是一个明智的解决方案,但只是试一试,我担心很多,因为同样的错误,最后改变了我的参考,它工作正常。希望它能解决你的问题。
答案 3 :(得分:1)
你需要告诉Spring对这些注释采取行动。在相关的上下文文件中,您应添加以下内容:
<context:annotation-config/>
现在它会扫描那些注释。请参阅Annotation-based configuration
上的Spring文档要限制扫描所需的类数,以免不必要地扫描没有自动装配的包,请添加:
<context:component-scan base-package="org.example"/>
有关详细信息,请参阅Auto-detecting components的文档,以及为引用这些标记而需要添加的XML命名空间。
答案 4 :(得分:0)
xml中userDetailsService
的bean名称是什么?您可能需要使用bean名称添加@Qualifier
注释,然后在上下文中添加<qualifier>
标记。
请查看有关该主题的Spring's documentation。
答案 5 :(得分:0)
我有同样的问题。似乎有一个代理UserDataOnDemand而不是真正的UserDataOnDemand。