【史上最全的Maven源码讲解(二)】

> ***两个核心功能:***
> - 下载依赖
> - 执行插件目标

```java
private void execute(MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex,
            DependencyContext dependencyContext) throws LifecycleExecutionException {
        List<MavenProject> forkedProjects = executeForkedExecutions(mojoExecution, session, projectIndex);
		// 核心一: 下载依赖
        ensureDependenciesAreResolved(mojoDescriptor, session, dependencyContext); // todo : 核心,解析依赖

        eventCatapult.fire(ExecutionEvent.Type.MojoStarted, session, mojoExecution);

        try {
            try { // 核心二执行目标
                pluginManager.executeMojo(session, mojoExecution); // 执行插件目标
            } catch (MojoFailure | PluginManager | PluginConfiguration | MojoExecution e) {
                throw new LifecycleExecutionException(mojoExecution, session.getCurrentProject(), e);
            }
            eventCatapult.fire(ExecutionEvent.Type.MojoSucceeded, session, mojoExecution); // 发布事件
        } catch (LifecycleExecutionException e) {
            eventCatapult.fire(ExecutionEvent.Type.MojoFailed, session, mojoExecution, e);
            throw e;
        } finally {
            for (MavenProject forkedProject : forkedProjects) {
                forkedProject.setExecutionProject(null);
            }
        }
    }
```

两个核心单独看

依赖下载

  • org.apache.maven.lifecycle.internal.MojoExecutor#ensureDependenciesAreResolved
public void ensureDependenciesAreResolved(MojoDescriptor mojoDescriptor, MavenSession session,
        DependencyContext dependencyContext) throws LifecycleExecutionException {
    MavenProject project = dependencyContext.getProject();
    boolean aggregating = mojoDescriptor.isAggregator(); // 看看是否是聚合工程

    if (dependencyContext.isResolutionRequiredForCurrentProject()) {
        Collection<String> scopesToCollect = dependencyContext.getScopesToCollectForCurrentProject();
        Collection<String> scopesToResolve = dependencyContext.getScopesToResolveForCurrentProject();

        lifeCycleDependencyResolver.resolveProjectDependencies(project, scopesToCollect, scopesToResolve, session,
                aggregating, Collections.<Artifact>emptySet()); // todo 核心

        dependencyContext.synchronizeWithProjectState();
    }

    if (aggregating) { // 聚合工程
        Collection<String> scopesToCollect = toScopes(mojoDescriptor.getDependencyCollectionRequired());
        Collection<String> scopesToResolve = toScopes(mojoDescriptor.getDependencyResolutionRequired());

        if (dependencyContext.isResolutionRequiredForAggregatedProjects(scopesToCollect, scopesToResolve)) {
            for (MavenProject aggregatedProject : session.getProjects()) { // 为什么没有递归? 是因为解析pom反应堆时候已经拉平了树结构了吗?
                if (aggregatedProject != project) {
                    lifeCycleDependencyResolver.resolveProjectDependencies(aggregatedProject, scopesToCollect,
                            scopesToResolve, session, aggregating, Collections.<Artifact>emptySet()); // todo 核心
                }
            }
        }
    }

    ArtifactFilter artifactFilter = getArtifactFilter(mojoDescriptor);
    List<MavenProject> projectsToResolve = LifecycleDependencyResolver.getProjects(session.getCurrentProject(),
            session, mojoDescriptor.isAggregator());
    for (MavenProject projectToResolve : projectsToResolve) {
        projectToResolve.setArtifactFilter(artifactFilter);
    }
}
  • org.apache.maven.lifecycle.internal.LifecycleDependencyResolver#getDependencies

  • org.apache.maven.project.DefaultProjectDependenciesResolver#resolve

  • org.eclipse.aether.internal.impl.DefaultRepositorySystem#collectDependencies

  • org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector#collectDependencies

  • org.apache.maven.repository.internal.DefaultArtifactDescriptorReader#readArtifactDescriptor

  • org.eclipse.aether.internal.impl.DefaultArtifactResolver#resolve

    关键代码:

    private List<ArtifactResult> resolve( RepositorySystemSession session,Collection<? extends ArtifactRequest> requests )throws ArtifactResolutionException{
            List<ArtifactResult> results = new ArrayList<>( requests.size() );
            boolean failures = false;
    
            LocalRepositoryManager lrm = session.getLocalRepositoryManager();
            WorkspaceReader workspace = session.getWorkspaceReader();
    
            List<ResolutionGroup> groups = new ArrayList<>();
    
            for ( ArtifactRequest request : requests ) { // 循环处理坐标请求
                RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
    
                ArtifactResult result = new ArtifactResult( request );
                results.add( result );
    
                Artifact artifact = request.getArtifact();
                List<RemoteRepository> repos = request.getRepositories(); // 获取可用的仓库或镜像: 问题: 这个列表是如何获解析出来的
                artifactResolving( session, trace, artifact );
    
                String localPath = artifact.getProperty( ArtifactProperties.LOCAL_PATH, null );
                if ( localPath != null ) {
                    continue;
                }
    			// 1. 处理版本
                VersionResult versionResult; // 版本结果
                try {
                    VersionRequest versionRequest=new VersionRequest( artifact, repos, request.getRequestContext());
                    versionRequest.setTrace( trace );
                    versionResult = versionResolver.resolveVersion( session, versionRequest );
                } catch ( VersionResolutionException e ) {
                    continue;
                }
    
                artifact = artifact.setVersion( versionResult.getVersion()); // 设置版本
    
                if ( versionResult.getRepository() != null ) {
                    if ( versionResult.getRepository() instanceof RemoteRepository ) {
                        repos = Collections.singletonList( (RemoteRepository) versionResult.getRepository() );
                    } else {
                        repos = Collections.emptyList();
                    }
                }
    
                if ( workspace != null ) {
                    File file = workspace.findArtifact( artifact ); // 工作空间查找
                    if ( file != null ) { // 找到提前结束
                        artifact = artifact.setFile( file );
                        result.setArtifact( artifact );
                        result.setRepository( workspace.getRepository() );
                        artifactResolved( session, trace, artifact, result.getRepository(), null );
                        continue;
                    }
                }
    
                LocalArtifactResult local =lrm.find( session, new LocalArtifactRequest( artifact, repos, request.getRequestContext() ) ); // 本地查找
                if ( isLocallyInstalled( local, versionResult ) ){
                } else if ( local.getFile() != null ) {
                    LOGGER.debug( "Verifying availability of {} from {}", local.getFile(), repos );
                }
    
                // 核心: 远程查找
                LOGGER.debug( "Resolving artifact {} from {}", artifact, repos );
                AtomicBoolean resolved = new AtomicBoolean( false );
                Iterator<ResolutionGroup> groupIt = groups.iterator(); // 这个group初始是没有值得,是一个缓存的作用
                for ( RemoteRepository repo : repos ) {
                    if ( !repo.getPolicy( artifact.isSnapshot() ).isEnabled() ) {
                        continue;
                    }
                    try {
                        Utils.checkOffline( session, offlineController, repo );
                    } catch ( RepositoryOfflineException e ) {
                        result.addException( exception );
                        continue;
                    }
                    ResolutionGroup group = null;
                    while ( groupIt.hasNext() ) { // 第一次进来不进入这里
                        ResolutionGroup t = groupIt.next();
                        if ( t.matches( repo ) ) {
                            group = t;
                            break;
                        }
                    }
                    if ( group == null ) { // 第一次执行这里
                        group = new ResolutionGroup( repo ); // 设置仓库地址
                        groups.add( group );
                        groupIt = Collections.<ResolutionGroup>emptyList().iterator();
                    } // 加入条目
                    group.items.add( new ResolutionItem( trace, artifact, resolved, result, local, repo ) );
                }
            }
    
            for ( ResolutionGroup group : groups ){
                performDownloads( session, group ); // 执行下载的
            }
    
            for ( ArtifactResult result : results ) {
                ArtifactRequest request = result.getRequest();
    
                Artifact artifact = result.getArtifact();
                if ( artifact == null || artifact.getFile() == null ) {
                    failures = true;
                    if ( result.getExceptions().isEmpty() ) {
                        Exception exception = new ArtifactNotFoundException( request.getArtifact(), null );
                        result.addException( exception );
                    }
                    RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
                    artifactResolved( session, trace, request.getArtifact(), null, result.getExceptions() );
                }
            }
    
            if ( failures ) {
                throw new ArtifactResolutionException( results );
            }
    
            return results;
        }
    

    这里有个ResolutionGroup类

    static class ResolutionGroup
    {
    
        final RemoteRepository repository; // 远程仓库
    
        final List<ResolutionItem> items = new ArrayList<>();
    
        ResolutionGroup( RemoteRepository repository ){
            this.repository = repository;
        }
    
        boolean matches( RemoteRepository repo )
        {
            return repository.getUrl().equals( repo.getUrl() )
                && repository.getContentType().equals( repo.getContentType() )
                && repository.isRepositoryManager() == repo.isRepositoryManager();
        }
    
    }
    
  • org.eclipse.aether.internal.impl.DefaultArtifactResolver#gatherDownloads

    一个条目对应一个远程仓库的选择

    private List<ArtifactDownload> gatherDownloads( RepositorySystemSession session, ResolutionGroup group )
    {
        LocalRepositoryManager lrm = session.getLocalRepositoryManager();
        List<ArtifactDownload> downloads = new ArrayList<>();
    
        for ( ResolutionItem item : group.items )    {
            Artifact artifact = item.artifact;
    
            if ( item.resolved.get() ) { // return value != 0; 这是一个开关, 具体作用暂时不知道
                // resolved in previous resolution group
                continue;
            }
    
            ArtifactDownload download = new ArtifactDownload();
            download.setArtifact( artifact );
            download.setRequestContext( item.request.getRequestContext() );
            download.setListener( SafeTransferListener.wrap( session ) );
            download.setTrace( item.trace );
            if ( item.local.getFile() != null ) {
                download.setFile( item.local.getFile() );
                download.setExistenceCheck( true );
            } else {
                String path =
                    lrm.getPathForRemoteArtifact( artifact, group.repository, item.request.getRequestContext() );
                download.setFile( new File( lrm.getRepository().getBasedir(), path ) );
            }
    
            boolean snapshot = artifact.isSnapshot();
            RepositoryPolicy policy =
                remoteRepositoryManager.getPolicy( session, group.repository, !snapshot, snapshot );
    
            int errorPolicy = Utils.getPolicy( session, artifact, group.repository );
            if ( ( errorPolicy & ResolutionErrorPolicy.CACHE_ALL ) != 0 ) {
                UpdateCheck<Artifact, ArtifactTransferException> check = new UpdateCheck<>();
                check.setItem( artifact );
                check.setFile( download.getFile() );
                check.setFileValid( false );
                check.setRepository( group.repository );
                check.setPolicy( policy.getUpdatePolicy() );
                item.updateCheck = check;
                updateCheckManager.checkArtifact( session, check );
                if ( !check.isRequired() ) {
                    item.result.addException( check.getException() );
                    continue;
                }
            }
    
            download.setChecksumPolicy( policy.getChecksumPolicy() );
            download.setRepositories( item.repository.getMirroredRepositories() );
            downloads.add( download );
            item.download = download;
        }
    
        return downloads; // 返回下载的依赖
    }
    

插件执行

执行方法org.apache.maven.plugin.DefaultBuildPluginManager#executeMojo,调用Mojo(一个goal对应一个Mojo)能力,执行org.apache.maven.plugin.MavenPluginManager#getConfiguredMojo获得Mojo实例执行org.apache.maven.plugin.Mojo#execute执行扩展插件的实现,至此,构建脱离公共流程,进入插件构建运行阶段

org.apache.maven.plugin.DefaultBuildPluginManager#executeMojo

public void executeMojo(MavenSession session, MojoExecution mojoExecution)
        throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException {
    MavenProject project = session.getCurrentProject();

    MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();

    Mojo mojo = null;

    ClassRealm pluginRealm;
    try {
        pluginRealm = getPluginRealm(session, mojoDescriptor.getPluginDescriptor());
    } catch (PluginResolutionException e) {
        throw new PluginExecutionException(mojoExecution, project, e);
    }

    ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
    Thread.currentThread().setContextClassLoader(pluginRealm);

    MavenSession oldSession = legacySupport.getSession();

    scope.enter();

    try {
        scope.seed(MavenProject.class, project);
        scope.seed(MojoExecution.class, mojoExecution);

        mojo = mavenPluginManager.getConfiguredMojo(Mojo.class, session, mojoExecution);

        legacySupport.setSession(session);
        try {
            MojoExecutionEvent mojoExecutionEvent = new MojoExecutionEvent(session, project, mojoExecution, mojo);

            mojoExecutionListener.beforeMojoExecution(mojoExecutionEvent);

            mojo.execute(); // 执行不同的mojo, 例如 CleanMojo

            mojoExecutionListener.afterMojoExecutionSuccess(mojoExecutionEvent);
        } catch {
            throw new PluginExecutionException(mojoExecution, project, e);
        }
    } catch (PluginContainerException e) {
    } finally {
    }
}

进入执行逻辑

mojo.execute(); // 不同mojo执行逻辑不同
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岁月玲珑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值