skip to content

What is an 'introduction' (inter-type declaration) in AOP, and how does it differ from advice?

level: seniorimportance: nice to knowfreq 30%

answer

  1. introduction = add a new interface to an object (mixin)
  2. advice changes behavior; introduction changes type
  3. @DeclareParents(value, defaultImpl) inside @Aspect
  4. proxy implements the extra interface, cast to use it
  5. AspectJ term: inter-type declaration (ITD)

basics

~20 s

An introduction adds a whole new interface and its implementation to an existing object, so the advised bean gains extra methods it never declared. Advice only wraps behavior around existing method calls; introduction adds new capabilities.

solid answer

~50 s

An **introduction** (AspectJ calls it an *inter-type declaration*) lets an aspect declare that advised objects should **implement additional interfaces** and supplies a default implementation for them. So a bean that only implements `OrderService` can be made to also implement, say, `Auditable`, gaining new methods at runtime through the proxy — without editing its source. In Spring you use `@DeclareParents` inside an `@Aspect`: it names the target types, the new interface, and a `defaultImpl` class. The proxy then exposes those extra methods, and callers can cast the bean to the introduced interface. The key difference: **advice modifies the behavior of existing join points (method executions)**, whereas **introduction changes the type/structure by adding new members**. Advice = 'do something around calls'; introduction = 'this object now also *is-a* X.' Introductions are rare in practice — mixins for tracking dirty state or adding management interfaces are typical uses.

code

java · 19 lines
java
@Aspect
@Component
public class LockMixin {
    // Introduce the Lockable interface onto every bean in com.app.domain
    @DeclareParents(
        value = "com.app.domain.*+",
        defaultImpl = DefaultLockable.class)
    private Lockable mixin;
}

public interface Lockable { void lock(); boolean isLocked(); }
public class DefaultLockable implements Lockable {
    private boolean locked;
    public void lock() { locked = true; }
    public boolean isLocked() { return locked; }
}

// Usage — the bean gained Lockable via the proxy, though its source never declared it:
// ((Lockable) someDomainBean).lock();

go deeper

for a junior

Likely won't know this term; recognizing 'adds a new interface' is enough.

for a middle

Should distinguish introduction (adds type/members) from advice (wraps behavior).

for a senior

Knows @DeclareParents mechanics and that only the proxy gains the interface.

for a principal

Can weigh introductions vs explicit composition and explain the proxy-vs-AspectJ ITD difference and where state lives.

## Introduction vs advice — two different powers AOP can affect a program in two dimensions: - **Advice** — *dynamic* crosscutting: it runs extra code **around existing method executions** (before/after/around). It changes **behavior**, not the type. - **Introduction** (a.k.a. **inter-type declaration**, ITD) — *static* crosscutting: it changes the **structure/type** of advised objects by **adding new interfaces, methods, or fields**. It makes an object *implement* something it didn't declare. So advice answers 'what happens when this method runs,' while introduction answers 'what type is this object / what members does it have.' ## How introduction works in Spring Spring supports introductions through **`@DeclareParents`** placed on a field inside an `@Aspect` class. Three parts: 1. **The `value`** — an AspectJ type pattern selecting the target beans (which classes get the new interface). 2. **`defaultImpl`** — the class that provides the implementation of the introduced interface. 3. **The field type** — the interface being introduced. ```java public interface Auditable { int getAccessCount(); void recordAccess(); } public class DefaultAuditable implements Auditable { private int count; public int getAccessCount() { return count; } public void recordAccess() { count++; } } @Aspect @Component public class AuditIntroduction { @DeclareParents( value = "com.app.service.*+", // targets: all types in service pkg defaultImpl = DefaultAuditable.class) // impl backing the new interface private Auditable auditable; // the introduced interface } ``` After this, any matched bean's **proxy also implements `Auditable`**, so a caller can do: ```java ((Auditable) orderService).recordAccess(); int n = ((Auditable) orderService).getAccessCount(); ``` The introduced state lives in the `defaultImpl` instance held by the proxy's introduction interceptor (`DelegatePerTargetObjectIntroductionInterceptor` / `DelegatingIntroductionInterceptor` under the hood), not in the original bean. ## Why the proxy makes this possible Because Spring wraps the bean in a proxy, the proxy can be made to implement *extra* interfaces beyond the target's own. Introductions therefore only work when a proxy is in play (Spring AOP) — the target class itself is untouched; only the proxy gains the interface. AspectJ can also do true inter-type declarations that add members to the class bytecode directly. ## Typical uses (and why they're rare) - **Mixins**: give many classes a common capability without a shared base class or editing each — e.g., making entities `Auditable`, `Lockable`, or `Comparable`. - **Dirty-tracking**: mark whether a domain object was modified. - **Management/monitoring interfaces**: expose a common admin interface across unrelated beans. They're uncommon because casting to an interface the source doesn't declare is opaque and surprising — most teams prefer explicit composition or a shared interface. Know the concept for interviews; reach for it sparingly. ## Contrast table | | Advice | Introduction | |---|---|---| | Kind of crosscutting | Dynamic (behavioral) | Static (structural) | | Affects | Existing method executions | The object's type/members | | Spring mechanism | `@Before/@After/@Around` | `@DeclareParents` | | Result | Extra code runs around calls | Object implements new interface | | Frequency in real code | Common | Rare |

  • Where does the state for an introduced interface live?
    In the defaultImpl instance held by the introduction interceptor on the proxy — not in the original target bean. The target class is untouched; only the proxy exposes the new interface and delegates to the impl.
  • Can you use introductions in pure Spring AOP without any proxy?
    No — Spring introductions rely on the proxy being able to implement the extra interface. Without a proxy there's nothing to add the interface to. AspectJ can add members to the class bytecode directly via inter-type declarations.

saying these in an interview costs you the question

  • Saying introduction is just another word for advice.
  • Claiming introduction modifies the original class's source or bytecode in Spring (it only augments the proxy).
  • Thinking you can call the introduced methods without casting to the new interface.

context