Usecases for Spring Profiles

Vinodhini Chockalingam
3 min readJan 31, 2019

--

We know that Spring profile is indeed an effective feature. I am summarizing the cases where I found them indispensible

Bypass web filter for local instances

There are few filters which apply only for production environment — Authentication filter, Monitoring filter that sends metrics to some monitoring system, etc

And I should be able to skip these for local/test environments.

-Dspring.profiles.active=testcase

So here we leave the decision of whether to bypass a filter or not to Spring, i.e. DelegatingFilterProxy

targetFilterLifecycle is the one which will delegate the init paramaters to the bean as well. Also, the bean name should match the filter-name (if you do not specify targetBeanName)

Coming to the part where we actually use the profile

const val AUTHENTICATION_FILTER_NAME = "AuthenticationFilter"const val TEST_PROFILE = "testcase"
const val NOT_TEST_PROFILE = "!" + TEST_PROFILE
@Configuration
class WebConfig {
@Profile(NOT_TEST_PROFILE)
@Bean(name = arrayOf(AUTHENTICATION_FILTER_NAME))
fun getAuthenticationFilter(): AuthenticationFilter = AuthenticationFilter()
@Profile(TEST_PROFILE)
@Bean(name = arrayOf(AUTHENTICATION_FILTER_NAME))
fun getByPassAuthenticationFilter(): Filter = ByPassFilter()
}

ByPassFilter would just the pass the request to the next filter in the chain

override fun doFilter(request: ServletRequest?, response: ServletResponse?, chain: FilterChain?) {
chain?.doFilter(request, response)
}

Overriding beans of same name

Refer my previous post to understand the project setup

In short, an application Foo, can be accessed heavy(i.e. you load Foo’s context in your application)/restfully.

So if Bar is a client application for Foo, when the context initializes, it should decide which bean to use for “fooService”. this heavy/light-weight decision can be set via property. And based on this property you can decide whether to override “fooService” with its light version

@Configuration
@Import(FooConfig.class)
public class BarConfig {

@Bean(name="fooService")
@Conditional(IsFooModeLightWeight.class)
public FooService getFooService() {
return com.foo.restful.FooLightWeightService();
}
}

If Bar is using Spring 5 and above, this will work flawlessly. But lets say Bar is using Spring 4 where this approach does not work.

You can refer more on this inconsistent behavior of Spring bean overriding across versions here

Guess what comes to rescue here. Profiles again.

@Profile("HEAVY")
@Configuration
@Import(FooConfig.class)
public class FooHeavyConfig {
}
@Profile("LIGHTWEIGHT")
@Configuration
public class FooLightConfig{
@Bean(name="fooService")
public FooService getFooService() {
return com.foo.restful.FooLightWeightService();
}
}

And this is also one of the ways you can mention active profiles:

In my case, the mode — heavy/light-weight varies per pod. i.e. in one container I can configure to run in light-weight and in another, to run in heavy mode. Not just this service mode, all other such configuration comes from another a configuration service to Bar Application. So I need to set the active profile AFTER I have read these properties

This is where Spring’s ApplicationContextInitializer comes into play.

public class BarApplicationContextInitializer extends SomePropertySourceContextInitializer {@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
super.initialize(applicationContext);
String fooServiceMode = applicationContext.getEnvironment()
.getProperty("fooServiceMode");
if (fooServiceMode.equals("light-weight")) {
applicationContext.getEnvironment().addActiveProfile("LIGHTWEIGHT");
}
}
}

SomePropertySourceContextInitiliazer reads the properties and add to the application context. Once that is done, I am checking for the mode and setting the active profile accordingly.

For this to work in your web application, you need to add Spring context loader listener in your web.xml and also pass this initializer as context-param

    <context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>
com.bar.BarApplicationContextInitializer
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

--

--

Vinodhini Chockalingam
Vinodhini Chockalingam

Written by Vinodhini Chockalingam

Not a blogger. I mostly move my well-written notes here.

No responses yet