This article has participated in the Denver Nuggets Creators Camp 3 “More Productive writing” track, see details: Digg project | creators Camp 3 ongoing, “write” personal impact.

Spring’s Environment interface has two key roles: 1. Profile and 2.properties. Take a look at the interface definition:

public interface Environment extends PropertyResolver {

	/**
	 * Return the set of profiles explicitly made active for this environment. Profiles
	 * are used for creating logical groupings of bean definitions to be registered
	 * conditionally, for example based on deployment environment. Profiles can be
	 * activated by setting {@linkplain AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
	 * "spring.profiles.active"} as a system property or by calling
	 * {@linkConfigurableEnvironment#setActiveProfiles(String...) }. * <p>If no profiles have explicitly been specified as active, then any * {@linkplain #getDefaultProfiles() default profiles} will automatically be activated.
	 * @see #getDefaultProfiles
	 * @see ConfigurableEnvironment#setActiveProfiles
	 * @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
	 */
	String[] getActiveProfiles();

	/**
	 * Return the set of profiles to be active by default when no active profiles have
	 * been set explicitly.
	 * @see #getActiveProfiles
	 * @see ConfigurableEnvironment#setDefaultProfiles
	 * @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME
	 */
	String[] getDefaultProfiles();

	/** * Return whether one or more of the given profiles is active or, in the case of no * explicit active profiles, whether one or more of the given profiles is included in * the set of default profiles. If a profile begins with '! ' the logic is inverted, * i.e. the method will return {@code true} if the given profile is <em>not</em> active.
	 * For example, {@codeenv.acceptsProfiles("p1", "! p2")} will return {@code true} if
	 * profile 'p1' is active or 'p2' is not active.
	 * @throws IllegalArgumentException if called with zero arguments
	 * or if any profile is {@code null}, empty, or whitespace only
	 * @see #getActiveProfiles
	 * @see #getDefaultProfiles
	 * @see #acceptsProfiles(Profiles)
	 * @deprecatedAs of 5.1 in favor of {@link #acceptsProfiles(Profiles)}
	 */
	@Deprecated
	boolean acceptsProfiles(String... profiles);

	/**
	 * Return whether the {@linkplain #getActiveProfiles() active profiles}
	 * match the given {@link Profiles} predicate.
	 */
	boolean acceptsProfiles(Profiles profiles);

}
Copy the code

It inherits PropertyResolver:

public interface PropertyResolver {

	/**
	 * Return whether the given property key is available for resolution,
	 * i.e. if the value for the given key is not {@code null}.
	 */
	boolean containsProperty(String key);

	/**
	 * Return the property value associated with the given key,
	 * or {@code null} if the key cannot be resolved.
	 * @param key the property name to resolve
	 * @see #getProperty(String, String)
	 * @see #getProperty(String, Class)
	 * @see #getRequiredProperty(String)
	 */
	@Nullable
	String getProperty(String key);

	/**
	 * Return the property value associated with the given key, or
	 * {@code defaultValue} if the key cannot be resolved.
	 * @param key the property name to resolve
	 * @param defaultValue the default value to return if no value is found
	 * @see #getRequiredProperty(String)
	 * @see #getProperty(String, Class)
	 */
	String getProperty(String key, String defaultValue);

	/**
	 * Return the property value associated with the given key,
	 * or {@code null} if the key cannot be resolved.
	 * @param key the property name to resolve
	 * @param targetType the expected type of the property value
	 * @see #getRequiredProperty(String, Class)
	 */
	@Nullable
	<T> T getProperty(String key, Class<T> targetType);

	/**
	 * Return the property value associated with the given key,
	 * or {@code defaultValue} if the key cannot be resolved.
	 * @param key the property name to resolve
	 * @param targetType the expected type of the property value
	 * @param defaultValue the default value to return if no value is found
	 * @see #getRequiredProperty(String, Class)
	 */
	<T> T getProperty(String key, Class<T> targetType, T defaultValue);

	/**
	 * Return the property value associated with the given key (never {@code null}).
	 * @throws IllegalStateException if the key cannot be resolved
	 * @see #getRequiredProperty(String, Class)
	 */
	String getRequiredProperty(String key) throws IllegalStateException;

	/**
	 * Return the property value associated with the given key, converted to the given
	 * targetType (never {@code null}).
	 * @throws IllegalStateException if the given key cannot be resolved
	 */
	<T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException;

	/** * Resolve ${... } placeholders in the given text, replacing them with corresponding * property values as resolved by {@link #getProperty}. Unresolvable placeholders with
	 * no default value are ignored and passed through unchanged.
	 * @param text the String to resolve
	 * @return the resolved String (never {@code null})
	 * @throws IllegalArgumentException if given text is {@code null}
	 * @see #resolveRequiredPlaceholders
	 * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders(String)
	 */
	String resolvePlaceholders(String text);

	/** * Resolve ${... } placeholders in the given text, replacing them with corresponding * property values as resolved by {@link #getProperty}. Unresolvable placeholders with
	 * no default value will cause an IllegalArgumentException to be thrown.
	 * @return the resolved String (never {@code null})
	 * @throws IllegalArgumentException if given text is {@code null}
	 * or if any placeholders are unresolvable
	 * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders(String, boolean)
	 */
	String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;

}
Copy the code

A Profile is a logical grouping of beans that is registered in the container only when a given Profile is active.

Properties is used to read property definitions from a variety of sources: property files, JVM system Properties, system environment variables, JNDI, servlet context parameters, special property objects, mapping objects, and so on.

Profiles

In development, we may need to define different configurations in different environments, for example:

  • Work with in-memory data sources during development rather than looking up the same data sources from JNDI in QA or production.
  • Register the monitoring infrastructure only when the application is deployed into the performance environment.
  • Deploy and register custom bean implementations for clients A and B.

If we have two data sources, one for the test environment and one for the online environment, we can specify different environments through profiles. As follows:

@Configuration
@Profile("development")
public class StandaloneDataConfig {

    @Bean
    public DataSource dataSource(a) {
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.HSQL)
                .addScript("classpath:com/bank/config/sql/schema.sql")
                .addScript("classpath:com/bank/config/sql/test-data.sql") .build(); }}Copy the code
@Configuration
@Profile("production")
public class JndiDataConfig {

    @Bean(destroyMethod="")
    public DataSource dataSource(a) throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); }}Copy the code

The @profile expressions can be simple strings or can support operators such as:

  • ! Logic is not
  • & logic and
  • | logic or

You can use @Profile as a meta-annotation to create custom composite annotations. The following example defines a custom @production annotation that you can use as an alternative to @profile (” Production “) :

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Profile("production")
public @Interface Production {
}
Copy the code

@profile can also be used at the method level to contain a particular bean or configuration class. As follows:

@Configuration
public class AppConfig {

    @Bean("dataSource")
    @Profile("development") 
    public DataSource standaloneDataSource(a) {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .addScript("classpath:com/bank/config/sql/test-data.sql")
            .build();
    }

    @Bean("dataSource")
    @Profile("production") 
    public DataSource jndiDataSource(a) throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); }}Copy the code

Profiles is used in XML

You can use the profile attribute in XML, as follows:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">

    <! -- other bean definitions -->

    <beans profile="development">
        <jdbc:embedded-database id="dataSource">
            <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/>
            <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/>
        </jdbc:embedded-database>
    </beans>

    <beans profile="production">
        <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
    </beans>
</beans>
Copy the code

To activate the Profile

We’ve defined profiles, but how do we activate them?

Activating a profile can be done in several ways, but the easiest way is programmatically through an environment API provided by the application context. The following example shows how to do this:

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.getEnvironment().setActiveProfiles("development");
        ctx.register(AppConfig.class, StandaloneDataConfig.class, JndiDataConfig.class);
        ctx.refresh();
    }
Copy the code

In addition, profiles can be declaratively activated through the spring.profiles. Active property, which can be specified through system environment variables, JVM system properties, servlet context parameters in web.xml, or even as an entry in JNDI. As follows:

-Dspring.profiles.active=”profile1,profile2″

You can also activate multiple POfiles at the same time

ctx.getEnvironment().setActiveProfiles(“profile1”, “profile2”);

The default Profile

The default Profile indicates that the Profile is activated by default, as shown below:

@Configuration
@Profile("default")
public class DefaultDataConfig {

    @Bean
    public DataSource dataSource(a) {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql") .build(); }}Copy the code

If no Profile is active, then the dataSource is created, which you can use as the default way to create a bean. If other profiles are activated, the default Profile will not be used.

You can change the name of the default profile using SetDefaultProfiles () in the environment, or declaratively change the name of the default profile using the spring.profiles.default property.

PropertySource

Here is an example of using PropertySource:

    public static void main(String[] args) {
        ApplicationContext ctx = new GenericApplicationContext();
        Environment env = ctx.getEnvironment();
        boolean containsMyProperty = env.containsProperty("my-property");
        System.out.println("Does my environment contain the 'my-property' property? " + containsMyProperty);
    }
Copy the code

Here Spring queries to see if the my-property property is defined, and StandardEnvironment defines two sets of PropertySource objects to query,

	/** System environment property source name: {@value}. * /
	public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

	/** JVM system properties property source name: {@value}. * /
	public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
Copy the code

One represents a set of JVM System properties (System.getProperties ()), and the other a set of System environment variables (System.getenv ()).

For common StandardServletEnvironment, property query priority is as follows:

  • ServletConfig parameter (if applicable – for example, for the DispatcherServlet context)
  • The ServletContext parameter (the web.xml context-param item)
  • JNDI environment variables (Java:COMP/Env/ entry)
  • JVM system Properties (-d command-line arguments)
  • JVM system environment (operating system environment variables)

Using the @ PropertySource

The @propertysource annotation provides a convenient and declarative mechanism for adding PropertySource to Spring.

The following @Configuration class uses @propertysource to call testBean.getName() to return myTestBean:

@Configuration
@PropertySource("classpath:app.properties")
public class PropertiesConfig {


    @Autowired
    Environment env;

    @Bean
    public TestBean testBean(a) {
        TestBean testBean = new TestBean();
        testBean.setName(env.getProperty("testbean.name"));
        returntestBean; }}Copy the code

@propertysource Any $… Placeholders are resolved against the source set of properties registered for the environment, as shown in the following example:

@PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties")
Copy the code

Given that my.placeholder exists in one of the registered property sources (for example, system property or environment variable), the placeholders are resolved to the corresponding values. If not, default/path is used as the default value. If a default value is not specified and the attribute cannot be resolved, an IllegalArgumentException is raised.

See Environment for examples in this section

See flydean’s blog for more tutorials