使用 AOP 陷阱之一

简介: 手头上的一个项目使用了Spring.net的AOP了处理程序的异常,一不小心就掉进了陷阱,这里记录下来,希望对后来者有所帮助。Spring.net的AOP实现是通过运行时创建动态的AOP代理来完成的。

    手头上的一个项目使用了Spring.net的AOP了处理程序的异常,一不小心就掉进了陷阱,这里记录下来,希望对后来者有所帮助。Spring.net的AOP实现是通过运行时创建动态的AOP代理来完成的。简单图示如下:

    图中的“POJO”以词来自Java,表示一个普通的.net对象,所有对POJO的调用都要经过Aop代理进行,因此Aop才有机会插入Pre_Action、Post_Action、和Around_Action。


    现在我以手上的工作举个例子,看我是如何掉入陷阱的:

    public   interface  IIrasRemotingServiceAccesser
    {
        
void  Initialize() ;

        
void  fsManager_AsServiceListChanged( int  serverID,  string  serverName, ArrayList serviceList) ;
        
void  CheckMySelf() ;
     }

    我们没有必要了解IIrasRemotingServiceAccesser接口的具体用途,只要了解这个接口将被Aop代理,为了使Aop能够截获fsManager_AsServiceListChanged方法,我把它放入了接口定义中,实际上它是一个事件处理函数,本应是私有的。
    Initialize方法使用fsManager_AsServiceListChanged预定了某个事件:

        public   void  Initialize()
        {                
            this .fsManager.AsServiceListChanged  +=   new  CbServiceChanged(fsManager_AsServiceListChanged);
        }

    运行程序后,发现CheckMySelf方法能正常被AOP截获,而当fsManager.AsServiceListChanged事件发生时,对fsManager_AsServiceListChanged的调用没有被截获。

    这是为什么?
    原来是预定事件时,绕过了AOP代理:

        public   void  Initialize()
        {                
            
this .fsManager.AsServiceListChanged  +=   new  CbServiceChanged(this.fsManager_AsServiceListChanged);
        }

    请注意红色的“this”,正是它绕过了AOP代理。所以fsManager_AsServiceListChanged的调用没有被截获。解决方案?我常用的有两种:
(1)将this换为代理:

        public   void  Initialize()
        {
            IIrasRemotingServiceAccesser myAopProxy 
=  (IIrasRemotingServiceAccesser)MainClass.SpringContext.GetObject( " irasRemotingServiceAccesser " ) ;
            
this .fsManager.AsServiceListChanged  +=   new  CbServiceChanged(myAopProxy.fsManager_AsServiceListChanged);
        }

    可以看到,myAopProxy.fsManager_AsServiceListChanged被委托为事件处理函数,这是通过Aop代理myAopProxy进行。这种方法解决了问题,但是又引入了新的问题--IIrasRemotingServiceAccesser实现类不再是一个“POJO”,而是依赖于Spring.net框架了。更好的办法是第二种:

(2)使用前文的Bridge方式。将IIrasRemotingServiceAccesser设计修改如下:

    public   interface  IIrasRemotingServiceAccesser
    {
        
void  Initialize() ;

        
void  ChangeServiceList( int  serverID,  string  serverName, ArrayList serviceList) ;
        
void  CheckMySelf() ;
    }

    然后通过Bridge将IIrasRemotingServiceAccesser 和 fsManager的事件桥接起来。(原理详见http://zhuweisky.cnblogs.com/archive/2005/12/20/301098.html
    如此,原来Initialize方法中的事件预定就转移到Bridge中了,所以就避免了绕过AOP代理的情况。



目录
相关文章
|
SQL 缓存 Java
Mybatis-plus缓存机制
MyBatis-Plus(简称MP)是一个基于MyBatis的增强工具,提供了更便捷的CRUD操作和其他功能。与MyBatis相比,MyBatis-Plus并没有引入自己的缓存机制,而是直接使用了MyBatis的缓存机制。 在MyBatis中,缓存分为一级缓存和二级缓存。 1. 一级缓存:一级缓存是SqlSession级别的缓存,它默认是开启的。当查询操作执行时,查询的结果会被缓存在SqlSession的内部数据结构中。如果后续再次执行相同的查询,MyBatis会先检查一级缓存中是否存在结果,如果存在则直接返回缓存的结果,而不会再次执行SQL语句。一级缓存的生命周期与SqlSession相同,
1361 0
|
5月前
|
人工智能 安全 算法
Go入门实战:并发模式的使用
本文详细探讨了Go语言的并发模式,包括Goroutine、Channel、Mutex和WaitGroup等核心概念。通过具体代码实例与详细解释,介绍了这些模式的原理及应用。同时分析了未来发展趋势与挑战,如更高效的并发控制、更好的并发安全及性能优化。Go语言凭借其优秀的并发性能,在现代编程中备受青睐。
158 33
|
5月前
|
人工智能 监控 安全
Go通道机制与应用详解
本文全面解析了Go语言中的通道(Channel),从基础概念到高级应用,涵盖创建、操作、垃圾回收及实际场景使用。通道作为Go并发模型的核心,支持协程间安全高效的数据通信与同步。文章介绍了无缓冲和有缓冲通道的特性,以及发送、接收、关闭等操作,并探讨了`select`语句、超时处理、遍历通道等高级用法。此外,还深入分析了通道的垃圾回收机制,包括引用计数、生命周期管理和循环引用问题。最后通过数据流处理、任务调度和状态监控等实例,展示了通道在实际开发中的广泛应用。理解通道不仅有助于构建高并发系统,还能优化资源管理,提升程序性能。
162 31
|
12月前
|
前端开发
PDF文件上传转成base64编码并支持预览
PDF文件上传转成base64编码并支持预览
600 12
|
5月前
|
机器学习/深度学习 人工智能 算法
破解生成式AI认知边界:框架思维引擎如何重塑产业智能化未来
该内容深入解析了核心技术架构,涵盖思维链强化系统(DTT)、认知框架建模体系和实时纠偏算法体系。DTT通过多级问题拆解、混合精度推理及分布式验证,大幅提升复杂问题处理能力;认知框架结合知识图谱与逻辑推理,实现精准医疗诊断等应用;实时纠偏算法则通过多级验证机制保障事实与逻辑准确性。整体架构分应用层、框架层和基础层,支持高效、可信的跨领域适配。技术创新体现在混合计算加速、持续学习机制等方面,显著优于传统模型,在事实准确性、逻辑连续性及响应速度上优势明显。
200 28
|
5月前
|
消息中间件 架构师 Java
美团面试:对比分析 RocketMQ、Kafka、RabbitMQ 三大MQ常见问题?
美团面试:对比分析 RocketMQ、Kafka、RabbitMQ 三大MQ常见问题?
美团面试:对比分析 RocketMQ、Kafka、RabbitMQ 三大MQ常见问题?
|
5月前
|
存储 缓存 运维
为什么强调 RESTful 的无状态性?-优雅草卓伊凡
为什么强调 RESTful 的无状态性?-优雅草卓伊凡
111 19
为什么强调 RESTful 的无状态性?-优雅草卓伊凡
|
5月前
|
数据挖掘
scRNA-seq 细胞通信 分析教程(长文+代码)
scRNA-seq 细胞通信 分析教程(长文+代码)
145 11
scRNA-seq 细胞通信 分析教程(长文+代码)
|
7月前
|
Java
java构造方法,构造代码块,静态代码块的执行顺序
本文介绍了Java中构造方法、构造代码块和静态代码块的执行顺序。静态代码块用`static`声明,在JVM加载类时执行一次;构造代码块在每次创建对象时执行,先于构造方法;构造方法用于对象初始化,创建对象时调用。示例代码展示了这三者的输出顺序,并解释了它们的区别和应用场景。
195 1
|
5月前
|
存储 Dart 前端开发
《社交应用架构生存战:React Native与Flutter的部署容灾决胜法则》
React Native和Flutter作为热门跨平台开发框架,在社交应用领域各有优势。React Native基于JavaScript,社区活跃,便于调用原生模块,适合快速开发;通过分层架构、缓存机制与异步加载提升性能,并依赖社区资源构建容灾策略。Flutter采用Dart语言,高性能自绘制UI,AOT编译优化启动速度,热重载加速迭代;其高效内存管理和渲染能力确保高并发下的流畅体验。两者在网络不稳定时均支持重试机制,数据存储方面结合本地与云服务保障安全。开发者需根据项目需求和技术背景选择合适框架,打造稳定高效的社交应用。
66 21