`
yangyangmyself
  • 浏览: 229528 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Java模块化解决方案

    博客分类:
  • Java
阅读更多

   网络上很多OSGi的文章上来就Activator实例,看得云里雾里。要想了解OSGi,首先要知道为什么要用

OSGi?它有哪些好处?

   首先要明确:Java缺少对高级模块化的支持。OSGi服务平台是专门针对Java对模块化支持不足的情况,

由OSGi联盟定义的一个行业标准,它引入了一个面向服务的编程模型,被称作“VM中的SOA”

Java模块化的不足

     为什么说Java缺少对高级模块化的支持?Java确实以面向对象的方式提供了某种程度的模块化,但它从未

考虑支持粗粒度的模块化编程。主要包括三个方面:

1. 可见性问题 / 信息隐藏

  • There is no mechanism for information hiding between JARs——JAR文件直接无法实现信息隐藏。

一个Java类,可以是public,也可以是package-private;但是一个Java包呢?Java提供了很多控制可见性的

访问修饰符,但这都是为了解决低层面向对象封装,而不是解决逻辑系统划分。这就导致一个问题:如果类

要在多个包之间可见,那么就必须是public!

例如,com.alpha.interface包定义了若干接口(public),com.alpha.imp包实现了这些接口
(public);可能你只想向第三方程序暴露com.alpha.interface中的接口,但你却无法阻止客户端直接
new一个实现类,因为你也暴露了 com.alpha.imp包!

如果没有OSGi,就不得不采用下面这种workaround:

  • 为了避免暴露非公有API,而把不相干的类放到同一个包中——损害程序的逻辑结构
    而如果保持程序逻辑结构而使用多个包,则又暴露了原本不想暴露的非公有API。

 

2. 易错的classpath

  • There is no runtime concept that corresponds to a JAR; they are only meaningful at build-time
  • and deploy-time. Once the Java Virtual Ma-chine is running, the contents of all the JARs are simply
  • concatenated and treated as a single, global list: the so-called “Classpath”. This model scales very
  • poorly.
  • They contain no standard metadata to indicate their dependencies.
  • They are not versioned, and multiple versions of JARs cannot be loaded simultaneous.

因为classpath隐藏了代码版本、依赖、一致性等特性,所以容易出错!

例如,同一个项目的不同组件,依赖log4j的不同版本;则类路径可能会强制选择某个可能并不合适的版本,

会找到一个并不匹配的Jar,抛出NoSuchMethodError。

——是否可以通过Maven解决?

Class Loading and the Global Classpath

Java的类加载模型如下:


 

ClassLoader有两个职责:

  • Finding classes, i.e. the physical bytes on disk, given their logical class——如何找类,可扩展
  • Transforming those physical bytes into a Class object in memory.——通过ClassLoader.defineClass
  • ()实现,这个方法是native final的,不可扩展

这种模型确保了类总是会尽可能被最上层的类加载器加载。

例如我们编写的类会被Application ClassLoader加载,该类加载器按顺序查找classpath中的实体,返回第一

个匹配实体。如果classpath中找不到,则报错ClassNotFoundException.

【总结】JRE的类加载机制是:类加载器只是简单地在classpath中按顺序查找类,并返回第一个匹配类;

JRE看到的不是一个个JAR文件,而是一个class文件列表。

By simply searching classpath entries in order and stopping on the first match, the JRE reduces JARs
to mere lists of class files, which are dumped into a single flat list
这个机制会导致一系列问题:

Conflicting Classes

the classpath will contain conflicting names. 如果classpath中包含冲突的类名,会发生什么情况?
 
【例1】
java -classpath obsolete.jar:log4j.jar:classes org.example.HelloWorld
本来想运行classes目录下的HelloWorld,但假如obsolete.jar中也包含一个HelloWorld,因为它排在classpath的靠前部分,则会执行这个过时的同名的类。
 
【例2】
java -classpath log4j-old.jar;log4j.jar;classes org.example.HelloWorld
本来想用log4j.jar;但log4j-old.jar排在classpath靠前部分,则会加载到这个老jar中的类。

Lack of Explicit Dependencies

大部分Jar都需要依赖其他Jar,但是我们如何知道这种依赖关系?

  1. 靠文档描述。——不靠谱
  2. 靠MANIFEST.MF/Class-Path描述。——不实用,it only allows one to list further JAR files to be added
  3. to the classpath using absolute file-system paths, or paths relative to the file-system location
Instead the dependency is implicit: lurking inside the class file in the JAR, ready to cause aClassNotFoundException when we try to use it.

Lack of Version Information

we need to specify a version range because depending on a single specific version of a library would make our system brittle.

考虑这么一个场景:A.jar依赖于Log4j-1.1.jar,B.jar依赖于Log4j-1.2.jar,而Log4j其他版本都会有问题。

我们要把这两个Log4j版本都加到classpath中,但是JRE总是只能取到第一个jar;这样我们要么修改A.jar,要么修改B.jar

LinkageError:例如classpath=Log4j-1.2.jar; Log4j-1.1.jar;后一个jar(Log4j-1.1.jar)中
的类都不会被加载到。但是如果后一个jar中有某个类,但是前一个jar中没有;则这个类还是会被加载
到;这样程序中会用到来自不同jar的类,可能导致LinkageError。
 

3. 部署和管理支持上的不足

在Java中存在对多个版本的依赖时,没有简单的办法来正确部署这些代码并执行;

部署之后也不易更新组件;

例如如果要支持动态插件机制,就需要动用类加载器(?)。

总结:JARs Are Not Modules

模块应该具有如下三个特性:

  • Self-Contained. A module is a logical whole: it can be moved around, installed and uninstalled as a
  • single unit. It is not an atom — it consists of smaller parts — but those parts cannot stand alone, and
  • the module may cease to function if any single part is removed.
Jar文件虽然是物理上的一个独立单元,可以拷来拷去;但是拷贝之后是否还能正常运行,就不得而知了。因
为依赖关系可能会缺失,或者变得不正确。
  • Highly Cohesive. Cohesion is a measure of how strongly related or focussed the responsibilities of
  • a module are. A module should not do many unrelated things, but stick to one logical purpose and
  • fulfil that purpose well.
因为Jar在运行时实际是不存在的,高内聚有何意义?
  • Loosely Coupled. A module should not be concerned with the internal im-plementation of other modules that it interacts with. Loose coupling allows us to change the implementation of one module without needing to update all other modules that use it (along with any modules that use those modules, and so on).
由于信息隐藏的问题,客户端可以直接访问jar中的impl而非接口;这样会导致紧耦合。
 

J2EE解决方案

J2EE应用服务器都具有deployment system,允许动态地部署、解部署应用,而无需重启服务器、不会影响其他应用。

这意味着标准Java应用所使用的类加载机制是不够用的;因为扁平化的全局classpath会导致一个应用中的类,会很容易影响到其他应用。所以J2EE使用了一个更复杂的类加载机制:


 

  • 如果某个类需要在EJB和WAR中共享,则其必须由EAR类加载器加载;
classes that need to be shared across both the EJBs and Web artifacts must be pushed up the tree, into the EAR Class Loader.
  • 如果某个类需要在EAR之间共享,则需要由Application类加载器加载;
And if there are classes we wish to share across multiple deployed applications, we must push them up into the system application class loader. Usually this is done by configuring the way the application server itself is started, adding JARs to the global classpath.

但是这种类就不能动态部署了,并且所有EAR都会依赖这个类,而不管是否需要。

为了达到动态部署的目的,一般的做法是在每个EAR中分别重复部署该类。

 

OSGi解决方案

每个模块都有自己独立的classpath

Java模块化不足问题的根源是那个全局的、扁平化的classpath;OSGi采取了一个完全不同的方法:每个模块都有自己独立的classpath
 

OSGi类加载机制

如何实现这一点呢?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类加载器能立即知道去哪里找类。

解决模块化问题

  1. OSGi可以帮助你先确保代码满足依赖关系,然后才允许执行代码;避免类路径错误
  2. OSGi会对类路径上的依赖集进行一致性检查(如:版本);
  3. 不必担心由于层次化的类加载模式隐含的限制;——何种限制?
  4. OSGi可以把程序打包逻辑上独立的JAR文件,并且只部署指定的部分、动态部署;——OSGi生命周期层实现动态部署
  5. OSGi可以声明JAR中的哪些代码可以被其他JAR访问,强化可见性 ——OSGi中,只有那些被显式导出的包才能被其他bundle使用。也就是说默认情况下,所有包都是bundle private的,不能被其他包看到。
  6. OSGi为程序定义了一个插件式的扩展机制。
In OSGi, only packages that are explicitly exported from a bundle can be imported and used in another bundle. Therefore all packages are “bundle private” by default, making it easy for us to hide the internal implementation details of our bundles from clients.
 
 
转自:http://blog.csdn.net/vking_wang/article/details/12379333
分享到:
评论

相关推荐

    java Android 算法 解决方案 分享.zip

    这使得Java编写的代码更加模块化、可维护和可扩展。 多线程支持: Java内置了对多线程的支持,允许程序同时执行多个任务。这对于开发需要高并发性能的应用程序(如服务器端应用、网络应用等)非常重要。 自动内存...

    Java办公自动化系统毕业论文

    4.3 Java数据库解决方案………………………………………………………………18 4.4 Java局域网解决方案………………………………………………………………21 4.5 系统界面解决方案…………………………………………...

    基于Spring Boot 2和Spring Cloud Finchley.RELEASE,致力做更简洁的分布式和服务化解决方案

    本项目为Roses系列微服务框架的模块之一,Roses基于Spring Boot 2和Spring Cloud Finchley.RELEASE,致力做更简洁的分布式和服务化解决方案,Roses拥有高效率的开发体验,提供可靠消息最终一致性分布式事务解决方案...

    JAVA上百实例源码以及开源项目

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    Java思维导图xmind文件+导出图片

    session跨域共享及企业级单点登录解决方案实战 分布式事务解决方案实战 高并发下的服务降级、限流实战 基于分布式架构下分布式锁的解决方案实战 分布式架构实现分布式定时调度 分布式架构-中间件 分布式消息...

    JAVA上百实例源码以及开源项目源代码

     Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、输出错误信息等Java编程小技巧。 Java数组倒置...

    基于Java的创创猫多商户电商平台设计源码

    系统采用了Vue、JavaScript和CSS等技术,为用户提供了一个功能丰富的电商解决方案。系统设计注重用户体验和响应速度,采用了模块化的开发方式,便于后续的扩展和维护。创创猫B2B2C多商户电商系统是一款完善且经过...

    基于java的-109-java学习平台-LW-源码.zip

    Java源码资源介绍 在寻求Java编程的学习材料或...项目实践:对于正在进行Java项目开发的人员来说,这份源码资源提供了丰富的实战案例和解决方案。无论是需要实现特定的功能还是解决复杂的性能问题,都能在这里找到灵感

    基于java的-209-仓储系统出入库模块设计--LW-源码.zip

    项目实践:对于正在进行Java项目开发的人员来说,这份源码资源提供了丰富的实战案例和解决方案。无论是需要实现特定的功能还是解决复杂的性能问题,都能在这里找到灵感和帮助。 教学辅导:对于教师和教育机构来说,...

    ElasticJob分布式调度解决方案是面向互联网生态和海量任务的分布式调度解决方案.rar

    SphereEx 中间件研发工程师,Apache ShardingSphere committer,ElasticJob 3.0.0 版本 Release Manager。目前专注于 Apache ...除此之外,得益于新的模块化架构,开发者可以方便地向社区回馈独立、通用的作业类型。

    基于java的-125-jspm新冠疫情下基于java的校园出入系统-LW-源码.zip

    Java源码资源介绍 在寻求Java编程的学习材料或...项目实践:对于正在进行Java项目开发的人员来说,这份源码资源提供了丰富的实战案例和解决方案。无论是需要实现特定的功能还是解决复杂的性能问题,都能在这里找到灵感

    Java毕业设计-JAVA SMART系统-系统框架设计与开发(源代码+论文).rar

    通过采用先进的Java EE技术和模块化设计理念,该系统易于维护和升级,同时保证了系统的稳定性和安全性。 源代码包含了系统的基础架构、核心功能模块、数据库设计以及相关的工具类库。论文部分则详细阐述了系统的...

    基于企业微信的开源 SCRM 系统,采用主流的 Java 微服务架构,是企业私域流量管理与营销的综合解决方案

    LinkWeChat 是基于企业微信的开源 SCRM 系统,是企业私域流量管理与营销的综合解决方案。 LinkWeChat 基于企业微信开放能力,不仅集成了企微强大的后台管理及基础的客户管理功能,而且提供了多种渠道、多个方式连接...

    基于java的-335-基于Java的校园拼车系统-源码.zip

    项目实践:对于正在进行Java项目开发的人员来说,这份源码资源提供了丰富的实战案例和解决方案。无论是需要实现特定的功能还是解决复杂的性能问题,都能在这里找到灵感和帮助。 教学辅导:对于教师和教育机构来说,...

    基于java的-109-java学习平台--LW-源码.zip

    项目实践:对于正在进行Java项目开发的人员来说,这份源码资源提供了丰富的实战案例和解决方案。无论是需要实现特定的功能还是解决复杂的性能问题,都能在这里找到灵感和帮助。 教学辅导:对于教师和教育机构来说,...

    基于java的-333-基于Java的校园即时服务平台-源码.zip

    项目实践:对于正在进行Java项目开发的人员来说,这份源码资源提供了丰富的实战案例和解决方案。无论是需要实现特定的功能还是解决复杂的性能问题,都能在这里找到灵感和帮助。 教学辅导:对于教师和教育机构来说,...

    基于java的-116-jspm基于Java的汽车销售系统-源码.zip

    项目实践:对于正在进行Java项目开发的人员来说,这份源码资源提供了丰富的实战案例和解决方案。无论是需要实现特定的功能还是解决复杂的性能问题,都能在这里找到灵感和帮助。 教学辅导:对于教师和教育机构来说,...

Global site tag (gtag.js) - Google Analytics