又见net.jxta.exception.ServiceNotFoundException

与以前帖子中提到的原因(JXSE的bug)不一样,不过这个也蛮奇怪的。

异常堆栈提示并不明显。在一堆日志中发现这么几行:

Exception in startApp() : jxmessenger.jxse.presenceservice.PresenceServiceImpl@1a33efb

java.lang.NullPointerException

Line 202 net.jxta.socket.JxtaMulticastSocket.joinGroup()

....

Service failed to start (-1) : jxmessenger.jxse.presenceservice.PresenceServiceImpl@1a33efb

 在确认了数遍后,确定startApp函数并没有问题?

在与之前正常的代码比较之后,发现在startApp()函数开始的地方少了

discovery = group.getDiscoveryService();
if(discovery == null) {
    
return Module.START_AGAIN_PROGRESS;
}

 因为后来该Service的实现不再需要发现服务,故上面这段代码被删除了,结果就出现了上面的问题。

奇怪的是,该Service并不需要发现服务。继续跟踪源代码...

--------------------------------------------------------------------------------------------------------

 找到原因了,是MulticastSocket引起的问题,请看修改前有问题的startApp代码

@Override
public int startApp(String[] args) {
    
// ...
    try {
        mcastSocket 
= new JxtaMulticastSocket(group, createSocketAdvertisement());
    } 
catch(IOException ex) {
        Exceptions.printStackTrace(ex);
    }
    
    
// ...

    
return Module.START_OK;
}

 在JxtaMulticastSocket.java的代码中,我们看到

    /**
     * joins MutlicastSocket to specified pipe within the context of group
     *
     * 
@param group  group context
     * 
@param pipeAd PipeAdvertisement
     * 
@throws IOException if an io error occurs
     
*/
    
public void joinGroup(PeerGroup group, PipeAdvertisement pipeAd) throws IOException {

        
if (pipeAd.getType() != null && !pipeAd.getType().equals(PipeService.PropagateType)) {
            
throw new IOException("Only propagate pipe advertisements are supported");
        }
        
if (pipeAd.getPipeID() == null) {
            
throw new IOException("Invalid pipe advertisement");
        }

        
this.group = group;
        
this.pipeAdv = pipeAd;
        pipeSvc = group.getPipeService();
        
this.in = pipeSvc.createInputPipe(pipeAd, this);
        
this.credentialDoc = getCredDoc(group);
        outputPipe 
= pipeSvc.createOutputPipe(pipeAd, 1);
        String id 
= group.getPeerID().toString();

        srcElement 
= new StringMessageElement(SRCIDTAG, id, null);

        Logging.logCheckedInfo(LOG, 
"Starting JxtaMulticastSocket on pipe id :", pipeAdv.getID());

        String pipeStr 
= pipeAd.getPipeID().getUniqueValue().toString();

        localAddress 
= InetAddress.getByAddress(pipeStr, fauxip);
        socketAddress 
= new InetSocketAddress(localAddress, 0);
        bound 
= true;
    }

 黄色底色两行需要管道服务,而通过调试,正是这个管道服务对象为null。可见MulticastSocket是依赖于管道服务的。这就提醒我们,在自定义服务中,如果使用

MulticastSocket,则必须保证管道服务优先加载。方法是在startApp方法中加入

PipeService pipeService = group.getPipeService();
if(pipeService == null) {
    
return Module.START_AGAIN_PROGRESS;
}
// ....

 而之前我们在现象描述时说加入类似的发现服务是也能使得程序正常,应该是一种巧合,刚好此时管道服务也被加载了。

 好了,原因及解决方法就到这里。

以后在涉及这种隐性依赖的时候需要注意处理,如果在自定义服务中使用高级的管道服务(JxtaBiDiPipe或JxtaSocket)可能也会遇到这种情况。



原文地址:https://www.cnblogs.com/cuizhf/p/2181461.html