Skip to content

Spring AOP ProxyFactory:编程式创建代理的艺术 🎯

引言:为什么需要编程式创建代理?

在 Spring AOP 的世界里,我们通常通过注解(如 @Aspect)或 XML 配置来声明式地创建代理。但有时候,我们需要在运行时动态地创建代理,或者在不依赖 Spring IoC 容器的情况下使用 AOP 功能。这就是 ProxyFactory 发挥作用的地方!

NOTE

ProxyFactory 是 Spring AOP 框架的核心组件,它允许我们在运行时编程式地创建 AOP 代理,无需依赖 Spring IoC 容器。

核心概念理解 🧠

ProxyFactory 的设计哲学

ProxyFactory 的设计遵循了几个重要原则:

  1. 灵活性:可以在运行时动态配置代理
  2. 独立性:不依赖 Spring IoC 容器
  3. 可扩展性:支持多种类型的通知(Advice)和顾问(Advisor)

基础用法:创建你的第一个编程式代理 🚀

简单示例

让我们从一个简单的业务接口开始:

kotlin
// 定义业务接口
interface UserService {
    fun createUser(name: String): String
    fun deleteUser(id: Long): Boolean
}

// 业务接口实现
class UserServiceImpl : UserService {
    override fun createUser(name: String): String {
        println("创建用户: $name") 
        return "用户 $name 创建成功"
    }
    
    override fun deleteUser(id: Long): Boolean {
        println("删除用户: $id") 
        return true
    }
}
kotlin
import org.aopalliance.intercept.MethodInterceptor
import org.aopalliance.intercept.MethodInvocation

// 自定义方法拦截器
class LoggingInterceptor : MethodInterceptor {
    override fun invoke(invocation: MethodInvocation): Any? {
        val methodName = invocation.method.name
        val args = invocation.arguments
        
        println("🔍 [开始] 执行方法: $methodName, 参数: ${args.contentToString()}") 
        
        val startTime = System.currentTimeMillis()
        
        return try {
            // 执行原始方法
            val result = invocation.proceed() 
            val endTime = System.currentTimeMillis()
            
            println("✅ [完成] 方法: $methodName, 耗时: ${endTime - startTime}ms, 结果: $result") 
            result
        } catch (ex: Exception) {
            println("❌ [异常] 方法: $methodName, 异常: ${ex.message}") 
            throw ex
        }
    }
}

使用 ProxyFactory 创建代理

kotlin
import org.springframework.aop.framework.ProxyFactory

fun createUserServiceProxy(): UserService {
    // 1. 创建目标对象
    val target = UserServiceImpl()
    
    // 2. 创建 ProxyFactory,传入目标对象
    val factory = ProxyFactory(target) 
    
    // 3. 添加方法拦截器
    factory.addAdvice(LoggingInterceptor()) 
    
    // 4. 获取代理对象
    return factory.proxy as UserService 
}

// 使用示例
fun main() {
    val userService = createUserServiceProxy()
    
    // 调用代理方法
    val result = userService.createUser("张三")
    println("最终结果: $result")
    
    userService.deleteUser(1L)
}

TIP

ProxyFactory 会自动检测目标对象实现的接口,并为这些接口创建代理。如果目标对象没有实现接口,Spring 会使用 CGLIB 创建基于类的代理。

高级用法:多种通知类型的组合 🎨

不同类型的通知

Spring AOP 支持多种类型的通知,让我们看看如何在 ProxyFactory 中使用它们:

kotlin
import org.springframework.aop.MethodBeforeAdvice
import java.lang.reflect.Method

class SecurityBeforeAdvice : MethodBeforeAdvice {
    override fun before(method: Method, args: Array<out Any>, target: Any?) {
        println("🔐 [安全检查] 验证方法 ${method.name} 的访问权限") 
        
        // 模拟权限检查
        if (method.name.startsWith("delete")) {
            println("⚠️  [权限警告] 执行删除操作需要管理员权限") 
        }
    }
}
kotlin
import org.springframework.aop.AfterReturningAdvice
import java.lang.reflect.Method

class AuditAfterAdvice : AfterReturningAdvice {
    override fun afterReturning(returnValue: Any?, method: Method, args: Array<out Any>, target: Any?) {
        println("📝 [审计日志] 方法 ${method.name} 执行完成") 
        println("📝 [审计日志] 返回值: $returnValue")
        
        // 记录到审计系统
        recordAuditLog(method.name, args, returnValue)
    }
    
    private fun recordAuditLog(methodName: String, args: Array<out Any>, returnValue: Any?) {
        // 实际项目中这里会写入数据库或日志系统
        println("💾 [持久化] 审计记录已保存")
    }
}
kotlin
import org.springframework.aop.ThrowsAdvice
import java.lang.reflect.Method

class ExceptionHandlingAdvice : ThrowsAdvice {
    
    // 处理特定异常类型
    fun afterThrowing(method: Method, args: Array<out Any>, target: Any, ex: IllegalArgumentException) {
        println("🚨 [异常处理] 捕获到参数异常: ${ex.message}") 
        // 发送告警通知
        sendAlert("参数异常", method.name, ex.message)
    }
    
    // 处理所有异常
    fun afterThrowing(method: Method, args: Array<out Any>, target: Any, ex: Exception) {
        println("🚨 [异常处理] 捕获到异常: ${ex.javaClass.simpleName} - ${ex.message}") 
        // 记录错误日志
        logError(method.name, ex)
    }
    
    private fun sendAlert(type: String, methodName: String, message: String?) {
        println("📧 [告警] $type 在方法 $methodName 中发生: $message")
    }
    
    private fun logError(methodName: String, ex: Exception) {
        println("📋 [错误日志] 方法 $methodName 发生异常,已记录到错误日志系统")
    }
}

组合多种通知

kotlin
fun createAdvancedUserServiceProxy(): UserService {
    val target = UserServiceImpl()
    val factory = ProxyFactory(target)
    
    // 添加多种类型的通知
    factory.addAdvice(SecurityBeforeAdvice())      // 前置通知:安全检查
    factory.addAdvice(LoggingInterceptor())        // 环绕通知:日志记录
    factory.addAdvice(AuditAfterAdvice())          // 后置通知:审计日志
    factory.addAdvice(ExceptionHandlingAdvice())   // 异常通知:异常处理
    
    return factory.proxy as UserService
}

使用 Advisor:更精确的切面控制 🎯

什么是 Advisor?

Advisor 是 Spring AOP 中的一个重要概念,它将 Pointcut(切点)和 Advice(通知)结合在一起,提供更精确的切面控制。

kotlin
import org.springframework.aop.support.DefaultPointcutAdvisor
import org.springframework.aop.support.NameMatchMethodPointcut

fun createSelectiveProxy(): UserService {
    val target = UserServiceImpl()
    val factory = ProxyFactory(target)
    
    // 创建切点:只匹配以 "create" 开头的方法
    val pointcut = NameMatchMethodPointcut().apply {
        setMappedName("create*") 
    }
    
    // 创建 Advisor,将切点和通知结合
    val advisor = DefaultPointcutAdvisor(pointcut, LoggingInterceptor()) 
    
    // 添加 Advisor 而不是直接添加 Advice
    factory.addAdvisor(advisor) 
    
    return factory.proxy as UserService
}

// 测试选择性代理
fun testSelectiveProxy() {
    val userService = createSelectiveProxy()
    
    println("=== 测试 create 方法(会被拦截)===")
    userService.createUser("李四")
    
    println("\n=== 测试 delete 方法(不会被拦截)===")
    userService.deleteUser(2L)
}

IMPORTANT

使用 Advisor 可以实现更精确的切面控制,只对特定的方法应用通知,而不是对所有方法都应用。

实际业务场景应用 💼

场景1:动态数据源切换

kotlin
import org.aopalliance.intercept.MethodInterceptor
import org.aopalliance.intercept.MethodInvocation

// 数据源上下文
object DataSourceContext {
    private val contextHolder = ThreadLocal<String>()
    
    fun setDataSource(dataSource: String) {
        contextHolder.set(dataSource)
    }
    
    fun getDataSource(): String? = contextHolder.get()
    
    fun clear() {
        contextHolder.remove()
    }
}

// 数据源切换拦截器
class DataSourceInterceptor : MethodInterceptor {
    override fun invoke(invocation: MethodInvocation): Any? {
        val method = invocation.method
        val methodName = method.name
        
        // 根据方法名决定使用哪个数据源
        val dataSource = when {
            methodName.startsWith("find") || methodName.startsWith("get") -> "read-db"
            methodName.startsWith("save") || methodName.startsWith("update") || methodName.startsWith("delete") -> "write-db"
            else -> "default-db"
        }
        
        return try {
            DataSourceContext.setDataSource(dataSource)
            println("🔄 [数据源切换] 方法 $methodName 使用数据源: $dataSource") 
            
            invocation.proceed()
        } finally {
            DataSourceContext.clear()
        }
    }
}

// 使用示例
fun createDataSourceAwareProxy(target: Any): Any {
    val factory = ProxyFactory(target)
    factory.addAdvice(DataSourceInterceptor()) 
    return factory.proxy
}

场景2:方法执行时间监控

点击查看完整的性能监控实现
kotlin
import org.aopalliance.intercept.MethodInterceptor
import org.aopalliance.intercept.MethodInvocation
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicLong

// 性能统计数据
data class MethodStats(
    val methodName: String,
    val totalCalls: AtomicLong = AtomicLong(0),
    val totalTime: AtomicLong = AtomicLong(0),
    val maxTime: AtomicLong = AtomicLong(0),
    val minTime: AtomicLong = AtomicLong(Long.MAX_VALUE)
) {
    fun getAverageTime(): Double = if (totalCalls.get() > 0) totalTime.get().toDouble() / totalCalls.get() else 0.0
}

// 性能监控拦截器
class PerformanceMonitorInterceptor : MethodInterceptor {
    private val statsMap = ConcurrentHashMap<String, MethodStats>()
    
    override fun invoke(invocation: MethodInvocation): Any? {
        val methodName = "${invocation.method.declaringClass.simpleName}.${invocation.method.name}"
        val startTime = System.currentTimeMillis()
        
        return try {
            val result = invocation.proceed()
            val executionTime = System.currentTimeMillis() - startTime
            
            // 更新统计信息
            updateStats(methodName, executionTime) 
            
            if (executionTime > 1000) { // 超过1秒的慢查询
                println("🐌 [慢查询警告] 方法 $methodName 执行时间: ${executionTime}ms") 
            }
            
            result
        } catch (ex: Exception) {
            val executionTime = System.currentTimeMillis() - startTime
            updateStats(methodName, executionTime)
            throw ex
        }
    }
    
    private fun updateStats(methodName: String, executionTime: Long) {
        val stats = statsMap.computeIfAbsent(methodName) { MethodStats(it) }
        
        stats.totalCalls.incrementAndGet()
        stats.totalTime.addAndGet(executionTime)
        stats.maxTime.updateAndGet { maxOf(it, executionTime) }
        stats.minTime.updateAndGet { minOf(it, executionTime) }
    }
    
    // 获取性能报告
    fun getPerformanceReport(): String {
        val report = StringBuilder()
        report.appendLine("📊 === 性能监控报告 ===")
        
        statsMap.values.sortedByDescending { it.getAverageTime() }.forEach { stats ->
            report.appendLine("""
                🔍 方法: ${stats.methodName}
                   📞 调用次数: ${stats.totalCalls.get()}
                   ⏱️  平均耗时: ${"%.2f".format(stats.getAverageTime())}ms
                   ⚡ 最快耗时: ${stats.minTime.get()}ms
                   🐌 最慢耗时: ${stats.maxTime.get()}ms
                   🕐 总耗时: ${stats.totalTime.get()}ms
            """.trimIndent())
        }
        
        return report.toString()
    }
}

// 使用示例
fun createPerformanceMonitoredProxy(target: Any): Pair<Any, PerformanceMonitorInterceptor> {
    val monitor = PerformanceMonitorInterceptor()
    val factory = ProxyFactory(target)
    factory.addAdvice(monitor)
    
    return Pair(factory.proxy, monitor)
}

// 测试性能监控
fun testPerformanceMonitoring() {
    val (proxy, monitor) = createPerformanceMonitoredProxy(UserServiceImpl())
    val userService = proxy as UserService
    
    // 执行一些操作
    repeat(5) {
        userService.createUser("用户$it")
        Thread.sleep(100) // 模拟耗时操作
    }
    
    repeat(3) {
        userService.deleteUser(it.toLong())
        Thread.sleep(200) // 模拟耗时操作
    }
    
    // 打印性能报告
    println(monitor.getPerformanceReport())
}

ProxyFactory vs 声明式 AOP 对比 ⚖️

kotlin
// 使用 @Aspect 注解
@Aspect
@Component
class LoggingAspect {
    
    @Around("execution(* com.example.service.*.*(..))")
    fun logExecutionTime(joinPoint: ProceedingJoinPoint): Any? {
        val startTime = System.currentTimeMillis()
        
        return try {
            val result = joinPoint.proceed()
            val endTime = System.currentTimeMillis()
            println("方法执行时间: ${endTime - startTime}ms")
            result
        } catch (ex: Exception) {
            println("方法执行异常: ${ex.message}")
            throw ex
        }
    }
}

// 需要 Spring 容器管理
@Service
class UserService {
    // 自动被代理
}
kotlin
// 完全编程式控制
fun createDynamicProxy(target: Any, condition: Boolean): Any {
    val factory = ProxyFactory(target)
    
    // 根据运行时条件决定是否添加通知
    if (condition) { 
        factory.addAdvice(LoggingInterceptor())
    }
    
    // 可以动态添加更多通知
    if (isProductionEnvironment()) { 
        factory.addAdvice(PerformanceMonitorInterceptor())
    }
    
    return factory.proxy
}

// 不依赖 Spring 容器
val userService = createDynamicProxy(UserServiceImpl(), true)

选择指南

特性声明式 AOPProxyFactory
易用性✅ 简单易用⚠️ 需要编程
灵活性⚠️ 相对固定✅ 高度灵活
运行时控制❌ 编译时确定✅ 运行时决定
Spring 依赖✅ 需要容器❌ 可独立使用
性能✅ 优化更好⚠️ 略有开销

TIP

何时使用 ProxyFactory?

  • 需要运行时动态创建代理
  • 不想依赖 Spring IoC 容器
  • 需要根据条件选择性地应用通知
  • 在非 Spring 环境中使用 AOP 功能

最佳实践与注意事项 ⚠️

1. 接口 vs 类代理

kotlin
// ✅ 推荐:基于接口的代理
interface PaymentService {
    fun processPayment(amount: Double): String
}

class PaymentServiceImpl : PaymentService {
    override fun processPayment(amount: Double): String {
        return "支付 $amount 元成功"
    }
}

// ❌ 避免:基于类的代理(需要 CGLIB)
class DirectPaymentService {
    fun processPayment(amount: Double): String { 
        return "支付 $amount 元成功"
    }
}

WARNING

基于类的代理有以下限制:

  • 无法代理 final 类和方法
  • 需要默认构造函数
  • 性能略低于接口代理

2. 代理对象的生命周期管理

kotlin
class ProxyManager {
    private val proxyCache = mutableMapOf<String, Any>()
    
    fun getOrCreateProxy(key: String, target: Any): Any {
        return proxyCache.computeIfAbsent(key) { 
            val factory = ProxyFactory(target)
            factory.addAdvice(LoggingInterceptor())
            factory.proxy
        }
    }
    
    fun clearCache() {
        proxyCache.clear() 
    }
}

3. 异常处理最佳实践

kotlin
class SafeProxyFactory {
    
    fun <T> createSafeProxy(target: T, targetInterface: Class<T>): T {
        return try {
            val factory = ProxyFactory(target)
            factory.addAdvice(createSafeInterceptor())
            factory.setInterfaces(targetInterface) 
            
            @Suppress("UNCHECKED_CAST")
            factory.proxy as T
        } catch (ex: Exception) {
            println("创建代理失败,返回原始对象: ${ex.message}") 
            target // 降级处理
        }
    }
    
    private fun createSafeInterceptor() = MethodInterceptor { invocation ->
        try {
            invocation.proceed()
        } catch (ex: Exception) {
            println("方法执行异常,进行降级处理: ${ex.message}") 
            // 返回默认值或执行降级逻辑
            getDefaultValue(invocation.method.returnType)
        }
    }
    
    private fun getDefaultValue(returnType: Class<*>): Any? {
        return when (returnType) {
            String::class.java -> "默认值"
            Boolean::class.java -> false
            Int::class.java -> 0
            else -> null
        }
    }
}

总结 🎉

ProxyFactory 是 Spring AOP 框架中一个非常强大的工具,它为我们提供了编程式创建代理的能力。通过本文的学习,我们了解到:

核心优势 ✨

  1. 运行时灵活性:可以根据条件动态创建和配置代理
  2. 独立性:不依赖 Spring IoC 容器
  3. 精确控制:通过 Advisor 实现精确的切面控制
  4. 多样化通知:支持各种类型的通知组合

适用场景 🎯

  • 需要动态创建代理的场景
  • 非 Spring 环境中使用 AOP
  • 需要运行时条件控制的切面
  • 第三方库集成

关键要点 📝

IMPORTANT

  • 优先使用基于接口的代理
  • 合理管理代理对象的生命周期
  • 注意异常处理和降级策略
  • 在大多数应用中,声明式 AOP 仍然是首选

通过掌握 ProxyFactory,你将拥有更强大的 AOP 编程能力,能够在复杂的业务场景中灵活运用 Spring AOP 技术! 🚀