【发布时间】:2015-11-02 08:43:39
【问题描述】:
我想用 OSGI 完成一些事情,这在 Guice 或 Spring 等依赖注入框架中非常简单。
我想把服务实现类和服务接口放在同一个包里。这使我能够使用与服务客户端无关的包可见方法。
Guice 实现这一点的方法很简单,让服务实现类包可见。服务接口:
package com.example.services;
public interface SomeService {
void scanClasses(ServiceHelper helper);
}
以及实现:
package com.example.services;
// Package visible service implementation
class SomeServiceImpl implements SomeService {
@Override
public void scanClasses(ServiceHelper helper) {
ClassLoader bundlesClassLoader = helper.getClassLoader();
// do something with bundle's classes
}
}
这是 ServiceHelper 类,它也有包可见的方法:
package com.example.services;
import org.osgi.framework.BundleContext;
import org.osgi.framework.wiring.BundleWiring;
public class ServiceHelper {
private ClassLoader bundleClassLoader;
public ServiceHelper(BundleContext bc) {
this.bundleClassLoader = bc.getBundle().adapt(BundleWiring.class).getClassLoader();
}
// Package visible method to be called from SomeServiceImpl class
ClassLoader getClassLoader() {
return bundleClassLoader;
}
}
但是 OSGI 不能用包可见声明或构造函数来实例化 ServiceImpl 类:
java.lang.IllegalAccessException:类 org.eclipse.equinox.internal.ds.model.ServiceComponent 无法访问带有修饰符“”的类 com.example.SomeServiceImpl 的成员
为了完成这个例子,这是服务客户端代码,它不应该受到设计的影响:
package com.example.serviceclient;
import org.osgi.framework.BundleContext;
import com.example.services.ServiceHelper;
import com.example.services.SomeService;
public class ServiceClientExample {
private SomeService someService;
public void activate(BundleContext bc) {
someService.scanClasses(new ServiceHelper(bc));
}
public void setSomeService(SomeService service) {
this.someService = service;
}
}
将服务实现放到另一个包中,尝试构建好的面向对象的封装需要太多的工作,比如将包可见方法映射到调用者的访问器类,我相信应该有另一种方式。
【问题讨论】:
-
您尝试做的事情会破坏基于包的 OSGI 导出和导入。客户端总是需要导入接口的包,所以这个包必须在 OSGi 中导出。不应导出实施。因此,即使您可以解决上述问题,您也应该始终为 interface 和 impl 使用单独的包。