在配置Maven的setting.xml文件時,裏面會有mirror元素和repository元素,前者時鏡像配置,後者是庫的配置。
什麼是鏡像,簡明扼要的說,如果Y庫中的所有東西,都能從X庫中得到,那麼X就是Y的鏡像。
如圖:
配置了mirror的話,就會從B中獲取資源,而如果沒有配置mirror,用戶只能從A中獲取獲取資源,而如果用戶此時對A的網絡情況不太好,那麼下載資源的速度會很慢,影響開發效率。這個時候,mirror更像是一個攔截器的存在,把對A的請求全部攔截髮往B。
我們可以從Maven的源代碼中窺探一下這兩者的關係:
@Deprecated
public ArtifactRepository getMirrorRepository(ArtifactRepository repository) {
Mirror mirror = mirrorSelector.getMirror(repository, legacySupport.getSession().getSettings().getMirrors());
if (mirror != null) {
String id = mirror.getId();
if (id == null) {
// TODO: this should be illegal in settings.xml
id = repository.getId();
}
log.debug("Using mirror: " + mirror.getUrl() + " (id: " + id + ")");
repository = artifactRepositoryFactory.createArtifactRepository(id, mirror.getUrl(),
repository.getLayout(), repository.getSnapshots(),
repository.getReleases());
}
return repository;
}
public 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;
}
從上面這兩段代碼中可以看出,
1.它會根據repository去尋找對應的mirror,如果沒有找到,則直接返回使用這個repository的配置,如果找到了,則通過createArtifactRepository方法使用這個mirror中的url新構造一個repository,來請求資源。
在兩個for循環中,分別是對mirror和repository的匹配,
第一種情況是針對單個id的匹配,mirror中mirrorOf的值等於repository的id,並且layout匹配(通常情況下layout是默認的,不會進行特殊配置),mirrorOf這個元素的意思很明顯,字面意思就是指誰的mirror,也就是對誰的鏡像,當mirrorOf的值和repository的id匹配時,那麼就使用這個mirror。
第二種情況是針對範圍的匹配,先看看matchPattern函數的內容:
static boolean matchPattern(ArtifactRepository originalRepository, String pattern) {
boolean result = false;
String originalId = originalRepository.getId();
//首先匹配*號,如果mirrorOf是*號,就用當前的鏡像
//或者如果當前的mirrorOf和repository的id一樣也返回(這在前面的for循環處理過,所以這種情況基本不會出現)
if (WILDCARD.equals(pattern) || pattern.equals(originalId)) {
result = true;
} else {
//其次mirrorOf支持多個用逗號隔開,這裏先拆分,逐個循環
String[] repos = pattern.split(",");
for (String repo : repos) {
//repo支持!(感嘆號)來屏蔽一個repository的Id,這裏先判斷如果是排除的,就return false
if (repo.length() > 1 && repo.startsWith("!")) {
if (repo.substring(1).equals(originalId)) {
// explicitly exclude. Set result and stop processing.
result = false;
break;
}
}
//逗號隔開中的一個值和repository的id一樣就返回true
else if (repo.equals(originalId)) {
result = true;
break;
}
//檢查外部匹配external:*
else if (EXTERNAL_WILDCARD.equals(repo) && isExternalRepo(originalRepository)) {
result = true;
}
//最後檢查*匹配
else if (WILDCARD.equals(repo)) {
result = true;
}
}
}
return result;
}
系統中定義了一個全匹配*和外部全匹配external:*private static final String WILDCARD = "*";
private static final String EXTERNAL_WILDCARD = "external:*";
從這段代碼可以得到如下規則:2.如果mirrorOf是*(星號通配符)或者和repository的id一樣就使用該mirror
3.對於mirrorOf多個或一個的情況,從第一個開始判斷
3.1如果是一個排除選項,就不使用這個mirror
3.2如果正好和repository的id一樣就使用這個mirror
3.3判斷是否外部匹配(這裏還有一個isExternalRepo方法,判斷是否爲本地庫),如果不是本地倉庫,就用該mirror
3.4判斷是否爲*(星號),如果是,就用該鏡像。
mirror的尋找中,首先會從settings配置的第一個mirror開始循環,其次從mirrorOf逗號隔開的內容循環。