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.
Files changed (175) hide show
  1. spring/__init__.py +66 -0
  2. spring/ai/__init__.py +78 -0
  3. spring/ai/advisors.py +139 -0
  4. spring/ai/annotations.py +74 -0
  5. spring/ai/autoconfig.py +481 -0
  6. spring/ai/core.py +391 -0
  7. spring/ai/etl.py +188 -0
  8. spring/ai/memory.py +109 -0
  9. spring/ai/observability.py +129 -0
  10. spring/ai/providers.py +789 -0
  11. spring/ai/resilience.py +258 -0
  12. spring/ai/tools.py +106 -0
  13. spring/ai/vectorstore.py +303 -0
  14. spring/annotations/__init__.py +188 -0
  15. spring/annotations/cache.py +126 -0
  16. spring/annotations/cloud.py +207 -0
  17. spring/annotations/conditional.py +272 -0
  18. spring/annotations/core.py +864 -0
  19. spring/annotations/messaging.py +107 -0
  20. spring/aop/__init__.py +4 -0
  21. spring/aop/cloud_aop.py +404 -0
  22. spring/aop/comprehensive_aop.py +1015 -0
  23. spring/aop/method_interceptor.py +19 -0
  24. spring/aop/proxy_factory.py +55 -0
  25. spring/cloud/__init__.py +76 -0
  26. spring/cloud/discovery.py +364 -0
  27. spring/cloud/feign.py +469 -0
  28. spring/cloud/gateway.py +452 -0
  29. spring/cloud/load_balancer.py +149 -0
  30. spring/cloud/seata.py +557 -0
  31. spring/cloud/sentinel.py +525 -0
  32. spring/cloud/tracer.py +337 -0
  33. spring/config/__init__.py +21 -0
  34. spring/config/binding.py +206 -0
  35. spring/config/config_loader.py +405 -0
  36. spring/context/__init__.py +13 -0
  37. spring/context/application_context.py +589 -0
  38. spring/context/bean_definition.py +70 -0
  39. spring/context/bean_factory.py +1052 -0
  40. spring/context/registry.py +58 -0
  41. spring/context/scanner.py +106 -0
  42. spring/core/__init__.py +3 -0
  43. spring/core/graceful_shutdown.py +196 -0
  44. spring/core/typing_utils.py +50 -0
  45. spring/csv/__init__.py +52 -0
  46. spring/csv/annotations.py +402 -0
  47. spring/csv/converters.py +69 -0
  48. spring/csv/easy_csv.py +95 -0
  49. spring/csv/exceptions.py +27 -0
  50. spring/csv/reader.py +195 -0
  51. spring/csv/writer.py +155 -0
  52. spring/data/__init__.py +54 -0
  53. spring/data/page.py +181 -0
  54. spring/data/repository.py +274 -0
  55. spring/data/specification.py +228 -0
  56. spring/datasource/__init__.py +66 -0
  57. spring/datasource/annotations.py +133 -0
  58. spring/datasource/context.py +69 -0
  59. spring/datasource/dynamic.py +148 -0
  60. spring/event/__init__.py +7 -0
  61. spring/event/publisher.py +69 -0
  62. spring/excel/__init__.py +51 -0
  63. spring/excel/annotations.py +405 -0
  64. spring/excel/converters.py +231 -0
  65. spring/excel/easy_excel.py +94 -0
  66. spring/excel/exceptions.py +31 -0
  67. spring/excel/reader.py +254 -0
  68. spring/excel/style.py +95 -0
  69. spring/excel/writer.py +197 -0
  70. spring/i18n/__init__.py +97 -0
  71. spring/i18n/accessor.py +94 -0
  72. spring/i18n/auto_config.py +177 -0
  73. spring/i18n/holder.py +106 -0
  74. spring/i18n/locale.py +152 -0
  75. spring/i18n/locale_resolver.py +367 -0
  76. spring/i18n/message_source.py +250 -0
  77. spring/i18n/middleware.py +79 -0
  78. spring/i18n/properties.py +168 -0
  79. spring/i18n/sources.py +255 -0
  80. spring/logging/__init__.py +1 -0
  81. spring/logging/loguru_logger.py +228 -0
  82. spring/main.py +378 -0
  83. spring/messaging/__init__.py +1 -0
  84. spring/messaging/rabbitmq.py +302 -0
  85. spring/monitoring/__init__.py +1 -0
  86. spring/monitoring/prometheus.py +199 -0
  87. spring/orm/__init__.py +258 -0
  88. spring/orm/database.py +222 -0
  89. spring/orm/ddl_auto.py +1217 -0
  90. spring/orm/migration.py +419 -0
  91. spring/orm/mybatis_integration.py +400 -0
  92. spring/orm/pymybatis/__init__.py +86 -0
  93. spring/orm/pymybatis/annotations/__init__.py +30 -0
  94. spring/orm/pymybatis/annotations/annotations.py +332 -0
  95. spring/orm/pymybatis/cache/__init__.py +47 -0
  96. spring/orm/pymybatis/cache/cache.py +371 -0
  97. spring/orm/pymybatis/cache/redis_cache.py +434 -0
  98. spring/orm/pymybatis/circuit_breaker/__init__.py +21 -0
  99. spring/orm/pymybatis/circuit_breaker/circuit_breaker.py +424 -0
  100. spring/orm/pymybatis/configuration.py +525 -0
  101. spring/orm/pymybatis/core/__init__.py +10 -0
  102. spring/orm/pymybatis/core/sql_session.py +1382 -0
  103. spring/orm/pymybatis/core/sql_session_factory.py +76 -0
  104. spring/orm/pymybatis/dialect/__init__.py +9 -0
  105. spring/orm/pymybatis/dialect/dialect.py +445 -0
  106. spring/orm/pymybatis/dynamic_sql/__init__.py +9 -0
  107. spring/orm/pymybatis/dynamic_sql/dynamic_sql.py +900 -0
  108. spring/orm/pymybatis/interceptor/__init__.py +31 -0
  109. spring/orm/pymybatis/interceptor/interceptor.py +427 -0
  110. spring/orm/pymybatis/mapper/__init__.py +9 -0
  111. spring/orm/pymybatis/mapper/mapper.py +540 -0
  112. spring/orm/pymybatis/metrics/__init__.py +41 -0
  113. spring/orm/pymybatis/metrics/metrics.py +595 -0
  114. spring/orm/pymybatis/pool/__init__.py +9 -0
  115. spring/orm/pymybatis/pool/connection_pool.py +711 -0
  116. spring/orm/pymybatis/security/__init__.py +19 -0
  117. spring/orm/pymybatis/security/access_control.py +415 -0
  118. spring/orm/pymybatis/security/password_encoder.py +293 -0
  119. spring/orm/pymybatis/security/sensitive_data_masker.py +326 -0
  120. spring/orm/pymybatis/security/sql_injection_detector.py +675 -0
  121. spring/orm/pymybatis/transaction/__init__.py +9 -0
  122. spring/orm/pymybatis/transaction/transaction.py +288 -0
  123. spring/orm/pymybatis/type_handler/__init__.py +37 -0
  124. spring/orm/pymybatis/type_handler/type_handler.py +473 -0
  125. spring/orm/pymybatis/version.py +9 -0
  126. spring/orm/pymybatis/xml_parser/__init__.py +9 -0
  127. spring/orm/pymybatis/xml_parser/xml_parser.py +761 -0
  128. spring/retry/__init__.py +12 -0
  129. spring/retry/retry_annotations.py +71 -0
  130. spring/retry/retry_decorator.py +155 -0
  131. spring/scheduling/__init__.py +3 -0
  132. spring/scheduling/scheduler.py +389 -0
  133. spring/security/__init__.py +39 -0
  134. spring/security/jwt_utils.py +281 -0
  135. spring/security/replay_protection.py +206 -0
  136. spring/security/secret_manager.py +226 -0
  137. spring/security/security_aop.py +248 -0
  138. spring/security/security_context.py +172 -0
  139. spring/test/__init__.py +45 -0
  140. spring/test/slicing.py +341 -0
  141. spring/tracing/__init__.py +11 -0
  142. spring/tracing/skywalking.py +229 -0
  143. spring/tx/__init__.py +52 -0
  144. spring/tx/events.py +172 -0
  145. spring/tx/synchronization.py +143 -0
  146. spring/utils/__init__.py +5 -0
  147. spring/utils/banner.py +32 -0
  148. spring/utils/logger.py +73 -0
  149. spring/utils/redis_client.py +526 -0
  150. spring/validation/__init__.py +55 -0
  151. spring/validation/aop.py +141 -0
  152. spring/validation/constraints.py +357 -0
  153. spring/validation/exceptions.py +55 -0
  154. spring/validation/validator.py +139 -0
  155. spring/web/__init__.py +12 -0
  156. spring/web/actuator.py +319 -0
  157. spring/web/exception_handler.py +61 -0
  158. spring/web/health.py +399 -0
  159. spring/web/interceptor.py +91 -0
  160. spring/web/result.py +44 -0
  161. spring/web/swagger.py +601 -0
  162. spring/web/web_context.py +755 -0
  163. spring/websocket/__init__.py +86 -0
  164. spring/websocket/annotations.py +169 -0
  165. spring/websocket/broker.py +238 -0
  166. spring/websocket/exceptions.py +26 -0
  167. spring/websocket/handler.py +243 -0
  168. spring/websocket/router.py +526 -0
  169. spring/websocket/session.py +216 -0
  170. springbootai-1.8.0.dist-info/METADATA +2796 -0
  171. springbootai-1.8.0.dist-info/RECORD +175 -0
  172. springbootai-1.8.0.dist-info/WHEEL +5 -0
  173. springbootai-1.8.0.dist-info/entry_points.txt +2 -0
  174. springbootai-1.8.0.dist-info/licenses/LICENSE +7 -0
  175. springbootai-1.8.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,864 @@
1
+ from typing import Optional, Union, Dict, Any, Type, List, Callable, Tuple
2
+ import inspect
3
+
4
+
5
+ class SpringAnnotation:
6
+ _annotation_type: str = "base"
7
+
8
+ def __new__(cls, *args, **kwargs):
9
+ # 如果第一个参数是类或函数,且不是内置类型,说明是@Annotation形式(不带括号)
10
+ if args and (isinstance(args[0], type) or callable(args[0])):
11
+ target = args[0]
12
+ # 排除内置类型(如ValueError, Exception等),它们是注解的参数,不是目标
13
+ if isinstance(target, type) and target.__module__ in ('builtins', '__builtin__'):
14
+ # 这是内置类型,作为注解参数处理
15
+ return super().__new__(cls)
16
+ # 创建注解实例
17
+ instance = super().__new__(cls)
18
+ # 应用注解
19
+ instance.__init__(*args[1:], **kwargs)
20
+ # ``hasattr`` also sees annotations inherited from a base class.
21
+ # Each decorated target needs its own list, otherwise decorating a
22
+ # subclass silently mutates the parent's Spring metadata.
23
+ if '__spring_annotations__' not in target.__dict__:
24
+ target.__spring_annotations__ = []
25
+ target.__spring_annotations__.append(instance)
26
+ instance._original_class = target
27
+ # 返回原始类,而不是注解实例
28
+ return target
29
+ # 否则是@Annotation()形式,返回注解实例
30
+ return super().__new__(cls)
31
+
32
+ def __init__(self, **kwargs):
33
+ self.__dict__.update(kwargs)
34
+ self._original_class = None
35
+
36
+ def __call__(self, target: Union[Type, Callable]) -> Union[Type, Callable]:
37
+ if '__spring_annotations__' not in target.__dict__:
38
+ target.__spring_annotations__ = []
39
+ target.__spring_annotations__.append(self)
40
+ self._original_class = target
41
+ return target
42
+
43
+
44
+ def get_spring_annotations(target: Any) -> List["SpringAnnotation"]:
45
+ """Return annotations declared directly on *target* in declaration order.
46
+
47
+ Spring's metadata is intentionally not merged from base classes. This
48
+ helper gives scanners and integrations one consistent read path and keeps
49
+ inherited annotations from being mistaken for declarations on a subclass.
50
+ """
51
+ return list(getattr(target, "__dict__", {}).get("__spring_annotations__", []))
52
+
53
+
54
+ class ApplicationEvent:
55
+ """Base class for events published through the application context."""
56
+
57
+ def __init__(self, source: Any = None):
58
+ self.source = source
59
+
60
+
61
+ class EventListener(SpringAnnotation):
62
+ """Mark a bean method as an application event listener."""
63
+
64
+ _annotation_type = "event_listener"
65
+
66
+ def __new__(cls, *args, **kwargs):
67
+ # ``@EventListener(MyEvent)`` is a common shorthand. The base
68
+ # annotation treats a positional class as a decorator target, so
69
+ # event classes need to be recognized before delegating to it.
70
+ if args and isinstance(args[0], type):
71
+ try:
72
+ if issubclass(args[0], ApplicationEvent):
73
+ return object.__new__(cls)
74
+ except TypeError:
75
+ pass
76
+ return super().__new__(cls, *args, **kwargs)
77
+
78
+ def __init__(
79
+ self,
80
+ event_type: Optional[Type[ApplicationEvent]] = None,
81
+ order: int = 0,
82
+ ):
83
+ super().__init__(event_type=event_type, order=order)
84
+
85
+
86
+ class SpringBootApplication(SpringAnnotation):
87
+ _annotation_type = "boot"
88
+
89
+ def __init__(self, scan_base_packages: Optional[List[str]] = None):
90
+ super().__init__(scan_base_packages=scan_base_packages)
91
+
92
+
93
+ class ComponentScan(SpringAnnotation):
94
+ _annotation_type = "scan"
95
+
96
+ def __init__(self, base_packages: Optional[List[str]] = None):
97
+ super().__init__(base_packages=base_packages)
98
+
99
+
100
+ class RestController(SpringAnnotation):
101
+ _annotation_type = "controller"
102
+
103
+ def __init__(self, value: str = ""):
104
+ super().__init__(value=value)
105
+
106
+
107
+ class Controller(SpringAnnotation):
108
+ _annotation_type = "controller"
109
+
110
+ def __init__(self, value: str = ""):
111
+ super().__init__(value=value)
112
+
113
+
114
+ class RequestMapping(SpringAnnotation):
115
+ _annotation_type = "mapping"
116
+
117
+ def __init__(
118
+ self,
119
+ path: Union[str, List[str]] = "",
120
+ method: Optional[Union[str, List[str]]] = None,
121
+ consumes: Optional[str] = None,
122
+ produces: Optional[str] = None,
123
+ value: Optional[Union[str, List[str]]] = None,
124
+ ):
125
+ if value is not None:
126
+ if path:
127
+ raise TypeError("RequestMapping 的 path 和 value 只能设置一个")
128
+ path = value
129
+ if isinstance(method, str):
130
+ method = [method]
131
+ super().__init__(path=path, method=[m.upper() for m in (method or [])], consumes=consumes, produces=produces)
132
+
133
+
134
+ class GetMapping(SpringAnnotation):
135
+ _annotation_type = "mapping"
136
+
137
+ def __init__(
138
+ self,
139
+ path: Union[str, List[str]] = "",
140
+ consumes: Optional[str] = None,
141
+ produces: Optional[str] = None,
142
+ value: Optional[Union[str, List[str]]] = None,
143
+ ):
144
+ if value is not None:
145
+ if path:
146
+ raise TypeError("GetMapping 的 path 和 value 只能设置一个")
147
+ path = value
148
+ super().__init__(path=path, method=["GET"], consumes=consumes, produces=produces)
149
+
150
+
151
+ class PostMapping(SpringAnnotation):
152
+ _annotation_type = "mapping"
153
+
154
+ def __init__(
155
+ self,
156
+ path: Union[str, List[str]] = "",
157
+ consumes: Optional[str] = None,
158
+ produces: Optional[str] = None,
159
+ value: Optional[Union[str, List[str]]] = None,
160
+ ):
161
+ if value is not None:
162
+ if path:
163
+ raise TypeError("PostMapping 的 path 和 value 只能设置一个")
164
+ path = value
165
+ super().__init__(path=path, method=["POST"], consumes=consumes, produces=produces)
166
+
167
+
168
+ class PutMapping(SpringAnnotation):
169
+ _annotation_type = "mapping"
170
+
171
+ def __init__(
172
+ self,
173
+ path: Union[str, List[str]] = "",
174
+ consumes: Optional[str] = None,
175
+ produces: Optional[str] = None,
176
+ value: Optional[Union[str, List[str]]] = None,
177
+ ):
178
+ if value is not None:
179
+ if path:
180
+ raise TypeError("PutMapping 的 path 和 value 只能设置一个")
181
+ path = value
182
+ super().__init__(path=path, method=["PUT"], consumes=consumes, produces=produces)
183
+
184
+
185
+ class PatchMapping(SpringAnnotation):
186
+ _annotation_type = "mapping"
187
+
188
+ def __init__(
189
+ self,
190
+ path: Union[str, List[str]] = "",
191
+ consumes: Optional[str] = None,
192
+ produces: Optional[str] = None,
193
+ value: Optional[Union[str, List[str]]] = None,
194
+ ):
195
+ if value is not None:
196
+ if path:
197
+ raise TypeError("PatchMapping 的 path 和 value 只能设置一个")
198
+ path = value
199
+ super().__init__(path=path, method=["PATCH"], consumes=consumes, produces=produces)
200
+
201
+
202
+ class DeleteMapping(SpringAnnotation):
203
+ _annotation_type = "mapping"
204
+
205
+ def __init__(
206
+ self,
207
+ path: Union[str, List[str]] = "",
208
+ consumes: Optional[str] = None,
209
+ produces: Optional[str] = None,
210
+ value: Optional[Union[str, List[str]]] = None,
211
+ ):
212
+ if value is not None:
213
+ if path:
214
+ raise TypeError("DeleteMapping 的 path 和 value 只能设置一个")
215
+ path = value
216
+ super().__init__(path=path, method=["DELETE"], consumes=consumes, produces=produces)
217
+
218
+
219
+ class Service(SpringAnnotation):
220
+ _annotation_type = "component"
221
+
222
+ def __init__(self, value: str = ""):
223
+ super().__init__(value=value)
224
+
225
+
226
+ class Component(SpringAnnotation):
227
+ _annotation_type = "component"
228
+
229
+ def __init__(self, value: str = ""):
230
+ super().__init__(value=value)
231
+
232
+
233
+ class Repository(SpringAnnotation):
234
+ _annotation_type = "component"
235
+
236
+ def __init__(self, value: str = ""):
237
+ super().__init__(value=value)
238
+
239
+
240
+ class Autowired(SpringAnnotation):
241
+ _annotation_type = "inject"
242
+
243
+ def __init__(self, required: bool = True):
244
+ super().__init__(required=required)
245
+
246
+
247
+ class Qualifier(SpringAnnotation):
248
+ _annotation_type = "qualifier"
249
+
250
+ def __init__(self, value: str):
251
+ super().__init__(value=value)
252
+
253
+
254
+ class Configuration(SpringAnnotation):
255
+ _annotation_type = "configuration"
256
+
257
+ def __init__(self, proxyBeanMethods: bool = True, proxy_bean_methods: Optional[bool] = None):
258
+ if proxy_bean_methods is not None:
259
+ proxyBeanMethods = proxy_bean_methods
260
+ super().__init__(proxyBeanMethods=proxyBeanMethods)
261
+
262
+
263
+ class Scope(SpringAnnotation):
264
+ """Declare a Bean scope (``singleton`` or ``prototype``)."""
265
+
266
+ _annotation_type = "scope"
267
+
268
+ def __init__(self, value: str = "singleton"):
269
+ normalized = str(value).lower()
270
+ if normalized not in {"singleton", "prototype"}:
271
+ raise ValueError("Scope 仅支持 singleton 或 prototype")
272
+ super().__init__(value=normalized)
273
+
274
+
275
+ class Bean(SpringAnnotation):
276
+ _annotation_type = "bean"
277
+
278
+ def __init__(
279
+ self,
280
+ name: Optional[str] = None,
281
+ scope: str = "singleton",
282
+ init_method: Optional[str] = None,
283
+ destroy_method: Optional[str] = None,
284
+ ):
285
+ super().__init__(name=name, scope=scope, init_method=init_method, destroy_method=destroy_method)
286
+
287
+
288
+ class Value(SpringAnnotation):
289
+ _annotation_type = "value"
290
+
291
+ def __init__(self, value: str, default: Any = None):
292
+ super().__init__(value=value, default=default)
293
+
294
+
295
+ class ConfigurationProperties(SpringAnnotation):
296
+ _annotation_type = "properties"
297
+
298
+ def __init__(self, prefix: str):
299
+ super().__init__(prefix=prefix)
300
+
301
+
302
+ class RequestParam:
303
+ _annotation_type = "param"
304
+
305
+ def __init__(
306
+ self,
307
+ name: Optional[str] = None,
308
+ required: bool = True,
309
+ default: Any = None,
310
+ value: Optional[str] = None,
311
+ ):
312
+ self.name = value if value is not None else name
313
+ self.required = required
314
+ self.default = default
315
+
316
+
317
+ class PathVariable:
318
+ _annotation_type = "param"
319
+
320
+ def __init__(self, name: Optional[str] = None, required: bool = True, value: Optional[str] = None):
321
+ self.name = value if value is not None else name
322
+ self.required = required
323
+
324
+
325
+ class RequestBody:
326
+ _annotation_type = "param"
327
+
328
+ def __init__(self, required: bool = True, value: Optional[bool] = None):
329
+ if value is not None:
330
+ required = value
331
+ self.required = required
332
+
333
+
334
+ class Valid(SpringAnnotation):
335
+ """Mark a request-body parameter for FastAPI/Pydantic validation.
336
+
337
+ Validation groups are retained as migration metadata. Field validation is
338
+ performed by the annotated Pydantic model at request time.
339
+ """
340
+
341
+ _annotation_type = "param"
342
+
343
+ def __init__(self, groups: Optional[List[Type]] = None):
344
+ super().__init__(groups=groups or [])
345
+
346
+
347
+ class Validated(SpringAnnotation):
348
+ """Request-body validation marker that keeps optional group metadata."""
349
+
350
+ _annotation_type = "param"
351
+
352
+ def __init__(self, groups: Optional[List[Type]] = None):
353
+ super().__init__(groups=groups or [])
354
+
355
+
356
+ class CrossOrigin(SpringAnnotation):
357
+ _annotation_type = "cors"
358
+
359
+ def __init__(
360
+ self,
361
+ origins: Optional[List[str]] = None,
362
+ methods: Optional[List[str]] = None,
363
+ allowedHeaders: Optional[List[str]] = None,
364
+ allowCredentials: bool = False,
365
+ maxAge: int = 3600,
366
+ allowed_headers: Optional[List[str]] = None,
367
+ allow_credentials: Optional[bool] = None,
368
+ max_age: Optional[int] = None,
369
+ ):
370
+ if allowed_headers is not None:
371
+ allowedHeaders = allowed_headers
372
+ if allow_credentials is not None:
373
+ allowCredentials = allow_credentials
374
+ if max_age is not None:
375
+ maxAge = max_age
376
+ super().__init__(
377
+ origins=origins or ["*"],
378
+ methods=methods or ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
379
+ allowedHeaders=allowedHeaders or ["*"],
380
+ allowCredentials=allowCredentials,
381
+ maxAge=maxAge,
382
+ )
383
+
384
+
385
+ class ControllerAdvice(SpringAnnotation):
386
+ _annotation_type = "advice"
387
+
388
+ def __init__(self):
389
+ super().__init__()
390
+
391
+
392
+ class ExceptionHandler(SpringAnnotation):
393
+ _annotation_type = "exception_handler"
394
+
395
+ def __init__(self, *exceptions: Type[Exception], value: Optional[List[Type[Exception]]] = None):
396
+ if value:
397
+ exceptions = tuple(value)
398
+ super().__init__(
399
+ value=list(exceptions) if exceptions else [],
400
+ exceptions=exceptions
401
+ )
402
+
403
+
404
+ class Slf4j(SpringAnnotation):
405
+ _annotation_type = "logging"
406
+
407
+ def __init__(self, logger_name: Optional[str] = None):
408
+ super().__init__(logger_name=logger_name)
409
+
410
+
411
+ class LogExecutionTime(SpringAnnotation):
412
+ _annotation_type = "logging"
413
+
414
+ def __init__(self, log_level: str = "info"):
415
+ super().__init__(log_level=log_level)
416
+
417
+ def __call__(self, func: Callable) -> Callable:
418
+ super().__call__(func)
419
+
420
+ import time
421
+ import functools
422
+
423
+ if inspect.iscoroutinefunction(func):
424
+ @functools.wraps(func)
425
+ async def async_wrapper(*args, **kwargs):
426
+ start_time = time.time()
427
+ try:
428
+ return await func(*args, **kwargs)
429
+ finally:
430
+ execution_time = time.time() - start_time
431
+ logger = self._get_logger(func)
432
+ log_method = getattr(logger, self.log_level.lower(), logger.info)
433
+ log_method(
434
+ f"Execution time for {func.__name__}: {execution_time:.4f}s"
435
+ )
436
+
437
+ return async_wrapper
438
+
439
+ @functools.wraps(func)
440
+ def wrapper(*args, **kwargs):
441
+ start_time = time.time()
442
+ try:
443
+ return func(*args, **kwargs)
444
+ finally:
445
+ execution_time = time.time() - start_time
446
+ logger = self._get_logger(func)
447
+ log_method = getattr(logger, self.log_level.lower(), logger.info)
448
+ log_method(f"Execution time for {func.__name__}: {execution_time:.4f}s")
449
+
450
+ return wrapper
451
+
452
+ def _get_logger(self, func: Callable) -> Any:
453
+ from spring.utils.logger import get_logger
454
+ return get_logger(func.__module__)
455
+
456
+
457
+ class PostConstruct(SpringAnnotation):
458
+ _annotation_type = "lifecycle"
459
+
460
+ def __init__(self):
461
+ super().__init__()
462
+
463
+
464
+ class PreDestroy(SpringAnnotation):
465
+ _annotation_type = "lifecycle"
466
+
467
+ def __init__(self):
468
+ super().__init__()
469
+
470
+
471
+ class Primary(SpringAnnotation):
472
+ _annotation_type = "primary"
473
+
474
+ def __init__(self):
475
+ super().__init__()
476
+
477
+
478
+ class Profile(SpringAnnotation):
479
+ _annotation_type = "profile"
480
+
481
+ def __init__(self, value: Union[str, List[str]]):
482
+ if isinstance(value, str):
483
+ value = [value]
484
+ super().__init__(value=value)
485
+
486
+
487
+ class Lazy(SpringAnnotation):
488
+ _annotation_type = "lazy"
489
+
490
+ def __init__(self, value: bool = True):
491
+ super().__init__(value=value)
492
+
493
+
494
+ class RequestHeader:
495
+ _annotation_type = "param"
496
+
497
+ def __init__(
498
+ self,
499
+ name: Optional[str] = None,
500
+ required: bool = True,
501
+ default: Any = None,
502
+ value: Optional[str] = None,
503
+ ):
504
+ self.name = value if value is not None else name
505
+ self.required = required
506
+ self.default = default
507
+
508
+
509
+ class CookieValue:
510
+ _annotation_type = "param"
511
+
512
+ def __init__(
513
+ self,
514
+ name: Optional[str] = None,
515
+ required: bool = True,
516
+ default: Any = None,
517
+ value: Optional[str] = None,
518
+ ):
519
+ self.name = value if value is not None else name
520
+ self.required = required
521
+ self.default = default
522
+
523
+
524
+ class ResponseStatus(SpringAnnotation):
525
+ _annotation_type = "response"
526
+
527
+ def __init__(self, code: int, reason: str = ""):
528
+ super().__init__(code=code, reason=reason)
529
+
530
+
531
+ class Transactional(SpringAnnotation):
532
+ _annotation_type = "aop"
533
+
534
+ def __init__(
535
+ self,
536
+ propagation: str = "REQUIRED",
537
+ rollback_for: Optional[List[Type[Exception]]] = None,
538
+ no_rollback_for: Optional[List[Type[Exception]]] = None,
539
+ ):
540
+ super().__init__(
541
+ propagation=propagation,
542
+ rollback_for=rollback_for or [],
543
+ no_rollback_for=no_rollback_for or [],
544
+ )
545
+
546
+
547
+ class Cacheable(SpringAnnotation):
548
+ _annotation_type = "aop"
549
+
550
+ def __init__(
551
+ self,
552
+ value: str,
553
+ key: Optional[str] = None,
554
+ condition: Optional[str] = None,
555
+ ):
556
+ super().__init__(value=value, key=key, condition=condition)
557
+
558
+
559
+ class Retryable(SpringAnnotation):
560
+ _annotation_type = "aop"
561
+
562
+ def __init__(
563
+ self,
564
+ value: Optional[Tuple[Type[Exception], ...]] = None,
565
+ max_retries: int = 3,
566
+ backoff: Optional[Union['Backoff', int, float]] = None,
567
+ exclude: Optional[Tuple[Type[Exception], ...]] = None,
568
+ recover: str = "",
569
+ max_attempts: Optional[int] = None,
570
+ ):
571
+ from spring.retry.retry_annotations import Backoff as RetryBackoff
572
+
573
+ if max_attempts is not None:
574
+ if max_retries != 3 and max_retries != max_attempts:
575
+ raise ValueError("max_retries 与 max_attempts 不能设置为不同值")
576
+ max_retries = max_attempts
577
+ if max_retries <= 0:
578
+ raise ValueError("max_retries 必须大于0")
579
+ if isinstance(backoff, (int, float)):
580
+ if backoff < 0:
581
+ raise ValueError("backoff 延迟不能小于0")
582
+ backoff = RetryBackoff(
583
+ delay=int(backoff),
584
+ max_delay=int(backoff),
585
+ multiplier=1.0,
586
+ random_factor=0.0,
587
+ )
588
+
589
+ super().__init__(
590
+ value=value or (Exception,),
591
+ max_retries=max_retries,
592
+ backoff=backoff or RetryBackoff(),
593
+ exclude=exclude or (),
594
+ recover=recover,
595
+ )
596
+
597
+
598
+ class Async(SpringAnnotation):
599
+ _annotation_type = "aop"
600
+
601
+ def __init__(self):
602
+ super().__init__()
603
+
604
+
605
+ class Scheduled(SpringAnnotation):
606
+ _annotation_type = "scheduling"
607
+
608
+ def __init__(
609
+ self,
610
+ fixed_rate: Optional[int] = None,
611
+ fixed_delay: Optional[int] = None,
612
+ cron: Optional[str] = None,
613
+ initial_delay: int = 0,
614
+ ):
615
+ configured = [fixed_rate is not None, fixed_delay is not None, cron is not None]
616
+ if sum(configured) != 1:
617
+ raise ValueError("Scheduled 必须且只能设置 fixed_rate、fixed_delay 或 cron 之一")
618
+ if fixed_rate is not None and fixed_rate <= 0:
619
+ raise ValueError("fixed_rate 必须大于0")
620
+ if fixed_delay is not None and fixed_delay <= 0:
621
+ raise ValueError("fixed_delay 必须大于0")
622
+ if initial_delay < 0:
623
+ raise ValueError("initial_delay 不能小于0")
624
+ super().__init__(
625
+ fixed_rate=fixed_rate,
626
+ fixed_delay=fixed_delay,
627
+ cron=cron,
628
+ initial_delay=initial_delay,
629
+ )
630
+
631
+
632
+ class AsyncResult(SpringAnnotation):
633
+ _annotation_type = "async"
634
+
635
+ def __init__(self, value: Any = None):
636
+ super().__init__(value=value)
637
+
638
+
639
+ # ==================== 进阶骚操作注解 ====================
640
+
641
+ class RateLimit(SpringAnnotation):
642
+ """接口限流注解"""
643
+ _annotation_type = "aop"
644
+
645
+ def __init__(
646
+ self,
647
+ max_requests: int = 100,
648
+ time_window: int = 60,
649
+ key: str = None,
650
+ ):
651
+ super().__init__(
652
+ max_requests=max_requests,
653
+ time_window=time_window,
654
+ key=key,
655
+ )
656
+
657
+
658
+ class CircuitBreaker(SpringAnnotation):
659
+ """熔断器注解"""
660
+ _annotation_type = "aop"
661
+
662
+ def __init__(
663
+ self,
664
+ failure_threshold: int = 5,
665
+ recovery_timeout: int = 30,
666
+ fallback_method: str = None,
667
+ ):
668
+ super().__init__(
669
+ failure_threshold=failure_threshold,
670
+ recovery_timeout=recovery_timeout,
671
+ fallback_method=fallback_method,
672
+ )
673
+
674
+
675
+ class Idempotent(SpringAnnotation):
676
+ """幂等性注解"""
677
+ _annotation_type = "aop"
678
+
679
+ def __init__(
680
+ self,
681
+ key: str = None,
682
+ expire: int = 300,
683
+ prefix: str = "idempotent",
684
+ ):
685
+ super().__init__(
686
+ key=key,
687
+ expire=expire,
688
+ prefix=prefix,
689
+ )
690
+
691
+
692
+ class AuditLog(SpringAnnotation):
693
+ """审计日志注解"""
694
+ _annotation_type = "aop"
695
+
696
+ def __init__(
697
+ self,
698
+ action: str = "",
699
+ target: str = "",
700
+ detail: str = "",
701
+ level: str = "INFO",
702
+ ):
703
+ super().__init__(
704
+ action=action,
705
+ target=target,
706
+ detail=detail,
707
+ level=level,
708
+ )
709
+
710
+
711
+ class FeatureToggle(SpringAnnotation):
712
+ """功能开关注解"""
713
+ _annotation_type = "aop"
714
+
715
+ def __init__(
716
+ self,
717
+ name: str,
718
+ default: bool = False,
719
+ ):
720
+ super().__init__(
721
+ name=name,
722
+ default=default,
723
+ )
724
+
725
+
726
+ class Lock(SpringAnnotation):
727
+ """分布式锁注解"""
728
+ _annotation_type = "aop"
729
+
730
+ def __init__(
731
+ self,
732
+ key: str = None,
733
+ expire: int = 10,
734
+ wait_timeout: int = 5,
735
+ prefix: str = "lock",
736
+ ):
737
+ super().__init__(
738
+ key=key,
739
+ expire=expire,
740
+ wait_timeout=wait_timeout,
741
+ prefix=prefix,
742
+ )
743
+
744
+
745
+ class Metrics(SpringAnnotation):
746
+ """指标监控注解"""
747
+ _annotation_type = "aop"
748
+
749
+ def __init__(
750
+ self,
751
+ name: str = None,
752
+ tags: List[str] = None,
753
+ ):
754
+ super().__init__(
755
+ name=name,
756
+ tags=tags or [],
757
+ )
758
+
759
+
760
+ class Synchronized(SpringAnnotation):
761
+ """方法同步注解"""
762
+ _annotation_type = "aop"
763
+
764
+ def __init__(
765
+ self,
766
+ lock_name: str = None,
767
+ ):
768
+ super().__init__(
769
+ lock_name=lock_name,
770
+ )
771
+
772
+
773
+ class Validate(SpringAnnotation):
774
+ """参数校验注解"""
775
+ _annotation_type = "param"
776
+
777
+ def __init__(
778
+ self,
779
+ field: str = None,
780
+ min_length: int = None,
781
+ max_length: int = None,
782
+ min: float = None,
783
+ max: float = None,
784
+ regex: str = None,
785
+ message: str = None,
786
+ ):
787
+ super().__init__(
788
+ field=field,
789
+ min_length=min_length,
790
+ max_length=max_length,
791
+ min=min,
792
+ max=max,
793
+ regex=regex,
794
+ message=message,
795
+ )
796
+
797
+
798
+ class Trace(SpringAnnotation):
799
+ """分布式追踪注解"""
800
+ _annotation_type = "aop"
801
+
802
+ def __init__(
803
+ self,
804
+ trace_id_key: str = "X-Trace-ID",
805
+ span_name: str = None,
806
+ ):
807
+ super().__init__(
808
+ trace_id_key=trace_id_key,
809
+ span_name=span_name,
810
+ )
811
+
812
+
813
+ # ==================== 安全注解 ====================
814
+
815
+ class PreAuthorize(SpringAnnotation):
816
+ """
817
+ 方法级权限控制注解
818
+ 支持表达式:
819
+ - hasRole('ROLE_ADMIN')
820
+ - hasAnyRole('ROLE_ADMIN', 'ROLE_USER')
821
+ - hasPermission('user:read')
822
+ - hasAnyPermission('user:read', 'user:write')
823
+
824
+ 使用示例:
825
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
826
+ def delete_user(self, user_id: int):
827
+ pass
828
+ """
829
+ _annotation_type = "security"
830
+
831
+ def __init__(self, value: str):
832
+ super().__init__(value=value)
833
+
834
+
835
+ class Secured(SpringAnnotation):
836
+ """
837
+ 角色权限控制注解
838
+ 检查当前用户是否拥有指定角色中的任一角色
839
+
840
+ 使用示例:
841
+ @Secured(["ROLE_ADMIN", "ROLE_USER"])
842
+ def update_user(self, user_id: int):
843
+ pass
844
+ """
845
+ _annotation_type = "security"
846
+
847
+ def __init__(self, value: List[str]):
848
+ super().__init__(value=value)
849
+
850
+
851
+ class Authenticate(SpringAnnotation):
852
+ """
853
+ 认证注解
854
+ 从请求头中获取 JWT Token 并验证,设置安全上下文
855
+
856
+ 使用示例:
857
+ @Authenticate
858
+ def get_user_profile(self):
859
+ pass
860
+ """
861
+ _annotation_type = "security"
862
+
863
+ def __init__(self):
864
+ super().__init__()