OSGi技术在Java Web开发中的应用

wuyabing 2012-09-20

随着Java SE对模块化功能原生支持的一再推迟(据最新的消息,Jigsaw项目——JavaSE中的标准模块系统——的开发工作相对滞后,已经延期到了Java 9中,而Java 9到2015年才有希望发布),OSGi作为事实标准的Java模块化实现得到了长足的发展,尤其是随着云计算和分布式技术的兴起,OSGi这种模块化、动态部署的核心功能将会受到越来越多的重视。

目前OSGi规范的主流实现框架是EclipseEquinox以及Apache Felix,其实际的应用场景也早就从起初的嵌入式设备扩展到桌面应用甚至Java企业级开发领域。最为大家所熟知的OSGi应用是Eclipse IDE,其实像Sun GlassFish、IBM WebSphere Application Server、JBoss ApplicationServer以及Apache的大量开源项目如Camel、Sling、ServiceMix、Kafaf等都使用了OSGi技术,随着其应用的日益广泛,技术的可用性和成熟度经受了充分的考验,实践证明OSGi是一项可靠的技术,完全可以应用于企业级应用的开发。尤其值得一提的是,随着OSGi Core Release5和OSGiEnterprise Release 5版本的发布,预计OSGi技术将会受到更多的关注,国内外已经有将OSGi应用于云计算和分布式计算的案例。

本文将选取OSGi应用于传统Java Web开发的场景,介绍借助于OSGi技术,怎样实现将web应用拆分成满足OSGi规范的bundle,实现组件的动态部署。目前,为了实现在bundle中支持JSP、Servlet等Java Web开发技术和规范,有两种主要的开发部署方式,本文都将进行介绍,但是这两种方案在实现上与传统的Java Web应用开发模式有较大的不同,且对JEE规范的支持尚不完整。

 

按照Eclipse Equinox的习惯,会将bundle称为插件,在后文中会根据具体的应用场景穿插使用这两个名词,但其本质是相同的。 

<!--[if !supportLists]-->一、将Web容器作为bundle置于 Equinox中进行开发 

在这种模式下,我们需要将支持JEE规范的容器也以bundle形式发布到OSGi容器中,而包含JSP、Servlet的bundle将会使用该容器接受对请求的访问,这种方式的好处在于OSGi容器管理整个运行环境,是个纯粹的可热插拔运行环境,其缺点在于需要Web容器支持以bundel的形式进行发布,对运行环境有一定的限制,目前支持该要求的Web容器有Tomcat和Jetty,但是主流的企业级应用服务器尚不支持这种部署方式。

鉴于Eclipse开发环境中已经包含了Jetty服务器,所以我们将会使用该服务器进行Web应用的开发。

首先我们需要使用Eclipse的工程向导创建一个插件工程。根据工程的需要,我们不生成启动类(activator),不使用任何模版,插件过程如下:

新建一个插件工程:

 输入工程的基本信息: 此处我们不使用任何模版,因为我们不会用到Eclipse的UI功能: 新建完成的项目结构如下所示: 为了测试进行Web开发,我们新建目录结构/WebRoot/jsp(该目录名称是任意的,只需在后续定义扩展点时进行匹配即可)并在该目录下创建一个JSP文件,此时的工程结构如下: JSP的代码如下:

 

 

Html代码  OSGi技术在Java Web开发中的应用
  1. <%@ page language="java" contentType="text/html; charset=ISO-8859-1"  
  2.     pageEncoding="ISO-8859-1"%>  
  3.   
  4. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  5. <html>  
  6. <head>  
  7. <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">  
  8. <title>Insert title here</title>  
  9. </head>  
  10. <body>  
  11. Hello,world!  
  12. </body>  
  13. </html>   

为了使用JSP和Servlet,我们需要使用一个扩展点,该扩展的名称为org.eclipse.equinox.http.registry.servlets,我们需要使用该扩展点进行JSP目录和访问地址的匹配,在我们这个样例中我们匹配了/WebRoot/jsp目录,其访问地址的前缀将会是/jsp/:

OSGi技术在Java Web开发中的应用

 除此以外,我们还需要添加对org.eclipse.equinox.jsp.jasper.registry插件的依赖,以实现JSP的编译功能。

 

OSGi技术在Java Web开发中的应用

 最后,我们还需要在运行时配置里将testweb和Jetty所依赖的插件全部选中,如下:

 

 

 然后点击“Run”按钮,此时就会启动OSGi运行环境,我们可以在控制台通过使用“ss”命令来查看运行插件的状态情况:

OSGi技术在Java Web开发中的应用

此时,我们可以在浏览器中输入http://localhost/jsp/index.jsp(Jetty的默认端口是80,可进行配置),就会看到我们所编写的JSP的代码了:

          要实现访问Servlet和静态资源(CSS、图片等),也需要类似的配置,下图是一个包含静态资源和Servlet的配置样例:

 

Xml代码  OSGi技术在Java Web开发中的应用
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2.  <?eclipse version="3.4"?>   
  3.  <plugin>   
  4.  <extension   
  5.     point="org.eclipse.equinox.http.registry.servlets">   
  6.      <servlet   
  7.          alias="/servlet/myfirstservlet"   
  8.          class="testjsp.LoginServlet"  
  9.          load-on-startup="true">       
  10.      </servlet>   
  11.      <servlet   
  12.         alias="/jsp/*.jsp"  
  13.         class="org.eclipse.equinox.jsp.jasper.registry.JSPFactory:/WebRoot/jsp/">   
  14.      </servlet>   
  15.  </extension>  
  16.  <extension  
  17.        point="org.eclipse.equinox.http.registry.resources">  
  18.         <resource  
  19.      alias="/web"  
  20.      base-name="/WebRoot/images"/>  
  21.  </extension>   
  22.  </plugin>  
 

二、将Equinox置于web容器中进行开发

以上的开发模式对于习惯于传统JEE开发模式的开发人员在接受上有一定的难度,直接使用Equinox作为运行环境在解决集群部署方面也有一定的难度,除此以外,主流的应用服务器并不提供bundle形式的jar以运行在OSGi容器中。所以,开发人员摸索出了另一种开发和部署模式。

在这种模式中,会将Equinox和我们开发的插件都打成一个标准的war包的格式,因此可以运行在任意支持JEE的容器中。Equinox的生命周期是通过Servlet来进行控制。这种模式被称为桥接模式。Equinox官方提供了该模式的实现,后来的社区贡献者基于此进行了功能的完善。

将下载后的代码导入到Eclipse中,工程目录如下所示:

 从该目录可以看出,这是一个典型JEE工程,可以运行在任意的支持规范的Web容器或应用服务器中,查看web.xml,我们可以看到这样的配置:

 

Xml代码  OSGi技术在Java Web开发中的应用
  1. <servlet id="bridge">  
  2.         <servlet-name>equinoxbridgeservlet</servlet-name>  
  3.         <display-name>Equinox Bridge Servlet</display-name>  
  4.         <description>Equinox Bridge Servlet</description>  
  5.         <servlet-class>org.eclipse.equinox.servletbridge.BridgeServlet</servlet-class>  
  6.         <init-param>  
  7.             <param-name>commandline</param-name>  
  8.             <param-value>-console</param-value>           
  9.         </init-param>       
  10.         <init-param>  
  11.             <param-name>enableFrameworkControls</param-name>  
  12.             <param-value>true</param-value>           
  13.         </init-param>  
  14.         <init-param>  
  15.             <param-name>extendedFrameworkExports</param-name>  
  16.             <param-value></param-value>           
  17.         </init-param>  
  18.         <load-on-startup>1</load-on-startup>  
  19.     </servlet>  
  20.     <servlet-mapping>  
  21.         <servlet-name>equinoxbridgeservlet</servlet-name>  
  22.         <url-pattern>/*</url-pattern>  
  23.     </servlet-mapping>  
  24.     <servlet-mapping>  
  25.         <servlet-name>equinoxbridgeservlet</servlet-name>  
  26.         <url-pattern>*.jsp</url-pattern>  
  27.     </servlet-mapping>      

 我们可以看到这个Servlet拦截了所有的请求,由该Servlet代理所有的请求。

在部署阶段,可以把插件打成jar包,放到/WEB-INF/eclipse/plugins目录下即可。如将我们上例中的testweb导出为jar包后,置于指定目录下。然后在Tomcat中运行该应用。访问http://localhost:8080/bridge/jsp/index.jsp就可以看到我们编写的JSP页面了。

使用以上的模式进行开发,对原有的开发和部署模式冲击较小而且支持所有的应用服务器。

 

参考资料:

 

http://www.ibm.com/developerworks/cn/web/0907_osgiweb_liuqing/

相关推荐