问题描述
我在这里有类似的问题
,其中包含针对Guice的解决方案。
with a solution for Guice.
但是我有一个使用spring di(beans)的项目,但是有同样的问题。
But I have a different project using spring di (beans), but with the same kind of issue.
I具有N个混凝土的界面。 (此处为3)
I have an interface with N number of concretes. (3 here)
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");
}
}
...
然后我有一堂课,需要了解所有三种混凝土。
Then I have a class that needs to know about ALL THREE concretes.
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;
}
}
=========== ==
=============
基本上,我想调用该方法,传入一个字符串参数,然后让它为我选择具体的方法。 (如果是我的真实代码,这是通过数据库值实现的,但是对于演示代码来说,这已经足够了)
Basically, I want to call the method, pass in a string argument, and have it choose the concrete for me. (if my real code, this is via a database value, but for the demo code, this is good enough)
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:
My Spring Configuration is via 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种具体情况。
So I want to xml configure the 3 concretes.
然后将它们注入到类中。
And then inject them into the class.
但是在我有我该怎么办N个ShipperInterfaces吗??的地方,我不知道该怎么办。
But where I have "How do I do N Number of ShipperInterfaces Here ??", I have no idea what to do.
首选JSR 330实施,但是会花费很多。
JSR 330 implementation preferred, but will take anything.
谢谢
请注意,在另一个问题(Guice问题)中,这也可能OrderProcessor的构造函数:
Note, in the other question (the Guice one), this was also a possiblity for the constructor of the 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()));
}
}
}
推荐答案
类似的事情应该起作用。这使用@Autowired而不是xml配置:
Something like this should work. This uses @Autowired and not xml configuration:
@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));
}
等级依赖提示:
compile group: 'org.springframework', name: 'spring-context', version: '5.1.9.RELEASE'
这篇关于带有多种混凝土的Spring DI(Beans)...选择其中之一的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!