Apache Felix @Reference注释问题

时间:2016-06-21 19:01:18

标签: java servlets osgi apache-felix sling

我目前正在开发一个Sling servlet,它通过Apache Felix使用OSGi框架。据我所知,如果您想获得并使用其他服务,您有两种选择: 1.编写服务监听器,确保在获取和使用服务之前注册所需的服务。 2.使用Apache Felix的@Reference注释获取服务。

我想做选项2,因为选项1需要大量我不需要编写的代码。

所以,这就是我如何做到的。只是一个免责声明:以下是我的代码的片段,并不构成我的整个项目。不要指望能够编译这个或任何东西。我已经包含了我认为相关的部分。

首先,我有我的sling servlet:

package mypackage;
import /*necessary imports*/

@Component( name = "My Sling Servlet", immediate = false, metatype = true)
@Properties({
    @Property(name = "sling.servlet.paths", value = "/bin/mytest"),
    @Property(name = "sling.servlet.methods", value = "GET")
})

@Service(Servlet.class)
public class MyServlet extends SlingSafeMethodsServlet {
    @Reference
    private MyService service;

    // Do stuff with service
}

据我所知,@Component注释让OSGi知道这个类文件定义了一个组件。 @Properties注释定义了组件的一些基本属性(在这种情况下,现在我们可以通过转到[hostname]/bin/mytest来运行此servlet,这对我们很重要)。 @Service注释允许OSGi知道该类是一个服务(特别是实现Servlet类的服务),并且还注册该服务。最后,@Reference注释告诉OSGi我们要声明的字段是这个包中已经注册的OSGi服务,我们应该抓住它。

现在,这是另一个相关文件,它定义了服务MyService:

package mypackage;
import /*necessary imports*/

@Component(name="MyService", immediate=false,metatype=true)

@Service(value = MyServiceInterface.class)
public class MyService implements MyServiceInterface {
    // Implementation of MyServiceInterface
}

在这里,我们声明MyService是一个使用@Component注释的OSGi组件。这里的重要注意事项是我们使用@Service注释,它显然完成了一项基本任务: @Service注释注册服务。

请假设有一个MyServiceInterface.java文件,如下所示:

package mypackage;
import /*necessary imports*/

public interface MyServiceInterface {
    //stuff
}

随着所有这些预备工作的完成,这是我的问题。当我通过在Web浏览器中访问[hostname]/bin/mytest来运行我的servlet时,我得到404页面未找到错误。这表明我的浏览器找不到servlet。

您现在可能会问自己为什么我认为这与@Reference注释有某种关联。嗯,我认为它有点负责任,因为当我发表评论并以旧式方式(即上面的方法1)获得服务时,servlet运行没有任何问题。

另一个可能相关的信息是我正在使用Maven来构建这个项目。如果您认为它们包含有用信息,我很乐意提供相关的pom.xml文件。

请帮助我弄清楚当我使用@Reference注释时无法找到我的servlet的原因!如果您在帮助我之前需要我提供更多信息,那么我很乐意这样做。如果我没有提供足够的信息,请在评论中注明。

提前致谢!

3 个答案:

答案 0 :(得分:0)

我经常做的第一件事是检查我的bundle和servlet是否在http://localhost:8080/system/console/bundleshttp://localhost:8080/system/console/components的Apache Felix控制台中处于活动状态。您是否有任何遗漏的依赖项阻止您的捆绑或组件变为活动状态?

根据您的问题,我的第一个猜测是您可能没有使用Apache Felix Maven SCR Plugin。如你所说,你不想手动创建ServiceListeners(你声明的选项1),而是宁愿使用Declarative Services(你声明的选项2),为此你需要SCR插件。诸如@Reference之类的注释不是运行时,SCR插件使用它们来生成服务在声明服务的OSGi环境中工作所需的代码和元数据。上面提供的文档链接详细介绍了插件的功能。只需将插件添加到pom.xml文件中,如文档中所示:

<project>
  ...
  <build>
    ...
    <plugins>
      ...
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-scr-plugin</artifactId>
        <version>1.20.0</version>
        <executions>
          <execution>
            <id>generate-scr-scrdescriptor</id>
            <goals>
              <goal>scr</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      ...
    </plugins>
    ...
  </build>
  ...
</project>

请参阅Using the Apache Felix Maven SCR Plugin to generate Declarative Services and Metatype Service descriptors during a Maven Build

答案 1 :(得分:0)

如果您的servlet在没有引用的情况下工作,并且在添加引用后它立即停止工作,那么引用本身就应该是问题。

最明显的解决方案是无法访问引用(无论出于何种原因,可能是服务接口类未导出但是它在另一个包中?)因此它的状态为“notisfied”。在这种情况下,servlet无法启动。

您是否确实在/ system / console / components中检查了servlet,或者您是否只检查了相应的组件?

BTW您的servlet不需要所有这些注释。简单地使用 @SlingServlet(paths = {“/ bin / mytest”},metatype = false,generateService = true) 您可以删除@Component和@Service。

答案 2 :(得分:0)

首先,您需要知道是什么原因造成的: 有时,您对一个对象(尤其是在大型项目中)使用多个依赖关系,这将导致IDE无法识别您的意思。

就我而言:

    <dependency>
        <groupId>org.onosproject</groupId>
        <artifactId>onos-api</artifactId>
        <version>${onos.version}</version>
    </dependency>

和:

    <dependency>
        <groupId>org.onosproject</groupId>
        <artifactId>onos-providers-openflow-meter</artifactId>
        <version>1.8.9</version>
    </dependency>

都指向同一个对象,因此使用@Reference批注会导致IDE无法注入该对象的问题。 错误文本可能是这样的:

Annotation @reference is disallowed for this location.

现在您知道了问题,如何解决: 不要使用超出项目需求的依赖项。 在上面的示例中,删除第二个依赖项解决了该问题。

另一种方法是设置您确切表示的依赖项: 如您所知,有多种方法可以在OSGi批注中使用@Reference批注。 而不是使用:

@Reference
MyService myService;

使用此:

private MyService myService;
@Reference
public void bindMyService(MyService myService) {
     this.myService = myService;
}
public void unbindMyService(MyService myService) {
     this.myService = myService;
}

第二个选项解决了这个问题。