这几天做SSM整合的时候,前端页面跳转的时候一直报404。
百思不得其解,我觉得我的配置没有问题呀,该有的都有。
然后我打了断点,想看看是哪里出问题了。结果发现根本就没有进入@Controller注解的类。。。
为什么没有找到@Controller注解的类?我明明在spring的配置文件里写了包扫描。
<!--包扫描-->
<context:component-scan base-package="com.ex"></context:component-scan>
随后我想到是不是因为没有扫描到@Controller所在的类,就尝试性将spring配置文件里的包扫描换在SpringMVC的配置文件里。(解决办法在下面)
然后,成功执行了。
-----------总结-------------
1.错误原因:
SpringMVC默认只会在自己容器中查找带有@Controller注解的bean,而不会去父容器中找,因此当SpringMVC的配置文件里没有配置@Controller注解的类所在的包扫描时,会导致找不到Controller类,因此无法进入controller进行请求映射,也就无法进行请求映射找到要跳转的页面,于是导致页面404。
2.解决办法:
在springmvc的配置文件里加上对conroller的包扫描即可顺利运行。
3.关于springmvc里只有controller类,但是能成功依赖注入的原因:
springIOC容器是springMVC ioc容器的父容器,当springMVC里的@Controller注解的类需要注入Service类的bean时,会首先在springmvc的容器中查找,查找不到就会去父容器也就是spring的容器中去找到,能找到就成功依赖注入。
4.建议配置:
当然,关于spring和springmvc里包扫描有好几种方法都可以成功运行,比如“spring中开启全包扫描,SpringMVC开启仅Handler(Controller)层的包扫描”,或者“Spring不开启包扫描,SpringMVC开启全包扫描”。
但是,官方推荐根据不同的业务模块来划分不同容器中注册不同类型的Bean:Spring父容器负责所有其他非@Controller注解的Bean的注册,而SpringMVC只负责@Controller注解的Bean的注册,使得他们各负其责、明确边界。
因为,如果两个扫描有重叠的话,会导致:
- 扫描的类增多, 项目启动时间会延长
- @PostConstruct 注解标注的方法会执行2次
- 会使事务失效
对于第三点会使事物失效,原因是什么?
同时使用springmvc 和 spring, 那么项目中就会有两个容器。
spring的是父容器,先进行初始化; springmvc是子容器, 后进行初始化。子容器可以访问父容器的bean,父容器不能访问子容器的bean。
springmvc后初始化,会重新创建service对象并重新注入,而springmvc再次创建service对象时不会读取spring的配置文件,因此也就无法知道service层是需要创建代理对象的,所以springmvc创建的service是普通的对象,而不是动态代理对象。
建议配置如下:
spring里包扫描:
<!-- Spring容器中注册非@controller注解的Bean -->
<context:component-scan base-package="com.hafiz.www">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
springMVC里包扫描:
<!-- SpringMVC容器中只注册带有@controller注解的Bean -->
<context:component-scan base-package="com.hafiz.www" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>