【Maven】setting.xml中mirror和repository的關係


在配置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逗號隔開的內容循環。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章