Root WebApplicationContext: 加载了两次,Spring依赖注入失败

Spring MVC,Spring,Mybatis 配置完,启动服务器,发现启动时差 15s 左右,log 是没有报错的,但是在测试,Service 和 Mapper 的时候,报 nullpoint 异常;调试了半天的配置文件,还不知道那里出问题了。
问题1:webApplicationContext加载了两次,从而导致 application.xml 文件加载两次
问题2:依赖注入的 bean 都是 null

两次加载
clipboard.png
clipboard.png

配置构建
图片描述

web.xml 文件配置如下

<!-- 加载spring容器 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:ApplicationContext-*.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


    <!-- springmvc前端控制器 -->
    <servlet>
        <servlet-name>springMvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:SpringMvc.xml</param-value>
        </init-param>
        <!-- 在tomcat启动的时候就加载这个servlet -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springMvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

application-dao.xml

<!-- 加载配置文件 -->
    <context:property-placeholder location="classpath:db.properties" />
    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
        destroy-method="close">
        <property name="driverClassName" value="${jdbc.driver}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
        <property name="maxActive" value="10" />
    </bean>

    <!-- mapper配置 -->
    <!-- 让spring管理sqlsessionfactory 使用mybatis和spring整合包中的 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 数据库连接池 -->
        <property name="dataSource" ref="dataSource" />
        <!-- 加载mybatis的全局配置文件 -->
        <property name="configLocation" value="classpath:SqlMapConfig.xml" />
    </bean>
    
    <!-- 配置Mapper扫描器 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.smniuhe.dao" />
    </bean>    

application-service.xml

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

    <!-- @Service扫描 -->
    <context:component-scan base-package="com.smniuhe.service"></context:component-scan>
    
</beans>

测试代码补充:

@Service
public class WordServiceImpl implements WordService {

    @Autowired(required=true)
    private WordMapper wordMapper;
    
    @Override
    public void word2() {
        System.out.println("....");
        WordModle modleById = wordMapper.findWordModleById(new Long(1));
        System.out.println(modleById);
    }

}

// mapper
public interface WordMapper {

    WordModle findWordModleById(Long id);

}
// mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.smniuhe.dao.WordMapper">

    <select id="findWordModleById" parameterType="long"
        resultType="com.smniuhe.pojo.WordModle">
        select * from wordModle where id = #{id}
    </select>

</mapper>

// test
@Test
public void findWordModle() {

    new WordServiceImpl().word2();
}
阅读 6.4k
3 个回答

发现问题了。

你在测试代码的时候,使用的是new,所以你当前的这个service实现类,不是受spring托管的。

建议你改被Spring 托管的方式,注入,或者从applicationcontext中取出来。

看一下 Spring和Junit 如何配合起来测试,网上例子很多,给你一个思路。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring-context.xml")    //这里需要把你的spring文件都加载
public class UserMapperTest {
    @Autowired
    private 你的那个Service  XXXX;
    
    @Test
    public void test() {
    
            XXXX.XXX
        
    }

类似于上文这样

http://www.cnblogs.com/wangmi...

你看一下这篇,如果用注解的话,你的mapper也需要注解的方式进来。

或者你可以自己在test里,从applicationcontext获取service这个bean,也可以尝试下。

加载两次的问题,可以看一下你的项目发布路径配置,包括tomcat的server.xml,eclipse里面的tomcat deploy root,project的Web context root,看日志,你这里应该是有配置,所以造成第一次加载在wtpwebapps/,第二次加载在webapps/。
注入bean是null的问题,可能的原因有很多,需要看更详细的日志,修改log的级别,看spring bean factory是否有成功创建bean实例。如果能排除配置文件的问题的话,有可能是在创建过程中报错了,常见的有循环依赖,多个实现等

springMVC的配置正确姿势

    <servlet>

        <servlet-name>springmvc</servlet-name>

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>

            <param-name>contextConfigLocation</param-name>

            <param-value>classpath:spring/spring-servlet.xml</param-value>

        </init-param>
        <load-on-startup>1</load-on-startup>

    </servlet>
  <mvc:annotation-driven conversion-service="conversionService" />
    <mvc:default-servlet-handler />
    <context:component-scan base-package="com" use-default-filters="false">
        <context:include-filter type="annotation"
                                expression="org.springframework.stereotype.Controller"/>
    </context:component-scan> 这里是关键,配置springMVC只扫描注解是@Controller的类

    <mvc:resources location="/css/" mapping="/css/**" />

    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="formatters">
            <set>
                 
                <bean class="org.springframework.format.datetime.DateFormatter">
                    <property name="pattern" value="yyyy-MM-dd"></property>
                </bean>
            </set>
        </property>
    </bean>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题