如何在运行时选择Spring bean实例

时间:2013-07-17 14:07:51

标签: java spring

基于传递给方法的参数,我需要从许多Spring bean中选择一个,这些Spring bean是同一个类的实现,但配置了不同的参数。

E.g。如果用户A调用该方法,我需要在bean A上调用dooFoo(),但如果它是用户B,那么我需要调用相同的方法,仅在bean B上调用。

除了将所有bean都粘贴在地图中,并从传递给我方法的参数中获取一个键之外,还有一种“更加弹性”的方法吗?

4 个答案:

答案 0 :(得分:10)

我们在项目中遇到了这个问题,我们通过Factory-Like类来解决它。客户端类 - 在运行时需要bean的客户端类 - 有一个工厂实例,它是通过Spring注入的:

@Component
public class ImTheClient{

    @Autowired
    private ImTheFactory factory;

    public void doSomething(
            Parameters parameters) throws Exception{        
        IWantThis theInstance = factory.getInstance(parameters);        

    }

}

因此,IWantThis实例取决于parameters参数的运行时值。 Factory实现如下:

@Component
public class ImTheFactoryImpl implements
        ImTheFactory {

    @Autowired
    private IWantThisBadly anInstance;
    @Autowired
    private IAlsoWantThis anotherInstance;

    @Override
    public IWantThis getInstance(Parameters parameters) {
        if (parameters.equals(Parameters.THIS)) {
            return anInstance;
        }

        if (parameters.equals(Parameters.THAT)) {
            return anotherInstance;
        }

        return null;
    }
}

因此,工厂实例保留对IWantThis类的两个有效值的引用,IWantThisBadlyIAlsoWantThis两个IWantThis的实现。

答案 1 :(得分:2)

将它们粘贴在地图中听起来不错。如果它是一个Spring管理的地图(使用util:map,或者在Java配置中),那比在其他地方创建它更好,因为Spring拥有所有对象引用并且可以正确地管理它们的生命周期。

答案 2 :(得分:2)

好像你想要一个ServiceLocator使用应用程序上下文作为注册表。

请参阅ServiceLocatorFactoryBean支持类,创建ServiceLocators,将键映射到bean名称,而不将客户端代码耦合到Spring。

其他选项是使用命名约定或基于注释的配置。

例如,假设您使用@ExampleAnnotation("someId")注释服务,您可以使用类似以下服务定位器的内容来检索它们。

public class AnnotationServiceLocator implements ServiceLocator {

    @Autowired
    private ApplicationContext context;
    private Map<String, Service> services;

    public Service getService(String id) {
        checkServices();
        return services.get(id);
    }

    private void checkServices() {
        if (services == null) {
            services = new HashMap<String, Service>();
            Map<String, Object> beans = context.getBeansWithAnnotation(ExampleAnnotation.class);
            for (Object bean : beans.values()) {
                ExampleAnnotation ann = bean.getClass().getAnnotation(ExampleAnnotation.class);
                services.put(ann.value(), (Service) bean);
            }
        }
    }   
}

答案 3 :(得分:-1)

如果您正在谈论的bean(A,B)是SessionScope,那么它们就没有问题,它们将被正确选择。

public class BusinessLogic {

  private BaseClassOfBeanAandB bean;

  public void methodCalledByUserAorB() {
    bean.doFoo();
  }

}