JCN
JCN

Reputation: 539

Can profiles be dynamically swapped during runtime?

I am modernizing a legacy web application. One of the difficult things about this app is the configuration model. Currently, each customer has a separate instance of the app, with separate config properties per instance. The properties are currently stored in Tomcat's context.xml, and there is a JNDI helper to extract those properties at startup. Since one Tomcat instance = one context.xml, this works. But now we want one instance (or cluster of instances) for all customers.

I think normally this would be done in the session. But in this case, that would be a large refactor. The config values are kept in a pojo with static setters and getters, which are called copiously throughout the codebase. The JNDI helper sets config on the pojo at startup, and that is how the app finds its config values.

We are taking baby steps while developing to improve this model, rather than do a big refactor. So the goal is to change as little as possible while moving in a good direction. One of the things I was considering was using Spring-Boot profiles. Instead of a separate instance per customer, there could be a spring-boot profile per customer. Then, upon each HTTP request, a servlet filter could activate the appropriate profile by observing who the user is, and activating their profile for the duration of the request, which I hope would then be able to inject values into the static setters from the filter.

I know this is abnormal, but I'm trying to think outside of the box.

I know about ConfigurableEnvironment.setActiveProfiles. What I'm not certain about is whether or not this will actively inject property value changes after the bootstrapping phase, and also whether or not this is likely to cause performance issues or for any other reason sounds crazy.

Upvotes: 0

Views: 165

Answers (2)

This is nothing to do with spring profiles ! You can manipulate them programmatically, but at one moment you have one spring context in your JVM (application). You want to operate with user specific properties, won't you ? This is a per request, or rather a per session scope, not an application scope ! I suggest you the following scenario:

1.) after authenticated your customer, store its values in a CustomerConfig instance (not static !), and store this customerConfig to the request or session Attributes

2.) you can do this in a HttpFilter :

if (session.isNew)
{   // read customerConfig from DB or resources etc...
    session.setAttribute("customerConfig",customerConfig);
}

3.) in your POJO classes you can reach it like

ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
CustomerConfig cc =(CustomerConfig)attr.getRequest().getSession().getAttribute("customerConfig");
parameter = cc.getYourCustomerProperty();

4.) in your Components, Service etc you can autowire the request like:

@Component
@Scope("request")
public class FooBar {
    @Autowired 
    private HttpServletRequest request;

    public void function()
    { CustomerConfig config = request().getSession().getAttribute("customerConfig");
      parameter = cc.getYourCustomerProperty();
      //...
     }  
}

Upvotes: 0

Anton N
Anton N

Reputation: 2375

From Spring documentation:

You can programmatically set active profiles by calling SpringApplication.setAdditionalProfiles(…​) before your application runs. It is also possible to activate profiles by using Spring’s ConfigurableEnvironment interface.

Upvotes: 1

Related Questions