OSGI bundle 运行报错 java.lang.ClassNotFoundException & java.lang.NoClassDefFoundError

OSGI bundle 运行报错 java.lang.ClassNotFoundException & java.lang.NoClassDefFoundError

在 helloworld-server bundle 中引入了 MySQL JDBC 驱动包(mysql-connector-java-5.1.35-bin.jar),helloworld-client bundle 调用 helloworld-server bundle MySQL 连接测试接口时报错,驱动加载失败。


测试过程中,里遇下面两种类型的报错:

错误1:ClassNotFoundException
...
!MESSAGE FrameworkEvent ERROR
!STACK 0
org.osgi.framework.BundleException: Exception in com.xxx.osgi.helloworld.client.Activator.start() of bundle helloworld_client.
    at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:839)
    at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:767)
    at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1032)
    at org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:371)
    at org.eclipse.osgi.container.Module.doStart(Module.java:605)
    at org.eclipse.osgi.container.Module.start(Module.java:468)
    at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel$2.run(ModuleContainer.java:1852)
    at org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor$1$1.execute(EquinoxContainerAdaptor.java:136)
    at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1845)
    at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1788)
    at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.doContainerStartLevel(ModuleContainer.java:1750)
    at org.eclipse.osgi.container.SystemModule.startWorker(SystemModule.java:269)
    at org.eclipse.osgi.container.Module.doStart(Module.java:605)
    at org.eclipse.osgi.container.Module.start(Module.java:468)
    at org.eclipse.osgi.container.SystemModule.start(SystemModule.java:193)
    at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:445)
    at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:464)
    at org.eclipse.osgi.launch.Equinox.start(Equinox.java:139)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.startup(EclipseStarter.java:338)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:251)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.main(EclipseStarter.java:228)
Caused by: java.lang.NoClassDefFoundError: javax/crypto/NoSuchPaddingException
    at com.mysql.cj.protocol.a.NativeProtocol.negotiateSSLConnection(NativeProtocol.java:334)
    at com.mysql.cj.protocol.a.NativeAuthenticationProvider.negotiateSSLConnection(NativeAuthenticationProvider.java:777)
    at com.mysql.cj.protocol.a.NativeAuthenticationProvider.proceedHandshakeWithPluggableAuthentication(NativeAuthenticationProvider.java:486)
    at com.mysql.cj.protocol.a.NativeAuthenticationProvider.connect(NativeAuthenticationProvider.java:202)
    at com.mysql.cj.protocol.a.NativeProtocol.connect(NativeProtocol.java:1449)
    at com.mysql.cj.NativeSession.connect(NativeSession.java:165)
    at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:955)
    at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:825)
    at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:455)
    at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:240)
    at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:199)
    at java.sql.DriverManager.getConnection(DriverManager.java:664)
    at java.sql.DriverManager.getConnection(DriverManager.java:247)
    

错误2:NoClassDefFoundError
...
!MESSAGE FrameworkEvent ERROR
!STACK 0
org.osgi.framework.BundleException: Exception in com.xxx.osgi.helloworld.client.Activator.start() of bundle helloworld_client.
    at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:839)
    at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:767)
    at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1032)
    at org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:371)
    at org.eclipse.osgi.container.Module.doStart(Module.java:605)
    at org.eclipse.osgi.container.Module.start(Module.java:468)
    at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel$2.run(ModuleContainer.java:1852)
    at org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor$1$1.execute(EquinoxContainerAdaptor.java:136)
    at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1845)
    at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.incStartLevel(ModuleContainer.java:1788)
    at org.eclipse.osgi.container.ModuleContainer$ContainerStartLevel.doContainerStartLevel(ModuleContainer.java:1750)
    at org.eclipse.osgi.container.SystemModule.startWorker(SystemModule.java:269)
    at org.eclipse.osgi.container.Module.doStart(Module.java:605)
    at org.eclipse.osgi.container.Module.start(Module.java:468)
    at org.eclipse.osgi.container.SystemModule.start(SystemModule.java:193)
    at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:445)
    at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:464)
    at org.eclipse.osgi.launch.Equinox.start(Equinox.java:139)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.startup(EclipseStarter.java:338)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:251)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.main(EclipseStarter.java:228)
Caused by: java.lang.NoClassDefFoundError: javax/naming/NamingException
    at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:186)
    at java.sql.DriverManager.getConnection(DriverManager.java:664)
    at java.sql.DriverManager.getConnection(DriverManager.java:247)
    at com.xxx.osgi.helloworld.server.MySQLConnImpl.selectTest(MySQLConnImpl.java:78)
    at com.xxx.osgi.helloworld.client.Activator.mysqlConnectorServiceTest(Activator.java:59)

g! install my_bundles/mysql-connector-java-5.1.35-bin.jar
Bundle ID: 45
g! install my_bundles/helloworld-server-1.0.0-SNAPSHOT.jar
Bundle ID: 46
g! install my_bundles/helloworld-client-1.0.0-SNAPSHOT.jar
Bundle ID: 47
g! ss
"Framework is launched."


id      State       Bundle
0       ACTIVE      org.eclipse.osgi_3.18.600.v20231110-1900
1       ACTIVE      org.eclipse.equinox.console_1.4.600.v20231106-0859
2       INSTALLED   org.eclipse.core.jobs_3.15.100.v20230930-1207
3       INSTALLED   org.eclipse.core.runtime_3.30.0.v20231102-0719
4       INSTALLED   org.eclipse.equinox.common_3.18.200.v20231106-1826
5       ACTIVE      org.apache.felix.gogo.command_1.1.2
6       ACTIVE      org.apache.felix.gogo.runtime_1.1.6
7       ACTIVE      org.apache.felix.gogo.shell_1.1.4
45      INSTALLED   com.mysql.jdbc_5.1.35
46      INSTALLED   helloworld_server_1.0.0.SNAPSHOT
47      INSTALLED   helloworld_client_1.0.0.SNAPSHOT
g! start 45

g! start 46
helloworld-server: start
helloworld-server: helloworld 服务已发布(注册)!
helloworld-server: mysqlConn 服务已发布(注册)!

g! start 47
helloworld-client: start
helloworld-client: call server getHelloMsg()
SUCCESS: return msg is:
[getHelloMsg:29]  HelloWorld Frank
[selectTest:65] ERROR: jdbc driver load failed, ClassNotFound!
java.sql.SQLException: java.lang.NoClassDefFoundError: javax/naming/RefAddr
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:998)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:937)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:926)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:872)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:904)
        at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:894)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:407)
        at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:399)
        at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:325)
        at java.sql.DriverManager.getConnection(DriverManager.java:664)
        at java.sql.DriverManager.getConnection(DriverManager.java:247)
        at com.xxx.osgi.helloworld.server.MySQLConnImpl.selectTest(MySQLConnImpl.java:46)
        at com.xxx.osgi.helloworld.client.Activator.mysqlConnectorServiceTest(Activator.java:59)
        at com.xxx.osgi.helloworld.client.Activator.start(Activator.java:35)
        at org.eclipse.osgi.internal.framework.BundleContextImpl$2.run(BundleContextImpl.java:818)
        at org.eclipse.osgi.internal.framework.BundleContextImpl$2.run(BundleContextImpl.java:1)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:810)
        at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:767)
        at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1032)
        at org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:371)
        at org.eclipse.osgi.container.Module.doStart(Module.java:605)
        at org.eclipse.osgi.container.Module.start(Module.java:468)
        at org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:445)
        at org.apache.felix.gogo.command.Basic.start(Basic.java:692)
        at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.apache.felix.gogo.runtime.Reflective.invoke(Reflective.java:143)
        at org.apache.felix.gogo.runtime.CommandProxy.execute(CommandProxy.java:91)
        at org.apache.felix.gogo.runtime.Closure.executeCmd(Closure.java:599)
        at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:526)
        at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:415)
        at org.apache.felix.gogo.runtime.Pipe.doCall(Pipe.java:416)
        at org.apache.felix.gogo.runtime.Pipe.call(Pipe.java:229)
        at org.apache.felix.gogo.runtime.Pipe.call(Pipe.java:59)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoClassDefFoundError: javax/naming/RefAddr
        at com.mysql.jdbc.ConnectionPropertiesImpl.<init>(ConnectionPropertiesImpl.java:657)
        at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:696)
        at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:44)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
        at com.mysql.jdbc.Util.handleNewInstance(Util.java:389)
        ... 33 more
Caused by: java.lang.ClassNotFoundException: javax.naming.RefAddr cannot be found by helloworld_server_1.0.0.SNAPSHOT
        at org.eclipse.osgi.internal.loader.BundleLoader.generateException(BundleLoader.java:541)
        at org.eclipse.osgi.internal.loader.BundleLoader.findClass0(BundleLoader.java:536)
        at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:416)
        at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:168)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 41 more
SUCCESS: mysqlConnectorServiceTest(), result:


最终的解决办法:
修改 pom ,增加 Dynamicimport-Package 配置:<Dynamicimport-Package>com.mysql.*</Dynamicimport-Package>,
或者配置成 <Dynamicimport-Package>*</Dynamicimport-Package>。
我之前是在配置 <Export-Package> 中导出 com.mysql.*。改为后:

执行结果:

g! stop 45 46 47
g! uninstall 45 46 47
g! 
g! install my_bundles/mysql-connector-java-5.1.35-bin.jar
g! Bundle ID: 48
g! install my_bundles/helloworld-server-1.0.0-SNAPSHOT.jar
g! Bundle ID: 49
g! install my_bundles/helloworld-client-1.0.0-SNAPSHOT.jar
g! Bundle ID: 50
g! 
g! start 48
g! start 49
helloworld-server: start
helloworld-server: helloworld 服务已发布(注册)!
helloworld-server: mysqlConn 服务已发布(注册)!

g! start 50
helloworld-client: start
helloworld-client: call server getHelloMsg()
SUCCESS: return msg is:
[getHelloMsg:29]  HelloWorld Frank
[selectTest:51] ==== Table: test01 ====
1,aaa,11
2,bbb,22
3,uu,12
4,xx,12

MySQL 连接测试成功。

1)mysql jdbc 驱动 bundle 需要先 install & start,否则会报错;
2)server bundle manifest 需要配置 Dynamicimport-Package,只 mysql jdbc bundle start,不设置 Dynamicimport-Package,也还是会报错;

网上有关于NoClassDefFoundError报错的类似介绍,项目引用了第三方包的class加载其他的类,而这些类又不在当前的 bundle 中就可能会出现这个 NoClassDefFoundError 异常
ExceptioninthreadThread-1java.lang.NoClassDefFoundError:javax/naming/NamingException
也有说配置成 DynamicImport-Package: * 。如果引入的第三方包的class加载其他的类比较多的话,可以直接配置成 * 动态导入所有依赖。
 

====== ====== ====== ====== ====== ======

mysql jdbc 驱动 jar 包也是一个bundle,从其 manifest 文件可以看出来。

为了避免手动 install & start mysql jdbc jar包,把第三方的 mysql-jdbc驱动jar包作为普通的jar包依赖打包到 helloworld-server jar包中(保存到 /lib 目录下、并自动加入 Bundle-ClassPath),

最终pom文件如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>helloworld</artifactId>
        <groupId>com.xxx.osgi</groupId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>helloworld-server</artifactId>
    <packaging>bundle</packaging>

    <name>helloworld-server</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <!-- osgi lib 使用主 pom 中定义的依赖,子模块不再重复定义 osgi lib dependency -->
<!--        <dependency>-->
<!--            <groupId>mysql</groupId>-->
<!--            <artifactId>mysql-connector-java</artifactId>-->
<!--            <version>8.0.15</version>-->
<!--        </dependency>-->

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.35</version>
        </dependency>

<!--        <dependency>-->
<!--            <groupId>mysql</groupId>-->
<!--            <artifactId>mysql-connector-java</artifactId>-->
<!--            <version>5.1.35</version>-->
<!--            <scope>system</scope>-->
<!--            <systemPath>${project.basedir}/lib/mysql-connector-java-5.1.35-bin.jar</systemPath>-->
<!--        </dependency>-->

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <!-- osgi 打包配置,使用 maven-bundle-plugin 插件进行 osgi 打包 bundle jar -->
                <!-- 使用maven-bundle-plugin打包方式时指定manifest文件不生效,但可在 instructions 中配置 manifest 参数 -->
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <version>${parent.maven.bundle.plugin.version}</version>
                <extensions>true</extensions>

                <configuration>
                    <instructions>
                        <!-- 把依赖的普通jar和bundle jar也一起打包进去(/lib目录下),bundle jar 服务依赖还要在 Import-Package 中指定 -->
                        <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
                        <Embed-Directory>/lib</Embed-Directory>
                        <Bundle-Name>${project.name}</Bundle-Name>
                        <Bundle-SymbolicName>$(replace;${project.artifactId};-;_)</Bundle-SymbolicName>
                        <Bundle-Version>${project.version}</Bundle-Version>
                        <Bundle-Activator>com.xxx.osgi.helloworld.server.Activator</Bundle-Activator>
                        <Dynamicimport-Package>*</Dynamicimport-Package>
                        <!-- <Dynamicimport-Package>com.mysql.*</Dynamicimport-Package> -->
                        <Import-Package>org.osgi.framework</Import-Package>
                        <Export-Package>
                            com.xxx.osgi.helloworld.server;version="${project.version}"
                        </Export-Package>
                    </instructions>
                </configuration>


<!--                <configuration>-->
<!--                    <instructions>-->
<!--                        &lt;!&ndash; 如果要把依赖的 jar 也一起打包进去,在 Import-Package 中指定、并设置 Embed-Dependency &ndash;&gt;-->
<!--                        <Embed-Dependency>*;scope=compile|runtime;inline=true</Embed-Dependency>-->
<!--                        <_exportcontents>*</_exportcontents>-->
<!--                    </instructions>-->
<!--                </configuration>-->

                <!-- maven-bundle-plugin 设置 goal bundleall 将所有依赖jar和所有依赖bundle-->
<!--                <executions>-->
<!--                    <execution>-->
<!--                        <id>wrap-my-dependency</id>-->
<!--                        <goals>-->
<!--                            <goal>bundleall</goal>-->
<!--                        </goals>-->
<!--                    </execution>-->
<!--                </executions>-->
<!--                <configuration>-->
<!--                    <wrapImportPackage>*</wrapImportPackage>-->
<!--                </configuration>-->

            </plugin>
        </plugins>
    </build>
</project>

最终生成的jar包架构和内容如下:

执行hellworld-server时自动会加载jdbc驱动包,不需要提前 install & start jdbc bundle: 

注意:如果需要把本地lib/目录下的下的第三方的jar包( dependency scope 为 system)也打入到目标jar包中去,Embed-Dependency 是做不到的,需要采用 Include-Resource 方式:

  • 20
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值