skip to content

What does @Configuration(proxyBeanMethods = false) do, and when would you set it?

level: seniorimportance: should knowfreq 48%

answer

  1. default true = CGLIB proxy = full mode
  2. false = no proxy, lite call semantics
  3. faster startup + native-image/AOT friendly
  4. must inject deps as parameters, no self-calls
  5. Spring Boot auto-config uses false

basics

~20 s

It 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 s

proxyBeanMethods=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
java
@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

for a junior

Know it disables the CGLIB proxy so @Bean methods behave like lite mode; don't call one @Bean method from another.

for a middle

Explain the startup/footprint benefit and the parameter-injection requirement; recognize it on Boot auto-config.

for a senior

Tie it to GraalVM native image / AOT processing and articulate the silent duplicate-instance risk when migrating.

for a principal

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.

context