Aspect-Oriented Programming (AOP) is a foundational technique that reduces code complexity by modularizing cross-cutting concerns—such as logging, security, transactions, response header injection, and global exception handling—away from core business logic.
While Spring AOP primarily focuses on proxying bean method invocations, Aspectran provides a highly optimized, pragmatic AOP architecture built upon two distinct pillars: the Activity Lifecycle and Selective Bean Proxying.
1. The Two Architectural Pillars of Aspectran AOP
Aspectran AOP offers two dimensions of join points and interception mechanisms tailored to their respective architectural purposes.
| Architectural Pillar | Target | Mechanism | Primary Use Cases |
|---|---|---|---|
| Activity Lifecycle AOP (Translet Lifecycle) | Activity (The entire request-processing flow) | Zero proxy overhead; the CoreActivity engine directly executes aspects according to lifecycle stages (Non-Proxy Core Interception) | Web security response headers, global character encoding and view dispatcher injection, pre/post-processing, authentication/authorization, global exception handling |
| Bean Proxy AOP (Method Interception) | Bean method invocations (JoinpointTargetType.METHOD) | Runtime dynamic proxy (AbstractBeanProxy, Javassist/JDK) intercepts methods annotated with @Advisable | Declarative database transactions, business method profiling, audit logging |
1.1. Activity Lifecycle AOP (Non-Proxy Core Interception)
In Aspectran, incoming client requests (Web, Daemon, Shell) are executed by an Activity instance. The Activity engine traverses predefined lifecycle stages from initiation to completion, directly invoking matched aspects without intermediate proxy overhead.
| Stage | Lifecycle Stage | Primary Tasks & Responsibilities |
|---|---|---|
| Stage 1 | Before Advice | Executes pre-processing logic, injects <settings> (encoding, view dispatcher) and security <headers>, validates authentication |
| Stage 2 | Translet Action Execution | Executes core business actions and process routines, generating response data |
| Stage 3 | After Advice | Performs post-processing on results, records audit logs |
| Stage 4 | Exception Handling (<exception>) | Catches exceptions and maps them to error view pages (<dispatch>) or RESTful JSON (<transform>) error responses |
| Stage 5 | Finally Advice | Always runs at the end regardless of success or failure to clean up resources and session states |
- Zero Overhead: Directly executed within the framework core flow without proxy creation or reflective overhead, ensuring maximum throughput.
- Structural Flow Control: Beyond simple method interception, it declaratively injects and manages request context (
Activity) attributes such as encoding, view dispatchers, security headers, and global exception screens.
1.2. Bean Proxy AOP (Selective Dynamic Proxying)
When applying AOP at the level of individual service methods, Aspectran employs dynamic proxies based on bytecode generation with Javassist (JavassistProxyBean) or standard JDK Dynamic Proxies (JdkDynamicProxyBean).
@AdvisableSelective Proxying (Performance Optimization):- Dynamic proxies do not indiscriminately intercept every method invocation.
- Pointcut evaluation and advice chains are triggered only for methods annotated with
@Advisable. - Unannotated regular methods bypass the proxy chain entirely, immediately delegating to the target method with zero proxy overhead.
2. Core Components of the <aspect> Rule
In Aspectran, aspects can be configured declaratively via <aspect> XML rules or Java annotations.
2.1. Fundamental Aspect Attributes
<aspect id="sampleAspect" order="0" isolated="true" disabled="false">
...
</aspect>
| Attribute | Description |
|---|---|
id | Unique identifier of the Aspect. |
order | Defines the execution precedence among multiple aspects. Lower integer values denote higher priority (default: Integer.MAX_VALUE). If two aspects have identical order values, the one declared first takes precedence. |
isolated | Configures Exception Isolation Mode (true/false). When isolated="true", any unhandled exception occurring inside the aspect’s advice will not halt the main request flow; an error log is recorded and the request proceeds normally. Ideal for non-critical cross-cutting concerns like statistics, monitoring, or external telemetry. |
disabled | When set to true, disables the aspect at runtime. |
2.2. Precision Joinpoint and Pointcut Control (<joinpoint>)
The <joinpoint> element precisely specifies where and when advice should be triggered.
<joinpoint target="activity">
methods: [
GET
POST
]
headers: [
"Accept=text/html"
"Origin"
]
pointcut: {
type: wildcard
+: /user/**@userService^get*
+: /order/**
-: /order/temp-*
}
</joinpoint>
| Attribute / Element | Default | Description |
|---|---|---|
target | activity | Specifies the join point target type. • activity: Intercepts the entire request lifecycle stages of Translets (Non-Proxy Core Interception).• method: Intercepts bean methods annotated with @Advisable via dynamic proxies (Selective Dynamic Proxying). |
methods | All | Restricts aspect execution to specific HTTP request methods (GET, POST, etc.). |
headers | All | Evaluates specific client request headers to determine aspect execution. |
pointcut | All | Granular filtering combining Translet names, Bean IDs, Class names, and Method patterns. |
a. Pointcut Expression Structure
Pointcuts are defined in APON format and follow this pattern:
\[\text{transletPattern}[\text{@beanOrClassPattern}][\text{^methodNamePattern}]\]A pointcut expression consists of three distinct segments delimited by @ and ^, allowing precise targeting combinations. Each segment is optional and can be omitted as needed.
- Delimiters:
@(Bean/Class Delimiter): Separates the Translet pattern from the Bean/Class pattern.^(Method Delimiter): Separates the Bean/Class pattern from the Method pattern.
- Segment Components:
- Translet Pattern (Pre-
@): Matches the target Translet name or request URI path pattern (e.g.,/user/**,/api/v1/*). If omitted, all Translets are targeted. - Bean ID Pattern (Post-
@, Pre-^): Matches the target Bean ID pattern (e.g.,@userService,@*Service). Specifying an identifier without any prefix directive is interpreted as a Bean ID. - Class Pattern (Post-
@class:, Pre-^): Matches fully-qualified package/class name patterns. To target class types, theclass:directive prefix is required (e.g.,@class:com.mycompany.service.*,@class:*.UserServiceImpl). This is essential for targeting anonymous beans (beans without an ID) or all implementations of a specific package/interface. - Method Pattern (Post-
^): Matches the target method name pattern (e.g.,^get*,^save*,^execute). If omitted, all methods of the target bean or the entire Activity lifecycle are targeted.
- Translet Pattern (Pre-
| Pattern Format | Pattern Example | Target Description |
|---|---|---|
transletPattern | /order/** | Targets the entire Activity lifecycle of all Translets under /order/ |
transletPattern@beanId | /user/*@userDao | Targets the userDao bean executing within /user/* Translets |
transletPattern@class:className | /api/**@class:com.mycompany.dao.* | Targets beans of class types in that package within /api/** Translets |
transletPattern@beanId^methodName | /user/*@userService^get* | Targets methods starting with get on the userService bean within /user/* Translets |
transletPattern@class:className^methodName | /translet@class:hello.Simplest^hello* | Targets methods starting with hello on the hello.Simplest class within /translet requests |
@beanId | @orderService | Targets the orderService bean across all Translets |
@class:className | @class:com.mycompany.service.* | Targets beans under the com.mycompany.service package across all Translets |
@beanId^methodName | @orderService^process* | Targets methods starting with process on the orderService bean across all Translets |
@class:className^methodName | @class:com.mycompany.service.*Service^process* | Targets methods starting with process on all Service classes across all Translets |
@^methodName | @^execute* | Targets methods starting with execute on all beans regardless of Translet or bean type |
- Advanced Pattern Matching Features:
- Single-Segment Wildcard (
*): Matches zero or more characters within a single segment excluding delimiters (/or.) (e.g.,/api/*matches/api/usersbut not/api/v1/users;com.example.*Servicematchescom.example.UserService). - Multi-Segment Wildcard (
**): Matches across multiple path or package hierarchy levels including delimiters (e.g.,/user/**matches/user/listand/user/a/b/c;@class:com.mycompany.**Servicematchescom.mycompany.order.OrderService). - Single-Character Wildcard (
?): Matches exactly one arbitrary character. - Multi-Pattern OR Matching (
|): Connects multiple patterns using the pipeline (|) symbol to evaluate OR conditions within a single rule (e.g.,+: /user/**|/order/**@userService|orderService^get*|find*). - Hierarchical Path and Namespace Matching: Translet names use the slash (
/) delimiter, while Bean IDs and class names use the dot (.) delimiter for structured matching.
- Single-Segment Wildcard (
b. Include (+:) and Exclude (-:) Rules with Top-Down Evaluation
Aspectran evaluates pointcut rules sequentially in top-down declaration order:
+:(Include): Includes matched targets into the AOP execution scope.-:(Exclude): Excludes matched targets from the AOP execution scope.
💡 Note (Order-based Granular Control): You can easily define complex filtering by including a broad range at the top (
+:) and excluding specific exceptions underneath (-:).
Wildcard Pointcut Example (type: wildcard):
<joinpoint>
pointcut: {
type: wildcard
+: /api/** # 1. Include all endpoints under /api/
-: /api/auth/login # 2. Exclude login endpoint from auth check
-: /api/health-check # 3. Exclude health check endpoint
+: /admin/**@adminService^* # 4. Include adminService methods under /admin/
-: /admin/**@adminService^get* # 5. Exclude read-only methods starting with 'get'
}
</joinpoint>
Regular Expression Pointcut Example (type: regexp): When using regular expressions, separate include and exclude blocks allow strict regex matching.
<joinpoint>
pointcut: {
type: regexp
include: {
translet: "^/api/v[1-9]/.*"
bean: "^(user|order)Service$"
method: "^(create|update|delete).*"
}
exclude: {
translet: "^/api/v.*/temp-.*"
bean: "^.*TestBean$"
}
}
</joinpoint>
c. Request Method (methods) Filtering
Restricts aspect execution to specific HTTP request methods such as GET, POST, PUT, DELETE, or PATCH.
d. Request Header (headers) Filtering
Controls aspect execution based on client request headers:
- Header Presence:
"Origin"(Matches if the header exists) - Exact Value Matching:
"X-Requested-With=XMLHttpRequest"(Matches if the header equals the value) - Negative Comparison:
"Accept!=application/json"(Matches if the header does not contain the value) - Complex Media Type Matching (Web Environment): Analyzes complex browser
Acceptheaders (e.g.,text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8) with quality factors (q-values) to accurately determine if it is an HTML page request ("Accept=text/html").
2.3. Settings Context Injection (<settings>)
The <settings> element injects configuration parameters directly into the matched Translet’s Activity context, avoiding redundant per-Translet declarations.
<aspect id="webTransletSettings">
<joinpoint>
pointcut: {
+: /**
}
</joinpoint>
<settings>
<setting name="characterEncoding" value="utf-8"/>
<setting name="viewDispatcher" value="thymeleafViewDispatcher"/>
</settings>
</aspect>
characterEncoding: Sets the default request/response character encoding.viewDispatcher: Assigns the defaultViewDispatcherbean for the matching scope.
2.4. Advice Types and Composition (<advice>)
Advice defines the concrete logic executed at a join point. Aspectran supports 5 standard advice types:
| Advice Type | Execution Timing | Primary Use Cases |
|---|---|---|
before | Prior to join point execution | Input validation, security verification, response header injection |
after | After successful join point execution | Result data enrichment, audit logging |
around | Surrounds join point execution | Execution profiling, transaction boundaries (begin & commit) |
thrown | Upon exception | Error logging, transaction rollback, alerting |
finally | Always executed at the end | Resource cleanup, session cleanup, ThreadLocal clearing |
Inside <advice>, you can configure bean method invocations (<invoke>), action routines (<action>), and declarative response header injection (<headers>):
<advice bean="securityAdvice">
<before>
<!-- Declarative response header injection -->
<headers>
<item name="X-Frame-Options">SAMEORIGIN</item>
<item name="X-Content-Type-Options">nosniff</item>
<item name="X-XSS-Protection">1; mode=block</item>
</headers>
<!-- Advice bean method execution -->
<invoke method="checkAuthentication"/>
</before>
</advice>
2.5. Global Exception Handling (<exception>)
Defining an <exception> element within an aspect allows catching specific exceptions globally and mapping them to error view pages or structured RESTful JSON responses.
<aspect id="globalExceptionAspect">
<joinpoint>
pointcut: {
+: /**
}
</joinpoint>
<exception>
<!-- Maps specific exception to a dedicated error page -->
<thrown type="com.mycompany.common.exception.UserNotFoundException">
<dispatch name="error/user-not-found" contentType="text/html" encoding="UTF-8"/>
</thrown>
<!-- Generic fallback for unhandled exceptions -->
<thrown type="java.lang.Throwable">
<action bean="errorLogger" method="logError"/>
<dispatch name="error/500" contentType="text/html" encoding="UTF-8"/>
</thrown>
</exception>
</aspect>
Differences Between <advice><thrown> and <exception><thrown>
When defining behavior for raised exceptions, Aspectran provides two distinct mechanisms: <thrown> inside <advice> and <thrown> inside <exception>. They differ fundamentally in purpose and exception propagation:
| Category | <advice><thrown> (Exception Handling Advice) | <exception><thrown> (Global Exception Response Mapping) |
|---|---|---|
| Primary Purpose | Executes supplementary logic upon exceptions (e.g., error logging, transaction rollback, alerting) | Catches raised exceptions and maps them to dedicated error view pages or JSON error responses |
| Exception Propagation | Executes advice logic and continues to propagate (rethrow) the exception upward | Completely catches and handles the exception, returning a normal error response to the client |
| Available Actions | Bean method invocations (<invoke>), Action executions (<action>), Header injection (<headers>) | View dispatching (<dispatch>), Data transformations (<transform>), Action executions (<action>) |
| Annotation Equivalent | Advice methods annotated with @ExceptionThrown | Translet/Aspect exception handling rule mappings |
3. Annotation-Based AOP Configuration
Aspectran allows full AOP configuration using pure Java classes and annotations without XML.
3.1. Core AOP Annotations
| Annotation | Description | Key Attributes |
|---|---|---|
@Aspect | Declares a class as an Aspect (used alongside @Component). | id, order, isolated, disabled |
@Joinpoint | Configures pointcut matching criteria. | pointcut, target, methods, headers |
@Before | Designates a Before advice method. | - |
@After | Designates an After advice method. | - |
@Around | Designates an Around advice method. | - |
@Finally | Designates a Finally advice method. | - |
@ExceptionThrown | Designates an Exception advice method. | value (Target exception class) |
@Settings | Injects settings into the Activity context. | name, value |
@Advisable | Marks a bean method as a target for Bean Proxy AOP. | - |
3.2. Annotation-Based Aspect Implementation Example
package com.aspectran.demo.aspect;
import com.aspectran.core.activity.Activity;
import com.aspectran.core.activity.Translet;
import com.aspectran.core.component.bean.annotation.After;
import com.aspectran.core.component.bean.annotation.Aspect;
import com.aspectran.core.component.bean.annotation.Before;
import com.aspectran.core.component.bean.annotation.Component;
import com.aspectran.core.component.bean.annotation.ExceptionThrown;
import com.aspectran.core.component.bean.annotation.Finally;
import com.aspectran.core.component.bean.annotation.Joinpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component
@Aspect(id = "loggingAspect", order = 1, isolated = true)
@Joinpoint(
pointcut = {
"+: /api/**",
"-: /api/health-check"
}
)
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@Before
public void beforeRequest(Translet translet) {
logger.info("[Request Start] {} {}", translet.getRequestMethod(), translet.getRequestName());
}
@After
public void afterRequest(Translet translet) {
logger.info("[Request Success] {}", translet.getRequestName());
}
@ExceptionThrown(Exception.class)
public void onError(Translet translet) {
Throwable e = translet.getRaisedException();
logger.error("[Request Error] {} - {}", translet.getRequestName(), e.getMessage(), e);
}
@Finally
public void onFinally(Translet translet) {
// Perform resource cleanup
}
}
4. Production Best Practice Patterns
Pattern 1: Global Web Security and Environment Auto-Injection
Automatically injects security response headers (CSP, X-Frame-Options) and default ViewDispatcher settings for all browser HTML requests.
<aspectran>
<!-- 1. Register View Dispatcher Bean -->
<bean id="thymeleafViewDispatcher" class="com.aspectran.thymeleaf.view.ThymeleafViewDispatcher">
<argument>#{thymeleafEngine}</argument>
<property name="contentType">text/html</property>
</bean>
<!-- 2. Global Web Translet Settings Aspect -->
<aspect id="webTransletSettings">
<joinpoint>
pointcut: {
+: /**
}
</joinpoint>
<settings>
<setting name="characterEncoding" value="utf-8"/>
<setting name="viewDispatcher" value="thymeleafViewDispatcher"/>
</settings>
<advice>
<before>
<headers>
<item name="X-Frame-Options">SAMEORIGIN</item>
<item name="X-Content-Type-Options">nosniff</item>
<item name="X-XSS-Protection">1; mode=block</item>
<item name="Referrer-Policy">strict-origin-when-cross-origin</item>
</headers>
</before>
</advice>
</aspect>
<!-- 3. HTML Browser Request Security Aspect -->
<aspect id="htmlWebSecuritySettings">
<joinpoint>
headers: [
"Accept=text/html"
]
pointcut: {
+: /**
}
</joinpoint>
<advice>
<before>
<headers>
<item name="Content-Security-Policy">default-src 'self'; script-src 'self' 'unsafe-inline' cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' fonts.googleapis.com; font-src 'self' fonts.gstatic.com;</item>
</headers>
</before>
</advice>
</aspect>
</aspectran>
Pattern 2: Declarative Transaction Management (SqlSessionAdvice + @Advisable)
Completely decouples MyBatis SqlSession lifecycle management (open, commit, rollback, close) from business logic.
1. Transaction Aspect Configuration (mybatis-context.xml):
<!-- 1. SqlSessionAdvice Bean Definition -->
<bean id="sqlSessionTxAdvice" class="com.aspectran.mybatis.SqlSessionAdvice" scope="prototype">
<argument>#{sqlSessionFactory}</argument>
</bean>
<!-- 2. Transaction Aspect Definition -->
<aspect id="txAspect" order="0">
<joinpoint>
pointcut: {
+: **@simpleSqlSession
}
</joinpoint>
<advice bean="sqlSessionTxAdvice">
<before>
<invoke method="open"/>
</before>
<after>
<invoke method="commit"/>
</after>
<finally>
<invoke method="close"/>
</finally>
</advice>
</aspect>
2. Transaction Usage in the Service Layer:
@Component
public class OrderService {
private final SimpleSqlSession sqlSession;
@Autowired
public OrderService(SimpleSqlSession sqlSession) {
this.sqlSession = sqlSession;
}
public void processOrder(Order order) {
// Calling sqlSession methods automatically triggers txAspect to handle the transaction
sqlSession.insert("app.demo.mapper.OrderMapper.insertOrder", order);
sqlSession.update("app.demo.mapper.ItemMapper.updateStock", order.getItemId());
}
}
Pattern 3: RESTful API Performance Profiling (Around Advice)
Monitors slow API requests using an Around advice with exception isolation.
package com.aspectran.demo.aspect;
import com.aspectran.core.activity.Translet;
import com.aspectran.core.component.bean.annotation.Around;
import com.aspectran.core.component.bean.annotation.Aspect;
import com.aspectran.core.component.bean.annotation.Component;
import com.aspectran.core.component.bean.annotation.Joinpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component
@Aspect(id = "profilingAspect", isolated = true)
@Joinpoint(pointcut = "+: /api/**")
public class ProfilingAspect {
private static final Logger logger = LoggerFactory.getLogger(ProfilingAspect.class);
@Around
public Object profile(Translet translet) throws Throwable {
long startTime = System.currentTimeMillis();
try {
// Proceed with the request flow
return null;
} finally {
long elapsedTime = System.currentTimeMillis() - startTime;
if (elapsedTime > 500) {
logger.warn("[SLOW QUERY/API] {} took {} ms", translet.getRequestName(), elapsedTime);
}
}
}
}
5. Conclusion
Aspectran AOP replaces bulky proxy configurations with two finely-tuned mechanisms: Framework Core Lifecycle Interception (Activity) and Selective Bean Proxying (@Advisable).
- Activity Lifecycle AOP: Provides zero-overhead declarative control over global environment settings, security headers, authentication, and exception routing.
- Bean Proxy AOP: Selectively applies dynamic proxies only where necessary, efficiently managing transactions and business method profiling.
This dual-pillar architecture empowers developers to build clean, maintainable, and high-performance enterprise applications with minimal configuration overhead.