# How to Use the @Interceptor Annotation to Modify Extension Execution in DDDplus

> Learn to use the @Interceptor annotation in DDDplus to modify extension execution. Intercept extension point calls for pre-processing, post-processing, or short-circuiting without altering extension code.

- Repository: [Funky Gao/cp-ddd-framework](https://github.com/funkygao/cp-ddd-framework)
- Tags: how-to-guide
- Published: 2026-03-02

---

**Annotate a Spring bean with `@Interceptor` and implement `IExtensionInterceptor` to intercept extension point calls, enabling pre-processing, post-processing, or short-circuiting of extension execution without modifying the original extension code.**

The **@Interceptor annotation** in the DDDplus framework (also known as cp-ddd-framework) provides a powerful mechanism for applying cross-cutting concerns to extension points. By implementing the `IExtensionInterceptor` interface and marking your Spring component with this annotation, you can modify extension execution behavior—such as adding logging, transactions, or validation—while keeping extension implementations clean and focused on business logic.

## Understanding the @Interceptor Annotation and Interface Contract

The `@Interceptor` annotation is defined in `io.github.dddplus.annotation.Interceptor` and serves as a marker for Spring components that should participate in the extension invocation chain. To create a functional interceptor, you must implement the `IExtensionInterceptor` interface, which defines a single method: `Object intercept(InvocationContext ctx) throws Throwable`.

The `InvocationContext` object, defined in `io.github.dddplus.runtime.interceptor.InvocationContext`, provides access to the target extension, its arguments, and the critical `proceed()` method. Calling `ctx.proceed()` invokes the next interceptor in the chain or the actual extension implementation if no further interceptors exist.

## How the Framework Registers and Indexes Interceptors

The DDDplus framework handles interceptor lifecycle through a coordinated registration and indexing process during application startup.

### Registry Factory and Definition Registration

In `RegistryFactory`, the framework registers `InterceptorDef` as a valid registry entry type for the `@Interceptor` annotation. When Spring instantiates a bean annotated with `@Interceptor`, the `registerBean` method in `InterceptorDef` receives the bean instance.

### Bean Extraction and Indexing

The `InterceptorDef` extracts the underlying interceptor implementation using `InternalAopUtils.getTarget` to unwrap any Spring proxies, storing the result in `interceptorBean`. Subsequently, `InternalIndexer.index(this)` adds the interceptor definition to the global interceptor chain maintained by the runtime. This index is consulted whenever an extension point is invoked to determine which interceptors apply.

## Implementing a Custom Extension Interceptor

Creating a custom interceptor requires three steps: implementing the interface, annotating the class, and handling the invocation context.

Here is a complete example demonstrating transaction management around extension execution:

```java
package com.example.interceptors;

import io.github.dddplus.runtime.interceptor.IExtensionInterceptor;
import io.github.dddplus.runtime.interceptor.InvocationContext;
import org.springframework.stereotype.Component;
import io.github.dddplus.annotation.Interceptor;

@Component
@Interceptor
public class TransactionInterceptor implements IExtensionInterceptor {

    @Override
    public Object intercept(InvocationContext ctx) throws Throwable {
        // begin transaction
        startTx();
        try {
            Object ret = ctx.proceed();   // call the original extension
            // commit if successful
            commitTx();
            return ret;
        } catch (Throwable ex) {
            // rollback on error
            rollbackTx();
            throw ex;
        }
    }

    private void startTx() { /* ... */ }
    private void commitTx() { /* ... */ }
    private void rollbackTx() { /* ... */ }
}

```

When the framework invokes any extension point, the `TransactionInterceptor` automatically wraps the execution, ensuring transactional consistency without modifying the extension implementation itself.

## Controlling Interceptor Execution Order

When multiple interceptors exist, the DDDplus framework respects Spring's standard ordering mechanism. You can control interceptor precedence using Spring's `@Order` annotation or by implementing the `Ordered` interface.

The default order is defined by `InterceptorDef` if no explicit ordering is specified. Interceptors with lower order values execute earlier in the chain, allowing fine-grained control over which concerns (such as logging, security, or transactions) run first.

## Key Source Files in the Interceptor Lifecycle

Understanding the source code structure helps when debugging or extending the framework's interception capabilities:

- **`io.github.dddplus.annotation.Interceptor`** ([Interceptor.java](https://github.com/funkygao/cp-ddd-framework/blob/master/dddplus-runtime/src/main/java/io/github/dddplus/annotation/Interceptor.java)): Defines the annotation used to mark interceptor beans.

- **`io.github.dddplus.runtime.registry.InterceptorDef`** ([InterceptorDef.java](https://github.com/funkygao/cp-ddd-framework/blob/master/dddplus-runtime/src/main/java/io/github/dddplus/runtime/registry/InterceptorDef.java)): Registry entry that processes `@Interceptor` beans, unwraps proxies, and stores the interceptor instance.

- **`io.github.dddplus.runtime.registry.RegistryFactory`** ([RegistryFactory.java](https://github.com/funkygao/cp-ddd-framework/blob/master/dddplus-runtime/src/main/java/io/github/dddplus/runtime/registry/RegistryFactory.java)): Registers `InterceptorDef` as a valid handler for the `@Interceptor` annotation type.

- **`io.github.dddplus.runtime.registry.InternalIndexer`** ([InternalIndexer.java](https://github.com/funkygao/cp-ddd-framework/blob/master/dddplus-runtime/src/main/java/io/github/dddplus/runtime/registry/InternalIndexer.java)): Maintains the global interceptor chain index consulted during extension invocation.

- **`io.github.dddplus.runtime.interceptor.IExtensionInterceptor`** ([IExtensionInterceptor.java](https://github.com/funkygao/cp-ddd-framework/blob/master/dddplus-runtime/src/main/java/io/github/dddplus/runtime/interceptor/IExtensionInterceptor.java)): Interface defining the `intercept(InvocationContext)` method that all interceptors must implement.

- **`io.github.dddplus.runtime.interceptor.InvocationContext`** ([InvocationContext.java](https://github.com/funkygao/cp-ddd-framework/blob/master/dddplus-runtime/src/main/java/io/github/dddplus/runtime/interceptor/InvocationContext.java)): Context object providing access to extension metadata and the `proceed()` method to continue the invocation chain.

## Summary

- The **`@Interceptor` annotation** marks Spring beans that implement `IExtensionInterceptor` to participate in extension point interception.
- During startup, `RegistryFactory` and `InterceptorDef` register and unwrap interceptor beans, while `InternalIndexer` builds the global interceptor chain.
- At runtime, the framework invokes interceptors in order (respecting Spring's `@Order`) before calling the actual extension, allowing pre-processing, post-processing, or short-circuiting via `InvocationContext.proceed()`.
- This mechanism enables cross-cutting concerns like logging, transactions, and validation without modifying extension implementations.

## Frequently Asked Questions

### How does the @Interceptor annotation differ from Spring AOP?

While Spring AOP uses proxy-based aspect weaving, the **@Interceptor annotation** in DDDplus provides a framework-specific interception mechanism tailored for extension points. It integrates with the DDDplus registry system (`InterceptorDef` and `InternalIndexer`) to maintain a dedicated interceptor chain for extension invocations, offering more granular control over extension lifecycle events than generic AOP.

### Can multiple interceptors be applied to a single extension point?

Yes, you can define multiple interceptors for the same extension point. The framework maintains a global interceptor chain in `InternalIndexer` that applies to all extension invocations. When multiple interceptors exist, their execution order is determined by Spring's `@Order` annotation or the `Ordered` interface, with lower values executing earlier in the chain.

### What happens if an interceptor throws an exception?

If an interceptor throws an exception before calling `ctx.proceed()`, the exception propagates up the call stack and subsequent interceptors in the chain (as well as the target extension) are not executed. If the exception occurs after `proceed()` but during post-processing, it prevents later interceptors from processing the result and propagates to the caller. This behavior allows interceptors to short-circuit execution for validation or security failures.

### Is it possible to modify the arguments passed to the extension?

Yes, interceptors can inspect and modify the arguments available through the `InvocationContext` before calling `ctx.proceed()`. While the provided code examples focus on pre/post logic and transaction management, the `InvocationContext` interface provides access to extension metadata and invocation details, enabling argument validation, transformation, or enrichment before the actual extension implementation receives them.