2016-03-11 35 views
0

我正在Spring Spring中編寫服務,從Spring雲中獲取它們的配置。這些服務是多租戶,租戶基於主機名。根據主機名加載Bean

什麼我現在已經是

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記錄指向同一個(池)實例,並且有一個實例能夠處理針對不同客戶端的請求。我希望能夠根據每個請求換出配置文件。

這可能嗎?

+0

不要......創建一個代理'MyService'並根據租戶使用正確的。我們使用這種方法即時切換數據源。我在這裏發佈了博客(https://mdeinum.wordpress.com/2007/01/05/one-application-per-client-database/),代碼是[here](https://github.com)/mdeinum /彈簧utils的)。 (我正在努力將其發展到自己的項目中)。它提供的是在運行時切換任何bean的能力,您可以使用您需要的或者默認的bean。 –

+0

爲什麼不使用彈簧配置文件,每個主機一個彈出配置文件,然後在啓動時將主機名作爲配置文件名稱傳遞。 – cjstehno

回答

1

Spring配置文件在這裏沒有幫助,每個客戶端需要一個應用程序上下文,而這看起來不是你想要的。

相反,您可以使用scoped bean。 作用域「客戶」創建你的客戶依賴豆:類型爲MyService的

@Bean 
@Scope(value="client",proxyMode = ScopedProxyMode.INTERFACES) 
@Primary 
MyService myService(){ 
    //does not really matter, which instance you create here 
    //the scope will create the real instance 
    //may be you can even return null, did not try that. 
    return new MyServiceDummy(); 
} 

將有至少3豆:作用域之一,併爲每個客戶端。註釋@Primary告訴spring總是使用scoped 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; 
    }; 
} 

和你的客戶的具體豆可以這樣來配置:

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

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

沒有測試,但在我的項目中使用它。應該管用。

tutorial spring custom scope