Tomcat启动Spring提示'dataSource' or 'jdbcTemplate' is required

来源:互联网 发布:淘宝哪家店的檀香靠谱 编辑:程序博客网 时间:2024/05/18 01:54

首先贴出自己的代码:

我是采用注解的方式,controller service reposity 进行注解; 下面是目录结构

这是我的web.xml文件

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee" xmlns:jsp="http://java.sun.com/xml/ns/javaee/jsp"xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"version="3.0"><!-- xmlns:xml NameSpace 的缩写: 也就是xml的命名空间 --><!-- display-name:可配置,也可不配置 --><display-name></display-name><!-- 配置log4j: log for java :java 的日志,可以不配置 --><!-- 第一步:指定了Spring Web容器实现(指定Web应用上下文实现)+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --><!-- 第二步:指定加载文件位置+++++++++++++++++++++++++++++++++++++++++++++++++++++++++配置SpringMvc最基础sevlet+++++++++++++++++++++++++++++++++++++++++++++++++++++++ --><!-- servlet配置也是分两步,第一注册,第二映射 --><!-- 前端控制器 DispatcherServlet :MVC框架将加载“/WEB-INF/*-servlet.xml”来进行初始化上下文 --><servlet><servlet-name>springMvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/*-servlet.xml</param-value></init-param><!-- 表示启动容器时初始化该Servlet --><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springMvc</servlet-name><!-- “*.html” 表示拦截所有以htm为扩展名的请求。 --><url-pattern>*.htm</url-pattern></servlet-mapping><!-- 第三步:加载和关闭容器+++++++++++++++++++++++++++++++++++++++++++++++++配置相关 监听器listener+++++++++++++++++++++++++++++++++++++++++++++++++ --><!-- ContextLoaderListener的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。 --><!-- 配置装配的文件位置;如果没有设置contextConfigLocation的参数则会使用默认参数WEB-INF路径下的applicationContext.xml文件 : 配置的是Spring集成Web环境的通用配置;一般用于加载除Web层的Bean(如DAO、Service等),以便于 与其他任何Web框架集成--><!-- <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><!-- 配置其它的监听器 比如安装了oppenOffice 服务,程序启动的时候就需要判断服务有没有启动成功 <listener> <listener-class>com.oumasoft.web.listener.OpenOfficeListener</listener-class> </listener> --><!-- +++++++++++++++++++++++++++++++++++++++++++++filter 分割线+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --><!-- web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter; 首先要开发一个filter,(这里是用的spring带的), 开发后需要注册(定义<filter>)后并映射(定义<filter-mapping>)才能使用。 --><filter>  <!-- 这里配置字符编码过滤器; 配置分两个部分 filter-name: filter-class:对应的fiter实体类 --><description>简单的描述,可配置可不配置,是字符过滤器</description><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><init-param><!-- encoding设置编码格式;forceEncoding设置是否理会 request.getCharacterEncoding()方法,设置为true则强制覆盖页面设置的编码格式 --><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><!-- 上面的filter注册完成后,使用下面的来完成映射 --><filter-mapping><filter-name>encodingFilter</filter-name><!--“/*”表示过滤所有的请求 --><url-pattern>/*</url-pattern><!-- 默认是REQUEST;其它值FORWARD,INCLUDE,ERROR --><dispatcher>REQUEST</dispatcher><!-- REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。 INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。 FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。 ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。 --></filter-mapping><!-- 注册自定义filter --><filter><description>自定义url拦截器</description><filter-name>urlFilter</filter-name><filter-class>com.zq.demo.web.filter.MyUrlFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><init-param><param-name>isReset</param-name><param-value>false</param-value></init-param></filter><!-- 映射自定义filter --><filter-mapping><filter-name>urlFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++设置简单错误页面++++++++++++++++++++++++++++++++++++++++++++++++++++ --><error-page><error-code>500</error-code><location>/error-500.jsp</location></error-page><error-page><error-code>404</error-code><location>/error-404.jsp</location></error-page><error-page><error-code>403</error-code><location>/error-403.jsp</location></error-page><!-- 配置前台页面超时异常跳转页面 :就是自定义了一个异常 --><error-page><exception-type>com.zq.demo.web.filter.FrontTimeOutException</exception-type><location>/error-timeout-front.jsp</location></error-page><!-- 配置后台页面超时异常跳转页面 :自定义了一个runtimeException异常 --><error-page><exception-type>com.zq.demo.web.filter.ExamTimeOutException</exception-type><location>/error-timeout-admin.jsp</location></error-page><!-- 配置session有效时长:30分钟++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --><session-config><session-timeout>30</session-timeout><!-- <tracking-mode>用于表示容器应该使用哪种技术追踪会话ID, 值有: URL ++++容器将只在URL中内嵌会话ID 。不使用cookie或SSL会话ID。这种方式非常不安全。 COOKIE ++++容器将使用会话cookie追踪会话ID 。该技术非常安全。 SSL ++++容器将使用SSL会话ID作为HTTP会话ID。该方法是最安全的方式,但要求使用的所有请求都必须是HTTPS请求。 可以不配置,可以为<tracking-mode>配置多个值,表示容器可以使用多种策略。 只有在追踪模式中使用了COOKIE时,才可以使用<cookie-config>标签。 <tracking-mode></tracking-mode> <cookie-config></cookie-config> --></session-config><!-- 配置欢迎页面++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --><welcome-file-list><welcome-file>/index.jsp</welcome-file></welcome-file-list><!-- 配置数据库连接池监控页面  http://ip:port/projectName/druid/index.html--> <servlet>          <servlet-name>DruidStatView</servlet-name>          <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>      </servlet>      <servlet-mapping>          <servlet-name>DruidStatView</servlet-name>          <url-pattern>/druid/*</url-pattern>      </servlet-mapping>  </web-app>

这是我的mvc-servlet.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:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:mvc="http://www.springframework.org/schema/mvc"    xsi:schemaLocation="        http://www.springframework.org/schema/beans             http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://www.springframework.org/schema/context        http://www.springframework.org/schema/context/spring-context-4.3.xsd        http://www.springframework.org/schema/mvc        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">    <!-- 配置spring自动扫描的包 -->    <context:component-scan base-package="com.zq.demo.*"></context:component-scan>    <!-- (1):HandlerMapping(定位请求处理器) :根据用户请求找到执行该请求的controller。                        1.根据配置文件对url到controller的映射进行注册                        2.根据具体的url请求找到执行该请求的controller                                    将请求的URL和Bean名字映射,如URL为 “上下文/hello”,则Spring配置文 件必须有一个名字为“/hello”的Bean         <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>        (2): HandlerAdapter :定位到Handler(controller)之后,DispatcherServlet会将得到的Handler告知HandlerAdapter,         HandlerAdapter再根据请求去定位请求的具体处理方法是哪一个。         <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>         -->    <!-- ++++++++++++Spring MVC3.0后新特性:自动注册的 DefaultAnnotationHandlerMapping、AnnotationMethodHandlerAdpater+++++++++++++ -->       <!-- 通过@Controller 和 @RequestMapping注解方式定义我们的处理器类。 -->       <!-- 一、定义我们的定位处理器handlerMapping。-->       <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean>       <!-- <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> -->    <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" ></bean> -->       <!-- 二、定义我们的方法发现器handlerAdapter(我胡诌的)-->       <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean>       <!-- <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> -->       <!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" ></bean>  -->       <!-- spring 3.1后,提供了新的处理器映射和 处理器适配器  RequestMappingHandlerAdapter与RequestMappingHandlerMapping  -->           <!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->    <!-- ViewResolver:用于支持Servlet、JSP视图解析 -->    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">        <!-- viewClass:JstlView表示JSP模板页面需要使用JSTL标签库,classpath中必须包含jstl的相关jar包; -->        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>        <property name="prefix" value="/WEB-INF/pages/"/>        <property name="suffix" value=".jsp"/>     </bean>    <!-- +++++++++++++++++++++++++++文件上传解析,用于支持文件上传++++++++++++++++++++++++++++++++++++++++++++++++++++ -->     <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">        <!--设置以字节为单位的最大上传文件的大小 -->        <property name="maxUploadSize" value="102400"></property>    </bean>   <!-- <mvc:default-servlet-handler/> -->    <!-- 配置数据源 -->    <!-- 第一部:配置属性文件位置:Spring提供了一个PropertyPlaceholderConfiguer的BeanFactory后置处理器,这个处理器语序用户将Bean配置的部分内容外移到“属性文件” 中,          可以在Bean配置文件中,以${var}的方式,PropertyPlaceholderConfiguer从属性文件里加载属性,并使用这些属性来替换变量 -->    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">        <property name="ignoreResourceNotFound" value="true" />        <property name="locations">            <list>                <value>/WEB-INF/classes/oracle-mysql.properties</value>            </list>        </property>    </bean>    <bean id="SpringApplicationContext" class="com.zq.demo.utils.ApplicationContextHelper"/>    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">        <property name="url">            <value>${datasource.url}</value>        </property>        <property name="username">            <value>${datasource.username}</value>        </property>        <property name="password">            <value>${datasource.password}</value>        </property>        <property name="maxActive" value="100" />        <property name="filters" value="stat" />                    <property name="initialSize" value="10" />        <property name="maxWait" value="60000" />        <property name="minIdle" value="10" />            <property name="timeBetweenEvictionRunsMillis" value="60000" />        <property name="minEvictableIdleTimeMillis" value="300000" />            <property name="validationQuery" value="SELECT 'x'" />        <property name="testWhileIdle" value="true" />        <property name="testOnBorrow" value="false" />        <property name="testOnReturn" value="false" />                 <!-- <property name="poolPreparedStatements" value="false" />        <property name="maxPoolPreparedStatementPerConnectionSize" value="10" /> -->    </bean>    <!-- 配置springTempleteJdbc    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">        <property name="dataSource" ref="dataSource"></property>    </bean>-->        <!--  将dataSource 注入 baseDao -->    <bean id="baseDao" class="com.zq.demo.user.dao.impl.BaseDao">        <property name="dataSource" ref="dataSource"/>    </bean>   <!--  第二种方式   <context:property-placeholder location="classpath:oracle-mysql.properties"/>    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">        <property name="user" value="${user}"></property>        <property name="password" value="${password}"></property>        <property name="jdbcUrl" value="${jdbcUrl}"></property>        <property name="driverClass" value="${driverClass}"></property>    </bean> -->    <!-- 配置事务 spring 提供的事务-->    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">        <property name="dataSource" ref="dataSource" />    </bean></beans>

controller:如下

@Controller@RequestMapping("/user")public class UserController {@Autowiredprivate UserService userService;@Testpublic void test(){this.userService.Save();}@RequestMapping("/toIndex")public String toIndex(HttpServletRequest request,HttpServletResponse response){System.out.println("从你的全世界路过!");return "welcome";}@RequestMapping("/seeUsers")public String seeUsers(HttpServletRequest request,HttpServletResponse response){List<User> userList = this.userService.getAllUsers();request.setAttribute("userList", userList);return "userList";}}


service省略掉:

dao如下:

package com.zq.demo.user.dao.impl;import java.util.List;import org.springframework.stereotype.Repository;import com.zq.demo.user.beans.User;import com.zq.demo.user.dao.UserDao;@Repository("userDao")public class UserDaoImpl extends BaseDao implements UserDao {@Overridepublic String saveUser() {System.out.println("userDaoImpl  save user");return "保存user";}@Overridepublic List<User> getAllUser() {String sql = "select * from sys_user s ";//List<User> ulist = this.queryList(sql, User.class);return null;}}

继承的Dao如下:

@SuppressWarnings("all")@Repository("baseDao")public class BaseDao extends JdbcDaoSupport {/** * Spring中的RowMapper可以将数据中的每一行数据封装成用户定义的类。 *  * @param sql * @param rowClass * @return */public List queryList(String sql, Class rowClass) {if (rowClass == null) {return this.getJdbcTemplate().queryForList(sql);}return this.getJdbcTemplate().query(sql,BeanPropertyRowMapper.newInstance(rowClass));}}
在如此情况下: 我的BaseDao extends JdbcDaoSupport 这个类,采用注解(@autowrie)的方式实现bean的注入,这个时候启动我们会发现问题;

java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
开始的时候很纳闷,为什么?

查看过JdbcDaoSupport的源码,里面会有根据注入的dataSource进行获取jdbcTemplate的方法,我们上边的xml文件中,在baseDao中注入了dataSource,按道理上面应该会注入成功,并能够有jdbcTemplate,打上断点发现每次都是null,说明这里dataSource,而且每次都是先走这个方法,

jdbcTemplate 这个时候是null,然后抛出异常;

@Overrideprotected void checkDaoConfig() {if (this.jdbcTemplate == null) {throw new IllegalArgumentException("'dataSource' or 'jdbcTemplate' is required");}}

偶然情况下:我把除了baseDao之外的dao都删除掉,走到JdbcDaoSupport,先走 的是如下这个方法:

/** * Set the JDBC DataSource to be used by this DAO. */public final void setDataSource(DataSource dataSource) {if (this.jdbcTemplate == null || dataSource != this.jdbcTemplate.getDataSource()) {this.jdbcTemplate = createJdbcTemplate(dataSource);initTemplateConfig();}}
这个时候,jdbcTemplate是NULL ,但是dataSource不是NULL,因为我们有注入,然后继续往下走,会执行创建jdbcTemplate的操作。

我有点懵逼。以下是瞎猜的原因,因为没办法完全解释上面的这种情况,只能解决这种情况。

报错的原因: XML里面配置的DataSource无法被Spring容器主动注入到dao(继承了JdbcDaoSupport)里面!从而在初始化dao(此dao有继承了JdbcDaoSupport类)的bean的时候,如果获取不到DataSource或者JdbcTemplate的话,会报错:无法找到数据源。

或者 :JdbcDaoSupport的父类DaoSupport继承了InitializingBean,在系统启动实例化dao时,会首先实例化JdbcDaoSupport,实例化后,执行立即检查dao配置,发现dataSource为null,则报错,dao实例化失败。

解决办法,在继承JdbcDaoSupport的dao中,添加如下代码:

  @Autowired    private DataSource dataSource;    @PostConstruct    private void initialize() {        setDataSource(dataSource);    }

其实这都不是根本原因,我们公司的一个项目,我也没找到 在哪里注入的,也是继承了jdbcdaosupport,而且baseDao中也没有用我这种解决办法,可是人家就是能用,但是版本是4.1.6,我这4.3.12就不行,可能是我搭建项目的时候不知道哪里出了纰漏








阅读全文
0 0
原创粉丝点击