扩展Tomcat支持OSGi应用服务(3)
4.测试通过以上的实现,我们将OSGi平台集成到了Tomcat中,并且明确了web应用如何使用OSGi服务。下面就来创建一个测试的例子,看看OSGi编程模式对web应用开发的影响,同时也测试一下集成的效果。
4.1 创建并发布OSGi服务
Step1.创建插件工程com.dinstone.demo.user,选择standard OSGi framework。创建接口:
package com.dinstone.demo.user;
publicinterface IUserService {
public String getUserName(String id);
}
Step2.创建插件工程com.dinstone.demo.user.db,创建类UserServiceImpl实现IUserService接口。
package com.dinstone.demo.user.db;
imp<wbr>ort java.util.logging.Logger;</wbr>
imp<wbr>ort com.dinstone.demo.user.IUserService;</wbr>
public class UserServiceImpl implements IUserService {
private static Logger log = Logger.getLogger(UserServiceImpl.class
.getName());
@Override
public String getUserName(String id) {
log.info("get user name from db");
return "db" + id;
}
}
Step3.向OSGi平台发布IUserService服务。创建Activator注册服务对象。
package com.dinstone.demo.user.db;
imp<wbr>ort java.util.Properties;</wbr>
imp<wbr>ort org.osgi.framework.BundleActivator;</wbr>
imp<wbr>ort org.osgi.framework.BundleContext;</wbr>
imp<wbr>ort org.osgi.framework.ServiceRegistration;</wbr>
imp<wbr>ort com.dinstone.demo.user.IUserService;</wbr>
public class Activator implements BundleActivator {
private ServiceRegistration serviceReg;
/*
* (non-Javadoc)
*
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
Properties p = new Properties();
serviceReg = context.registerService(IUserService.class.getName(),
new UserServiceImpl(), p);
}
/*
* (non-Javadoc)
*
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
serviceReg.unregister();
}
}
Step4.
创建插件工程com.dinstone.demo.user.file,创建类UserServiceImpl实现IUserService接口。
package com.dinstone.demo.user.file;
imp<wbr>ort java.util.logging.Logger;</wbr>
imp<wbr>ort com.dinstone.demo.user.IUserService;</wbr>
public class UserServiceImpl implements IUserService {
private static Logger log = Logger.getLogger(UserServiceImpl.class
.getName());
@Override
public String getUserName(String id) {
log.info("get user name from file");
return "file" + id;
}
}
Step5.向OSGi平台发布IUserService服务。创建Activator注册服务对象。
package com.dinstone.demo.user.file;
imp<wbr>ort java.util.Properties;</wbr>
imp<wbr>ort org.osgi.framework.BundleActivator;</wbr>
imp<wbr>ort org.osgi.framework.BundleContext;</wbr>
imp<wbr>ort org.osgi.framework.ServiceRegistration;</wbr>
imp<wbr>ort com.dinstone.demo.user.IUserService;</wbr>
public class Activator implements BundleActivator {
private ServiceRegistration serviceReg;
/*
* (non-Javadoc)
*
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
Properties p = new Properties();
serviceReg = context.registerService(IUserService.class.getName(),
new UserServiceImpl(), p);
}
/*
* (non-Javadoc)
*
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
serviceReg.unregister();
}
}
4.2 创建Web应用
Step1.创建动态web工程webDemo,并新建类:UserServiceFacade。
package com.dinsotne.web.demo;
imp<wbr>ort com.dinsotne.web.osgi.OsgiServiceFacade;</wbr>
imp<wbr>ort com.dinstone.demo.user.IUserService;</wbr>
public class UserServiceFacade {
public static String getUserName(String id) {
try {
IUserService service = OsgiServiceFacade.getOsgiService(
"osgi/services", IUserService.class, IUserService.class
.getName());
return service.getUserName(id);
} catch (IllegalArgumentException e) {
e.printStackTrace();
e.printStackTrace();
}
return null;
}
}
Step2.创建index.jsp页面。
<%@
page language="java"
contentType="text/html; charset=utf-8"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE
html PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@page
imp<wbr>ort</wbr>="com.dinsotne.web.demo.UserServiceFacade"%>
<html>
<head>
<meta
http-equiv="Content-Type"
content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
User Name is
<%=UserServiceFacade.getUserName("001")
%>
</body>
</html>
Step3.修改web.xml文件,添加红色部分。
<?xml
version="1.0"
encoding="UTF-8"?>
<web-app
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID"
version="2.5">
<display-name>webDemo</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<resource-env-ref>
<description>osgi service</description>
<resource-env-ref-name>osgi/services</resource-env-ref-name>
<resource-env-ref-type>
com.dinstone.osgi.OsgiServices
</resource-env-ref-type>
</resource-env-ref>
</web-app>
说明:
1.
由于UserServiceFacade依赖IUserService类,故需要将com.dinstone.demo.user_1.0.0.jar(参见4.3)添加到lib中。
2.
由于UserServiceFacade依赖OsgiServiceFacade类,故将com.dinsotne.web.osgi_1.12.0.jar(参见3.4说明)添加到lib中。
4.3 发布OSGi Bundle
Step1.依次从插件工程导出插件包:com.dinstone.demo.user_1.0.0.jar,com.dinstone.demo.user.file_1.0.0.jar,com.dinstone.demo.user.db_1.0.0.jar。
Step2.将以上的插件放于${Tomcat_Home}\osgi\felix\bundle目录下。
4.4 发布web应用
Step1.导出web应用webDemo.war。
Step2.将webDemo.war放于${Tomcat_Home}\webapps目录下。
4.5 启动Tomcat并安装OSGi Bundle
Step1.在命令行下启动Tomcat。E:\Cluster\apache-tomcat-6.0.18为我的${Tomcat_Home}。
E:\Cluster\apache-tomcat-6.0.18>bin\startup.bat
Using CATALINA_BASE: E:\Cluster\apache-tomcat-6.0.18
Using CATALINA_HOME: E:\Cluster\apache-tomcat-6.0.18
Using CATALINA_TMPDIR: E:\Cluster\apache-tomcat-6.0.18\temp
Using JRE_HOME: C:\Program Files\Java\jdk1.6.0_10
2009-8-12 13:21:39 com.dinstone.tomcat.osgi.OsgiLifecycleListener lifecycleEvent
信息: The osgi content is initialized. Using osgi content:felix
2009-8-12 13:21:39 org.apache.coyote.http11.Http11Protocol init
信息: Initializing Coyote HTTP/1.1 on http-8080
2009-8-12 13:21:40 org.apache.coyote.http11.Http11Protocol init
信息: Initializing Coyote HTTP/1.1 on http-8443
2009-8-12 13:21:40 org.apache.catalina.startup.Catalina load
信息: Initialization processed in 1748 ms
2009-8-12 13:21:41 com.dinstone.tomcat.osgi.OsgiLifecycleListener lifecycleEvent
信息: Starting osgi service.
2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start
信息: *********************************
2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start
信息: catalina home is E:\Cluster\apache-tomcat-6.0.18
2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start
信息: osgi home is E:\Cluster\apache-tomcat-6.0.18\osgi\felix
2009-8-12 13:21:41 com.dinstone.tomcat.osgi.felix.FelixContent start
信息: ******user.dir is E:\Cluster\apache-tomcat-6.0.18
Welcome to Felix.
=================
-> 2009-8-12 13:21:42 org.apache.catalina.core.StandardService start
信息: Starting service Catalina
2009-8-12 13:21:42 org.apache.catalina.core.StandardEngine start
信息: Starting Servlet Engine: Apache Tomcat/6.0.18
2009-8-12 13:21:42 org.apache.catalina.loader.WebappLoader start
信息: Dual registration of jndi stream handler: factory already defined
2009-8-12 13:21:44 org.apache.coyote.http11.Http11Protocol start
信息: Starting Coyote HTTP/1.1 on http-8080
2009-8-12 13:21:44 org.apache.coyote.http11.Http11Protocol start
信息: Starting Coyote HTTP/1.1 on http-8443
2009-8-12 13:21:44 org.apache.jk.common.ChannelSocket init
信息: JK: ajp13 listening on /0.0.0.0:8009
2009-8-12 13:21:44 org.apache.jk.server.JkMain start
信息: Jk running ID=0 time=0/47 config=null
2009-8-12 13:21:44 org.apache.catalina.startup.Catalina start
信息: Server startup in 3882 ms
-> ps
START LEVEL 1
ID State Level Name
[ 0] [ 0] System Bundle (1.6.0)
[ 25] [ 1] Apache Felix Shell Service (1.2.0)
[ 26] [ 1] Apache Felix Shell TUI (1.2.0)
[ 27] [ 1] Apache Felix Bundle Repository (1.4.0)
->
Step2.安装bundle。
-> install file:E:\Cluster\apache-tomcat-6.0.18\osgi\felix\bundle\com.dinstone.demo.user_1.0.0.jar
Bundle ID: 39
-> install file:E:\Cluster\apache-tomcat-6.0.18\osgi\felix\bundle\com.dinstone.demo.user.db_1.0.0.jar
Bundle ID: 40
-> install file:E:\Cluster\apache-tomcat-6.0.18\osgi\felix\bundle\com.dinstone.demo.user.file_1.0.0.jar
Bundle ID: 41
-> ps
START LEVEL 1
ID State Level Name
[ 0] [ 0] System Bundle (1.6.0)
[ 25] [ 1] Apache Felix Shell Service (1.2.0)
[ 26] [ 1] Apache Felix Shell TUI (1.2.0)
[ 27] [ 1] Apache Felix Bundle Repository (1.4.0)
[ 39] [ 1] User Model Interface Plug-in (1.0.0)
[ 40] [ 1] User DB Implement Plug-in (1.0.0)
[ 41] [ 1] User File Implement Plug-in (1.0.0)
->
Step3.访问web应用,http://localhost:8080/webDemo/。由于没有启动OSGi服务,故出现500异常页面,错误原因是没有找到服务。
root cause
com.dinsotne.web.osgi.IllegalServiceException: Cann't find out osgi service:com.dinstone.demo.user.IUserService
com.dinsotne.web.osgi.OsgiServiceInvocationHandler.invoke(OsgiServiceInvocationHandler.java:30)
$Proxy0.getUserName(Unknown Source)
com.dinsotne.web.demo.UserServiceFacade.getUserName(UserServiceFacade.java:14)
org.apache.jsp.index_jsp._jspService(index_jsp.java:64)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
Step4.启动User DB Implement Plug-in服务,激活User模块的DB实现。
->ps
START LEVEL 1
ID State Level Name
[ 0] [ 0] System Bundle (1.6.0)
[ 25] [ 1] Apache Felix Shell Service (1.2.0)
[ 26] [ 1] Apache Felix Shell TUI (1.2.0)
[ 27] [ 1] Apache Felix Bundle Repository (1.4.0)
[ 39] [ 1] User Model Interface Plug-in (1.0.0)
[ 40] [ 1] User DB Implement Plug-in (1.0.0)
[ 41] [ 1] User File Implement Plug-in (1.0.0)
-> start 40
-> ps -s
START LEVEL 1
ID State Level Symbolic name
[ 0] [ 0] org.apache.felix.framework (1.6.0)
[ 25] [ 1] org.apache.felix.shell (1.2.0)
[ 26] [ 1] org.apache.felix.shell.tui (1.2.0)
[ 27] [ 1] org.apache.felix.bundlerepository (1.4.0)
[ 39] [ 1] com.dinstone.demo.user (1.0.0)
[ 40] [ 1] com.dinstone.demo.user.db (1.0.0)
[ 41] [ 1] com.dinstone.demo.user.file (1.0.0)
->
访问http://localhost:8080/webDemo/。页面显示:
Step5.
启动User File Implement Plug-in服务,激活User模块的File实现。
-> ps
START LEVEL 1
ID State Level Name
[ 0] [ 0] System Bundle (1.6.0)
[ 25] [ 1] Apache Felix Shell Service (1.2.0)
[ 26] [ 1] Apache Felix Shell TUI (1.2.0)
[ 27] [ 1] Apache Felix Bundle Repository (1.4.0)
[ 39] [ 1] User Model Interface Plug-in (1.0.0)
[ 40] [ 1] User DB Implement Plug-in (1.0.0)
[ 41] [ 1] User File Implement Plug-in (1.0.0)
-> start 41
-> ps
START LEVEL 1
ID State Level Name
[ 0] [ 0] System Bundle (1.6.0)
[ 25] [ 1] Apache Felix Shell Service (1.2.0)
[ 26] [ 1] Apache Felix Shell TUI (1.2.0)
[ 27] [ 1] Apache Felix Bundle Repository (1.4.0)
[ 39] [ 1] User Model Interface Plug-in (1.0.0)
[ 40] [ 1] User DB Implement Plug-in (1.0.0)
[ 41] [ 1] User File Implement Plug-in (1.0.0)
->
访问http://localhost:8080/webDemo/。页面显示:
Step6.现在停止User DB Implement Plug-in服务。
-> ps
START LEVEL 1
ID State Level Name
[ 0] [ 0] System Bundle (1.6.0)
[ 25] [ 1] Apache Felix Shell Service (1.2.0)
[ 26] [ 1] Apache Felix Shell TUI (1.2.0)
[ 27] [ 1] Apache Felix Bundle Repository (1.4.0)
[ 39] [ 1] User Model Interface Plug-in (1.0.0)
[ 40] [ 1] User DB Implement Plug-in (1.0.0)
[ 41] [ 1] User File Implement Plug-in (1.0.0)
-> stop 40
-> ps
START LEVEL 1
ID State Level Name
[ 0] [ 0] System Bundle (1.6.0)
[ 25] [ 1] Apache Felix Shell Service (1.2.0)
[ 26] [ 1] Apache Felix Shell TUI (1.2.0)
[ 27] [ 1] Apache Felix Bundle Repository (1.4.0)
[ 39] [ 1] User Model Interface Plug-in (1.0.0)
[ 40] [ 1] User DB Implement Plug-in (1.0.0)
[ 41] [ 1] User File Implement Plug-in (1.0.0)
->
访问http://localhost:8080/webDemo/。页面显示:
4.6 停止Tomcat服务器
重新打开一个命令行窗口,切换到${Tomcat_Home}\bin目录下。执行:
E:\Cluster\apache-tomcat-6.0.18\bin>shutdown.bat
Tomcat服务器关闭。
5结论
通过以上的测试,我们发现以上的实现基本符合最初的设想:
l
OSGi的集成对Tomcat几乎是透明的。
l
OSGi的所有优点。
l
Web表现和业务逻辑的完全分离。
l 基于模块化服务的编程模型。
同时,我们也发现了一些问题:
l
Web层没有支持模块化、可热插拔的编程模型。
l
OSGi层的服务日志跟web层的日志分离增加了维护的难度。
l 该集成方式没有经严格测试,虽然已经有产品应用了。
附录:
1.测试Demo
…
2.源码工程
…
页:
[1]