drools动态规则之Maven解析

drools实现动态规则的两种形式:

1.将规则文件存储到数据库中,按照一定的规则去加载更新规则文件。

2.通过动态加载 jar(Maven) 的方式来实现资源加载和动态更新(官方推荐)

我们这里说的就是第二种形式,这里源码说明的drools版本为:7.73.0.Final。

动态加载规则,不得不提到一个类 KieScanner

使用方法:

KieServices kieServices = KieServices.Factory.get();
ReleaseIdImpl releaseId = new ReleaseIdImpl("com.myspace","stream_test3","1.0.0");
kieContainer = kieServices.newKieContainer(releaseId);
KieScanner kieScanner = kieServices.newKieScanner(kieContainer);
// 现在开始扫描
kieScanner.scanNow();
KieSession kieSession = kieContainer.newKieSession();

仅仅如此使用KieScanner是远远不够的,还需要添加依赖:

     
         org.kie
         kie-ci
         7.73.0.Final
     

既然说到了跟maven有关,那么kie-ci又是如何获取maven的本地及远程仓库呢,那我们就看看kie-ci的pom.xml文件中有什么吧:

 
      org.apache.maven
      maven-core
    
    
      org.apache.maven
      maven-model
    
    
      org.apache.maven
      maven-model-builder
    
    
      org.apache.maven
      maven-settings
    
    
      org.apache.maven
      maven-settings-builder
    
    
      org.apache.maven
      maven-compat
    
    
      org.apache.maven
      maven-aether-provider
    
    
      org.apache.maven.wagon
      wagon-provider-api
      
        
          org.codehaus.plexus
          plexus-utils
        
      
    

上面的依赖是kie-ci依赖的一部分,但是可以看出,kie-ci是依赖了maven的一些类库,以此类库为基础,实现动态加载jar。

以下是代码部分:

KieServicesImpl类
 public KieContainer newKieContainer(String containerId, ReleaseId releaseId, ClassLoader classLoader) {
// 从仓库获取kieModule,我们接着看getRepository()方法,可以看到此处的仓库跟maven没啥关系,是kieModule的仓库,直接看getKieModule()方法
        InternalKieModule kieModule = (InternalKieModule) getRepository().getKieModule(releaseId);
        if (kieModule == null) {
            throw new RuntimeException("Cannot find KieModule: " + releaseId);
        }
        if (classLoader == null) {
            classLoader = kieModule.getModuleClassLoader();
        }
        KieProject kProject = new KieModuleKieProject( kieModule, classLoader );
        if (classLoader != kProject.getClassLoader()) {
            // if the new kproject has a different classloader than the original one it has to be initialized
            kProject.init();
        }

    	if (containerId == null) {
    	    KieContainerImpl newContainer = new KieContainerImpl( UUID.randomUUID().toString(), kProject, getRepository(), releaseId );
    		return newContainer;
    	}
    	if ( kContainers.get(containerId) == null ) {
            KieContainerImpl newContainer = new KieContainerImpl( containerId, kProject, getRepository(), releaseId );
            KieContainer check = kContainers.putIfAbsent(containerId, newContainer);
            if (check == null) {
            	return newContainer;
            } else {
            	newContainer.dispose();
            	throw new IllegalStateException("There's already another KieContainer created with the id "+containerId);
            }
        } else {
            throw new IllegalStateException("There's already another KieContainer created with the id "+containerId);
        }
    }

KieRepositoryImpl类
 public KieModule getKieModule(ReleaseId releaseId, PomModel pomModel) {
        //从kieModuleRepo加载
        KieModule kieModule = kieModuleRepo.load( KieScannerHolder.kieScanner, releaseId );
        if (kieModule == null) {
            log.debug("KieModule Lookup. ReleaseId {} was not in cache, checking classpath",
                      releaseId.toExternalForm());
            //如果加载不到从ClassPath加载
            kieModule = checkClasspathForKieModule(releaseId);
        }

        if (kieModule == null) {
            log.debug("KieModule Lookup. ReleaseId {} was not in cache, checking maven repository",
                      releaseId.toExternalForm());
            //都加载不到则从Maven仓库加载,这正是我们要找的
            kieModule = loadKieModuleFromMavenRepo(releaseId, pomModel);
        }

        return kieModule;
    }

从上面的代码可以看出,加载KieModule的过程是分阶段的,都找不到了,再从Maven仓库加载。

KieRepositoryScannerImpl类
   public synchronized KieModule loadArtifact(ReleaseId releaseId, PomModel pomModel) {
// 这里先创建了一个ArtifactResolver类 , 我们重点看 getArtifactResolver()方法
ArtifactResolver resolver = pomModel != null ?
                                    ArtifactResolver.getResolverFor(pomModel) :
                                    getArtifactResolver();
        // 当得到ArtifactResolver实例后,我们在看该方法
        return loadArtifact( releaseId, resolver );
    }

DefaultArtifactResolver类
    DefaultArtifactResolver() {
        // 这一步是解析pom.xml文件,当我们打开EmbeddedPomParser的定义时,发现其中只有一个成员变量为MavenProject(这个变量是maven类中的类),同时需要注意EmbeddedPomParser还实现了获取依赖的方法,也跟MavenProject类有关。
        this.pomParser = new EmbeddedPomParser();
        // 获取maven远程仓库的方法
        this.mavenRepository = MavenRepository.getMavenRepository();
    }

那么我们看看MavenProject类是如何初始化的吧。

MavenProjectLoader类
public static MavenProject parseMavenPom(File pomFile, boolean offline) {
        boolean hasPom = pomFile.exists();
        //重点,下面会贴代码
        MavenRequest mavenRequest = createMavenRequest(offline);
        if (hasPom) {
            mavenRequest.setPom(pomFile.getAbsolutePath());
        }
        MavenEmbedder mavenEmbedder = null;
        try {
            mavenEmbedder = new MavenEmbedder(mavenRequest);
            return hasPom ?
                    mavenEmbedder.readProject(pomFile) :
                    mavenEmbedder.readProject(new ByteArrayInputStream(DUMMY_POM.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (mavenEmbedder != null) {
                mavenEmbedder.dispose();
            }
        }
    }
    public static MavenRequest createMavenRequest(boolean _offline) {
        MavenRequest mavenRequest = new MavenRequest();
// 这里设置了本地maven仓库的地址,我们可以看看这个本地地址是如何确定的,重点在MavenSettings.getSettings(),而且该方法返回Settings类,该类是maven类库中的类
        mavenRequest.setLocalRepositoryPath(MavenSettings.getSettings().getLocalRepository());
// 这里设定了一些用户的个性配置(主要跟kie相关的),MavenSettings.getUserSettingsSource() 返回的是SettingsSource的子类,不过在当前版本SettingsSource接口已过时
 mavenRequest.setUserSettingsSource(MavenSettings.getUserSettingsSource());

        final boolean offline = IS_FORCE_OFFLINE || _offline;

        // BZ-1007894: If dependency is not resolvable and maven project builder does not complain about it,
        // then a java.lang.NullPointerException is thrown to the client.
        // So, the user will se an exception message "null", not descriptive about the real error.
        mavenRequest.setResolveDependencies(!offline);
//设置离线是否是模式
        mavenRequest.setOffline(offline);
        return mavenRequest;
    }
MavenSettings类
    private static Settings initSettings(SettingsSource userSettingsSource) {
        SettingsBuilder settingsBuilder = new DefaultSettingsBuilderFactory().newInstance();
        DefaultSettingsBuildingRequest request = new DefaultSettingsBuildingRequest();

        if (userSettingsSource != null) {
            request.setUserSettingsSource( userSettingsSource );
        }

        String mavenHome = System.getenv( "M2_HOME" );
        if (mavenHome != null) {
            File globalSettingsFile = new File( mavenHome + "/conf/settings.xml" );
            if (globalSettingsFile.exists()) {
                request.setGlobalSettingsFile( globalSettingsFile );
            }
        } else {
            log.warn("Environment variable M2_HOME is not set");
        }

        request.setSystemProperties( System.getProperties() );

        Settings settings = null;
        try {
            settings = settingsBuilder.build( request ).getEffectiveSettings();
        } catch ( SettingsBuildingException e ) {
            throw new RuntimeException(e);
        }

        if (settings.getLocalRepository() == null) {
            String userHome = System.getProperty( "user.home" );
            if (userHome != null) {
                settings.setLocalRepository( userHome + "/.m2/repository" );
            } else {
                log.error("Cannot find maven local repository");
            }
        }

        return settings;
    }

上图代码初始化了Setting类(maven类库中的类),是如何初始化的,其实就是读取了maven的环境变量或者默认配置,从而找到了setting.xml,此时已经知道了maven的设置,那么一切就变得清晰起来,此时回来填坑。有了本地仓库就一定有远程仓库。远程仓库的设置已经标识在从当前向上第四份代码处,那我们就看看远程仓库是如何设置的。

MavenRepository类
    public static synchronized MavenRepository getMavenRepository() {
        if ( defaultMavenRepository == null ) {
            // 查看了这个方法,里面又出现了我们熟悉的Settings类,即Maven的setting.xml的信息
            Aether defaultAether = Aether.getAether();
            // 重点看这个
            defaultMavenRepository = new MavenRepository( defaultAether );
        }
        return defaultMavenRepository;
    }

    private Collection initRemoteRepositoriesForRequest() {
        final MavenRepositoryConfiguration repositoryUtils = getMavenRepositoryConfiguration();
        Collection remoteRepos = new HashSet();
 
        remoteRepos.addAll( repositoryUtils.getRemoteRepositoriesForRequest() );
        //aether对象,即上述包含了Settings类的对象
        for ( RemoteRepository repo : aether.getRepositories() ) {
            //resolveMirroredRepo方法是做了一些远程仓库的初始化
            remoteRepos.add( repositoryUtils.resolveMirroredRepo( repo ) );
        }
        //终于返回了远程仓库的集合
        return remoteRepos;
    }
MavenRepositoryConfiguration类
// maven的相关知识,不再赘述   
public RemoteRepository resolveMirroredRepo( RemoteRepository repo ) {
        for ( Mirror mirror : settings.getMirrors() ) {
            if ( isMirror( repo, mirror.getMirrorOf() ) ) {
                return toRemoteRepositoryBuilder( settings,
                                                  mirror.getId(),
                                                  mirror.getLayout(),
                                                  mirror.getUrl() ).build();
            }
        }
        return repo;
    }

上面终于讲完了maven仓库的相关配置,接下来终于可以开始获取需要的依赖了。

KieRepositoryScannerImpl类
   private KieModule loadArtifact( ReleaseId releaseId, ArtifactResolver resolver ) {
        //resolver对象中包含了maven的配置信息,但是该方法还不是获取依赖,二是配置依赖的信息
Artifact artifact = resolver.resolveArtifact(releaseId);
        // buildArtifact() /loadPomArtifact() 后面再看
        return artifact != null ? buildArtifact(artifact, resolver) : loadPomArtifact(releaseId);
    }
MavenRepository类
   public Artifact resolveArtifact( AFReleaseId releaseId ) {
        String artifactName = releaseId.toString();
        // 判断依赖版本是否是范围设置,这里的判断也很简单,就是判断version中是否包含中括号和括号
        if ( DependencyDescriptor.isRangedVersion( releaseId.getVersion() ) ) {
            Version v = resolveVersion( artifactName );
            if ( v == null ) {
                return null;
            }
            artifactName = releaseId.getGroupId() + ":" + releaseId.getArtifactId() + ":" + v;
        }
        //获取依赖在这一步
        return resolveArtifact( artifactName );
    }

 

   public Artifact resolveArtifact( String artifactName,
                                     boolean logUnresolvedArtifact ) {
        Artifact artifact = new DefaultArtifact( artifactName );
        ArtifactRequest artifactRequest = new ArtifactRequest();
        artifactRequest.setArtifact( artifact );
        for ( RemoteRepository repo : remoteRepositoriesForRequest ) {
            artifactRequest.addRepository( repo );
        }

        RepositorySystemSession session = aether.getSession();
        Object sessionChecks = null;
        boolean isSnapshot = artifactName.endsWith( "-SNAPSHOT" );
        if (artifactName.endsWith( "-SNAPSHOT" )) {
            // ensure to always update snapshots
            sessionChecks = session.getData().get( SESSION_CHECKS );
            session.getData().set( SESSION_CHECKS, null );
        }

        try {
            // 获取依赖
            ArtifactResult artifactResult = aether.getSystem().resolveArtifact( session, artifactRequest );
            return artifactResult.getArtifact();
        } catch ( ArtifactResolutionException e ) {
            if ( logUnresolvedArtifact ) {
                if ( log.isDebugEnabled() ) {
                    log.debug( "Unable to resolve artifact: " + artifactName, e );
                } else {
                    log.warn( "Unable to resolve artifact: " + artifactName );
                }
            }
            return null;
        } finally {
            if (sessionChecks != null) {
                session.getData().set( SESSION_CHECKS, sessionChecks );
            }
        }
    }

构建完了Artifact类就开始构建KieModule了。

KieRepositoryScannerImpl类
    private InternalKieModule buildArtifact(Artifact artifact, ArtifactResolver resolver) {
        DependencyDescriptor dependencyDescriptor = new DependencyDescriptor(artifact);
        ReleaseId releaseId = adapt( dependencyDescriptor.getReleaseId() );
        InternalKieModule kieModule = createKieModule(releaseId, artifact.getFile());
        if (kieModule != null) {
            addDependencies(kieModule, resolver, resolver.getArtifactDependecies(dependencyDescriptor.toString()));
        }
        return kieModule;
    }
    
    private void addDependencies(InternalKieModule kieModule, ArtifactResolver resolver, List dependencies) {
        for (DependencyDescriptor dep : dependencies) {
            InternalKieModule dependency = (InternalKieModule) KieServices.Factory.get().getRepository().getKieModule(adapt( dep.getReleaseId() ));
            if (dependency != null) {
                kieModule.addKieDependency(dependency);
            } else {
                Artifact depArtifact = resolver.resolveArtifact(dep.getReleaseId());
                if (depArtifact != null && isKJar(depArtifact.getFile())) {
                    ReleaseId depReleaseId = adapt( new DependencyDescriptor(depArtifact).getReleaseId() );
                    InternalKieModule zipKieModule = createKieModule(depReleaseId, depArtifact.getFile());
                    if (zipKieModule != null) {
                        kieModule.addKieDependency(zipKieModule);
                    }
                }
            }
        }
    }
    private KieModule loadPomArtifact(ReleaseId releaseId) {
        ArtifactResolver resolver = ArtifactResolver.getResolverFor(releaseId, false);
        if (resolver == null) {
            return null;
        }

        MemoryKieModule kieModule = new MemoryKieModule(releaseId);
        addDependencies(kieModule, resolver, resolver.getPomDirectDependencies( DependencyFilter.COMPILE_FILTER ));
        return kieModule;
    }

你可能感兴趣的:(maven,java,开发语言,drools)