What is an introduction in Spring AOP, and what does @DeclareParents do?
answer
- mixin / inter-type declaration
- @DeclareParents on an @Aspect field
- field type = introduced interface
- value = target pattern, defaultImpl = impl class
- proxy implements the new interface
basics
~20 sAn introduction adds a new interface (and a default implementation) to advised beans. @DeclareParents declares which interface to add, which beans get it, and which class implements it, so the proxy now implements that extra type.
solid answer
~40 sAn introduction (sometimes called an inter-type declaration or mixin) lets an aspect give matched beans a brand-new interface plus a default implementation, without editing those bean classes. In Spring you write it inside an @Aspect class with @DeclareParents on a field: the field's type is the interface to add, value is an AspectJ type pattern selecting target beans, and defaultImpl is the class supplying the behavior. Spring's proxy then implements that interface, so callers can cast the bean to it and call the new methods. Unlike @Before/@Around advice (which wraps existing method calls), an introduction changes the type of the bean by giving it capabilities it never declared, all through the proxy.
code
java · 24 linespublic interface UsageTracked {
void incrementUseCount();
int getUseCount();
}
public class DefaultUsageTracked implements UsageTracked {
private int useCount;
public void incrementUseCount() { useCount++; }
public int getUseCount() { return useCount; }
}
@Aspect
@Component
public class UsageTrackingAspect {
// Every bean under com.example.service now also implements UsageTracked
@DeclareParents(
value = "com.example.service.*+",
defaultImpl = DefaultUsageTracked.class)
public static UsageTracked mixin;
}
// Consumer casts the proxy to the introduced interface:
// UsageTracked ut = (UsageTracked) ctx.getBean("orderService");
// ut.incrementUseCount();go deeper
Know the one-line definition: introductions make a bean implement an extra interface via @DeclareParents.
Know the three attributes/parts: field type = interface, value = target pattern, defaultImpl = implementation class.
Explain the proxy mechanism and the casting requirement, plus the interfaces-only constraint in Spring AOP.
Weigh introductions against composition/delegation and articulate why they're rarely the right tool.
**Introductions (a.k.a. inter-type declarations or mixins)** are one of AOP's less common but distinctive features. Ordinary advice — `@Before`, `@After`, `@Around` — intercepts *existing* method calls on a bean. An **introduction** goes further: it makes advised beans *implement a new interface they never declared*, supplying the implementation from a separate class. This is how you bolt a cross-cutting capability (say, `IsModified`, `UsageTracked`, `Auditable`) onto many beans without touching their source. **The annotation: `@DeclareParents`.** You place it on a field inside an `@Aspect`-annotated class. It has two key attributes: - `value` — an **AspectJ type-matching pattern** naming the target types that should gain the interface, e.g. `"com.example.service.*+"`. The trailing `+` means "this type and all subtypes." - `defaultImpl` — the concrete class that provides the introduced methods. The **type of the annotated field is the interface being introduced**. So the declaration reads: "beans matching `value` now also implement *FieldType*, backed by an instance of *defaultImpl*." **How it works at runtime.** Spring AOP is proxy-based. When it creates the proxy for a matched bean, it makes that proxy implement the extra interface. Method calls against the introduced interface are routed to an instance of `defaultImpl`; calls against the target's own methods still go to the target. Because the *proxy* carries the new interface — not the raw target object — you must hold the proxied reference and cast it: `UsageTracked ut = (UsageTracked) applicationContext.getBean("myService");`. **Key constraints in Spring AOP:** 1. Spring can only introduce **interfaces**, not new concrete methods onto the target class directly (that would need full AspectJ weaving). The `defaultImpl` supplies the concrete behavior. 2. The introduction is **type-level**, not tied to a method execution — it applies to the whole bean/proxy, not a specific join point. 3. The `defaultImpl` instance is typically **one per advised bean/proxy**, so it can hold per-bean mixin state (e.g., a counter). **When to use it.** Rarely. Good fits: giving a family of beans a uniform auxiliary capability (change-tracking, usage metrics, tagging) where you don't want each class to implement boilerplate. In modern code, plain interfaces + composition or delegation usually read more clearly, so introductions are considered a niche tool. **Gotchas.** Because the capability lives on the proxy, self-invocation (`this.newMethod()`) inside the target won't work — the target doesn't know the interface exists. And you can only cast to the introduced type when you hold the proxy, not `this`.
- How does an introduction differ from @Before or @Around advice?Advice intercepts calls to methods that already exist on the bean. An introduction adds a whole new interface and implementation, changing the bean's type so callers can invoke methods the original class never declared.
saying these in an interview costs you the question
- Thinking @DeclareParents adds methods directly to the target class rather than to the proxy
- Saying you can call the introduced method as this.method() from inside the target
- Confusing introduction with simply implementing an interface on the class itself