springbootAI 1.8.8__tar.gz → 2.0.0__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 (260) hide show
  1. springbootai-2.0.0/PKG-INFO +1765 -0
  2. springbootai-2.0.0/README.md +1644 -0
  3. {springbootai-1.8.8 → springbootai-2.0.0}/pyproject.toml +93 -19
  4. {springbootai-1.8.8 → springbootai-2.0.0}/requirements.txt +3 -3
  5. {springbootai-1.8.8 → springbootai-2.0.0}/spring/__init__.py +1 -1
  6. {springbootai-1.8.8 → springbootai-2.0.0}/spring/ai/advisors.py +33 -6
  7. {springbootai-1.8.8 → springbootai-2.0.0}/spring/ai/annotations.py +1 -1
  8. {springbootai-1.8.8 → springbootai-2.0.0}/spring/ai/autoconfig.py +11 -4
  9. {springbootai-1.8.8 → springbootai-2.0.0}/spring/ai/core.py +14 -3
  10. {springbootai-1.8.8 → springbootai-2.0.0}/spring/ai/etl.py +1 -1
  11. {springbootai-1.8.8 → springbootai-2.0.0}/spring/ai/memory.py +13 -4
  12. {springbootai-1.8.8 → springbootai-2.0.0}/spring/ai/providers.py +104 -12
  13. {springbootai-1.8.8 → springbootai-2.0.0}/spring/ai/resilience.py +1 -2
  14. springbootai-2.0.0/spring/ai/tools.py +196 -0
  15. {springbootai-1.8.8 → springbootai-2.0.0}/spring/ai/vectorstore.py +88 -1
  16. {springbootai-1.8.8 → springbootai-2.0.0}/spring/annotations/cache.py +1 -1
  17. {springbootai-1.8.8 → springbootai-2.0.0}/spring/annotations/cloud.py +2 -2
  18. {springbootai-1.8.8 → springbootai-2.0.0}/spring/annotations/core.py +1 -1
  19. {springbootai-1.8.8 → springbootai-2.0.0}/spring/annotations/messaging.py +1 -1
  20. {springbootai-1.8.8 → springbootai-2.0.0}/spring/aop/cloud_aop.py +1 -1
  21. {springbootai-1.8.8 → springbootai-2.0.0}/spring/aop/comprehensive_aop.py +1 -1
  22. {springbootai-1.8.8 → springbootai-2.0.0}/spring/cloud/discovery.py +0 -2
  23. {springbootai-1.8.8 → springbootai-2.0.0}/spring/cloud/feign.py +1 -1
  24. {springbootai-1.8.8 → springbootai-2.0.0}/spring/cloud/gateway.py +1 -1
  25. {springbootai-1.8.8 → springbootai-2.0.0}/spring/cloud/load_balancer.py +1 -1
  26. {springbootai-1.8.8 → springbootai-2.0.0}/spring/cloud/sentinel.py +2 -3
  27. {springbootai-1.8.8 → springbootai-2.0.0}/spring/config/binding.py +1 -1
  28. {springbootai-1.8.8 → springbootai-2.0.0}/spring/context/bean_factory.py +7 -1
  29. {springbootai-1.8.8 → springbootai-2.0.0}/spring/context/scanner.py +0 -1
  30. {springbootai-1.8.8 → springbootai-2.0.0}/spring/core/graceful_shutdown.py +1 -1
  31. {springbootai-1.8.8 → springbootai-2.0.0}/spring/data/page.py +1 -1
  32. {springbootai-1.8.8 → springbootai-2.0.0}/spring/data/repository.py +2 -3
  33. {springbootai-1.8.8 → springbootai-2.0.0}/spring/datasource/annotations.py +1 -1
  34. {springbootai-1.8.8 → springbootai-2.0.0}/spring/excel/converters.py +1 -1
  35. {springbootai-1.8.8 → springbootai-2.0.0}/spring/excel/easy_excel.py +1 -1
  36. {springbootai-1.8.8 → springbootai-2.0.0}/spring/excel/reader.py +1 -1
  37. {springbootai-1.8.8 → springbootai-2.0.0}/spring/i18n/accessor.py +0 -1
  38. {springbootai-1.8.8 → springbootai-2.0.0}/spring/i18n/auto_config.py +0 -1
  39. {springbootai-1.8.8 → springbootai-2.0.0}/spring/i18n/locale.py +0 -1
  40. {springbootai-1.8.8 → springbootai-2.0.0}/spring/i18n/locale_resolver.py +1 -1
  41. {springbootai-1.8.8 → springbootai-2.0.0}/spring/i18n/message_source.py +1 -1
  42. {springbootai-1.8.8 → springbootai-2.0.0}/spring/i18n/properties.py +1 -1
  43. {springbootai-1.8.8 → springbootai-2.0.0}/spring/i18n/sources.py +1 -2
  44. springbootai-2.0.0/spring/langchain/__init__.py +112 -0
  45. springbootai-2.0.0/spring/langchain/adapters.py +335 -0
  46. springbootai-2.0.0/spring/langchain/agents/__init__.py +4 -0
  47. springbootai-2.0.0/spring/langchain/agents/services.py +211 -0
  48. springbootai-2.0.0/spring/langchain/autoconfig.py +364 -0
  49. springbootai-2.0.0/spring/langchain/callbacks/__init__.py +4 -0
  50. springbootai-2.0.0/spring/langchain/callbacks/handlers.py +50 -0
  51. springbootai-2.0.0/spring/langchain/chains/__init__.py +4 -0
  52. springbootai-2.0.0/spring/langchain/chains/services.py +339 -0
  53. springbootai-2.0.0/spring/langchain/core.py +580 -0
  54. springbootai-2.0.0/spring/langchain/indexes/__init__.py +4 -0
  55. springbootai-2.0.0/spring/langchain/indexes/index.py +93 -0
  56. springbootai-2.0.0/spring/langchain/loaders/__init__.py +4 -0
  57. springbootai-2.0.0/spring/langchain/loaders/loaders.py +207 -0
  58. springbootai-2.0.0/spring/langchain/memory/__init__.py +4 -0
  59. springbootai-2.0.0/spring/langchain/memory/memory.py +106 -0
  60. springbootai-2.0.0/spring/langchain/parsers/__init__.py +4 -0
  61. springbootai-2.0.0/spring/langchain/parsers/parsers.py +84 -0
  62. springbootai-2.0.0/spring/langchain/partners.py +203 -0
  63. springbootai-2.0.0/spring/langchain/prompts/__init__.py +4 -0
  64. springbootai-2.0.0/spring/langchain/prompts/templates.py +105 -0
  65. springbootai-2.0.0/spring/langchain/retrievers/__init__.py +4 -0
  66. springbootai-2.0.0/spring/langchain/retrievers/retrievers.py +95 -0
  67. springbootai-2.0.0/spring/langchain/tools/__init__.py +4 -0
  68. springbootai-2.0.0/spring/langchain/tools/tools.py +94 -0
  69. springbootai-2.0.0/spring/langchain/utilities/__init__.py +4 -0
  70. springbootai-2.0.0/spring/langchain/utilities/utils.py +170 -0
  71. springbootai-2.0.0/spring/langchain/vectorstores/__init__.py +4 -0
  72. springbootai-2.0.0/spring/langchain/vectorstores/stores.py +143 -0
  73. {springbootai-1.8.8 → springbootai-2.0.0}/spring/logging/loguru_logger.py +0 -2
  74. {springbootai-1.8.8 → springbootai-2.0.0}/spring/main.py +0 -1
  75. {springbootai-1.8.8 → springbootai-2.0.0}/spring/monitoring/prometheus.py +1 -3
  76. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/database.py +2 -2
  77. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/ddl_auto.py +1 -2
  78. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/migration.py +1 -2
  79. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/mybatis_integration.py +1 -1
  80. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/cache/redis_cache.py +1 -1
  81. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/core/sql_session.py +1 -2
  82. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/metrics/metrics.py +1 -1
  83. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/security/sql_injection_detector.py +1 -1
  84. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/xml_parser/xml_parser.py +1 -1
  85. {springbootai-1.8.8 → springbootai-2.0.0}/spring/scheduling/scheduler.py +1 -1
  86. {springbootai-1.8.8 → springbootai-2.0.0}/spring/security/replay_protection.py +1 -1
  87. {springbootai-1.8.8 → springbootai-2.0.0}/spring/security/secret_manager.py +0 -1
  88. {springbootai-1.8.8 → springbootai-2.0.0}/spring/security/security_aop.py +1 -1
  89. {springbootai-1.8.8 → springbootai-2.0.0}/spring/tracing/skywalking.py +1 -1
  90. {springbootai-1.8.8 → springbootai-2.0.0}/spring/utils/banner.py +1 -1
  91. {springbootai-1.8.8 → springbootai-2.0.0}/spring/utils/redis_client.py +1 -1
  92. {springbootai-1.8.8 → springbootai-2.0.0}/spring/validation/validator.py +0 -1
  93. {springbootai-1.8.8 → springbootai-2.0.0}/spring/web/actuator.py +1 -4
  94. {springbootai-1.8.8 → springbootai-2.0.0}/spring/web/exception_handler.py +1 -2
  95. {springbootai-1.8.8 → springbootai-2.0.0}/spring/web/interceptor.py +1 -1
  96. {springbootai-1.8.8 → springbootai-2.0.0}/spring/web/result.py +1 -1
  97. {springbootai-1.8.8 → springbootai-2.0.0}/spring/web/swagger.py +1 -1
  98. {springbootai-1.8.8 → springbootai-2.0.0}/spring/websocket/annotations.py +1 -1
  99. {springbootai-1.8.8 → springbootai-2.0.0}/spring/websocket/handler.py +2 -2
  100. {springbootai-1.8.8 → springbootai-2.0.0}/spring/websocket/router.py +2 -2
  101. {springbootai-1.8.8 → springbootai-2.0.0}/spring/websocket/session.py +0 -1
  102. springbootai-2.0.0/springbootAI.egg-info/PKG-INFO +1765 -0
  103. {springbootai-1.8.8 → springbootai-2.0.0}/springbootAI.egg-info/SOURCES.txt +31 -0
  104. springbootai-2.0.0/springbootAI.egg-info/requires.txt +112 -0
  105. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_actuator.py +0 -2
  106. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_ai_module.py +14 -10
  107. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_annotation_combinations.py +5 -9
  108. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_cache_annotations.py +0 -1
  109. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_cloud_embedded_full.py +0 -1
  110. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_component_init_error.py +0 -2
  111. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_conditional_annotations.py +0 -4
  112. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_config_fixes_185.py +1 -5
  113. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_connection_resilience.py +1 -3
  114. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_csv_module.py +1 -3
  115. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_data_repository.py +1 -2
  116. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_datasource_routing.py +0 -1
  117. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_di_config_event_full.py +0 -2
  118. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_excel_module.py +3 -4
  119. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_i18n_module.py +3 -5
  120. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_jpa_version_transient.py +1 -3
  121. springbootai-2.0.0/tests/test_langchain_ext.py +3596 -0
  122. springbootai-2.0.0/tests/test_langchain_module.py +840 -0
  123. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_logging_config.py +0 -1
  124. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_new_features.py +4 -8
  125. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_production_readiness.py +0 -3
  126. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_security.py +0 -1
  127. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_swagger_module.py +2 -6
  128. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_test_slicing.py +1 -2
  129. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_validation_module.py +1 -4
  130. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_websocket_module.py +3 -4
  131. springbootai-1.8.8/PKG-INFO +0 -2811
  132. springbootai-1.8.8/README.md +0 -2727
  133. springbootai-1.8.8/spring/ai/tools.py +0 -106
  134. springbootai-1.8.8/springbootAI.egg-info/PKG-INFO +0 -2811
  135. springbootai-1.8.8/springbootAI.egg-info/requires.txt +0 -74
  136. {springbootai-1.8.8 → springbootai-2.0.0}/LICENSE +0 -0
  137. {springbootai-1.8.8 → springbootai-2.0.0}/MANIFEST.in +0 -0
  138. {springbootai-1.8.8 → springbootai-2.0.0}/setup.cfg +0 -0
  139. {springbootai-1.8.8 → springbootai-2.0.0}/setup.py +0 -0
  140. {springbootai-1.8.8 → springbootai-2.0.0}/spring/ai/__init__.py +0 -0
  141. {springbootai-1.8.8 → springbootai-2.0.0}/spring/ai/observability.py +0 -0
  142. {springbootai-1.8.8 → springbootai-2.0.0}/spring/annotations/__init__.py +0 -0
  143. {springbootai-1.8.8 → springbootai-2.0.0}/spring/annotations/conditional.py +0 -0
  144. {springbootai-1.8.8 → springbootai-2.0.0}/spring/aop/__init__.py +0 -0
  145. {springbootai-1.8.8 → springbootai-2.0.0}/spring/aop/method_interceptor.py +0 -0
  146. {springbootai-1.8.8 → springbootai-2.0.0}/spring/aop/proxy_factory.py +0 -0
  147. {springbootai-1.8.8 → springbootai-2.0.0}/spring/cloud/__init__.py +0 -0
  148. {springbootai-1.8.8 → springbootai-2.0.0}/spring/cloud/seata.py +0 -0
  149. {springbootai-1.8.8 → springbootai-2.0.0}/spring/cloud/seata_bridge.py +0 -0
  150. {springbootai-1.8.8 → springbootai-2.0.0}/spring/cloud/tracer.py +0 -0
  151. {springbootai-1.8.8 → springbootai-2.0.0}/spring/cloud/transaction_store.py +0 -0
  152. {springbootai-1.8.8 → springbootai-2.0.0}/spring/config/__init__.py +0 -0
  153. {springbootai-1.8.8 → springbootai-2.0.0}/spring/config/config_loader.py +0 -0
  154. {springbootai-1.8.8 → springbootai-2.0.0}/spring/context/__init__.py +0 -0
  155. {springbootai-1.8.8 → springbootai-2.0.0}/spring/context/application_context.py +0 -0
  156. {springbootai-1.8.8 → springbootai-2.0.0}/spring/context/bean_definition.py +0 -0
  157. {springbootai-1.8.8 → springbootai-2.0.0}/spring/context/registry.py +0 -0
  158. {springbootai-1.8.8 → springbootai-2.0.0}/spring/core/__init__.py +0 -0
  159. {springbootai-1.8.8 → springbootai-2.0.0}/spring/core/typing_utils.py +0 -0
  160. {springbootai-1.8.8 → springbootai-2.0.0}/spring/csv/__init__.py +0 -0
  161. {springbootai-1.8.8 → springbootai-2.0.0}/spring/csv/annotations.py +0 -0
  162. {springbootai-1.8.8 → springbootai-2.0.0}/spring/csv/converters.py +0 -0
  163. {springbootai-1.8.8 → springbootai-2.0.0}/spring/csv/easy_csv.py +0 -0
  164. {springbootai-1.8.8 → springbootai-2.0.0}/spring/csv/exceptions.py +0 -0
  165. {springbootai-1.8.8 → springbootai-2.0.0}/spring/csv/reader.py +0 -0
  166. {springbootai-1.8.8 → springbootai-2.0.0}/spring/csv/writer.py +0 -0
  167. {springbootai-1.8.8 → springbootai-2.0.0}/spring/data/__init__.py +0 -0
  168. {springbootai-1.8.8 → springbootai-2.0.0}/spring/data/specification.py +0 -0
  169. {springbootai-1.8.8 → springbootai-2.0.0}/spring/datasource/__init__.py +0 -0
  170. {springbootai-1.8.8 → springbootai-2.0.0}/spring/datasource/context.py +0 -0
  171. {springbootai-1.8.8 → springbootai-2.0.0}/spring/datasource/dynamic.py +0 -0
  172. {springbootai-1.8.8 → springbootai-2.0.0}/spring/event/__init__.py +0 -0
  173. {springbootai-1.8.8 → springbootai-2.0.0}/spring/event/publisher.py +0 -0
  174. {springbootai-1.8.8 → springbootai-2.0.0}/spring/excel/__init__.py +0 -0
  175. {springbootai-1.8.8 → springbootai-2.0.0}/spring/excel/annotations.py +0 -0
  176. {springbootai-1.8.8 → springbootai-2.0.0}/spring/excel/exceptions.py +0 -0
  177. {springbootai-1.8.8 → springbootai-2.0.0}/spring/excel/style.py +0 -0
  178. {springbootai-1.8.8 → springbootai-2.0.0}/spring/excel/writer.py +0 -0
  179. {springbootai-1.8.8 → springbootai-2.0.0}/spring/i18n/__init__.py +0 -0
  180. {springbootai-1.8.8 → springbootai-2.0.0}/spring/i18n/holder.py +0 -0
  181. {springbootai-1.8.8 → springbootai-2.0.0}/spring/i18n/middleware.py +0 -0
  182. {springbootai-1.8.8 → springbootai-2.0.0}/spring/logging/__init__.py +0 -0
  183. {springbootai-1.8.8 → springbootai-2.0.0}/spring/messaging/__init__.py +0 -0
  184. {springbootai-1.8.8 → springbootai-2.0.0}/spring/messaging/rabbitmq.py +0 -0
  185. {springbootai-1.8.8 → springbootai-2.0.0}/spring/monitoring/__init__.py +0 -0
  186. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/__init__.py +0 -0
  187. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/__init__.py +0 -0
  188. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/annotations/__init__.py +0 -0
  189. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/annotations/annotations.py +0 -0
  190. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/cache/__init__.py +0 -0
  191. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/cache/cache.py +0 -0
  192. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/circuit_breaker/__init__.py +0 -0
  193. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/circuit_breaker/circuit_breaker.py +0 -0
  194. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/configuration.py +0 -0
  195. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/core/__init__.py +0 -0
  196. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/core/sql_session_factory.py +0 -0
  197. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/dialect/__init__.py +0 -0
  198. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/dialect/dialect.py +0 -0
  199. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/dynamic_sql/__init__.py +0 -0
  200. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/dynamic_sql/dynamic_sql.py +0 -0
  201. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/interceptor/__init__.py +0 -0
  202. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/interceptor/interceptor.py +0 -0
  203. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/mapper/__init__.py +0 -0
  204. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/mapper/mapper.py +0 -0
  205. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/metrics/__init__.py +0 -0
  206. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/pool/__init__.py +0 -0
  207. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/pool/connection_pool.py +0 -0
  208. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/security/__init__.py +0 -0
  209. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/security/access_control.py +0 -0
  210. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/security/password_encoder.py +0 -0
  211. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/security/sensitive_data_masker.py +0 -0
  212. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/transaction/__init__.py +0 -0
  213. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/transaction/transaction.py +0 -0
  214. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/type_handler/__init__.py +0 -0
  215. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/type_handler/type_handler.py +0 -0
  216. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/version.py +0 -0
  217. {springbootai-1.8.8 → springbootai-2.0.0}/spring/orm/pymybatis/xml_parser/__init__.py +0 -0
  218. {springbootai-1.8.8 → springbootai-2.0.0}/spring/retry/__init__.py +0 -0
  219. {springbootai-1.8.8 → springbootai-2.0.0}/spring/retry/retry_annotations.py +0 -0
  220. {springbootai-1.8.8 → springbootai-2.0.0}/spring/retry/retry_decorator.py +0 -0
  221. {springbootai-1.8.8 → springbootai-2.0.0}/spring/scheduling/__init__.py +0 -0
  222. {springbootai-1.8.8 → springbootai-2.0.0}/spring/security/__init__.py +0 -0
  223. {springbootai-1.8.8 → springbootai-2.0.0}/spring/security/jwt_utils.py +0 -0
  224. {springbootai-1.8.8 → springbootai-2.0.0}/spring/security/security_context.py +0 -0
  225. {springbootai-1.8.8 → springbootai-2.0.0}/spring/test/__init__.py +0 -0
  226. {springbootai-1.8.8 → springbootai-2.0.0}/spring/test/slicing.py +0 -0
  227. {springbootai-1.8.8 → springbootai-2.0.0}/spring/tracing/__init__.py +0 -0
  228. {springbootai-1.8.8 → springbootai-2.0.0}/spring/tx/__init__.py +0 -0
  229. {springbootai-1.8.8 → springbootai-2.0.0}/spring/tx/events.py +0 -0
  230. {springbootai-1.8.8 → springbootai-2.0.0}/spring/tx/synchronization.py +0 -0
  231. {springbootai-1.8.8 → springbootai-2.0.0}/spring/utils/__init__.py +0 -0
  232. {springbootai-1.8.8 → springbootai-2.0.0}/spring/utils/bean_utils.py +0 -0
  233. {springbootai-1.8.8 → springbootai-2.0.0}/spring/utils/logger.py +0 -0
  234. {springbootai-1.8.8 → springbootai-2.0.0}/spring/validation/__init__.py +0 -0
  235. {springbootai-1.8.8 → springbootai-2.0.0}/spring/validation/aop.py +0 -0
  236. {springbootai-1.8.8 → springbootai-2.0.0}/spring/validation/constraints.py +0 -0
  237. {springbootai-1.8.8 → springbootai-2.0.0}/spring/validation/exceptions.py +0 -0
  238. {springbootai-1.8.8 → springbootai-2.0.0}/spring/web/__init__.py +0 -0
  239. {springbootai-1.8.8 → springbootai-2.0.0}/spring/web/health.py +0 -0
  240. {springbootai-1.8.8 → springbootai-2.0.0}/spring/web/web_context.py +0 -0
  241. {springbootai-1.8.8 → springbootai-2.0.0}/spring/websocket/__init__.py +0 -0
  242. {springbootai-1.8.8 → springbootai-2.0.0}/spring/websocket/broker.py +0 -0
  243. {springbootai-1.8.8 → springbootai-2.0.0}/spring/websocket/exceptions.py +0 -0
  244. {springbootai-1.8.8 → springbootai-2.0.0}/springbootAI.egg-info/dependency_links.txt +0 -0
  245. {springbootai-1.8.8 → springbootai-2.0.0}/springbootAI.egg-info/entry_points.txt +0 -0
  246. {springbootai-1.8.8 → springbootai-2.0.0}/springbootAI.egg-info/top_level.txt +0 -0
  247. {springbootai-1.8.8 → springbootai-2.0.0}/sql/seata_undo_log.sql +0 -0
  248. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_annotations_contract.py +0 -0
  249. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_aop_annotations_full.py +0 -0
  250. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_bean_utils.py +0 -0
  251. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_config_binding.py +0 -0
  252. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_core_annotations_full.py +0 -0
  253. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_ddl_auto.py +0 -0
  254. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_orm_pymybatis_full.py +0 -0
  255. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_pymybatis_contract.py +0 -0
  256. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_seata_bridge.py +0 -0
  257. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_seata_durable_store.py +0 -0
  258. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_security_full.py +0 -0
  259. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_transactional_events.py +0 -0
  260. {springbootai-1.8.8 → springbootai-2.0.0}/tests/test_web_annotations_full.py +0 -0
@@ -0,0 +1,1765 @@
1
+ Metadata-Version: 2.4
2
+ Name: springbootAI
3
+ Version: 2.0.0
4
+ Summary: Python版Spring Boot框架,集成PyMyBatis ORM
5
+ Author-email: YuConggen <1516933915@qq.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/YUCONGGEN/springbootAI
8
+ Project-URL: Repository, https://github.com/YUCONGGEN/springbootAI.git
9
+ Keywords: spring,springboot,mybatis,orm,web,framework,python
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
17
+ Classifier: Topic :: Database
18
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: fastapi==0.141.1
23
+ Requires-Dist: uvicorn==0.39.0
24
+ Requires-Dist: websockets==15.0.1
25
+ Requires-Dist: pyyaml==6.0.3
26
+ Requires-Dist: python-dotenv==1.2.2
27
+ Requires-Dist: DBUtils==3.1.2
28
+ Requires-Dist: cryptography==50.0.0
29
+ Requires-Dist: bcrypt==5.0.0
30
+ Requires-Dist: pyjwt==2.13.0
31
+ Requires-Dist: pydantic==2.13.4
32
+ Requires-Dist: requests==2.34.2
33
+ Requires-Dist: httpx==0.28.1
34
+ Provides-Extra: mysql
35
+ Requires-Dist: PyMySQL==1.2.0; extra == "mysql"
36
+ Provides-Extra: postgresql
37
+ Requires-Dist: psycopg2-binary==2.9.12; extra == "postgresql"
38
+ Provides-Extra: sqlalchemy
39
+ Requires-Dist: sqlalchemy==2.0.40; extra == "sqlalchemy"
40
+ Provides-Extra: redis
41
+ Requires-Dist: redis==8.1.0; extra == "redis"
42
+ Provides-Extra: rabbitmq
43
+ Requires-Dist: pika==1.4.4; extra == "rabbitmq"
44
+ Provides-Extra: nacos
45
+ Requires-Dist: nacos-sdk-python==2.0.11; extra == "nacos"
46
+ Provides-Extra: prometheus
47
+ Requires-Dist: prometheus-client==0.26.0; extra == "prometheus"
48
+ Provides-Extra: logging
49
+ Requires-Dist: loguru==0.7.3; extra == "logging"
50
+ Provides-Extra: ast
51
+ Requires-Dist: sqlglot==27.28.1; extra == "ast"
52
+ Provides-Extra: excel
53
+ Requires-Dist: openpyxl==3.1.5; extra == "excel"
54
+ Provides-Extra: ai
55
+ Requires-Dist: langchain-openai==1.4.1; extra == "ai"
56
+ Requires-Dist: langchain-core==1.5.1; extra == "ai"
57
+ Requires-Dist: langchain-classic==1.0.8; extra == "ai"
58
+ Requires-Dist: langchain-text-splitters==1.1.2; extra == "ai"
59
+ Requires-Dist: langchain-community==0.4.2; extra == "ai"
60
+ Requires-Dist: numpy==2.2.6; extra == "ai"
61
+ Requires-Dist: pydantic==2.13.4; extra == "ai"
62
+ Provides-Extra: langchain
63
+ Requires-Dist: langchain-openai==1.4.1; extra == "langchain"
64
+ Requires-Dist: langchain-core==1.5.1; extra == "langchain"
65
+ Requires-Dist: langchain-classic==1.0.8; extra == "langchain"
66
+ Requires-Dist: langchain-text-splitters==1.1.2; extra == "langchain"
67
+ Requires-Dist: langchain-community==0.4.2; extra == "langchain"
68
+ Requires-Dist: numpy==2.2.6; extra == "langchain"
69
+ Requires-Dist: pydantic==2.13.4; extra == "langchain"
70
+ Requires-Dist: faiss-cpu<2,>=1.7.4; extra == "langchain"
71
+ Requires-Dist: pypdf<6,>=4.0.0; extra == "langchain"
72
+ Requires-Dist: beautifulsoup4<5,>=4.12.0; extra == "langchain"
73
+ Requires-Dist: sqlalchemy<3,>=2.0.0; extra == "langchain"
74
+ Requires-Dist: langchain-anthropic<2,>=0.2.0; extra == "langchain"
75
+ Requires-Dist: langchain-ollama<2,>=0.2.0; extra == "langchain"
76
+ Requires-Dist: langchain-chroma<2,>=0.1.0; extra == "langchain"
77
+ Requires-Dist: langchain-mistralai<2,>=0.2.0; extra == "langchain"
78
+ Requires-Dist: langchain-cohere<2,>=0.3.0; extra == "langchain"
79
+ Requires-Dist: langchain-google-vertexai<3,>=2.0.0; extra == "langchain"
80
+ Requires-Dist: langchain-deepseek<2,>=0.1.0; extra == "langchain"
81
+ Requires-Dist: langchain-zhipuai<2,>=0.0.1; extra == "langchain"
82
+ Requires-Dist: langchain-experimental<2,>=0.3.0; extra == "langchain"
83
+ Provides-Extra: dev
84
+ Requires-Dist: pytest==9.1.1; extra == "dev"
85
+ Requires-Dist: pytest-cov==7.1.0; extra == "dev"
86
+ Requires-Dist: redis==8.1.0; extra == "dev"
87
+ Requires-Dist: sqlglot==27.28.1; extra == "dev"
88
+ Provides-Extra: full
89
+ Requires-Dist: PyMySQL==1.2.0; extra == "full"
90
+ Requires-Dist: psycopg2-binary==2.9.12; extra == "full"
91
+ Requires-Dist: sqlalchemy==2.0.40; extra == "full"
92
+ Requires-Dist: redis==8.1.0; extra == "full"
93
+ Requires-Dist: pika==1.4.4; extra == "full"
94
+ Requires-Dist: nacos-sdk-python==2.0.11; extra == "full"
95
+ Requires-Dist: prometheus-client==0.26.0; extra == "full"
96
+ Requires-Dist: loguru==0.7.3; extra == "full"
97
+ Requires-Dist: sqlglot==27.28.1; extra == "full"
98
+ Requires-Dist: requests==2.34.2; extra == "full"
99
+ Requires-Dist: httpx==0.28.1; extra == "full"
100
+ Requires-Dist: openpyxl==3.1.5; extra == "full"
101
+ Requires-Dist: langchain-openai==1.4.1; extra == "full"
102
+ Requires-Dist: langchain-core==1.5.1; extra == "full"
103
+ Requires-Dist: langchain-classic==1.0.8; extra == "full"
104
+ Requires-Dist: langchain-text-splitters==1.1.2; extra == "full"
105
+ Requires-Dist: langchain-community==0.4.2; extra == "full"
106
+ Requires-Dist: numpy==2.2.6; extra == "full"
107
+ Requires-Dist: pydantic==2.13.4; extra == "full"
108
+ Requires-Dist: faiss-cpu<2,>=1.7.4; extra == "full"
109
+ Requires-Dist: pypdf<6,>=4.0.0; extra == "full"
110
+ Requires-Dist: beautifulsoup4<5,>=4.12.0; extra == "full"
111
+ Requires-Dist: langchain-experimental<2,>=0.3.0; extra == "full"
112
+ Requires-Dist: langchain-anthropic<2,>=0.2.0; extra == "full"
113
+ Requires-Dist: langchain-ollama<2,>=0.2.0; extra == "full"
114
+ Requires-Dist: langchain-chroma<2,>=0.1.0; extra == "full"
115
+ Requires-Dist: langchain-mistralai<2,>=0.2.0; extra == "full"
116
+ Requires-Dist: langchain-cohere<2,>=0.3.0; extra == "full"
117
+ Requires-Dist: langchain-google-vertexai<3,>=2.0.0; extra == "full"
118
+ Requires-Dist: langchain-deepseek<2,>=0.1.0; extra == "full"
119
+ Requires-Dist: langchain-zhipuai<2,>=0.0.1; extra == "full"
120
+ Dynamic: license-file
121
+
122
+ # SpringBootAI 综合使用指南
123
+
124
+ > **🐣 三句话搞懂这是什么**:SpringBootAI 就像一个"网站后台乐高套装"——你想写个网站接口?拼上 `@RestController` 积木。想操作数据库?拼上 `@Mapper` 积木。想加登录验证?拼上 `@Authenticate` 积木。所有的积木都有一套统一的拼法(注解),不需要自己从零搭轮子。它底层跑的是 Python + FastAPI,但写法上借鉴了 Java Spring Boot 的分层思路,让你用 `@Service`、`@Autowired` 这些熟悉的标签来组织代码。
125
+
126
+ - SpringBootAI 版本:`2.0.0`
127
+ - 内嵌 PyMyBatis 版本:`1.4.0`
128
+ - Python:3.10+
129
+ - 仓库:[GitHub - YUCONGGEN/springbootAI](https://github.com/YUCONGGEN/springbootAI)
130
+ - License:MIT
131
+
132
+ ---
133
+
134
+ ## 🚀 10 分钟快速体验
135
+
136
+ 想在 10 分钟内跑通第一个接口?按以下步骤来:
137
+
138
+ ```powershell
139
+ # 1. 创建项目并安装框架(如果还没装过)
140
+ mkdir my-first-app
141
+ cd my-first-app
142
+ python -m venv .venv
143
+ .\.venv\Scripts\Activate.ps1
144
+ python -m pip install springbootAI
145
+
146
+ # 2. 创建目录结构
147
+ mkdir demo
148
+ mkdir demo\controller
149
+ New-Item -Path "demo\__init__.py" -ItemType File -Force
150
+ New-Item -Path "demo\controller\__init__.py" -ItemType File -Force
151
+
152
+ # 3. 启动应用(先创建以下三份代码文件:demo/Application.py、demo/controller/HelloController.py、demo/application.yml)
153
+ python -m demo.Application
154
+ # 看到 "Uvicorn running on http://127.0.0.1:8080" 就成功了!
155
+
156
+ # 4. 测试(另开一个终端)
157
+ curl http://127.0.0.1:8080/api/hello/Alice
158
+ # 返回:{"code":200,"message":"success","data":{"message":"Hello, Alice"}}
159
+ ```
160
+
161
+ > 完整的代码文件内容和详细解释,请看 [新手入门指南](doc/BEGINNER_GUIDE.md) 第 4 节"快速开始"。这份入门指南从安装到验证,每一步都写好了,代码可以直接复制粘贴。
162
+
163
+ ---
164
+
165
+ ## 模块文档导航
166
+
167
+ 第一次使用请先读 [新手入门指南](doc/BEGINNER_GUIDE.md)。它从安装开始,带你创建第一个接口,并解释 Controller、Service、Bean、依赖注入和配置文件是什么。各模块文档统一按 **① 这解决什么问题?→ ② 怎么用?(贴代码)→ ③ 怎么验证?** 三步走模式组织,按需查阅即可。
168
+
169
+ | 模块 | 文档 | 安装方式 | 一句话说明 |
170
+ |------|------|----------|-----------|
171
+ | ✅ 新手入门 | [BEGINNER_GUIDE.md](doc/BEGINNER_GUIDE.md) | 随核心包 | 从零安装、创建项目、运行接口、打开 Swagger |
172
+ | ✅ 常用注解模块 | [ANNOTATION_MODULES.md](doc/ANNOTATION_MODULES.md) | 随核心包 | Bean Validation / 条件装配 / 缓存增强 / CSV / `@Version` / `@Transient` |
173
+ | 📦 AI(对接大模型) | [AI_MODULE.md](doc/AI_MODULE.md) | `pip install springbootAI[ai]` | ChatClient / Advisor / Tools / RAG / Function Calling / 多厂商适配 |
174
+ | 📦 LangChain | [LANGCHAIN_MODULE.md](doc/LANGCHAIN_MODULE.md) | `pip install springbootAI[langchain]` | Chains / Agents / Memory / Retrievers / VectorStores / 30+ 提供商 |
175
+ | ✅ 内嵌 PyMyBatis ORM | [ORM_MODULE.md](doc/ORM_MODULE.md) | 随核心包 | Mapper 注解 / XML Mapper / 分页 / SQL 安全 / DDL 自动建表 |
176
+ | ✅ Cloud 微服务 | [CLOUD_MODULE.md](doc/CLOUD_MODULE.md) | 随核心包 | 服务注册发现 / 配置刷新 / Feign / Sentinel / Gateway / 分布式事务 |
177
+ | 📦 Excel 读写 | [EXCEL_MODULE.md](doc/EXCEL_MODULE.md) | `pip install springbootAI[excel]` | `@ExcelProperty` / `@ExcelIgnore` 注解驱动读写 |
178
+ | 📦 CSV 读写 | [CSV_MODULE.md](doc/CSV_MODULE.md) | `pip install springbootAI[csv]` | `@CsvProperty` / `@CsvIgnore` 注解驱动读写 |
179
+ | ✅ Swagger 文档 | [SWAGGER_MODULE.md](doc/SWAGGER_MODULE.md) | 随核心包 | `@Tag` / `@Operation` 注解驱动 API 文档 |
180
+ | ✅ 八大模块 | [EIGHT_MODULES.md](doc/EIGHT_MODULES.md) | 随核心包 | 分页 / Actuator / 多数据源 / i18n / WebSocket 等 |
181
+ | ✅ 安全 | [SECURITY.md](doc/SECURITY.md) | 随核心包 | JWT 生成校验 / 密码加密 / SQL 注入防护 / 访问控制 |
182
+ | ✅ BeanUtils | [BEAN_UTILS.md](doc/BEAN_UTILS.md) | 随核心包 | `copy_properties` / `clone` 属性复制工具 |
183
+ | — AI 与 LangChain 测试 | [AI_LANGCHAIN_TEST_GUIDE.md](doc/AI_LANGCHAIN_TEST_GUIDE.md) | — | 162 个测试用例详解 |
184
+ | — 测试报告 | [TEST_REPORT.md](doc/TEST_REPORT.md) | — | 全量测试用例与覆盖范围 |
185
+
186
+ > 图例:✅ = 随核心包自带,不需要额外安装 | 📦 = 需要单独安装 extras | — = 参考文档,不是功能模块
187
+
188
+ 所有模块文档统一存放于 [`doc/`](doc/) 目录。
189
+
190
+ ### 🎯 新手推荐阅读顺序
191
+
192
+ 1. 先按 [新手入门指南](doc/BEGINNER_GUIDE.md) 跑通 `/api/hello/{name}`。
193
+ 2. 阅读本页第 4、6、7 章,理解配置、依赖注入和 Controller。
194
+ 3. 做数据库 CRUD 时阅读 [ORM_MODULE.md](doc/ORM_MODULE.md)。
195
+ 4. 需要输入校验、缓存或条件开关时阅读 [ANNOTATION_MODULES.md](doc/ANNOTATION_MODULES.md)。
196
+ 5. 最后再按业务需要选择安全、Cloud、AI、LangChain、Excel、WebSocket 等文档。
197
+
198
+ ---
199
+
200
+ ## 目录
201
+
202
+ 1. [框架概述与定位](#1-框架概述与定位)
203
+ 2. [能力状态](#2-能力状态)
204
+ 3. [安装与快速开始](#3-安装与快速开始)
205
+ 4. [配置系统(5 分钟看懂)](#4-配置系统5-分钟看懂)
206
+ 5. [注解参考](#5-注解参考)
207
+ 6. [IoC 与依赖注入(厨房比喻版)](#6-ioc-与依赖注入厨房比喻版)
208
+ 7. [Web 控制器](#7-web-控制器)
209
+ 8. [内嵌 PyMyBatis ORM 与 DDL](#8-内嵌-pymybatis-orm-与-ddl)
210
+ 9. [事务](#9-事务)
211
+ 10. [安全与权限](#10-安全与权限)
212
+ 11. [缓存、任务与高级 AOP](#11-缓存任务与高级-aop)
213
+ 12. [AI 与 LangChain 模块](#12-ai-与-langchain-模块)
214
+ 13. [Java 开发者看这里](#13-java-开发者看这里)
215
+ 14. [生产部署](#14-生产部署)
216
+ 15. [项目结构](#15-项目结构)
217
+ 16. [测试](#16-测试)
218
+ 17. [常见问题与排错](#17-常见问题与排错)
219
+ 18. [性能与容量验证](#18-性能与容量验证)
220
+
221
+ ---
222
+
223
+ ## 1. 框架概述与定位
224
+
225
+ ### 1.1 这是什么?
226
+
227
+ SpringBootAI 是一个 **Python Web 框架**。它把 Java Spring Boot 的"注解 + Controller/Service/Mapper 分层"思路搬到了 Python 世界——你写的是 Python 代码,用的是 `@Service`、`@RestController` 这些看起来像 Spring Boot 的注解,但底层真正跑起来的是 FastAPI 和 Uvicorn。
228
+
229
+ ### 1.2 三句话版本
230
+
231
+ 1. **写法像 Spring Boot**:用 `@RestController`、`@Service`、`@Mapper` 组织代码,Java 开发者一眼就懂。
232
+ 2. **运行在 Python**:底层是 FastAPI + Uvicorn,不依赖 Java、JAR 包或 Maven。
233
+ 3. **功能开箱即用**:数据库、缓存、安全、文档、AI 等能力已经打包好,装完就能用。
234
+
235
+ ### 1.3 版本
236
+
237
+ | 组件 | 当前版本 |
238
+ |------|----------|
239
+ | `spring` 框架 API | 2.0.0 |
240
+ | `spring.orm.pymybatis` | 1.4.0 |
241
+ | `spring.ai` AI 模块 | 1.3.0 |
242
+ | `spring.langchain` LangChain 模块 | 1.0.0 |
243
+ | Python | 3.10+ |
244
+
245
+ ### 1.4 适合什么场景
246
+
247
+ - 内部管理接口、轻量业务服务、教学和原型验证。
248
+ - 希望用 Controller/Service/Mapper 分层方式写 Python 的团队。
249
+ - SQLite 本地工具,或经过目标数据库集成测试的服务。
250
+ - 微服务架构(内置服务发现、限流熔断、分布式追踪、分布式事务)。
251
+
252
+ ### 1.5 能力边界(使用前必读)
253
+
254
+ - 自动化 ORM 测试使用 SQLite;MySQL、PostgreSQL、Oracle 需单独验证。
255
+ - `@Transactional` 支持七种 Spring 传播模式;`REQUIRES_NEW` 和 `NOT_SUPPORTED` 需要连接池有额外可用连接。
256
+ - Profile 会筛选 `@Profile` Bean,但不会自动合并 `application-{profile}.yml`。
257
+ - Nacos、RabbitMQ、Prometheus 依赖外部服务;Sentinel 限流熔断和 OpenTelemetry 追踪可内嵌运行。
258
+ - HTTP 事务模式是持久化补偿协调器,不提供 Seata AT 强一致性;生产强一致场景必须使用真实 Seata Server。
259
+ - 限流、分布式锁、幂等和缓存语义依赖 Redis 等后端,Redis 不可用时有本地降级路径。
260
+
261
+ ### 1.6 注解使用总览
262
+
263
+ SpringBootAI 注解会先把元数据放到 `__spring_annotations__`。之后是否生效,取决于有没有对应的扫描器或切面:
264
+
265
+ | 状态 | 含义 |
266
+ |------|------|
267
+ | 容器执行 | `ApplicationContext`、`BeanFactory` 或 Web 上下文会读取并执行 |
268
+ | 受管 Bean 执行 | 只有被组件扫描并由容器创建的实例方法才会被 AOP 包装;自己 `ClassName()` 创建的对象不生效 |
269
+ | 直接执行 | 装饰器本身返回包装函数,不依赖 IoC 容器 |
270
+ | 仅元数据 | 当前有注解类,但主运行链路没有消费者,写上不会得到注解名字所暗示的功能 |
271
+
272
+ > **⚠️ 这是最容易混淆的地方**:同名的注解(如 `@Transactional`),在 Java Spring 和 SpringBootAI 中的具体行为可能不同。不要因为名字一样就假设效果也一样。
273
+
274
+ ---
275
+
276
+ ## 2. 能力状态
277
+
278
+ | 模块 | 状态 | 一句话说明 |
279
+ |------|------|-----------|
280
+ | IoC 容器 | ✅ 可用 | 组件扫描、构造器/字段注入、Bean、延迟初始化、生命周期回调、Profile 过滤 |
281
+ | Web MVC | ✅ 可用 | 基于 FastAPI 的 GET/POST/PUT/PATCH/DELETE 路由、参数绑定、异常处理、CORS 和静态文件 |
282
+ | 配置 | ✅ 可用 | YAML、`${ENV:default}`、固定环境变量覆盖、标量类型保留 |
283
+ | 应用事件 | ✅ 可用 | `ApplicationEvent`、`@EventListener`、同步有序发布和异步监听 |
284
+ | 内嵌 ORM + DDL Auto | ✅ 可用 | PyMyBatis + JPA ddl-auto 自动建表(create/update/validate),支持 XML/注解 SQL、事务、缓存 |
285
+ | 本地事务 | ✅ 可用 | `@Transactional` 支持七种 Spring 传播模式 |
286
+ | JWT 与方法安全 | ✅ 可用 | access/refresh token、`@Authenticate`、角色/权限授权、401/403 映射 |
287
+ | 重试/异步 | ✅ 可用 | 受管 Bean 的退避重试、恢复方法和 Future/Task 异步调度 |
288
+ | Redis/缓存 | ✅ 可用 | 分布式锁、KV/Hash/List/Set/Counter,需要 Redis 服务 |
289
+ | RabbitMQ | ✅ 可用 | `@RabbitListener` 自动注册并后台消费,`RabbitTemplate` 发送 |
290
+ | Nacos 服务发现 | ✅ 可用 | 服务注册/发现/订阅 |
291
+ | Sentinel 限流熔断 | ✅ 可用 | 内嵌引擎,QPS 限流、异常比例熔断、热点参数限流,无需 Dashboard |
292
+ | 分布式追踪 | ✅ 可用 | 原生 OpenTelemetry(W3C traceparent),自动 HTTP/Feign 注入 |
293
+ | Seata 分布式事务 | ⚠️ 有边界 | `distributed` 对接真实 Seata SDK;`http` 仅提供持久化补偿,不等同 AT |
294
+ | API Gateway | ✅ 可用 | 轻量 ASGI/WSGI 网关,路由转发、路径重写、过滤器链、负载均衡 |
295
+ | Prometheus 监控 | ✅ 可用 | Counter/Gauge/Histogram 指标暴露 |
296
+ | Feign 声明式 HTTP | ✅ 可用 | 声明式接口、Fallback 降级、自动传播 XID 和 trace 头 |
297
+ | 高级 AOP | ✅ 可用 | 限流、熔断、幂等、审计、锁、指标、追踪、缓存 |
298
+ | AI 模块 | ✅ 可用 | ChatClient/ChatModel/EmbeddingModel/Advisor/Tools,OpenAI/Ollama/DeepSeek/Moonshot 适配 |
299
+ | LangChain 模块 | ✅ 可用 | Chains/Agents(6 种)/Memory/Retrievers/VectorStores + 30+ 提供商,双向适配器 |
300
+
301
+ ---
302
+
303
+ ## 3. 安装与快速开始
304
+
305
+ ### 3.1 环境准备
306
+
307
+ ```bash
308
+ cd springboot
309
+ python -m venv .venv
310
+ ```
311
+
312
+ 激活虚拟环境:
313
+
314
+ ```powershell
315
+ # PowerShell
316
+ .\.venv\Scripts\Activate.ps1
317
+ ```
318
+
319
+ ```bash
320
+ # Linux/macOS
321
+ source .venv/bin/activate
322
+ ```
323
+
324
+ ### 3.2 安装框架
325
+
326
+ ```bash
327
+ python -m pip install --upgrade pip
328
+ python -m pip install -e .
329
+ ```
330
+
331
+ 核心依赖包含 FastAPI、Uvicorn、PyYAML、python-dotenv、DBUtils、PyJWT、cryptography、bcrypt 和 Pydantic。**核心安装已包含内嵌 `spring.orm.pymybatis`,使用 Mapper 模式不需要再安装独立 `pymybatis`。**
332
+
333
+ ### 3.3 可选 extras
334
+
335
+ ```bash
336
+ python -m pip install -e ".[mysql]" # PyMySQL
337
+ python -m pip install -e ".[postgresql]" # psycopg2-binary
338
+ python -m pip install -e ".[oracle]" # cx-Oracle
339
+ python -m pip install -e ".[sqlalchemy]" # SQLAlchemy 模式
340
+ python -m pip install -e ".[redis]" # Redis 能力
341
+ python -m pip install -e ".[ast]" # sqlglot AST 校验
342
+ python -m pip install -e ".[rabbitmq]" # pika
343
+ python -m pip install -e ".[nacos]" # Nacos 客户端
344
+ python -m pip install -e ".[prometheus,logging]" # 指标和 loguru
345
+ python -m pip install -e ".[dev]" # 测试和静态工具
346
+ ```
347
+
348
+ AI 模块为可选依赖:
349
+
350
+ ```bash
351
+ pip install -r requirements-ai.txt # langchain-openai/langchain-community/numpy
352
+ ```
353
+
354
+ LangChain 模块复用 AI 模块的依赖,额外按需安装 partner 包(30+ 提供商懒加载,未安装的自动跳过):
355
+
356
+ ```bash
357
+ pip install langchain-anthropic # Anthropic Claude
358
+ pip install langchain-deepseek # DeepSeek
359
+ pip install langchain-ollama # Ollama 本地模型
360
+ pip install faiss-cpu # FAISS 向量库
361
+ pip install langchain-chroma # Chroma 向量库
362
+ ```
363
+
364
+ ### 3.4 验证安装
365
+
366
+ ```bash
367
+ python -c "import spring; print(spring.__version__)"
368
+ python -c "from spring.orm.pymybatis import __version__; print(__version__)"
369
+ ```
370
+
371
+ ### 3.5 最小应用
372
+
373
+ 仓库中的 `example`、`example1`、`example5` 只用于源码参考和回归验证,不会打包进 `springbootAI`。安装后请按下面结构创建自己的应用包。**每个被扫描目录都必须包含 `__init__.py`,并从项目根目录启动。**
374
+
375
+ 创建包结构:
376
+
377
+ ```text
378
+ demo/
379
+ |-- __init__.py
380
+ |-- Application.py
381
+ |-- application.yml
382
+ `-- controller/
383
+ |-- __init__.py
384
+ `-- HelloController.py
385
+ ```
386
+
387
+ 创建 `demo/Application.py`:
388
+
389
+ ```python
390
+ from spring.annotations import SpringBootApplication
391
+ from spring.main import run
392
+
393
+
394
+ @SpringBootApplication(scan_base_packages=["demo"])
395
+ class Application:
396
+ pass
397
+
398
+
399
+ if __name__ == "__main__":
400
+ run(Application)
401
+ ```
402
+
403
+ 创建 `demo/controller/HelloController.py`:
404
+
405
+ ```python
406
+ from spring.annotations import GetMapping, RequestMapping, RestController
407
+
408
+
409
+ @RequestMapping("/api")
410
+ @RestController
411
+ class HelloController:
412
+ @GetMapping("/hello/{name}")
413
+ def hello(self, name: str):
414
+ return {"message": f"Hello, {name}"}
415
+ ```
416
+
417
+ 创建 `demo/application.yml`:
418
+
419
+ ```yaml
420
+ server:
421
+ host: 127.0.0.1
422
+ port: 8080
423
+ cors:
424
+ allow_origins: []
425
+ allow_credentials: false
426
+
427
+ redis:
428
+ enabled: false
429
+
430
+ database:
431
+ enabled: false
432
+
433
+ jwt:
434
+ secret_key: development-only-secret
435
+ algorithm: HS256
436
+ ```
437
+
438
+ 运行和验证:
439
+
440
+ ```bash
441
+ python -m demo.Application
442
+ curl http://127.0.0.1:8080/api/hello/Alice
443
+ curl http://127.0.0.1:8080/actuator/health/liveness
444
+ curl http://127.0.0.1:8080/actuator/info
445
+ ```
446
+
447
+ 默认响应会统一包装为 `Result`:
448
+
449
+ ```json
450
+ {
451
+ "code": 200,
452
+ "message": "success",
453
+ "data": {"message": "Hello, Alice"}
454
+ }
455
+ ```
456
+
457
+ 交互式 API 文档由 FastAPI 提供,默认访问 `http://127.0.0.1:8080/docs`;原始规范位于 `/openapi.json`。
458
+
459
+ ### 3.6 生产 ASGI 入口
460
+
461
+ 开发时可以使用 `run()`;生产进程管理应使用 `create_app()` 构建 ASGI 应用:
462
+
463
+ ```python
464
+ # asgi.py
465
+ from spring.main import create_app
466
+ from demo.Application import Application
467
+
468
+ app = create_app(Application)
469
+ ```
470
+
471
+ ```bash
472
+ uvicorn asgi:app --host 0.0.0.0 --port 8080 --workers 2
473
+ ```
474
+
475
+ 多 worker 会创建多个独立进程、IoC 容器和连接池。连接池总量应按 `worker 数 x max_size` 评估。
476
+
477
+ ---
478
+
479
+ ## 4. 配置系统(5 分钟看懂)
480
+
481
+ > **🔑 核心概念**:配置文件(`application.yml`)就像餐厅的"运营手册"——写着餐厅地址(`host`)、门牌号(`port`)、要不要开外卖(`redis.enabled`)。换地方开店只改手册,不用重新装修。这一节 5 分钟帮你看懂配置的核心用法。
482
+
483
+ ### 4.1 配置放哪里
484
+
485
+ `ApplicationContext` 按以下顺序找配置文件:
486
+
487
+ 1. 启动类文件所在目录的 `application.yml`。
488
+ 2. 启动类目录下的 `config/application.yml`。
489
+ 3. 两处都不存在时使用代码默认值和环境变量。
490
+
491
+ 两处都存在时第一项优先,不会合并。
492
+
493
+ ### 4.2 环境变量占位符
494
+
495
+ ```yaml
496
+ server:
497
+ port: ${SERVER_PORT:8080}
498
+ database:
499
+ enabled: ${DB_ENABLED:false}
500
+ password: ${DB_PASSWORD}
501
+ ```
502
+
503
+ - `${NAME}`:环境变量必填,未设置时报错。
504
+ - `${NAME:default}`:未设置时用冒号后的默认值。
505
+ - 占位符占满整个值时,YAML 会把 `8080`、`false`、`null` 保留为 int、bool、None(标量类型不变)。
506
+ - 占位符嵌入普通字符串时结果是字符串。
507
+
508
+ ### 4.3 固定覆盖变量(常用)
509
+
510
+ 除了 YAML 里的 `${...}` 占位符,加载器还会直接读取以下环境变量:
511
+
512
+ | 分类 | 环境变量 |
513
+ |------|----------|
514
+ | 服务 | `SERVER_HOST`、`SERVER_PORT` |
515
+ | 环境 | `SPRING_PROFILES_ACTIVE`、`STARTUP_FAIL_FAST` |
516
+ | JWT | `JWT_SECRET_KEY`、`JWT_ALGORITHM` |
517
+ | 数据库 | `DB_ENABLED`、`DB_URL`、`DB_HOST`、`DB_PORT`、`DB_NAME`、`DB_USERNAME`、`DB_PASSWORD`、`DB_DRIVER` |
518
+ | Redis | `REDIS_ENABLED`、`REDIS_HOST`、`REDIS_PORT`、`REDIS_DB`、`REDIS_PASSWORD` |
519
+ | CORS | `CORS_ALLOW_ORIGINS`、`CORS_ALLOW_CREDENTIALS` |
520
+ | 日志 | `LOG_LEVEL`、`LOG_DIR`、`LOG_RETENTION`、`LOG_ROTATION` |
521
+ | 中间件 | `DISCOVERY_*`、`NACOS_SERVER`、`NACOS_USERNAME`、`NACOS_PASSWORD`、`SEATA_*`、`RABBITMQ_*`、`PROMETHEUS_*` |
522
+
523
+ `SPRING_PROFILES_ACTIVE` 用于 `@Profile` 组件筛选、生产安全校验,以及**自动加载并深度合并** `application-{profile}.yml`(v1.8.5 起实现)。Profile 文件与主 `application.yml` 同目录,加载顺序:主配置 → profile 配置深度合并(profile 覆盖主配置的同名键),合并后再解析 `${ENV:default}` 占位符。例如 `SPRING_PROFILES_ACTIVE=prod` 会自动合并 `application-prod.yml`。
524
+
525
+ ### 4.4 Docker 容器 IP 自动检测(开发环境)
526
+
527
+ 在开发环境中,当 `database.host` 设为 `127.0.0.1` 或 `localhost` 时,框架会自动通过 `docker ps` 和 `docker inspect` 查找映射了目标端口的容器内部 IP 进行连接。
528
+
529
+ - 支持通过端口映射精确匹配(如 `0.0.0.0:3306->3306/tcp`)
530
+ - 支持 MySQL/MariaDB/PostgreSQL 数据库镜像兜底匹配
531
+ - 设置 `SPRING_DISABLE_DOCKER_IP_DETECT=1` 可禁用(生产环境推荐)
532
+
533
+ ### 4.5 在代码里读配置
534
+
535
+ ```python
536
+ from spring.config import ConfigLoader
537
+
538
+ loader = ConfigLoader("./myapp/application.yml")
539
+ port = loader.get("server.port", 8080)
540
+ database = loader.get_prefix_config("database")
541
+ snapshot = loader.get_config()
542
+ ```
543
+
544
+ 返回的配置是深拷贝,你改了不会影响原始配置。
545
+
546
+ ### 4.6 Profile 的真实行为
547
+
548
+ ```python
549
+ from spring.annotations import Profile, Service
550
+
551
+
552
+ @Profile("dev")
553
+ @Service
554
+ class DevelopmentService:
555
+ pass
556
+ ```
557
+
558
+ Profile 用于 Bean 过滤和生产安全校验。多环境配置可使用以下方式之一:
559
+
560
+ 1. 在部署流程中生成最终 `application.yml`。
561
+ 2. 大量使用环境变量占位符。
562
+ 3. 显式创建 `ConfigLoader(config_path=...)` 和 `ApplicationContext`。
563
+
564
+ ### 4.7 生产配置校验
565
+
566
+ 当 Profile 是 `prod` 或 `production` 时:
567
+
568
+ - 默认 JWT 密钥、空密钥或少于 32 字符的密钥会导致启动失败。
569
+ - `startup.fail_fast` 默认视为开启。
570
+ - CORS 开启凭证时配置 `*` 来源会直接失败。
571
+
572
+ ### 4.8 健康检查
573
+
574
+ | 地址 | 用途 |
575
+ |------|------|
576
+ | `/actuator/health` | 聚合组件健康状态;降级时返回 503 |
577
+ | `/actuator/health/liveness` | 进程存活检查(用于 K8s livenessProbe) |
578
+ | `/actuator/health/readiness` | 服务就绪检查(用于 K8s readinessProbe) |
579
+ | `/actuator/info` | 应用名称、当前 Profile、框架和 Python 版本 |
580
+
581
+ `database.enabled: false` 时数据库状态为 `DISABLED`,不会创建 `test.db`。
582
+
583
+ > **⚠️ 新手常见错误**:
584
+ > - ❌ 错误:"我改了 YAML,重新请求接口怎么没生效?"
585
+ > - ✅ 正解:修改 YAML 后需要**重启应用**(`Ctrl+C` 停掉再重新运行)。YAML 配置是启动时一次性读取的。
586
+
587
+ ---
588
+
589
+ ## 5. 注解参考
590
+
591
+ > 说明:本节是框架最完整的注解参考。所有 AOP 类注解(事务、缓存、重试、异步、定时、高级 AOP、安全等)都要求**方法所在类带组件注解(`@Service`/`@Component`/`@Repository`/`@Controller` 等)并由容器取得实例**,自己 `ClassName()` 创建的对象不会生效。
592
+
593
+ ### 5.1 启动与扫描
594
+
595
+ #### @SpringBootApplication
596
+
597
+ **含义**:应用启动类注解,组合了 `@Configuration`、`@ComponentScan` 的功能。
598
+
599
+ **参数**:
600
+
601
+ | 参数 | 类型 | 默认值 | 说明 |
602
+ |------|------|--------|------|
603
+ | scan_base_packages | List[str] | None | 扫描的基础包路径 |
604
+
605
+ ```python
606
+ from spring.annotations import SpringBootApplication
607
+
608
+ @SpringBootApplication(scan_base_packages=["com.example.service", "com.example.controller"])
609
+ class Application:
610
+ pass
611
+ ```
612
+
613
+ **注意事项**:每个应用只能有一个启动类;`scan_base_packages` 是可导入包名,不是文件路径。
614
+
615
+ ### 5.2 组件与依赖注入
616
+
617
+ #### @Component / @Service / @Repository
618
+
619
+ ```python
620
+ from spring.annotations import Component, Service, Repository
621
+
622
+ @Component
623
+ class EmailUtil:
624
+ def send(self, to: str, content: str):
625
+ pass
626
+
627
+ @Service
628
+ class UserService:
629
+ def get_user(self, user_id: int):
630
+ return {"id": user_id, "name": "test"}
631
+
632
+ @Repository
633
+ class UserRepository:
634
+ def find_by_id(self, user_id: int):
635
+ pass
636
+ ```
637
+
638
+ #### @Autowired
639
+
640
+ ```python
641
+ from spring.annotations import Service, Autowired
642
+
643
+ @Service
644
+ class UserService:
645
+ # 构造函数注入(推荐)
646
+ @Autowired
647
+ def __init__(self, user_repository):
648
+ self.user_repository = user_repository
649
+ ```
650
+
651
+ **推荐构造器注入**。依赖参数应写类型注解,构造器注入能在启动阶段暴露缺失和循环依赖。
652
+
653
+ #### @Qualifier / @Primary / @Profile / @Lazy
654
+
655
+ 完整参数、示例和边界说明见原文档第 5.2 节。
656
+
657
+ ### 5.3 Web 控制器注解
658
+
659
+ #### @Controller / @RestController
660
+
661
+ `@RestController` 组合了 `@Controller` 和 `@ResponseBody`,返回值自动序列化为 JSON。
662
+
663
+ ```python
664
+ from spring.annotations import RestController, GetMapping
665
+
666
+ @RestController
667
+ class UserController:
668
+ @GetMapping("/api/users/{id}")
669
+ def get_user(self, id: int):
670
+ return {"id": id, "name": "test"}
671
+ ```
672
+
673
+ #### @RequestMapping / @GetMapping / @PostMapping / @PutMapping / @PatchMapping / @DeleteMapping
674
+
675
+ ```python
676
+ from spring.annotations import RestController, GetMapping, PostMapping, PutMapping, PatchMapping, DeleteMapping
677
+
678
+ @RestController
679
+ class UserController:
680
+ @GetMapping("/api/users/{id}")
681
+ def get_user(self, id: int):
682
+ return {"id": id, "name": "test"}
683
+
684
+ @PostMapping("/api/users")
685
+ def create_user(self, name: str, email: str):
686
+ return {"id": 1, "name": name, "email": email}
687
+
688
+ @PutMapping("/api/users/{id}")
689
+ def update_user(self, id: int, name: str):
690
+ return {"id": id, "name": name}
691
+
692
+ @PatchMapping("/api/users/{id}")
693
+ def patch_user(self, id: int, name: str = ""):
694
+ return {"id": id, "name": name, "method": "PATCH"}
695
+
696
+ @DeleteMapping("/api/users/{id}")
697
+ def delete_user(self, id: int):
698
+ return {"status": "deleted", "id": id}
699
+ ```
700
+
701
+ #### @ControllerAdvice / @ExceptionHandler
702
+
703
+ ```python
704
+ from spring.annotations import ControllerAdvice, ExceptionHandler
705
+
706
+ @ControllerAdvice
707
+ class GlobalExceptionHandler:
708
+ @ExceptionHandler(ValueError, TypeError)
709
+ def handle_validation_error(self, e: Exception):
710
+ return {"code": 400, "message": f"参数错误: {str(e)}"}
711
+
712
+ @ExceptionHandler(Exception)
713
+ def handle_generic_error(self, e: Exception):
714
+ return {"code": 500, "message": f"服务器错误: {str(e)}"}
715
+ ```
716
+
717
+ ### 5.4 参数绑定注解
718
+
719
+ > 参数标记的正确语法是 **"作为默认值"写在方法参数上**,而不是写在函数上方。
720
+
721
+ | 写法 | 来源 |
722
+ |------|------|
723
+ | 参数名出现在 `{...}` 路径 | 路径参数 |
724
+ | 参数类型是 `dict` | JSON 请求体 |
725
+ | 有普通默认值 | 可选查询参数 |
726
+ | 无默认值且不在路径 | 必填查询参数 |
727
+ | 默认值为 `RequestParam(...)` | 显式查询参数 |
728
+ | 默认值为 `RequestBody()` | 显式请求体 |
729
+ | 默认值为 `RequestHeader(...)` | Header |
730
+ | 默认值为 `CookieValue(...)` | Cookie |
731
+
732
+ 完整参数和示例见原文档第 5.4 节。
733
+
734
+ ### 5.5 配置与属性注解
735
+
736
+ ```python
737
+ from spring.annotations import Configuration, Bean, Service, Value, ConfigurationProperties, Component
738
+
739
+ @Configuration
740
+ class AppConfig:
741
+ @Bean(name="dataSource", init_method="init", destroy_method="close")
742
+ def data_source(self):
743
+ return DataSource()
744
+
745
+ @Service
746
+ class AppService:
747
+ @Value("${app.name}")
748
+ def set_app_name(self, value: str):
749
+ self.app_name = value
750
+
751
+ @Component
752
+ @ConfigurationProperties(prefix="spring.datasource")
753
+ class DataSourceProperties:
754
+ def __init__(self):
755
+ self.url = ""
756
+ self.username = ""
757
+ self.password = ""
758
+ ```
759
+
760
+ ### 5.6 日志与生命周期
761
+
762
+ ```python
763
+ from spring.annotations import Service, Slf4j, PostConstruct, PreDestroy
764
+
765
+ @Service
766
+ @Slf4j # 自动创建 self.logger
767
+ class UserService:
768
+ def create_user(self, name: str):
769
+ self.logger.info(f"正在创建用户: {name}")
770
+ return {"id": 1, "name": name}
771
+
772
+ @Service
773
+ class InitService:
774
+ @PostConstruct
775
+ def init(self):
776
+ self.config = self.load_config()
777
+
778
+ @PreDestroy
779
+ def cleanup(self):
780
+ if self.connection:
781
+ self.connection.close()
782
+ ```
783
+
784
+ ### 5.7 应用事件
785
+
786
+ ```python
787
+ from spring.annotations import ApplicationEvent, Autowired, EventListener, Service
788
+ from spring.event import ApplicationEventPublisher
789
+
790
+
791
+ class UserCreatedEvent(ApplicationEvent):
792
+ def __init__(self, user_id: int):
793
+ super().__init__(source="user-service")
794
+ self.user_id = user_id
795
+
796
+
797
+ @Service
798
+ class UserEventHandler:
799
+ @EventListener(event_type=UserCreatedEvent, order=1)
800
+ def on_user_created(self, event: UserCreatedEvent):
801
+ print(f"created: {event.user_id}")
802
+
803
+
804
+ @Service
805
+ class UserService:
806
+ @Autowired
807
+ def __init__(self, publisher: ApplicationEventPublisher):
808
+ self.publisher = publisher
809
+
810
+ def create(self, user_id: int):
811
+ self.publisher.publish_event(UserCreatedEvent(user_id))
812
+ ```
813
+
814
+ ### 5.8 核心高级注解(10 个)
815
+
816
+ #### @RateLimit - 接口限流
817
+
818
+ **解决什么问题**:限制接口被调用的频率,防止被刷爆。
819
+
820
+ ```python
821
+ from spring.annotations import RateLimit, Service
822
+
823
+ @Service
824
+ class OrderService:
825
+ # 每分钟最多100次请求(全局限制)
826
+ @RateLimit(max_requests=100, time_window=60)
827
+ def create_order(self, user_id: str, product_id: str):
828
+ return {"order_id": "ORD_123"}
829
+
830
+ # 按用户ID限流:每个用户每秒最多10次
831
+ @RateLimit(max_requests=10, time_window=1, key="user_id")
832
+ def get_user_info(self, user_id: str):
833
+ return {"user_id": user_id}
834
+ ```
835
+
836
+ #### @CircuitBreaker - 熔断器
837
+
838
+ **解决什么问题**:当某个方法持续失败时,暂时停止调用它("熔断"),等一段时间后再试。
839
+
840
+ ```python
841
+ from spring.annotations import CircuitBreaker, Service
842
+
843
+ @Service
844
+ class PaymentService:
845
+ @CircuitBreaker(failure_threshold=3, recovery_timeout=10, fallback_method="payment_fallback")
846
+ def process_payment(self, order_id: str, amount: float):
847
+ if amount > 10000:
848
+ raise Exception("支付网关超时")
849
+ return {"status": "success", "transaction_id": "TXN_123"}
850
+
851
+ def payment_fallback(self, order_id: str, amount: float):
852
+ return {"status": "degraded", "message": "支付服务暂时不可用,请稍后重试"}
853
+ ```
854
+
855
+ #### @Idempotent - 幂等性
856
+
857
+ **解决什么问题**:用户手抖点了两次"下单",保证只有一次生效。
858
+
859
+ ```python
860
+ from spring.annotations import Idempotent, Service
861
+
862
+ @Service
863
+ class OrderService:
864
+ @Idempotent(key="order_id", expire=300, prefix="order")
865
+ def create_order(self, order_id: str, user_id: str, amount: float):
866
+ return {"order_id": order_id, "status": "created"}
867
+ ```
868
+
869
+ #### @AuditLog / @FeatureToggle / @Lock / @Metrics / @Synchronized / @Validate / @Trace
870
+
871
+ 这些高级注解的完整参数、示例和边界,沿用上方 @RateLimit 和 @CircuitBreaker 的模式。详细参数表见原文档第 5.8 节。
872
+
873
+ ### 5.9 事务、缓存、任务与异步注解
874
+
875
+ ```python
876
+ from spring.annotations import Service, Transactional, Cacheable, Retryable, Async, Scheduled
877
+ from spring.retry.retry_annotations import Backoff
878
+
879
+ @Service
880
+ class OrderService:
881
+ @Transactional(rollback_for=[Exception])
882
+ def create_order(self, user_id: int, product_id: int):
883
+ return {"order_id": 1}
884
+
885
+ @Cacheable(value="users", key="#user_id")
886
+ def get_user(self, user_id: int):
887
+ return {"id": user_id, "name": "test"}
888
+
889
+ @Retryable(value=(ConnectionError,), max_retries=3, backoff=Backoff(delay=1000, multiplier=2.0))
890
+ def call_remote(self):
891
+ pass
892
+
893
+ @Async
894
+ def send_email(self, to: str, content: str):
895
+ time.sleep(1)
896
+ print(f"Email sent to {to}")
897
+
898
+ @Service
899
+ class ScheduledTasks:
900
+ @Scheduled(fixed_rate=5000)
901
+ def report_current_time(self):
902
+ print("Current time:", time.time())
903
+ ```
904
+
905
+ **边界要点**:`max_retries=3` 包含首次调用;`@Async` 同步方法返回 `Future`;`@Scheduled` 多 worker 会重复执行。
906
+
907
+ ### 5.10 安全、Cloud 与消息注解
908
+
909
+ | 注解 | 设计意图 | 当前真实状态 |
910
+ |------|----------|--------------|
911
+ | `@Authenticate` | 校验 JWT 并建立安全上下文 | 受管 Bean 实际执行;HTTP 控制器自动读取 `Authorization: Bearer ...` |
912
+ | `@PreAuthorize` | 按角色/权限表达式授权 | 受管 Bean 实际执行;未认证返回 401,权限不足返回 403 |
913
+ | `@Secured` | 按任一角色授权 | 受管 Bean 实际执行 |
914
+ | `@SentinelResource` | 限流、业务异常 fallback | 受管 Bean 方法会包装;已内嵌限流熔断引擎 |
915
+ | `@GlobalTransactional` | 通过 Seata 管理全局事务 | 受管 Bean 方法调用 Seata manager |
916
+ | `@RabbitListener` | 注册 RabbitMQ 消费者 | 可直接装饰受管 Bean 方法 |
917
+
918
+ > Cloud 注解完整参数已分离至:[CLOUD_MODULE.md](doc/CLOUD_MODULE.md)。MyBatis 注解已分离至:[ORM_MODULE.md](doc/ORM_MODULE.md)。
919
+
920
+ ### 5.13 注解组合使用与执行顺序
921
+
922
+ **注解执行顺序**(AOP 从外到内):
923
+
924
+ ```
925
+ 1. @SentinelResource / @CircuitBreaker (最外层,熔断降级)
926
+ 2. @RateLimit (限流)
927
+ 3. @Lock / @Synchronized (锁)
928
+ 4. @Metrics (监控)
929
+ 5. @Trace (追踪)
930
+ 6. @AuditLog (审计)
931
+ 7. @Idempotent (幂等)
932
+ 8. @Validate / @Valid / @Validated (参数校验)
933
+ 9. 业务方法
934
+ ```
935
+
936
+ **常用组合模式**:
937
+
938
+ ```python
939
+ # 接口防护三件套
940
+ @SentinelResource(value="xxx", fallback="xxx_fallback")
941
+ @Metrics(name="xxx")
942
+ @RateLimit(max_requests=100, time_window=60)
943
+ def xxx_method(self):
944
+ pass
945
+
946
+ # 支付操作完整组合
947
+ @Metrics(name="payment.create")
948
+ @Lock(key="payment_{order_id}", expire=10, wait_timeout=3)
949
+ @Idempotent(key="payment_{order_id}", expire=300)
950
+ @Validate(field="amount", min=0.01, message="金额必须大于0")
951
+ def create(self, order_id: str, amount: float):
952
+ return {"order_id": order_id, "amount": amount}
953
+ ```
954
+
955
+ ---
956
+
957
+ ## 6. IoC 与依赖注入(厨房比喻版)
958
+
959
+ > 🍽️ **厨房比喻**:想象你开一个餐厅。IoC 容器就是一个"自动 HR 系统"——你只要在员工简历上贴标签(`@Service`=厨师、`@Controller`=服务员、`@Mapper`=仓管员),系统就自动把他们招来、办好入职、安排工位。依赖注入(`@Autowired`)就是——厨师说"我需要一个仓管员配合我",HR 自动把人分过去,不用你自己跑仓库找人。
960
+
961
+ ### 6.1 组件类型
962
+
963
+ | 注解 | 用途 | 厨房角色 |
964
+ |------|------|----------|
965
+ | `@Component` | 通用组件 | 任何员工 |
966
+ | `@Service` | 业务服务 | 后厨大厨 |
967
+ | `@Repository` | 数据访问封装 | 仓库管理员 |
968
+ | `@RestController` / `@Controller` | Web 控制器 | 前台服务员 |
969
+ | `@Configuration` | Bean 配置类 | HR 经理(定义"怎么招人") |
970
+ | `@Bean` | 工厂方法产生 Bean | 招聘流程 |
971
+ | `@Primary` | 同类型多个 Bean 时的首选 | "优先选这个人" |
972
+ | `@Profile` | 按环境筛选 | "这个人只在旗舰店上班" |
973
+ | `@Lazy` | 延迟创建 | 弹性用工(需要时才入职) |
974
+
975
+ ### 6.2 构造器注入(推荐方式)
976
+
977
+ ```python
978
+ from spring.annotations import Autowired, Service
979
+
980
+
981
+ @Service
982
+ class GreetingService:
983
+ def greet(self, name: str) -> str:
984
+ return f"Hello, {name}"
985
+
986
+
987
+ @Service
988
+ class UserService:
989
+ @Autowired
990
+ def __init__(self, greeting_service: GreetingService):
991
+ self.greeting_service = greeting_service
992
+ ```
993
+
994
+ 构造器注入能在启动阶段暴露缺失和循环依赖,优先于字段注入。
995
+
996
+ ### 6.3 多实现与 @Qualifier
997
+
998
+ 同类型存在多个 Bean 时,使用 `@Primary` 或 `@Qualifier` 指定名称。
999
+
1000
+ ### 6.4 配置类和 @Bean
1001
+
1002
+ ```python
1003
+ from spring.annotations import Bean, Configuration
1004
+
1005
+
1006
+ @Configuration
1007
+ class AppConfig:
1008
+ @Bean(name="clock")
1009
+ def clock(self):
1010
+ import time
1011
+ return time.time
1012
+ ```
1013
+
1014
+ ### 6.5 生命周期
1015
+
1016
+ ```python
1017
+ from spring.annotations import Component, PostConstruct, PreDestroy
1018
+
1019
+
1020
+ @Component
1021
+ class ResourceHolder:
1022
+ @PostConstruct
1023
+ def start(self):
1024
+ # 初始化资源:打开数据库连接、加载配置等
1025
+ pass
1026
+
1027
+ @PreDestroy
1028
+ def stop(self):
1029
+ # 清理资源:关闭连接、保存状态等
1030
+ pass
1031
+ ```
1032
+
1033
+ > **⚠️ 新手常见错误**:
1034
+ > - ❌ 错误:手动 `service = UserService()` 创建对象,然后问"为什么 `@Cacheable` 不生效?"
1035
+ > - ✅ 正解:容器创建的 Bean 才是"正式员工",有事务、缓存、重试等 AOP 能力。你自己 `new` 出来的是"临时工",什么福利都没有。
1036
+
1037
+ ---
1038
+
1039
+ ## 7. Web 控制器
1040
+
1041
+ > 🍽️ **厨房比喻**:Controller 就是餐厅的前台服务员——客人进来点菜(发 HTTP 请求),服务员把菜单传给后厨(Service),再把做好的菜端回来(返回 JSON)。服务员不炒菜,只接单和上菜。
1042
+
1043
+ ### 7.1 类和方法映射
1044
+
1045
+ ```python
1046
+ from spring.annotations import (
1047
+ DeleteMapping, GetMapping, PatchMapping, PostMapping, PutMapping,
1048
+ RequestMapping, RestController,
1049
+ )
1050
+
1051
+
1052
+ @RequestMapping("/users")
1053
+ @RestController
1054
+ class UserController:
1055
+ @GetMapping("/{user_id}")
1056
+ def get(self, user_id: int):
1057
+ return {"id": user_id}
1058
+
1059
+ @PostMapping("")
1060
+ def create(self, body: dict):
1061
+ return body
1062
+
1063
+ @PutMapping("/{user_id}")
1064
+ def update(self, user_id: int, body: dict):
1065
+ return {"id": user_id, **body}
1066
+
1067
+ @PatchMapping("/{user_id}")
1068
+ def patch(self, user_id: int, body: dict):
1069
+ return {"id": user_id, **body, "partial": True}
1070
+
1071
+ @DeleteMapping("/{user_id}")
1072
+ def delete(self, user_id: int):
1073
+ return {"deleted": user_id}
1074
+ ```
1075
+
1076
+ 未指定映射路径时默认使用方法名;类级路径前缀必须使用 `@RequestMapping("/users")`。
1077
+
1078
+ ### 7.2 统一返回值
1079
+
1080
+ ```python
1081
+ from spring.web import Result
1082
+
1083
+ return Result.success({"id": 1}, message="创建成功")
1084
+ return Result.bad_request("姓名不能为空")
1085
+ return Result.not_found("用户不存在")
1086
+ ```
1087
+
1088
+ ### 7.3 全局异常处理 & CORS & 拦截器
1089
+
1090
+ ```python
1091
+ from spring.annotations import ControllerAdvice, ExceptionHandler, Component
1092
+ from spring.web import Result
1093
+ from spring.web.interceptor import HandlerInterceptor
1094
+
1095
+
1096
+ @ControllerAdvice
1097
+ class GlobalExceptionHandler:
1098
+ @ExceptionHandler(ValueError)
1099
+ def handle_value_error(self, error: ValueError):
1100
+ return Result.bad_request(str(error))
1101
+
1102
+
1103
+ @Component
1104
+ class AuditInterceptor(HandlerInterceptor):
1105
+ async def pre_handle(self, request, handler):
1106
+ request.state.started = True
1107
+ return True
1108
+ ```
1109
+
1110
+ CORS 配置:
1111
+
1112
+ ```yaml
1113
+ server:
1114
+ cors:
1115
+ allow_origins:
1116
+ - https://console.example.com
1117
+ allow_credentials: true
1118
+ ```
1119
+
1120
+ ---
1121
+
1122
+ ## 8. 内嵌 PyMyBatis ORM 与 DDL
1123
+
1124
+ > 🍽️ **厨房比喻**:数据库就是仓库,Mapper 就是仓库管理员。厨师说要什么食材,管理员去仓库精准取货。你不用自己写繁琐的库存查询,只要告诉管理员"我要用户 ID 为 1 的信息"。
1125
+
1126
+ > 本节(Mapper 注解、XML Mapper、分页、SQL 安全、DDL 自动建表等)已分离至:[ORM_MODULE.md](doc/ORM_MODULE.md)。
1127
+
1128
+ ---
1129
+
1130
+ ## 9. 事务
1131
+
1132
+ > 🍽️ **厨房比喻**:事务就像"做一道菜"——切菜、下锅、调味、装盘,必须全部完成才能端给客人。中间任何一步失败,前面切好的菜也要扔掉(回滚)。
1133
+
1134
+ ### 9.1 Service 事务
1135
+
1136
+ ```python
1137
+ from spring.annotations import Autowired, Service, Transactional
1138
+
1139
+
1140
+ @Service
1141
+ class RegistrationService:
1142
+ @Autowired
1143
+ def __init__(self, user_mapper: UserMapper, audit_mapper: AuditMapper):
1144
+ self.user_mapper = user_mapper
1145
+ self.audit_mapper = audit_mapper
1146
+
1147
+ @Transactional(rollback_for=[Exception])
1148
+ def register(self, name: str, email: str):
1149
+ user_id = self.user_mapper.insert(name, email)
1150
+ self.audit_mapper.insert("USER_CREATED", user_id)
1151
+ return user_id
1152
+ ```
1153
+
1154
+ **执行过程**:进入方法时创建会话并开始事务 → 当前上下文内所有 Mapper 共用该会话 → 正常返回时提交 → 满足回滚规则的异常导致回滚 → 退出后归还连接池。
1155
+
1156
+ ### 9.2 传播级别(支持全部七种)
1157
+
1158
+ ```python
1159
+ @Transactional(propagation="REQUIRED")
1160
+ @Transactional(propagation="NESTED")
1161
+ ```
1162
+
1163
+ `NESTED` 在已有事务中创建 savepoint;`REQUIRES_NEW` 使用独立 Session/连接,连接池 `max_size` 至少应能容纳并发的外层和内层连接。
1164
+
1165
+ ### 9.3 嵌套事务 & 手动事务
1166
+
1167
+ 嵌套 `REQUIRED` 采用 rollback-only 语义。显式 `NESTED` 时内层异常回滚到 savepoint,外层仍可提交。
1168
+
1169
+ ```python
1170
+ with factory.open_session() as session:
1171
+ with session.transaction():
1172
+ session.insert("INSERT INTO users(name) VALUES (#{name})", {"name": "A"})
1173
+ session.insert("INSERT INTO audit(event) VALUES (#{event})", {"event": "created"})
1174
+ ```
1175
+
1176
+ ---
1177
+
1178
+ ## 10. 安全与权限
1179
+
1180
+ > ✈️ **安检通道比喻**:安全模块就像机场安检——`@Authenticate` 检查登机牌(JWT Token),`@PreAuthorize` 检查是不是头等舱(角色/权限),`@Secured` 检查有没有进入某个区域的权限。
1181
+
1182
+ ### 10.1 JWT 初始化
1183
+
1184
+ ```yaml
1185
+ jwt:
1186
+ secret_key: ${JWT_SECRET_KEY}
1187
+ algorithm: HS256
1188
+ expires_in: 3600
1189
+ issuer: springpy-api
1190
+ audience: springpy-client
1191
+ leeway: 5
1192
+ ```
1193
+
1194
+ 生产密钥至少 32 字符。
1195
+
1196
+ ### 10.2 access/refresh token
1197
+
1198
+ ```python
1199
+ from spring.security.jwt_utils import JwtUtils, jwt_utils
1200
+
1201
+ access = jwt_utils.generate_token({"sub": "user-1"})
1202
+ refresh = jwt_utils.generate_refresh_token({"sub": "user-1"})
1203
+ claims = jwt_utils.decode_token(access)
1204
+ new_access = jwt_utils.refresh_token(refresh)
1205
+ ```
1206
+
1207
+ **易错点**:access token 不能当作 refresh token 使用;不同密钥生成的 token 不能交叉校验。
1208
+
1209
+ ### 10.3 方法权限
1210
+
1211
+ ```python
1212
+ from spring.annotations import Authenticate, GetMapping, PreAuthorize, RequestMapping, RestController
1213
+
1214
+
1215
+ @RestController
1216
+ @RequestMapping("/admin")
1217
+ class AdminController:
1218
+ @GetMapping("/report")
1219
+ @Authenticate
1220
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
1221
+ def report(self):
1222
+ return {"scope": "admin"}
1223
+ ```
1224
+
1225
+ 认证失败 → HTTP 401,授权失败 → HTTP 403。
1226
+
1227
+ ### 10.4 安全基线
1228
+
1229
+ - `SPRING_PROFILES_ACTIVE=production` + `STARTUP_FAIL_FAST=true`
1230
+ - `JWT_SECRET_KEY` 使用至少 32 字符的随机密钥
1231
+ - `CORS_ALLOW_CREDENTIALS=true` 时不能用 `*` 来源
1232
+ - SQL 值始终使用 `#{name}` 参数绑定
1233
+
1234
+ ---
1235
+
1236
+ ## 11. 缓存、任务与高级 AOP
1237
+
1238
+ ### 11.1 @Cacheable
1239
+
1240
+ ```python
1241
+ from spring.annotations import Service, Cacheable
1242
+
1243
+ @Service
1244
+ class UserService:
1245
+ @Cacheable(value="users", key="#user_id")
1246
+ def get_user(self, user_id: int):
1247
+ return {"id": user_id, "name": "test"}
1248
+ ```
1249
+
1250
+ 本地内存缓存,最多 1000 项、TTL 300 秒,不跨进程。生产多 worker 应接入共享 Redis。
1251
+
1252
+ ### 11.2 @Retryable
1253
+
1254
+ ```python
1255
+ from spring.annotations import Retryable
1256
+ from spring.retry.retry_annotations import Backoff
1257
+
1258
+ @Retryable(value=(ConnectionError,), max_retries=3, backoff=Backoff(delay=1000, multiplier=2.0))
1259
+ def call_remote(self):
1260
+ pass
1261
+ ```
1262
+
1263
+ **只对幂等操作开启自动重试**(如读操作)。写操作必须先设计幂等键。
1264
+
1265
+ ### 11.3 @Async & @Scheduled
1266
+
1267
+ ```python
1268
+ from spring.annotations import Service, Async, Scheduled
1269
+
1270
+ @Service
1271
+ class EmailService:
1272
+ @Async
1273
+ def send_email(self, to: str, content: str):
1274
+ time.sleep(1)
1275
+ print(f"Email sent to {to}")
1276
+
1277
+ @Service
1278
+ class CleanupJob:
1279
+ @Scheduled(cron="0 */5 * * * *")
1280
+ def cleanup(self):
1281
+ pass
1282
+ ```
1283
+
1284
+ `@Async` 线程池任务不继承 MyBatis 事务;`@Scheduled` 多 worker 会重复执行。
1285
+
1286
+ ### 11.4 高级 AOP 上线前验证
1287
+
1288
+ | 注解 | 上线前必须验证 |
1289
+ |------|--------------|
1290
+ | `@RateLimit` | 多进程/多副本一致性、Redis 故障降级 |
1291
+ | `@CircuitBreaker` | 状态存储、半开恢复、超时 |
1292
+ | `@Idempotent` | 键设计、TTL、并发竞争 |
1293
+ | `@Lock` | 租约续期、误释放、时钟同步 |
1294
+
1295
+ ---
1296
+
1297
+ ## 12. AI 与 LangChain 模块
1298
+
1299
+ ### 12.1 AI 模块(对接大模型)
1300
+
1301
+ > 完整文档:[AI_MODULE.md](doc/AI_MODULE.md)。安装:`pip install springbootAI[ai]`。
1302
+ >
1303
+ > 提供 ChatClient(链式对话)、Advisor(对话顾问)、Tools(工具调用)、RAG(知识库检索增强生成)、Function Calling 等能力。支持 OpenAI / Ollama / DeepSeek / Moonshot 等多家大模型。
1304
+
1305
+ ### 12.2 LangChain 模块
1306
+
1307
+ > 完整文档:[LANGCHAIN_MODULE.md](doc/LANGCHAIN_MODULE.md)。安装:`pip install springbootAI[langchain]`。
1308
+ >
1309
+ > 封装 langchain classic 全套:Chains / Agents(6 种) / Memory / Retrievers / VectorStores / Parsers / Loaders + 30+ 提供商。双向适配器复用 `spring.ai` 的模型 Bean。
1310
+
1311
+ **最小示例**(无需 API Key):
1312
+
1313
+ ```python
1314
+ from spring.context.registry import BeanRegistry
1315
+ from spring.ai.autoconfig import configure_ai
1316
+ from spring.langchain.autoconfig import configure_langchain
1317
+
1318
+ registry = BeanRegistry()
1319
+ configure_ai(registry=registry)
1320
+ beans = configure_langchain(registry=registry)
1321
+
1322
+ chain = beans["lcChainService"]
1323
+ print(chain.run_llm_chain("回答: {q}", q="你好"))
1324
+ ```
1325
+
1326
+ ---
1327
+
1328
+ ## 13. Java 开发者看这里
1329
+
1330
+ > 📌 **Java 开发者专用**:如果你之前用 Java Spring Boot / Spring Cloud Alibaba / MyBatis,这一节告诉你如何迁移到 SpringBootAI。
1331
+
1332
+ ### 13.1 核心原则(5 条)
1333
+
1334
+ 1. 先迁移接口契约和测试,再迁移框架注解。
1335
+ 2. Python 使用类型标注、Pydantic 和显式依赖,比模拟 Java 反射更可靠。
1336
+ 3. **只有由容器创建的 Bean 才获得事务、缓存、重试等 AOP 行为**——手工 `new` 的对象不受容器管理。
1337
+ 4. Java 中的 XML SQL 可以大部分保留,但数据库函数、分页、类型名和连接配置需要按目标 Python 驱动验证。
1338
+ 5. 不把"有同名注解"理解为"与 Java 完全等价"。
1339
+
1340
+ ### 13.2 项目结构对照
1341
+
1342
+ | Java Spring Boot | SpringBootAI |
1343
+ |---|---|
1344
+ | `src/main/java/com/acme/Application.java` | `acme/Application.py` |
1345
+ | `src/main/resources/application.yml` | `acme/application.yml` 或 `acme/config/application.yml` |
1346
+ | `controller/` | `acme/controller/` |
1347
+ | `service/` | `acme/service/` |
1348
+ | `mapper/` 和 `resources/mapper/` | `acme/mappers/` 和同目录/配置指定的 XML |
1349
+ | `mvn spring-boot:run` | `python -m acme.Application` 或 `uvicorn asgi:app` |
1350
+
1351
+ ### 13.3 启动和依赖注入对照
1352
+
1353
+ **启动类**:Java `@SpringBootApplication(scanBasePackages = "com.acme")` + `SpringApplication.run()` → Python `@SpringBootApplication(scan_base_packages=["acme"])` + `run(Application)`
1354
+
1355
+ **Bean 注解映射**:
1356
+
1357
+ | Java 注解 | SpringBootAI | 说明 |
1358
+ |---|---|---|
1359
+ | `@Component` / `@Service` / `@Repository` | 同名 | 行为一致 |
1360
+ | `@RestController` | `@RestController` | 注册 FastAPI JSON 路由 |
1361
+ | `@Controller` | `@Controller` | 当前按 API 响应处理,不提供模板视图语义 |
1362
+ | `@Configuration` + `@Bean` | 同名 | 行为一致 |
1363
+ | `@Primary` / `@Qualifier` / `@Profile` / `@Lazy` | 同名 | 行为基本一致 |
1364
+
1365
+ **推荐构造器注入**:
1366
+
1367
+ ```python
1368
+ from spring.annotations import Autowired, Service
1369
+
1370
+ @Service
1371
+ class UserService:
1372
+ @Autowired
1373
+ def __init__(self, user_mapper: UserMapper):
1374
+ self.user_mapper = user_mapper
1375
+ ```
1376
+
1377
+ ### 13.4 Web 层 & AOP & MyBatis 迁移
1378
+
1379
+ | Java | SpringBootAI | 注意事项 |
1380
+ |---|---|---|
1381
+ | `@GetMapping` / `@PostMapping` 等 | 同名 | `@PathVariable` 等参数绑定写在默认值位置 |
1382
+ | `@Transactional` | `@Transactional` | 支持全部七种传播模式 |
1383
+ | `@Cacheable` | `@Cacheable` | 本地缓存默认 TTL 300 秒 |
1384
+ | `@Retryable` | `@Retryable` | `max_retries` 包含首次调用 |
1385
+ | `@Async` | `@Async` | 返回 `Future`/`Task`,不继承线程事务 |
1386
+ | `@Scheduled` | `@Scheduled` | 每个 worker 都会调度 |
1387
+ | MyBatis `@Mapper` | `@Mapper` + 注解/SQL | XML 功能矩阵基本对齐 |
1388
+
1389
+ ### 13.5 MyBatis 到 PyMyBatis(代码对照)
1390
+
1391
+ Java:
1392
+ ```java
1393
+ @Mapper
1394
+ public interface UserMapper {
1395
+ @Select("select id, name from users where id = #{id}")
1396
+ User findById(@Param("id") long id);
1397
+ }
1398
+ ```
1399
+
1400
+ Python:
1401
+ ```python
1402
+ from dataclasses import dataclass
1403
+ from typing import Optional
1404
+ from spring.orm import Mapper, Param, Select
1405
+
1406
+
1407
+ @dataclass
1408
+ class User:
1409
+ name: str
1410
+ id: Optional[int] = None
1411
+
1412
+
1413
+ @Mapper
1414
+ class UserMapper:
1415
+ @Select("SELECT id, name FROM users WHERE id = #{id}")
1416
+ def find_by_id(self, id: int) -> Optional[User]:
1417
+ pass
1418
+ ```
1419
+
1420
+ ### 13.6 Cloud & DDL 迁移
1421
+
1422
+ | Java | SpringBootAI | 说明 |
1423
+ |---|---|---|
1424
+ | `@EnableDiscoveryClient` + Nacos | `@EnableDiscoveryClient` + `discovery` 配置 | 需部署 Nacos 并做集成测试 |
1425
+ | `@FeignClient` | 同名 + `spring.cloud.feign` | 不兼容 Java interface proxy |
1426
+ | `@SentinelResource` | 同名 | 已内嵌引擎,无需 Dashboard |
1427
+ | JPA `hibernate.ddl-auto` | `@entity` + `ddl-auto` 配置 | 支持 create/update/validate/create-drop |
1428
+
1429
+ ### 13.7 验证顺序
1430
+
1431
+ 1. 创建虚拟环境,安装依赖。
1432
+ 2. 运行内置测试。
1433
+ 3. 用 SQLite 验证 Mapper SQL、事务、动态 SQL。
1434
+ 4. 用目标数据库版本执行相同测试。
1435
+ 5. 启动 ASGI 应用,检查 `/docs`、`/actuator/health`。
1436
+ 6. 接入外部中间件,演练断线、重复投递和回滚。
1437
+
1438
+ ---
1439
+
1440
+ ## 14. 生产部署
1441
+
1442
+ ### 14.1 环境要求
1443
+
1444
+ | 组件 | 版本要求 | 说明 |
1445
+ |------|---------|------|
1446
+ | Python | 3.10+ | 推荐 3.12 |
1447
+ | Redis | 6.0+ | 分布式锁、限流、缓存 |
1448
+ | MySQL | 5.7+ / 8.0+ | 业务数据存储 |
1449
+ | Nacos | 2.0+ | 服务注册发现(可选) |
1450
+
1451
+ ### 14.2 基础服务部署
1452
+
1453
+ **Redis**:
1454
+ ```bash
1455
+ sudo apt update && sudo apt install redis-server # Ubuntu/Debian
1456
+ redis-cli ping # 应返回 PONG
1457
+ ```
1458
+
1459
+ **MySQL 8+ 用户创建**:
1460
+ ```sql
1461
+ CREATE USER 'spring_python'@'%' IDENTIFIED BY 'your_secure_password';
1462
+ GRANT ALL PRIVILEGES ON your_database.* TO 'spring_python'@'%';
1463
+ FLUSH PRIVILEGES;
1464
+ ```
1465
+
1466
+ ### 14.3 生产配置与启动
1467
+
1468
+ ```yaml
1469
+ # application-prod.yml
1470
+ server:
1471
+ port: 8080
1472
+
1473
+ redis:
1474
+ enabled: true
1475
+ host: your-redis-host
1476
+ port: 6379
1477
+ password: your-redis-password
1478
+
1479
+ jwt:
1480
+ secret_key: your-strong-secret-key-change-in-production
1481
+ expires_in: 7200
1482
+
1483
+ database:
1484
+ enabled: true
1485
+ url: mysql+pymysql://user:password@localhost:3306/your_database?charset=utf8mb4
1486
+ ddl-auto:
1487
+ mode: validate
1488
+ entity_packages: app.entity
1489
+ ```
1490
+
1491
+ **生产启动**:
1492
+ ```bash
1493
+ export SPRING_PROFILES_ACTIVE=production
1494
+ export JWT_SECRET_KEY="使用密钥管理系统注入至少32字符的随机值"
1495
+ export STARTUP_FAIL_FAST=true
1496
+ uvicorn myapp.asgi:app --host 0.0.0.0 --port 8080 --workers 4
1497
+ ```
1498
+
1499
+ **Gunicorn(推荐)**:
1500
+ ```bash
1501
+ pip install gunicorn uvicorn
1502
+ gunicorn -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8080 myapp.asgi:app
1503
+ ```
1504
+
1505
+ ### 14.4 生产环境变量速查
1506
+
1507
+ | 环境变量 | 说明 | 默认值 |
1508
+ |---------|------|--------|
1509
+ | `SERVER_PORT` | 服务端口 | 8080 |
1510
+ | `JWT_SECRET_KEY` | JWT 密钥 | spring-python-secret-key-change-in-production |
1511
+ | `DB_URL` | 数据库连接 URL | sqlite:///./test.db |
1512
+ | `REDIS_HOST` / `REDIS_PORT` / `REDIS_PASSWORD` | Redis 连接 | localhost/6379/空 |
1513
+ | `NACOS_SERVER` | Nacos 地址 | localhost:8848 |
1514
+ | `SPRING_DISABLE_DOCKER_IP_DETECT` | 禁用容器 IP 检测 | 0 |
1515
+
1516
+ ### 14.5 验证部署 & 故障排查
1517
+
1518
+ ```bash
1519
+ curl http://localhost:8080/actuator/health
1520
+ # 返回 {"status":"UP","components":{"redis":"UP","database":"UP",...}}
1521
+ ```
1522
+
1523
+ **常见故障**:Nacos Docker 退出码 255 → 配置认证 Token;MySQL 认证失败 → 检查 `allowPublicKeyRetrieval=true`;Redis 连接 111 → `redis-cli ping` 检查。
1524
+
1525
+ ---
1526
+
1527
+ ## 15. 项目结构
1528
+
1529
+ `example`、`example1`、`example5`、`example_langchain` 是仓库级示例,不属于 `springbootAI` 安装包。实际项目应创建自己的应用包。
1530
+
1531
+ 推荐目录结构:
1532
+
1533
+ ```text
1534
+ myapp/
1535
+ |-- __init__.py
1536
+ |-- Application.py
1537
+ |-- application.yml
1538
+ |-- controller/
1539
+ | |-- __init__.py
1540
+ | `-- UserController.py
1541
+ |-- service/
1542
+ | |-- __init__.py
1543
+ | `-- UserService.py
1544
+ |-- mappers/
1545
+ | |-- __init__.py
1546
+ | `-- UserMapper.py
1547
+ |-- config/
1548
+ | `-- AppConfig.py
1549
+ `-- exception/
1550
+ `-- GlobalExceptionHandler.py
1551
+ ```
1552
+
1553
+ 每个被扫描目录都应包含 `__init__.py`,并从项目根目录启动。`scan_base_packages` 和 `@MapperScan` 接受的是可导入包名。
1554
+
1555
+ ---
1556
+
1557
+ ## 16. 测试
1558
+
1559
+ 从工作区根目录运行:
1560
+
1561
+ ```bash
1562
+ python -m pytest -q tests
1563
+ ```
1564
+
1565
+ 重点覆盖:
1566
+ - 独立和内嵌 ORM 源码一致。
1567
+ - 连接池共享、扩容、归还和未提交回滚。
1568
+ - 普通事务与嵌套 rollback-only。
1569
+ - Spring Mapper 在事务中复用 Session。
1570
+ - JWT access/refresh、生产密钥校验。
1571
+ - AI 模块 87 用例,LangChain 模块 75 用例,全量 707 用例 0 失败。
1572
+
1573
+ > 详细测试环境、套件覆盖和集成测试结果,见 [TEST_REPORT.md](doc/TEST_REPORT.md)。
1574
+
1575
+ ---
1576
+
1577
+ ## 17. 常见问题与排错
1578
+
1579
+ ### 17.1 启动时找不到组件
1580
+
1581
+ 1. 目录是否有 `__init__.py`。
1582
+ 2. `scan_base_packages` 是否是可导入包名,不是文件路径。
1583
+ 3. 启动工作目录是否包含项目根目录。
1584
+ 4. 组件类是否带 `@Service`、`@RestController` 等注解。
1585
+ 5. `@Profile` 是否与当前环境一致。
1586
+
1587
+ ### 17.2 Mapper 未注册
1588
+
1589
+ 检查 `database.enabled: true`、`database.orm: mybatis`、`@Mapper`、`@MapperScan` 路径。
1590
+
1591
+ ### 17.3 `@Transactional` 报缺少工厂
1592
+
1593
+ 说明 MyBatis 没有初始化。确认数据库已启用、ORM 模式正确、Service 是由容器创建而不是手工 `UserService()`。
1594
+
1595
+ ### 17.4 数据库连接耗尽
1596
+
1597
+ 检查 Session 是否通过上下文管理器关闭、请求是否有长事务、`实例 x worker x max_size` 是否超过数据库上限。
1598
+
1599
+ ### 17.5 生产启动拒绝 JWT
1600
+
1601
+ 设置 `SPRING_PROFILES_ACTIVE=production`、`STARTUP_FAIL_FAST=true`、`JWT_SECRET_KEY=<至少32字符随机密钥>`。
1602
+
1603
+ ### 17.6 Nacos / PATCH / 配置同步排错
1604
+
1605
+ - **Nacos Docker 退出码 255**:配置认证 Token 和相关环境变量。
1606
+ - **`PATCH /api/...` 返回 404**:确认方法用 `@PatchMapping`,框架已接入 `fastapi_app.patch()`。
1607
+ - **`ConfigLoader()` 读不同文件**:确认通过 `ApplicationContext` 启动,不是在不同工作目录直接实例化加载器。
1608
+
1609
+ ### 17.7 LangChain 模块排错
1610
+
1611
+ - **`@Autowired` 注入 `lcChainService` 失败**:确认调用了 `configure_ai()` + `configure_langchain()`。
1612
+ - **Partner 注册失败(跳过)**:按告警提示 `pip install langchain-<partner>`。
1613
+ - **RAG 报`嵌入模型未装配`**:设置 `AI_ALLOW_FAKE=true` 降级或提供真实 API Key。
1614
+
1615
+ ### 17.8 上线前清单
1616
+
1617
+ - 使用实际数据库版本运行 CRUD、事务、断连恢复测试。
1618
+ - 使用迁移工具管理结构,不让应用运行账号执行 DDL。
1619
+ - 锁定依赖,执行漏洞扫描。
1620
+ - 为 JWT、数据库、Redis 使用密钥管理系统。
1621
+ - 配置 TLS、CORS 白名单、请求限制。
1622
+ - 验证备份恢复、主从切换。
1623
+ - 对定时任务设计唯一执行或幂等。
1624
+ - 执行越权、SQL 注入、重放测试。
1625
+
1626
+ ---
1627
+
1628
+ ## 18. 性能与容量验证
1629
+
1630
+ 仓库提供 Docker 化的 SpringBootAI 基准服务和 k6 `smoke`、`baseline`、`stress`、`soak` 四档压测。快速验证:
1631
+
1632
+ ```powershell
1633
+ .\scripts\run-load-test.ps1 -Profile smoke
1634
+ ```
1635
+
1636
+ 完整参数和说明见 [`tests_performance/README.md`](tests_performance/README.md)。
1637
+
1638
+ ---
1639
+
1640
+ ## 附录 A:完整环境变量清单
1641
+
1642
+ ```bash
1643
+ # Server
1644
+ export SERVER_PORT=8080
1645
+ export SERVER_HOST=0.0.0.0
1646
+
1647
+ # Redis
1648
+ export REDIS_ENABLED=true
1649
+ export REDIS_HOST=localhost
1650
+ export REDIS_PORT=6379
1651
+ export REDIS_PASSWORD=
1652
+ export REDIS_DB=0
1653
+
1654
+ # JWT
1655
+ export JWT_SECRET_KEY=your-secret-key
1656
+ export JWT_ALGORITHM=HS256
1657
+ export JWT_EXPIRES_IN=3600
1658
+
1659
+ # Database
1660
+ export DB_ENABLED=false
1661
+ export DB_URL=sqlite:///./test.db
1662
+ export DB_USERNAME=
1663
+ export DB_PASSWORD=
1664
+ export DB_DRIVER=sqlite
1665
+ export DB_HOST=localhost
1666
+ export DB_PORT=3306
1667
+ export DB_DATABASE=./test.db
1668
+
1669
+ # ORM DDL Auto
1670
+ export DB_DDL_AUTO=none # none|validate|update|create|create-drop
1671
+ export DB_ENTITY_PACKAGES=
1672
+
1673
+ # Nacos
1674
+ export DISCOVERY_ENABLED=false
1675
+ export NACOS_SERVER=localhost:8848
1676
+ export NACOS_NAMESPACE=
1677
+ export NACOS_GROUP=DEFAULT_GROUP
1678
+ export NACOS_USERNAME=nacos
1679
+ export NACOS_PASSWORD=nacos
1680
+
1681
+ # Docker 辅助
1682
+ export SPRING_DISABLE_DOCKER_IP_DETECT=0
1683
+
1684
+ # Retry
1685
+ export RETRY_ENABLED=true
1686
+ export RETRY_MAX_RETRIES=3
1687
+ export RETRY_DELAY=1000
1688
+ export RETRY_MAX_DELAY=10000
1689
+ export RETRY_MULTIPLIER=2.0
1690
+
1691
+ # RabbitMQ
1692
+ export RABBITMQ_ENABLED=false
1693
+ export RABBITMQ_HOST=localhost
1694
+ export RABBITMQ_PORT=5672
1695
+ export RABBITMQ_USERNAME=guest
1696
+ export RABBITMQ_PASSWORD=guest
1697
+
1698
+ # Prometheus
1699
+ export PROMETHEUS_ENABLED=false
1700
+ export PROMETHEUS_PORT=8000
1701
+
1702
+ # Logging
1703
+ export LOG_LEVEL=INFO
1704
+ export LOG_DIR=logs
1705
+
1706
+ # AI 模块
1707
+ export AI_PROVIDER=openai
1708
+ export AI_ALLOW_FAKE=true
1709
+ export OPENAI_API_KEY=sk-xxx
1710
+ export OPENAI_CHAT_MODEL=gpt-4o-mini
1711
+ export OLLAMA_BASE_URL=http://localhost:11434
1712
+ export OLLAMA_CHAT_MODEL=llama3
1713
+
1714
+ # LangChain 模块
1715
+ export LC_ENABLED=true
1716
+ export LC_DEFAULT_LLM=auto
1717
+ export LC_AGENT_TYPE=react
1718
+ export LC_AGENT_MAX_ITER=10
1719
+ export LC_VECTOR_STORE=faiss
1720
+ export LC_RETRIEVER=similarity
1721
+ export LC_RETRIEVER_K=4
1722
+ export LC_MEMORY=buffer
1723
+ export LC_MEMORY_MAX=20
1724
+ ```
1725
+
1726
+ ## 附录 B:Docker Compose 示例
1727
+
1728
+ ```yaml
1729
+ version: '3.8'
1730
+
1731
+ services:
1732
+ redis:
1733
+ image: redis:7-alpine
1734
+ ports:
1735
+ - "6379:6379"
1736
+ volumes:
1737
+ - redis_data:/data
1738
+
1739
+ mysql:
1740
+ image: mysql:8.0
1741
+ ports:
1742
+ - "3306:3306"
1743
+ environment:
1744
+ MYSQL_ROOT_PASSWORD: root
1745
+ MYSQL_DATABASE: example_db
1746
+ volumes:
1747
+ - mysql_data:/var/lib/mysql
1748
+
1749
+ nacos:
1750
+ image: nacos/nacos-server:v2.3.0
1751
+ ports:
1752
+ - "8848:8848"
1753
+ - "9848:9848"
1754
+ environment:
1755
+ MODE: standalone
1756
+ NACOS_AUTH_ENABLE: "true"
1757
+ NACOS_AUTH_TOKEN: "c3ByaW5ncHktbmFjb3MtaGFuZHNoYWtlLXNlY3JldC0yMDI2LTA4LTA0LTAx"
1758
+ NACOS_AUTH_IDENTITY_KEY: "springpy"
1759
+ NACOS_AUTH_IDENTITY_VALUE: "springpy-local"
1760
+ JAVA_TOOL_OPTIONS: "-XX:-UseContainerSupport"
1761
+
1762
+ volumes:
1763
+ redis_data:
1764
+ mysql_data:
1765
+ ```