面向切面编程 (Aspect-Oriented Programming)
面向切面编程(AOP)是一种编程范式,通过将横切关注点(如日志、安全、事务管理等)从核心业务逻辑中分离出来,提高代码的模块化程度。在 Valkyrie 中,AOP 通过 Effect 系统实现,提供了强大而灵活的切面编程能力。
基本概念
切面 (Aspect)
切面是横切关注点的模块化单元,包含了在特定连接点执行的代码。
连接点 (Join Point)
连接点是程序执行过程中可以插入切面代码的点,如方法调用、字段访问等。
通知 (Advice)
通知是在连接点执行的代码,包括前置通知、后置通知、环绕通知等。
Effect 系统中的 AOP
定义切面 Effect
valkyrie
# 定义日志切面 Effect
effect LogAspect {
before_method(class_name: String, method_name: String, args: [Any]): Unit
after_method(class_name: String, method_name: String, result: Any): Unit
on_error(class_name: String, method_name: String, error: Error): Unit
}
# 定义性能监控切面 Effect
effect MetricsAspect {
start_timing(operation: String): TimingContext
end_timing(context: TimingContext): Duration
record_metric(name: String, value: f64): Unit
}实现切面处理器
valkyrie
# 日志切面处理器
class ConsoleLogHandler {
handle LogAspect {
before_method(class_name, method_name, args) {
println(f"→ {class_name}.{method_name}({args})")
}
after_method(class_name, method_name, result) {
println(f"← {class_name}.{method_name} = {result}")
}
on_error(class_name, method_name, error) {
println(f"× {class_name}.{method_name} throws {error}")
}
}
}
# 性能监控处理器
class MetricsHandler {
private mut timings: {String: DateTime} = {}
handle MetricsAspect {
start_timing(operation) -> TimingContext {
let start_time = now()
self.timings[operation] = start_time
TimingContext { operation, start_time }
}
end_timing(context) -> Duration {
let end_time = now()
let duration = end_time - context.start_time
self.timings.remove(context.operation)
duration
}
record_metric(name, value) {
metrics_store.record(name, value)
}
}
}使用切面注解
valkyrie
class PaymentService {
# 使用多个切面
↯around(LogAspect, MetricsAspect)
process_payment(self, order_id: String, amount: Decimal) -> Receipt {
# 前置通知自动执行
perform LogAspect.before_method("PaymentService", "process_payment", [order_id, amount])
let timing_ctx = perform MetricsAspect.start_timing("payment_processing")
try {
# 核心业务逻辑
let receipt = self.do_payment(order_id, amount)
# 后置通知
perform LogAspect.after_method("PaymentService", "process_payment", receipt)
let duration = perform MetricsAspect.end_timing(timing_ctx)
perform MetricsAspect.record_metric("payment_duration", duration.as_millis())
receipt
}
.catch {
case _:
perform LogAspect.on_error("PaymentService", "process_payment", error)
raise error
}
}
private micro do_payment(self, order_id: String, amount: Decimal) -> Receipt {
# 实际支付逻辑
Receipt { id: generate_id(), order_id, amount, timestamp: now() }
}
}组合切面
valkyrie
# 定义复合切面
effect AuditAspect {
log_access(user_id: String, resource: String, action: String): Unit
log_data_change(table: String, record_id: String, old_value: Any, new_value: Any): Unit
}
# 安全审计服务
class SecurityAuditService {
↯around(LogAspect, AuditAspect)
update_user_profile(self, user_id: String, profile: UserProfile) -> Unit {
perform AuditAspect.log_access(user_id, "user_profile", "update")
let old_profile = self.get_user_profile(user_id)
# 更新逻辑
self.save_user_profile(user_id, profile)
perform AuditAspect.log_data_change("users", user_id, old_profile, profile)
}
}条件切面
valkyrie
# 定义条件切面 Effect
effect ConditionalAspect {
should_apply(context: AspectContext) -> bool
apply_advice(context: AspectContext): Unit
}
class DebugAspect {
handle ConditionalAspect {
should_apply(context) -> bool {
# 只在调试模式下应用
config.debug_mode && context.method_name.starts_with("debug_")
}
apply_advice(context) {
println(f"Debug: {context.class_name}.{context.method_name}")
}
}
}切面组合器
valkyrie
# 切面组合器
class AspectComposer {
static micro compose_aspects<T>(aspects: [Effect]) -> Effect {
effect ComposedAspect {
execute(context: AspectContext): T
}
handle ComposedAspect {
execute(context) -> T {
# 按顺序执行所有切面的前置通知
for aspect in aspects {
perform aspect.before(context)
}
try {
let result = context.proceed()
# 按逆序执行所有切面的后置通知
for aspect in aspects.reverse() {
perform aspect.after(context, result)
}
result
}
.catch {
case _:
# 执行异常通知
for aspect in aspects.reverse() {
perform aspect.on_error(context, error)
}
raise error
}
}
}
}
}高级特性
动态切面
valkyrie
# 动态切面管理器
class DynamicAspectManager {
private mut aspects: [Effect] = []
add_aspect(self, aspect: Effect) {
self.aspects.push(aspect)
}
remove_aspect(self, aspect: Effect) {
self.aspects.retain({ $a != aspect })
}
↯around(DynamicAspect)
execute_with_aspects<T>(self, operation: { -> T }) -> T {
let context = AspectContext::new()
# 动态应用所有注册的切面
for aspect in self.aspects {
perform aspect.before(context)
}
try {
let result = operation()
for aspect in self.aspects.reverse() {
perform aspect.after(context, result)
}
result
}
.catch {
case _:
for aspect in self.aspects.reverse() {
perform aspect.on_error(context, error)
}
raise error
}
}
}切面链
valkyrie
# 切面链处理
class AspectChain {
private aspects: [Effect]
private mut current_index: usize = 0
proceed<T>(mut self, context: AspectContext) -> T {
if self.current_index >= self.aspects.len() {
# 执行原始方法
context.target_method()
} else {
let aspect = self.aspects[self.current_index]
self.current_index += 1
# 执行当前切面
perform aspect.around(context, || { self.proceed(context) })
}
}
}最佳实践
1. 切面职责单一
每个切面应该只关注一个横切关注点,避免在单个切面中混合多种功能。
2. 合理使用切面顺序
当多个切面作用于同一个连接点时,要考虑它们的执行顺序。
3. 避免切面间的强耦合
切面之间应该保持独立,避免相互依赖。
4. 性能考虑
切面会增加方法调用的开销,在性能敏感的场景中要谨慎使用。
valkyrie
# 示例:完整的 AOP 应用
class OrderService {
↯around(LogAspect, MetricsAspect, SecurityAspect, TransactionAspect)
create_order(self, user_id: String, items: [OrderItem]) -> Order {
# 所有切面的前置通知会自动执行
# - 日志记录方法调用
# - 开始性能计时
# - 安全检查
# - 开始事务
let order = Order {
id: generate_order_id(),
user_id,
items,
status: OrderStatus.Pending,
created_at: now()
}
self.save_order(order)
# 所有切面的后置通知会自动执行
# - 提交事务
# - 记录安全日志
# - 记录性能指标
# - 记录方法返回值
order
}
}
# 使用示例
let order_service = new OrderService {}
let log_handler = new ConsoleLogHandler {}
let metrics_handler = new MetricsHandler {}
with log_handler, metrics_handler {
let order = order_service.create_order("user123", [
new OrderItem { product_id: "p1", quantity: 2 },
new OrderItem { product_id: "p2", quantity: 1 }
])
println(f"Created order: {order.id}")
}通过 Effect 系统实现的 AOP 提供了类型安全、组合性强、易于测试的切面编程能力,使得横切关注点的管理变得更加优雅和强大。