无法通过Spring加载数据库驱动程序,但可以在类路径上手动找到它

时间:2013-02-20 19:37:43

标签: java spring tomcat

尝试使用在Tomcat下运行的Spring创建数据源时,我在数据库驱动程序类上遇到ClassNotFoundException。但是,我可以直接从同一个数据访问组件(通过Class.forNamegetClass().getClassLoader().loadClass())加载驱动程序类。驱动程序jar仅安装在一个位置($CATALINA_HOME/lib)。

Spring配置文件中的数据源定义:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

Spring配置文件中的DAO定义:

<bean id="countryDao" class="com.mycompany.pmo.dao.CountryDao">
    <constructor-arg ref="dataSource"/>
</bean>

DAO本身:

public class CountryDao {
    private NamedParameterJdbcTemplate jdbcTemplate;

    public CountryDao(DataSource dataSource) {
        jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
    }

    public List<Country> getCountries() {
        //I can manually load the driver class here
        String sql = "select * from ref.country";

        Map<String, Object> namedParameters = new HashMap<String, Object>();
        //next line is line 34, where the stack trace starts
        return jdbcTemplate.query(sql, namedParameters,new CountryMapper());
    }
}

堆栈跟踪:

Feb 20, 2013 2:18:35 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/PMO] threw exception [Request processing failed; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class '"com.microsoft.sqlserver.jdbc.SQLServerDriver"'] with root cause
java.lang.ClassNotFoundException: "com.microsoft.sqlserver.jdbc.SQLServerDriver"
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
    at org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1420)
    at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1371)
    at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
    at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
    at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:573)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:637)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:662)
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:702)
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:166)
    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:172)
    at com.mycompany.pmo.dao.CountryDao.getCountries(CountryDao.java:34)

2 个答案:

答案 0 :(得分:4)

jar不应该在$CATALINA_HOME/lib中。它应该在您的网络应用的WEB-INF/lib中。我相信$CATALINA_HOME/lib将用于加载和运行Tomcat,但您的应用类路径依赖项是从WEB-INF/lib加载的。

如果您正在使用IDE进行开发并在其中运行程序,则可能还需要将jar添加到项目构建路径中。

答案 1 :(得分:2)

正如@Sotirios Delimanolis提到的那样(+1)尝试将jar放在你应用程序的WEB-INF/lib下。

使用您的手动代码找到类并且无法通过Spring找到该类的事实表明问题出在类加载器中。当您调用Class.forName()时,您肯定使用系统类加载器,因此该类是从catalina lib目录加载的。当你从DAO调用getClass().getClassLoader().loadClass()时,我无法解释它为什么有效:在这种情况下,应该使用相同的应用程序类加载器。但是我可能不太了解Spring如何与类加载器一起玩。