说我有一个服务接口ServiceInterface和一些实现它的组件的以下结构:ProductAService和ProductBService我还有一个RequestContext bean,它有一个限定属性,表示我们现在正在处理ProductA或ProductB.那么如何可以自动注入自动装配或其他注释正确的实现(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(); }
解决方法
Spring Source在版本1.1.4中创建了
ServiceLocatorFactoryBean时引用了您的问题.为了使用它,您需要添加类似于下面的界面:
public interface ServiceLocator { //ServiceInterface service name is the one //set by @Component public ServiceInterface lookup(String serviceName); }
您需要将以下代码片段添加到您的applicationContext.xml中
<bean id="serviceLocatorfactorybean" class="org.springframework.beans.factory.config.ServiceLocatorfactorybean"> <property name="serviceLocatorInterface" value="org.haim.springframwork.stackoverflow.ServiceLocator" /> </bean>
现在您的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(); } }
ServiceLocatorfactorybean将根据RequestContext限定符返回所需的服务.
除了弹簧注释,你的代码不依赖于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(); } }
显示控制台
你好,一个服务
你好,B服务
一句警告. API文档说明
“这样的服务定位器…通常将用于原型bean,即对于每个调用返回一个新实例的工厂方法,对于单例bean,最好是直接设置器或构造器注入目标bean.
我不明白为什么会导致一个问题.在我的代码中,它返回相同的服务在两个序列调用serviceThatNeedsServiceInterface.useService();