spring 能弹@AutowiredMap吗?

u0njafvf  于 2022-11-21  发布在  Spring
关注(0)|答案(8)|浏览(127)

这是Map

@Autowired
private Map<String, ISendableConverter> converters;

ISendableConverter

public interface ISendableConverter {

    ISendableMsg convert(BaseMessage baseMessage);

    String getType();
}

有一些类实现ISendableConverter
我想使用spring@Autowried注解将它们注入变量converters
类的示例作为值,方法getType()的结果作为键。
就像这个

@Component
public class SendableVoiceMsgConverter implements ISendableConverter {

    @Override
    public ISendableMsg convert(BaseMessage baseMessage) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getType() {
        return "VOICE";
    }
}

这可能吗?怎么可能?

qybjjes1

qybjjes11#

您可以使用SpringJava配置创建一个自动初始化的Map,其中包含您选择的键:
在使用@Configuration注解注解的类中:

@Autowired
private List<ISendableConverter> sendableConverters;

@Bean
public Map<String, ISendableConverter> sendableConvertersMap() {
    Map<String, ISendableConverter> sendableConvertersMap = new HashMap<>();
    for (ISendableConverter converter : sendableConverters) {
        sendableConvertersMap.put(converter.getType(), converter);
    }
    return sendableConvertersMap;
}

然后在Map中注入:

@Resource()
private Map<String, ISendableConverter> sendableConverters;

如果您定义了多个相同类型的Map,则可以选择将一些选择器字符串添加到@Resource注解中。
这样,您只需通过spring bean实现ISendableConverter,它就会自动出现在上面定义的Map中,而不需要为每个实现手动创建Map项。

lfapxunr

lfapxunr2#

尝试使用类似于@Resource的内容-我还没有测试过这段代码。

@Resource(name="converters")
private Map<String, ISendableConverter> converters;

@Value("#{converters}")
private Map<String, ISendableConverter> converters;

从Spring文档
(..)无法通过@Autowired注入本身定义为集合或Map类型的Bean,因为类型匹配不适用于它们。请对此类Bean使用@Resource,通过唯一名称引用特定的集合或MapBean。
只有在准备converters bean时,这才能正常工作:

<util:map id="converters" scope="prototype" map-class="java.util.HashMap" 
          key-type="java.lang.String" value-type="...ISendableConverter">
    <entry key="VOICE" value="sendableVoiceMsgConverter" />
</util:map>

这也是类似的问题:

9bfwbjaz

9bfwbjaz3#

您可以执行以下操作:

@SuppressWarnings("unused")
private List<OneTypeImageLoader> imageLoaders;
private Map<String, OneTypeImageLoader> imageLoaderMap=new HashMap<>();

@Autowired
public void setImageLoaders(List<OneTypeImageLoader> imageLoaders) {
    this.imageLoaders = imageLoaders;
    imageLoaders.forEach(l-> {
        imageLoaderMap.put(l.getType(), l);
    });
}
uelo1irk

uelo1irk4#

试试这样的东西,它对我很有效

private Map<String, ISendableConverter> converters;

@Autowired
public void setUploadServices(Set<ISendableConverter> converters){
    this.conveters = converters.stream()
        .collect(Collectors.toMap(ISendableConverter::getType, Function.identity()));
}

使用构造函数注入可以实现相同的结果:

private Map<String, ISendableConverter> converters;

@Autowired
public Foo(Set<ISendableConverter> converters) {
    this.conveters = converters.stream()
        .collect(Collectors.toMap(ISendableConverter::getType, Function.identity()));
}
ss2ws0br

ss2ws0br5#

@Component("VOICE")
public class SendableVoiceMsgConverter implements ISendableConverter {

    @Override
    public ISendableMsg convert(BaseMessage baseMessage) {
        // TODO Auto-generated method stub
        return null;
    }
}

您可能只想将类型名称直接添加到组件注解中,这样就可以完成任务。

w6mmgewl

w6mmgewl6#

首先,将Bean名称设置为getType()的返回值

@Component("VOICE")
public class SendableVoiceMsgConverter implements ISendableConverter {

    @Override
    public ISendableMsg convert(BaseMessage baseMessage) {
        // TODO Auto-generated method stub
        return null;
    }
}

你可以这样使用:

@Autowired
private Map<String, ISendableConverter> converters;

该MapV类型是Bean的示例,K类型是Bean的名称

nkoocmlb

nkoocmlb7#

这可以通过spring-componentmaphttps://github.com/krud-dev/spring-componentmap)来实现
根据您的示例:

public interface ISendableConverter {

    ISendableMsg convert(BaseMessage baseMessage);

    @ComponentMapKey
    String getType();
}

@Component
public class SendableVoiceMsgConverter implements ISendableConverter {

    @Override
    public ISendableMsg convert(BaseMessage baseMessage) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public String getType() {
        return "VOICE";
    }
}

// Call the converter by type
@Component
class SendableMsgConverter {

    // @ComponentMap replaces @Autowired in this case
    @ComponentMap
    private Map<String, ISendableConverter> converterMap;

    public ISendableMsg convert(BaseMessage baseMessage) {
        ISendableConverter converter = converterMap.get(baseMessage.getType());
        return converter.convert(baseMessage);
    }
}

免责声明:我与他人共同开发了spring-componentmap

8qgya5xd

8qgya5xd8#

您可以使其更通用,并构建如下所示的内容:

public interface BasicStrategy {
        String getKey();
    }

    public final class StrategyMap<K extends BasicStrategy> extends HashMap<String, K> {

    public StrategyMap(List<K> strategies) {
        super(strategies.stream().collect(Collectors.toMap(K::getKey, Function.identity())));
    }

    @Override
    public K get(Object key) {
        BasicStrategy basicStrategy = super.get(key);
        if (basicStrategy == null) {
            throw new RuntimeException("No strategy found for key: '" + key + "'");
        }
        return (K) basicStrategy;
    }
}

现在,您可以在代码中的任何地方使用StrategyMap,如下所示:

private StrategyMap<ISendableConverter> converters;

@Autowired
public Foo(List<ISendableConverter> converters) {
    this.conveters = new StrategyMap<>(converters);
}

这种方法一般化了StrategyMap的创建,并且还可以集中化未找到值的情况下的逻辑。
PS:当然ISendableConverter必须扩展BasicStrategy接口。

相关问题