Spring 3中的Custom Autowire候选bean

Str*_*lok 10 java spring annotations dependency-injection

说我有一个服务接口下面的结构ServiceInterface和实现它几个部分组成:ProductAServiceProductBService我也有一个RequestContext是有说,我们说目前正在处理产品A产品B或一个合格资产豆.然后,如何将自动装配或其他注释自动注入正确的实现(ProductAService或ProductBService)到需要它的某个服务(ServiceThatNeedsServiceInterface如下).

public interface ServiceInterface {
  void someMethod();
}

@Component(name="ProductAService")
public class ProductAService implements ServiceInterface {
  @Override public void someMethod() { 
    System.out.println("Hello, A Service"); 
  }
}

@Component(name="ProductBService")
public class ProductBService implements ServiceInterface {
  @Override public void someMethod() { 
    System.out.println("Hello, B Service"); 
  }
}

@Component
public class ServiceThatNeedsServiceInterface {

  // What to do here???
  @Autowired
  ServiceInterface service;

  public void useService() {
    service.someMethod();
  }
}

@Component
@Scope( value = WebApplicationContext.SCOPE_REQUEST )
public class RequestContext {
  String getSomeQualifierProperty();
}
Run Code Online (Sandbox Code Playgroud)

Hai*_*man 11

Spring Source 在版本1.1.4中创建ServiceLocatorFactoryBean时引用了您的问题.要使用它,您需要添加类似下面的界面:

public interface ServiceLocator {
    //ServiceInterface service name is the one 
      //set by @Component
    public ServiceInterface lookup(String serviceName);
}
Run Code Online (Sandbox Code Playgroud)

您需要将以下代码段添加到applicationContext.xml中

<bean id="serviceLocatorFactoryBean"
    class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
    <property name="serviceLocatorInterface"
              value="org.haim.springframwork.stackoverflow.ServiceLocator" />
</bean>
Run Code Online (Sandbox Code Playgroud)

现在您的ServiceThatNeedsServiceInterface看起来类似于下面的那个:

@Component
public class ServiceThatNeedsServiceInterface {
    // What to do here???
    //  @Autowired
    //  ServiceInterface service;

    /*
     * ServiceLocator lookup returns the desired implementation
     * (ProductAService or ProductBService) 
     */ 
 @Autowired
     private ServiceLocator serviceLocatorFactoryBean;

     //Let’s assume we got this from the web request 
     public RequestContext context;

     public void useService() {
        ServiceInterface service =  
        serviceLocatorFactoryBean.lookup(context.getQualifier());
        service.someMethod();         
      }
}
Run Code Online (Sandbox Code Playgroud)

ServiceLocatorFactoryBean将根据RequestContext限定符返回所需的服务.除了spring注释,您的代码不依赖于Spring.我为上面的内容执行了以下单元测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:META-INF/spring/applicationContext.xml" })
public class ServiceThatNeedsServiceInterfaceTest {

    @Autowired
    ServiceThatNeedsServiceInterface serviceThatNeedsServiceInterface;

    @Test
    public void testUseService() {
    //As we are not running from a web container
    //so we set the context directly to the service 
        RequestContext context = new RequestContext();
        context.setQualifier("ProductAService");
        serviceThatNeedsServiceInterface.context = context;
        serviceThatNeedsServiceInterface.useService();

        context.setQualifier("ProductBService");
        serviceThatNeedsServiceInterface.context = context;
        serviceThatNeedsServiceInterface.useService();
    }

}
Run Code Online (Sandbox Code Playgroud)

控制台将显示
Hello,A Service
Hello,B Service

一句警告.API文档声明
"这样的服务定位器......通常用于原型bean,即用于为每次调用返回新实例的工厂方法...对于单例bean,直接setter或构造函数注入目标bean是可取的. "

我不明白为什么这可能会导致问题.在我的代码中,它在对serviceThatNeedsServiceInterface.useService()的两个序列调用中返回相同的服务;

您可以在GitHub中找到我的示例的源代码