You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Maven Resolver始终从远程仓库下载maven-metadata.xml问题排查

Maven依赖加载器快照依赖解析问题

项目代码

Java核心实现

public class ResolverTest {
    
    private static final File LOCAL_REPO_DIR = new File("localRepo");
    
    public static void main(String[] args) throws MalformedURLException, DependencyResolutionException {
        downloadLibraries(
            Arrays.asList(
                "https://repo1.maven.org/maven2/",
                "https://repository.apache.org/content/repositories/snapshots/"
            ),
            List.of("commons-io:commons-io:2.12.0-SNAPSHOT")
        );
    }
    
    public static List<URL> downloadLibraries(List<String> repositories, List<String> libraries) throws DependencyResolutionException, MalformedURLException {
        // setup connection
        var locator = MavenRepositorySystemUtils.newServiceLocator();
        locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
        locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
        
        var repoSystem = locator.getService(RepositorySystem.class);
        
        var session = MavenRepositorySystemUtils.newSession();
        session.setChecksumPolicy(RepositoryPolicy.CHECKSUM_POLICY_FAIL);
        session.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_NEVER);
        session.setLocalRepositoryManager(repoSystem.newLocalRepositoryManager(session, new LocalRepository(LOCAL_REPO_DIR)));
        session.setTransferListener(new LoggingTransferListener());
        session.setReadOnly();
        
        List<RemoteRepository> remoteRepos = new ArrayList<>();
        
        var repoIdx = 0;
        for (var repoUrl : repositories) {
            remoteRepos.add(new RemoteRepository.Builder(String.valueOf(repoIdx), "default", repoUrl).build());
            repoIdx++;
        }
        
        remoteRepos = repoSystem.newResolutionRepositories(session, remoteRepos);
        
        // download libraries
        var request = new DependencyRequest(
            new CollectRequest(
                (Dependency) null,
                libraries.stream().map(library ->
                    new Dependency(new DefaultArtifact(library), null)
                ).toList(),
                remoteRepos
            ),
            null
        );
        
        var results = repoSystem.resolveDependencies(session, request).getArtifactResults();
        
        var urls = new ArrayList<URL>();
        for (var result : results) {
            urls.add(result.getArtifact().getFile().toURI().toURL());
        }
        
        return urls;
    }
    
    private static class LoggingTransferListener extends AbstractTransferListener {
        
        @Override
        public void transferInitiated(TransferEvent event) {
            System.out.println("Init transfer " + event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
        }
        
    }
}

依赖配置(Kotlin DSL)

implementation("org.apache.maven:maven-resolver-provider:3.8.6")
implementation("org.apache.maven.resolver:maven-resolver-connector-basic:1.7.3")
implementation("org.apache.maven.resolver:maven-resolver-transport-http:1.8.2")

遇到的问题

  • 每次重启程序调用加载器时,解析器会尝试从未获取过该依赖的远程仓库下载maven-metadata.xml,仅快照依赖存在此现象
  • 即使设置了RepositoryPolicy.UPDATE_POLICY_NEVER,仍会从其他仓库拉取元数据
  • 设置session.setOffline(true)后,尽管依赖已存在于本地仓库(并非从Central仓库下载),仍抛出异常:

    org.eclipse.aether.resolution.DependencyResolutionException: Cannot access central (https://repo.maven.apache.org/maven2) in offline mode and the artifact (path to artifact) has not been downloaded from it before

解决方案

1. 解决快照依赖元数据重复拉取问题

快照依赖的元数据检查逻辑独立于全局会话配置,需为每个远程仓库单独配置快照策略:

for (var repoUrl : repositories) {
    RemoteRepository.Builder builder = new RemoteRepository.Builder(String.valueOf(repoIdx), "default", repoUrl);
    // 显式禁用快照元数据更新检查
    RepositoryPolicy snapshotPolicy = new RepositoryPolicy(true, RepositoryPolicy.UPDATE_POLICY_NEVER, RepositoryPolicy.CHECKSUM_POLICY_FAIL);
    builder.setSnapshotPolicy(snapshotPolicy);
    remoteRepos.add(builder.build());
    repoIdx++;
}

2. 修复离线模式下的Central仓库异常

Maven Resolver会默认加入Central仓库,需显式禁用默认仓库:

// 初始化会话时添加
session.getSystemProperties().setProperty("maven.resolver.skip.default.repositories", "true");

同时调整CollectRequest的创建逻辑,确保仅使用指定的远程仓库:

var collectRequest = new CollectRequest();
collectRequest.setDependencies(libraries.stream().map(library ->
    new Dependency(new DefaultArtifact(library), null)
).toList());
collectRequest.setRepositories(remoteRepos);
// 禁用默认仓库继承
collectRequest.setRequestContext("standalone");
var request = new DependencyRequest(collectRequest, null);

3. 额外优化

若依赖从非Central仓库下载,可确保本地仓库的_remote.repositories文件中标记了对应来源仓库,避免Resolver误判依赖获取来源。

内容的提问来源于stack exchange,提问作者StudioCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 22:15:39