具有多个混凝土的 Spring DI (Beans)……选择其中一个
Posted
技术标签:
【中文标题】具有多个混凝土的 Spring DI (Beans)……选择其中一个【英文标题】:Spring DI (Beans) with multiple concretes…picking one of them 【发布时间】:2022-01-24 06:36:01 【问题描述】:我也有类似的问题
Guice with multiple concretes......picking one of them
为 Guice 提供解决方案。
但我有一个使用 spring di (bean) 的不同项目,但有同样的问题。
我有一个包含 N 个混凝土的接口。 (这里有 3 个)
public interface OrderProcessorInterface
void ProcessOrder(String preferredShipperAbbreviation, Order ord);
public class FedExShipper implements ShipperInterface
private Log logger;
public FedExShipper(Log lgr)
if (null == lgr)
throw new IllegalArgumentException("Log is null");
this.logger = lgr;
public void ShipOrder(Order ord)
this.logger.info("I'm shipping the Order with FexEx");
public class UpsShipper implements ShipperInterface
private Log logger;
public UpsShipper(Log lgr)
if (null == lgr)
throw new IllegalArgumentException("Log is null");
this.logger = lgr;
public void ShipOrder(Order ord)
this.logger.info("I'm shipping the Order with Ups");
public class UspsShipper implements ShipperInterface
private Log logger;
public UspsShipper(Log lgr)
if (null == lgr)
throw new IllegalArgumentException("Log is null");
this.logger = lgr;
public void ShipOrder(Order ord)
this.logger.info("I'm shipping the Order with Usps");
........
然后我有一个需要了解所有三个混凝土的课程。
import java.util.Collection;
import java.util.Set;
import org.apache.commons.logging.Log;
public class OrderProcessorImpl implements OrderProcessorInterface
private Log logger;
private java.util.Map<String, javax.inject.Provider<ShipperInterface>> shipperProviderMap;
public OrderProcessorImpl(Log lgr, java.util.Map<String, javax.inject.Provider<ShipperInterface>> spMap)
if (null == lgr)
throw new IllegalArgumentException("Log is null");
if (null == spMap)
throw new IllegalArgumentException("Provider<ShipperInterface> is null");
this.logger = lgr;
this.shipperProviderMap = spMap;
public void ProcessOrder(String preferredShipperAbbreviation, Order ord)
this.logger.info(String.format("About to ship. (%1s)", preferredShipperAbbreviation));
ShipperInterface foundShipperInterface = this.FindShipperInterface(preferredShipperAbbreviation);
foundShipperInterface.ShipOrder(ord);
private ShipperInterface FindShipperInterface(String preferredShipperAbbreviation)
ShipperInterface foundShipperInterface = this.shipperProviderMap.get(preferredShipperAbbreviation).get();
if (null == foundShipperInterface)
throw new NullPointerException(
String.format("ShipperInterface not found in shipperProviderMap. ('%1s')", preferredShipperAbbreviation));
return foundShipperInterface;
=============
基本上,我想调用该方法,传入一个字符串参数,然后让它为我选择具体的。 (如果我的真实代码,这是通过数据库值,但对于演示代码,这已经足够了)
Order ord = new Order();
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
BeanFactory factory = context;
OrderProcessorInterface opi = context.getBean(OrderProcessorImpl.class);
opi.ProcessOrder("myFedExName", ord); /* friendlyName would be nice, but fully qualified concrete name also assceptable */
我的 Spring 配置是通过 xml:
<bean id="theLoggerBean"
class="org.apache.commons.logging.impl.Log4JLogger">
<constructor-arg value="log" />
</bean>
<bean id="fedExBean"
class="com.me.FedExShipper">
<constructor-arg ref="theLoggerBean"></constructor-arg>
</bean>
<bean id="uspsExBean"
class="com.me.FedExShipper">
<constructor-arg ref="theLoggerBean"></constructor-arg>
</bean>
<bean id="upsExBean"
class="com.me.FedExShipper">
<constructor-arg ref="theLoggerBean"></constructor-arg>
</bean>
.......
=================================
<bean id="OrderProcessorImplBean"
class="com.me.OrderProcessorImpl">
<constructor-arg ref="theLoggerBean"></constructor-arg>
<constructor-arg ref="How do I do N Number of ShipperInterfaces Here ??"></constructor-arg>
</bean>
所以我想用 xml 配置这 3 个混凝土。
然后将它们注入到类中。
但是我有“我如何在这里做 N 个 ShipperInterfaces ??”,我不知道该怎么做。
首选 JSR 330 实现,但可以采取任何措施。
谢谢
注意,在另一个问题(Guice 问题)中,这也是 OrderProcessor 的构造函数的一种可能性:
public class OrderProcessorImpl implements OrderProcessorInterface
private Log logger;
Set<ShipperInterface> shippers;
public OrderProcessorImpl(Log lgr, Set<ShipperInterface> shprs)
if (null == lgr)
throw new IllegalArgumentException("Log is null");
if (null == shprs)
throw new IllegalArgumentException("ShipperInterface(s) is null");
this.logger = lgr;
this.shippers = shprs;
public void ProcessOrder(String preferredShipperAbbreviation, Order ord)
this.logger.info(String.format("About to ship. (%1s)", preferredShipperAbbreviation));
for (ShipperInterface sh : shippers)
this.logger.info(String.format("ShipperInterface . (%1s)", sh.getClass().getSimpleName()));
【问题讨论】:
【参考方案1】:这样的事情应该可以工作。这使用 @Autowired 而不是 xml 配置:
@org.springframework.stereotype.Service
public class OrderProcessorImpl implements OrderProcessorInterface
private List<ShipperInterface> shipperProviders;
private Map<String, ShipperInterface> shipperProvidersMap = new HashMap<>();
@Autowired
public void setShipperProviders(List<ShipperInterface> shipperProviders)
this.shipperProviders= shipperProviders;
this.shipperProviders.stream().forEach(p->shipperProvidersMap .put(/* your code for getting the key */, p));
Gradle 依赖提示:
compile group: 'org.springframework', name: 'spring-context', version: '5.1.9.RELEASE'
【讨论】:
感谢您的尝试。但这是(1)基于setter,而不是基于构造(2)(at)Autowire((at)Annotation)基于而不是基于xml。所以我还在寻找答案。谢谢。 这实际上帮助了我解决我面临的另一个问题......(不是xml)............所以......我赞成。未来的读者。另见:***.com/questions/17629761/…【参考方案2】:我认为我有一些可行的方法:
beans.xml(注意命名空间中声明的“util”额外内容)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.5.xsd">
<bean id="theLoggerBean"
class="org.apache.commons.logging.impl.Log4JLogger">
<constructor-arg value="log" />
</bean>
<bean id="fedExShipperBean"
class="com.me.shipping.FedExShipper">
<constructor-arg ref="theLoggerBean"></constructor-arg>
</bean>
<bean id="upsShipperBean"
class="com.me.shipping.UpsShipper">
<constructor-arg ref="theLoggerBean"></constructor-arg>
</bean>
<bean id="uspsShipperBean"
class="com.me.shipping.UspsShipper">
<constructor-arg ref="theLoggerBean"></constructor-arg>
</bean>
<util:map id="shipperInterfaceMap" key-type="java.lang.String"
value-type="com.me.shipping.interfaces.ShipperInterface">
<entry key="fedexFriendlyName" value-ref="fedExShipperBean" />
<entry key="upsFriendlyName" value-ref="upsShipperBean" />
<entry key="uspsFriendlyName" value-ref="uspsShipperBean" />
</util:map>
<bean id="orderProcessorImplBean"
class="com.me.shipping.OrderProcessorImpl">
<constructor-arg ref="theLoggerBean"></constructor-arg>
<constructor-arg ref="shipperInterfaceMap"></constructor-arg>
</bean>
</beans>
和java
package com.me.shipping;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import com.me.shipping.interfaces.OrderProcessorInterface;
import com.me.shipping.interfaces.ShipperInterface;
import com.me.Models.Order;
public class OrderProcessorImpl implements OrderProcessorInterface
private Log logger;
private java.util.Map<String, ShipperInterface> shipperInterfaceMap;
public OrderProcessorImpl(Log lgr, java.util.Map<String, ShipperInterface> siMap)
if (null == lgr)
throw new IllegalArgumentException("Log is null");
if (null == siMap)
throw new IllegalArgumentException("Map<String, ShipperInterface> is null");
this.logger = lgr;
this.shipperInterfaceMap = siMap;
public void ProcessOrder(String preferredShipperAbbreviation, Order ord)
this.logger.info(String.format("About to ship. (%1s)", preferredShipperAbbreviation));
ShipperInterface foundShipperInterface = this.FindShipperInterface(preferredShipperAbbreviation);
foundShipperInterface.ShipOrder(ord);
private ShipperInterface FindShipperInterface(String friendlyName)
ShipperInterface returnItem = null;
if (null != this.shipperInterfaceMap)
returnItem = this.shipperInterfaceMap.entrySet().stream()
.filter(e -> e.getKey().equalsIgnoreCase(friendlyName))
.map(Map.Entry::getValue)
.findFirst()
.orElse(null);
if (null == returnItem)
throw new NullPointerException(String.format("shipperProviderMap did not contain expected item. (Key='%s')", friendlyName));
return returnItem;
和“主要”方法
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
BeanFactory factory = context;
Order ord = new Order();
OrderProcessorInterface opi = context.getBean(OrderProcessorImpl.class);
opi.ProcessOrder("fedexFriendlyName", ord);
【讨论】:
以上是关于具有多个混凝土的 Spring DI (Beans)……选择其中一个的主要内容,如果未能解决你的问题,请参考以下文章