下面的示例显示了使用spring java config显式地进行依赖关系的连接,这导致在对spring配置类使用and接口时,连接了另一个bean。
似乎不应该发生这种情况,或者至少发出正常警告,即有两个bean作为自动装配的候选对象,并且它不知道选择哪个。
对这个问题有什么想法吗?我的猜测是语法“ this.iConfig.a()”所隐含的配置类之间没有真实名称间隔吗?是否可以将其视为错误(如果仅是为了不警告有关两个候选bean的话)?
public class Main
{
public static void main( final String[] args )
{
final ApplicationContext context = new AnnotationConfigApplicationContext( IConfigImpl.class, ServiceConfig.class );
final Test test = context.getBean( Test.class );
System.out.println( test );
}
}
public class Test
{
private final String string;
public Test( final String param )
{
this.string = param;
}
public String toString()
{
return this.string;
}
}
@Configuration
public interface IConfig
{
@Bean
public String a();
}
@Configuration
public class IConfigImpl implements IConfig
{
@Bean
public String a()
{
return "GOOD String";
}
}
@Configuration
public class ServiceConfig
{
@Autowired
IConfig iConfig;
@Bean
Test test()
{
return new Test( this.iConfig.a() );
}
@Bean
String a()
{
return "BAD String";
}
}
在这种情况下,我希望“ GOOD String”始终连接在Test对象中,但是在上下文加载器中翻转IConfigImpl.class和ServiceConfig.class的顺序会更改加载的字符串。
在Spring 4.0.7中测试
编辑:进一步的测试表明,这与固有配置无关。如果删除IConfig接口,也会产生相同的结果。
最佳答案
Stepan提到了订单问题。以下是关于your comment的答案
覆盖同名的bean是有意义的,但是在这种情况下,
专门引用iConfig
中指定的bean
组态。我希望在那里指定一个。
为了实现@Configuration
和bean的缓存,这样的调用就像
@Configuration
class Example {
@Bean
public UncaughtExceptionHandler uncaughtExceptionHandler() {
return (thread, throwable) -> System.out.println(thread + " => " + throwable.getMessage());
}
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Thread newThread() {
Thread thread = new Thread();
thread.setUncaughtExceptionHandler(uncaughtExceptionHandler()); // <<<<<< allowing this
return thread;
}
}
Spring实际上使用CGLIB来创建
@Configuration
带注释类的代理子类型。该代理维护对支持ApplicationContext
的引用,并使用该引用来解析bean。因此,您的示例中的调用
return new Test(this.iConfig.a());
并不是真正地调用
IConfigImpl#a()
。它从代理侦听器调用this code(从4.2开始)。该代码使用相应的Method
确定目标bean名称,并使用ApplicationContext
的BeanFactory
解析bean。由于名为a
的bean的bean定义已被覆盖,因此将使用新的bean定义。该bean定义使用ServiceConfig#a()
方法作为其工厂方法。在文档here中对此进行了描述。
所有
@Configuration
类在启动时都使用CGLIB进行了子类化。在子类中,子方法首先检查容器中是否存在任何
在调用父方法并创建一个
新实例。
可以将其视为错误[...]吗?
我不相信该行为已记录。