`
wyuch
  • 浏览: 74226 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

大型CMS产品研发心得:参考OSGI实现插件机制

阅读更多
最近一两年一直在负责一个内容管理产品的研发,十几个人的团队,产品核心部分有40万行代码的规模,扩展功能有约10万行代码,分成50多个插件。说是大型CMS应用,实际上对于互联网应用来说依然是一个小型应用,毕竟产品基本不上不可能会运行在超过十台服务器的集群上。

首先说说我们的现状:
1、专职开发团队,有专职的设计工程师、前端工程师、JAVA工程师、测试工程师,本人担当产品经理,并负责一部分关键代码。
2、是起步阶段的公司,刚入职的同事技术水平都比较一般。
3、项目一般情况下都不会特别小,做不到只卖产品不需实施,客户一般都会提一些客户化的要求。但也做不到很大,一般不超过50万。
4、产品有过1.x版本,也积累了一些客户,但在项目实施上存在着较多问题。

这些问题是:
1、功能和功能之间藕合紧密,修改一处代码可能会影响多个功能,测试量很大。
2、藕合太紧导致可扩展性比较差,模块和模块之间边界比较模糊,有时候该使用接口却没有使用接口。
3、如果有合作伙伴或客户自己修改代码,又或者项目结束一段时间后(超过一年),就很难再和主版本同步了。
4、基本上需要为每个有客户化代码的项目保留一个SVN分支。
5、如果熟悉某一分支的同事离职,则后人接手维护需要有一个比较长的熟悉过程。
6、所有实施工程师都得熟知各个小版本之间的差异,以及每个小版本修正过什么BUG。
7、项目金额不大不小,既不可能让一个人只维护一个项目,又不可能完全不维护,导致每个人都得从SVN中检出多个分支版本。

总之,因为设计时对可扩展性考虑不足,导致了实施中的很多问题。因此我们想要引入插件机制,将功能分成一个个插件,插件之间有确定的依赖关系,如果不声明依赖哪个插件,则不允许引用该插件中的类,插件和插件之间以接口为契约。

OSGI作为极有声望的JAVA的组件技术,久经考验非常成熟,并且其开发有Eclipse做支撑,可以直接使用Eclipse开发OSGI bundle,所以是我们重点考察的对象。其优点不多说了,总之非常优秀。但我们发现有几个方面不是很符合我们这种类型的公司:
1、我们不能控制客户使用什么中间件、操作系统和数据库,因此我们的插件机制必须是在一个Web app内部运行的,不可能将一个产品分成很多个war,让每个war就是一个bundle。
2、让OSGI在Web app内部运行,感觉目前还不是很成熟,还不太适合企业应用开发,Equinox主页上有一篇文章讲到怎么在一个让OSGI在一个web app内部运行,但自2007年后就没有更新过了,似乎没有投入什么力量来发展这一块。
3、使用OSGI基本上就只能让一个bundle成为一个工程,这样随着产品和公司的发展,一个workspace中会有上百个工程,再考虑分支版本和多个产品的情况,感觉很难加以整体掌握。
4、对于RCP或者Eclipse plug-in,开发和调试bundle都非常方便,修改后立即编译然后立即生效。但如果是WebApp,基本上不太可能达到这种效果,每次修改后都必须部署后才能运行和调试,开发效率会受到很大的影响。
5、OSGI本身未不支持PDE中的plugin.xml,非常重要的extension point和extension相关的功能需要另行引入。
6、OSGI的学习曲线比较高,让每个产品开发人员达到能够定义extendsion point的水平相当困难,不适合我们目前的人力资源状况。

其实还有一个非常重要的问题是各种流行框架对OSGI的支持目前还有一些问题,使用Spring的同学可以考虑DM,能够解决一部分问题,但据说实际使用中也比较郁闷。我们使用的是自己开发的全套框架,不使用Servlet和JSP页面,只需要改造一下ClassLoader机制和资源文件、配置文件查找机制,就可以很快适应OSGI,所以不存在这个问题。

鉴于我们的技术水平、公司现状,均衡考虑开发效率和学习曲线,最终我们没有选择OSGI,而是决定参考了部分OSGI的设计,实现一个自己插件运行机制。主要有以下设计目的:
1、一个Eclipse工程中可以有多个插件,工程的组织方式和普通的J2EE工程完全相同,可以做到在Eclipse中即时修改即时编译即时生效,不需要在改动后执行部署动作,也不需要重启中间件。
2、插件可以单独安装、启动、停止、卸载,并且不需要重启中间件或应用。
3、插件可以单独在线升级,升级不需要重启应用。
4、插件如果被停止则依赖于该插件会自动停止,如果卸载了,则依赖于它的插件不能再启动。
5、每个插件有自己配置文件,配置文件以${PluginID}.plugin.xml命名,存放在一个专门目录里。
6、每个plugin.xml文件管理着自己对其他插件的依赖关系、菜单、扩展服务、扩展项以及哪些文件属于本插件。
7、系统中的菜单由各个插件通过plugin.xml提供,如果插件被停止,则相应的菜单会自动消失。
8、一个文件不可能同时属于两个插件。
9、插件只能引用被自己依赖的插件中的类(但没有实现OSGI中的Export package和Import package功能)
10、允许第三jar在不同插件中有不同的版本(但不允许一个插件有多个不同版本)
11、以一种简化的方式实现了类似于PDE中extension point和extension的功能。
12、普通开发人员必须能够在三天之内掌握插件开发机制。

其中比较特别的是扩展服务和扩展项:某一插件实现的功能需要依赖于本插件定义的某一接口的子类的集合时,需要定义扩展服务。扩展服务是一个插件配置项,用于声明本插件的一个扩展项注册入口;扩展项也是一个插件配置项,用于声明向哪个扩展服务注册扩展项。扩展项指定的类必须实现扩展服务指定的接口。
例如:内容核心插件需要管理所有的模板标签,但内容核心插件不知道其他插件都实现了什么标签,所以需要提供一个模板标签扩展服务。其他插件则可以将自己实现的模板标签扩展项注册到此服务,从而通知内容核心在模板编译、执行、标签展示等环节使用此标签。

扩展服务和扩展项是PDE中extension point和extension的粗糙替代物,和extension point的xsd方式不同的是,扩展服务只是简单定义扩展项需要使用的接口,所以语义性的东西都由接口通过get函数返回。这主要是因为我们的人员包括我本人对xsd不熟练,更愿意写接口。

为了达到以上设计目的,我们修改了自己的框架,主要修改的地方有两处:
1、全新设计了应用自己的ClassLoader,WEB-INF/lib下基本上没有jar包,绝大部分的jar包包括第三方jar包都被部署到了WEB-INF/plugins目录下,这是为避免jar文件被中间件的ClassLoader加载后不能进行动态更新的问题。ClassLoader还在运行时检查了插件之间的依赖关系。
2、静态变量和定时任务需要特别设计,可能会导致插件卸载和更新时不能回收ClassLoader实例的问题,从而导致PermGen内存泄漏。

另外,为了更好进行项目实施我们加了一个比较ugly的机制,将所有的页面/css/js/图片等资源文件打包到了单独的jar中,应用目录下基本上只有一个WEB-INF了。通过一个特别优化的(主要是处理Last-Modified头让浏览器尽量使用缓存)Filter来处理资源URL。这样做的目的是为了更好地进行实施,我们的框架会优先读取应用下的资源文件,找不到才会从jar中读取,这样项目实施时只需要在相应目录下放入该项目特有的资源(一般是登录界面什么的)就可以实现界面的客户化。

为此,我们开发了一系列的Eclipse插件,用来支撑我们的这种工程组织方式,提供编译检查、插件打包等服务,并提供了类似于PDE的界面来编辑我们自己的plugin.xml文件。

整个过程从决定自己开发到最终产品发布,历时近十个月,目前产品开发和定制开发效率都比较理想,总体来说付出的劳动还是值的。
分享到:
评论
3 楼 Justgin 2013-12-19  
不错,有机会可以交流一下,我们这边也基本Equinox搭建了一个开发框架,目前已完成了若干项目的开发,充分体会到了模块化开发的好处。
2 楼 dargoner 2013-02-20  
确实不错,每次反编译代码,都会重新认识这个产品
1 楼 zrzking 2012-11-02  
发自内心的感慨真的很牛,但是建议能写出一个系列来,期待中...

相关推荐

    OSGI进阶插件开发

    本教程将深入探讨如何基于OSGi进行高级插件开发,包括设计、实现、部署和测试项目和产品。 一、OSGi设计原则 1. **模块化**:OSGi的核心是模块化,每个bundle都是一个自包含的模块,有自己的类加载器,确保了类的...

    OSGI 实例eclipse插件开发

    OSGI(Open Services Gateway Initiative)是一种模块化系统和Java服务框架,它允许...同时,掌握OSGI的生命周期管理和服务发现机制,以及Spring在OSGI环境下的工作原理,对于构建灵活、可扩展的Eclipse插件至关重要。

    osgi 插件开发

    ### OSGi插件开发详解 #### OSGi概述 **OSGi**,即Open Service Gateway Initiative,是一种针对Java的动态模块系统。它为模块化应用程序的开发提供了一个基础架构,使得开发者能够轻松管理和控制各个模块间的依赖...

    osgi插件化开发流程

    osgi插件化开发流程

    OSGi.NET插件框架

    开放工厂向您提供了规范化的OSGi.NET插件框架和可复用的插件仓库,通过插件仓库来解决应用系统的持续集成、远程管理、自动更新、敏捷发布,无缝实现开发/QA/运维间无缝协作,并允许您将自定义的插件共享。 插件仓库...

    osgi,林昊写的osgi实战和进阶

    林昊所著的《OSGI实战》与《OSGI进阶》是深入理解OSGI技术的重要参考资料,适合对Java模块化系统感兴趣的初学者和有经验的开发者。 在《OSGI实战》中,作者林昊可能会详细讲解以下几个核心知识点: 1. **OSGI基础*...

    OSGI 开发文档中文的

    6. **插件模块开发**:如何设计和实现OSGI插件,包括定义插件接口、实现业务逻辑、打包和部署。这部分内容可能涉及Maven或Gradle的OSGI插件,以及如何配置它们来生成符合OSGI规范的JAR。 7. **代码示例**:提供的...

    osgi资料

    - 模块系统:详述OSGi的包和类加载机制,以及如何定义和管理模块(也称为bundle)。 - 依赖管理:解释如何声明和解决模块间的依赖关系,确保正确地加载和启动服务。 - 动态性:介绍如何在运行时安装、启动、停止...

    OSGI常用通信实例

    在本实例中,我们看到OSGI与C++的结合,以及如何在Visual Studio 2010和Qt 5.11环境中实现插件间的通信。下面将详细介绍这个主题中的关键知识点。 1. OSGI框架: OSGI的核心是它的模块系统,它允许应用程序被分解...

    incubator-taverna-osgi:Apache Taverna OSGi 插件系统(暂存)

    3. **兼容性**:虽然最初是为Apache Taverna设计的,但该插件系统的设计理念和实现方式使其具备广泛的适用性,可以应用于其他基于OSGi的命令行或桌面产品,从而扩大了其潜在的应用范围。 4. **动态性**:OSGi的动态...

    osgi框架开发介绍

    2. **企业级应用**:在大型企业应用中,OSGi可以帮助构建松耦合的组件,便于开发、测试和部署。 3. **IDE和工具平台**:Eclipse IDE就是一个基于OSGi的平台,其插件系统就是OSGi服务模型的体现。 四、学习资源 ...

    spring-osgi 入门手册和代码

    - **Blueprint Container**:Spring OSGi 提供了一个基于 Blueprint 的容器,它是 OSGi 社区对 CDI(Contexts and Dependency Injection)的实现,类似于 Java EE 中的 CDI 容器。 - **Module Bundles**:Spring ...

    未来10年:OSGi、Spring-DM.docx

    OSGi(Open Service Gateway Initiative)是一种基于Java的动态模块化框架,旨在解决Java EE开发及部署模型的局限性。该框架可以提供模块化、动态性和灵活性,解决研发、部署和维护等方面的挑战。 Java EE开发及...

    OSGI参考例子程序

    在"OSGI参考例子程序"中,你将找到一系列有关OSGI技术的示例代码,特别关注于留言板应用。这些例子对于初学者来说非常有价值,它们可以帮助你理解OSGI的基本概念和工作原理,并提供实际操作经验。 1. **模块化**:...

    OSGI实战及源码

    通过学习和实践《OSGI实战及源码》,开发者可以提高构建可扩展、灵活且易于维护的Java应用的能力,尤其在大型企业级项目中,OSGI的应用可以显著提升软件的可维护性和复用性。对于想要深入了解和应用OSGI的开发者来说...

    漂亮的WPF界面框架(OSGi.NET插件)源码

    该界面框架是在ModernUI(http://mui.codeplex.com/)基础上开发的非常现代、漂亮的通用界面框架,通过简单的配置,您可以将自定义的功能注册到页面。...使用的OSGi.NET插件 欢迎感兴趣的用户下载研究

    OSGi实现用户登录验证

    在IT行业中,OSGi(Open Service Gateway Initiative)是一种模块化软件开发框架,它允许开发者将应用程序分解为独立的、可重用的组件,称为服务。这些服务之间通过接口进行交互,使得系统更易于管理和扩展。OSGi的...

    osgi hibernate

    3. **OSGi与Hibernate集成的动机**:讨论为何要在OSGi环境中使用Hibernate,可能是为了实现更灵活的模块化开发,或者解决传统Java应用中类加载器和依赖管理的问题。 4. **集成步骤**:详细步骤可能包括: - 创建...

Global site tag (gtag.js) - Google Analytics