【问题标题】:Spring unnecessarily modifying Bean on ReturnSpring 在返回时不必要地修改 Bean
【发布时间】:2016-11-21 07:57:46
【问题描述】:

我在 Spring 中遇到了非常奇怪的行为。我有一个@Bean,它返回一个地图。但是,当 Bean 为 @Autowired 时,映射的键与 @Bean 方法中分配的键不同。我的@Bean 有两个输入参数,它们也是来自另一个配置类的 Spring Bean。一旦@Autowired 我的地图的键被更改以匹配作为依赖项传入的@Bean 方法的名称,我的地图返回Bean。 @Beanin 问题位于 @ConfigurationProperties 类中,我从 application.yml 文件中提取一些值,这些值都正确返回。

@Component
@ConfigurationProperties(prefix = "channel-broker")
@EnableConfigurationProperties
public class ChannelLookupConfig {

    private String messageDeliveryChannelKey;

    private String otherDeliveryChannelKey;


    public String getMessageDeliveryChannelKey() {
        return messageDeliveryChannelKey;
    }

    public void setMessageDeliveryChannelKey(String messageDeliveryChannelKey) {
        this.messageDeliveryChannelKey = messageDeliveryChannelKey;
    }

    public String getOtherDeliveryChannelKey() {
        return otherDeliveryChannelKey;
    }

    public void setOtherDeliveryChannelKey(String OtherDeliveryChannelKey) {
        this.otherDeliveryChannelKey = OtherDeliveryChannelKey;
    }

    @Bean
    public Map<String, MessageDeliveryClient> channelCallerLookup(MessageDeliveryClient MessageDispatcherClient, MessageDeliveryClient otherDeliveryClient) {
        Map<String, MessageDeliveryClient> channelCallerLookup = new HashMap<>();
        channelCallerLookup.put(messageDeliveryChannelKey, MessageDispatcherClient);
        channelCallerLookup.put(otherDeliveryChannelKey, otherDeliveryClient);
        return channelCallerLookup;
    }
}

我的第二个配置文件

@Configuration
public class Config {
    @Bean
    public MessageDeliveryClient MessageDispatcherClient() {
        MessageDeliveryClient client = MessageDeliveryClient.builder()
                .awsAccessKey(destinationSqsAccessKey)
                .awsSecretKey(destinationSqsSecretKey)
                .awsRegion(destinationSqsRegion)
                .destinationQueueName(destinationSqsName)
                .build();
        return client;
    }

    @Bean
    public MessageDeliveryClient otherPickerDeliveryClient() {
        MessageDeliveryClient client = MessageDeliveryClient.builder()
                .awsAccessKey(destinationSqsAccessKey)
                .awsSecretKey(destinationSqsSecretKey)
                .awsRegion(destinationSqsRegion)
                .destinationQueueName(destinationOtherPickerSqsName)
                .build();
        return client;
    }
}

自动连线以供使用:

public class SimpleCustomerMessageDeliveryBrokerImpl implements CustomerMessageDeliveryBroker {
        private Map<String, MessageDeliveryClient> channelCallerLookup = new HashMap<>();

        @Autowired
        public void setBrokerConfiguration(BrokerConfiguration brokerConfiguration) {
            this.brokerConfiguration = brokerConfiguration;
        }
    }

地图应包含 2 个元素,第一个元素的键等于字符串 messageDeliveryChannelKey 中的值,第二个元素的键等于字符串 otherDeliveryChannelKey 中的值。但是,键总是设置为等于传递到我的分数中的 @Beans 方法的名称。即使我将方法名称更改为无意义的,地图的键也将等于该值。

如何防止这种行为发生

【问题讨论】:

  • A Map&lt;String, MessageDeliveryClient&gt; 由 Spring 解释,因为您希望将所有类型的 bean 注入到该映射中。关键是 bean 的名称。因此,当使用 Map&lt;String, MessageDeliveryClient&gt; 时,这就是您所得到的。这是默认行为,无法关闭。
  • 但是您可以做的是使用 SimpleCustomerMessageDeliveryBrokerImpl 类中的 @Value 注释读取这些参数。
  • @FedericoJoséSorenson 是的,这就是我以前真正拥有的。但我试图从那个类中提取它,只给它 Map 以便地图基本上可以根据需要增长,并且每次添加新东西时都不必更改类。
  • @M.Deinum 感谢您的帮助这真的很不幸,我没有看到 Spring 做这样的事情的好处。
  • @M.Deinum 实际上它有点酷,我只是认为它应该允许开发人员覆盖它

标签: java spring spring-boot


【解决方案1】:

这是由于默认的 Spring 行为而发生的。为了解决这个问题,我在返回 Map 周围应用了一个 Wrapper。

把我的 Bean 改成了这个

@Bean
public ChannelCallerLookup channelCallerLookup(MessageDeliveryClient messageDispatcherClient, MessageDeliveryClient otherPickerDeliveryClient) {
    HashMap<String, MessageDeliveryClient> channelCallerLookup = new HashMap<>();
    channelCallerLookup.put(CHANNEL1_KEY, messageDispatcherClient);
    channelCallerLookup.put(CHANNEL1_KEY2, otherPickerDeliveryClient);
    ChannelCallerLookup callerLookup = new ChannelCallerLookup(channelCallerLookup);
    return callerLookup;
}

创建了这个包装类

public class ChannelCallerLookup {

    Map<String, MessageDeliveryClient> lookupMap;

    public ChannelCallerLookup(Map<String, MessageDeliveryClient> lookupMap) {
        this.lookupMap = lookupMap;
    }

    public Map<String, MessageDeliveryClient> getLookupMap() {
        return lookupMap;
    }

    public MessageDeliveryClient get(String key){
        return lookupMap.get(key);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    • 2014-12-29
    • 2016-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多