OSGi 中 Java 类加载器的使用 [英] Java classloader usage in OSGi

查看:38
本文介绍了OSGi 中 Java 类加载器的使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于在 OSGi 中使用 Java ClassLoader 的问题.

I have a question about the usage of Java ClassLoader in OSGi.

我编写了两个 OSGi 包,即服务器包和客户端包.

I wrote two OSGi bundles, namely server bundle and client bundle.

在服务器包中,我实现了 BundleActivator,如:

In server bundle, I implemented BundleActivator like:

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 如下:

And in client bundle, I implemented BundleActivator like:

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 时,控制台输出:

And when I started OSGi, the console output:

[Server:Activator.java:26] org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@56b161a[osgi-server:1.0.0(id=54)][Client: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)]

[Server:Activator.java:26] org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader@56b161a[osgi-server:1.0.0(id=54)] [Client: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,无论是在服务器端还是客户端.

As you can see, the classloader that loads HelloService is always DefaultClassLoader@56b161a no matter it is at server side or client side.

我无法理解这一点.据我所知,当A类引用B类时,B类的类加载器和A类的类加载器是一样的.但在 OSGi 中,似乎不是这样.

I can not understand this. In my knowledge, when class B is referenced in class A, the classloader of class B is the same as class A's classloader. But in OSGi, it seems not this way.

你能指教我吗?我想念 Java ClassLoader 吗?还是 OSGi 在做一些棘手的事情?

Can you enlighten me? Is there something I miss about Java ClassLoader? Or is OSGi doing something tricky?

服务器包的清单是:

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

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

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

尼尔,这是我刚刚做的实验:

Hi Neil, this is the experiment I just did:

我有 ClassA 和 ClassB,class Wrapper 是指这两个类.

I have ClassA and ClassB, and class Wrapper refers to these 2 classes.

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:

And I wrote my own customized classloader 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();,控制台输出:

Then I called Class.forName("com.cisco.ruan.classloader.Wrapper", true, mcl).newInstance();, and the console outputs:

[Wrapper.java:5] com.cisco.ruan.classloader.HaoClassLoader@248523a0[Wrapper.java:8] com.cisco.ruan.classloader.RuanClassLoader@3c635421

[Wrapper.java:5] com.cisco.ruan.classloader.HaoClassLoader@248523a0 [Wrapper.java:8] com.cisco.ruan.classloader.RuanClassLoader@3c635421

因此,可以推断ClassA和ClassB首先被MyClassLoader加载,然后实际被HaoClassLoader和RuanClassLoader加载.而且我认为这个实验可以看作是 OSGi bundle 类加载器机制的一个非常简单的实现?对吗?

So, it can be inferred that ClassA and ClassB is at first loaded by MyClassLoader and then actually loaded by HaoClassLoader and RuanClassLoader. And I think this experiment can be seem as a very simple implementation of OSGi bundle classloader mechanism? Right?

推荐答案

这在 OSGi 中是完全正常的.在 OSGi 中,每个包有一个类加载器.这个类加载器为位于包中的所有类提供服务.对于 bundle 之外的所有类,都有 Import-Package 定义.在运行时,每个包导入都连接到一个导出包的包.当加载来自此类包的类时,加载会委托给其他包类加载器.

This is completely normal in OSGi. In OSGi there is one classloader per bundle. This classloader serves all classes that are located in the bundle. For all classes outside the bundle there are Import-Package definitions. At runtime each package import is wired to a bundle that exports the package. When a class from such a package is loaded the loading is delegated to the other bundles classloader.

让我们来看看你的场景.

Lets go through your scenario.

捆绑 osgi-server 包含类 com.cisco.ruan.server.HelloService 它也导出包 com.cisco.ruan.server.捆绑 osgi-client 导入包 com.cisco.ruan.server.当您在 osgi-client 的 Activator 中加载 HelloService 类时,会要求 osgi-client 的类加载器加载该类.它为包找到一个委托并将加载委托给 osgi-server 的类加载器.然后这个类加载器是用户加载类.

Bundle osgi-server contains the class com.cisco.ruan.server.HelloService it also export the package com.cisco.ruan.server. Bundle osgi-client imports the package com.cisco.ruan.server. When you load the HelloService class in the Activator of osgi-client the classloader of osgi-client is asked to load the class. It finds a delegation for the package and delegates loading to the classloader of osgi-server. This classloader is then user to load the class.

这是 OSGi 中的默认行为,如果您认为它很有意义.

This is the default behaviour in OSGi and if you think it through it makes a lot of sense.

这篇关于OSGi 中 Java 类加载器的使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆