SpringMVC的父子容器问题
在使用SpringMVC 的时候,我们需要对前端控制器进行配置,前端控制器(DispatcherServlet)需要有一个 WebApplicationConetxt作为它的环境配置。
而 SpringMVC 作为 Spring 框架的一个子框架 ,自己拥有一个独立的子容器(Servlet WebApplicationContext),这个容器中应该包含 controller、view resolvers(视图适配器)、handlerMapping(处理器映射器)以及其他的一些和 web 相关的类;
但是如果在这个子容器中没有找到需要的组件(Component),那么SpringMVC 会到一个父容器的环境中(Root WebApplicationContext)去获取。而如果这个时候,父容器没有创建,那么就找不到对应的组件,编译器就会抛出异常,因此在配置前端控制器的时候,应该保证子容器当中可以获取到controller等的一些组件,并且父容器也要被创建。
解决方法
在 springmvc.xml 中配置包扫描,扫描 controller 包
<beansxmlns="http://www.springframework.org/schema/beans"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.alibaba.com/schema/stat"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.alibaba.com/schema/stathttp://www.alibaba.com/schema/stat.xsd"><!--扫描controller--><context:component-scanbase-package="com.sxt.controller"/><!--配置spring注解的驱动(处理器映射器、处理器适配器)--><mvc:annotation-driven/><!--配置视图适配器--><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><propertyname="prefix"value="/view/"/><propertyname="suffix"value=".jsp"/></bean></beans>
情况一:在配置前端控制器的时候,使用通配符( * )来引入两个配置文件(springdao.xml [主容器配置文件]和 springmvc.xml [springMVC配置文件])
这种情况在理论上是可以满足需求的,但是由于使用的是通配符直接加载两个配置文件,不排除在创建的时候父容器之前就已经创建了子容器,这样也会出现错误
<!--配置前端控制器--><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><!--读取springmvc配置文件--><param-value>classpath:spring*.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet>
情况二:在 web.xml 中配置监听器(ContextLoaderListener),这个监听器在 web 启动的时候就会加载对应的 contextConfig 对应的配置文件,来创建父容器
<!--配置监听器--><!--该监听器可以使 web 在启动的时候加载contextConfig配置文件,创建application容器--><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--配置环境配置文件--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:springdao.xml</param-value></context-param>
情况三:前端控制器中配置 springdao.xml 作为它的环境配置(ContextConfiguration),并且在 springdao.xml 中通过 <import> 引入 springmvc.xml,这样来保证两个容器的创建顺序。
<!--配置前端控制器--><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><!--读取springmvc配置文件--><param-value>classpath:springdao.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet>
springdao.xml 文件配置:
<beansxmlns="http://www.springframework.org/schema/beans"xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttps://www.springframework.org/schema/tx/spring-tx.xsd"><!--设置注解配置包的扫描位置--><context:component-scanbase-package="com.sxt"/><!--配置读取db.properties数据库配置文件--><context:property-placeholderlocation="classpath:dbinfo.properties"/><!--配置数据库连接池--><beanid="dataSource"class="com.alibaba.druid.pool.DruidDataSource"><propertyname="driverClassName"value="${mysql.driver}"/><propertyname="url"value="${mysql.url}"/><propertyname="username"value="${mysql.username}"/><propertyname="password"value="${mysql.password}"/></bean><!--配置mybatis框架的 SqlSessionFactory 类,创建 SqlSessionFactory 工厂对象--><beanclass="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"id="sqlSessionFactory"><!--注入数据--><propertyname="dataSource"ref="dataSource"/><!--配置别名使用包扫描--><propertyname="typeAliasesPackage"value="com.sxt.bean"/><!--读取mybatis-config配置文件,实现其他个性配置--><propertyname="configLocation"value="classpath:mybatis-config.xml"/></bean><!--使用包扫描创建 Mapper 代理对象--><beanclass="org.mybatis.spring.mapper.MapperScannerConfigurer"><!--配置需要创建Mapper接口代理对象对应的包--><propertyname="basePackage"value="com.sxt.mapper"/><!--配置SqlSessionFactory的名称,不是引用--><propertyname="sqlSessionFactoryBeanName"value="sqlSessionFactory"/></bean><!--配置事务管理器--><beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!--注入数据源--><propertyname="dataSource"ref="dataSource"/></bean><!--spring事务配置--><tx:adviceid="txAdvice"transaction-manager="transactionManager"><tx:attributes><!--DQL:查询操作,配置只读事务--><tx:methodname="get*"read-only="true"isolation="REPEATABLE_READ"propagation="REQUIRED"/><tx:methodname="find*"read-only="true"isolation="REPEATABLE_READ"propagation="REQUIRED"/><tx:methodname="select*"read-only="true"isolation="REPEATABLE_READ"propagation="REQUIRED"/><tx:methodname="query*"read-only="true"isolation="REPEATABLE_READ"propagation="REQUIRED"/><!--其他SQL:非只读事务--><tx:methodname="*"read-only="false"isolation="REPEATABLE_READ"propagation="REQUIRED"/></tx:attributes></tx:advice><!--配置AOP切入事务--><aop:config><!--切入点--><aop:pointcutid="pt"expression="execution(* com.sxt.service..*(..))"/><!--切面--><aop:advisoradvice-ref="txAdvice"pointcut-ref="pt"/></aop:config><importresource="classpath:springmvc.xml"/></beans>