【问题标题】:Spring DI (Beans) with multiple concretes…picking one of them具有多个混凝土的 Spring DI (Beans)……选择其中一个
【发布时间】: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()));
    }

  }
}

【问题讨论】:

    标签: dependency-injection spring-bean


    【解决方案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)............所以......我赞成。未来的读者。另见:stackoverflow.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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-09
      • 1970-01-01
      • 2017-08-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多