What does @Configuration(proxyBeanMethods = false) do, and when would you set it?
answer
- default true = CGLIB proxy = full mode
- false = no proxy, lite call semantics
- faster startup + native-image/AOT friendly
- must inject deps as parameters, no self-calls
- Spring Boot auto-config uses false
basics
~20 sIt keeps @Configuration semantics but skips CGLIB enhancement, so the class isn't proxied. @Bean methods then behave like lite mode: direct inter-bean calls create new objects. Use it when methods don't call each other, to speed startup and help native images.
solid answer
~40 sproxyBeanMethods=false tells Spring not to CGLIB-enhance the @Configuration class. The class is still a configuration class (its @Bean methods are registered), but there's no generated subclass, so calling one @Bean method from another is a plain Java call that returns a new instance rather than the cached singleton — effectively lite-mode call semantics. The payoff is faster context startup (no proxy generation), a smaller memory/CGLIB footprint, and better compatibility with GraalVM native images and AOT processing, which dislike runtime bytecode generation. The trade-off: you must not rely on inter-bean method calls for shared singletons — express every dependency as a @Bean method parameter instead. Spring Boot's own auto-configuration classes set proxyBeanMethods=false for exactly these reasons, since they inject collaborators as parameters and never self-call.
code
java · 18 lines@Configuration(proxyBeanMethods = false) // no CGLIB enhancement
class HttpConfig {
@Bean
ObjectMapper objectMapper() {
return new ObjectMapper();
}
// Do NOT call objectMapper() here — it would build a new one.
// Inject it as a parameter to get the managed singleton.
@Bean
RestClient restClient(ObjectMapper objectMapper) {
return RestClient.builder()
.messageConverters(c -> c.add(
new MappingJackson2HttpMessageConverter(objectMapper)))
.build();
}
}go deeper
Know it disables the CGLIB proxy so @Bean methods behave like lite mode; don't call one @Bean method from another.
Explain the startup/footprint benefit and the parameter-injection requirement; recognize it on Boot auto-config.
Tie it to GraalVM native image / AOT processing and articulate the silent duplicate-instance risk when migrating.
Reason about it as the framework's default direction for AOT/native, weigh it against inter-bean ergonomics, and set org-wide conventions (parameter injection, lint for self-calls).
## What the flag controls `@Configuration` has an attribute `proxyBeanMethods`, default `true`. It controls whether Spring generates the **CGLIB subclass** that intercepts `@Bean` method calls (full-mode behavior). - `proxyBeanMethods = true` (default): **full mode**. CGLIB enhancement; inter-bean method calls return the cached singleton. - `proxyBeanMethods = false`: **no enhancement**. The class is still recognized as configuration and its `@Bean` methods are registered, but there is **no proxy**, so a direct call from one `@Bean` method to another executes the method body and yields a **new object** — the same call semantics as lite mode. Important nuance: even with `proxyBeanMethods=false`, the class keeps some full-mode niceties (e.g. it's still treated as a configuration class for validation and for allowing declarative features); the *only* thing you give up is the runtime interception of inter-bean calls. ## Why turn it off — benefits 1. **Faster startup:** no CGLIB subclass to generate/load per configuration class. Across many auto-configuration classes this is measurable. 2. **Lower footprint:** fewer generated classes and proxy instances. 3. **Native-image / AOT friendliness:** GraalVM native compilation and Spring's Ahead-Of-Time processing struggle with runtime-generated CGLIB subclasses. Skipping enhancement makes the config statically analyzable. This is a big reason Spring Boot 2.2+ set `proxyBeanMethods=false` on virtually all `@Configuration` in its auto-configuration. ## The cost — what you must give up With the proxy gone, **direct inter-bean method calls no longer return the singleton**. So this is a bug: ```java @Configuration(proxyBeanMethods = false) class Cfg { @Bean Foo foo() { return new Foo(); } @Bean Bar bar() { return new Bar(foo()); } // NEW Foo, not the bean! } ``` Fix by injecting the dependency as a parameter: ```java @Configuration(proxyBeanMethods = false) class Cfg { @Bean Foo foo() { return new Foo(); } @Bean Bar bar(Foo foo) { return new Bar(foo); } // container-supplied singleton } ``` Parameter injection works identically whether or not proxying is enabled, so it's the portable, recommended style. ## Decision guide - Use `proxyBeanMethods = false` when your `@Bean` methods **don't call each other** (they use parameter injection) — the common, clean case. Preferred for library/auto-configuration code and native builds. - Keep the default `true` when you **intentionally rely on inter-bean method calls** and want the singleton-identity safety net, and you're not targeting native image. ## Relationship to lite mode `proxyBeanMethods=false` gives you lite-mode *call semantics* while still being a declared `@Configuration`. The practical difference from a plain `@Component` with `@Bean` methods is mostly intent/validation; the inter-bean-call behavior is the same (no interception). ## Gotchas - Silent bug: turning the flag off on an existing config that *did* rely on inter-bean calls can suddenly create duplicate objects (e.g. two DataSources) without any error — only misbehavior. Audit for direct method calls before flipping it. - IDE/tests may still pass because each method individually works; the breakage is shared-identity, which is easy to miss.
- Why does Spring Boot set proxyBeanMethods=false on its auto-configuration classes?To cut startup time and memory by avoiding CGLIB proxy generation across many config classes, and to support GraalVM native images / AOT processing, which don't handle runtime bytecode generation well. Auto-config classes inject collaborators as parameters and never self-call, so they don't need interception.
- What subtle bug can appear if you flip an existing @Configuration to proxyBeanMethods=false?Any @Bean method that called another @Bean method directly now creates a new instance instead of reusing the singleton — e.g. two DataSources — with no error, only wrong runtime behavior. You must convert those calls to parameter injection first.
saying these in an interview costs you the question
- Saying proxyBeanMethods=false makes the class no longer a @Configuration (it stays a configuration class; only interception is dropped).
- Claiming it improves runtime request performance (the benefit is startup/footprint/native-image, not request latency).
- Thinking inter-bean method calls still return singletons with the flag off — they don't.
- Assuming Spring warns you when a self-call breaks singleton identity — it fails silently.