How to choose spring configuration in runtime based on a tenant?
grails, multi-tenant, spring
Solution
A couple of years ago we needed somthing like this but only for `DataSource`s and `ViewResolvers`. We developed a solution using spring' `TargetSource` solution. (Initially we used a `HotswappableTargetSource` but that wasn't adequate for our use-case.
The code we developed is availabe here in the multi-tenant directory.
It is fully configurable and flexible.
Basically what you do is you configura a `ContextSwappableTargetSource` and tell it what type of interface/class it needs to return.
<bean id="yourTentantBasedServiceId" class="biz.deinum.multitenant.aop.target.ContextSwappableTargetSource">
<constructor-arg value="ExchangeService" />
</bean>
The default is to lookup beans in the ApplicationContext based on the tenantId (see the `BeanFactoryTargetRegistry` for this). However you can specify one or more of those (we used a `JndiLookupTargetRegistry` to dynamically lookup datasource, which allowed use to add tenants on the fly without restarting the application).
If you explicitly configure a `BeanFactoryTargetRegistry` you can add a `prefix` and `suffix`.
<bean id="exchangeService" class="biz.deinum.multitenant.aop.target.ContextSwappableTargetSource">
<constructor-arg value="ExchangeService" />
<property name="targetRegistry>
<bean class="biz.deinum.multitenant.aop.target.registry.impl.BeanFactoryTargetRegistry">
<property suffix="ExchangeService"/>
</bean>
</property>
</bean>
Now for foo it would lookup a bean named `fooExchangeService` and for bar `barExchangeService`.
The tenantId is stored in a `ThreadLocal` which is wrapped inside the `ContextHolder`. You need to find a way to fill and clear this thread local (in general a servlet `Filter` does that trick.
In your code you can now simply use the interface `ExchangeService` and at runtime based on the `tenantId` the correct implemenation will be looked up.
Also see http://mdeinum.wordpress.com/2007/01/05/one-application-per-client-database/
Problem
I would like to be able to choose specific Spring (or Grails) context configuration based on the tenant that user belongs to in runtime. Let's say I use Spring Security and I retrieve tenantId during login. Imagine now I have a two tenants and they pay different commission. How to inject specific service into a controller without too much plumbing? Here are two different contexts. So, I should inject different ExchangeService based on tenant. ``` @Configuration public class FooTenant{ @Bean public ExchangeService bar() { return new ZeroCommisionExchangeService (); } } @Configuration public class BarTenant{ @Bean public ExchangeService bar() { return new StandardCommisionExchangeService (); } } ``` Edit: I am aware I can obtain reference to Spring context and ask for service "manually", but I am looking for a more generic solution where this problematic is solved by IoC framework.