You have a bean MyServiceImpl implements MyService, and Spring AOP proxies it. Why does @Autowired MyServiceImpl (by concrete class) fail, and how do you fix it?
answer
- proxy implements interface, extends Proxy
- not instanceof MyServiceImpl
- NoSuchBeanDefinition / ClassCastException
- inject the interface
- proxyTargetClass=true for CGLIB
basics
~20 sThe JDK proxy implements the interface MyService, not the class MyServiceImpl, so it isn't a MyServiceImpl. Injecting by the concrete class finds no matching bean (or a class-cast failure). Fix it by injecting the interface MyService.
solid answer
~40 sWhen Spring AOP applies a JDK dynamic proxy, the bean the container hands out is a runtime proxy that implements MyService but does NOT extend MyServiceImpl. So it's assignable to the interface but not to the concrete class. Autowiring by concrete type MyServiceImpl then fails — the proxy isn't of that type, so no matching candidate is found (you typically get a NoSuchBeanDefinitionException, or a ClassCastException if you cast). The correct fix is to depend on the interface: @Autowired MyService. That's the whole point of interface-based proxying and 'program to interfaces.' If you genuinely must inject the concrete class, you can force CGLIB proxying with @EnableAspectJAutoProxy(proxyTargetClass = true), since a CGLIB proxy is a subclass of MyServiceImpl and therefore assignable to it — but injecting the interface is the idiomatic answer.
code
java · 12 lines// FAILS: proxy is not a MyServiceImpl
@Autowired
private MyServiceImpl service; // NoSuchBeanDefinitionException
// WORKS: proxy implements MyService
@Autowired
private MyService service; // gets the JDK dynamic proxy
// If you MUST have the concrete type, force CGLIB globally:
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
class AopConfig { }go deeper
Recognize that injecting the interface is the safe choice.
Explain the type-assignability reason and the exceptions you'd see.
Contrast with CGLIB assignability and the proxyTargetClass escape hatch.
Weigh interface discipline vs forcing CGLIB across the codebase and its side effects.
## The setup ``` interface MyService { void doWork(); } @Service class MyServiceImpl implements MyService { ... } ``` Suppose an aspect (e.g. `@Transactional` or a custom `@Aspect`) applies to `MyServiceImpl`. Spring AOP therefore wraps the real bean in a **JDK dynamic proxy**. ## Why concrete-type injection fails The JDK proxy is generated by `java.lang.reflect.Proxy`. Its class: - **extends** `java.lang.reflect.Proxy` (fixed superclass), and - **implements** `MyService` (the interface you asked for). Critically, it does **not** extend `MyServiceImpl`. In Java's type system the proxy `instanceof MyService` is `true`, but `instanceof MyServiceImpl` is `false`. So: ``` @Autowired MyServiceImpl svc; // no bean matches this concrete type ``` At injection time Spring looks for a bean assignable to `MyServiceImpl`. The only candidate — the proxy — is **not** assignable, so you get a **`NoSuchBeanDefinitionException`** ("expected at least 1 bean"). If instead you obtain the bean as `Object` and cast, `(MyServiceImpl) bean` throws a **`ClassCastException`**. ## The fix: program to interfaces ``` @Autowired MyService svc; // proxy IS a MyService -> works ``` Injecting the interface is idiomatic and always works whether the bean is proxied or not, JDK or CGLIB. ## Alternative: force CGLIB If you truly need the concrete type (legacy code, no interface method you can move), switch to subclass-based proxying: ``` @EnableAspectJAutoProxy(proxyTargetClass = true) // or property: spring.aop.proxy-target-class=true ``` A **CGLIB** proxy *extends* `MyServiceImpl`, so it **is** assignable to it and concrete-type injection succeeds. Note this is a global switch and has its own caveats (final methods/classes can't be proxied, constructor runs, etc.). ## Related gotchas - The same reason explains why you can't inject a JDK-proxied bean into a field typed as the impl and then call impl-only public methods — those methods aren't on the interface, so they're not reachable through the proxy at all. - `AopUtils.isJdkDynamicProxy(bean)` / `AopProxyUtils.ultimateTargetClass(bean)` help you inspect what you actually got. ## Bottom line JDK proxy = interface type only. Depend on the interface, or force CGLIB if you must have the class.
- With proxyTargetClass=true, why does injecting the concrete class now work?CGLIB generates a runtime subclass of MyServiceImpl, so the proxy IS-A MyServiceImpl and is assignable to that type.
- A public method exists on MyServiceImpl but not on MyService. Is it advised by the JDK proxy?No. Only interface-declared methods are exposed by the JDK proxy, so a class-only method can't be intercepted (and can't be called through the interface reference).
saying these in an interview costs you the question
- Saying the JDK proxy is a subclass of MyServiceImpl.
- Claiming @Autowired matches by name so concrete type is fine.
- Thinking you can cast the proxy to MyServiceImpl safely.