Lesson 5 · Spring Core

Properties, Profiles & SpEL

Externalising configuration, switching beans per environment, and the expression language — three loose threads from earlier lessons, tied together.

What you'll be tested on Where external properties come from and how @Value reads them; what @Profile does, where it goes, and how profiles are activated; and — the recurring one — the difference between ${...} and #{...}.

Part 1 — External properties

Hard-coding values is brittle. Spring reads configuration from an Environment abstraction populated by property sources (files, system properties, environment variables). You add a file as a source with @PropertySource:

@Configuration
@PropertySource("classpath:app.properties")   // adds a source to the Environment
public class AppConfig {

  @Value("${app.timeout:30}")   // inject property; 30 is the default if missing
  private int timeout;

  @Autowired Environment env;   // or read programmatically
  // env.getProperty("app.timeout")
}

Part 2 — Profiles

A profile is a named group of beans that's only active in certain environments. @Profile makes a bean conditional on the active profile(s):

@Bean
@Profile("dev")                  // only when 'dev' is active
public DataSource devDataSource() { return ...; }

@Bean
@Profile("!prod")                 // active when 'prod' is NOT active
public Mailer fakeMailer() { return ...; }
AspectDetail
Can annotate@Configuration class, @Bean method, @Component class, or another annotation (meta) — not a field
Expressions!prod (not), {"p1","p2"} (either / OR), "p1 & p2" (both)
Activate viaspring.profiles.active property · SPRING_PROFILES_ACTIVE env var · -Dspring.profiles.active=… · env.setActiveProfiles(…) · @ActiveProfiles in tests
Multiple activeYes — several profiles can be active at once
The "default" profile trap A bean with no @Profile is always registered, whatever profiles are active. A bean marked @Profile("default") is active only when no other profile is set. Those are different things — the exam checks you know it.

Part 3 — Spring Expression Language (SpEL)

You've met ${...} and #{...} separately. Here they are side by side — this table is the single highest-value thing on the page:

SyntaxIs a…DoesExample
${...}Property placeholderLooks up a property in the Environment@Value("${app.timeout}")
#{...}SpEL expressionEvaluates code: beans, methods, operators, literals@Value("#{2 * 60}")
#nameSpEL variable refReferences a variable in the eval context (#root, #this, …)#{#root.name}

SpEL #{...} can reference other beans, call methods, use operators, and read system properties:

@Value("#{systemProperties['user.timezone']}")  String tz;   // system property via SpEL
@Value("#{pricingService.vatRate * 100}")       double vatPct; // reference another bean
@Value("#{T(java.lang.Math).PI}")                 double pi;    // static method/field
Don't mix them up ${...} resolves a property; #{...} runs an expression. SpEL does not resolve ${...} placeholders itself — that's the placeholder configurer's job. A question hinges on this almost every exam.
Primary source — read this
Spring Framework 5.3 — Core: Bean Definition Profiles & Spring Expression Language (SpEL)

Read "Bean Definition Profiles" and "Environment Abstraction", then skim the SpEL intro — you only need the annotation-based (@Value) usage.

Check yourself

The ${...} vs #{...} question and the "default profile" trap are the two to nail. Options shuffle on every load.

Then drill the book Container section: the $/# reference questions, @PropertySource, and the @Profile combination/target questions. Then re-run the Container Drill.
I'm your teacher — ask me anything. If the ${}/#{} split still feels slippery, ask me for five more examples of each. Say "continue" for Lesson 6 — the Bean Lifecycle, BeanPostProcessors & proxies (where a lot of earlier threads finally connect).
← Lesson 4 · Bean Scopes Lesson 6 · Bean Lifecycle & Proxies → (coming next)