OSGi 探秘系列 (4)- OSGi Bundle之依赖关系

本文深入探讨OSGi框架下类加载机制的改进,特别关注包级别的导入与导出,以及如何在Bundle间明确声明依赖关系与版本化信息。通过实例解析,展示了如何在Bundle中导出和导入接口,以及依赖关系的定义与解析过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在之前一篇我写的文章OSGi 探秘系列 (1)- 概述什么是OSGi框架 中,OSGi对Java平台的类加载机制的一个重要改进就是支持包级别的类导入和导出,而不仅仅在jar级别。本文将详细介绍OSGi这一改进机制,并介绍在OSGi中如何定义和解析Bundle之间的依赖关系。

 

在Java以及很多其它面向对象编程语言中,类之间的依赖关系都是在code中隐含的,当依赖关系不满足的时候,在运行时会产生ClassNotFoundException或者NoClassDefFoundError之类的异常或者错误。OSGi则改变了这一状况,类之间的依赖关系是显式声明 的以及版本化 的。显式声明指的是依赖关系是按照某种标准的方式写在文件里,任何人任何程序都可以访问和看懂,而不是写在代码里;版本化指的是依赖关系显示声明所依赖的类的版本。

 

我们先通过一个例子介绍如何在Bundle中Export和Import包。该例子实例了一个Mailbox服务,包括了两个Bundle。

 

=============================== 第一个Bundle ===============================

 

包含了两个接口

 

// org.osgi.message.reader.api.MailBox.java

package org.osgi.message.reader.api;

public interface MailBox {
    
    public static final String NAME_PROPERTY = "mailboxName ";
    
    long [] getAllMessages() throws MailboxException;
    
    long [] getMessagesSince(long id) throws MailboxException;
    
    void markRead(boolean read, long [] ids) throws MailboxException;
    
    Message [] getMessages(long [] ids) throws MailboxException;

}

 

// org.osgi.message.reader.api.Message.java

 

package org.osgi.message.reader.api;

 

import java.io.InputStream;

public interface Message {

    long getId();
    
    String getSummary();
    
    String getMIMEType();
    
    InputStream getContent() throws MessageReaderException;
    
}

 

创建一个mailbox_api.bnd的文件,文件内容如下

 

Export-Package : org.osgi.message.reader.api;version=1.0.0

 

右击然后点击Make Bundle, 可以看到生成了Bundle的jar文件mailbox_api.jar.

 

=============================== 第二个Bundle ===============================

该Bundle包含了对上面两个接口的实现类。

//org.osgi.message.reader.fixedmailbox.FixedMailbox.java

 

package org.osgi.message.reader.fixedmailbox;

import java.util.ArrayList;
import java.util.List;

import org.osgi.message.reader.api.MailBox;
import org.osgi.message.reader.api.MailboxException;
import org.osgi.message.reader.api.Message;

public class FixedMailbox implements MailBox {

    protected final List<Message> messages;
    
    public FixedMailbox() {
        messages = new ArrayList<Message>(2);
        messages.add(new StringMessage(0, "Hello", "Welcome to OSGi"));
        messages.add(new StringMessage(1, "Getting Started", "Study OSGi in depth"));
    }

 

    // Omit the implementation of the inherited methods from MailBox.java

 

}

 

// org.osgi.message.reader.fixedmailbox.StringMessage.java

package org.osgi.message.reader.fixedmailbox;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

import org.osgi.message.reader.api.Message;
import org.osgi.message.reader.api.MessageReaderException;

public class StringMessage implements Message {

    private static final String MIME_TYPE_TEXT = "text/plain";
    private long id;
    private String summary;
    private String content;
    
    public StringMessage(long id, String summary, String content){
        this .id = id;
        this .summary = summary;
        this .content = content;
    }

 

    // Omit the implementation of the inherited methods from Message.java


}

 

创建一个fixed_mailbox.bnd的文件,文件内容如下

 

Private-Package: org.osgi.message.reader.fixedmailbox;

 

右击然后点击Make Bundle, 可以看到生成了Bundle的jar文件mailbox_api.jar. 在这个jar文件中,MANIFEST 的文件内容如下。可以看到,BND编辑器自动解析了在实现类中import的java包,然后加在了Import-Package中。

 

Bnd-LastModified                        1262573897968                           
Bundle-ManifestVersion              2                                       
Bundle-Name                              fixed_mailbox                           
Bundle-SymbolicName                 fixed_mailbox                           
Bundle-Version                           0                                       
Created-By                                 1.6.0_13 (Sun Microsystems Inc.)        
Import-Package                          org.osgi.message.reader.api             
Manifest-Version                        1.0                                     
Private-Package                         org.osgi.message.reader.fixedmailbox    
Tool                                            Bnd-0.0.384

 

 

在上面的例子中,我们看到第一个Bundle所Export的包org.osgi.message.reader.api被第二个Bundle Import了,我们就说第二个Bundle对第一个Bundle存在依赖关系 

 

在OSGi R4中,引入了一个新的header叫做"Required-Bundle",其实际效果等于Import该Bundle所有Export出来的包。我觉得这其实是一个非常有用的header。想象一下在一个有数以千计的Bundle的系统中,如果逐个指定包层次的依赖关系将会是怎样一个噩梦。另外值得注意的是,所有java.*的包都是默认被Import的,不需要再在MANIFEST文件中声明,但是javax.*的包则需要声明。

 

从上面我们可以看到OSGi如何通过显示声明的方式定义Bundle之间的依赖关系,下面我们介绍在依赖声明中如何指定版本化信息。在OSGi中,版本信息的格式是三个数字段加上一个字符串段,比如"1.2.3", "1.1", "1.0.2.beta1". 下面这个例子可以让大家了解如何基本使用版本信息。

 

                     Export-Package                            org.osgi.message.reader.api;version="1.0.0"

                     Bundle-Version                            1.0.0

 

另外,版本也可以用范围的形式指定。假设版本值用变量v表示,(1.0, 2.0)表明1.0<v<2.0, [1.1.2, 1.2.1]表明1.1.2<= v<=1.2.1,以此类推。下面两个例子示范了如何在Import包以及Bundle中使用版本范围。

                     Import - Package                           org.apache.log4j.*; version = " [ 1 . 2 , 1 . 3 ) "

                     Require-Bundle                           mailbox-api;bundle-version="[1.0.0, 1,1.2]"

 


在这篇文章的最后,我再总结一下OSGi框架下的类加载机制。当Bundle被安装后,OSGi按照以下顺序进行类加载:

1) 从上层类加载器中加载java.*的包

2) 加载MANIFEST中的Import-Package所指定的包

3) 加载MANIFEST中的Require-Bundle所指定的Bundle

4) 加载该Bundle自身包含的类

5) 从Fragment bundle中加载类。

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值