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.

Original source