根据主机名加载Bean

时间:2016-03-11 12:12:25

标签: java spring spring-cloud

我正在Spring启动服务,从Spring云中获取配置。这些服务是多租户,租户基于主机名。

我现在拥有的是

public class MyController {
    @Autowired
    public MyController(MyServiceFactory factory) {
        ...
    }

    @RequestMapping("some/path/{id}")
    ResponseEntity<SomeEntity> getSomeEntity(@RequestHeader header, @PathVariable id) {
        return factory.getMyService(header).handle(id);
    }
}

MyServiceFactory看起来像......

public class MyServiceFactory {
    private final HashMap<String, MyService> serviceRegistry = new HashMap<>();
    public MyService getMyService(String key) {
        return serviceRegistry.get(key);
    }

    MyServiceFactory withService(String key, MyService service) {
        this.serviceRegistry.put(key, service);
        return this;
    }

}

然后在配置文件中

@Configuration
public ServiceFactoryConfiguration {

    @Bean
    public MyServiceFactory getMyServiceFactory() {
        return new MyServiceFactory()
            .withService("client1", new MyService1())
            .withService("client2", new MyService2());
    }
}

虽然我现在的工作原理,我不喜欢我需要为我的控制器可能拥有的每个依赖项创建一个工厂。我想让我的代码看起来像这样...

public class MyController {
    @Autowired
    public MyController(MyService service) {
    ...
    }

    @RequestMapping("some/path/{id}")
    ResponseEntity<SomeEntity> getSomeEntity(@PathVariable id) {
        return service.handle(id);
    }
}

使用类似

的配置文件
@Configuration
public class MyServiceConfiguration() {

    @Bean
    @Qualifier("Client1")
    public MyService getMyService1() {
        return new MyService1();
    }

    @Bean
    @Qualifier("Client2")
    public MyService getMyService2() {
        return new MyService2();
    }
}

如果我在应用程序启动时使用配置文件,我可以获取我想要编写的代码。但我希望有许多不同的DNS记录指向同一个(池)实例,并且有一个实例能够处理不同客户端的请求。我希望能够根据每个请求交换配置文件。

这可能吗?

1 个答案:

答案 0 :(得分:1)

Spring配置文件在这里没有帮助,每个客户端需要一个应用程序上下文,这似乎不是你想要的。

相反,你可以使用scoped bean。 使用范围“client”创建客户端相关bean:

public class ClientScope implements Scope {
   @Autowired
   BeanFactory beanFactory;

   Object get(String name, ObjectFactory<?> objectFactory){
       //we do not use the objectFactory here, instead the beanFactory           
       //you somehow have to know which client is the current
       //from the config, current request, session,  or ThreadLocal..
       String client=findCurrentClient(..);
       //client now is something like 'Client1'

      //check if your cache (HashMap) contains an instance with
      //BeanName = name for the client, if true, return that
       ..  
      //if not, create a new instance of the bean with the given name 
      //for the current client. Easiest way using a naming convention 
        String clientBeanName=client+'.'+name;
        Object clientBean=BeanFactory.getBean(clientBeanName);
      //put in cache ...
        return clientBean;  
   };
}

将至少有3个MyService类型的bean:作用域,每个客户端一个。注释@Primary告诉spring总是使用scoped bean进行注入。

创建范围:

@Bean('Client1.myService')
public MyService getMyService1() {
    return new MyService1();
}

@Bean('Client2.myService')
public MyService getMyService2() {
    return new MyService2();
}

您的客户特定bean配置如下:

success: function(response) {
   var resp = JSON.parse(response);
   alert(resp.text); // Login success or Fail
}

没有测试它,但在我的项目中使用它。应该工作。

tutorial spring custom scope