最近使用SpringMVC开发一个后台应用, 要求对操作进行权限控制并记录操作日志。这是典型的AOP应用场景, 所以自然而然的想通过 AOP 拦截 SpringMVC 的 Controller 执行来达到想要的效果. 但是在按照之前的配置调试的时候, AOP的拦截代码并没有得到执行。经过几番研究后找到了答案。
首先因为 SpringMVC 的 Controller 是没有接口的, 但是Spring 默认使用的JDK的动态代理。动态代理会限制必须有接口才行,所以在配置上要指定使用cglib代理。通过以下的配置可以指定 Spring 使用 cglib:
<aop:aspectj-autoproxy proxy-target-class="true"/>
但是要想达到想要的效果, 这个配置的声明位置还有讲究。这个主要是 Spring 的父子容器访问规则导致的。子容器可以访问父容器中配置的bean, 但是父容器不能访问子容器中的bean .
SpringMVC 实现的时候就是这样一个父子结构。通过 ContextLoaderListener
创建的容器作为父容器。 每个 DispatcherServlet
创建的容器作为子容器。
所以当把上面的申明放到父容器相关的配置文件中的时候, 父容器会尝试寻找切入点, 但是这个时候切入点其实在子容器, 父容器访问不到子容器中的bean, 达不到拦截的效果。
将配置迁移到 子容器相关的配置文件中就能达到拦截的效果。至于 Aspect 的bean 可以配置在父容器中 也可以配置在子容器中。