Servlets 在OSGi环境中的Jetty中注册servlet(类加载问题)

Servlets 在OSGi环境中的Jetty中注册servlet(类加载问题),servlets,jetty,osgi,Servlets,Jetty,Osgi,我有一个带有嵌入式Jetty 8.1.1服务器的OSGi应用程序 当我以monolit(无OSGi环境)运行我的应用程序时,我可以通过调用org.eclipse.jetty.servlet.ServletContextHandler.addServlet(字符串类名,字符串映射)方法成功注册servlet。所以现在我正试图在OSGi环境中做同样的事情 目标是编写一个bundle(ServletExtender),它将在其他bundle启动时注册它们提供的servlet(extender模式)。因

我有一个带有嵌入式Jetty 8.1.1服务器的OSGi应用程序

当我以monolit(无OSGi环境)运行我的应用程序时,我可以通过调用
org.eclipse.jetty.servlet.ServletContextHandler.addServlet(字符串类名,字符串映射)
方法成功注册servlet。所以现在我正试图在OSGi环境中做同样的事情

目标是编写一个bundle(
ServletExtender
),它将在其他bundle启动时注册它们提供的servlet(extender模式)。因此,在我的应用程序启动之后,只有两个基本的包在运行:
jetty
servlet extender

第一次尝试编写
servlet extender

首先,我决定在提供servlet的bundle的
MANIFEST.MF
文件中声明servlet及其映射。如果启动了这样的捆绑包,那么
servlet extender
将在其
MANIFEST.MF
中搜索servlet映射声明。如果找到任何servlet映射声明,则调用前面提到的
ServletContextHandler.addServlet(…)
方法来实际注册servlet

虽然这个想法似乎还可以,但类加载存在问题。事实上,Jetty调用
Class.forName(“org.my.servlets.MyServletClass”).newInstance()
。虽然
jetty
捆绑包不导入
org.my.servlets
打包调用
Class.forName(“org.my.servlets.MyServletClass”)
失败,出现
ClassNotFoundException

第二次尝试编写
servlet extender


我在OSGi中搜索了一些与类加载相关的文章。我希望通过一些OSGi服务提供加载的servlet类来解决前面的问题。因此,我使用
Map创建了
ServletProvider
服务,您不必自己做这件事。已经有PaxWeb提供了这种功能。看

PaxWeb在ApacheKaraf中也可用。在那里,您可以使用以下功能安装它:安装http白板


如果你想自己做,你可以看看PaxWeb的代码。这里的概念是简单地将servlet注册为OSGi服务。使用服务属性,您可以提供http路径等参数进行注册。

我最近注意到Jetty的8.1.1
ServletContextHandler
有一个方法
addServlet(ServletHolder,String)
。我修改了前面提到的
servlet extender
,因此它现在以以下方式注册servlet:

 public void servletProviderRegistered(ServletProvider servletProvider) {
     Map<? extends HttpServlet, String> servlets = servletProvider.getServlets();
     for (Entry<? extends HttpServlet, String> entry : servlets.entrySet()) {
         HttpServlet servletInstance = entry.getKey();
         String mapping mapping = entry.getValue();
         ServletHolder servletHolder = new ServletHolder(servletInstance);
         servletContextHandler.addServlet(servletHolder, mapping);
     }
 }
public void servletProviderRegistered(ServletProvider ServletProvider){

MapQ:我仍然对声明式注册servlet的方式感到好奇:通过servlet类名。可能吗

A:是的:)

第一种可能的解决方案:如果允许修改jetty清单,可以在清单中添加“DynamicImport Package:*”,这将允许它加载任何类,同时不依赖于自定义org.my.servlets包。 当然,请注意,对于OSGi来说,这通常是不好的做法

第二种可能的解决办法: 防波堤保持原样。 Servlet捆绑包列表,在清单中声明性地包含Servlet,与第一次尝试一样。 这里的关键是servlet extender。它将创建servlet并在jetty中注册它。整个类加载问题的重要一点是,必须在类加载器(在本例中是servlet extender的类加载器)所在的位置创建servlet对象可以访问servlet的类。 这不能发生在jetty中,因为您不能修改MF。 但是,您可以完全控制servlet extender的MF,对吗

您可以导入org.my.servlets(不推荐,因为无法预见将来必须安装哪些servlet)

或者在MF中使用“DynamicImport Package:*”(一般不推荐使用;)


或者(推荐)扩展器使用servlet jar的类加载器从servlet jar加载类-使用Bundle loadClass()方法(请参阅)。这将正确加载类。请注意,这可能会受到安全限制。

Pax web is:“OSGi R4 Http服务和web应用程序(OSGi企业版第128章)使用Jetty 7实现。”我文章的最后一句话应该解释为什么我不能使用Pax web。我认为最新的Pax web支持Jetty 8,但不确定WebSocketServlet。顺便说一句,ops4j非常乐意提供帮助。也许你可以向Pax web添加所需的功能。在OSGi中使用类名通常是一个错误的选择,因为类名仅相对于bundle cla是唯一的ssloader。最好在您自己的捆绑包中创建Servlet类并将其注册为服务。如果您使用blueprint或DS,那么我也会将此称为声明性。感谢您的回答。我有点困惑。现在我想我明白了。OSGi世界与“非模块化”Java世界非常不同。您提出的上一个解决方案(
Bundle.loadClass()
)非常好用。谢谢!