切面编程是什么
切面编程说的高大上,其实就是动态代理,参考慕课网教程
如果再讲的透彻一点。。就是使用反射动态的构造一个新的Class,新的Class包含旧的Class,可以在旧的Class执行前后和中间插入代码
Spring中如何使用切面
Maven配置
Spring本身提供对切面的支持(注意是支持),但是本身并不能实现切面功能,必须借助AspectJ才行,所以记得在你的Pom文件中加入以下代码
1 | <!-- aspectjweaver --> |
Context配置
除了在POM中加入了AspectJ之外,需要在Spring和SpringMVC的配置文件中启用切面 注意Spring和SpringMVC要分别起用
注意Beans 要有命名空间
xmlns:aop=”http://www.springframework.org/schema/aop"
和 Location
xsi:schemaLocation=”http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
Spring配置文件 applicationContext.xml
1 | <beans .....> |
SpringMVC配置文件 spring-mvc.xml
1 | <beans .....> |
为什么配置不一样
在开篇我们提到,所谓切面编程就是动态代理,那么动态代理有两种方式,一种是JDK本身提供的DynamicProxy,还有一种是CGLIB提供的,参考文章从动态代理中取出Target两者的区别在于:
- JDK的动态代理是针对接口的,某个Class首先要实现某个接口,可以对接口方法进行代理
- CGLib是针对具体的Class的,不需要你的Object去implement某个接口
在SpringMVC配置中的 proxy-target-class 等于true的意思就是(中文直译):代理-目标-Class为真,即使用cglib进行代理,这里注意如果你的pom里没有cglib的包,在使用了这个选项记得加上
为什么MVC要使用CGLib代理
在通常情况下(约定俗成)Java的开发者都有一颗面向接口编程的心,或者是C++转来的觉得没有个.h文件总感觉哪里不对劲,所以大家都写了
- XXXService: 某个接口
- XXXServiceImpl: 某个实现
所以说Spring里的类一般都有一个接口,所以可以使用JDK的动态代理,但是在SpringMVC的Controller里呢?通常大家都这么写
1 | @Controller |
其 本身并没有实现任何接口,所以需要使用CGLib直接对Class进行动态代理
那Spring里使用CGLib行不行
Spring里当然也可以使用CGLib,但是由于一般Service会牵扯到事务Transactional,事务的实现也是由JDK动态代理实现的,所以作为强迫症,我推荐大家还是使用JDK自身的动态代理
闲话
关于为什么Java的Service中要使用一个接口对应一个实现的问题,知乎上有过专门的讨论,总体来讲大家都觉得是.h文件写High了的后遗症,使用接口固然有它的好处,在重构的时候可以减少工作量,但是大部分情况下,如果一个接口只有一个实现,在Java中只会产生冗余的文件,因为要记得接口本身是为了多态而存在的,总之看个人习惯吧。
如果Service里不写接口,只能用CGLib做动态代理了,强迫症表示有点不适应