Detailed explanation of Spring Profiles

1 Overview

In this tutorial, we will focus on Profiles in Spring.

Profiles are the core functionality of the framework - allowing us to map beans to different Profiles - for example, dev , test and prod .

We can then activate different Profiles in different environments to bootstrap only the beans we need.

2. Use on Bean@Profile

Let's start simple and see how to make a bean belong to a specific Profile. We use @Profileannotations - we map the bean to that particular Profile ; annotations take the name of one (or more) Profiles.

Consider a basic scenario: we have a bean that should only be active during development, but not deployed in production.

We annotate the bean with @Profile("dev") and it will only be present in the container during development. In production, dev doesn't activate at all:

@Component
@Profile("dev")
public class DevDatasourceConfig

As a quick side note, Profile names can also be prefixed with the NOT operator, for example !dev, to exclude them from the Profile.

In the example, the component is only activated if the dev Profile is not active:

@Component
@Profile("!dev")
public class DevDatasourceConfig

3. Declare Profiles in XML

Profiles can also be configured in XML. The tag has a profile attribute, which takes comma-separated values of the applicable profiles:

<beans profile="dev">
    <bean id="devDatasourceConfig" 
      class="org.baeldung.profiles.DevDatasourceConfig" />
</beans>

4. Set Profiles

The next step is to activate and set up the Profiles so that the corresponding beans are registered with the container.

This can be done in a number of ways, which we'll explore in the following sections.

4.1. Programmatically via WebApplicationInitializerthe interface

In a web application, WebApplicationInitializer can be used to programmatically configure the ServletContext .

This is also a very convenient place to programmatically set our active profiles:

@Configuration
public class MyWebApplicationInitializer 
  implements WebApplicationInitializer {
    
    

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
    
    
 
        servletContext.setInitParameter(
          "spring.profiles.active", "dev");
    }
}

4.2. ConfigurableEnvironmentProgrammatically

We can also set profiles directly in the environment:

@Autowired
private ConfigurableEnvironment env;
...
env.setActiveProfiles("someProfile");

4.3. web.xmlContext parameters in

Similarly, we can define the active Profile in the web application's web.xml file using the context parameter:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/app-config.xml</param-value>
</context-param>
<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>dev</param-value>
</context-param>

4.4. JVM system parameters

The profile name can also be passed in via JVM system parameters. These profiles will be activated during application startup:

-Dspring.profiles.active=dev

4.5. Environment variables

On Unix, profiles can also be activated via environment variables :

export SPRING_PROFILES_ACTIVE=dev
//或者
export spring_profiles_active=dev

4.6. Maven Profile

Spring Profiles can also be activated via Maven Profiles by specifying spring.profiles.activeconfiguration properties .

In each Maven Profile, we can set a spring.profiles.active property:

<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <spring.profiles.active>dev</spring.profiles.active>
        </properties>
    </profile>
    <profile>
        <id>prod</id>
        <properties>
            <spring.profiles.active>prod</spring.profiles.active>
        </properties>
    </profile>
</profiles>

Its value will be used to application.propertiesreplace @spring.profiles.active@placeholders in the file:

spring.profiles.active=@spring.profiles.active@

Now we need to enable resource filtering in pom.xml :

<build>
    <resources>
        <resource>
            <filtering>true</filtering>
            <directory>src/main/resources</directory>
            <includes>
              <include>public/**</include>
              <include>static/**</include>
              <include>templates/**</include>
              <include>tpl/**</include>
              <include>application.*</include>
              <include>application-${spring.profiles.active}.*</include>
              <include>log*-${spring.profiles.active}.xml</include>
            </includes>
        </resource>
    </resources>
    ...
</build>

And append a -P parameter to switch which Maven Profile will be applied:

mvn clean package -Pprod

This command will package the application for the prod Profile. It also applies the spring.profiles.active value to prod when the application is running .

4.7. @ActiveProfileIn testing

To enable specific profiles using the @ActiveProfile annotation, tests can easily specify which profiles are active:

@ActiveProfiles("dev")

So far, we've looked at various ways to activate a Profile. Now let's see which priority is higher than the other, what happens if we use multiple priorities from high to low:

  1. Context parameters in the web.xml file
  2. WebApplicationInitializer interface
  3. JVM system parameters
  4. environment variable
  5. Maven profile

5. Default Profile

Any bean that does not specify a profile belongs to the default profile.

Spring also provides a way to set a default profile when no other profiles are active - by using the spring.profiles.default property.

6. Get activity profile

Spring's active Profile drives the behavior of the @Profile annotation to enable/disable beans. However, we may also wish to programmatically access the list of active profiles.

We have two methods, **using Environmentor spring.profiles.active**.

6.1. Using Environment

We can access active profiles by injecting the Environment object:

public class ProfileManager {
    
    
    @Autowired
    private Environment environment;

    public void getActiveProfiles() {
    
    
        for (String profileName : environment.getActiveProfiles()) {
    
    
            System.out.println("Currently active profile - " + profileName);
        }  
    }
}

6.2. Usespring.profiles.active

Alternatively, we can access the profile by injecting the property spring.profiles.active :

@Value("${spring.profiles.active}")
private String activeProfile;

Here, our activeProfile variable will contain the names of the currently active profiles, or comma-separated names if there are more than one.

However, we should consider what happens if there is no active profile at all. **For our code above, the absence of a profile will prevent the application context from being created. This will cause an IllegalArgumentException to be thrown due to missing placeholders for injected variables .

To avoid this, we can define a default value :

@Value("${spring.profiles.active:}")
private String activeProfile;

Now, our activeProfile will just contain an empty string if no Profile is active .

If we want to access a list of them like in the previous example, we can do so by splitting the activeProfile variable:

public class ProfileManager {
    
    
    @Value("${spring.profiles.active:}")
    private String activeProfiles;

    public String getActiveProfiles() {
    
    
        for (String profileName : activeProfiles.split(",")) {
    
    
            System.out.println("Currently active profile - " + profileName);
        }
    }
}

7. Example: Separate data source configuration using Profiles

Now that the basics are covered, let's look at a real example.

Consider a scenario where we have to maintain datasource configurations for development and production environments .

Let's create a public interface DatasourceConfig that needs to be implemented by two datasource implementations:

public interface DatasourceConfig {
    
    
    public void setup();
}

The following is the configuration of the development environment:

@Component
@Profile("dev")
public class DevDatasourceConfig implements DatasourceConfig {
    
    
    @Override
    public void setup() {
    
    
        System.out.println("Setting up datasource for DEV environment. ");
    }
}

And the configuration of the production environment:

@Component
@Profile("production")
public class ProductionDatasourceConfig implements DatasourceConfig {
    
    
    @Override
    public void setup() {
    
    
       System.out.println("Setting up datasource for PRODUCTION environment. ");
    }
}

Now let's create a test and inject our DatasourceConfig interface; depending on the active profile, Spring will inject the DevDatasourceConfig or ProductionDatasourceConfig bean:

public class SpringProfilesWithMavenPropertiesIntegrationTest {
    
    
    @Autowired
    DatasourceConfig datasourceConfig;

    public void setupDatasource() {
    
    
        datasourceConfig.setup();
    }
}

When the dev profile is active, Spring injects the DevDatasourceConfig object, and then calls the setup() method, the output is as follows:

Setting up datasource for DEV environment.

8. Profiles in Spring Boot

Spring Boot supports all profiles outlined so far, with some additional features.

8.1. Activate or set up a Profile

The initialization parameter spring.profiles.active introduced in Section 4 can also be set as a property in Spring Boot to define the currently active profiles. Here are the standard properties that Spring Boot will pick up automatically:

spring.profiles.active=dev

However, as of Spring Boot 2.4, this property cannot be used with spring.config.activate.on-profile , as this may throw a ConfigDataException ( i.e. InvalidConfigDataPropertyException or InactiveConfigDataAccessException ).

To set profiles programmatically we can also use the SpringApplication class:

SpringApplication.setAdditionalProfiles("dev");

To set up a Profile using Maven in Spring Boot, we can specify the Profile name under spring-boot-maven-plugin in pom.xml:

<plugins>
    <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
            <profiles>
                <profile>dev</profile>
            </profiles>
        </configuration>
    </plugin>
    ...
</plugins>

and execute Spring Boot-specific Maven goals:

mvn spring-boot:run

8.2. Profile-specific properties files

However, the most important Profile-related feature that Spring Boot brings is Profile-specific properties files. **These files must be named in the format application-{profile}.properties .

Spring Boot will automatically load the properties in the application.properties file for all profiles , and only load the properties in the profile-specific .properties file for the specified profile.

For example, we can configure different data sources for the dev and production profiles using two files named application-dev.properties and application-production.properties :

In the application-production.properties file, we can set a MySql data source:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=root
spring.datasource.password=root

We can then configure the same properties for the dev Profile in the application-dev.properties file to use the in-memory H2 database:

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa

In this way, we can easily provide different configurations for different environments.

Prior to Spring Boot 2.4, profiles could be activated from profile-specific documentation. But this is no longer the case; with later versions, the framework will again throw InvalidConfigDataPropertyException or InactiveConfigDataAccessException in these cases .

8.3. Multiple document files

To further simplify defining properties for separate environments, we can even combine all properties in the same file and use a delimiter to indicate the Profile.

Starting with version 2.4, Spring Boot has extended support for multi-document files for property files, in addition to the previously supported YAML . So now, we can specify and properties in the same *application.properties* :devproduction

my.prop=used-always-in-all-profiles
#---
spring.config.activate.on-profile=dev
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=root
spring.datasource.password=root
#---
spring.config.activate.on-profile=production
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa

This file is read by Spring Boot in order from top to bottom. That is, if some property, like my.prop , appears at the end again in the example above, the endmost value will be considered.

8.4. Profile group

Another feature added in Spring Boot 2.4 is the configuration of Profile groups. As the name suggests, it allows us to group similar Profiles together .

Let's consider a use case where we have multiple production profiles. For example, proddb is used for the database, and prodquartz is used for the scheduler in the production environment.

To enable these profiles at the same time through our application.properties file, we can specify:

spring.profiles.group.production=proddb,prodquartz

Therefore, activating the production Profile also activates proddb and prodquartz .


<<<<<< [完] >>>>>>

Guess you like

Origin blog.csdn.net/wjw465150/article/details/129468327