一、 osgi内嵌jetty
1、在MANIFEST.MF中添加"Service-Component : service.xml"
2、通过注册HttpService的方式来注入eclipse自己的实现,然后通过httpService对象来添加servlet拦截请求。核心xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr= "http://www.osgi.org/xmlns/scr/v1.1.0" name="org.guanmu.jetty"
activate="startup" deactivate= "shutdown">
<implementation class="org.guanmu.jetty.JettyService" />
<reference bind="setHttpService" name= "httpService"
interface="org.osgi.service.http.HttpService" policy="static"/>
</scr:component>
3、通过httpService对象的registerServlet方法添加servlet。
二、问题描述
httpService接口只提供了registerServlet、registerResources和unregister方法。没有添加过滤器的方法,所以当需要过滤需求(过滤非本地请求)时,则没法实现。
三、解决方案
打断点可以发现,在jetty调用servlet的service方法之前,是由一个ProxyServlet类中完成的,调用时先判断是否有过滤器,没有过滤器时才走到service中。进一步发现ProxyServlet的过滤器list是在org.eclipse.equinox.http.servlet.internal.HttpServiceImpl中有添加过滤器的方法。打断点发现注入的httpService对象的实际就是该类实现的,所以将httpService对象强转为httpServiceImpl对象就可以添加过滤器了。由于是osgi插件开发,导入插件依赖后,发现还是无法导入该类,在build path中去掉插件访问权限的限制,就可以引入了。虽然检查没有错误,但是运行osgi时还是报错。
1、由于能看到源码,所以尝试使用反射试试,没想到在有HttpServiceImpl 实例的情况下使用反射功能非常简单。实现如下:
Class<?> implClass = httpService.getClass();
Method method = implClass.getMethod("registerFilter", new Class[]{String.class,Filter.class,Dictionary.class,HttpContext.class});
if (method == null) {
logger.error("the httpService is not HttpServiceImpl.[" + httpService.getClass().getName() + "]");
return;
}
method.invoke(httpService, new Object[]{"/", responseFilter, null, null});
讲解:先获取到Classs对象(org.eclipse.equinox.http.servlet.internal.HttpServiceImpl类的),然后找到registerFilter方法,然后调用注册过滤器方法。该方案可以在不知道具体实现类的情况下直接调用某方法,如果没有该方法异常处理。
2、通过看源码发现org.eclipse.equinox.http.servlet包有两个公开接口除了HttpService还有一个ExtendedHttpService,ExtendedHttpService继承HttpService接口,内部访问类HttpServiceImpl就是实现了ExtendedHttpService接口,且registerFilter方法就是在ExtendedHttpService接口中定义,所以直接将httpService对象转化为ExtendedHttpService类型的实例就可以调用registerFilter方法,比反射看起来更舒服。实现如下:
if (!(httpService instanceof ExtendedHttpService)) {
logger.error("the httpService is not ExtendedHttpService.[" + httpService.getClass().getName() + "]");
return;
}
ExtendedHttpService extendHttpService = (ExtendedHttpService) httpService;
extendHttpService.registerFilter("/", responseFilter, null, null);
3、通过service.xml配置发现,注入时指定了类型是HttpService,假如直接指定为ExtendedHttpService类型呢?实验结果是ok的,这样就可以直接使用ExtendedHttpService类型的对象。但这个方法通过配置将类型写死了,如果是另外一种实现可能会出问题,还是没有第二种好,兼容其他情况。