我的Liferay服务实现模块的两个实例

时间:2017-08-25 14:11:02

标签: liferay osgi liferay-7

我写了一个定义服务的模块:

public interface TranslationService {
    // a method.
}

......实现服务的模块:

@Component(
    immediate = true,
    configurationPid = "my.TranslationConfiguration"
)
public class TranslationServiceImpl implements TranslationService {

    log.info("Constructor " + getClass().getName()
             + " " + System.identityHashCode(this));

    @Activate
    @Modified
    protected void activate(Map<String, Object> properties) {
        log.info("Configuring " + translationService.getClass().getName()
                 + " " + System.identityHashCode(this));
        configuration = ConfigurableUtil.createConfigurable(
            TranslationConfiguration.class, properties);
}

    // an implementation of the method.
}

其服务激活器:

public class ServiceActivator implements BundleActivator {

    private ServiceRegistration registration;

    @Override
    public void start(BundleContext context) throws Exception {
        registration = context.registerService(TranslationService.class.getName(), new TranslationServiceImpl(), null);
    }

    [...]
}

...以及使用该服务的模块:

@Component(
    immediate = true,
    configurationPid = [...]
    service = Portlet.class
)
public class TranslationPortlet extends MVCPortlet {

    @Reference(unbind = "-")
    protected void setTranslationService(TranslationService translationService) {
        log.info("Using " + translationService.getClass().getName()
               + " " + System.identityHashCode(translationService));
        this.translationService = translationService;
    }

    private TranslationService translationService;
}

日志

当我开始(通过Gogo Shell)API和实施模块时记录:

Constructor my.TranslationServiceImpl 606817095
Service registered.
STARTED my.impl_1.0.0 [538]
Constructor my.TranslationServiceImpl 362465287
Configuring my.TranslationServiceImpl 362465287

然后当我开始(通过Gogo Shell)使用模块:

STARTED my.app_1.0.0 [558]
Using my.TranslationServiceImpl 606817095

问题

为什么要使用两个实例?
如何让所有模块使用我的服务实现的相同实例?

详细

调用实现构造函数的两次Stacktraces:

my.TranslationServiceImpl.<init>(TranslationServiceImpl.java:56)
my.ServiceActivator.start(ServiceActivator.java:24)
org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:774)
org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:1)
java.security.AccessController.doPrivileged(Native Method)
org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:767)
org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:724)
org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:951)
org.eclipse.osgi.internal.framework.EquinoxBundle$EquinoxModule.startWorker(EquinoxBundle.java:328)
org.eclipse.osgi.container.Module.doStart(Module.java:566)
org.eclipse.osgi.container.Module.start(Module.java:434)
org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:402)
org.apache.felix.gogo.command.Basic.start(Basic.java:729)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.apache.felix.gogo.runtime.Reflective.invoke(Reflective.java:137)

然后:

my.TranslationServiceImpl.<init>(TranslationServiceImpl.java:56)
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
java.lang.reflect.Constructor.newInstance(Constructor.java:423)
java.lang.Class.newInstance(Class.java:442)
org.apache.felix.scr.impl.manager.SingleComponentManager.createImplementationObject(SingleComponentManager.java:236)
org.apache.felix.scr.impl.manager.SingleComponentManager.createComponent(SingleComponentManager.java:108)
org.apache.felix.scr.impl.manager.SingleComponentManager.getService(SingleComponentManager.java:906)
org.apache.felix.scr.impl.manager.SingleComponentManager.getServiceInternal(SingleComponentManager.java:879)
org.apache.felix.scr.impl.manager.AbstractComponentManager.activateInternal(AbstractComponentManager.java:748)
org.apache.felix.scr.impl.manager.AbstractComponentManager.enableInternal(AbstractComponentManager.java:674)
org.apache.felix.scr.impl.manager.AbstractComponentManager.enable(AbstractComponentManager.java:429)
org.apache.felix.scr.impl.manager.ConfigurableComponentHolder.enableComponents(ConfigurableComponentHolder.java:657)
org.apache.felix.scr.impl.BundleComponentActivator.initialEnable(BundleComponentActivator.java:341)
org.apache.felix.scr.impl.Activator.loadComponents(Activator.java:403)
org.apache.felix.scr.impl.Activator.access$200(Activator.java:54)
org.apache.felix.scr.impl.Activator$ScrExtension.start(Activator.java:278)
org.apache.felix.utils.extender.AbstractExtender.createExtension(AbstractExtender.java:259)
org.apache.felix.utils.extender.AbstractExtender.modifiedBundle(AbstractExtender.java:232)
org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:482)
org.osgi.util.tracker.BundleTracker$Tracked.customizerModified(BundleTracker.java:1)
org.osgi.util.tracker.AbstractTracked.track(AbstractTracked.java:232)
org.osgi.util.tracker.BundleTracker$Tracked.bundleChanged(BundleTracker.java:444)
org.eclipse.osgi.internal.framework.BundleContextImpl.dispatchEvent(BundleContextImpl.java:905)
org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:230)
org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:148)
org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEventPrivileged(EquinoxEventPublisher.java:165)
org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:75)
org.eclipse.osgi.internal.framework.EquinoxEventPublisher.publishBundleEvent(EquinoxEventPublisher.java:67)
org.eclipse.osgi.internal.framework.EquinoxContainerAdaptor.publishModuleEvent(EquinoxContainerAdaptor.java:102)
org.eclipse.osgi.container.Module.publishEvent(Module.java:461)
org.eclipse.osgi.container.Module.start(Module.java:452)
org.eclipse.osgi.internal.framework.EquinoxBundle.start(EquinoxBundle.java:402)
org.apache.felix.gogo.command.Basic.start(Basic.java:729)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.apache.felix.gogo.runtime.Reflective.invoke(Reflective.java:137)

所以看起来我不应该在服务激活器中实例化实现?这就是this tutorial中似乎如何完成的。

2 个答案:

答案 0 :(得分:3)

您正在获取组件的第二个实例,因为您是在ServiceActivator.java的第24行显式创建它。这是由您发布的第一个堆栈跟踪显示的。

只需删除该行代码,一切都会好的。

事实上,你可能根本不需要ServiceActivator。我假设你的捆绑包是BundleActivator?在使用DS时,您不需要编写激活器,因为您可以在激活器中执行的任何操作都可以在DS组件中完成,此外还有更多功能。事实上,我的一般建议是永远不要编写捆绑激活器。

答案 1 :(得分:2)

Neil找到了答案,让我补充一些细节:

正如Neil所说,不需要服务激活器,尽管我在我的问题中提到了教程。只需将其删除即可。

显然,同时从Bundle-Activator:移除bnd.bnd行,否则在部署时会出现Bundle-Activator not found on the bundle class path nor in imports错误。

代替服务激活器,使用&#34; DS&#34;尼尔谈到的事情。它表示声明式服务,是一种使用注释的OSGi技术。要使用它,只需在实现类的service =注释中添加@Component指令,并将实现的服务(API)接口作为值。例如:

@Component(
    service = TranslationService.class,
    immediate = true,
    configurationPid = "my.TranslationConfiguration"
)
public class TranslationServiceImpl implements TranslationService {