1.目的
在这篇文章中,我们将采取两种方式用OSGI运行Servlet,一种是利用服务追踪器的方式,一种是利用声明式服务的方式。
2.概念
在OSGI中,最重要的概念就是Bundle、服务和生命周期。
Bundle也就是OSGI模块化编程的模块;Bundle之间的互相依赖主要体现在,某些Bundle会注册服务提供使用,而某些Bundle则会使用这些服务;而生命周期,则是指在运行系统时,可以安装、启动、停止、更新和卸载Bundle。
由于OSGI系统本身是松耦合的,所以并不存在一个主Bundle最先运行的概念,所有Bundle都是同级运行的。这样就引发一个问题,即如果Bundle A引用了Bundle B的服务,那么如果Bundle A在Bundle B之前运行,就会出错。
服务追踪器和声明式服务则让我们可以规避掉Bundle启动顺序的问题,它使得我们可以在所依赖的服务被注册时才使用该服务(这点是OSGI内部已经实现好了的,我们只需要按照它提供的API使用即可)。
3.实现
1.服务追踪器方式运行Servlet
a.首先,新建一个plugin project,命名为 org.osgiequinox.servlet.test1。
b.然后,选择Run-Run Configuration,选中OSGI Framework新建一个New_Configuration。在Bundle页签中,首先选择Deselect All,然后将org.osgiequinox.servlet.test1勾选上,同时还需要勾选上运行OSGI项目所需要的其他Bundle,分别为:
所有含有"jetty"字样的bundle
org.apache.felix.gogo.command
org.apache.felix.gogo.runtime
org.apache.felix.gogo.shell
org.eclipse.equinox.console
org.eclispe.quinox.util
org.eclipse.osgi.services
再选择“Add Required Bundle”添加所有其他依赖的Bundle。
此时,选择run。在浏览器中输入http://localhost,可以看到:
HTTP ERROR: 404
Problem accessing /. Reason:
ProxyServlet: /
Powered by Jetty://
c.我们选中MANIFEST.MF,然后选择Dependencies,然后选择Auto Management of Dependencies,保证Imported-Package被勾选上。加入以下包。
javax.servlet
javax.servlet.http
org.osgi.framework
org.osgi.util.tracker
org.osgi.service.http
d.我们在src/org.osgiequinox.servlet.test1下新建TestServlet,代码如下:
package org.osgiequinox.servlet.test1;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Tammy Pi
* @function print a sentence
*/
public class TestServlet extends HttpServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response){
response.setContentType("text/html");
PrintWriter out = null;
try{
out = response.getWriter();
out.println("Hello OSGI!");
out.flush();
}catch(Exception ex){
ex.printStackTrace();
}finally{
if(out != null){
out.close();
}
}
}
}
e.在同级目录下,新建激活器(如果已经有激活器了,就直接在里面写代码就可以了),利用服务追踪器获得HttpService服务,从而利用HttpService注册Servlet:
package org.osgiequinox.servlet.test1;
import javax.servlet.ServletException;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
* @author Tammy Pi
* @function 1.tracker httpservice 2.register servlet
*/
public class Activator implements BundleActivator {
private ServiceTracker httpServiceTracker;
private BundleContext ctx;
private HttpService httpService;
private ServiceTrackerCustomizer createHttpServiceCustomizer(){
return new ServiceTrackerCustomizer(){
@Override
public Object addingService(ServiceReference arg0) {
Object service = ctx.getService(arg0);
Activator.this.httpService = (HttpService) service;
try {
Activator.this.httpService.registerServlet("/demo/test",new TestServlet(),null,null);
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NamespaceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return service;
}
@Override
public void modifiedService(ServiceReference arg0, Object arg1) {
}
@Override
public void removedService(ServiceReference arg0, Object arg1) {
if(arg1 != Activator.this.httpService){
return;
}
Activator.this.httpService.unregister("/demo/test");
Activator.this.httpService = null;
}
};
}
@Override
public void start(BundleContext arg0) throws Exception {
ctx = arg0;
ServiceTrackerCustomizer cus = createHttpServiceCustomizer();
httpServiceTracker = new ServiceTracker(arg0,HttpService.class.getName(),
cus);
httpServiceTracker.open();
}
@Override
public void stop(BundleContext arg0) throws Exception {
httpServiceTracker.close();
}
}
f 此时在浏览器访问:http://localhost/demo/test
即可以看到:
Hello OSGI!
字样,即表明运行servlet成功。
2.声明式服务方式运行Servlet
从上面可以看到,通过服务追踪器运行servlet需要用到ServiceTracker和ServiceCustomerizer,有点小复杂(考虑一下需要用到很多服务的情况)。有没有一种办法可以让我们不用写那么多代码,服务就自动依赖注入进去呢?就像Spring的IoC那样。这个时候,就是声明式服务发挥作用的时候了。
a.咱们换一个workspace,然后再新建一个Plugin Project,取名为org.osgiequinox.servlet.test2
b..然后,选择Run-Run Configuration,选中OSGI Framework新建一个New_Configuration。在Bundle页签中,首先选择Deselect All,然后将org.osgiequinox.servlet.test2勾选上,同时还需要勾选上运行OSGI项目所需要的其他Bundle,分别为:
所有含有"jetty"字样的bundle
org.apache.felix.gogo.command
org.apache.felix.gogo.runtime
org.apache.felix.gogo.shell
org.eclipse.equinox.console
org.eclispe.quinox.util
org.eclipse.osgi.services
org.eclipse.equinox.ds
再选择“Add Required Bundle”添加所有其他依赖的Bundle。
c.由于声明式服务不需要激活器了,所以我们把项目中的激活器给删掉
d.我们选中MANIFEST.MF,然后选择Dependencies,然后选择Auto Management of Dependencies,保证Imported-Package被勾选上。加入以下包。
javax.servlet
javax.servlet.http
org.osgi.framework
org.osgi.service.httpe.在src/org.osgiequinox.servlet.test2目录下,新建TestServlet,代码如下:
package org.osgiequinox.servlet.test2;
import java.io.PrintWriter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Tammy Pi
* @function print a sentence
*/
public class TestServlet extends HttpServlet{
public void doGet(HttpServletRequest request,HttpServletResponse response){
response.setContentType("text/html");
PrintWriter out = null;
try{
out = response.getWriter();
out.println("Hello OSGI again!");
out.flush();
}catch(Exception ex){
ex.printStackTrace();
}finally{
if(out != null){
out.close();
}
}
}
}
f.在同级目录下新建Component.java文件,内容如下:
package org.osgiequinox.servlet.test2;
import javax.servlet.ServletException;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
/**
* @author Tammy Pi
* @function register servlet
*/
public class Component {
private HttpService httpService;
public void setHttpService(HttpService httpService) {
this.httpService = httpService;
}
public void startup(){
try {
this.httpService.registerServlet("/demo/test", new TestServlet(), null, null);
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NamespaceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void shutdown(){
this.httpService.unregister("/demo/test");
}
}
g.在项目上点击右键,New->Other->Plugin Devlopment->Component Definition。然后选择文件夹OSGI-INF,类org.osgiequinox.servlet.test2.Component,新建component.xml文件,文件内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.osgiequinox.servlet.test2"
activate="startup" deactivate="shutdown">
<implementation class="org.osgiequinox.servlet.test2.Component"/>
<reference bind="setHttpService" name="httpService"
interface="org.osgi.service.http.HttpService" policy="static"/>
</scr:component>
h.运行项目,Run As->OSGI framewok。然后,在浏览器中输入:http://localhost/demo/test
可以看到:Hello OSGI again!
声明式服务运行servlet成功。
4.总结
以上就是通过服务追踪器和声明式服务运行Servlet的过程,可以看到,声明式服务更加简洁、明了。