这两天学习Spring,用了SpringMVC的注解,然后配置事务和AOP,发现没用。和别的人讨论了下,大致得出了一个结论:这大约是Spring上下文的问题。


详细情况是这样的:项目引用了SpringMVC框架,在编写Controller以及Service的时候添加@Transactional的情况下和编写AspectJ的切面的情况下,事务和AOP都没有生效,而我的AOP配置是这样的:AOP命名空间和<aop:aspectj-autoproxy  proxy-target-class="true />这两个都配在了ApplicationContext.xml里面了,而不是SpringMVC框架自己约定的配置文件中(我这个项目里面,这个配置文件叫做springmvc-servlet.xml),正因为这样,出问题了。后来,我把AOP命名空间和<aop:aspectj-autoproxy  proxy-target-class="true />挪到SpringMVC自己的配置文件里面,AOP就生效了。同理,把注解相应的命名空间和<tx:annotation-driven>放在SpringMVC的配置文件里,事务也生效了。

另外以上所述的是对controller进行切面时的配置,如果是对service进行切面,那么

<context:component-scan base-package="com.java1234.aop" />
<aop:aspectj-autoproxy />

这两个注释就要用在ApplicationContext.xml里面了,注意此时不要开启aop的cglib代理模式。



解释:


1.SpringMVC这个框架很好用,没问题,他的注解也简化了很多的配置,但是请注意@Controller和@Service都是SpringMVC框架包里面的,也就是说,这些类的实例化以及注入也是由SpringMVC这个框架完成的(确切的来说是这个框架自己有的上下文的IoC容器完成的)。


2.而对AOP和事务的支持是Spring框架本身完成的,是Spring框架的应用上下文所扫描并处理的。

从1.2可以得出一个结论,如果SpringMVC和Spring本身用的是一个应用上下文,一个Ioc容器,那随便你的<aop:aspectj-autoproxy />和命名空间配置在哪里,无论是Spring的ApplicationContext.xml还是SpringMVC的springmvc-servlet.xml里面,反正都是一个容器,怎么扫描,怎么处理都能找到。


但关键的是以上假设不成立,总的来说SpringMVC的应用上下文的 “ 父 ” 上下文才是Spring的应用上下文。那么这个也就是说Spring的应用上下文初始化完成的时候,它开始扫描到底哪些Bean用了AspectJ的注解,哪些用了Transactional的注解,但是利用SpringMVC注解配置的这些Bean它是找不到的,因为用了这些注解的Bean还没有被实例化甚至是还没有被装载,为什么呢?因为管理这些bean的SpringMVC的上下文可能还没有完成初始化。OK,既然Spring的上下文找不到到底哪些Bean应用了注解,那他自然也没有办法给这些Bean提供声明式AOP和事务的支持了。


至于为什么SpringMVC的应用上下文的 “ 父 ” 上下文才是Spring的应用上下文,这里有大牛为我们详解:





这个是坑点啊~~~


另外,Spring中的切面类固然要用@Aspect标注,但也不要忘了用@Componet标注,这样才能被注册到容器中