How to Use the @Governance Annotation for Managing Extension Lifecycle in cp-ddd-framework
The @Governance annotation activates service-level governance for public methods in BaseRouter subclasses, wrapping extension invocations in an AOP interceptor that handles invocation counting, availability monitoring, performance profiling, and exception-impact control.
The funkygao/cp-ddd-framework provides a DDDplus runtime for orchestrating domain extensions through routers. The @Governance annotation serves as a single point of control to monitor and protect the entire extension chain lifecycle, from router entry to result aggregation.
What Is the @Governance Annotation?
The @Governance annotation is defined in annotation/Governance.java as a method-level marker used exclusively on public methods of BaseRouter subclasses. It accepts a single boolean attribute profiler() that defaults to true, allowing developers to toggle performance profiling for specific router methods.
When present, the annotation signals the framework to apply an AOP interceptor that wraps the actual extension invocation. This interceptor is implemented primarily within ExtensionInvocationHandler, which acts as a dynamic proxy responsible for executing extensions while collecting lifecycle metrics.
How @Governance Manages Extension Lifecycle
The governance interceptor manages four critical lifecycle concerns during extension execution.
Invocation Counting and Availability Monitoring
Each call to a @Governance-annotated method triggers the ExtensionInvocationHandler to increment an invocation counter before delegating to the real extension. If the extension throws an exception, the handler logs the failure and decreases the availability metric, providing real-time health indicators for domain services.
Performance Profiling and Timeouts
When profiler() is true (the default), the handler captures start and end timestamps around the extension execution. For methods requiring timeout protection, the framework utilizes ExtensionInvocationHandler.invokeExtensionMethodWithTimeout, which executes the method via a timed Future. If the execution exceeds the configured threshold, an ExtTimeoutException is thrown and recorded as a timeout event in the profiler metrics.
Exception-Impact Control
The framework provides the IExceptionIgnoreProfilerError marker interface to fine-tune error reporting. When an exception implements this interface, the ExtensionInvocationHandler recognizes it via an instanceof check and excludes it from penalizing the profiler’s availability metric. This allows business exceptions to propagate without distorting service health statistics.
Implementation Architecture
The governance mechanism relies on several key components within the dddplus-runtime module:
annotation/Governance.java: Defines the annotation and itsprofilerattribute.runtime/BaseRouter.java: The abstract base class whose public methods can be annotated; providesforEachExtensionfor extension discovery viaInternalIndexer.runtime/ExtensionInvocationHandler.java: The dynamic proxy that intercepts extension calls, implements timeout handling viainvokeExtensionMethodWithTimeout, and records profiling data.runtime/IExceptionIgnoreProfilerError.java: Marker interface to exempt specific exceptions from error metrics.
During application startup, a Spring AOP aspect (referenced in tests as GovernanceAspect) detects @Governance annotations and weaves the interception logic around the target methods.
Practical Code Examples
Basic Router with Governance
The following example from BarRouter.java demonstrates standard usage:
// src/test/java/io/github/dddplus/runtime/registry/mock/router/BarRouter.java
@Router(domain = FooDomain.CODE)
@Slf4j
public class BarRouter extends BaseRouter<IFooExt, FooModel> {
@LogInfo(in = true, out = true)
@Governance // enable profiling (default = true)
public String submit(FooModel model) {
int result = forEachExtension(model, IReducer.stopOnFirstMatch(
i -> i > 1)).execute(model);
return String.valueOf(result);
}
@Governance(profiler = false) // disable profiling for this method
public void nonProfiledMethod(FooModel model) {
// business logic without metrics collection
}
}
Governance on Domain Policies
The annotation also applies to policy methods, as shown in TriggerPolicy.java:
// src/test/java/io/github/dddplus/runtime/registry/mock/policy/TriggerPolicy.java
@Policy
public class TriggerPolicy implements IPolicy {
@Governance // governance also works on policies
public void afterInsert(FooModel model) {
log.info("foo trigger");
}
}
Timeout Configuration with Governance
To utilize timeout protection with governance profiling:
@Governance(profiler = true)
public String timedSubmit(FooModel model) {
// Timeout configured via forEachExtension
return forEachExtension(model, IReducer.allOf())
.timeout(500, TimeUnit.MILLISECONDS)
.execute(model);
}
If execution exceeds the threshold, ExtensionInvocationHandler.invokeExtensionMethodWithTimeout throws ExtTimeoutException and records the timeout in profiler metrics.
Summary
- The
@Governanceannotation activates service-level governance for public methods inBaseRoutersubclasses and policy implementations. - It wraps extension invocations in an AOP interceptor implemented by
ExtensionInvocationHandler, providing unified lifecycle management. - Key capabilities include invocation counting, availability monitoring via error-rate tracking, performance profiling with timeout enforcement, and exception-impact control through
IExceptionIgnoreProfilerError. - The
profiler()attribute allows selective enablement of performance metrics per method. - Governance integrates seamlessly with the DDDplus runtime extension discovery mechanism via
InternalIndexerand result aggregation throughIReducer.
Frequently Asked Questions
What is the difference between @Governance and standard Spring AOP?
@Governance is a domain-specific annotation within the cp-ddd-framework that signals the framework's internal ExtensionInvocationHandler to apply DDDplus-specific governance concerns—such as extension timeout handling, availability metrics for domain extensions, and the IExceptionIgnoreProfilerError exception filtering. While it leverages Spring AOP mechanisms (as seen in the test suite's GovernanceAspect), it specifically targets the lifecycle of extensions orchestrated by BaseRouter rather than generic cross-cutting concerns.
Can I use @Governance on private methods or classes other than BaseRouter?
No. The @Governance annotation is designed exclusively for public methods of BaseRouter subclasses (routers) and methods of classes annotated with @Policy. The framework's AOP pointcuts and the ExtensionInvocationHandler proxy mechanism expect the annotated method to be part of the router's public API that orchestrates extensions via forEachExtension. Applying it to private methods or non-router classes will result in the annotation being ignored because the interception logic cannot bind to those targets.
How does the profiler handle timeouts and where is the threshold configured?
When profiler() is true (default), the ExtensionInvocationHandler measures execution latency and can enforce timeouts via invokeExtensionMethodWithTimeout. The timeout threshold is not configured directly on the @Governance annotation itself; instead, it is specified when calling forEachExtension(...).timeout(duration, timeUnit) within the router method. If the extension execution exceeds this threshold, the handler throws ExtTimeoutException, which is recorded as a timeout event in the profiler metrics without necessarily decreasing availability, allowing operators to identify slow extensions independently of error rates.
What exceptions should implement IExceptionIgnoreProfilerError?
Exceptions that represent expected business outcomes or control-flow mechanisms—rather than service failures—should implement IExceptionIgnoreProfilerError. When an extension throws such an exception, the ExtensionInvocationHandler detects the marker interface and excludes the exception from the availability error-rate calculation. This prevents legitimate business exceptions (such as validation failures, business rule violations, or expected "not found" scenarios) from distorting the service health metrics, ensuring that the profiler reflects only genuine system or unexpected errors that impact service availability.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →