Appearance
Spring AOP ProxyFactory:编程式创建代理的艺术 🎯
引言:为什么需要编程式创建代理?
在 Spring AOP 的世界里,我们通常通过注解(如 @Aspect
)或 XML 配置来声明式地创建代理。但有时候,我们需要在运行时动态地创建代理,或者在不依赖 Spring IoC 容器的情况下使用 AOP 功能。这就是 ProxyFactory
发挥作用的地方!
NOTE
ProxyFactory
是 Spring AOP 框架的核心组件,它允许我们在运行时编程式地创建 AOP 代理,无需依赖 Spring IoC 容器。
核心概念理解 🧠
ProxyFactory 的设计哲学
ProxyFactory
的设计遵循了几个重要原则:
- 灵活性:可以在运行时动态配置代理
- 独立性:不依赖 Spring IoC 容器
- 可扩展性:支持多种类型的通知(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)
选择指南
特性 | 声明式 AOP | ProxyFactory |
---|---|---|
易用性 | ✅ 简单易用 | ⚠️ 需要编程 |
灵活性 | ⚠️ 相对固定 | ✅ 高度灵活 |
运行时控制 | ❌ 编译时确定 | ✅ 运行时决定 |
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 框架中一个非常强大的工具,它为我们提供了编程式创建代理的能力。通过本文的学习,我们了解到:
核心优势 ✨
- 运行时灵活性:可以根据条件动态创建和配置代理
- 独立性:不依赖 Spring IoC 容器
- 精确控制:通过 Advisor 实现精确的切面控制
- 多样化通知:支持各种类型的通知组合
适用场景 🎯
- 需要动态创建代理的场景
- 非 Spring 环境中使用 AOP
- 需要运行时条件控制的切面
- 第三方库集成
关键要点 📝
IMPORTANT
- 优先使用基于接口的代理
- 合理管理代理对象的生命周期
- 注意异常处理和降级策略
- 在大多数应用中,声明式 AOP 仍然是首选
通过掌握 ProxyFactory
,你将拥有更强大的 AOP 编程能力,能够在复杂的业务场景中灵活运用 Spring AOP 技术! 🚀