Welcome to the spring framework series, In this article we will understand how Spring Environment abstraction works. Spring Environment abstraction is integrated to the container, Profiles and Properties are the two important aspects that model the spring environment. Here, we are going to look at how Profiles and Properties are used to provide environment abstraction in Spring.
First, Let’s understand what is Environment?.
Let’s consider this simple example to understand why we need environment abstraction. For example, Consider that we are building a spring application which has to be developed, tested and finally it should be deployed into production. In order to deploy our application into production, It has to go through multiple stages such as development, testing..etc. We can consider each of this stage as Environment.
Any application which runs in production might have to connect with datasource, message queue, cache or some external services. In order to successfully complete our development and testing, We must connect different datasource, message queue, cache or other external services that run on the similar environment. This is where environment comes into the practice.
Let’s consider another scenario where we are required to enable or disable some infrastructure services such as logging, distributed tracing …etc. Here, We could optionally enable or disable those infrastructure beans or service in our application.
In the above example, we have an IOC container with 9 beans and it is numbered for understanding. At each stage of this environment, some beans are not loaded or registered into the container. for example, bean numbered 5 is loaded in staging environment and bean 6 is only registered during production environment.
@Profile
Profile is a named logical group of bean definitions to be registered with the container. When we register beans into the container, Profile annotation helps us to group the bean definitions based on the profile name. When we annotate bean with the given profile such @Profile(“dev”), This bean will be loaded and registered with the container only if the profile dev is set active. Otherwise, It is skipped and It’s not loaded during other environement. The following is a simple example which demonstrates how to enable bean under certain environment.
// simple bean in dev environment
@Configuration
class AppConfig {
@Bean
@Profile("dev")
public DataSource dataSource() {
// return data source
DataSource dataSource = new DataSource();
// setup dataSource
return dataSource;
}
}
// simple configuration bean registed while staging env is active
// bean is avaialable during stging environment
@Configuration
@Profile("staging")
public class AppConfiguration {
@Bean
@Description("File Service Configuration")
public FileServiceConfig fileServiceConfig() {
return new FileServiceConfig();
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicatoinContext(UserService.class, AppConfiguration.class);
ctx.getEnvironment().setActiveProfiles("development", "production");
FileServiceConfig fileServiceConfig = ctx.getBean("fileServiceConfig");
System.out.println(fileServiceConfig);
}
@PropertySource
Property Source is an abstraction which source key value pairs in spring. We have seen how the profile annotation plays an important role in grouping beans by name. Here, we will look PropertySources. PropertySources are list of PropertySource objects that are configured in heirarchies. When we annotate a bean with PropertySource annotation, It would load the property file into the environment. We can specify any property that is stored in the classpath to load into the environment so that it can be accessed using Environment object.
The following example shows how to load application.properties into our current environment. ${current.env} placeholder is different for each environment so that it will find the right application.properties for the corresponding environment.
@Configuration
@PropertySource("classpath:./${current.env:default/path}/application.properties")
public class AppConfig {
@AutoWired
Environment env;
@Bean
public FileServiceConfig fileServiceConfig() {
FileServiceConfig fsConfig = new FileServiceConfig();
fsConfig.setRegion(env.getProperty("region.name"));
return fsConfig;
}
}
Conclusion
In this article, we looked at what is Environment and how we can group bean definitions based on the profile name. We have also seen the importance of PropertySource to load the property file. These two profile and properties are what make the spring environment.