【发布时间】:2016-04-16 17:04:50
【问题描述】:
我有一个关于在 OSGi 中使用 Java ClassLoader 的问题。
我写了两个 OSGi 包,分别是服务器包和客户端包。
在服务器捆绑包中,我实现了 BundleActivator,如下所示:
public class Activator implements BundleActivator {
public void start(BundleContext context) {
System.out.println("[Server:Activator.java:26] " + Activator.class.getClassLoader());
context.registerService(HelloService.class, new HelloService(), null);
}
public void stop(BundleContext context) {
System.out.println("Stopping the bundle");
}
}
在客户端包中,我实现了 BundleActivator,如下所示:
public class Activator implements BundleActivator {
public void start(BundleContext context) {
ServiceReference<HelloService> ref = context.getServiceReference(HelloService.class);
HelloService service = context.getService(ref);
System.out.println("[Client:Activator.java:48] " + HelloService.class.getClassLoader());
System.out.println("[Client:Activator.java:49] " + Activator.class.getClassLoader());
}
public void stop(BundleContext context) {
System.out.println("Stopping the bundle");
}
}
当我启动 OSGi 时,控制台输出:
[服务器:Activator.java:26] org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@56b161a[osgi-server:1.0.0(id=54)] [客户端:Activator.java:48] org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@56b161a[osgi-server:1.0.0(id=54)] [Client:Activator.java:49] org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@3a1b72aa[osgi-client:1.0.0(id=55)]
如您所见,加载 HelloService 的类加载器始终是 DefaultClassLoader@56b161a,无论是在服务器端还是客户端。
我无法理解这一点。据我所知,当A类引用B类时,B类的类加载器和A类的类加载器是一样的。但在 OSGi 中,似乎不是这样的。
你能告诉我吗? Java ClassLoader 有什么我想念的吗?还是 OSGi 在做一些棘手的事情?
服务器包的清单是:
Manifest-Version: 1.0
Bnd-LastModified: 1452582379580
Build-Jdk: 1.7.0_45
Built-By: haoruan
Bundle-Activator: com.cisco.ruan.server.Activator
Bundle-Description: osgi-server OSGi bundle project.
Bundle-ManifestVersion: 2
Bundle-Name: osgi-server Bundle
Bundle-SymbolicName: osgi-server
Bundle-Version: 1.0
Created-By: Apache Maven Bundle Plugin
Export-Package: com.cisco.ruan.server;version="1.0";uses:="org.osgi.fram
ework"
Import-Package: org.osgi.framework;version="[1.7,2)"
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.5))"
Tool: Bnd-3.0.0.201509101326
客户端包的清单是:
Manifest-Version: 1.0
Bnd-LastModified: 1452582396099
Build-Jdk: 1.7.0_45
Built-By: haoruan
Bundle-Activator: com.cisco.ruan.client.Activator
Bundle-Description: osgi-client OSGi bundle project.
Bundle-ManifestVersion: 2
Bundle-Name: osgi-client Bundle
Bundle-SymbolicName: osgi-client
Bundle-Version: 1.0
Created-By: Apache Maven Bundle Plugin
Export-Package: com.cisco.ruan.client;version="1.0";uses:="com.cisco.rua
n.server,org.osgi.framework"
Import-Package: com.cisco.ruan.server;version="[1.0,2)",org.osgi.framewo
rk;version="[1.7,2)",org.slf4j;version="[1.7,2)"
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.5))"
Tool: Bnd-3.0.0.201509101326
================================================ =======
嗨,尼尔,这是我刚刚做的实验:
我有ClassA和ClassB,class Wrapper就是指这2个类。
public class Wrapper {
public Wrapper() {
showInfo();
}
public void showInfo() {
System.out.println("[Wrapper.java:5] " + ClassA.class.getClassLoader());
System.out.println("[Wrapper.java:8] " + ClassB.class.getClassLoader());
}
}
并且我编写了自己的自定义类加载器 MyClassLoader:
class MyClassLoader extends ClassLoader {
private ClassLoader haocl;
private ClassLoader ruancl;
public MyClassLoader() {
this.haocl = new HaoClassLoader();
this.ruancl = new RuanClassLoader();
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.endsWith("com.cisco.ruan.classloader.ClassA")) {
return haocl.loadClass(name);
}
if (name.endsWith("com.cisco.ruan.classloader.ClassB")) {
return ruancl.loadClass(name);
}
if (name.endsWith("Wrapper")) {
InputStream is = null;
try {
is = new FileInputStream("/Users/haoruan/Desktop/Projects/cl-test/target/classes/com/cisco/ruan/classloader/Wrapper.class");
} catch (Exception e) {
e.printStackTrace();
}
byte[] bytes = null;
try {
bytes = ByteStreams.toByteArray(is);
} catch (Exception e) {
e.printStackTrace();
}
return defineClass(name, bytes, 0, bytes.length);
}
return super.loadClass(name);
}
}
然后我打电话给Class.forName("com.cisco.ruan.classloader.Wrapper", true, mcl).newInstance();,控制台输出:
[Wrapper.java:5] com.cisco.ruan.classloader.HaoClassLoader@248523a0 [Wrapper.java:8] com.cisco.ruan.classloader.RuanClassLoader@3c635421
因此,可以推断ClassA和ClassB首先是由MyClassLoader加载的,然后是HaoClassLoader和RuanClassLoader实际加载的。而且我认为这个实验可以看作是 OSGi 捆绑类加载器机制的一个非常简单的实现?对吧?
【问题讨论】:
-
你能显示为你的 .bnd 文件或清单或 pom 吗?也许你设置了错误的捆绑激活器类。
标签: java osgi classloader osgi-bundle karaf