ユース ケース: クラスパス スキャン @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 情報 | 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 情報 | 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 {
}
注 ロギングが debug に設定されている場合、Spring は定義をスキップしていることを示していることに注意してください。これはバグのようです。
21:09 デバッグ | oscaConfigurationClassBeanDefinitionReader | [BeanMethod:name=accountDao,declaringClass=com.glassworks.mock.ScanExample$OverrideConfig] の Bean 定義の読み込みをスキップしています: Bean 'accountDao' の定義は既に存在します。これは、XML のオーバーライドが原因である可能性があります。