一、概述
maven的settings.xml文件里面有proxy、server、repository、mirror的配置,在配置仓库地址的时候容易混淆
- proxy是服务器不能直接访问外网时需要设置的代理服务,不常用
- server是服务器要打包上传到私服时,设置私服的鉴权信息
- repository是服务器下载jar包的仓库地址
- mirror是用于替代仓库地址的镜像地址
二、源码解析执行流程
2.1》初始化远程仓库
在maven的远程仓库初始化时会执行newRepositorySession方法,会创建mirror、proxy、authentication和其它系统环境信息:
this.mavenRepositorySystem.injectMirror(request.getRemoteRepositories(), request.getMirrors());
this.mavenRepositorySystem.injectProxy(session, request.getRemoteRepositories());
this.mavenRepositorySystem.injectAuthentication(session, request.getRemoteRepositories());
2.2》遍历注入镜像
在injectMirror方法中:
public void injectMirror(List<ArtifactRepository> repositories, List<Mirror> mirrors){if ((repositories != null) && (mirrors != null)) {for (ArtifactRepository repository : repositories){Mirror mirror = getMirror(repository, mirrors);injectMirror(repository, mirror);}}}
遍历repositories,获得mirror然后注入mirror
注:这里不用担心repositories没数据,因为在之前的初始化repositories方法中会判断没有配置"central"中央仓库的时候加入默认仓库
private void injectDefaultRepositories(MavenExecutionRequest request)throws MavenExecutionRequestPopulationException{Set<String> definedRepositories = this.repositorySystem.getRepoIds(request.getRemoteRepositories());if (!definedRepositories.contains("central")) {try{request.addRemoteRepository(this.repositorySystem.createDefaultRemoteRepository(request));}catch (Exception e){throw new MavenExecutionRequestPopulationException("Cannot create default remote repository.", e);}}}
public ArtifactRepository createDefaultRemoteRepository(MavenExecutionRequest request)throws Exception{return createRepository("https://repo.maven.apache.org/maven2", "central", true, "daily", false, "daily", "warn");}
2.3》匹配镜像
在getMirror方法中:
public static Mirror getMirror(ArtifactRepository repository, List<Mirror> mirrors){String repoId = repository.getId();if ((repoId != null) && (mirrors != null)){for (Mirror mirror : mirrors) {if ((repoId.equals(mirror.getMirrorOf())) && (matchesLayout(repository, mirror))) {return mirror;}}for (Mirror mirror : mirrors) {if ((matchPattern(repository, mirror.getMirrorOf())) && (matchesLayout(repository, mirror))) {return mirror;}}}return null;}
忽略不常用的layout配置,第一个循环优先寻找mirrorOf与repositoryId完全相同的mirror
第二个循环通过规则来匹配mirror,matchPattern的方法:
static boolean matchPattern(ArtifactRepository originalRepository, String pattern){boolean result = false;String originalId = originalRepository.getId();if (("*".equals(pattern)) || (pattern.equals(originalId))){result = true;}else{String[] repos = pattern.split(",");for (String repo : repos) {if ((repo.length() > 1) && (repo.startsWith("!"))){if (repo.substring(1).equals(originalId)){result = false;break;}}else{if (repo.equals(originalId)){result = true;break;}if (("external:*".equals(repo)) && (isExternalRepo(originalRepository))) {result = true;} else if ("*".equals(repo)) {result = true;}}}}return result;}
如果是mirrorOf是*号就匹配,如果不是就遍历可能是逗号分隔的mirrorOf值,同时看是否是!号排除的
在找到mirror后会执行injectMirror方法,把匹配的mirror注入到repository里面:
private void injectMirror(ArtifactRepository repository, Mirror mirror){if (mirror != null){ArtifactRepository original = createArtifactRepository(repository.getId(), repository.getUrl(), repository.getLayout(), repository.getSnapshots(), repository.getReleases());repository.setMirroredRepositories(Collections.singletonList(original)); repository.setId(mirror.getId());repository.setUrl(mirror.getUrl());if (StringUtils.isNotEmpty(mirror.getLayout())) {repository.setLayout(getLayout(mirror.getLayout()));}}}
三、结论
1、在mirrorOf与repositoryId相同的时候优先是使用mirror的地址
2、mirrorOf等于*的时候覆盖所有repository配置
3、存在多个mirror配置的时候mirrorOf等于*放到最后
4、只配置mirrorOf为central的时候可以不用配置repository
四 、实践
4.1》maven settings.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"><pluginGroups></pluginGroups><proxies></proxies><servers><server><id>nexus-releases</id><username>admin</username><password>admin123</password></server><server><id>nexus-snapshots</id><username>admin</username><password>admin123</password></server></servers><mirrors> <mirror> <id>nexus-releases</id> <mirrorOf>nexus-releases</mirrorOf> <url>http://localhost:8081/nexus/content/groups/public</url> </mirror><mirror> <id>nexus-snapshots</id> <mirrorOf>nexus-snapshots</mirrorOf> <url>http://localhost:8081/nexus/content/groups/public-snapshots</url> </mirror> </mirrors> <profiles><profile><id>nexus</id><repositories><repository><id>nexus-releases</id><url>http://nexus-releases</url><releases><enabled>true</enabled></releases><snapshots><enabled>true</enabled></snapshots></repository><repository><id>nexus-snapshots</id><url>http://nexus-snapshots</url><releases><enabled>true</enabled></releases><snapshots><enabled>true</enabled></snapshots></repository></repositories><pluginRepositories><pluginRepository><id>nexus-releases</id><url>http://nexus-releases</url><releases><enabled>true</enabled></releases><snapshots><enabled>true</enabled></snapshots></pluginRepository><pluginRepository><id>nexus-snapshots</id><url>http://nexus-snapshots</url><releases><enabled>true</enabled></releases><snapshots><enabled>true</enabled></snapshots></pluginRepository></pluginRepositories></profile></profiles><activeProfiles><activeProfile>nexus</activeProfile></activeProfiles></settings>
4.2》项目所在pom.xml配置
<distributionManagement><!-- 两个ID必须与 setting.xml中的<server><id>nexus-releases</id></server>保持一致--><repository><id>nexus-releases</id><name>Nexus Release Repository</name><url>http://localhost:8081/nexus/content/repositories/releases</url></repository><snapshotRepository><id>nexus-snapshots</id><name>Nexus Snapshot Repository</name><url>http://localhost:8081/nexus/content/repositories/snapshots</url></snapshotRepository></distributionManagement>