如何配置Maven Artifact Resolver实现传递依赖列表输出?
你的代码缺少LocalRepositoryManager初始化、RepositorySystem正确实例化以及远程仓库配置等关键环节,以下是基于你使用的依赖版本(Apache Maven Model v4.0.0-alpha-2、Maven Artifact Resolver v1.8.2)的完整可行方案:
1. 确保依赖配置正确
首先在项目的pom.xml中补充必要依赖(缺少的连接器和传输组件是远程依赖拉取的核心):
<dependencies> <!-- Maven Model --> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-model</artifactId> <version>4.0.0-alpha-2</version> </dependency> <!-- Maven Artifact Resolver核心 --> <dependency> <groupId>org.apache.maven.resolver</groupId> <artifactId>maven-resolver-api</artifactId> <version>1.8.2</version> </dependency> <dependency> <groupId>org.apache.maven.resolver</groupId> <artifactId>maven-resolver-impl</artifactId> <version>1.8.2</version> </dependency> <!-- 依赖拉取的连接器与传输组件 --> <dependency> <groupId>org.apache.maven.resolver</groupId> <artifactId>maven-resolver-connector-basic</artifactId> <version>1.8.2</version> </dependency> <dependency> <groupId>org.apache.maven.resolver</groupId> <artifactId>maven-resolver-transport-file</artifactId> <version>1.8.2</version> </dependency> <dependency> <groupId>org.apache.maven.resolver</groupId> <artifactId>maven-resolver-transport-http</artifactId> <version>1.8.2</version> </dependency> <!-- 用于完整解析POM(处理父POM、依赖管理等) --> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-model-builder</artifactId> <version>4.0.0-alpha-2</version> </dependency> </dependencies>
2. 完整的依赖解析代码
替换你原有的main方法,以下是包含所有必要配置的实现:
import org.apache.maven.model.Dependency; import org.apache.maven.model.Model; import org.apache.maven.model.building.DefaultModelBuilder; import org.apache.maven.model.building.DefaultModelBuilderFactory; import org.apache.maven.model.building.DefaultModelBuildingRequest; import org.apache.maven.model.building.ModelBuildingResult; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.collection.CollectResult; import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.impl.DefaultServiceLocator; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.DependencyRequest; import org.eclipse.aether.resolution.DependencyResult; import org.eclipse.aether.util.repository.DefaultMirrorSelector; import org.eclipse.aether.util.repository.DefaultProxySelector; import java.io.File; import java.io.FileReader; import java.util.ArrayList; import java.util.List; public class MavenDependencyResolver { private static RepositorySystem newRepositorySystem() { // 必须通过ServiceLocator获取RepositorySystem实例,不能直接new DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); locator.addService(RepositorySystem.class, org.eclipse.aether.internal.impl.DefaultRepositorySystem.class); return locator.getService(RepositorySystem.class); } private static RepositorySystemSession newRepositorySystemSession(RepositorySystem system) { RepositorySystemSession session = MavenRepositorySystemUtils.newSession(); // 配置本地仓库:指向用户目录下的.m2/repository String localRepoPath = System.getProperty("user.home") + File.separator + ".m2" + File.separator + "repository"; LocalRepository localRepo = new LocalRepository(localRepoPath); session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo)); // 配置镜像与代理(可根据公司Maven settings.xml扩展) session.setMirrorSelector(new DefaultMirrorSelector()); session.setProxySelector(new DefaultProxySelector()); return session; } private static List<RemoteRepository> newRepositories(RepositorySystem system, RepositorySystemSession session) { List<RemoteRepository> repos = new ArrayList<>(); // 添加Maven中央仓库,也可从settings.xml读取内部镜像 repos.add(new RemoteRepository.Builder("central", "default", "https://repo1.maven.org/maven2/").build()); return repos; } // 将Maven Model的Dependency转换为Aether的Artifact private static Artifact toArtifact(Dependency dependency) { return new DefaultArtifact( dependency.getGroupId(), dependency.getArtifactId(), dependency.getClassifier(), dependency.getType(), dependency.getVersion() ); } public static void main(String[] args) throws Exception { // 1. 读取并构建完整的POM模型(处理父POM、依赖管理等逻辑) File pomFile = new File("C:\\Users\\lc70844\\eclipse-workspace\\test\\pom.xml"); MavenXpp3Reader reader = new MavenXpp3Reader(); Model rawModel = reader.read(new FileReader(pomFile)); DefaultModelBuilder modelBuilder = new DefaultModelBuilderFactory().newInstance(); DefaultModelBuildingRequest buildingRequest = new DefaultModelBuildingRequest(); buildingRequest.setModel(rawModel); buildingRequest.setPomFile(pomFile); ModelBuildingResult buildingResult = modelBuilder.build(buildingRequest); Model model = buildingResult.getEffectiveModel(); // 2. 初始化RepositorySystem和Session RepositorySystem system = newRepositorySystem(); RepositorySystemSession session = newRepositorySystemSession(system); List<RemoteRepository> remoteRepos = newRepositories(system, session); // 3. 解析每个依赖(含传递依赖) for (Dependency dependency : model.getDependencies()) { System.out.println("=== 解析依赖:" + dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion() + " ==="); // 创建收集请求获取完整依赖树 CollectRequest collectRequest = new CollectRequest(); collectRequest.setRoot(new org.eclipse.aether.graph.Dependency(toArtifact(dependency), dependency.getScope())); collectRequest.setRepositories(remoteRepos); CollectResult collectResult = system.collectDependencies(session, collectRequest); // 解析收集到的依赖 DependencyRequest dependencyRequest = new DependencyRequest(collectResult.getRoot(), null); DependencyResult dependencyResult = system.resolveDependencies(session, dependencyRequest); // 打印解析结果 dependencyResult.getArtifactResults().stream() .map(result -> result.getArtifact()) .map(artifact -> artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion()) .forEach(System.out::println); } } }
关键修正说明
- RepositorySystem实例化:必须通过
DefaultServiceLocator加载实现类,不能直接new DefaultRepositorySystem,这是Aether的规范要求。 - LocalRepositoryManager配置:通过
System.getProperty("user.home")动态获取用户目录,自动指向.m2/repository,避免硬编码路径。 - 完整POM解析:使用
maven-model-builder构建有效模型,确保处理父POM继承、dependencyManagement覆盖等逻辑,避免原始POM信息不全的问题。 - 依赖流程规范:先通过
collectDependencies获取完整依赖树,再通过resolveDependencies解析实际文件,这是Aether的标准流程。
优化方案:一次性解析全项目依赖树
如果需要获取整个项目的完整依赖树(含传递依赖),可以直接以项目自身为根节点,效率更高:
// 替换main方法中的循环部分 DefaultArtifact projectArtifact = new DefaultArtifact( model.getGroupId(), model.getArtifactId(), model.getPackaging(), model.getVersion() ); CollectRequest collectRequest = new CollectRequest(); collectRequest.setRoot(new org.eclipse.aether.graph.Dependency(projectArtifact, "compile")); collectRequest.setRepositories(remoteRepos); CollectResult collectResult = system.collectDependencies(session, collectRequest); DependencyRequest dependencyRequest = new DependencyRequest(collectResult.getRoot(), null); DependencyResult dependencyResult = system.resolveDependencies(session, dependencyRequest); // 打印树形结构的依赖 printDependencyTree(dependencyResult.getRoot(), 0);
// 添加打印依赖树的工具方法
private static void printDependencyTree(DependencyNode node, int depth) {
StringBuilder indent = new StringBuilder();
for (int i = 0; i < depth; i++) {
indent.append(" ");
}
Artifact artifact = node.getArtifact();
System.out.println(indent + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion());
for (DependencyNode child : node.getChildren()) {
printDependencyTree(child, depth + 1);
}
}
内容的提问来源于stack exchange,提问作者Cardinal System

