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.
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.
at com.mysql.jdbc.ConnectionImpl.
at com.mysql.jdbc.JDBC4Connection.
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 配置:
或者配置成
我之前是在配置
执行结果:
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文件如下:
helloworld
com.xxx.osgi
1.0.0-SNAPSHOT
4.0.0
helloworld-server
bundle
helloworld-server
http://maven.apache.org
UTF-8
mysql
mysql-connector-java
5.1.35
org.apache.felix
maven-bundle-plugin
${parent.maven.bundle.plugin.version}
true
*;scope=compile|runtime
/lib
${project.name}
$(replace;${project.artifactId};-;_)
${project.version}
com.xxx.osgi.helloworld.server.Activator
*
org.osgi.framework
com.xxx.osgi.helloworld.server;version="${project.version}"
最终生成的jar包架构和内容如下:
执行hellworld-server时自动会加载jdbc驱动包,不需要提前 install & start jdbc bundle:
注意:如果需要把本地lib/目录下的下的第三方的jar包( dependency scope 为 system)也打入到目标jar包中去,Embed-Dependency 是做不到的,需要采用 Include-Resource 方式: