使用Java Config自动装配setter [英] Autowire setter override with Java Config

查看:150
本文介绍了使用Java Config自动装配setter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下类:

public class MyBean {
    private A a;

    @Autowired(required=true)
    public void setA(A a) {
        this.a = a;
    }

    public A getA() {
        return a;
    }
}

有些情况需要覆盖自动装配注射,例如当Spring无法找到单个注射剂时。在XML中我可以有以下示例:

There are cases when one need need to override the autowired injection, for example when Spring cannot find a single candidate for the injection. In XML I can have the following example:

<?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而失败:

Is there a way to do the same thing with Java Config? The following doesn't work (and I understand why) because Spring try to autowire the property after returning from myBean method and it fails with 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配置的情况吗?

To modify the MyBean class isn't always an option, for example because it comes from an external library. Is this a case where I have to use XML configuration?

谢谢,
Andrea Polci

Thanks, Andrea Polci

更新
感谢两个解决方案如此票价(按名称注入,并使用@Primary),但它们无法解决我的用例,所以我需要更具体我认为。

Update Thanks for the two solution so fare (injection by name, and use of @Primary) but they don't solve my use case so I need to be more specific I think.

在我的用例中,MyBean类来自外部库,因此无法对其进行任何更改。我还需要有多个MyBean实例,每个实例注入A接口的不同内容。我已经更新了上面的代码来反映这个(xml和java)。

In my use case the MyBean class comes from an external library so any change to it is not possible. I also need to have more than one instance of MyBean, each one injecting different intances of the A interface. I've update the code above to reflect this (both xml and java).

有没有使用java配置的解决方案?是否有可能避免依赖MyBean的自动装配? (仅限于该类的bean,而不是完全禁用上下文中每个bean的自动装配)

Is there any solution using java config? Is it possible to avoid the autowire of the dependency on MyBean? (Only on the beans of that class, not disablig autowiring completely for every bean in the context)

推荐答案

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

Ok here it goes, I believe this answer will satisfy your needs.

我们需要的是 MergedBeanDefinitionPostProcessor 的实现,它将为属性 a 类 MyBean 。这可以通过以下类来完成

What we need is an implementation of MergedBeanDefinitionPostProcessor that will set the correct value for the property a of class MyBean. This can be done by the following class

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注释也将使用它

As you can see the names of the beans here are hardcoded but they could be set in static final String that would be also used by the @Bean annotations in the following code

@Configuration
public class Configuration {



    @Bean
    public MyBean myBeanFirst() {
        return new MyBean();
    }

    @Bean
    public MyBean myBeanSecond() {
        return new MyBean();
    }

}

您将在以下代码中注意到在MyBean创建方法中没有调用setA,因为当Spring执行bean后处理器时,无论我们设置什么值(或者在这种情况下都没有设置)都将被覆盖。

You will notice in the following code that setA is not called in the MyBean creation methods, because no matter what value we set (or in this case don't set) will be overridden when Spring executes the bean post processor.

如果您需要A的默认值(例如,如果您将其注入其他bean),请继续在先前的配置中定义@Bean

In case you need a default value for A (if for example you are injecting it in other beans), proceed to define a @Bean in the previous configuration

这篇关于使用Java Config自动装配setter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆