思路

OSGi每个模块都有自己独立的classpath。如何实现这一点呢?是因为OSGi采取了不同的类加载机制:

  • OSGi为每个bundle提供一个类加载器,该加载器能够看到bundle Jar文件内部的类和资源;
  • 为了让bundle能互相协作,可以基于依赖关系,从一个bundle类加载器委托到另一个bundle类加载器。
 

Java和J2EE的类加载模型都是层次化的,只能委托给上一层类加载器;

而OSGi类加载模型则是网络图状的,可以在bundle间互相委托。——这样更合理,因为bundle间的依赖关系并不是层次化的。

例如bundleA、B都依赖于bundleC,当他们访问bundleC中的类时,就会委托给bundleC的类加载器,由它来查找类;如果它发现还要依赖bundleE中的类,就会再委托给bundleE的类加载器。

优点

  • 找不到类时的错误提示更友好。假如bundleE不存在,则bundleC就不会被解析成功,会有错误消息提示为何未能解析;而不是报错ClassNotFoundException或NoClassDefFoundError。
  • 效率更高。在标准Java类加载模型中,总是会在classpath那一长串列表中进行查找;而OSGi类加载器能立即知道去哪里找类。

类加载步骤

 

 
 

Step 1: 检查是否java.*,或者在bootdelegation中定义

当bundle类加载器需要加载一个类时,首先检查包名是否以java.*开头,或者是否在一个特定的配置文件(org.osgi.framework.bootdelegation)中定义。如果是,则bundle类加载器立即委托给父类加载器(通常是Application类加载器)。

这么做有两个原因:

  • 唯一能够定义java.*包的类加载器是bootstrap类加载器,这个规则是JVM要求的。如果OSGI bundle类加载器试图加载这种类,则会抛Security Exception。
  • 一些JVM错误地假设父加载器委托永远会发生,内部VM类就能够通过任何类加载器找到特定的其他内部类。所以OSGi提供了org.osgi.framework.bootdelegation属性,允许对特定的包(即那些内部VM类)使用父加载器委托

Step 2: 检查是否在Import-Package中声明

检查是否在Import-Package中声明。如果是,则找到导出包的bundle,将类加载请求委托给该bundle的类加载器。如此往复。

Step 3: 检查是否在Require-Bundle中声明

检查是否在Require-Bundle中声明。如果是,则将类加载请求委托给required bundle的类加载器。

Step 4: 检查是否bundle内部类

检查是否是该bundle内部的类,即当前JAR文件中的类。

Step5:  检查fragment

搜索可能附加在当前bundle上的fragment中的内部类。

什么是fragment?

Fragment bundle是OSGi 4引入的概念,它是一种不完整的bundle,必须要附加到一个host bundle上才能工作;fragment能够为host bundle添加类或资源,在运行时,fragment中的类会合并到host bundle的内部classpath中。

fragment有什么作用?

【场景1】bundle中有针对特定平台的代码

假设bundle对不同平台的实现方式稍有不同,Windows和Linux下代码有不同之处,即bundle中有针对特定平台的代码。

我们应该为每个平台提供不同的bundle吗?——显然不能,因为那会造成代码重复。

或者将共同代码放到bundle A中,Windows特定的那部分代码放到bundle Pwin中,Linux特定的那部分代码放到bundle Plinux中。——有问题:Pwin肯定要依赖A中某些包,我们就必须在A中导出这些包,如果只有Pwin用到这些包 岂不破坏封装性。

最好的解决方法是把Pwin作为fragment,附加到A中。这样Pwin就能看到A中的所有包,A也能看到Pwin的所有包。

【场景2】针对不同国家用户提供不同的i18n

GUI程序通常会通过properties文件定义i18n信息,可以将不同的i18n存到不同的fragment中。运行时用户只需要下载host bundle以及特定的i18n fragment即可,不需要把其他国家的i18n也下载下来。

Step6: 动态类加载

//TODO

完整的类加载流程图如下:

The class search algorithm as described always attempts to load classes from another bundle in preference to classes that may be on the classpath of the present bundle. This may seem counterintuitive at first, but in fact it makes a lot of sense, and it fits perfectly with the conventional Java approach.
A traditional Java class loader always first delegates to its parent before attempting to define a class itself. This helps to ensure that classes are loaded as few times as possible, by favouring already-defined copies of a class over redefining it in a lower-level class loader. The opposite approach would result in many copies of the same class, which would be considered incompatible because they were defined by different class loaders.
Back in OSGi, where the class loaders are arranged in a graph rather than a tree, the same principle of minimising class loading translates to making every effort to find a class from a bundle’s imports rather than loading it from the internal bundle classpath.
 

OSGi类加载流程的更多相关文章

  1. OSGi类加载问题

    项目中遇到的JVM难点 ——启动OSGi容器时,出现永久代内存不够.内存泄露 ——OSGi找不到类路径问题. ——线程死锁问题.   问题一:OSGi类内存问题         其次,从内存用量来看, ...

  2. JVM,Tomcat与OSGi类加载机制比较

    首先一个思维导图来看下Tomcat的类加载机制和JVM类加载机制的过程 类加载 在JVM中并不是一次性把所有的文件都加载到,而是一步一步的,按照需要来加载. 比如JVM启动时,会通过不同的类加载器加载 ...

  3. 并行类加载与OSGI类加载

    这回来分析一下OSGI的类加载机制. 先说一下OSGI能解决什么问题吧. 记得在上家公司的时候,经常参与上线.上线一般都是增加了一些功能或者修改了一些功能,然后将所有的代码重新部署.过程中要将之前的服 ...

  4. Android类加载流程

    背景 由于前前前阵子写了个壳,得去了解类的加载流程,当时记了一些潦草的笔记.这几天把这些东西简单梳理了一下,本文分析的代码基于Android8.1.0源码. 流程分析 从loadClass开始,我们来 ...

  5. JVM类加载流程

    1.加载 a.装载类的第一个阶段 b.取得类的二进制流 c.转为方法区数据结构 d.在Java堆中生成对应的java.lang.Class对象 2.链接 a.验证(保证Class流的格式是正确的) 文 ...

  6. 深入理解JVM(六)——类加载器原理

    我们知道我们编写的java代码,会经过编译器编译成字节码文件(class文件),再把字节码文件装载到JVM中,映射到各个内存区域中,我们的程序就可以在内存中运行了.那么字节码文件是怎样装载到JVM中的 ...

  7. JVM学习--(六)类加载器原理

    我们知道我们编写的java代码,会经过编译器编译成字节码文件(class文件),再把字节码文件装载到JVM中,映射到各个内存区域中,我们的程序就可以在内存中运行了.那么字节码文件是怎样装载到JVM中的 ...

  8. 深入理解JVM一类加载器原理

    我们知道我们编写的java代码,会经过编译器编译成字节码文件(class文件),再把字节码文件装载到JVM中,映射到各个内存区域中,我们的程序就可以在内存中运行了.那么字节码文件是怎样装载到JVM中的 ...

  9. 深入理解JVM虚拟机6:深入理解JVM类加载机制

    深入理解JVM类加载机制 简述:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 下面我们具体 ...

随机推荐

  1. fidller判断只抓固定host

    设置好,填入对应的host,操作-立即运行过滤设置 效果

  2. java springboot 大文件分片上传处理

    参考自:https://blog.csdn.net/u014150463/article/details/74044467 这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时 ...

  3. Python之MySQL库表操作

    一:库操作 1.1 增 # 语法 # create database 库名 default charset utf8; create database db1 default charset utf8 ...

  4. 错误笔记 对象为null时调用改对象的方法会报错

    对象为null时调用改对象的方法会报错

  5. OpenCV-Python:车道检测

    任务: 一共要完成两项任务: 1. 在所提供的公路图片上检测出车道线并标记 2. 在所提供的公路视频上检测出车道线并标记 方案: 要检测出当前车道,就是要检测出左右两条车道直线.由于无人车一直保持在当 ...

  6. 关于8.0.15版本的mysql下载与安装

    下载MYSQL 官网下载MYSQL8.0.15版本,链接地址https://www.mysql.com/downloads/,流程如下 点击进入后,网页滑到最下面,根据自己电脑的型号下载相应的版本 安 ...

  7. python批量重命名【截取文件名前六个字符 】

    #!/usr/bin/python # -*- coding: UTF-8 -*- import os, sys # 打开文件 path = "/home/landv/Desktop/l/& ...

  8. Rafy 框架 - 时间戳插件

    本文将解释 Rafy 框架中的时间戳插件的场景.使用方法.原理. 场景 在开发各类数据库应用系统时,业务领域实体往往需要包含"创建时间"."最后更新时间".&q ...

  9. vmware安装VMTools , VirtualBox "安装增强功能"

    https://www.vmware.com/support/ws45/doc/new_guest_tools_ws.html 直接参考官方文档,中文没找到啥有用的资料 https://www.cnb ...

  10. 利用Skywalking-netcore监控你的应用性能

    Skywalking SkyWalking开源项目由吴晟于2015年创建,同年10月在GitHub上作为个人项目开源. SkyWalking项目的核心目标,是针对微服务.Cloud Native.容器 ...