SpringMVC关于AOP拦截controller的注意事项
在网上也找了不少资料,但是感觉网上都没说清楚,在这里我把自己亲自验证的结果和配置方法在这里详细的讲解:
首先aop切面是可以拦截controller层的。这一点再次强调一下,只不过它是有条件的。(条件就是如下3点:
请仔细,耐心的读完下面3句英文)
Indeed your controller (annotated by @Controller) and your aspects (annotated by @Aspect) should be in the same Spring context. (我自己翻译的,英文不好请别吐槽)
1.Controller层和你自己定义的切面,必须在相同的spring上下文中(context).
1.Controller层和你自己定义的切面,必须在相同的spring上下文中(context).
Usually people define their controllers in the dispatch-servlet.xml or xxx-servlet.xml and their service beans (including the aspects) in the main applicationContext.xml. It will not work.
2.通常大家会把 controllers 定义在dispatch-servlet.xml 或者 xxx-servlet.xml 这样的配置文件中,但是把自定义的切面放在spring的主配置文件 applicationContext.xml中。这样子导致controller和你的切面不在同一个context中,从而你的切面类逻辑不会拦截对应的controller.
When Spring initializes the MVC context, it will create a proxy for your controller but if your aspects are not in the same context, Spring will not create interceptors for them.
3.当spring初始化MVC的context的时候,它会同时为
controller 创建代理,但是如果自定义切面没有和mvc在同一个context中,那么你的切面是不会去拦截这些controller 的
综合上面的三点:具体到我们如何实践呢?
先看如下配置文件,然后看下面的分析(这个xml 是图中的 applicationContext.xml 主配置文件)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.yt.*" />
<!--拦截controller层的方法,需要配置注解扫描 切面类 -->
<context:component-scan base-package="com.memcached" />
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 那些类的哪些方法参与事务 -->
<aop:config proxy-target-class="true">
<aop:pointcut id="allServiceMethod"
expression="execution(* com.yt.*.service.*.*(..))" />
<aop:advisor pointcut-ref="allServiceMethod" advice-ref="txAdvice" />
</aop:config>
</beans>
1.配置文件中需要把切面类和controller 放在同一个spring的xml配置文件中,如下两个配置证明了,上述英文说明的第一点
<!--这个扫描配置,com.yt下面所有的包都扫描,但是没有扫描com.memcached这个包下的切面类-->
<context:component-scan base-package="com.yt.*" />
<!--拦截controller层的方法,需要配置注解扫描 切面类(其实切面类就是anotationAspect.java),这里必选配置启动扫描 -->
<context:component-scan base-package="com.memcached" />
<!--注意不要忘记,使用cglib来做代理,实现aop-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
上面的两个扫描初始化都是在同一个配置文件中,说要当初始化spring上下文的时候,切面类和controller会在相同的context
2.配置文件中,如果 把切面类和controller 分开,不在同一contex中,会出现什么效果呢?你自己可以亲自实验一下,把
<context:component-scan base-package="com.memcached" />
把这段配置剪切到 spring-mvc.xml(springmvc的配置文件中)或者其他配置文件中,或者干脆不扫描切面类
这样子,就会导致anotationAspect.java这个切面类不会拦截。这也验证了上述英文说明的第二点和第三点