How do you register an EnvironmentPostProcessor so Spring Boot actually invokes it, and why can't it be a @Component?
answer
- META-INF/spring.factories key = EPP FQN
- SpringFactoriesLoader, reflection, pre-context
- NOT AutoConfiguration.imports (that's @AutoConfiguration)
- @Component silently never post-processes env
- EnvironmentPostProcessorApplicationListener loads them
basics
~10 sList its fully-qualified class name in META-INF/spring.factories under the key org.springframework.boot.env.EnvironmentPostProcessor. It can't be a @Component because it runs before the application context and component scanning exist.
solid answer
~30 sRegistration is via the spring.factories mechanism: create META-INF/spring.factories and map the key org.springframework.boot.env.EnvironmentPostProcessor to your implementation's fully-qualified class name (comma/backslash-separated for multiples). Spring Boot's EnvironmentPostProcessorApplicationListener uses an EnvironmentPostProcessorsFactory to load these names and instantiate them by reflection during ApplicationEnvironmentPreparedEvent. It can't be a @Component because that timing is *before* the ApplicationContext is created — there is no bean factory and no component scan yet. A common trap: EnvironmentPostProcessor is NOT registered through META-INF/spring/…AutoConfiguration.imports. That file is only for @AutoConfiguration classes (the Boot 2.7+ replacement for the EnableAutoConfiguration key), which are an unrelated mechanism that runs much later, during context refresh.
code
java · 10 lines// src/main/resources/META-INF/spring.factories
// (a plain text file — this is the registration)
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.DefaultsEnvironmentPostProcessor,\
com.example.SecretsEnvironmentPostProcessor
// WRONG registration file for an EPP — this only works for @AutoConfiguration classes:
// src/main/resources/META-INF/spring/
// org.springframework.boot.autoconfigure.AutoConfiguration.importsgo deeper
Know the file is META-INF/spring.factories and it isn't a @Component.
State the exact key, explain SpringFactoriesLoader/reflection, and distinguish spring.factories from AutoConfiguration.imports.
Explain aggregation across jars and the fixed set of constructor-injectable types Boot supplies.
Discuss registration-time implications for library authors shipping EPPs in starters and avoiding classpath ordering surprises.
## The registration mechanism: spring.factories Because an `EnvironmentPostProcessor` runs **before the ApplicationContext exists**, Spring can't find it by scanning for annotations — component scanning is a context-time activity. Instead Boot uses the older **`spring.factories`** discovery mechanism (`SpringFactoriesLoader`), which reads plain text files off the classpath at `META-INF/spring.factories`. You add an entry keyed by the SPI interface's fully-qualified name: ``` org.springframework.boot.env.EnvironmentPostProcessor=\ com.example.DefaultsEnvironmentPostProcessor,\ com.example.SecretsEnvironmentPostProcessor ``` The value is a comma-separated list of your implementation classes (backslash lets you wrap lines). Spring Boot reads **all** such files from **every** jar on the classpath and aggregates the implementations — that's how starters ship their own EPPs. ## What actually loads them Inside Boot, `EnvironmentPostProcessorApplicationListener` listens for `ApplicationEnvironmentPreparedEvent`. When it fires, it asks an `EnvironmentPostProcessorsFactory` (built from `spring.factories` via `EnvironmentPostProcessorsFactory.fromSpringFactories(...)`) to instantiate the classes, then calls `postProcessEnvironment(...)` on each in order. ## Why NOT @Component - No `ApplicationContext` yet → no `BeanFactory` → nothing to register beans in. - Component scanning is triggered during context refresh, long after the Environment is prepared. - If you annotate it `@Component`, Spring will happily create it *as a bean* later, but it will **never call `postProcessEnvironment`** for that purpose, so it silently does nothing useful for environment mutation. ## The big gotcha: it is NOT AutoConfiguration.imports Since Spring Boot 2.7, **auto-configuration classes** (`@AutoConfiguration`) are listed in `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`, replacing the old `EnableAutoConfiguration` key in `spring.factories`. People conflate the two, but: - `AutoConfiguration.imports` → only for `@AutoConfiguration` classes → runs during **context refresh**, after the Environment is finalized. - `EnvironmentPostProcessor` → still uses **`spring.factories`** → runs during **environment preparation**. Putting an EPP in `AutoConfiguration.imports` does nothing; putting an auto-config in the EPP key does nothing. ## Constructor injection of a few special types An EPP is instantiated by reflection, but Boot does allow a constructor that accepts a small fixed set of types it can supply itself — notably `DeferredLogFactory`, `org.apache.commons.logging.Log`, and `ConfigurableBootstrapContext`/`BootstrapContext`/`BootstrapRegistry`. This is not general DI; it's a hard-coded convenience for deferred logging and bootstrap context sharing (see the logging question). ## Ordering across multiple EPPs When several are registered, control order by implementing `Ordered` or annotating with `@Order` (lower value = earlier). Boot's own `ConfigDataEnvironmentPostProcessor` sits near the top of precedence.
- Where do @AutoConfiguration classes get registered since Spring Boot 2.7, and how is that different from EPP registration?In META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. That's a separate mechanism running at context-refresh time; EnvironmentPostProcessor still uses META-INF/spring.factories and runs during environment preparation.
- If a starter jar and your app both register EPPs, do all of them run?Yes. spring.factories files are aggregated across every jar on the classpath, so all registered EnvironmentPostProcessors run; use Ordered/@Order to control relative order.
saying these in an interview costs you the question
- Claiming you register an EnvironmentPostProcessor in AutoConfiguration.imports.
- Annotating it @Component and expecting postProcessEnvironment to be called.
- Believing only one EPP can exist per application.