开发者社区> Biubiu> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Spring和SpringMVC 父子容器的问题

简介: Spring与SpringMVC的容器属于父子容器关系,在配置使用SpringMVC时,若SpringMVC容器在Spring容器之前创建,可能会导致项目在编译运行时出现异常。
+关注继续查看

SpringMVC的父子容器问题

在使用SpringMVC 的时候,我们需要对前端控制器进行配置,前端控制器(DispatcherServlet)需要有一个 WebApplicationConetxt作为它的环境配置。


而 SpringMVC 作为 Spring 框架的一个子框架 ,自己拥有一个独立的子容器(Servlet WebApplicationContext),这个容器中应该包含 controller、view resolvers(视图适配器)、handlerMapping(处理器映射器)以及其他的一些和 web 相关的类;


但是如果在这个子容器中没有找到需要的组件(Component),那么SpringMVC 会到一个父容器的环境中(Root WebApplicationContext)去获取。而如果这个时候,父容器没有创建,那么就找不到对应的组件,编译器就会抛出异常,因此在配置前端控制器的时候,应该保证子容器当中可以获取到controller等的一些组件,并且父容器也要被创建。

image.pngimage.png

解决方法

在 springmvc.xml 中配置包扫描,扫描 controller 包

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.alibaba.com/schema/stat
        http://www.alibaba.com/schema/stat.xsd">

    <!--扫描controller-->
    <context:component-scan base-package="com.sxt.controller"/>

    <!--配置spring注解的驱动(处理器映射器、处理器适配器)-->
    <mvc:annotation-driven/>

    <!--配置视图适配器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/view/"/>
        <property name="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 文件配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--设置注解配置包的扫描位置-->
    <context:component-scan base-package="com.sxt"/>

    <!--配置读取db.properties数据库配置文件-->
    <context:property-placeholder location="classpath:dbinfo.properties"/>

    <!--配置数据库连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${mysql.driver}"/>
        <property name="url" value="${mysql.url}"/>
        <property name="username" value="${mysql.username}"/>
        <property name="password" value="${mysql.password}"/>
    </bean>

    <!--配置mybatis框架的 SqlSessionFactory 类,创建 SqlSessionFactory 工厂对象-->
    <bean class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" id="sqlSessionFactory">
        <!--注入数据-->
        <property name="dataSource" ref="dataSource"/>

        <!--配置别名使用包扫描-->
        <property name="typeAliasesPackage" value="com.sxt.bean"/>
        <!--读取mybatis-config配置文件,实现其他个性配置-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>

    <!--使用包扫描创建 Mapper 代理对象-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--配置需要创建Mapper接口代理对象对应的包-->
        <property name="basePackage" value="com.sxt.mapper"/>
        <!--配置SqlSessionFactory的名称,不是引用-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

    <!--配置事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--spring事务配置-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--DQL:查询操作,配置只读事务-->
            <tx:method name="get*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
            <tx:method name="find*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
            <tx:method name="select*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
            <tx:method name="query*" read-only="true" isolation="REPEATABLE_READ" propagation="REQUIRED"/>

            <!--其他SQL:非只读事务-->
            <tx:method name="*" read-only="false" isolation="REPEATABLE_READ" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <!--配置AOP切入事务-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="pt" expression="execution(* com.sxt.service..*(..))"/>
        <!--切面-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
    </aop:config>

    <import resource="classpath:springmvc.xml"/>
</beans>

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Spring容器 IoC思想 DI实现
Spring容器 IoC思想 DI实现
0 0
Spring容器的事件监听机制(简单明了的介绍)
上一篇我们介绍了SpringFactoriesLoader。这一篇我接着来介绍一下Spring的另一个知识点,就是Spring容器的事件监听机制。
0 0
看了这一篇Spring容器Bean的生命周期,面试再也不用怕了
上一篇我们介绍了Spring IOC容器的启动过程以及bean的实例化过程,这一篇我们接着来学习另外一个知识点,就是Bean的生命周期,我们知道直接通过(new XX())来创建的实例,当这个实例没有被引用时就会被垃圾回收机制回收,但是通过IOC容器实例化的Bean的生命周期又是如何呢?
0 0
「推荐收藏!」【Spring源码探究】(一)MVC容器初始化🏅彻底让你明白运行原理和源码流程
「推荐收藏!」【Spring源码探究】(一)MVC容器初始化🏅彻底让你明白运行原理和源码流程
0 0
【Spring专场】「MVC容器」不看源码就带你认识核心流程以及运作原理
【Spring专场】「MVC容器」不看源码就带你认识核心流程以及运作原理
0 0
【Spring专场】「AOP容器」不看源码就带你认识核心流程以及运作原理
【Spring专场】「AOP容器」不看源码就带你认识核心流程以及运作原理
0 0
【Spring 专场】「IOC 容器」不看源码就带你认识核心流程以及运作原理
【Spring 专场】「IOC 容器」不看源码就带你认识核心流程以及运作原理
0 0
【Spring容器启动执行流程】
【Spring容器启动执行流程】
0 0
【Spring专题】「实战系列」Spring容器注入Bean对象的方法及梳理
【Spring专题】「实战系列」Spring容器注入Bean对象的方法及梳理
0 0
+关注
文章
问答
文章排行榜
最热
最新
相关电子书
更多
电商网站需求分析和架构设计Spring Boot2.6入门
立即下载
Java Spring Boot开发实战系列课程(第17讲):Spring Boot 2.0实战Docker容器Linux
立即下载
Spring Boot 2.6.0电商网站开发实战
立即下载