使用在后台运行的 REST Web 服务的 OSGi 网站

Posted

技术标签:

【中文标题】使用在后台运行的 REST Web 服务的 OSGi 网站【英文标题】:Website in OSGi that consumes REST web service running in background 【发布时间】:2016-03-20 05:00:32 【问题描述】:

我花了好几天的时间试图弄清楚如何在 OSGi 中添加网站。

我有一个使用 Jetty 扩展运行的 Restlet Web 服务,以使用 Jetty 作为连接器。此功能在多个 URL 下提供不同的资源。

但我还想在系统上运行一个用户可以访问的小型网站。我想使用一些 htmljavascript、CSS 并通过一些图形和图片提供当前数据状态。

我假设由于 Jetty 在后台运行,我将能够在 Jetty 上部署该网站,并可能在 Javascript 中调用 Restlet 提供的服务器资源。

显然,除了 restlet 服务之外,没有任何效果。

我的问题是是否可以添加 WAB 捆绑包并期望它能够工作(因为 Jetty 在后台运行)?或者有没有更好的方法在 OSGi 中添加网站? 要么 我现在唯一的选择是,因为可以返回 HTML 表单作为表示,将我所有的 javascript 代码添加到 HTML 表单中并将其作为对 GET 请求的响应发送(我认为这是一团糟)。

一切都将在 Raspberry pi 中运行,因此我只能占用很小的空间。我正在使用 Equinox、Restlet 2.3.0 和 Jetty 9.2.6。

如果有人知道一个链接,我可以在其中获取有关在 OSGi 中运行至少一个示例页面的信息,我将不胜感激。我试过很多都没有运气。

【问题讨论】:

【参考方案1】:

我建议您看看它是如何在 Apache Karaf (https://github.com/apache/karaf) 中完成的。更多关于 Apache Karaf 和 WebContainers 的信息:http://karaf.apache.org/manual/latest/users-guide/webcontainer.html

【讨论】:

【参考方案2】:

事实上,Restlet 通过其连接器功能在内部使用了 Jetty。这样,动态注册应用程序不方便(也不是正确的方法)。

也就是说,Restlet 非常灵活和动态。这意味着您可以以与 WAB 包类似的方式动态处理包含 Restlet 应用程序的包,即将它们附加到组件的虚拟主机。

实现方法如下:

创建一个捆绑包,使 Restlet 组件可用于 OSGi 容器。您应该利用 FrameworkListener 侦听器来将所有连接器、转换器等...注册到 Restlet 引擎中:

private Component component;

public void start(BundleContext bundleContext) throws Exception 
    bundleContext.addFrameworkListener(new FrameworkListener() 
        component = new Component();
        (...)
        component.start();
    );


public void stop(BundleContext bundleContext) throws Exception 
    component.stop();

当组件启动时,您可以查找容器中存在的包和包含的 Restlet 应用程序。对于这种类型的每个捆绑包,您可以注册一个专用的 OSGi 服务,该服务使您想要针对该组件注册的内部 Restlet 应用程序可用。

ServiceReference[] restletAppRefs = bundleContext.getServiceReferences(
     "restletApplication",
                null);

if (restletAppsRefs != null) 
    for (ServiceReference restletAppRef : restletAppsRefs) 
        RestletApplicationService descriptor
             = (RestletApplicationService) bundleContext
               .getService(serviceReference);
        String path = descriptor.getPath();
        Application restletApplication = descriptor.getApplication();

        // Register the application against the component
        (...)
    

针对组件注册应用程序是

try 
    VirtualHost virtualHost = getExistingVirtualHost(
                   component, hostDomain, hostPort);
    if (virtualHost == null) 
        virtualHost = new VirtualHost();
        virtualHost.setHostDomain(hostDomain);
        virtualHost.setHostPort(hostPort);

        component.getHosts().add(virtualHost);
    

    Context context = component.getContext().createChildContext();
    virtualHost.setContext(context);

    virtualHost.attachDefault(application);

    component.updateHosts();

    application.start();
 catch(Exception ex) 
    (...)

您还需要考虑 OSGi 的动态性。我的意思是捆绑可以在 OSGi 容器本身启动之后来来去去。你可以利用

bundleContext.addServiceListener(new ServiceListener() 
    public void serviceChanged(ServiceEvent event) 
        if (isServiceClass(event, RestletApplicationService)) 
            int type = event.getType();

            if (type == ServiceEvent.REGISTERED) 
                // Register the Restlet application against the component
             else if (type == ServiceEvent.UNREGISTERING) 
                // Unregister the Restlet application
            
        
    
);

希望对你有帮助 蒂埃里

【讨论】:

非常感谢您的回复。但是我已经运行了一个完整的基于 Restlet 的服务。我已经创建了组件,注册了我的应用程序,并使用相应的 url 添加了到我的不同资源类的路由。问题在于为网站提供一个漂亮的用户界面来总结和呈现状态(通过访问不同的资源 url 并添加一些 javascript、css ......)。我目前使用 FreeMarker,并将网站作为 FreeMarker 的 html 表单表示返回。但这违背了html表单的概念。我想让网站 HTML 直接可访问【参考方案3】:

您可以使用许多选项 - OSGi 并没有真正对您可以做的事情施加太多限制。如果您想使用 OSGi 的功能,那么这里有几个想法:

一种选择是部署 WAB。您需要确保您的框架运行了必要的 OSGi 服务。仅仅因为某些包在内部使用了 Jetty,它并不意味着必要的 OSGi 服务正在运行。

包 org.apache.felix.http.jetty 确实提供了部署 WAB 所需的服务。 2.2.2 版的磁盘空间为 1.3MB,并嵌入了自己的 Jetty 副本。其他实现是可用的(例如 Pax-Web,在 Karaf 中使用 - 它也嵌入了 Jetty)

另一种选择是直接使用 OSGi Http 服务(同样,您需要包含一个实现此服务的包(如提到的 Felix)。调用 org.osgi.service.http.HttpService.registerResources() 将从您的内部提供静态内容捆绑。

如果这个额外的足迹是一个真正的问题,那么您可能想看看如何让 Restlet 使用 OSGi http 服务,而不是通过嵌入式 Jetty 提供它自己的服务。

另一种选择是以 Jetty 为中心的观点。 Restlet 的嵌入式 Jetty 可能未配置为从磁盘提供任意内容。您可以考虑重新配置嵌入式 Jetty 来执行此操作,或者考虑将 Restlet 部署到“标准”Jetty 安装。就个人而言,我会尝试后者。

【讨论】:

正如您在部署 WAB 的第一个选项中所说,我需要拥有必要的捆绑包,这是我的问题之一。鉴于在 J2SE 选项下没有明确的 Equinox 指南,识别和实现依赖关系是一件令人头疼的事情。我将在周末尝试 org.apache.felix.http.jetty,但我认为这又会带来对其他 felix 捆绑包的完全其他依赖。至于第二个,Jetty 甚至建议在 OSGi 中嵌入 Jetty,而不是在 Jetty 上部署应用程序。

以上是关于使用在后台运行的 REST Web 服务的 OSGi 网站的主要内容,如果未能解决你的问题,请参考以下文章

如何在eclipse上配置rest服务啊

Spring 4 REST Web 服务无法使用安全性

使用 IIS 在 Delphi 2009 中创建 REST Web 服务

在同一个 Spring Boot 应用程序中的 Rest 服务和 Web 服务

2022就业季|Spring认证教你,如何使用 Spring 构建 REST 服务

Geoserver的rest接口使用(后台或者前端调实现自动发布服务)