考虑以下类别:
public class MyBean {
private A a;
@Autowired(required=true)
public void setA(A a) {
this.a = a;
}
public A getA() {
return a;
}
}
在某些情况下,需要覆盖自动装配的注射,例如,当Spring无法找到单个注射候选物时。在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.xsd">
<bean id="first" class="my.pkg.AImpl"/>
<bean id="second" class="my.pkg.AImpl"/>
<bean id="myBeanFirst" class="my.pkg.MyBean">
<property name="a" ref="first"/>
</bean>
<bean id="myBeanSecond" class="my.pkg.MyBean">
<property name="a" ref="second"/>
</bean>
</beans>
有没有办法用Java Config做同样的事情?以下内容不起作用(我理解为什么),因为Spring尝试从myBean方法返回后尝试自动装配属性,并且失败并显示NoUniqueBeanDefinitionException:
@Configuration
public class MyConfig {
@Bean
public A first() {
return new AImpl();
}
@Bean
public A second() {
return new AImpl();
}
@Bean
public MyBean myBeanFirst(A first) {
MyBean myBean = new MyBean();
myBean.setA(first);
return myBean;
}
@Bean
public MyBean myBeanSecond(A second) {
MyBean myBean = new MyBean();
myBean.setA(first);
return myBean;
}
}
修改MyBean类并不总是一种选择,例如,因为它来自外部库。
这是我必须使用XML配置的情况吗?
谢谢,
安德里亚·波奇(Andrea Polci)
更新资料
感谢您提供的这两种解决方案(按名称注入和使用@Primary),但是它们不能解决我的用例,因此我认为我需要更具体。
在我的用例中,MyBean类来自外部库,因此无法对其进行任何更改。我还需要有一个以上的MyBean实例,每个实例都注入A接口的不同实例。我已经更新了上面的代码以反映这一点(xml和java)。
有使用java config的解决方案吗?是否可以避免依赖MyBean的依赖自动装配? (仅在该类的bean上,而不是为上下文中的每个bean完全禁止自动装配)
最佳答案
可以,我相信这个答案会满足您的需求。
我们需要的是MergedBeanDefinitionPostProcessor
的实现,它将为类a
的属性MyBean
设置正确的值。可以通过以下课程来完成
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.stereotype.Component;
@Component
public class MyBeanPostProcessor implements MergedBeanDefinitionPostProcessor {
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if(beanName.equals("myBeanFirst")) {
beanDefinition.getPropertyValues().add("a", getMyBeanFirstAImpl());
}
else if(beanName.equals("myBeanSecond")) {
beanDefinition.getPropertyValues().add("a", getMyBeanSecondAImpl());
}
}
private Object getMyBeanFirstAImpl() {
return new AImpl();
}
private Object getMyBeanSecondAImpl() {
return new AImpl();
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
如您所见,这里的bean名称是硬编码的,但是可以在静态最终String中设置它们,以下代码中的@Bean批注也将使用它们
@Configuration
public class Configuration {
@Bean
public MyBean myBeanFirst() {
return new MyBean();
}
@Bean
public MyBean myBeanSecond() {
return new MyBean();
}
}
您将在以下代码中注意到,在MyBean创建方法中未调用setA,因为无论我们设置的值(或本例中未设置)在Spring执行bean后处理器时都将被覆盖。
如果您需要A的默认值(例如,如果将其注入其他bean),请继续在先前的配置中定义一个@Bean
关于java - 使用Java Config覆盖 Autowiring 设定器,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22416140/