首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么罐子里的罐子不能看到其他罐子里的东西,如果它们在同一个罐子里?

为什么罐子里的罐子不能看到其他罐子里的东西,如果它们在同一个罐子里?
EN

Stack Overflow用户
提问于 2017-04-17 20:21:17
回答 3查看 491关注 0票数 7

tl;dr:我们Spring中的类似乎在捆绑的jar中看到了类,但是它们的内容似乎不能。为什么?

我们的主要产品是一个web应用程序,但是所有的业务逻辑都集中在一个核心的mac-guffin-api.jar中。mac-guffin-api.jar不是Spring项目,而是一个名为net.initech.api.Configuration的Spring文件,用于初始化所有服务和存储库等。我们使用MS作为后端,并使用sqljdbc42:jar驱动程序。

我们需要编写一个ETL,它需要重用来自API项目的相同业务逻辑,因此我们创建了一个项目,该项目将mac-guffin-api.jar作为Maven依赖项导入。ETL(net.initech.etl.Configuration)导入的API配置没有问题(我可以从控制台日志中看到),但是当API配置用于创建数据库连接时,它找不到驱动程序。

代码语言:javascript
运行
复制
Caused by: java.lang.ClassNotFoundException: 'com.microsoft.sqlserver.jdbc.SQLServerDriver'
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:94)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:246)
    ... 113 more

但是,我可以清楚地看到,包含驱动程序的罐子是存在的。ETL的内容如下(Nb: mac-guffin-api.jarsqljdbc42-4.2.jar未解压缩,它们是ETL中的jar ):

代码语言:javascript
运行
复制
mac-guffin-etl.jar
|
+- org.springframework.boot.loader...
|
+- BOOT-INF
   |
   +- classes
   |  |
   |  +- com.initech.etl.Main.class
   |  |
   |  +- com.initech.etl.Configuration.class
   |
   +- lib
      |
      +- mac-guffin-api.jar
      |  |
      |  +- com.initech.api.Configuration.class
      |
      +- sqljdbc42-4.2.jar
         |
         +- com.microsoft.sqlserver.jdbc.SQLServerDriver.class

因此,显然,类ETL的配置类可以看到包含的jar的内容(或者至少是API的内容),但是它们似乎无法在同类的Server中看到com.microsoft.sqlserver.jdbc.SQLServerDriver.class

我甚至可以在Spring上下文实例化之前执行一个Class.forName( "com.microsoft.sqlserver.jdbc.SQLServerDriver.class" ),而且它没有问题。

这是类加载器的限制吗?这是因为API项目不是Spring吗?是因为缺少配置参数吗?这里发生什么事情?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-04-22 04:11:06

在您的配置中,您最终得到了用作值的类名:

代码语言:javascript
运行
复制
'com.microsoft.sqlserver.jdbc.SQLServerDriver'

上面有单引号。通常,要加载的类名不带双引号或单引号。

这将解释为什么您能够加载类,但是API jar不能加载。检查设置驱动程序名称的配置/生成文件。

演示

我唯一能收到像你这样的信息的方法是:

代码语言:javascript
运行
复制
Caused by: java.lang.ClassNotFoundException: 'com.microsoft.sqlserver.jdbc.SQLServerDriver'

而不是:

代码语言:javascript
运行
复制
Caused by: java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver

是故意要求加载名称中带有单引号的类。例如:

代码语言:javascript
运行
复制
import java.lang.*;

public class myclass {

        public static void test(String thename) {
                System.out.println("trying " + thename);
                try {
                        myclass test = (myclass) myclass.class
                                .getClassLoader()
                                .loadClass(thename)
                                .newInstance();
                        System.out.println(test.toString());
                } catch (Exception e){
                        System.out.println("failed to load " + thename);
                        e.printStackTrace();
                }
        }

        public static void main(String[] args) {
                test("my.package.itwontexist");
                test("'my.package.itwontexist'");
        }
}

产出:

代码语言:javascript
运行
复制
trying my.package.itwontexist
failed to load my.package.itwontexist
java.lang.ClassNotFoundException: my.package.itwontexist
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at myclass.test(myclass.java:10)
    at myclass.main(myclass.java:20)
trying 'my.package.itwontexist'
failed to load 'my.package.itwontexist'
java.lang.ClassNotFoundException: 'my.package.itwontexist'
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at myclass.test(myclass.java:10)
    at myclass.main(myclass.java:21)
票数 2
EN

Stack Overflow用户

发布于 2017-04-26 19:18:21

您可能是从配置中获得驱动程序值的。

'com.microsoft.sqlserver.jdbc.SQLServerDriver‘= my.driver

该配置使用单引号返回值。请检查您的配置文件。

票数 2
EN

Stack Overflow用户

发布于 2017-04-27 13:39:48

看起来,您缺少了指导Spring如何加载嵌套jars的MANFIEST.MF文件。这里是Spring文档中的一个示例层次结构。您可以阅读如何配置它到这里来

MANIFEST.MF应该包含此内容(用于下面的结构):

代码语言:javascript
运行
复制
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.mycompany.project.MyApplication

Start-Class是您进入应用程序的入口点,Main-Class是加载嵌套jars所需的加载器。

示例结构:

代码语言:javascript
运行
复制
example.war
 |
 +-META-INF
 |  +-MANIFEST.MF
 +-org
 |  +-springframework
 |     +-boot
 |        +-loader
 |           +-<spring boot loader classes>
 +-WEB-INF
    +-classes
    |  +-com
    |     +-mycompany
    |        +-project
    |           +-YourClasses.class
    +-lib
    |  +-dependency1.jar
    |  +-dependency2.jar
    +-lib-provided
       +-servlet-api.jar
       +-dependency3.jar
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43458991

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档