maven wagon 引起的一个 IOException
使用 maven 进行 build 的时候,maven 会从 repository 中下载 artifact,maven 抽象了一个 Wagon 对象,由它来 download 和 deploy artifact。最近碰到了一个由它引起的一个灵异现象,花了一天才解决。
先说一下我们的应用场景吧,不理解我们的应用场景是很难理解为什么我们会碰到这个问题。现在我们的部分应用使用 maven build,我们有大量的遗留 java 类库,这些类库之前是放在 svn 中,如开发要使用只需 checkout,并使用我们自己开发的依赖管理工具来管理应用中的依赖。现在这些类库需要提供给使用 maven build 的应用使用,同时遗留应用还要能用以前的方式来使用这些类库。为此我们写了一个代理程序,简单地说就是一个 servlet,只要在 maven 的 settings 或 pom 中配置一下,maven 就能从这个代理中下载这些依赖。
代理的最近一次更新后频繁地抛 EofException(jetty 中的一个异常),引起这个异常的原因是 nio channel 中出现 broken pipe 的异常。一开始我以为是这次更新的代码中有 bug,但查了很久都没发现。后来我老板说,很有可能是我们返回给 maven 的某些信息,使 maven 提前关闭了 channel。在这句话的启发下,开始从 maven 入手。maven 中处理网络 i/o 就是 wagon,查看了 wagon 的代码后发现,果然是 wagon 提前关闭了输入流。maven 通过 WagonManager 下载依赖的时候,会首先尝试使用 Wagon 的 getIfNewer 方法,如果它失败,则会使用 Wagon 的 get 方法再尝试下载一次。下面是 StreamWagon 的 getIfNewer 方法的代码,这个类是个抽象类:
public boolean getIfNewer( String resourceName, File destination, long timestamp ) throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException { boolean retValue = false; Resource resource = new Resource( resourceName ); fireGetInitiated( resource, destination ); resource.setLastModified( timestamp ); InputStream is = getInputStream( resource ); // always get if timestamp is 0 (ie, target doesn't exist), otherwise only if older than the remote file if ( timestamp == 0 || timestamp < resource.getLastModified() ) { retValue = true; checkInputStream( is, resource ); getTransfer( resource, destination, is ); } else { IOUtil.close( is ); } return retValue; }