How many times did you have to use different credentials or configuration in production and development applications? I bet your answer is ‘Every single time!’. The simplest example describing this is using payment systems in your application. In development mode you want to use test payments in order not to loose all off your money during testing your app and in production real payments should work. If you still manually change this credentials in your code every single time while running your server side in production or development then you definitely have to read this article.
Profiles in Spring Boot applications
To avoid this annoying work Spring Boot Profiles should be used. So, in this article we are going to talk about using Profiles in Spring Boot applications.
Profile is a set of some properties or even class that should be enabled in some specific environment like production, development, test etc. Spring Boot lets you to do that by creating profile-specific properties files. As you know Spring Boot application uses application.properties or application.yml files for storing some of your properties. So lets create two files application-dev.yml and application-prod.yml which will be responsible for ‘dev’ and ‘prod’ environment. They will content port on which server will be running and some custom message.
application-dev.yml:
server: port: 9090 message: Development mode is on application-prod.yml: server: port: 8888 message: Production mode is on
Now lets activate one of the profiles. We can do it in a several ways:
- Enabling active profile in application.yml file which is considered by spring as a default property file.
spring: profiles: active: dev
2. By specifying in command line while running .jar file.
java -jar myapp.jar --spring.profiles.active=dev
3. Programmatically in main application method.
@SpringBootApplication public class Application { public static void main(String[] args) { new SpringApplicationBuilder() .sources(Application.class) .profiles("prod") .run(args); } }
When you’ll run your application with active profile ‘dev’ tomcat will start on port 9090. If ‘prod’ is activated then port will be 8888. If there is no active profile specified then ‘default’ profile will be activated with default port 8080. So your set of properties will vary according to activated profile.
But what if we want some piece of code to be executed in some special environment? Spring also has a solution for this.
One way is to use @Profile annotation on class. If we want some method to have different implementations for different environments, we can define an interface with this method, then create two classes that implement this interface and add annotations @Profile(“dev”) and @Profile(“prod”) to this classes. Let’s see how it looks in real example.
Config.class
public interface Config { setup(); } DevConfig.class @Profile("dev") @Component public class DevConfig implements Config { @Override public void setup() { //setup some configuration here System.out.println("Development configuration setup"); } } ProdConfig.class @Profile("prod") @Component public class ProdConfig implements Config { @Override public void setup() { //setup some configuration here System.out.println("Production configuration setup"); } }
If we will inject this Config.class into some service and try to call setup() method, spring will create appropriate bean according to activated profile. Let’s add calling this method after application startup using CommandLineRunner.
@SpringBootApplication public class Application { private Config config; @Autowired Application(Config config) { this.config = config; } public static void main(String[] args) { new SpringApplicationBuilder() .sources(Application.class) .profiles("prod") .run(args); } @Bean CommandLineRunner execute() { return args -> config.setup(); } }
After running this application you should see message ‘Production configuration setup’ in the console.
What if you don’t want to create interface and two classes and instead you just want to change a single line of code in one of your method? There is also a method that allows you to do that. You can use Environment class which has a method acceptsProfiles(String … args). This method returns true if profile that you pass is active.
@Autowired private Environment environment;void environmentSpecificMethod() { if (environment.acceptsProfiles("prod")) { System.out.println("This will be executed only in production mode"); //do some stuff here } else { System.out.println("This will be executed for all other profiles"); } }
This method is very useful when you want to use the same getter method but return different values according to active profile.
Conclusion
You can play around with spring boot profiles and learn more about this, but this is the basics which is enough to make your development process easier and environment specific.
If this article was useful for you do not forget to press claps button and share it with your friends. Also feel free to leave a comment.
You can find a full example on Oril Software GitHub.