OSGI运行Servlet(使用Equinox框架)

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.http

e.在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的过程,可以看到,声明式服务更加简洁、明了。


你可能感兴趣的:(OSGI运行Servlet(使用Equinox框架))