本文介绍了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:

如您所见,加载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,包装器类指的是这两个类.

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:

因此,可以推断出ClassA和ClassB首先是由MyClassLoader加载的,然后实际上是由HaoClassLoader和RuanClassLoader加载的.而且我认为这个实验可以看作是OSGi捆绑软件类加载器机制的一种非常简单的实现?对吧?

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中,每个捆绑包有一个类加载器.该类加载器服务于捆绑软件中的所有类.对于捆绑软件之外的所有类,都有导入打包"定义.在运行时,每个导入的软件包都连接到一个导出软件包的包中.从此类包中加载类时,将加载委派给其他捆绑软件类加载器.

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的激活器中加载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类加载器的用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-12 06:50