HIT软件构造实验之Spring踩坑记

本文记录我在HIT软件构造实验中使用spring框架时遇到的一些问题。

为什么需要Spring?

如果翻看spring的教程,许多作者推荐spring的主要理由是spring提供了依赖注入和面向切面编程这两大核心功能,可以为大型项目的开发提供便利。
那你水几个小实验用这么麻烦的框架干嘛??emmmm一方面是为了练习,一方面也是因为有几个实验的代码量膨胀的比较快,实验3,4,5演进下来项目里零零总总也有两百余个类,近万行代码,让人感觉代码即将超出我的掌控范围了。此外,由于实验不断增加新要求,利用spring面向切面的能力也是我基于spring改造代码的重要原因。

Spring 踩坑记

由于本学期时间紧张,很多情况下,东西还没学明白就直接上手用了,所以踏坑无数,而sping AOP中的坑大多都和它动态代理的实现方式有关。

面向接口编程

对于初学者来说,习惯上只会对那些有多个实现的类提供接口,类内部的实例域常常直接引用外部的类而非接口。
于是坑来了。。。。
在这里插入图片描述
如上,如果MonkeyGenerator 是一个具体类而非接口,而你在某个切面中切入了MonkeyGenerator ,那么恭喜,errors甩脸预定了。
原因在于spring的AOP是基于动态代理的,用切面增强了MonkeyGenerator 后实际上是在外层套了一个代理类,该代理类实现你在切面中增强的功能,再调用原始的MonkeyGenerator 方法。
于是,spring上下文中其实是没有MonkeyGenerator 类对象的,只有一个
MonkeyGenerator 类的代理对象,该对象无法注入到MonkeyGenerator 类对象中。
解决方案是,将MonkeyGenerator 实现为接口,这样,AOP的代理类会自动实现该接口,于是就可以正常注入了。

Spring AOP 对内部调用失效

在这里插入图片描述
如上图,我试图将切点定义在start(),init()和iteration()方法上。但init()和iteration()上的aop通知并没有起效。为什么?
问题仍旧和springAOP的实现方式有关。
因为start()是在目标对象外部被调用的,而init()和iteration()方法是在目标对象内部被调用的。对外部调用,调用的其实是被spring封装后的代理对象的方法,故aop正常起效,而内部调用时,调用的是原始对象上的方法,aop无法产生作用。

解决方案:

一.从spring上下文获取代理后的对象,在该对象上调用内部方法。
这么做有违框架代码对业务代码的最小侵入原则,会污染业务逻辑,不推荐。
二.调整代码结构,使得将被增强的方法从目标对象外部被调用。
这样自然就不存在内部调用不起效的问题了。
具体怎么调整对业务代码的原有逻辑影响最小呢?
说来话长啊(血泪踩坑史)
最初的设想是使用私有内部类,因为这样对外部的影响最小。
然鹅,一言难尽,且看下一篇博文。

猜你喜欢

转载自blog.csdn.net/hieheihei/article/details/91142868
今日推荐