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是远远不够的,还需要添加依赖:
- <dependency>
- <groupId>org.kiegroupId>
- <artifactId>kie-ciartifactId>
- <version>7.73.0.Finalversion>
- dependency>
既然说到了跟maven有关,那么kie-ci又是如何获取maven的本地及远程仓库呢,那我们就看看kie-ci的pom.xml文件中有什么吧:
- <dependency>
- <groupId>org.apache.mavengroupId>
- <artifactId>maven-coreartifactId>
- dependency>
- <dependency>
- <groupId>org.apache.mavengroupId>
- <artifactId>maven-modelartifactId>
- dependency>
- <dependency>
- <groupId>org.apache.mavengroupId>
- <artifactId>maven-model-builderartifactId>
- dependency>
- <dependency>
- <groupId>org.apache.mavengroupId>
- <artifactId>maven-settingsartifactId>
- dependency>
- <dependency>
- <groupId>org.apache.mavengroupId>
- <artifactId>maven-settings-builderartifactId>
- dependency>
- <dependency>
- <groupId>org.apache.mavengroupId>
- <artifactId>maven-compatartifactId>
- dependency>
- <dependency>
- <groupId>org.apache.mavengroupId>
- <artifactId>maven-aether-providerartifactId>
- dependency>
- <dependency>
- <groupId>org.apache.maven.wagongroupId>
- <artifactId>wagon-provider-apiartifactId>
- <exclusions>
- <exclusion>
- <groupId>org.codehaus.plexusgroupId>
- <artifactId>plexus-utilsartifactId>
- exclusion>
- exclusions>
- dependency>
上面的依赖是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;
- }