第03章 - 核心架构与模块设计
第03章 - 核心架构与模块设计
3.1 GeoTools 整体架构
3.1.1 分层架构设计
GeoTools 采用分层架构设计,从底层到高层依次为:
┌─────────────────────────────────────────────────────────────────────┐
│ 应用层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ GeoServer │ │ uDig │ │ 自定义应用 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────────┤
│ 服务层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ WMS │ │ WFS │ │ WCS │ │
│ │ gt-wms │ │ gt-wfs-ng │ │ gt-wcs │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────────────┤
│ 表现层 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 渲染引擎 (gt-render) │ │
│ │ 样式系统 │ 符号化 │ 标注 │ 地图输出 │ │
│ └─────────────────────────────────────────────────────────┘ │
├─────────────────────────────────────────────────────────────────────┤
│ 数据层 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ DataStore API (gt-main) │ │
│ ├───────────┬───────────┬───────────┬───────────┬─────────┤ │
│ │ Shapefile │ GeoJSON │ PostGIS │ GeoPackage│ WFS │ │
│ └───────────┴───────────┴───────────┴───────────┴─────────┘ │
├─────────────────────────────────────────────────────────────────────┤
│ 模型层 │
│ ┌───────────────────┐ ┌───────────────────┐ │
│ │ Feature Model │ │ CRS/Transform │ │
│ │ 要素模型 │ │ 坐标系统 │ │
│ └─────────┬─────────┘ └─────────┬─────────┘ │
│ │ │ │
│ ┌─────────▼─────────────────────▼─────────┐ │
│ │ JTS Geometry │ │
│ │ 几何引擎 │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
3.1.2 模块分类
GeoTools 的模块按功能分为以下几类:
核心库 (library):
| 模块 | 说明 |
|---|---|
| gt-main | 核心 API,Feature、DataStore 等基础接口 |
| gt-api | GeoTools API 定义 |
| gt-metadata | 元数据支持 |
| gt-referencing | 坐标参考系统 |
| gt-coverage | 栅格数据支持 |
| gt-render | 渲染引擎 |
| gt-jdbc | JDBC 数据访问基础 |
插件 (plugin):
| 模块 | 说明 |
|---|---|
| gt-shapefile | Shapefile 格式支持 |
| gt-geojson | GeoJSON 格式支持 |
| gt-geopkg | GeoPackage 格式支持 |
| gt-geotiff | GeoTIFF 格式支持 |
| gt-jdbc-postgis | PostGIS 数据库支持 |
| gt-jdbc-h2gis | H2GIS 数据库支持 |
扩展 (extension):
| 模块 | 说明 |
|---|---|
| gt-wms | WMS 客户端 |
| gt-wfs-ng | WFS 客户端 |
| gt-wps | WPS 客户端 |
| gt-graph | 图论/网络分析 |
| gt-brewer | ColorBrewer 配色方案 |
| gt-validation | 数据验证 |
3.1.3 依赖关系
gt-api
│
▼
gt-main
┌─────────┼─────────┐
│ │ │
▼ ▼ ▼
gt-referencing gt-render gt-coverage
│ │ │
▼ │ │
gt-epsg-hsql │ │
│ │
┌─────────┼─────────┘
│ │
▼ ▼
gt-shapefile gt-geotiff
│
▼
gt-jdbc
│
┌─────────┼─────────┐
│ │ │
▼ ▼ ▼
gt-jdbc- gt-jdbc- gt-jdbc-
postgis h2gis oracle
3.2 核心接口设计
3.2.1 DataStore API
DataStore 是 GeoTools 数据访问的核心接口,提供统一的数据源访问方式。
/**
* DataStore 接口层次结构
*/
public interface DataStore extends DataAccess<SimpleFeatureType, SimpleFeature> {
// 获取类型名称列表
String[] getTypeNames() throws IOException;
// 获取要素类型
SimpleFeatureType getSchema(String typeName) throws IOException;
// 获取要素源(只读)
SimpleFeatureSource getFeatureSource(String typeName) throws IOException;
// 获取要素写入器
FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter(
String typeName, Transaction transaction) throws IOException;
// 创建要素类型
void createSchema(SimpleFeatureType featureType) throws IOException;
// 更新要素类型
void updateSchema(String typeName, SimpleFeatureType featureType) throws IOException;
// 删除要素类型
void removeSchema(String typeName) throws IOException;
// 释放资源
void dispose();
}
DataStore 实现类:
DataStore
│
├── FileDataStore # 文件数据源
│ ├── ShapefileDataStore # Shapefile
│ ├── GeoJSONDataStore # GeoJSON
│ └── GeoPackageDataStore # GeoPackage
│
├── JDBCDataStore # 数据库数据源
│ ├── PostGISDataStore # PostGIS
│ ├── OracleDataStore # Oracle Spatial
│ └── H2GISDataStore # H2GIS
│
└── ContentDataStore # 通用内容数据源
└── MemoryDataStore # 内存数据源
使用示例:
// 1. 文件数据源
File shapefile = new File("data/countries.shp");
FileDataStore store = FileDataStoreFinder.getDataStore(shapefile);
// 2. 数据库数据源
Map<String, Object> params = new HashMap<>();
params.put("dbtype", "postgis");
params.put("host", "localhost");
params.put("port", 5432);
params.put("database", "gisdb");
params.put("user", "postgres");
params.put("passwd", "password");
DataStore pgStore = DataStoreFinder.getDataStore(params);
// 3. 内存数据源
MemoryDataStore memStore = new MemoryDataStore();
3.2.2 FeatureSource / FeatureStore
FeatureSource 和 FeatureStore 是访问要素数据的核心接口:
/**
* FeatureSource - 只读要素访问
*/
public interface SimpleFeatureSource {
// 获取要素类型
SimpleFeatureType getSchema();
// 获取所有要素
SimpleFeatureCollection getFeatures() throws IOException;
// 按过滤条件获取要素
SimpleFeatureCollection getFeatures(Filter filter) throws IOException;
// 按查询条件获取要素
SimpleFeatureCollection getFeatures(Query query) throws IOException;
// 获取要素数量
int getCount(Query query) throws IOException;
// 获取边界范围
ReferencedEnvelope getBounds() throws IOException;
// 获取边界范围(按查询)
ReferencedEnvelope getBounds(Query query) throws IOException;
// 获取数据源
DataStore getDataStore();
}
/**
* FeatureStore - 可写要素访问(继承 FeatureSource)
*/
public interface SimpleFeatureStore extends SimpleFeatureSource {
// 添加要素
List<FeatureId> addFeatures(FeatureCollection<SimpleFeatureType, SimpleFeature> features)
throws IOException;
// 删除要素
void removeFeatures(Filter filter) throws IOException;
// 修改要素属性
void modifyFeatures(Name[] attributeNames, Object[] attributeValues, Filter filter)
throws IOException;
// 设置事务
void setTransaction(Transaction transaction);
// 获取事务
Transaction getTransaction();
}
使用示例:
// 获取 FeatureSource
SimpleFeatureSource source = dataStore.getFeatureSource("countries");
// 检查是否支持写入
if (source instanceof SimpleFeatureStore) {
SimpleFeatureStore featureStore = (SimpleFeatureStore) source;
// 开启事务
Transaction transaction = new DefaultTransaction("create");
featureStore.setTransaction(transaction);
try {
// 添加要素
featureStore.addFeatures(featureCollection);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
} finally {
transaction.close();
}
}
3.2.3 Filter API
Filter API 用于构建查询过滤条件:
/**
* Filter 接口层次
*/
Filter
│
├── ComparisonOperator # 比较操作符
│ ├── PropertyIsEqualTo # 等于
│ ├── PropertyIsNotEqualTo # 不等于
│ ├── PropertyIsLessThan # 小于
│ ├── PropertyIsGreaterThan # 大于
│ ├── PropertyIsLike # 模糊匹配
│ └── PropertyIsBetween # 区间
│
├── SpatialOperator # 空间操作符
│ ├── Intersects # 相交
│ ├── Contains # 包含
│ ├── Within # 在内部
│ ├── Touches # 相接
│ ├── Crosses # 穿越
│ ├── DWithin # 距离内
│ └── BBOX # 边界框
│
└── LogicOperator # 逻辑操作符
├── And # 与
├── Or # 或
└── Not # 非
Filter 构建示例:
import org.geotools.api.filter.Filter;
import org.geotools.api.filter.FilterFactory;
import org.geotools.factory.CommonFactoryFinder;
// 获取过滤器工厂
FilterFactory ff = CommonFactoryFinder.getFilterFactory();
// 1. 属性过滤
Filter nameFilter = ff.equals(
ff.property("name"),
ff.literal("Beijing")
);
// 2. 数值比较
Filter popFilter = ff.greater(
ff.property("population"),
ff.literal(1000000)
);
// 3. 模糊匹配
Filter likeFilter = ff.like(
ff.property("name"),
"*ing" // 以 ing 结尾
);
// 4. 空间过滤 - BBOX
Filter bboxFilter = ff.bbox(
ff.property("the_geom"),
115.0, 39.0, 117.0, 41.0, // minX, minY, maxX, maxY
"EPSG:4326"
);
// 5. 空间过滤 - 相交
Geometry queryGeom = createQueryGeometry();
Filter intersectsFilter = ff.intersects(
ff.property("the_geom"),
ff.literal(queryGeom)
);
// 6. 组合过滤
Filter combinedFilter = ff.and(
nameFilter,
ff.or(popFilter, bboxFilter)
);
// 应用过滤器
SimpleFeatureCollection filtered = source.getFeatures(combinedFilter);
3.2.4 Style API
Style API 用于定义地图样式:
/**
* 样式接口层次
*/
Style
│
├── FeatureTypeStyle # 要素类型样式
│ └── Rule # 规则
│ └── Symbolizer # 符号化器
│ ├── PointSymbolizer # 点符号
│ ├── LineSymbolizer # 线符号
│ ├── PolygonSymbolizer # 面符号
│ ├── TextSymbolizer # 文本标注
│ └── RasterSymbolizer # 栅格符号
│
└── StyledLayerDescriptor # SLD 文档
Style 构建示例:
import org.geotools.api.style.*;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.styling.SLD;
// 获取样式工厂
StyleFactory sf = CommonFactoryFinder.getStyleFactory();
FilterFactory ff = CommonFactoryFinder.getFilterFactory();
// 1. 简单方式创建样式
Style simpleStyle = SLD.createPolygonStyle(
Color.BLUE, // 边框颜色
Color.CYAN, // 填充颜色
0.5f // 透明度
);
// 2. 详细方式创建样式
// 创建填充
Fill fill = sf.createFill(
ff.literal(Color.CYAN),
ff.literal(0.5)
);
// 创建边框
Stroke stroke = sf.createStroke(
ff.literal(Color.BLUE),
ff.literal(1.0)
);
// 创建面符号化器
PolygonSymbolizer polygonSymbolizer = sf.createPolygonSymbolizer(stroke, fill, null);
// 创建规则
Rule rule = sf.createRule();
rule.symbolizers().add(polygonSymbolizer);
// 创建要素类型样式
FeatureTypeStyle fts = sf.createFeatureTypeStyle();
fts.rules().add(rule);
// 创建样式
Style style = sf.createStyle();
style.featureTypeStyles().add(fts);
// 3. 从 SLD 文件加载
StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory();
SLDParser parser = new SLDParser(styleFactory, new File("style.sld"));
Style[] styles = parser.readXML();
3.3 工厂模式详解
3.3.1 CommonFactoryFinder
GeoTools 使用 CommonFactoryFinder 作为工厂定位器:
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.util.factory.Hints;
// 获取各种工厂
FilterFactory filterFactory = CommonFactoryFinder.getFilterFactory();
FilterFactory2 filterFactory2 = CommonFactoryFinder.getFilterFactory2();
StyleFactory styleFactory = CommonFactoryFinder.getStyleFactory();
FeatureFactory featureFactory = CommonFactoryFinder.getFeatureFactory();
FunctionFactory functionFactory = CommonFactoryFinder.getFunctionFactory();
// 使用 Hints 定制工厂行为
Hints hints = new Hints();
hints.put(Hints.FILTER_FACTORY, FilterFactory2.class);
FilterFactory customFactory = CommonFactoryFinder.getFilterFactory(hints);
3.3.2 DataStoreFinder
数据源查找使用 DataStoreFinder:
import org.geotools.api.data.DataStore;
import org.geotools.api.data.DataStoreFinder;
import org.geotools.api.data.FileDataStoreFinder;
// 1. 通过参数查找
Map<String, Object> params = new HashMap<>();
params.put("url", new File("data/countries.shp").toURI().toURL());
DataStore store = DataStoreFinder.getDataStore(params);
// 2. 文件数据源快捷方式
FileDataStore fileStore = FileDataStoreFinder.getDataStore(new File("data/countries.shp"));
// 3. 获取所有可用的 DataStoreFactory
Iterator<DataStoreFactorySpi> factories = DataStoreFinder.getAvailableDataStores();
while (factories.hasNext()) {
DataStoreFactorySpi factory = factories.next();
System.out.println(factory.getDisplayName() + ": " + factory.getDescription());
}
3.3.3 JTSFactoryFinder
几何工厂查找:
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.PrecisionModel;
// 获取默认几何工厂
GeometryFactory gf = JTSFactoryFinder.getGeometryFactory();
// 自定义精度模型
PrecisionModel pm = new PrecisionModel(1000); // 精确到小数点后3位
GeometryFactory preciseGF = JTSFactoryFinder.getGeometryFactory(
new Hints(Hints.JTS_PRECISION_MODEL, pm)
);
// 指定 SRID
GeometryFactory sridGF = JTSFactoryFinder.getGeometryFactory(
new Hints(Hints.JTS_SRID, 4326)
);
3.4 SPI 服务发现机制
3.4.1 SPI 概述
GeoTools 使用 Java SPI (Service Provider Interface) 机制实现插件化:
META-INF/services/
├── org.geotools.api.data.DataStoreFactorySpi
├── org.geotools.api.data.FileDataStoreFactorySpi
├── org.geotools.api.filter.FilterFactory
├── org.geotools.api.style.StyleFactory
└── org.geotools.referencing.operation.MathTransformProvider
3.4.2 DataStore SPI
/**
* DataStoreFactorySpi 接口
*/
public interface DataStoreFactorySpi extends Factory {
// 显示名称
String getDisplayName();
// 描述
String getDescription();
// 参数描述
Param[] getParametersInfo();
// 是否可用
boolean isAvailable();
// 能否处理给定参数
boolean canProcess(Map<String, ?> params);
// 创建 DataStore
DataStore createDataStore(Map<String, ?> params) throws IOException;
// 创建新的 DataStore
DataStore createNewDataStore(Map<String, ?> params) throws IOException;
}
自定义 DataStore 工厂示例:
public class MyDataStoreFactory implements DataStoreFactorySpi {
public static final Param URL_PARAM = new Param(
"url", URL.class, "数据文件 URL", true);
@Override
public String getDisplayName() {
return "My DataStore";
}
@Override
public String getDescription() {
return "自定义数据格式支持";
}
@Override
public Param[] getParametersInfo() {
return new Param[] { URL_PARAM };
}
@Override
public boolean canProcess(Map<String, ?> params) {
if (params.containsKey("url")) {
URL url = (URL) params.get("url");
return url.toString().endsWith(".myformat");
}
return false;
}
@Override
public DataStore createDataStore(Map<String, ?> params) throws IOException {
URL url = (URL) params.get("url");
return new MyDataStore(url);
}
@Override
public DataStore createNewDataStore(Map<String, ?> params) throws IOException {
return createDataStore(params);
}
@Override
public boolean isAvailable() {
return true;
}
}
注册服务:
创建文件 META-INF/services/org.geotools.api.data.DataStoreFactorySpi:
com.example.MyDataStoreFactory
3.5 事务管理
3.5.1 Transaction 接口
/**
* Transaction 接口
*/
public interface Transaction extends Closeable {
// 提交事务
void commit() throws IOException;
// 回滚事务
void rollback() throws IOException;
// 关闭事务
void close() throws IOException;
// 获取/设置状态
State getState(Object key);
void putState(Object key, State state);
// 添加事务监听器
void addAuthorization(String authID) throws IOException;
}
3.5.2 事务使用示例
import org.geotools.api.data.Transaction;
import org.geotools.data.DefaultTransaction;
public class TransactionExample {
public void addFeaturesWithTransaction(
SimpleFeatureStore store,
SimpleFeatureCollection features) throws IOException {
// 创建事务
Transaction transaction = new DefaultTransaction("add-features");
try {
// 绑定事务
store.setTransaction(transaction);
// 执行操作
store.addFeatures(features);
// 提交事务
transaction.commit();
System.out.println("添加成功");
} catch (Exception e) {
// 回滚事务
transaction.rollback();
System.err.println("添加失败,已回滚: " + e.getMessage());
throw new IOException(e);
} finally {
// 关闭事务
transaction.close();
}
}
public void batchUpdate(SimpleFeatureStore store, Filter filter,
String attrName, Object newValue) throws IOException {
Transaction transaction = new DefaultTransaction("batch-update");
store.setTransaction(transaction);
try {
// 批量更新
store.modifyFeatures(attrName, newValue, filter);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw new IOException(e);
} finally {
transaction.close();
}
}
}
3.6 资源管理
3.6.1 资源释放原则
GeoTools 遵循以下资源管理原则:
- DataStore.dispose() - 释放数据源连接
- Transaction.close() - 关闭事务
- FeatureIterator.close() - 关闭迭代器
- MapContent.dispose() - 释放地图资源
3.6.2 使用 try-with-resources
// 1. 迭代器使用
try (SimpleFeatureIterator features = collection.features()) {
while (features.hasNext()) {
SimpleFeature feature = features.next();
// 处理要素
}
}
// 2. 数据源使用
FileDataStore store = null;
try {
store = FileDataStoreFinder.getDataStore(file);
SimpleFeatureSource source = store.getFeatureSource();
// 使用数据源
} finally {
if (store != null) {
store.dispose();
}
}
// 3. 事务使用
try (Transaction tx = new DefaultTransaction("operation")) {
store.setTransaction(tx);
store.addFeatures(collection);
tx.commit();
} catch (Exception e) {
// 异常时自动关闭事务
}
3.6.3 资源泄漏检测
// 启用资源泄漏检测(仅用于开发调试)
System.setProperty("org.geotools.referencing.forceXY", "true");
// 使用 Hints 配置
Hints hints = new Hints();
hints.put(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
3.7 线程安全
3.7.1 线程安全级别
| 组件 | 线程安全 | 说明 |
|---|---|---|
| GeometryFactory | 是 | 可在多线程中共享 |
| FilterFactory | 是 | 可在多线程中共享 |
| StyleFactory | 是 | 可在多线程中共享 |
| DataStore | 是 | 可在多线程中共享 |
| FeatureSource | 是 | 可在多线程中共享 |
| FeatureIterator | 否 | 每个线程独立使用 |
| Transaction | 否 | 每个线程独立事务 |
| MapContent | 否 | UI 线程使用 |
3.7.2 多线程使用示例
public class MultiThreadExample {
// 共享的只读资源
private final DataStore dataStore;
private final GeometryFactory geometryFactory;
private final FilterFactory filterFactory;
public MultiThreadExample(DataStore dataStore) {
this.dataStore = dataStore;
this.geometryFactory = JTSFactoryFinder.getGeometryFactory();
this.filterFactory = CommonFactoryFinder.getFilterFactory();
}
public void parallelProcess(List<Geometry> queryGeometries) {
// 并行处理
queryGeometries.parallelStream().forEach(geom -> {
try {
processQuery(geom);
} catch (IOException e) {
e.printStackTrace();
}
});
}
private void processQuery(Geometry queryGeom) throws IOException {
// 每个线程获取独立的 FeatureSource
SimpleFeatureSource source = dataStore.getFeatureSource("layer");
// 构建过滤器(FilterFactory 线程安全)
Filter filter = filterFactory.intersects(
filterFactory.property("the_geom"),
filterFactory.literal(queryGeom)
);
// 使用独立的迭代器
try (SimpleFeatureIterator features = source.getFeatures(filter).features()) {
while (features.hasNext()) {
SimpleFeature feature = features.next();
// 处理结果
}
}
}
}
3.8 日志系统
3.8.1 日志配置
GeoTools 使用 Java Util Logging (JUL),可以桥接到其他日志框架:
log4j2.xml 配置:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="File" fileName="logs/geotools.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"/>
</File>
</Appenders>
<Loggers>
<!-- GeoTools 日志级别 -->
<Logger name="org.geotools" level="INFO"/>
<Logger name="org.geotools.data" level="DEBUG"/>
<Logger name="org.geotools.jdbc" level="DEBUG"/>
<Logger name="org.geotools.referencing" level="WARN"/>
<!-- JTS 日志 -->
<Logger name="org.locationtech.jts" level="WARN"/>
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>
3.8.2 代码中使用日志
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geotools.util.logging.Logging;
public class LoggingExample {
// GeoTools 推荐方式
private static final Logger LOGGER = Logging.getLogger(LoggingExample.class);
public void process() {
LOGGER.info("开始处理");
try {
// 业务逻辑
LOGGER.fine("详细调试信息");
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "处理失败", e);
}
LOGGER.info("处理完成");
}
}
3.9 本章小结
本章详细介绍了 GeoTools 的核心架构和模块设计:
-
分层架构
- 模型层、数据层、表现层、服务层、应用层
- 清晰的职责划分
-
核心接口
- DataStore API:统一数据访问
- Filter API:查询过滤
- Style API:地图样式
-
工厂模式
- CommonFactoryFinder:工厂定位器
- DataStoreFinder:数据源查找
- JTSFactoryFinder:几何工厂
-
SPI 机制
- 插件化扩展
- 服务发现
-
事务和资源管理
- Transaction 接口
- 资源释放原则
-
线程安全和日志
- 线程安全级别
- 日志配置
关键要点
- GeoTools 采用接口导向的设计
- 使用工厂模式创建对象
- SPI 机制支持插件扩展
- 注意资源释放和线程安全
下一步
在下一章中,我们将深入学习 JTS 几何对象的使用。

浙公网安备 33010602011771号