springbootAI 1.8.1__tar.gz → 1.8.2__tar.gz

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 (217) hide show
  1. {springbootai-1.8.1/springbootAI.egg-info → springbootai-1.8.2}/PKG-INFO +18 -13
  2. {springbootai-1.8.1 → springbootai-1.8.2}/README.md +17 -12
  3. {springbootai-1.8.1 → springbootai-1.8.2}/pyproject.toml +1 -1
  4. {springbootai-1.8.1 → springbootai-1.8.2}/spring/__init__.py +1 -1
  5. {springbootai-1.8.1 → springbootai-1.8.2}/spring/utils/__init__.py +2 -1
  6. springbootai-1.8.2/spring/utils/bean_utils.py +314 -0
  7. {springbootai-1.8.1 → springbootai-1.8.2/springbootAI.egg-info}/PKG-INFO +18 -13
  8. {springbootai-1.8.1 → springbootai-1.8.2}/springbootAI.egg-info/SOURCES.txt +2 -0
  9. springbootai-1.8.2/tests/test_bean_utils.py +316 -0
  10. {springbootai-1.8.1 → springbootai-1.8.2}/LICENSE +0 -0
  11. {springbootai-1.8.1 → springbootai-1.8.2}/MANIFEST.in +0 -0
  12. {springbootai-1.8.1 → springbootai-1.8.2}/requirements.txt +0 -0
  13. {springbootai-1.8.1 → springbootai-1.8.2}/setup.cfg +0 -0
  14. {springbootai-1.8.1 → springbootai-1.8.2}/setup.py +0 -0
  15. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/__init__.py +0 -0
  16. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/advisors.py +0 -0
  17. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/annotations.py +0 -0
  18. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/autoconfig.py +0 -0
  19. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/core.py +0 -0
  20. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/etl.py +0 -0
  21. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/memory.py +0 -0
  22. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/observability.py +0 -0
  23. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/providers.py +0 -0
  24. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/resilience.py +0 -0
  25. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/tools.py +0 -0
  26. {springbootai-1.8.1 → springbootai-1.8.2}/spring/ai/vectorstore.py +0 -0
  27. {springbootai-1.8.1 → springbootai-1.8.2}/spring/annotations/__init__.py +0 -0
  28. {springbootai-1.8.1 → springbootai-1.8.2}/spring/annotations/cache.py +0 -0
  29. {springbootai-1.8.1 → springbootai-1.8.2}/spring/annotations/cloud.py +0 -0
  30. {springbootai-1.8.1 → springbootai-1.8.2}/spring/annotations/conditional.py +0 -0
  31. {springbootai-1.8.1 → springbootai-1.8.2}/spring/annotations/core.py +0 -0
  32. {springbootai-1.8.1 → springbootai-1.8.2}/spring/annotations/messaging.py +0 -0
  33. {springbootai-1.8.1 → springbootai-1.8.2}/spring/aop/__init__.py +0 -0
  34. {springbootai-1.8.1 → springbootai-1.8.2}/spring/aop/cloud_aop.py +0 -0
  35. {springbootai-1.8.1 → springbootai-1.8.2}/spring/aop/comprehensive_aop.py +0 -0
  36. {springbootai-1.8.1 → springbootai-1.8.2}/spring/aop/method_interceptor.py +0 -0
  37. {springbootai-1.8.1 → springbootai-1.8.2}/spring/aop/proxy_factory.py +0 -0
  38. {springbootai-1.8.1 → springbootai-1.8.2}/spring/cloud/__init__.py +0 -0
  39. {springbootai-1.8.1 → springbootai-1.8.2}/spring/cloud/discovery.py +0 -0
  40. {springbootai-1.8.1 → springbootai-1.8.2}/spring/cloud/feign.py +0 -0
  41. {springbootai-1.8.1 → springbootai-1.8.2}/spring/cloud/gateway.py +0 -0
  42. {springbootai-1.8.1 → springbootai-1.8.2}/spring/cloud/load_balancer.py +0 -0
  43. {springbootai-1.8.1 → springbootai-1.8.2}/spring/cloud/seata.py +0 -0
  44. {springbootai-1.8.1 → springbootai-1.8.2}/spring/cloud/sentinel.py +0 -0
  45. {springbootai-1.8.1 → springbootai-1.8.2}/spring/cloud/tracer.py +0 -0
  46. {springbootai-1.8.1 → springbootai-1.8.2}/spring/config/__init__.py +0 -0
  47. {springbootai-1.8.1 → springbootai-1.8.2}/spring/config/binding.py +0 -0
  48. {springbootai-1.8.1 → springbootai-1.8.2}/spring/config/config_loader.py +0 -0
  49. {springbootai-1.8.1 → springbootai-1.8.2}/spring/context/__init__.py +0 -0
  50. {springbootai-1.8.1 → springbootai-1.8.2}/spring/context/application_context.py +0 -0
  51. {springbootai-1.8.1 → springbootai-1.8.2}/spring/context/bean_definition.py +0 -0
  52. {springbootai-1.8.1 → springbootai-1.8.2}/spring/context/bean_factory.py +0 -0
  53. {springbootai-1.8.1 → springbootai-1.8.2}/spring/context/registry.py +0 -0
  54. {springbootai-1.8.1 → springbootai-1.8.2}/spring/context/scanner.py +0 -0
  55. {springbootai-1.8.1 → springbootai-1.8.2}/spring/core/__init__.py +0 -0
  56. {springbootai-1.8.1 → springbootai-1.8.2}/spring/core/graceful_shutdown.py +0 -0
  57. {springbootai-1.8.1 → springbootai-1.8.2}/spring/core/typing_utils.py +0 -0
  58. {springbootai-1.8.1 → springbootai-1.8.2}/spring/csv/__init__.py +0 -0
  59. {springbootai-1.8.1 → springbootai-1.8.2}/spring/csv/annotations.py +0 -0
  60. {springbootai-1.8.1 → springbootai-1.8.2}/spring/csv/converters.py +0 -0
  61. {springbootai-1.8.1 → springbootai-1.8.2}/spring/csv/easy_csv.py +0 -0
  62. {springbootai-1.8.1 → springbootai-1.8.2}/spring/csv/exceptions.py +0 -0
  63. {springbootai-1.8.1 → springbootai-1.8.2}/spring/csv/reader.py +0 -0
  64. {springbootai-1.8.1 → springbootai-1.8.2}/spring/csv/writer.py +0 -0
  65. {springbootai-1.8.1 → springbootai-1.8.2}/spring/data/__init__.py +0 -0
  66. {springbootai-1.8.1 → springbootai-1.8.2}/spring/data/page.py +0 -0
  67. {springbootai-1.8.1 → springbootai-1.8.2}/spring/data/repository.py +0 -0
  68. {springbootai-1.8.1 → springbootai-1.8.2}/spring/data/specification.py +0 -0
  69. {springbootai-1.8.1 → springbootai-1.8.2}/spring/datasource/__init__.py +0 -0
  70. {springbootai-1.8.1 → springbootai-1.8.2}/spring/datasource/annotations.py +0 -0
  71. {springbootai-1.8.1 → springbootai-1.8.2}/spring/datasource/context.py +0 -0
  72. {springbootai-1.8.1 → springbootai-1.8.2}/spring/datasource/dynamic.py +0 -0
  73. {springbootai-1.8.1 → springbootai-1.8.2}/spring/event/__init__.py +0 -0
  74. {springbootai-1.8.1 → springbootai-1.8.2}/spring/event/publisher.py +0 -0
  75. {springbootai-1.8.1 → springbootai-1.8.2}/spring/excel/__init__.py +0 -0
  76. {springbootai-1.8.1 → springbootai-1.8.2}/spring/excel/annotations.py +0 -0
  77. {springbootai-1.8.1 → springbootai-1.8.2}/spring/excel/converters.py +0 -0
  78. {springbootai-1.8.1 → springbootai-1.8.2}/spring/excel/easy_excel.py +0 -0
  79. {springbootai-1.8.1 → springbootai-1.8.2}/spring/excel/exceptions.py +0 -0
  80. {springbootai-1.8.1 → springbootai-1.8.2}/spring/excel/reader.py +0 -0
  81. {springbootai-1.8.1 → springbootai-1.8.2}/spring/excel/style.py +0 -0
  82. {springbootai-1.8.1 → springbootai-1.8.2}/spring/excel/writer.py +0 -0
  83. {springbootai-1.8.1 → springbootai-1.8.2}/spring/i18n/__init__.py +0 -0
  84. {springbootai-1.8.1 → springbootai-1.8.2}/spring/i18n/accessor.py +0 -0
  85. {springbootai-1.8.1 → springbootai-1.8.2}/spring/i18n/auto_config.py +0 -0
  86. {springbootai-1.8.1 → springbootai-1.8.2}/spring/i18n/holder.py +0 -0
  87. {springbootai-1.8.1 → springbootai-1.8.2}/spring/i18n/locale.py +0 -0
  88. {springbootai-1.8.1 → springbootai-1.8.2}/spring/i18n/locale_resolver.py +0 -0
  89. {springbootai-1.8.1 → springbootai-1.8.2}/spring/i18n/message_source.py +0 -0
  90. {springbootai-1.8.1 → springbootai-1.8.2}/spring/i18n/middleware.py +0 -0
  91. {springbootai-1.8.1 → springbootai-1.8.2}/spring/i18n/properties.py +0 -0
  92. {springbootai-1.8.1 → springbootai-1.8.2}/spring/i18n/sources.py +0 -0
  93. {springbootai-1.8.1 → springbootai-1.8.2}/spring/logging/__init__.py +0 -0
  94. {springbootai-1.8.1 → springbootai-1.8.2}/spring/logging/loguru_logger.py +0 -0
  95. {springbootai-1.8.1 → springbootai-1.8.2}/spring/main.py +0 -0
  96. {springbootai-1.8.1 → springbootai-1.8.2}/spring/messaging/__init__.py +0 -0
  97. {springbootai-1.8.1 → springbootai-1.8.2}/spring/messaging/rabbitmq.py +0 -0
  98. {springbootai-1.8.1 → springbootai-1.8.2}/spring/monitoring/__init__.py +0 -0
  99. {springbootai-1.8.1 → springbootai-1.8.2}/spring/monitoring/prometheus.py +0 -0
  100. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/__init__.py +0 -0
  101. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/database.py +0 -0
  102. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/ddl_auto.py +0 -0
  103. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/migration.py +0 -0
  104. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/mybatis_integration.py +0 -0
  105. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/__init__.py +0 -0
  106. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/annotations/__init__.py +0 -0
  107. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/annotations/annotations.py +0 -0
  108. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/cache/__init__.py +0 -0
  109. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/cache/cache.py +0 -0
  110. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/cache/redis_cache.py +0 -0
  111. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/circuit_breaker/__init__.py +0 -0
  112. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/circuit_breaker/circuit_breaker.py +0 -0
  113. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/configuration.py +0 -0
  114. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/core/__init__.py +0 -0
  115. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/core/sql_session.py +0 -0
  116. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/core/sql_session_factory.py +0 -0
  117. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/dialect/__init__.py +0 -0
  118. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/dialect/dialect.py +0 -0
  119. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/dynamic_sql/__init__.py +0 -0
  120. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/dynamic_sql/dynamic_sql.py +0 -0
  121. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/interceptor/__init__.py +0 -0
  122. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/interceptor/interceptor.py +0 -0
  123. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/mapper/__init__.py +0 -0
  124. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/mapper/mapper.py +0 -0
  125. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/metrics/__init__.py +0 -0
  126. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/metrics/metrics.py +0 -0
  127. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/pool/__init__.py +0 -0
  128. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/pool/connection_pool.py +0 -0
  129. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/security/__init__.py +0 -0
  130. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/security/access_control.py +0 -0
  131. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/security/password_encoder.py +0 -0
  132. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/security/sensitive_data_masker.py +0 -0
  133. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/security/sql_injection_detector.py +0 -0
  134. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/transaction/__init__.py +0 -0
  135. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/transaction/transaction.py +0 -0
  136. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/type_handler/__init__.py +0 -0
  137. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/type_handler/type_handler.py +0 -0
  138. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/version.py +0 -0
  139. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/xml_parser/__init__.py +0 -0
  140. {springbootai-1.8.1 → springbootai-1.8.2}/spring/orm/pymybatis/xml_parser/xml_parser.py +0 -0
  141. {springbootai-1.8.1 → springbootai-1.8.2}/spring/retry/__init__.py +0 -0
  142. {springbootai-1.8.1 → springbootai-1.8.2}/spring/retry/retry_annotations.py +0 -0
  143. {springbootai-1.8.1 → springbootai-1.8.2}/spring/retry/retry_decorator.py +0 -0
  144. {springbootai-1.8.1 → springbootai-1.8.2}/spring/scheduling/__init__.py +0 -0
  145. {springbootai-1.8.1 → springbootai-1.8.2}/spring/scheduling/scheduler.py +0 -0
  146. {springbootai-1.8.1 → springbootai-1.8.2}/spring/security/__init__.py +0 -0
  147. {springbootai-1.8.1 → springbootai-1.8.2}/spring/security/jwt_utils.py +0 -0
  148. {springbootai-1.8.1 → springbootai-1.8.2}/spring/security/replay_protection.py +0 -0
  149. {springbootai-1.8.1 → springbootai-1.8.2}/spring/security/secret_manager.py +0 -0
  150. {springbootai-1.8.1 → springbootai-1.8.2}/spring/security/security_aop.py +0 -0
  151. {springbootai-1.8.1 → springbootai-1.8.2}/spring/security/security_context.py +0 -0
  152. {springbootai-1.8.1 → springbootai-1.8.2}/spring/test/__init__.py +0 -0
  153. {springbootai-1.8.1 → springbootai-1.8.2}/spring/test/slicing.py +0 -0
  154. {springbootai-1.8.1 → springbootai-1.8.2}/spring/tracing/__init__.py +0 -0
  155. {springbootai-1.8.1 → springbootai-1.8.2}/spring/tracing/skywalking.py +0 -0
  156. {springbootai-1.8.1 → springbootai-1.8.2}/spring/tx/__init__.py +0 -0
  157. {springbootai-1.8.1 → springbootai-1.8.2}/spring/tx/events.py +0 -0
  158. {springbootai-1.8.1 → springbootai-1.8.2}/spring/tx/synchronization.py +0 -0
  159. {springbootai-1.8.1 → springbootai-1.8.2}/spring/utils/banner.py +0 -0
  160. {springbootai-1.8.1 → springbootai-1.8.2}/spring/utils/logger.py +0 -0
  161. {springbootai-1.8.1 → springbootai-1.8.2}/spring/utils/redis_client.py +0 -0
  162. {springbootai-1.8.1 → springbootai-1.8.2}/spring/validation/__init__.py +0 -0
  163. {springbootai-1.8.1 → springbootai-1.8.2}/spring/validation/aop.py +0 -0
  164. {springbootai-1.8.1 → springbootai-1.8.2}/spring/validation/constraints.py +0 -0
  165. {springbootai-1.8.1 → springbootai-1.8.2}/spring/validation/exceptions.py +0 -0
  166. {springbootai-1.8.1 → springbootai-1.8.2}/spring/validation/validator.py +0 -0
  167. {springbootai-1.8.1 → springbootai-1.8.2}/spring/web/__init__.py +0 -0
  168. {springbootai-1.8.1 → springbootai-1.8.2}/spring/web/actuator.py +0 -0
  169. {springbootai-1.8.1 → springbootai-1.8.2}/spring/web/exception_handler.py +0 -0
  170. {springbootai-1.8.1 → springbootai-1.8.2}/spring/web/health.py +0 -0
  171. {springbootai-1.8.1 → springbootai-1.8.2}/spring/web/interceptor.py +0 -0
  172. {springbootai-1.8.1 → springbootai-1.8.2}/spring/web/result.py +0 -0
  173. {springbootai-1.8.1 → springbootai-1.8.2}/spring/web/swagger.py +0 -0
  174. {springbootai-1.8.1 → springbootai-1.8.2}/spring/web/web_context.py +0 -0
  175. {springbootai-1.8.1 → springbootai-1.8.2}/spring/websocket/__init__.py +0 -0
  176. {springbootai-1.8.1 → springbootai-1.8.2}/spring/websocket/annotations.py +0 -0
  177. {springbootai-1.8.1 → springbootai-1.8.2}/spring/websocket/broker.py +0 -0
  178. {springbootai-1.8.1 → springbootai-1.8.2}/spring/websocket/exceptions.py +0 -0
  179. {springbootai-1.8.1 → springbootai-1.8.2}/spring/websocket/handler.py +0 -0
  180. {springbootai-1.8.1 → springbootai-1.8.2}/spring/websocket/router.py +0 -0
  181. {springbootai-1.8.1 → springbootai-1.8.2}/spring/websocket/session.py +0 -0
  182. {springbootai-1.8.1 → springbootai-1.8.2}/springbootAI.egg-info/dependency_links.txt +0 -0
  183. {springbootai-1.8.1 → springbootai-1.8.2}/springbootAI.egg-info/entry_points.txt +0 -0
  184. {springbootai-1.8.1 → springbootai-1.8.2}/springbootAI.egg-info/requires.txt +0 -0
  185. {springbootai-1.8.1 → springbootai-1.8.2}/springbootAI.egg-info/top_level.txt +0 -0
  186. {springbootai-1.8.1 → springbootai-1.8.2}/sql/seata_undo_log.sql +0 -0
  187. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_actuator.py +0 -0
  188. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_ai_module.py +0 -0
  189. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_annotation_combinations.py +0 -0
  190. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_annotations_contract.py +0 -0
  191. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_aop_annotations_full.py +0 -0
  192. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_cache_annotations.py +0 -0
  193. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_cloud_embedded_full.py +0 -0
  194. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_conditional_annotations.py +0 -0
  195. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_config_binding.py +0 -0
  196. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_connection_resilience.py +0 -0
  197. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_core_annotations_full.py +0 -0
  198. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_csv_module.py +0 -0
  199. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_data_repository.py +0 -0
  200. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_datasource_routing.py +0 -0
  201. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_ddl_auto.py +0 -0
  202. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_di_config_event_full.py +0 -0
  203. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_excel_module.py +0 -0
  204. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_i18n_module.py +0 -0
  205. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_jpa_version_transient.py +0 -0
  206. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_new_features.py +0 -0
  207. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_orm_pymybatis_full.py +0 -0
  208. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_production_readiness.py +0 -0
  209. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_pymybatis_contract.py +0 -0
  210. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_security.py +0 -0
  211. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_security_full.py +0 -0
  212. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_swagger_module.py +0 -0
  213. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_test_slicing.py +0 -0
  214. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_transactional_events.py +0 -0
  215. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_validation_module.py +0 -0
  216. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_web_annotations_full.py +0 -0
  217. {springbootai-1.8.1 → springbootai-1.8.2}/tests/test_websocket_module.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: springbootAI
3
- Version: 1.8.1
3
+ Version: 1.8.2
4
4
  Summary: Python版Spring Boot框架,集成PyMyBatis ORM
5
5
  Author-email: YuConggen <1516933915@qq.com>
6
6
  License-Expression: MIT
@@ -86,7 +86,7 @@ Dynamic: license-file
86
86
 
87
87
  SpringBootAI 是一个借鉴 Spring Boot 编程模型的 Python Web 框架,提供装饰器式组件扫描、依赖注入、FastAPI 路由、配置加载、安全能力、内嵌的 PyMyBatis ORM,以及企业级 AI 模块(对齐 Spring AI 2.0:ChatClient/Advisor/Tools/RAG/Function Calling)。本指南为框架核心综合使用文档;**AI / ORM / Cloud / Excel 等模块的完整注解与功能说明已分离为独立文档**(见下方“模块文档”),本指南相应章节保留概览与跳转链接。
88
88
 
89
- - SpringBootAI 版本:`1.8.1`
89
+ - SpringBootAI 版本:`1.8.2`
90
90
  - 内嵌 PyMyBatis 版本:`1.4.0`
91
91
  - Python:3.10+
92
92
  - 状态:Beta(企业试点)
@@ -107,6 +107,7 @@ SpringBootAI 是一个借鉴 Spring Boot 编程模型的 Python Web 框架,提
107
107
  | Swagger / OpenAPI(对齐 SpringDoc) | [SWAGGER_MODULE.md](doc/SWAGGER_MODULE.md) | 随核心包 | `@Tag` / `@Operation` / `@ApiResponse` / `@Parameter` / `@Schema` / `@SecurityScheme` 注解驱动 API 文档 + Swagger2 别名 |
108
108
  | P0/P1/P2 八大模块 | [EIGHT_MODULES.md](doc/EIGHT_MODULES.md) | 随核心包 | Spring Data Repository / Actuator / 多数据源读写分离 / 事务事件 / 配置松散绑定 / 测试切片 / i18n / WebSocket |
109
109
  | 安全 | [SECURITY.md](doc/SECURITY.md) | 随核心包 | JWT 生成校验 / 密码加密(SHA256/MD5/BCrypt)/ SQL 注入防护 / 访问控制 |
110
+ | BeanUtils(属性复制工具) | [BEAN_UTILS.md](doc/BEAN_UTILS.md) | 随核心包 | `copy_properties` / `clone` / `get_property` / `set_property` / `populate` / `describe` 对齐 Spring + Apache Commons BeanUtils |
110
111
  | 测试报告 | [TEST_REPORT.md](doc/TEST_REPORT.md) | — | 全量测试用例与覆盖范围 |
111
112
 
112
113
  > 所有模块文档统一存放于 [`doc/`](doc/) 目录。本指南正文中出现的"已分离至独立文档"链接均指向 `doc/` 下的对应文件。
@@ -142,7 +143,7 @@ SpringBootAI 借鉴了 Spring Boot 的注解和分层习惯,但运行时是 Py
142
143
 
143
144
  | 组件 | 当前版本 |
144
145
  |------|----------|
145
- | `spring` 框架 API | 1.8.0 |
146
+ | `spring` 框架 API | 1.8.2 |
146
147
  | `spring.orm.pymybatis` | 1.4.0 |
147
148
  | Python | 3.10+ |
148
149
 
@@ -158,7 +159,7 @@ SpringBootAI 借鉴了 Spring Boot 的注解和分层习惯,但运行时是 Py
158
159
  - 自动化 ORM 契约测试使用 SQLite;MySQL、PostgreSQL、Oracle 需单独验证。
159
160
  - 本地 `@Transactional` 支持全部七种 Spring 传播模式;`REQUIRES_NEW` 和 `NOT_SUPPORTED` 需要连接池有额外可用连接。
160
161
  - Profile 会筛选 `@Profile` Bean,但不会自动合并 `application-{profile}.yml`。
161
- - Nacos、RabbitMQ、Prometheus 依赖外部服务;SentinelSeata HTTP-AT、OpenTelemetry 追踪均已内嵌实现无需外部 Server
162
+ - Nacos、RabbitMQ、Prometheus 依赖外部服务;Sentinel 和 OpenTelemetry 追踪可内嵌运行。HTTP 事务模式是持久化补偿协调器,不提供 Seata AT 强一致性;生产强一致场景必须使用真实 Seata Server 或可靠消息方案。
162
163
  - 限流、分布式锁、幂等和缓存语义依赖 Redis 等后端,降级路径需要故障注入。
163
164
 
164
165
  ### 1.4 注解使用总览
@@ -193,7 +194,7 @@ SpringBootAI 注解会先把元数据放到 `__spring_annotations__`。之后是
193
194
  | Nacos 服务发现 | ✅ 可用 | 服务注册/发现/订阅,支持无认证开发模式 |
194
195
  | Sentinel 限流熔断 | ✅ 可用 | 内嵌引擎,QPS 限流、异常比例/异常数/慢调用熔断、热点参数限流,无需 Dashboard |
195
196
  | 分布式追踪 | ✅ 可用 | 原生 OpenTelemetry(W3C traceparent),自动 HTTP/Feign 注入,无需 OAP Server |
196
- | Seata 分布式事务 | 可用 | 内嵌 HTTP-AT 模式,分支注册/提交/回滚,XID 自动传播,无需 Seata Server |
197
+ | Seata 分布式事务 | ⚠️ 有边界 | `distributed` 对接真实 Seata SDK/Server;`http` 仅提供显式启用的持久化补偿,支持重启恢复和 XID 传播,不等同 AT |
197
198
  | API Gateway | ✅ 可用 | 轻量 ASGI/WSGI 网关,路由转发、路径重写、过滤器链、负载均衡 |
198
199
  | Prometheus 监控 | ✅ 可用 | Counter/Gauge/Histogram 指标暴露 |
199
200
  | Feign 声明式 HTTP | ✅ 可用 | 声明式接口、Fallback 降级、自动传播 XID 和 trace 头 |
@@ -1491,7 +1492,7 @@ class ScheduledTasks:
1491
1492
  | `@SentinelResource` | 限流、业务异常 fallback | 受管 Bean 方法会包装;已内嵌限流熔断引擎,无需 Sentinel Dashboard |
1492
1493
  | `@EnableGateway` | 启用 API Gateway | 元数据标记;配合 `GatewayRouter` 使用,内嵌轻量 ASGI/WSGI 网关 |
1493
1494
  | `@LoadBalanced` | 给 `@Bean` 工厂返回对象添加负载均衡标记 | `@Bean` 方法上会执行,但实际请求仍需配合框架负载均衡客户端 |
1494
- | `@GlobalTransactional` | 通过 Seata 管理全局事务 | 受管 Bean 方法会调用 Seata manager;已内嵌 HTTP-AT 模式,XID 自动通过 Feign 传播;不支持嵌套 |
1495
+ | `@GlobalTransactional` | 通过 Seata 管理全局事务 | 受管 Bean 方法调用 Seata managerHTTP 模式为持久化补偿且要求幂等回调,强一致生产场景使用 `distributed`;不支持嵌套 |
1495
1496
  | `@Valid` | 非空/嵌套对象基础检查 | 受管 Bean 方法会执行简化校验,不等同 Jakarta Bean Validation |
1496
1497
  | `@Validated` | 分组校验 | 会执行简化检查,但 `groups` 当前未驱动真正的分组规则 |
1497
1498
  | `@RabbitListener` | 注册 RabbitMQ 消费者 | 可直接装饰受管 Bean 方法;容器声明队列/交换机、注册回调,并在刷新后启动后台消费;支持同步和异步回调 |
@@ -2018,7 +2019,7 @@ class CleanupJob:
2018
2019
 
2019
2020
  `@SentinelResource`、`@GlobalTransactional` 和方法级 `@LoadBalanced` 有 AOP 消费路径;`@EnableDiscoveryClient`、`@FeignClient` 等当前主要是元数据,Nacos 实际初始化由 `discovery.enabled` 和 `ApplicationContext` 启动流程控制。Nacos 客户端需要 `nacos-sdk-python`、`NACOS_SERVER`、`NACOS_USERNAME`、`NACOS_PASSWORD`;Nacos 2.2+ Docker 服务端还需要 Base64 token 和 identity 环境变量。
2020
2021
 
2021
- 配置 `rabbitmq.enabled: true` 并提供 host、port、username、password、virtual_host。开发环境也应在真实 Nacos、RabbitMQ、Redis 等环境执行集成、断线和重复投递测试。Sentinel、Seata HTTP-AT、OpenTelemetry 追踪、API Gateway 均已内嵌实现,无需外部 Server。
2022
+ 配置 `rabbitmq.enabled: true` 并提供 host、port、username、password、virtual_host。开发环境也应在真实 Nacos、RabbitMQ、Redis 等环境执行集成、断线和重复投递测试。HTTP 事务模式会将协调元数据写入 `seata.store_path`,并在 worker 启动后周期恢复;它是补偿事务,不是 Seata AT,也不能单独满足支付、订单、库存的一致性要求。
2022
2023
 
2023
2024
  ---
2024
2025
 
@@ -2228,7 +2229,7 @@ class UserMapper:
2228
2229
  | `@LoadBalanced` | 同名注解 | 使用 Python 负载均衡实现;不要复用 `RestTemplate` 用法 |
2229
2230
  | Sentinel `@SentinelResource` | 同名注解 | 已内嵌限流熔断引擎,无需 Dashboard;如需更强大治理能力可对接外部 Sentinel Dashboard |
2230
2231
  | Spring Cloud Gateway | `@EnableGateway` + `GatewayRouter` | 内嵌轻量 ASGI/WSGI 网关;复杂网关需求可使用 Kong/APISIX 等专业网关 |
2231
- | Seata `@GlobalTransactional` | 同名注解 | 已内嵌 HTTP-AT 模式,无需 Seata Server,XID 自动通过 Feign 传播;如需更强一致性保障可对接外部 Seata Server |
2232
+ | Seata `@GlobalTransactional` | 同名注解 | `http` 模式是持久化补偿协调器,依赖幂等分支回调;企业强一致场景必须配置真实 Seata Server 与兼容 SDK |
2232
2233
 
2233
2234
  **Cloud 高级功能迁移对照**:
2234
2235
 
@@ -2236,7 +2237,7 @@ class UserMapper:
2236
2237
  |---|---|---|
2237
2238
  | Sentinel Dashboard + `@SentinelResource` | `@SentinelResource` | 内嵌引擎,无需 Dashboard;支持 QPS 限流、异常比例/异常数/慢调用熔断、热点参数限流 |
2238
2239
  | SkyWalking Agent + OAP Server | `@Trace` + 内嵌 Tracer | 原生 OpenTelemetry(W3C traceparent),无需 OAP Server;自动注入 HTTP/Feign 追踪头 |
2239
- | Seata Server + `@GlobalTransactional` | `@GlobalTransactional` | 内嵌 HTTP-AT 模式,无需 Seata Server;支持分支注册/提交/回滚,XID 自动传播 |
2240
+ | Seata Server + `@GlobalTransactional` | `@GlobalTransactional` | `distributed` 模式对接 Seata Server;`http` 仅用于补偿流程和故障演练,不提供 AT 语义 |
2240
2241
  | Spring Cloud Gateway | `GatewayRouter` | 轻量 ASGI/WSGI 网关,支持路由转发、路径重写、过滤器链、负载均衡 |
2241
2242
  | JPA `hibernate.ddl-auto` | `@entity` + `ddl-auto` 配置 | 支持 create/update/validate/create-drop;自动扫描实体包,自动建表/添加列/创建索引 |
2242
2243
 
@@ -2322,7 +2323,7 @@ Java 的 profile 文件自动合并不是当前功能。部署流程应生成最
2322
2323
  4. 用目标 MySQL/PostgreSQL/Oracle 版本执行相同测试,特别验证自增主键、事务隔离、超时和连接中断。
2323
2324
  5. 启动 ASGI 应用,检查 `/docs`、`/actuator/health/liveness` 和 `/actuator/health/readiness`。
2324
2325
  6. 接入 Nacos、RabbitMQ、Redis 等外部中间件,并演练断线、重复投递和回滚。
2325
- 7. 验证内嵌 Cloud 功能:`@SentinelResource` 限流熔断、`@Trace` 追踪、`@GlobalTransactional` 分布式事务、`GatewayRouter` 网关、`@entity` + `ddl-auto` 自动建表。这些功能无需部署外部 Server,但应在真实流量和故障注入下验证。
2326
+ 7. 验证 Cloud 功能:`@SentinelResource` 限流熔断、`@Trace` 追踪、`@GlobalTransactional` 补偿流程、`GatewayRouter` 网关、`@entity` + `ddl-auto` 自动建表。HTTP 补偿模式必须验证重复回调、进程重启和部分失败;强一致事务需部署真实 Seata Server 并执行集成测试。
2326
2327
 
2327
2328
  ---
2328
2329
 
@@ -2446,9 +2447,13 @@ logging:
2446
2447
  | `DISCOVERY_ENABLED` | 是否启用 Nacos 服务发现 | false |
2447
2448
  | `NACOS_SERVER` | Nacos 地址 | localhost:8848 |
2448
2449
  | `NACOS_USERNAME` / `NACOS_PASSWORD` | Nacos 客户端账号/密码 | 空 |
2450
+ | `SEATA_HTTP_STORE_PATH` | HTTP 补偿协调 SQLite 文件路径(同主机多 worker 共享) | `./data/seata-http.sqlite3` |
2451
+ | `SEATA_HTTP_RECOVER_ON_STARTUP` | 初始化时扫描并恢复未完成补偿 | true |
2452
+ | `SEATA_HTTP_RECOVERY_GRACE_MS` | 接管其他 worker 的 COMMITTING/ROLLING_BACK 前等待时间 | 30000 |
2453
+ | `SEATA_HTTP_RECOVERY_INTERVAL_S` | worker 内周期恢复间隔,0 表示关闭 | 30 |
2449
2454
  | `SPRING_DISABLE_DOCKER_IP_DETECT` | 设为 1 禁用 Docker 容器 IP 自动检测 | 0 |
2450
2455
 
2451
- > Sentinel、OpenTelemetry 追踪、Seata HTTP-AT、API Gateway 已内嵌实现,没有对应环境变量。
2456
+ > HTTP 补偿模式使用 `SEATA_HTTP_*` 配置,仍不提供 Seata AT;生产强一致事务必须配置 `SEATA_MODE=distributed`、真实 Server 和兼容 SDK。
2452
2457
 
2453
2458
  ### 14.5 启动应用
2454
2459
 
@@ -2526,7 +2531,7 @@ curl http://localhost:8080/actuator/health
2526
2531
  }
2527
2532
  ```
2528
2533
 
2529
- > Sentinel、OpenTelemetry 追踪、Seata HTTP-AT、API Gateway 已内嵌实现,不属于外部依赖组件,因此不显示在聚合健康检查中;可通过应用日志或 `@SentinelResource`、`@Trace`、`@GlobalTransactional` 注解的实际调用验证。
2534
+ > Sentinel、OpenTelemetry 追踪和 API Gateway 可内嵌运行;HTTP 补偿协调器的未完成事务会纳入恢复日志。它不属于强一致外部事务协调器,不能替代 Seata Server。
2530
2535
 
2531
2536
  ### 14.7 部署故障排查
2532
2537
 
@@ -2751,7 +2756,7 @@ export LOG_LEVEL=INFO
2751
2756
  export LOG_DIR=logs
2752
2757
  ```
2753
2758
 
2754
- > Sentinel 限流熔断、OpenTelemetry 分布式追踪、Seata HTTP-AT 分布式事务、API Gateway 均为内嵌实现,无对应环境变量。AI 模块环境变量见第 12.2 节。
2759
+ > Sentinel 限流熔断、OpenTelemetry 分布式追踪和 API Gateway 可内嵌实现;HTTP 补偿事务通过 `SEATA_HTTP_*` 配置。AI 模块环境变量见第 12.2 节。
2755
2760
 
2756
2761
  ## 附录 B:Docker Compose 示例
2757
2762
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  SpringBootAI 是一个借鉴 Spring Boot 编程模型的 Python Web 框架,提供装饰器式组件扫描、依赖注入、FastAPI 路由、配置加载、安全能力、内嵌的 PyMyBatis ORM,以及企业级 AI 模块(对齐 Spring AI 2.0:ChatClient/Advisor/Tools/RAG/Function Calling)。本指南为框架核心综合使用文档;**AI / ORM / Cloud / Excel 等模块的完整注解与功能说明已分离为独立文档**(见下方“模块文档”),本指南相应章节保留概览与跳转链接。
4
4
 
5
- - SpringBootAI 版本:`1.8.1`
5
+ - SpringBootAI 版本:`1.8.2`
6
6
  - 内嵌 PyMyBatis 版本:`1.4.0`
7
7
  - Python:3.10+
8
8
  - 状态:Beta(企业试点)
@@ -23,6 +23,7 @@ SpringBootAI 是一个借鉴 Spring Boot 编程模型的 Python Web 框架,提
23
23
  | Swagger / OpenAPI(对齐 SpringDoc) | [SWAGGER_MODULE.md](doc/SWAGGER_MODULE.md) | 随核心包 | `@Tag` / `@Operation` / `@ApiResponse` / `@Parameter` / `@Schema` / `@SecurityScheme` 注解驱动 API 文档 + Swagger2 别名 |
24
24
  | P0/P1/P2 八大模块 | [EIGHT_MODULES.md](doc/EIGHT_MODULES.md) | 随核心包 | Spring Data Repository / Actuator / 多数据源读写分离 / 事务事件 / 配置松散绑定 / 测试切片 / i18n / WebSocket |
25
25
  | 安全 | [SECURITY.md](doc/SECURITY.md) | 随核心包 | JWT 生成校验 / 密码加密(SHA256/MD5/BCrypt)/ SQL 注入防护 / 访问控制 |
26
+ | BeanUtils(属性复制工具) | [BEAN_UTILS.md](doc/BEAN_UTILS.md) | 随核心包 | `copy_properties` / `clone` / `get_property` / `set_property` / `populate` / `describe` 对齐 Spring + Apache Commons BeanUtils |
26
27
  | 测试报告 | [TEST_REPORT.md](doc/TEST_REPORT.md) | — | 全量测试用例与覆盖范围 |
27
28
 
28
29
  > 所有模块文档统一存放于 [`doc/`](doc/) 目录。本指南正文中出现的"已分离至独立文档"链接均指向 `doc/` 下的对应文件。
@@ -58,7 +59,7 @@ SpringBootAI 借鉴了 Spring Boot 的注解和分层习惯,但运行时是 Py
58
59
 
59
60
  | 组件 | 当前版本 |
60
61
  |------|----------|
61
- | `spring` 框架 API | 1.8.0 |
62
+ | `spring` 框架 API | 1.8.2 |
62
63
  | `spring.orm.pymybatis` | 1.4.0 |
63
64
  | Python | 3.10+ |
64
65
 
@@ -74,7 +75,7 @@ SpringBootAI 借鉴了 Spring Boot 的注解和分层习惯,但运行时是 Py
74
75
  - 自动化 ORM 契约测试使用 SQLite;MySQL、PostgreSQL、Oracle 需单独验证。
75
76
  - 本地 `@Transactional` 支持全部七种 Spring 传播模式;`REQUIRES_NEW` 和 `NOT_SUPPORTED` 需要连接池有额外可用连接。
76
77
  - Profile 会筛选 `@Profile` Bean,但不会自动合并 `application-{profile}.yml`。
77
- - Nacos、RabbitMQ、Prometheus 依赖外部服务;SentinelSeata HTTP-AT、OpenTelemetry 追踪均已内嵌实现无需外部 Server
78
+ - Nacos、RabbitMQ、Prometheus 依赖外部服务;Sentinel 和 OpenTelemetry 追踪可内嵌运行。HTTP 事务模式是持久化补偿协调器,不提供 Seata AT 强一致性;生产强一致场景必须使用真实 Seata Server 或可靠消息方案。
78
79
  - 限流、分布式锁、幂等和缓存语义依赖 Redis 等后端,降级路径需要故障注入。
79
80
 
80
81
  ### 1.4 注解使用总览
@@ -109,7 +110,7 @@ SpringBootAI 注解会先把元数据放到 `__spring_annotations__`。之后是
109
110
  | Nacos 服务发现 | ✅ 可用 | 服务注册/发现/订阅,支持无认证开发模式 |
110
111
  | Sentinel 限流熔断 | ✅ 可用 | 内嵌引擎,QPS 限流、异常比例/异常数/慢调用熔断、热点参数限流,无需 Dashboard |
111
112
  | 分布式追踪 | ✅ 可用 | 原生 OpenTelemetry(W3C traceparent),自动 HTTP/Feign 注入,无需 OAP Server |
112
- | Seata 分布式事务 | 可用 | 内嵌 HTTP-AT 模式,分支注册/提交/回滚,XID 自动传播,无需 Seata Server |
113
+ | Seata 分布式事务 | ⚠️ 有边界 | `distributed` 对接真实 Seata SDK/Server;`http` 仅提供显式启用的持久化补偿,支持重启恢复和 XID 传播,不等同 AT |
113
114
  | API Gateway | ✅ 可用 | 轻量 ASGI/WSGI 网关,路由转发、路径重写、过滤器链、负载均衡 |
114
115
  | Prometheus 监控 | ✅ 可用 | Counter/Gauge/Histogram 指标暴露 |
115
116
  | Feign 声明式 HTTP | ✅ 可用 | 声明式接口、Fallback 降级、自动传播 XID 和 trace 头 |
@@ -1407,7 +1408,7 @@ class ScheduledTasks:
1407
1408
  | `@SentinelResource` | 限流、业务异常 fallback | 受管 Bean 方法会包装;已内嵌限流熔断引擎,无需 Sentinel Dashboard |
1408
1409
  | `@EnableGateway` | 启用 API Gateway | 元数据标记;配合 `GatewayRouter` 使用,内嵌轻量 ASGI/WSGI 网关 |
1409
1410
  | `@LoadBalanced` | 给 `@Bean` 工厂返回对象添加负载均衡标记 | `@Bean` 方法上会执行,但实际请求仍需配合框架负载均衡客户端 |
1410
- | `@GlobalTransactional` | 通过 Seata 管理全局事务 | 受管 Bean 方法会调用 Seata manager;已内嵌 HTTP-AT 模式,XID 自动通过 Feign 传播;不支持嵌套 |
1411
+ | `@GlobalTransactional` | 通过 Seata 管理全局事务 | 受管 Bean 方法调用 Seata managerHTTP 模式为持久化补偿且要求幂等回调,强一致生产场景使用 `distributed`;不支持嵌套 |
1411
1412
  | `@Valid` | 非空/嵌套对象基础检查 | 受管 Bean 方法会执行简化校验,不等同 Jakarta Bean Validation |
1412
1413
  | `@Validated` | 分组校验 | 会执行简化检查,但 `groups` 当前未驱动真正的分组规则 |
1413
1414
  | `@RabbitListener` | 注册 RabbitMQ 消费者 | 可直接装饰受管 Bean 方法;容器声明队列/交换机、注册回调,并在刷新后启动后台消费;支持同步和异步回调 |
@@ -1934,7 +1935,7 @@ class CleanupJob:
1934
1935
 
1935
1936
  `@SentinelResource`、`@GlobalTransactional` 和方法级 `@LoadBalanced` 有 AOP 消费路径;`@EnableDiscoveryClient`、`@FeignClient` 等当前主要是元数据,Nacos 实际初始化由 `discovery.enabled` 和 `ApplicationContext` 启动流程控制。Nacos 客户端需要 `nacos-sdk-python`、`NACOS_SERVER`、`NACOS_USERNAME`、`NACOS_PASSWORD`;Nacos 2.2+ Docker 服务端还需要 Base64 token 和 identity 环境变量。
1936
1937
 
1937
- 配置 `rabbitmq.enabled: true` 并提供 host、port、username、password、virtual_host。开发环境也应在真实 Nacos、RabbitMQ、Redis 等环境执行集成、断线和重复投递测试。Sentinel、Seata HTTP-AT、OpenTelemetry 追踪、API Gateway 均已内嵌实现,无需外部 Server。
1938
+ 配置 `rabbitmq.enabled: true` 并提供 host、port、username、password、virtual_host。开发环境也应在真实 Nacos、RabbitMQ、Redis 等环境执行集成、断线和重复投递测试。HTTP 事务模式会将协调元数据写入 `seata.store_path`,并在 worker 启动后周期恢复;它是补偿事务,不是 Seata AT,也不能单独满足支付、订单、库存的一致性要求。
1938
1939
 
1939
1940
  ---
1940
1941
 
@@ -2144,7 +2145,7 @@ class UserMapper:
2144
2145
  | `@LoadBalanced` | 同名注解 | 使用 Python 负载均衡实现;不要复用 `RestTemplate` 用法 |
2145
2146
  | Sentinel `@SentinelResource` | 同名注解 | 已内嵌限流熔断引擎,无需 Dashboard;如需更强大治理能力可对接外部 Sentinel Dashboard |
2146
2147
  | Spring Cloud Gateway | `@EnableGateway` + `GatewayRouter` | 内嵌轻量 ASGI/WSGI 网关;复杂网关需求可使用 Kong/APISIX 等专业网关 |
2147
- | Seata `@GlobalTransactional` | 同名注解 | 已内嵌 HTTP-AT 模式,无需 Seata Server,XID 自动通过 Feign 传播;如需更强一致性保障可对接外部 Seata Server |
2148
+ | Seata `@GlobalTransactional` | 同名注解 | `http` 模式是持久化补偿协调器,依赖幂等分支回调;企业强一致场景必须配置真实 Seata Server 与兼容 SDK |
2148
2149
 
2149
2150
  **Cloud 高级功能迁移对照**:
2150
2151
 
@@ -2152,7 +2153,7 @@ class UserMapper:
2152
2153
  |---|---|---|
2153
2154
  | Sentinel Dashboard + `@SentinelResource` | `@SentinelResource` | 内嵌引擎,无需 Dashboard;支持 QPS 限流、异常比例/异常数/慢调用熔断、热点参数限流 |
2154
2155
  | SkyWalking Agent + OAP Server | `@Trace` + 内嵌 Tracer | 原生 OpenTelemetry(W3C traceparent),无需 OAP Server;自动注入 HTTP/Feign 追踪头 |
2155
- | Seata Server + `@GlobalTransactional` | `@GlobalTransactional` | 内嵌 HTTP-AT 模式,无需 Seata Server;支持分支注册/提交/回滚,XID 自动传播 |
2156
+ | Seata Server + `@GlobalTransactional` | `@GlobalTransactional` | `distributed` 模式对接 Seata Server;`http` 仅用于补偿流程和故障演练,不提供 AT 语义 |
2156
2157
  | Spring Cloud Gateway | `GatewayRouter` | 轻量 ASGI/WSGI 网关,支持路由转发、路径重写、过滤器链、负载均衡 |
2157
2158
  | JPA `hibernate.ddl-auto` | `@entity` + `ddl-auto` 配置 | 支持 create/update/validate/create-drop;自动扫描实体包,自动建表/添加列/创建索引 |
2158
2159
 
@@ -2238,7 +2239,7 @@ Java 的 profile 文件自动合并不是当前功能。部署流程应生成最
2238
2239
  4. 用目标 MySQL/PostgreSQL/Oracle 版本执行相同测试,特别验证自增主键、事务隔离、超时和连接中断。
2239
2240
  5. 启动 ASGI 应用,检查 `/docs`、`/actuator/health/liveness` 和 `/actuator/health/readiness`。
2240
2241
  6. 接入 Nacos、RabbitMQ、Redis 等外部中间件,并演练断线、重复投递和回滚。
2241
- 7. 验证内嵌 Cloud 功能:`@SentinelResource` 限流熔断、`@Trace` 追踪、`@GlobalTransactional` 分布式事务、`GatewayRouter` 网关、`@entity` + `ddl-auto` 自动建表。这些功能无需部署外部 Server,但应在真实流量和故障注入下验证。
2242
+ 7. 验证 Cloud 功能:`@SentinelResource` 限流熔断、`@Trace` 追踪、`@GlobalTransactional` 补偿流程、`GatewayRouter` 网关、`@entity` + `ddl-auto` 自动建表。HTTP 补偿模式必须验证重复回调、进程重启和部分失败;强一致事务需部署真实 Seata Server 并执行集成测试。
2242
2243
 
2243
2244
  ---
2244
2245
 
@@ -2362,9 +2363,13 @@ logging:
2362
2363
  | `DISCOVERY_ENABLED` | 是否启用 Nacos 服务发现 | false |
2363
2364
  | `NACOS_SERVER` | Nacos 地址 | localhost:8848 |
2364
2365
  | `NACOS_USERNAME` / `NACOS_PASSWORD` | Nacos 客户端账号/密码 | 空 |
2366
+ | `SEATA_HTTP_STORE_PATH` | HTTP 补偿协调 SQLite 文件路径(同主机多 worker 共享) | `./data/seata-http.sqlite3` |
2367
+ | `SEATA_HTTP_RECOVER_ON_STARTUP` | 初始化时扫描并恢复未完成补偿 | true |
2368
+ | `SEATA_HTTP_RECOVERY_GRACE_MS` | 接管其他 worker 的 COMMITTING/ROLLING_BACK 前等待时间 | 30000 |
2369
+ | `SEATA_HTTP_RECOVERY_INTERVAL_S` | worker 内周期恢复间隔,0 表示关闭 | 30 |
2365
2370
  | `SPRING_DISABLE_DOCKER_IP_DETECT` | 设为 1 禁用 Docker 容器 IP 自动检测 | 0 |
2366
2371
 
2367
- > Sentinel、OpenTelemetry 追踪、Seata HTTP-AT、API Gateway 已内嵌实现,没有对应环境变量。
2372
+ > HTTP 补偿模式使用 `SEATA_HTTP_*` 配置,仍不提供 Seata AT;生产强一致事务必须配置 `SEATA_MODE=distributed`、真实 Server 和兼容 SDK。
2368
2373
 
2369
2374
  ### 14.5 启动应用
2370
2375
 
@@ -2442,7 +2447,7 @@ curl http://localhost:8080/actuator/health
2442
2447
  }
2443
2448
  ```
2444
2449
 
2445
- > Sentinel、OpenTelemetry 追踪、Seata HTTP-AT、API Gateway 已内嵌实现,不属于外部依赖组件,因此不显示在聚合健康检查中;可通过应用日志或 `@SentinelResource`、`@Trace`、`@GlobalTransactional` 注解的实际调用验证。
2450
+ > Sentinel、OpenTelemetry 追踪和 API Gateway 可内嵌运行;HTTP 补偿协调器的未完成事务会纳入恢复日志。它不属于强一致外部事务协调器,不能替代 Seata Server。
2446
2451
 
2447
2452
  ### 14.7 部署故障排查
2448
2453
 
@@ -2667,7 +2672,7 @@ export LOG_LEVEL=INFO
2667
2672
  export LOG_DIR=logs
2668
2673
  ```
2669
2674
 
2670
- > Sentinel 限流熔断、OpenTelemetry 分布式追踪、Seata HTTP-AT 分布式事务、API Gateway 均为内嵌实现,无对应环境变量。AI 模块环境变量见第 12.2 节。
2675
+ > Sentinel 限流熔断、OpenTelemetry 分布式追踪和 API Gateway 可内嵌实现;HTTP 补偿事务通过 `SEATA_HTTP_*` 配置。AI 模块环境变量见第 12.2 节。
2671
2676
 
2672
2677
  ## 附录 B:Docker Compose 示例
2673
2678
 
@@ -12,7 +12,7 @@ build-backend = "setuptools.build_meta"
12
12
  [project]
13
13
  # 发行名 springbootAI(PyPI 包名,pip install springbootAI);导入包名仍为 spring
14
14
  name = "springbootAI"
15
- version = "1.8.1"
15
+ version = "1.8.2"
16
16
  description = "Python版Spring Boot框架,集成PyMyBatis ORM"
17
17
  readme = "README.md"
18
18
  license = "MIT"
@@ -5,7 +5,7 @@ from .config import *
5
5
  from .utils import *
6
6
  from .main import create_app, run, SpringApplication, run_cli
7
7
 
8
- __version__ = "1.8.1"
8
+ __version__ = "1.8.2"
9
9
  __author__ = "yuconggen"
10
10
  __license__ = "MIT"
11
11
 
@@ -1,5 +1,6 @@
1
1
  from .logger import SpringLogger
2
2
  from .banner import BannerPrinter
3
3
  from .redis_client import RedisClient
4
+ from .bean_utils import BeanUtils
4
5
 
5
- __all__ = ["SpringLogger", "BannerPrinter", "RedisClient"]
6
+ __all__ = ["SpringLogger", "BannerPrinter", "RedisClient", "BeanUtils"]
@@ -0,0 +1,314 @@
1
+ """
2
+ BeanUtils - 属性复制工具(对齐 Spring org.springframework.beans.BeanUtils)
3
+
4
+ 提供对象间属性复制、属性读写、属性描述符等功能,命名与方法语义对齐 Spring BeanUtils,
5
+ 并补充 Apache Commons BeanUtils 常用方法(getProperty/setProperty/populate/describe)。
6
+
7
+ == 与 Java Spring BeanUtils 的差异 ==
8
+ 1. Python 动态类型,属性复制不做类型转换(Java 通过 PropertyEditor/ConversionService 转换);
9
+ 若同名属性类型不兼容,直接原样赋值,由目标对象自行决定是否接受。
10
+ 2. 基于 ``__dict__`` / ``getattr`` / ``setattr`` 实现,支持普通类、dataclass、Pydantic v2 Model、ORM entity。
11
+ 3. 默认浅拷贝(嵌套对象复制引用),需要深拷贝请用 ``copy_deep=True`` 或 ``BeanUtils.clone(source, deep=True)``。
12
+ 4. 不支持 Java 的 PropertyChangeListener / VetoableChangeListener 等监听机制。
13
+ 5. 双下划线开头(``__``)的特殊属性与方法(callable)自动排除;单下划线(``_``)约定的私有属性默认参与复制,
14
+ 如需排除请通过 ``ignore`` 显式指定。
15
+
16
+ == 方法对齐速查 ==
17
+ - Spring BeanUtils: copy_properties / copy_property / get_property_descriptors / get_property_descriptor / clone
18
+ - Apache Commons BeanUtils: get_property / set_property / get_simple_property / populate / describe
19
+ """
20
+ from __future__ import annotations
21
+
22
+ import copy as _copy_module
23
+ from typing import Any, Dict, Iterable, Mapping, Optional
24
+
25
+
26
+ __all__ = ["BeanUtils"]
27
+
28
+
29
+ def _is_copyable_attr(name: str, value: Any) -> bool:
30
+ """判断属性是否可参与复制:排除双下划线特殊属性与可调用对象(方法)。"""
31
+ if name.startswith("__"):
32
+ return False
33
+ if callable(value):
34
+ return False
35
+ return True
36
+
37
+
38
+ def _get_readable_properties(source: Any) -> Dict[str, Any]:
39
+ """
40
+ 收集源对象所有可读属性(实例属性 + 类上定义的 property)。
41
+
42
+ 优先取实例 ``__dict__``,再补充类层 property(dataclass/普通类均覆盖)。
43
+ property 的 getter 抛异常时跳过该属性,避免复制中断。
44
+ """
45
+ props: Dict[str, Any] = {}
46
+ source_dict = getattr(source, "__dict__", None)
47
+ if isinstance(source_dict, dict):
48
+ for name, value in source_dict.items():
49
+ if _is_copyable_attr(name, value):
50
+ props[name] = value
51
+
52
+ # 补充类层 property(不含实例 __dict__ 已收集的)
53
+ for klass in type(source).__mro__:
54
+ try:
55
+ klass_vars = vars(klass)
56
+ except TypeError:
57
+ continue
58
+ for name, attr in klass_vars.items():
59
+ if name in props:
60
+ continue
61
+ if name.startswith("__"):
62
+ # 提前跳过 dunder,避免触发 Pydantic 等内部 property 的弃用 getter
63
+ continue
64
+ if isinstance(attr, property) and attr.fget is not None:
65
+ try:
66
+ value = attr.fget(source)
67
+ except Exception:
68
+ continue
69
+ if _is_copyable_attr(name, value):
70
+ props[name] = value
71
+ return props
72
+
73
+
74
+ def _is_writable(target: Any, name: str) -> bool:
75
+ """判断目标对象是否能写入该属性:只读 property 返回 False。"""
76
+ for klass in type(target).__mro__:
77
+ try:
78
+ klass_vars = vars(klass)
79
+ except TypeError:
80
+ continue
81
+ if name in klass_vars:
82
+ attr = klass_vars[name]
83
+ if isinstance(attr, property):
84
+ return attr.fset is not None
85
+ # dataclass field / 普通类属性 -> 可写
86
+ return True
87
+ # 实例 __dict__ 可动态扩展的普通对象 -> 可写
88
+ return hasattr(target, "__dict__") or hasattr(target, "__slots__")
89
+
90
+
91
+ class BeanUtils:
92
+ """属性复制工具类(对齐 Spring BeanUtils + Apache Commons BeanUtils)。"""
93
+
94
+ # ------------------------------------------------------------------
95
+ # Spring BeanUtils 对齐
96
+ # ------------------------------------------------------------------
97
+ @staticmethod
98
+ def copy_properties(
99
+ source: Any,
100
+ target: Any,
101
+ ignore: Optional[Iterable[str]] = None,
102
+ copy_deep: bool = False,
103
+ ) -> None:
104
+ """
105
+ 复制源对象同名属性到目标对象(对齐 Spring ``BeanUtils.copyProperties``)。
106
+
107
+ Args:
108
+ source: 源对象(``None`` 时直接返回)。
109
+ target: 目标对象(``None`` 时直接返回)。
110
+ ignore: 忽略的属性名集合(对齐 Java ``ignoreProperties`` 变长参数)。
111
+ copy_deep: 是否对每个属性值做深拷贝。默认 False(浅拷贝,与 Spring 一致)。
112
+
113
+ 规则:
114
+ - 仅复制源对象存在且可读的属性;目标对象不可写(如只读 property)时跳过。
115
+ - 双下划线属性与方法自动排除;私有属性(单下划线)默认复制。
116
+ - 目标对象 setattr 失败(如 Pydantic frozen / slots 限制)时跳过,不抛异常。
117
+ """
118
+ if source is None or target is None:
119
+ return
120
+ ignore_set: set = set(ignore) if ignore else set()
121
+ for name, value in _get_readable_properties(source).items():
122
+ if name in ignore_set:
123
+ continue
124
+ if not _is_writable(target, name):
125
+ continue
126
+ try:
127
+ setattr(target, name, _copy_module.deepcopy(value) if copy_deep else value)
128
+ except (AttributeError, TypeError, ValueError):
129
+ # 目标对象校验失败或不可写:跳过,保持 Spring 的"尽力复制"语义
130
+ continue
131
+
132
+ @staticmethod
133
+ def copy_property(source: Any, target: Any, property_name: str) -> bool:
134
+ """
135
+ 复制单个属性(对齐 Spring ``BeanUtils.copyProperty``)。
136
+
137
+ Returns:
138
+ 是否复制成功(源无此属性或目标不可写返回 False)。
139
+ """
140
+ if source is None or target is None:
141
+ return False
142
+ if not hasattr(source, property_name):
143
+ return False
144
+ try:
145
+ value = getattr(source, property_name)
146
+ except Exception:
147
+ return False
148
+ if not _is_copyable_attr(property_name, value):
149
+ return False
150
+ if not _is_writable(target, property_name):
151
+ return False
152
+ try:
153
+ setattr(target, property_name, value)
154
+ return True
155
+ except (AttributeError, TypeError, ValueError):
156
+ return False
157
+
158
+ @staticmethod
159
+ def clone(source: Any, deep: bool = False) -> Any:
160
+ """
161
+ 克隆对象(对齐 Spring ``BeanUtils.cloneBean``,Apache Commons 风格)。
162
+
163
+ Args:
164
+ source: 源对象。
165
+ deep: True 做深拷贝;False 仅复制顶层(嵌套对象共享引用)。
166
+
167
+ Returns:
168
+ 与源同类型的新对象,属性已复制。
169
+ """
170
+ if source is None:
171
+ return None
172
+ target = type(source).__new__(type(source))
173
+ BeanUtils.copy_properties(source, target, copy_deep=deep)
174
+ return target
175
+
176
+ @staticmethod
177
+ def get_property_descriptors(obj: Any) -> Dict[str, Optional[type]]:
178
+ """
179
+ 获取属性描述符(对齐 Spring ``BeanUtils.getPropertyDescriptors``)。
180
+
181
+ Returns:
182
+ 属性名 -> 属性值类型的映射(无法推断类型时为 None)。
183
+ """
184
+ descriptors: Dict[str, Optional[type]] = {}
185
+ for name, value in _get_readable_properties(obj).items():
186
+ descriptors[name] = type(value) if value is not None else None
187
+ return descriptors
188
+
189
+ @staticmethod
190
+ def get_property_descriptor(obj: Any, name: str) -> Optional[type]:
191
+ """获取单个属性的描述符(对齐 Spring ``BeanUtils.getPropertyDescriptor``)。"""
192
+ if obj is None or not hasattr(obj, name):
193
+ return None
194
+ try:
195
+ value = getattr(obj, name)
196
+ except Exception:
197
+ return None
198
+ return type(value) if value is not None else None
199
+
200
+ # ------------------------------------------------------------------
201
+ # Apache Commons BeanUtils 对齐
202
+ # ------------------------------------------------------------------
203
+ @staticmethod
204
+ def get_property(obj: Any, name: str, default: Any = None) -> Any:
205
+ """
206
+ 获取属性值,支持嵌套路径(对齐 Apache Commons ``BeanUtils.getProperty``)。
207
+
208
+ Args:
209
+ name: 属性名,支持点号嵌套,如 ``"user.address.city"``。
210
+ default: 路径中断或取值异常时返回的默认值。
211
+
212
+ Returns:
213
+ 属性值;路径中断或异常返回 ``default``。
214
+ """
215
+ if obj is None or not name:
216
+ return default
217
+ current: Any = obj
218
+ for part in name.split("."):
219
+ if current is None:
220
+ return default
221
+ if isinstance(current, Mapping) and part in current:
222
+ current = current[part]
223
+ elif hasattr(current, part):
224
+ try:
225
+ current = getattr(current, part)
226
+ except Exception:
227
+ return default
228
+ else:
229
+ return default
230
+ return current if current is not None else default
231
+
232
+ @staticmethod
233
+ def set_property(obj: Any, name: str, value: Any) -> bool:
234
+ """
235
+ 设置属性值,支持嵌套路径(对齐 Apache Commons ``BeanUtils.setProperty``)。
236
+
237
+ Args:
238
+ name: 属性名,支持点号嵌套;嵌套中间节点为 None 时创建失败返回 False。
239
+
240
+ Returns:
241
+ 是否设置成功。
242
+ """
243
+ if obj is None or not name:
244
+ return False
245
+ parts = name.split(".")
246
+ current: Any = obj
247
+ for part in parts[:-1]:
248
+ if current is None:
249
+ return False
250
+ if isinstance(current, Mapping):
251
+ if part not in current or current[part] is None:
252
+ return False
253
+ current = current[part]
254
+ elif hasattr(current, part):
255
+ try:
256
+ nxt = getattr(current, part)
257
+ except Exception:
258
+ return False
259
+ if nxt is None:
260
+ return False
261
+ current = nxt
262
+ else:
263
+ return False
264
+ leaf = parts[-1]
265
+ try:
266
+ if isinstance(current, Mapping):
267
+ current[leaf] = value
268
+ else:
269
+ setattr(current, leaf, value)
270
+ return True
271
+ except (AttributeError, TypeError, ValueError, KeyError):
272
+ return False
273
+
274
+ @staticmethod
275
+ def get_simple_property(obj: Any, name: str, default: Any = None) -> Any:
276
+ """获取简单属性(不支持嵌套,对齐 Apache Commons ``getSimpleProperty``)。"""
277
+ if obj is None or not name or not hasattr(obj, name):
278
+ return default
279
+ try:
280
+ value = getattr(obj, name)
281
+ except Exception:
282
+ return default
283
+ return value if value is not None else default
284
+
285
+ @staticmethod
286
+ def populate(obj: Any, properties: Mapping[str, Any]) -> None:
287
+ """
288
+ 用字典批量设置属性(对齐 Apache Commons ``BeanUtils.populate``)。
289
+
290
+ Args:
291
+ obj: 目标对象。
292
+ properties: 属性名 -> 值的映射;不可写的属性自动跳过。
293
+ """
294
+ if obj is None or not properties:
295
+ return
296
+ for name, value in properties.items():
297
+ if not _is_writable(obj, name):
298
+ continue
299
+ try:
300
+ setattr(obj, name, value)
301
+ except (AttributeError, TypeError, ValueError):
302
+ continue
303
+
304
+ @staticmethod
305
+ def describe(obj: Any) -> Dict[str, Any]:
306
+ """
307
+ 将对象可读属性导出为字典(对齐 Apache Commons ``BeanUtils.describe``)。
308
+
309
+ Returns:
310
+ 属性名 -> 值的映射(仅可读属性,排除方法与双下划线属性)。
311
+ """
312
+ if obj is None:
313
+ return {}
314
+ return _get_readable_properties(obj)