使用Java Config自动装配setter

时间:2014-03-14 21:34:36

标签: java spring spring-java-config

考虑以下课程:

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配置的解决方案?是否有可能避免依赖MyBean的自动装配? (仅限于该类的bean,而不是完全禁用上下文中每个bean的自动装配)

3 个答案:

答案 0 :(得分:3)

如果您有多个注射候选者,您可以通过在要成为默认AImpl的bean上使用@Primary来指定默认值。这样就不需要对MyBean进行任何更改

答案 1 :(得分:3)

好的,我相信这个答案将满足您的需求。

我们需要的是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名称是硬编码的,但它们可以在静态的最终字符串中设置,以下代码中的@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

答案 2 :(得分:0)

如果您想首先使用myBeanFirst,那么只需调用first()即可。同样适用于myBeanSecond,希望它使用秒,然后在设置A时调用second();

@Configuration
public class MyConfig {
    @Bean
    public A first() {
        return new AImpl();
    }

    @Bean
    public A second() {
        return new AImpl();
    }

    @Bean
    public MyBean myBeanFirst() {
        MyBean myBean = new MyBean();
        myBean.setA(first());
        return myBean;
    }

    @Bean
    public MyBean myBeanSecond() {
        MyBean myBean = new MyBean();
        myBean.setA(second());
        return myBean;
    }
}