使用案例:我通过类路径扫描@ComponentScan配置了我的容器。对于我的测试配置,我需要能够模拟特定的bean。
由于加载顺序,使用@Configuration时,通过类路径扫描加载的bean不会正确覆盖。以下代码示例演示了此问题。 BaseExample.java显示了如何通过配置覆盖bean。 ScanExample.java显示覆盖了通过@ComponentScan加载的bean(参见最后的注释)。
bitbucket上有一个演示项目。
// BaseExample.java
package com.glassworks.mock;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.common.base.Joiner;
public class BaseExample {
private static final Logger log = LoggerFactory.getLogger(BaseExample.class);
private static AnnotationConfigApplicationContext ctx;
public static void main(String args[]) {
ctx = new AnnotationConfigApplicationContext(Config.class, OverrideConfig.class);
String beans[] = ctx.getBeanDefinitionNames();
log.info("{} beans found: {}", beans.length, Joiner.on(",").join(beans));
for(String bean : beans) {
log.info("{}: {}", bean, ctx.getBean(bean));
}
}
@Configuration
public static class Config {
@Bean
public AccountDao accountDao() {
log.debug("Creating accountDao [Config]");
return new AccountDao();
}
}
@Configuration
public static class OverrideConfig {
@Bean
public Object accountDao() {
log.debug("Creating accountDao [OverrideConfig]");
return Mockito.mock(AccountDao.class);
}
}
}
输出: 21:05 INFO | com.glassworks.mock.BaseExample | accountDao:模拟AccountDao,hashCode:666537607
[// ScanExample.java
package com.glassworks.mock;
import org.mockito.Mockito;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.google.common.base.Joiner;
public class ScanExample {
private static final Logger log = LoggerFactory.getLogger(ScanExample.class);
private static AnnotationConfigApplicationContext ctx;
public static void main(String args[]) {
ctx = new AnnotationConfigApplicationContext(Config.class, OverrideConfig.class);
String beans[] = ctx.getBeanDefinitionNames();
log.info("{} beans found: {}", beans.length, Joiner.on(",").join(beans));
for(String bean : beans) {
log.info("{}: {}", bean, ctx.getBean(bean));
}
}
@Configuration
@ComponentScan("com.glassworks.services")
public static class Config {
}
@Configuration
public static class OverrideConfig {
@Bean
public AccountDao accountDao() {
log.debug("Creating accountDao [OverrideConfig]");
return Mockito.mock(AccountDao.class);
}
}
}
输出: 21:08 INFO | com.glassworks.mock.ScanExample | accountDao:com.glassworks.services.AccountDao@48805ebb
// AccountDao.java
package com.glassworks.services;
import org.springframework.stereotype.Repository;
@Repository
public class AccountDao {
}
注意 值得注意的是,在将日志设置为调试的情况下,Spring表示它正在跳过定义。这似乎是一个错误。
21:09 DEBUG | o.s.c.a.ConfigurationClassBeanDefinitionReader |跳过[BeanMethod:name = accountDao,declaringClass = com.glassworks.mock.ScanExample $ OverrideConfig]的加载bean定义:bean“accountDao”的定义已经存在。这可能是由于XML中的覆盖。