说我有一个服务接口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();