skip to content

Environment, Properties & SpEL

Where configuration values come from and how they reach your code: the Environment abstraction, profiles, ordered property sources, @Value binding and SpEL. Interviewers ask because externalized configuration is where environments quietly diverge.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

20

What is a Spring profile, and how do you activate one?

level: juniorimportance: must knowfreq 78%

answer

  1. label on beans, only loaded when active
  2. spring.profiles.active
  3. no profile set → 'default' profile
  4. @Profile = @Conditional(ProfileCondition)
  5. comma-separated multiple

basics

~10 s

A profile is a named group of beans/config that is only registered when active. Mark beans with @Profile("dev"). Activate by setting the property spring.profiles.active=dev (property file, env var, or JVM flag).

solid answer

~40 s

A profile is a logical name (e.g. dev, prod, test) you attach to beans or configuration so they are only created when that profile is active. You annotate a @Component or @Bean method with @Profile("prod"); the bean is skipped unless prod is among the active profiles. You activate profiles via the spring.profiles.active property, set through application.properties, the SPRING_PROFILES_ACTIVE environment variable, or a JVM system property (-Dspring.profiles.active=prod). Multiple profiles are comma-separated. If none are set, Spring falls back to the 'default' profile, so @Profile("default") beans act as fallbacks. This lets one codebase behave differently per environment without code changes, most commonly for datasources, mail senders, mock vs real clients, and logging.

code

java · 16 lines
java
@Configuration
public class MailConfig {

    @Bean
    @Profile("prod")
    MailSender smtpSender() {
        return new JavaMailSenderImpl(); // real SMTP
    }

    @Bean
    @Profile("!prod")   // any non-prod profile
    MailSender loggingSender() {
        return new ConsoleLoggingMailSender();
    }
}
// Run with: -Dspring.profiles.active=prod

go deeper

for a junior

Define profile as environment-specific bean groups; know @Profile and spring.profiles.active.

for a middle

Add the 'default' profile fallback, comma-separated multiples, and the various ways to set the property (env var, JVM flag, file).

for a senior

Mention it's @Conditional under the hood, that it gates bean registration not values, and testing via @ActiveProfiles.

for a principal

Frame profiles as one of several conditional strategies; discuss when @Profile vs @ConditionalOnProperty is the better boundary and the operational risks of profile sprawl.

## What a profile is A **profile** is just a *label* (a String like `dev`, `prod`, `test`) that you can attach to beans and configuration. Beans tagged with a profile are only added to the `ApplicationContext` when that profile is **active**. This is Spring's built-in mechanism for environment-specific wiring — one codebase, different beans per environment. ## Declaring profile-scoped beans Use the `@Profile` annotation (package `org.springframework.context.annotation`): - On a `@Component`/`@Configuration` class — the whole class is conditional. - On a `@Bean` factory method — just that bean is conditional. ```java @Configuration public class DataConfig { @Bean @Profile("prod") DataSource prodDs() { /* real pooled DS */ } @Bean @Profile("dev") DataSource devDs() { /* H2 in-memory */ } } ``` A bean **without** any `@Profile` is always registered, regardless of active profiles. ## Activating profiles The active set is driven by the property **`spring.profiles.active`**. Common ways to set it (highest precedence wins): - JVM system property: `-Dspring.profiles.active=prod` - OS environment variable: `SPRING_PROFILES_ACTIVE=prod` (relaxed binding — underscores/uppercase). - In `application.properties`/`application.yml`: `spring.profiles.active=prod` - Programmatically before refresh (see ConfigurableEnvironment). Multiple profiles are comma-separated: `spring.profiles.active=prod,cloud`. ## The 'default' profile If **no** active profile is set, Spring uses the **default profiles** — literally the profile named `default`. So `@Profile("default")` beans are the fallback that loads only when nobody activated anything else. You can rename the fallback via `spring.profiles.default`. ## How it works under the hood `@Profile` is a meta-annotation: it is itself annotated with `@Conditional(ProfileCondition.class)`. During bean registration, `ProfileCondition` asks the `Environment` whether any of the listed profiles are accepted. So profiles are a specialization of the general `@Conditional` mechanism. ## When to use Datasource per environment, mock vs real external clients, dev-only debug beans, seed-data loaders, disabling schedulers in tests. In tests, activate with `@ActiveProfiles("test")`. ## Gotchas - Profiles decide **whether a bean is created**, not property values — for values use property files (though profile-specific files like `application-prod.properties` combine both). - Setting `spring.profiles.active` inside a profile-specific document is not allowed in Spring Boot. - A misspelled profile name silently activates nothing useful — no error.

  • What happens if you don't set spring.profiles.active at all?
    No profile is active, so Spring applies the 'default' profiles (the profile literally named 'default'). Beans annotated @Profile("default") load; other @Profile beans are skipped; unannotated beans always load.
  • Does @Profile control property values or bean creation?
    Bean creation/registration. It decides whether a bean definition is added to the context. Property values come from PropertySources; profile-specific property files (application-prod.properties) are a separate, complementary mechanism.

saying these in an interview costs you the question

  • Claiming @Profile changes property values
  • Thinking beans without @Profile only load in the default profile
  • Saying a wrong/misspelled profile name throws an error
  • Believing you must recompile to switch environments

context

open as a page

What is Spring's Environment / PropertySources abstraction, and what does @PropertySource do?

level: juniorimportance: must knowfreq 58%

basics

~20 s

The Environment holds an ordered list of PropertySources (files, JVM system properties, OS env vars). getProperty() searches them in order. @PropertySource loads a .properties file and adds it as one more source so its keys become available.

open as a page

What is the Spring Expression Language (SpEL) and where do you commonly use it in a Spring application?

level: juniorimportance: must knowfreq 70%

basics

~10 s

SpEL is a small expression language that Spring evaluates at runtime. You write expressions inside #{...} — often in @Value — to compute values, call methods, read bean properties, or reference other beans.

open as a page

How does @Value with a ${...} placeholder work, and how do you supply a default when the property is missing?

level: juniorimportance: must knowfreq 85%

basics

~10 s

@Value("${my.prop}") injects the value of property my.prop from the environment into a field or parameter. Use ${my.prop:fallback} to supply a default when the property is not set.

open as a page

What is Spring's Environment abstraction, and how does it relate to profiles and properties?

level: middleimportance: must knowfreq 62%

basics

~10 s

Environment is a container the context exposes that models two things: which profiles are active, and a hierarchy of property sources. You inject it to read properties (getProperty) or check profiles (getActiveProfiles / acceptsProfiles).

open as a page

In the default StandardEnvironment, what is the precedence order between JVM system properties, OS environment variables, and an @PropertySource file — and why?

level: middleimportance: must knowfreq 60%

basics

~10 s

JVM system properties (-D) win over OS environment variables, which win over @PropertySource files. Lookup walks the ordered list and takes the first match, and @PropertySource files are added at the bottom.

open as a page

How does ${...} placeholder resolution work against the PropertySources, and what role does PropertySourcesPlaceholderConfigurer play?

level: middleimportance: must knowfreq 52%

basics

~10 s

${key} placeholders are resolved by looking key up in the Environment's ordered PropertySources. ${key:default} supplies a fallback. In plain Spring, a PropertySourcesPlaceholderConfigurer bean resolves these placeholders; Spring Boot registers one automatically.

open as a page

What is the difference between @Value("${...}") and @Value("#{...}"), and can they be combined?

level: middleimportance: must knowfreq 75%

basics

~20 s

${...} is a property placeholder: it looks up a property in the Environment. #{...} is a SpEL expression that is evaluated (method calls, math, bean references). You can nest a placeholder inside SpEL, e.g. #{'${my.list}'.split(',')}.

open as a page

How do @Profile expressions work — the !, & and | operators?

level: middleimportance: should knowfreq 45%

basics

~10 s

Since Spring 5.1, @Profile accepts a boolean expression over profile names: ! is NOT, & is AND, | is OR. Example @Profile("prod & cloud"). You must use parentheses if you mix & and |.

open as a page

Explain SpEL collection selection and projection. What do the .?[] and .![] operators do?

level: middleimportance: should knowfreq 45%

basics

~10 s

Selection .?[expr] filters a collection, keeping elements where the boolean expr is true. Projection .![expr] transforms each element, producing a new collection of the results. Inside both, #this is the current element.

open as a page

In SpEL, how do you access static members/types with T(), and how do you reference other Spring beans by name?

level: middleimportance: should knowfreq 35%

basics

~10 s

T(fully.qualified.Type) gives you a type reference so you can call its static methods, read static fields, or use enum constants — e.g. T(java.lang.Math).PI. To use another bean, write @beanName in the expression, e.g. @configService.timeout.

open as a page

When should you choose @Value over @ConfigurationProperties for binding configuration, and what are the tradeoffs?

level: middleimportance: should knowfreq 60%

basics

~20 s

Use @Value for a few individual, unrelated settings or when you need SpEL. Use @ConfigurationProperties to bind a whole group of related properties into a typed object with relaxed binding, validation, and easy testing. @Value doesn't support relaxed binding or bean validation.

open as a page

How can you activate or change profiles programmatically, and why is timing critical?

level: seniorimportance: should knowfreq 38%

basics

~10 s

Use ConfigurableEnvironment (from context.getEnvironment()): setActiveProfiles(...) or addActiveProfiles(...). This must happen before the context is refreshed, because @Profile is evaluated during bean registration. After refresh it's too late.

open as a page

How do you programmatically add or reorder PropertySources via MutablePropertySources, and at what point in the lifecycle should you do it?

level: seniorimportance: should knowfreq 33%

basics

~10 s

Get ConfigurableEnvironment.getPropertySources() (a MutablePropertySources) and use addFirst/addLast/addBefore/addAfter/replace/remove to control ordering. Do it early — in an ApplicationContextInitializer or EnvironmentPostProcessor — before beans read properties.

open as a page

How do you use SpEL programmatically? Walk through SpelExpressionParser and EvaluationContext, including #root and #this.

level: seniorimportance: should knowfreq 40%

basics

~20 s

Create a SpelExpressionParser, call parseExpression(str) to get an Expression, then getValue(). To evaluate against data and variables you pass an EvaluationContext (e.g. StandardEvaluationContext) holding a root object and #variables. #root is the root object; #this is the current item during iteration.

open as a page

When you inject a property string into a non-String type via @Value, how does Spring convert it, and what types work out of the box?

level: seniorimportance: should knowfreq 55%

basics

~20 s

Property values are Strings. Spring converts the injected String to the target type using the ConversionService (plus PropertyEditors). Out of the box it handles primitives, enums, Duration, DataSize, arrays/List/Set/Map from delimited text, and more. Register a custom Converter for unsupported types.

open as a page

Why is SpEL a security concern, and how do you evaluate potentially untrusted expressions safely?

level: principalimportance: should knowfreq 30%

basics

~20 s

A full SpEL context can call any static method or constructor via T(), so evaluating attacker-controlled expressions enables remote code execution (e.g. T(Runtime).exec). Never build expressions from user input; if you must evaluate dynamic strings, use SimpleEvaluationContext, which disables T(), constructors, and bean access.

open as a page

Explain active vs default profiles and the subtle gotchas around @Profile("default") and negation.

level: principalimportance: nice to knowfreq 26%

basics

~20 s

Active profiles are the ones you explicitly turned on. Default profiles are the fallback used only when zero profiles are active (default name: 'default'). @Profile("default") beans load solely in that no-active-profile case; @Profile("!x") loads whenever x is not active.

open as a page

Explain SystemEnvironmentPropertySource's relaxed name matching and the subtler @PropertySource gotchas (YAML, location placeholders, repeatable ordering, profiles).

level: principalimportance: nice to knowfreq 18%

basics

~10 s

SystemEnvironmentPropertySource matches names leniently: env.getProperty("db.url") also finds DB_URL (dots↔underscores, case-insensitive). @PropertySource gotchas: no YAML by default, its location placeholder can't self-reference, later declarations override earlier ones, and it isn't profile-aware like Boot's config files.

open as a page

What are the timing and placement gotchas of @Value: injecting into static fields, reading the value in a constructor, and using @Value inside a BeanFactoryPostProcessor?

level: principalimportance: nice to knowfreq 35%

basics

~20 s

@Value doesn't work on static fields. With field injection the value isn't set until after construction, so reading it in the constructor gives null — use constructor-param @Value instead. And placeholders may not resolve inside a BeanFactoryPostProcessor because it is created before the placeholder configurer runs.

open as a page