springbootAI 1.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spring/__init__.py +66 -0
- spring/ai/__init__.py +78 -0
- spring/ai/advisors.py +139 -0
- spring/ai/annotations.py +74 -0
- spring/ai/autoconfig.py +481 -0
- spring/ai/core.py +391 -0
- spring/ai/etl.py +188 -0
- spring/ai/memory.py +109 -0
- spring/ai/observability.py +129 -0
- spring/ai/providers.py +789 -0
- spring/ai/resilience.py +258 -0
- spring/ai/tools.py +106 -0
- spring/ai/vectorstore.py +303 -0
- spring/annotations/__init__.py +188 -0
- spring/annotations/cache.py +126 -0
- spring/annotations/cloud.py +207 -0
- spring/annotations/conditional.py +272 -0
- spring/annotations/core.py +864 -0
- spring/annotations/messaging.py +107 -0
- spring/aop/__init__.py +4 -0
- spring/aop/cloud_aop.py +404 -0
- spring/aop/comprehensive_aop.py +1015 -0
- spring/aop/method_interceptor.py +19 -0
- spring/aop/proxy_factory.py +55 -0
- spring/cloud/__init__.py +76 -0
- spring/cloud/discovery.py +364 -0
- spring/cloud/feign.py +469 -0
- spring/cloud/gateway.py +452 -0
- spring/cloud/load_balancer.py +149 -0
- spring/cloud/seata.py +557 -0
- spring/cloud/sentinel.py +525 -0
- spring/cloud/tracer.py +337 -0
- spring/config/__init__.py +21 -0
- spring/config/binding.py +206 -0
- spring/config/config_loader.py +405 -0
- spring/context/__init__.py +13 -0
- spring/context/application_context.py +589 -0
- spring/context/bean_definition.py +70 -0
- spring/context/bean_factory.py +1052 -0
- spring/context/registry.py +58 -0
- spring/context/scanner.py +106 -0
- spring/core/__init__.py +3 -0
- spring/core/graceful_shutdown.py +196 -0
- spring/core/typing_utils.py +50 -0
- spring/csv/__init__.py +52 -0
- spring/csv/annotations.py +402 -0
- spring/csv/converters.py +69 -0
- spring/csv/easy_csv.py +95 -0
- spring/csv/exceptions.py +27 -0
- spring/csv/reader.py +195 -0
- spring/csv/writer.py +155 -0
- spring/data/__init__.py +54 -0
- spring/data/page.py +181 -0
- spring/data/repository.py +274 -0
- spring/data/specification.py +228 -0
- spring/datasource/__init__.py +66 -0
- spring/datasource/annotations.py +133 -0
- spring/datasource/context.py +69 -0
- spring/datasource/dynamic.py +148 -0
- spring/event/__init__.py +7 -0
- spring/event/publisher.py +69 -0
- spring/excel/__init__.py +51 -0
- spring/excel/annotations.py +405 -0
- spring/excel/converters.py +231 -0
- spring/excel/easy_excel.py +94 -0
- spring/excel/exceptions.py +31 -0
- spring/excel/reader.py +254 -0
- spring/excel/style.py +95 -0
- spring/excel/writer.py +197 -0
- spring/i18n/__init__.py +97 -0
- spring/i18n/accessor.py +94 -0
- spring/i18n/auto_config.py +177 -0
- spring/i18n/holder.py +106 -0
- spring/i18n/locale.py +152 -0
- spring/i18n/locale_resolver.py +367 -0
- spring/i18n/message_source.py +250 -0
- spring/i18n/middleware.py +79 -0
- spring/i18n/properties.py +168 -0
- spring/i18n/sources.py +255 -0
- spring/logging/__init__.py +1 -0
- spring/logging/loguru_logger.py +228 -0
- spring/main.py +378 -0
- spring/messaging/__init__.py +1 -0
- spring/messaging/rabbitmq.py +302 -0
- spring/monitoring/__init__.py +1 -0
- spring/monitoring/prometheus.py +199 -0
- spring/orm/__init__.py +258 -0
- spring/orm/database.py +222 -0
- spring/orm/ddl_auto.py +1217 -0
- spring/orm/migration.py +419 -0
- spring/orm/mybatis_integration.py +400 -0
- spring/orm/pymybatis/__init__.py +86 -0
- spring/orm/pymybatis/annotations/__init__.py +30 -0
- spring/orm/pymybatis/annotations/annotations.py +332 -0
- spring/orm/pymybatis/cache/__init__.py +47 -0
- spring/orm/pymybatis/cache/cache.py +371 -0
- spring/orm/pymybatis/cache/redis_cache.py +434 -0
- spring/orm/pymybatis/circuit_breaker/__init__.py +21 -0
- spring/orm/pymybatis/circuit_breaker/circuit_breaker.py +424 -0
- spring/orm/pymybatis/configuration.py +525 -0
- spring/orm/pymybatis/core/__init__.py +10 -0
- spring/orm/pymybatis/core/sql_session.py +1382 -0
- spring/orm/pymybatis/core/sql_session_factory.py +76 -0
- spring/orm/pymybatis/dialect/__init__.py +9 -0
- spring/orm/pymybatis/dialect/dialect.py +445 -0
- spring/orm/pymybatis/dynamic_sql/__init__.py +9 -0
- spring/orm/pymybatis/dynamic_sql/dynamic_sql.py +900 -0
- spring/orm/pymybatis/interceptor/__init__.py +31 -0
- spring/orm/pymybatis/interceptor/interceptor.py +427 -0
- spring/orm/pymybatis/mapper/__init__.py +9 -0
- spring/orm/pymybatis/mapper/mapper.py +540 -0
- spring/orm/pymybatis/metrics/__init__.py +41 -0
- spring/orm/pymybatis/metrics/metrics.py +595 -0
- spring/orm/pymybatis/pool/__init__.py +9 -0
- spring/orm/pymybatis/pool/connection_pool.py +711 -0
- spring/orm/pymybatis/security/__init__.py +19 -0
- spring/orm/pymybatis/security/access_control.py +415 -0
- spring/orm/pymybatis/security/password_encoder.py +293 -0
- spring/orm/pymybatis/security/sensitive_data_masker.py +326 -0
- spring/orm/pymybatis/security/sql_injection_detector.py +675 -0
- spring/orm/pymybatis/transaction/__init__.py +9 -0
- spring/orm/pymybatis/transaction/transaction.py +288 -0
- spring/orm/pymybatis/type_handler/__init__.py +37 -0
- spring/orm/pymybatis/type_handler/type_handler.py +473 -0
- spring/orm/pymybatis/version.py +9 -0
- spring/orm/pymybatis/xml_parser/__init__.py +9 -0
- spring/orm/pymybatis/xml_parser/xml_parser.py +761 -0
- spring/retry/__init__.py +12 -0
- spring/retry/retry_annotations.py +71 -0
- spring/retry/retry_decorator.py +155 -0
- spring/scheduling/__init__.py +3 -0
- spring/scheduling/scheduler.py +389 -0
- spring/security/__init__.py +39 -0
- spring/security/jwt_utils.py +281 -0
- spring/security/replay_protection.py +206 -0
- spring/security/secret_manager.py +226 -0
- spring/security/security_aop.py +248 -0
- spring/security/security_context.py +172 -0
- spring/test/__init__.py +45 -0
- spring/test/slicing.py +341 -0
- spring/tracing/__init__.py +11 -0
- spring/tracing/skywalking.py +229 -0
- spring/tx/__init__.py +52 -0
- spring/tx/events.py +172 -0
- spring/tx/synchronization.py +143 -0
- spring/utils/__init__.py +5 -0
- spring/utils/banner.py +32 -0
- spring/utils/logger.py +73 -0
- spring/utils/redis_client.py +526 -0
- spring/validation/__init__.py +55 -0
- spring/validation/aop.py +141 -0
- spring/validation/constraints.py +357 -0
- spring/validation/exceptions.py +55 -0
- spring/validation/validator.py +139 -0
- spring/web/__init__.py +12 -0
- spring/web/actuator.py +319 -0
- spring/web/exception_handler.py +61 -0
- spring/web/health.py +399 -0
- spring/web/interceptor.py +91 -0
- spring/web/result.py +44 -0
- spring/web/swagger.py +601 -0
- spring/web/web_context.py +755 -0
- spring/websocket/__init__.py +86 -0
- spring/websocket/annotations.py +169 -0
- spring/websocket/broker.py +238 -0
- spring/websocket/exceptions.py +26 -0
- spring/websocket/handler.py +243 -0
- spring/websocket/router.py +526 -0
- spring/websocket/session.py +216 -0
- springbootai-1.8.0.dist-info/METADATA +2796 -0
- springbootai-1.8.0.dist-info/RECORD +175 -0
- springbootai-1.8.0.dist-info/WHEEL +5 -0
- springbootai-1.8.0.dist-info/entry_points.txt +2 -0
- springbootai-1.8.0.dist-info/licenses/LICENSE +7 -0
- springbootai-1.8.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PyMyBatis配置管理模块
|
|
3
|
+
|
|
4
|
+
负责加载和管理框架的所有配置项,包括:
|
|
5
|
+
- 数据源配置(支持环境变量读取)
|
|
6
|
+
- 映射文件配置
|
|
7
|
+
- 缓存配置
|
|
8
|
+
- 事务配置
|
|
9
|
+
- 安全配置
|
|
10
|
+
- 连接池配置
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import json
|
|
15
|
+
import yaml
|
|
16
|
+
import re
|
|
17
|
+
from typing import Dict, List, Optional, Any
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ConfigurationError(ValueError):
|
|
21
|
+
"""Raised when ORM configuration is missing or internally inconsistent."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class Configuration:
|
|
25
|
+
"""
|
|
26
|
+
配置管理类
|
|
27
|
+
|
|
28
|
+
核心职责:
|
|
29
|
+
1. 加载配置文件(JSON/YAML)
|
|
30
|
+
2. 管理多数据源配置
|
|
31
|
+
3. 管理映射器配置
|
|
32
|
+
4. 管理缓存配置
|
|
33
|
+
5. 管理事务和安全配置
|
|
34
|
+
6. 支持环境变量读取(${ENV_VAR}格式)
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
# 环境变量替换模式:${ENV_VAR} 或 ${ENV_VAR:default}
|
|
38
|
+
ENV_VAR_PATTERN = re.compile(r'\$\{([^}]+)\}')
|
|
39
|
+
|
|
40
|
+
def __init__(self):
|
|
41
|
+
# 数据源配置
|
|
42
|
+
self.datasources: Dict[str, Dict[str, Any]] = {}
|
|
43
|
+
|
|
44
|
+
# 默认数据源名称
|
|
45
|
+
self.default_datasource: str = 'default'
|
|
46
|
+
|
|
47
|
+
# 映射器配置
|
|
48
|
+
self.mappers: List[str] = []
|
|
49
|
+
|
|
50
|
+
# XML映射文件路径
|
|
51
|
+
self.mapper_locations: List[str] = []
|
|
52
|
+
|
|
53
|
+
# 缓存配置
|
|
54
|
+
self.cache_enabled: bool = True
|
|
55
|
+
self.cache_type: str = 'lru'
|
|
56
|
+
self.cache_size: int = 1024
|
|
57
|
+
self.cache_ttl: int = 3600
|
|
58
|
+
|
|
59
|
+
# Redis缓存配置(可选)
|
|
60
|
+
self.redis_cache_enabled: bool = False
|
|
61
|
+
self.redis_cache_config: Dict[str, Any] = {}
|
|
62
|
+
|
|
63
|
+
# 事务配置
|
|
64
|
+
self.default_transaction_isolation: str = 'READ_COMMITTED'
|
|
65
|
+
self.default_fetch_size: int = 100
|
|
66
|
+
self.default_timeout: int = 30
|
|
67
|
+
|
|
68
|
+
# 连接池配置
|
|
69
|
+
self.pool_min_size: int = 5
|
|
70
|
+
self.pool_max_size: int = 20
|
|
71
|
+
self.pool_max_idle: int = 10
|
|
72
|
+
self.pool_wait_timeout: int = 30
|
|
73
|
+
self.pool_validation_interval: int = 300
|
|
74
|
+
self.leak_detection_enabled: bool = True
|
|
75
|
+
self.leak_timeout: int = 300
|
|
76
|
+
|
|
77
|
+
# 熔断器配置
|
|
78
|
+
self.circuit_breaker_enabled: bool = False
|
|
79
|
+
self.circuit_breaker_failure_threshold: int = 3
|
|
80
|
+
self.circuit_breaker_recovery_timeout: int = 60
|
|
81
|
+
self.circuit_breaker_success_threshold: int = 3
|
|
82
|
+
|
|
83
|
+
# 安全配置
|
|
84
|
+
self.sql_injection_detection: bool = True
|
|
85
|
+
self.ast_validation_enabled: bool = False # AST验证(需要sqlglot)
|
|
86
|
+
self.sensitive_data_masking: bool = True
|
|
87
|
+
self.access_control_enabled: bool = False
|
|
88
|
+
self.log_masking_enabled: bool = True
|
|
89
|
+
self.block_ddl: bool = True
|
|
90
|
+
self.allow_raw_params: bool = False
|
|
91
|
+
self.allowed_tables: List[str] = [] # 允许的表名白名单
|
|
92
|
+
self.allowed_columns: List[str] = [] # 允许的字段名白名单
|
|
93
|
+
|
|
94
|
+
# 性能配置
|
|
95
|
+
self.sql_precompile_cache: bool = True
|
|
96
|
+
self.result_map_cache: bool = True
|
|
97
|
+
self.lazy_load_mappers: bool = True
|
|
98
|
+
|
|
99
|
+
# 批量操作配置
|
|
100
|
+
self.max_batch_size: int = 1000
|
|
101
|
+
self.batch_split_size: int = 100
|
|
102
|
+
|
|
103
|
+
# 类型处理器注册
|
|
104
|
+
self.type_handlers: Dict[str, Any] = {}
|
|
105
|
+
|
|
106
|
+
# 拦截器列表
|
|
107
|
+
self.interceptors: List[Any] = []
|
|
108
|
+
|
|
109
|
+
# 方言配置
|
|
110
|
+
self.dialect: str = 'mysql'
|
|
111
|
+
|
|
112
|
+
# 日志配置
|
|
113
|
+
self.log_level: str = 'INFO'
|
|
114
|
+
self.log_file: Optional[str] = None
|
|
115
|
+
|
|
116
|
+
# 分页配置
|
|
117
|
+
self.max_pagination_offset: int = 10000
|
|
118
|
+
|
|
119
|
+
# 监控指标配置
|
|
120
|
+
self.metrics_enabled: bool = False
|
|
121
|
+
self.metrics_endpoint: str = '/metrics'
|
|
122
|
+
self.metrics_port: int = 9090
|
|
123
|
+
|
|
124
|
+
def _resolve_env_var(self, value: str) -> Any:
|
|
125
|
+
"""
|
|
126
|
+
解析环境变量引用
|
|
127
|
+
|
|
128
|
+
支持格式:
|
|
129
|
+
- ${ENV_VAR} - 直接读取环境变量
|
|
130
|
+
- ${ENV_VAR:default} - 读取环境变量,不存在使用默认值
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
value: 包含环境变量引用的字符串
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
解析后的字符串
|
|
137
|
+
"""
|
|
138
|
+
if not isinstance(value, str):
|
|
139
|
+
return value
|
|
140
|
+
|
|
141
|
+
exact_placeholder = self.ENV_VAR_PATTERN.fullmatch(value)
|
|
142
|
+
|
|
143
|
+
def replace_env(match):
|
|
144
|
+
env_spec = match.group(1)
|
|
145
|
+
|
|
146
|
+
# 检查是否有默认值
|
|
147
|
+
if ':' in env_spec:
|
|
148
|
+
env_name, default_value = env_spec.split(':', 1)
|
|
149
|
+
else:
|
|
150
|
+
env_name = env_spec
|
|
151
|
+
default_value = None # 使用None表示没有默认值
|
|
152
|
+
|
|
153
|
+
# 从环境变量获取值
|
|
154
|
+
env_value = os.environ.get(env_name.strip())
|
|
155
|
+
|
|
156
|
+
# 如果环境变量不存在,使用默认值
|
|
157
|
+
if env_value is None:
|
|
158
|
+
if default_value is None:
|
|
159
|
+
raise ConfigurationError(f"必需的环境变量 {env_name.strip()} 未设置")
|
|
160
|
+
return default_value
|
|
161
|
+
|
|
162
|
+
return env_value
|
|
163
|
+
|
|
164
|
+
resolved = self.ENV_VAR_PATTERN.sub(replace_env, value)
|
|
165
|
+
if exact_placeholder:
|
|
166
|
+
parsed = yaml.safe_load(resolved)
|
|
167
|
+
if not isinstance(parsed, (dict, list)):
|
|
168
|
+
return parsed
|
|
169
|
+
return resolved
|
|
170
|
+
|
|
171
|
+
def _resolve_config_recursive(self, config: Any) -> Any:
|
|
172
|
+
"""
|
|
173
|
+
递归解析配置中的环境变量
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
config: 配置值(可能是字典、列表或字符串)
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
解析后的配置值
|
|
180
|
+
"""
|
|
181
|
+
if isinstance(config, str):
|
|
182
|
+
return self._resolve_env_var(config)
|
|
183
|
+
|
|
184
|
+
if isinstance(config, dict):
|
|
185
|
+
resolved = {}
|
|
186
|
+
for key, value in config.items():
|
|
187
|
+
resolved[key] = self._resolve_config_recursive(value)
|
|
188
|
+
return resolved
|
|
189
|
+
|
|
190
|
+
if isinstance(config, list):
|
|
191
|
+
resolved = []
|
|
192
|
+
for item in config:
|
|
193
|
+
resolved.append(self._resolve_config_recursive(item))
|
|
194
|
+
return resolved
|
|
195
|
+
|
|
196
|
+
return config
|
|
197
|
+
|
|
198
|
+
def load_config(self, config: Dict[str, Any]) -> None:
|
|
199
|
+
"""
|
|
200
|
+
加载配置字典(支持环境变量解析)
|
|
201
|
+
|
|
202
|
+
Args:
|
|
203
|
+
config: 配置字典
|
|
204
|
+
"""
|
|
205
|
+
# 递归解析环境变量
|
|
206
|
+
config = self._resolve_config_recursive(config)
|
|
207
|
+
if not isinstance(config, dict):
|
|
208
|
+
raise ConfigurationError("ORM配置根节点必须是对象")
|
|
209
|
+
|
|
210
|
+
# 加载数据源配置(支持单数据源和多数据源两种格式)
|
|
211
|
+
if 'datasource' in config:
|
|
212
|
+
# 单数据源格式
|
|
213
|
+
self.datasources = {'default': config['datasource']}
|
|
214
|
+
self.default_datasource = 'default'
|
|
215
|
+
|
|
216
|
+
# 根据驱动自动设置方言
|
|
217
|
+
driver = config['datasource'].get('driver', 'mysql').lower()
|
|
218
|
+
if driver == 'sqlite':
|
|
219
|
+
self.dialect = 'sqlite'
|
|
220
|
+
elif driver == 'postgresql':
|
|
221
|
+
self.dialect = 'postgresql'
|
|
222
|
+
elif driver == 'oracle':
|
|
223
|
+
self.dialect = 'oracle'
|
|
224
|
+
else:
|
|
225
|
+
self.dialect = 'mysql'
|
|
226
|
+
|
|
227
|
+
elif 'datasources' in config:
|
|
228
|
+
# 多数据源格式
|
|
229
|
+
self.datasources = config['datasources']
|
|
230
|
+
if 'default' in self.datasources:
|
|
231
|
+
self.default_datasource = 'default'
|
|
232
|
+
|
|
233
|
+
# 加载默认数据源
|
|
234
|
+
if 'default_datasource' in config:
|
|
235
|
+
self.default_datasource = config['default_datasource']
|
|
236
|
+
|
|
237
|
+
# 加载映射器配置
|
|
238
|
+
if 'mappers' in config:
|
|
239
|
+
self.mappers = config['mappers']
|
|
240
|
+
|
|
241
|
+
# 加载XML映射文件路径(支持mapper_paths和mapper_locations两种格式)
|
|
242
|
+
if 'mapper_paths' in config:
|
|
243
|
+
self.mapper_locations = config['mapper_paths']
|
|
244
|
+
elif 'mapper_locations' in config:
|
|
245
|
+
self.mapper_locations = config['mapper_locations']
|
|
246
|
+
|
|
247
|
+
# 加载缓存配置
|
|
248
|
+
if 'cache' in config:
|
|
249
|
+
cache_config = config['cache']
|
|
250
|
+
self.cache_enabled = cache_config.get('enabled', True)
|
|
251
|
+
self.cache_type = cache_config.get('type', 'lru')
|
|
252
|
+
self.cache_size = cache_config.get('size', 1024)
|
|
253
|
+
self.cache_ttl = cache_config.get('ttl', 3600)
|
|
254
|
+
|
|
255
|
+
# Redis缓存配置
|
|
256
|
+
if 'redis' in cache_config:
|
|
257
|
+
redis_config = cache_config['redis']
|
|
258
|
+
self.redis_cache_enabled = redis_config.get('enabled', False)
|
|
259
|
+
self.redis_cache_config = redis_config
|
|
260
|
+
|
|
261
|
+
# 加载事务配置
|
|
262
|
+
if 'transaction' in config:
|
|
263
|
+
tx_config = config['transaction']
|
|
264
|
+
self.default_transaction_isolation = tx_config.get('isolation', 'READ_COMMITTED')
|
|
265
|
+
self.default_fetch_size = tx_config.get('fetch_size', 100)
|
|
266
|
+
self.default_timeout = tx_config.get('timeout', 30)
|
|
267
|
+
|
|
268
|
+
# 加载连接池配置
|
|
269
|
+
if 'pool' in config:
|
|
270
|
+
pool_config = config['pool']
|
|
271
|
+
self.pool_min_size = int(pool_config.get('min_size', 5))
|
|
272
|
+
self.pool_max_size = int(pool_config.get('max_size', 20))
|
|
273
|
+
self.pool_max_idle = float(pool_config.get('max_idle', 10))
|
|
274
|
+
self.pool_wait_timeout = float(pool_config.get('wait_timeout', 30))
|
|
275
|
+
self.pool_validation_interval = float(pool_config.get('validation_interval', 300))
|
|
276
|
+
self.leak_detection_enabled = pool_config.get('leak_detection_enabled', True)
|
|
277
|
+
self.leak_timeout = float(pool_config.get('leak_timeout', 300))
|
|
278
|
+
|
|
279
|
+
# 熔断器配置
|
|
280
|
+
if 'circuit_breaker' in pool_config:
|
|
281
|
+
cb_config = pool_config['circuit_breaker']
|
|
282
|
+
self.circuit_breaker_enabled = cb_config.get('enabled', False)
|
|
283
|
+
self.circuit_breaker_failure_threshold = int(cb_config.get('failure_threshold', 3))
|
|
284
|
+
self.circuit_breaker_recovery_timeout = float(cb_config.get('recovery_timeout', 60))
|
|
285
|
+
self.circuit_breaker_success_threshold = int(cb_config.get('success_threshold', 3))
|
|
286
|
+
|
|
287
|
+
# 加载安全配置
|
|
288
|
+
if 'security' in config:
|
|
289
|
+
security_config = config['security']
|
|
290
|
+
self.sql_injection_detection = security_config.get('sql_injection_detection', True)
|
|
291
|
+
self.ast_validation_enabled = security_config.get('ast_validation_enabled', False)
|
|
292
|
+
self.sensitive_data_masking = security_config.get('sensitive_data_masking', True)
|
|
293
|
+
self.access_control_enabled = security_config.get('access_control_enabled', False)
|
|
294
|
+
self.log_masking_enabled = security_config.get('log_masking_enabled', True)
|
|
295
|
+
self.block_ddl = security_config.get('block_ddl', True)
|
|
296
|
+
self.allow_raw_params = security_config.get('allow_raw_params', False)
|
|
297
|
+
self.allowed_tables = security_config.get('allowed_tables', [])
|
|
298
|
+
self.allowed_columns = security_config.get('allowed_columns', [])
|
|
299
|
+
|
|
300
|
+
# 加载性能配置
|
|
301
|
+
if 'performance' in config:
|
|
302
|
+
perf_config = config['performance']
|
|
303
|
+
self.sql_precompile_cache = perf_config.get('sql_precompile_cache', True)
|
|
304
|
+
self.result_map_cache = perf_config.get('result_map_cache', True)
|
|
305
|
+
self.lazy_load_mappers = perf_config.get('lazy_load_mappers', True)
|
|
306
|
+
|
|
307
|
+
# 加载批量操作配置
|
|
308
|
+
if 'batch' in config:
|
|
309
|
+
batch_config = config['batch']
|
|
310
|
+
self.max_batch_size = batch_config.get('max_size', 1000)
|
|
311
|
+
self.batch_split_size = batch_config.get('split_size', 100)
|
|
312
|
+
|
|
313
|
+
# 加载方言配置
|
|
314
|
+
if 'dialect' in config:
|
|
315
|
+
self.dialect = config['dialect']
|
|
316
|
+
|
|
317
|
+
# 加载日志配置
|
|
318
|
+
if 'logging' in config:
|
|
319
|
+
logging_config = config['logging']
|
|
320
|
+
self.log_level = logging_config.get('level', 'INFO')
|
|
321
|
+
self.log_file = logging_config.get('file')
|
|
322
|
+
|
|
323
|
+
# 加载分页配置
|
|
324
|
+
if 'pagination' in config:
|
|
325
|
+
pagination_config = config['pagination']
|
|
326
|
+
self.max_pagination_offset = pagination_config.get('max_offset', 10000)
|
|
327
|
+
|
|
328
|
+
# 加载监控指标配置
|
|
329
|
+
if 'metrics' in config:
|
|
330
|
+
metrics_config = config['metrics']
|
|
331
|
+
self.metrics_enabled = metrics_config.get('enabled', False)
|
|
332
|
+
self.metrics_endpoint = metrics_config.get('endpoint', '/metrics')
|
|
333
|
+
self.metrics_port = metrics_config.get('port', 9090)
|
|
334
|
+
|
|
335
|
+
self._validate()
|
|
336
|
+
|
|
337
|
+
def _validate(self) -> None:
|
|
338
|
+
if self.datasources and self.default_datasource not in self.datasources:
|
|
339
|
+
raise ConfigurationError(f"默认数据源不存在: {self.default_datasource}")
|
|
340
|
+
if self.pool_min_size < 0 or self.pool_max_size < 1:
|
|
341
|
+
raise ConfigurationError("连接池大小必须为非负数,且 max_size 必须大于 0")
|
|
342
|
+
if self.pool_min_size > self.pool_max_size:
|
|
343
|
+
raise ConfigurationError("连接池 min_size 不能大于 max_size")
|
|
344
|
+
if self.pool_wait_timeout <= 0 or self.pool_validation_interval <= 0 or self.leak_timeout <= 0:
|
|
345
|
+
raise ConfigurationError("连接池超时配置必须大于 0")
|
|
346
|
+
valid_isolation_levels = {
|
|
347
|
+
'READ_UNCOMMITTED', 'READ_COMMITTED', 'REPEATABLE_READ', 'SERIALIZABLE'
|
|
348
|
+
}
|
|
349
|
+
if self.default_transaction_isolation not in valid_isolation_levels:
|
|
350
|
+
raise ConfigurationError(
|
|
351
|
+
f"不支持的事务隔离级别: {self.default_transaction_isolation}"
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
def load_config_file(self, file_path: str) -> None:
|
|
355
|
+
"""
|
|
356
|
+
从配置文件加载配置(支持环境变量解析)
|
|
357
|
+
|
|
358
|
+
Args:
|
|
359
|
+
file_path: 配置文件路径,支持JSON和YAML格式
|
|
360
|
+
"""
|
|
361
|
+
if not os.path.exists(file_path):
|
|
362
|
+
raise FileNotFoundError(f"配置文件不存在: {file_path}")
|
|
363
|
+
|
|
364
|
+
ext = os.path.splitext(file_path)[1].lower()
|
|
365
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
|
366
|
+
if ext == '.json':
|
|
367
|
+
config = json.load(f)
|
|
368
|
+
elif ext in ('.yaml', '.yml'):
|
|
369
|
+
config = yaml.safe_load(f)
|
|
370
|
+
else:
|
|
371
|
+
raise ValueError(f"不支持的配置文件格式: {ext}")
|
|
372
|
+
|
|
373
|
+
self.load_config(config)
|
|
374
|
+
|
|
375
|
+
def get_datasource(self, name: Optional[str] = None) -> Dict[str, Any]:
|
|
376
|
+
"""
|
|
377
|
+
获取数据源配置(已解析环境变量)
|
|
378
|
+
|
|
379
|
+
Args:
|
|
380
|
+
name: 数据源名称,默认为默认数据源
|
|
381
|
+
|
|
382
|
+
Returns:
|
|
383
|
+
数据源配置字典
|
|
384
|
+
"""
|
|
385
|
+
ds_name = name or self.default_datasource
|
|
386
|
+
if ds_name not in self.datasources:
|
|
387
|
+
raise ValueError(f"数据源不存在: {ds_name}")
|
|
388
|
+
return self.datasources[ds_name]
|
|
389
|
+
|
|
390
|
+
def register_type_handler(self, java_type: str, handler: Any) -> None:
|
|
391
|
+
"""
|
|
392
|
+
注册自定义类型处理器
|
|
393
|
+
|
|
394
|
+
Args:
|
|
395
|
+
java_type: Java类型全限定名
|
|
396
|
+
handler: 类型处理器实例
|
|
397
|
+
"""
|
|
398
|
+
self.type_handlers[java_type] = handler
|
|
399
|
+
|
|
400
|
+
def register_interceptor(self, interceptor: Any) -> None:
|
|
401
|
+
"""
|
|
402
|
+
注册拦截器
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
interceptor: 拦截器实例
|
|
406
|
+
"""
|
|
407
|
+
self.interceptors.append(interceptor)
|
|
408
|
+
|
|
409
|
+
def is_cache_enabled(self) -> bool:
|
|
410
|
+
"""检查缓存是否启用"""
|
|
411
|
+
return self.cache_enabled
|
|
412
|
+
|
|
413
|
+
def is_sql_injection_detection_enabled(self) -> bool:
|
|
414
|
+
"""检查SQL注入检测是否启用"""
|
|
415
|
+
return self.sql_injection_detection
|
|
416
|
+
|
|
417
|
+
def is_sensitive_data_masking_enabled(self) -> bool:
|
|
418
|
+
"""检查敏感数据脱敏是否启用"""
|
|
419
|
+
return self.sensitive_data_masking
|
|
420
|
+
|
|
421
|
+
def is_access_control_enabled(self) -> bool:
|
|
422
|
+
"""检查访问控制是否启用"""
|
|
423
|
+
return self.access_control_enabled
|
|
424
|
+
|
|
425
|
+
def is_log_masking_enabled(self) -> bool:
|
|
426
|
+
"""检查日志脱敏是否启用"""
|
|
427
|
+
return self.log_masking_enabled
|
|
428
|
+
|
|
429
|
+
def is_sql_precompile_cache_enabled(self) -> bool:
|
|
430
|
+
"""检查SQL预编译缓存是否启用"""
|
|
431
|
+
return self.sql_precompile_cache
|
|
432
|
+
|
|
433
|
+
def is_result_map_cache_enabled(self) -> bool:
|
|
434
|
+
"""检查结果集映射缓存是否启用"""
|
|
435
|
+
return self.result_map_cache
|
|
436
|
+
|
|
437
|
+
def is_lazy_load_mappers_enabled(self) -> bool:
|
|
438
|
+
"""检查映射器懒加载是否启用"""
|
|
439
|
+
return self.lazy_load_mappers
|
|
440
|
+
|
|
441
|
+
def is_ddl_blocked(self) -> bool:
|
|
442
|
+
"""检查DDL语句是否被阻止"""
|
|
443
|
+
return self.block_ddl
|
|
444
|
+
|
|
445
|
+
def is_raw_params_allowed(self) -> bool:
|
|
446
|
+
"""检查${}参数是否允许使用"""
|
|
447
|
+
return self.allow_raw_params
|
|
448
|
+
|
|
449
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
450
|
+
"""将配置转换为字典(不包含敏感信息)"""
|
|
451
|
+
return {
|
|
452
|
+
'datasources': {name: {k: '******' if k.lower() in ('password', 'pwd') else v
|
|
453
|
+
for k, v in ds.items()}
|
|
454
|
+
for name, ds in self.datasources.items()},
|
|
455
|
+
'default_datasource': self.default_datasource,
|
|
456
|
+
'mappers': self.mappers,
|
|
457
|
+
'mapper_locations': self.mapper_locations,
|
|
458
|
+
'cache': {
|
|
459
|
+
'enabled': self.cache_enabled,
|
|
460
|
+
'type': self.cache_type,
|
|
461
|
+
'size': self.cache_size,
|
|
462
|
+
'ttl': self.cache_ttl,
|
|
463
|
+
'redis': {
|
|
464
|
+
'enabled': self.redis_cache_enabled,
|
|
465
|
+
**{k: '******' if k.lower() == 'password' else v
|
|
466
|
+
for k, v in self.redis_cache_config.items()}
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
'transaction': {
|
|
470
|
+
'isolation': self.default_transaction_isolation,
|
|
471
|
+
'fetch_size': self.default_fetch_size,
|
|
472
|
+
'timeout': self.default_timeout
|
|
473
|
+
},
|
|
474
|
+
'pool': {
|
|
475
|
+
'min_size': self.pool_min_size,
|
|
476
|
+
'max_size': self.pool_max_size,
|
|
477
|
+
'max_idle': self.pool_max_idle,
|
|
478
|
+
'wait_timeout': self.pool_wait_timeout,
|
|
479
|
+
'validation_interval': self.pool_validation_interval,
|
|
480
|
+
'leak_detection_enabled': self.leak_detection_enabled,
|
|
481
|
+
'leak_timeout': self.leak_timeout,
|
|
482
|
+
'circuit_breaker': {
|
|
483
|
+
'enabled': self.circuit_breaker_enabled,
|
|
484
|
+
'failure_threshold': self.circuit_breaker_failure_threshold,
|
|
485
|
+
'recovery_timeout': self.circuit_breaker_recovery_timeout,
|
|
486
|
+
'success_threshold': self.circuit_breaker_success_threshold
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
'security': {
|
|
490
|
+
'sql_injection_detection': self.sql_injection_detection,
|
|
491
|
+
'ast_validation_enabled': self.ast_validation_enabled,
|
|
492
|
+
'sensitive_data_masking': self.sensitive_data_masking,
|
|
493
|
+
'access_control_enabled': self.access_control_enabled,
|
|
494
|
+
'log_masking_enabled': self.log_masking_enabled,
|
|
495
|
+
'block_ddl': self.block_ddl,
|
|
496
|
+
'allow_raw_params': self.allow_raw_params,
|
|
497
|
+
'allowed_tables': self.allowed_tables,
|
|
498
|
+
'allowed_columns': self.allowed_columns
|
|
499
|
+
},
|
|
500
|
+
'performance': {
|
|
501
|
+
'sql_precompile_cache': self.sql_precompile_cache,
|
|
502
|
+
'result_map_cache': self.result_map_cache,
|
|
503
|
+
'lazy_load_mappers': self.lazy_load_mappers
|
|
504
|
+
},
|
|
505
|
+
'batch': {
|
|
506
|
+
'max_size': self.max_batch_size,
|
|
507
|
+
'split_size': self.batch_split_size
|
|
508
|
+
},
|
|
509
|
+
'dialect': self.dialect,
|
|
510
|
+
'logging': {
|
|
511
|
+
'level': self.log_level,
|
|
512
|
+
'file': self.log_file
|
|
513
|
+
},
|
|
514
|
+
'pagination': {
|
|
515
|
+
'max_offset': self.max_pagination_offset
|
|
516
|
+
},
|
|
517
|
+
'metrics': {
|
|
518
|
+
'enabled': self.metrics_enabled,
|
|
519
|
+
'endpoint': self.metrics_endpoint,
|
|
520
|
+
'port': self.metrics_port
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
def __repr__(self) -> str:
|
|
525
|
+
return f"<Configuration dialect={self.dialect}, datasources={list(self.datasources.keys())}>"
|