作者:Neshoir
上一篇,我们介绍了iServer GP服务的使用,用户反馈我们要实现的业务功能在GP服务算子列表里没有提供,怎么办啊?当然有办法,GP服务设计的初衷就是为了让开发人员能够快速简单的实现一个算子以便于重复使用。GP服务提供了实现算子的接口,开发人员只需要集成接口用注解方式即可快速实现业务算子。GP服务兼容了gt-process模块(gt-process是geotools的地理处理组件,可自行补充该技术点)。我们有几种方式来实现算子的扩展,比如1. 基于gt-process的注解实现。2.基于gt-process的静态方法工厂实现。3.基于GP服务模块的AbstractProcess、IProcessFactory等基类实现。以方式1来自定义实现缓冲区功能为例。
一、扩展实现
-
通过IDE工具或maven创建java应用工程。
-
引入scala开发环境,缓冲区功能暂且就用bdt的接口实现。
-
在main包下新建scala文件夹,并将其设置为"Sources Root"源码文件夹,并新建package。
-
引入bdt组件的jar库。由于我们要实现的业务功能在bdt组件里提供了接口,且bdt组件包已集成了gt-process模块。注意:如果不用bdt组件包,那么需要在pom.xml文件里引入gt-process的依赖。
<!--没有引用bdt库,就需要单独依赖gt-process--> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-process</artifactId> <version>${geotools.version}</version> </dependency>
-
创建一个接口类文件,便于于注解工厂扫描该接口的所有实现类。
public interface IBufferProcess { }
-
基于AnnotatedBeanProcessFactory基类创建一个类文件,用于IBufferProcess接口的注册。
import org.geotools.process.factory.AnnotatedBeanProcessFactory; import org.geotools.text.Text; public class MyAnnotatedBeanProcessFactory extends AnnotatedBeanProcessFactory { static volatile BeanFactoryRegistry<IBufferProcess> registry; public static BeanFactoryRegistry<IBufferProcess> getRegistry() { try { if (registry == null) { synchronized (MyAnnotatedBeanProcessFactory.class) { if (registry == null) { registry = new BeanFactoryRegistry<IBufferProcess>(IBufferProcess.class); } } } } catch (Exception ex) { ex.printStackTrace(); } return registry; } public MyAnnotatedBeanProcessFactory() { super(Text.text("gp test"), "custom buffer", getRegistry().lookupBeanClasses()); } }
-
创建一个IBufferProcess接口的实现类,并在execute方法里实现业务功能。注意:方法名称必须execute。需要用gt-process的注解(@DescribeProcess,@DescribeParameter,@DescribeResult)来描述我们的算子,参数以及结果。这样算子工厂才能扫描到该算子并装载。
import com.supermap.bdt.FeatureRDD import com.supermap.bdt.analyst.vector.cpp.{BufferAnalyst, BufferParam} import com.supermap.bdt.base.LinearUnit import com.typesafe.scalalogging.LazyLogging import org.geotools.process.factory.{DescribeParameter, DescribeProcess, DescribeResult} @DescribeProcess(title = "customBuffer", description = "自定义缓冲区分析") //算子的名称和描述 class BufferProcessIMPL extends IBufferProcess with LazyLogging { //注解的使用可以自行查api @DescribeResult(name = "result", description = "缓冲区分析结果featureRDD") def execute(@DescribeParameter(name = "featureRDD", description = "待缓冲区分析的featureRDD") featureRDD: FeatureRDD, @DescribeParameter(name = "radius", description = "缓冲半径") radius: Double, @DescribeParameter(name = "meter", description = "缓冲单位", defaultValue = "Meter") unit: String = "Meter"): FeatureRDD = { logger.info("start buffer") val bufferParam = BufferParam(radius, LinearUnit(unit)) val resultRDD = BufferAnalyst.apply(featureRDD, bufferParam) logger.info("end ") resultRDD } }
-
为了让自定义的算子工厂被FactoryFinder找到,需要在资源文件夹下创建一个services 文件夹,创建算子工厂文件,并把自定义的工厂类sm.yb.test.MyAnnotatedBeanProcessFactory进去。以及创建接口类文件,把实现的算子sm.yb.test.BufferProcessIMPL加入进去里。
-
编译打包为jar,可以不把bdt和spark的依赖打包进去,因为GP服务进程已加载了这些依赖。打包后的jar如图。
二、扩展部署,将上一步打包的JAR文件添加至iServer安装目录…\support\geoprocessing\lib路径下,重新启动iServer后进入Geoprocessing Modeler页面,自定义算子即可添加至页面左侧的算子列表中,供您进行建模使用。 如图:
三、算子验证:可以读取一份点数据然后做缓冲区分析,最后计算结果对象数量。
四、总结,gp算子的自定义实现原理,java spi插件机制遍历services下的所有接口找到自定义的算子工厂,算子工厂通过注解找到自定义的算子,算子的线程池启动一个线程执行execute方法。每个业务算子实现完成后,最好用Junit测试下功能性。