Back to Master Spring Boot
    Topic 5

    Using Profiles

    Manage environment-specific configurations with Spring Profiles - development, testing, staging, and production setups

    Understanding Profiles

    Profile is a feature provided by Spring that represents the concept of an environment. It allows you to use a single codebase with different configurations and functionalities in different environments.

    Environment-based Profiles

    native
    test
    production

    Git Branch-based Profiles

    master
    dev

    Activating Profiles

    When starting a Spring application, you can pass in one or more environments:

    Activating Profiles
    -Dspring.profiles.active=test,master

    In most cases, using one environment is sufficient.

    Multi-Profile Configuration in YAML

    Spring Boot's support for Profiles allows configuration of each environment within a single application.yml file. Use --- as a separator between configurations:

    application.yml (Multi-Profile)
    spring:application:name: ${APP_NAME:unnamed}datasource:url: jdbc:hsqldb:file:testdb
    username: sa
    password:driver-class-name: org.hsqldb.jdbc.JDBCDriver
    hikari:auto-commit:falseconnection-timeout:3000validation-timeout:3000max-lifetime:60000maximum-pool-size:20minimum-idle:1pebble:suffix:cache:falseserver:port: ${APP_PORT:8080}---spring:config:activate:on-profile: test
    server:port:8000---spring:config:activate:on-profile: production
    server:port:80pebble:cache:true

    Configuration Breakdown:

    • Default: Uses port 8080, Pebble cache disabled
    • test: Uses port 8000
    • production: Uses port 80, Pebble cache enabled

    Starting with a Profile

    If we start the application without specifying any profile, then the actual profile is default:

    Default Profile Log
    2022-11-25T11:10:34.006+08:00  INFO 13537 --- [main] c.i.learnjava.Application     : No active profile set, falling back to 1 default profile: "default"

    To start with the test environment:

    Run with Test Profile
    $ java-Dspring.profiles.active=test -jar springboot-profiles-1.0-SNAPSHOT.jar

    The logs will show the active profile and the configured port:

    Test Profile Log
    2022-11-25T11:09:02.946+08:00  INFO 13510 --- [main] c.i.learnjava.Application     : The following 1 profile is active: "test"
    ...
    2022-11-25T11:09:05.124+08:00  INFO 13510 --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8000 (http) with context path ''

    Profile-based Bean Configuration

    Profiles allow you to use different implementations in different environments. For example, using file storage during development and cloud storage in production.

    1. Define the Storage Interface:

    StorageService.java
    publicinterfaceStorageService{// Open InputStream based on URI:InputStreamopenInputStream(String uri)throwsIOException;// Save and return URI based on extension + InputStream:Stringstore(String extName,InputStream input)throwsIOException;}

    Local Storage Implementation

    @Profile("default")
    LocalStorageService.java
    @Component@Profile("default")publicclassLocalStorageServiceimplementsStorageService{@Value("${storage.local:/var/static}")String localStorageRootDir;finalLogger logger =LoggerFactory.getLogger(getClass());privateFile localStorageRoot;@PostConstructpublicvoidinit(){
    logger.info("Initializing local storage with root dir: {}",this.localStorageRootDir);this.localStorageRoot =newFile(this.localStorageRootDir);}@OverridepublicInputStreamopenInputStream(String uri)throwsIOException{File targetFile =newFile(this.localStorageRoot, uri);returnnewBufferedInputStream(newFileInputStream(targetFile));}@OverridepublicStringstore(String extName,InputStream input)throwsIOException{String fileName =UUID.randomUUID().toString()+"."+ extName;File targetFile =newFile(this.localStorageRoot, fileName);try(OutputStream output =newBufferedOutputStream(newFileOutputStream(targetFile))){
    input.transferTo(output);}return fileName;}}

    @Profile("default") means this implementation is enabled by default when no profile is specified.

    Cloud Storage Implementation

    @Profile("!default")
    CloudStorageService.java
    @Component@Profile("!default")publicclassCloudStorageServiceimplementsStorageService{@Value("${storage.cloud.bucket:}")String bucket;@Value("${storage.cloud.access-key:}")String accessKey;@Value("${storage.cloud.access-secret:}")String accessSecret;finalLogger logger =LoggerFactory.getLogger(getClass());@PostConstructpublicvoidinit(){
    logger.info("Initializing cloud storage...");}@OverridepublicInputStreamopenInputStream(String uri)throwsIOException{// TODO: Implement cloud storage readthrownewIOException("File not found: "+ uri);}@OverridepublicStringstore(String extName,InputStream input)throwsIOException{// TODO: Implement cloud storage writethrownewIOException("Unable to access cloud storage.");}}

    @Profile("!default") means this implementation is enabled when any profile OTHER than default is active (e.g., test, production).

    Summary

    Spring Boot allows configuration for different profiles in a single configuration file using --- separators.

    Spring Boot defaults to the default profile if no profile is specified.

    Use @Profile annotation to conditionally load beans based on the active profile.

    Activate profiles using -Dspring.profiles.active=profileName when starting the application.

    💬 Comments & Discussion