0

尝试使用在 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)
4

2 回答 2

4

jar不应该在$CATALINA_HOME/lib. 它应该在WEB-INF/lib您的网络应用程序中。我相信$CATALINA_HOME/lib会被用来加载和运行Tomcat,但是你的app类路径依赖是从WEB-INF/lib.

如果您在 IDE 中开发并在其中运行程序,则可能还必须将 jar 添加到项目构建路径中。

于 2013-02-20T19:44:49.547 回答
2

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

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

于 2013-02-20T19:50:15.433 回答