From 928058d55cc5f6bb6ed77dc7f6d8504d8c708d75 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=BB=84=E5=B0=8F=E6=96=9C?= <362294931@qq.com>
Date: Sat, 15 Apr 2023 11:48:55 +0800
Subject: [PATCH 01/32] add SpringBoot1
---
ReadMe.md | 32 +--
...15\344\270\226\344\273\212\347\224\237.md" | 246 ++++++++++++++++++
...37\347\220\206\350\257\246\350\247\243.md" | 0
...37\347\220\206\350\257\246\350\247\243.md" | 0
...4\232SpringAOP\346\246\202\350\277\260.md" | 0
...40\350\275\275\350\277\207\347\250\213.md" | 0
...13\345\212\241\346\246\202\350\277\260.md" | 0
...20\347\240\201\345\211\226\346\236\220.md" | 0
...\274\232Spring\346\246\202\350\277\260.md" | 0
...70\345\277\203\346\265\201\347\250\213.md" | 0
...07\347\250\213\345\210\206\346\236\220.md" | 0
...\243\347\241\256\347\232\204Controller.md" | 0
...67\346\261\202\350\275\254\345\217\221.md" | 0
...4\232SpringMVC\346\246\202\350\277\260.md" | 0
...43\346\236\220\345\216\237\347\220\206.md" | 0
...5\277\265\344\270\216DispatcherServlet.md" | 0
...6@ResponseBody\346\263\250\350\247\243.md" | 0
...45\350\257\206\346\270\205\345\215\225.md" | 0
18 files changed, 262 insertions(+), 16 deletions(-)
create mode 100644 "docs/spring/SpringBoot/SpringBoot\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md"
rename "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" => "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" (100%)
rename "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md" => "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md" (100%)
rename "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md" => "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md" (100%)
rename "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md" => "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md" (100%)
rename "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md" => "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md" (100%)
rename "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md" => "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md" (100%)
rename "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md" => "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md" (100%)
rename "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md" => "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md" (100%)
rename "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md" => "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md" (100%)
rename "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md" => "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md" (100%)
rename "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md" => "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md" (100%)
rename "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md" => "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md" (100%)
rename "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md" => "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md" (100%)
rename "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md" => "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md" (100%)
rename "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md" => "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md" (100%)
rename "docs/java-web/Spring/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md" => "docs/spring/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md" (100%)
diff --git a/ReadMe.md b/ReadMe.md
index dc53ae6..c83ee64 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -144,28 +144,28 @@
### Spring
-* [Springæº�ç �剖æž�:Spring概述](docs/java-web/Spring/Springæº�ç �剖æž�:Spring概述.md)
-* [Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程](docs/java-web/Spring/Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程.md)
-* [Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹ ](docs/java-web/Spring/Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹.md)
-* [Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�](docs/java-web/Spring/Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�.md)
-* [Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£ ](docs/java-web/Spring/Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£.md)
-* [Springæº�ç �剖æž�:SpringAOP概述](docs/java-web/Spring/Springæº�ç �剖æž�:SpringAOP概述.md)
-* [Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£ ](docs/java-web/Spring/Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£.md)
-* [Springæº�ç �剖æž�:Spring事务概述](docs/java-web/Spring/Springæº�ç �剖æž�:Spring事务概述.md)
-* [Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�](docs/java-web/Spring/Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�.md)
+* [Springæº�ç �剖æž�:Spring概述](docs/spring/Springæº�ç �剖æž�:Spring概述.md)
+* [Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程](docs/spring/Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程.md)
+* [Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹ ](docs/spring/Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹.md)
+* [Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�](docs/spring/Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�.md)
+* [Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£ ](docs/spring/Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£.md)
+* [Springæº�ç �剖æž�:SpringAOP概述](docs/spring/Springæº�ç �剖æž�:SpringAOP概述.md)
+* [Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£ ](docs/spring/Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£.md)
+* [Springæº�ç �剖æž�:Spring事务概述](docs/spring/Springæº�ç �剖æž�:Spring事务概述.md)
+* [Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�](docs/spring/Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�.md)
### SpringMVC
-* [SpringMVCæº�ç �分æž�:SpringMVC概述](docs/java-web/SpringMVC/SpringMVCæº�ç �分æž�:SpringMVC概述.md)
-* [SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet](docs/java-web/SpringMVC/SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet.md)
-* [SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘ ](docs/java-web/SpringMVC/SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘.md)
-* [SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller ](docs/java-web/SpringMVC/SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller.md)
-* [SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解](docs/java-web/SpringMVC/SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解.md)
-* [SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�† ](docs/java-web/SpringMVC/SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�†.md)
+* [SpringMVCæº�ç �分æž�:SpringMVC概述](docs/spring/springMVC/SpringMVCæº�ç �分æž�:SpringMVC概述.md)
+* [SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet](docs/spring/springMVC/SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet.md)
+* [SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘ ](docs/spring/springMVC/SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘.md)
+* [SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller ](docs/spring/springMVC/SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller.md)
+* [SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解](docs/spring/springMVC/SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解.md)
+* [SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�† ](docs/spring/springMVC/SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�†.md)
### SpringBoot
-todo
+* [SpringBoot系列:SpringBoot的�世今生](docs/spring/SpringBoot/SpringBoot的�世今生.md)
### SpringCloud
diff --git "a/docs/spring/SpringBoot/SpringBoot\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md" "b/docs/spring/SpringBoot/SpringBoot\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md"
new file mode 100644
index 0000000..c524bd5
--- /dev/null
+++ "b/docs/spring/SpringBoot/SpringBoot\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md"
@@ -0,0 +1,246 @@
+# SpringBootµÄǰÊÀ½ñÉú
+
+Spring Boot 2.0 µÄÍÆ³öÓÖ¼¤ÆðÁËÒ»Õóѧϰ Spring Boot ÈÈ£¬¾Íµ¥´ÓÎÒ¸öÈ˵IJ©¿ÍµÄ·ÃÎÊÁ¿´ó·ùÔö¼Ó¾Í¿ÉÒÔ¸ÐÊܵ½´ó¼Ò¶Ôѧϰ Spring Boot µÄÈÈÇ飬ÄÇôÔÚÕâô¶àÈËÈÈÖÔÓÚѧϰ Spring Boot ֮ʱ£¬ÎÒ×Ô¼ºÒ²ÔÚ˼¿¼£º Spring Boot µ®ÉúµÄ±³¾°ÊÇʲô£¿Spring ÆóÒµÓÖÊÇ»ùÓÚʲôÑùµÄ¿¼ÂÇ´´½¨ Spring Boot? ´«Í³ÆóҵʹÓà Spring Boot »á¸øÎÒÃÇ´øÀ´Ê²Ã´Ñù±ä¸ï?
+
+´ø×ÅÕâЩÎÊÌ⣬ÎÒÃÇÒ»ÆðÀ´Á˽âÏ Spring Boot µ½µ×ÊÇʲô?
+
+## Spring ÀúÊ·
+
+˵Æð Spring Boot ÎÒÃDz»µÃ²»ÏÈÁ˽âһϠSpring Õâ¸öÆóÒµ£¬²»½öÒòΪ Spring Boot À´Ô´ÓÚ Spirng ´ó¼Ò×壬¶øÇÒ Spring Boot µÄµ®ÉúºÍ Sping ¿ò¼ÜµÄ·¢Õ¹Ï¢Ï¢Ïà¹Ø¡£
+
+ʱ¼ä»Øµ½2002Ä꣬µ±Ê±ÕýÊÇ Java EE ºÍ EJB ´óÐÐÆäµÀµÄʱºò£¬ºÜ¶àÖªÃû¹«Ë¾¶¼ÊDzÉÓô˼¼Êõ·½°¸½øÐÐÏîÄ¿¿ª·¢¡£ÕâʱºòÓÐÒ»¸öÃÀ¹úµÄС»ï×ÓÈÏΪ EJB Ì«¹ýÓ·Ö×£¬²¢²»ÊÇËùÓеÄÏîÄ¿¶¼ÐèҪʹÓà EJB ÕâÖÖ´óÐÍ¿ò¼Ü£¬Ó¦¸Ã»áÓÐÒ»ÖÖ¸üºÃµÄ·½°¸À´½â¾öÕâ¸öÎÊÌâ¡£
+
+ΪÁËÖ¤Ã÷ËûµÄÏë·¨ÊÇÕýÈ·µÄ£¬ÓÚ2002Äê10ÔÂÉõÖÁдÁËÒ»±¾Êé¡¶ Expert One-on-One J2EE ¡·£¬½éÉÜÁ˵±Ê± Java ÆóÒµÓ¦ÓóÌÐò¿ª·¢µÄÇé¿ö£¬²¢Ö¸³öÁË Java EE ºÍ EJB ×é¼þ¿ò¼ÜÖдæÔÚµÄһЩÖ÷ҪȱÏÝ¡£ÔÚÕâ±¾ÊéÖУ¬ËûÌá³öÁËÒ»¸ö»ùÓÚÆÕͨ Java ÀàºÍÒÀÀµ×¢ÈëµÄ¸ü¼òµ¥µÄ½â¾ö·½°¸¡£
+
+ÔÚÊéÖУ¬ËûչʾÁËÈçºÎÔÚ²»Ê¹Óà EJB µÄÇé¿öϹ¹½¨¸ßÖÊÁ¿£¬¿ÉÀ©Õ¹µÄÔÚÏß×ùλԤÁôϵͳ¡£ÎªÁ˹¹½¨Ó¦ÓóÌÐò£¬Ëû±àдÁ˳¬¹ý 30,000 ÐеĻù´¡½á¹¹´úÂ룬ÏîÄ¿Öеĸù°üÃüÃûΪ com.interface21£¬ËùÒÔÈËÃÇ×î³õ³ÆÕâÌ׿ªÔ´¿ò¼ÜΪ interface21£¬Ò²¾ÍÊÇ Spring µÄǰÉí¡£
+
+ËûÊÇËÄØ£¬Ëû¾ÍÊÇ´óÃû¶¦¶¦µÄ Rod Johnson £¨ÏÂͼ£©, Rod Johnson ÔÚϤÄá´óѧ²»½ö»ñµÃÁ˼ÆËã»úѧλ£¬Í¬Ê±»¹»ñµÃÁËÒôÀÖѧ룬¸üÁîÈ˳ԾªµÄÊÇÔڻص½Èí¼þ¿ª·¢ÁìÓò֮ǰ£¬Ëû»¹»ñµÃÁËÒôÀÖѧµÄ²©Ê¿Ñ§Î»¡£ÏÖÔÚ Rod Johnson ÒѾÀ뿪ÁË Spring £¬³ÉΪÁËÒ»¸öÌìʹͶ×ÊÈË£¬Í¬Ê±Ò²ÊǶà¸ö¹«Ë¾µÄ¶Ê£¬ÔçÒÑ×ßÉÏÈËÉúáÛ·å¡£
+
+
+
+ÔÚÕâ±¾Êé·¢²¼ºó£¬Ò»¶ÔÒ»µÄ J2EE Éè¼ÆºÍ¿ª·¢Ò»ÅÚ¶øºì¡£Õâ±¾ÊéÃâ·ÑÌṩµÄ´ó²¿·Ö»ù´¡¼Ü¹¹´úÂë¶¼ÊǸ߶ȿÉÖØÓõġ£ 2003 Äê Rod Johnson ºÍͬ°éÔÚ´Ë¿ò¼ÜµÄ»ù´¡ÉÏ¿ª·¢ÁËÒ»¸öȫеĿò¼ÜÃüÃûΪ Spring ,¾Ý Rod Johnson ½éÉÜ Spring ÊÇ´«Í³ J2EE еĿªÊ¼¡£Ëæºó Spring ·¢Õ¹½øÈë¿ì³µµÀ¡£
+
+* 2004 Äê 03 Ô£¬1.0 °æ·¢²¼¡£
+* 2006 Äê 10 Ô£¬2.0 °æ·¢²¼¡£
+* 2007 Äê 11 Ô¸üÃûΪ SpringSource£¬Í¬Ê±·¢²¼ÁË Spring 2.5¡£
+* 2009 Äê 12 Ô£¬Spring 3.0 ·¢²¼¡£
+* 2013 Äê 12 Ô£¬Pivotal Ðû²¼·¢²¼ Spring ¿ò¼Ü 4.0¡£
+* 2017 Äê 09 Ô£¬Spring 5.0 ·¢²¼¡£
+
+## Spring Boot µÄµ®Éú
+
+Ëæ×ÅʹÓà Spring ½øÐпª·¢µÄ¸öÈËºÍÆóÒµÔ½À´Ô½¶à£¬Spring Ò²ÂýÂý´ÓÒ»¸öµ¥Ò»¼ò½àµÄС¿ò¼Ü±ä³ÉÒ»¸ö´ó¶øÈ«µÄ¿ªÔ´Èí¼þ£¬Spring µÄ±ß½ç²»¶ÏµÄ½øÐÐÀ©³ä£¬µ½Á˺óÀ´ Spring ¼¸ºõ¿ÉÒÔ×öÈκÎÊÂÇéÁË£¬ÊÐÃæÉÏÖ÷Á÷µÄ¿ªÔ´Èí¼þ¡¢Öмä¼þ¶¼ÓÐ Spring ¶ÔÓ¦×é¼þÖ§³Ö£¬ÈËÃÇÔÚÏíÓà Spring µÄÕâÖÖ±ãÀûÖ®ºó£¬Ò²Óöµ½ÁËһЩÎÊÌâ¡£
+
+Spring ÿ¼¯³ÉÒ»¸ö¿ªÔ´Èí¼þ£¬¾ÍÐèÒªÔö¼ÓһЩ»ù´¡ÅäÖã¬ÂýÂýµÄËæ×ÅÈËÃÇ¿ª·¢µÄÏîĿԽÀ´Ô½ÅÓ´ó£¬ÍùÍùÐèÒª¼¯³ÉºÜ¶à¿ªÔ´Èí¼þ£¬Òò´ËºóÆÚʹÓà Spirng ¿ª·¢´óÐÍÏîÄ¿ÐèÒªÒýÈëºÜ¶àÅäÖÃÎļþ£¬Ì«¶àµÄÅäÖ÷dz£ÄÑÒÔÀí½â£¬²¢ÈÝÒ×ÅäÖóö´í£¬µ½Á˺óÀ´ÈËÃÇÉõÖÁ³Æ Spring ΪÅäÖõØÓü¡£
+
+Spring ËÆºõÒ²Òâʶµ½ÁËÕâЩÎÊÌ⣬¼±ÐèÓÐÕâôһÌ×Èí¼þ¿ÉÒÔ½â¾öÕâЩÎÊÌ⣬Õâ¸öʱºò΢·þÎñµÄ¸ÅÄîÒ²ÂýÂýÐËÆð£¬¿ìËÙ¿ª·¢Î¢Ð¡¶ÀÁ¢µÄÓ¦ÓñäµÃ¸üΪ¼±ÆÈ£¬Spring ¸ÕºÃ´¦ÔÚÕâôһ¸ö½»²æµãÉÏ£¬ÓÚ 2013 Äê³õ¿ªÊ¼µÄ Spring Boot ÏîÄ¿µÄÑз¢£¬2014Äê4Ô£¬Spring Boot 1.0.0 ·¢²¼¡£
+
+Spring Boot µ®ÉúÖ®³õ£¬¾ÍÊܵ½¿ªÔ´ÉçÇøµÄ³ÖÐø¹Ø×¢£¬Â½ÐøÓÐһЩ¸öÈËºÍÆóÒµ³¢ÊÔ×ÅʹÓÃÁË Spring Boot£¬²¢Ñ¸ËÙϲ»¶ÉÏÁËÕâ¿î¿ªÔ´Èí¼þ¡£Ö±µ½2016Ä꣬ÔÚ¹úÄÚ Spring Boot ²Å±»ÕýÕæÊ¹ÓÃÁËÆðÀ´£¬ÆÚ¼äºÜ¶àÑо¿ Spring Boot µÄ¿ª·¢ÕßÔÚÍøÉÏдÁË´óÁ¿¹ØÓÚ Spring Boot µÄÎÄÕ£¬Í¬Ê±ÓÐһЩ¹«Ë¾ÔÚÆóÒµÄÚ²¿½øÐÐÁËС¹æÄ£µÄʹÓ㬲¢½«Ê¹ÓþÑé·ÖÏíÁ˳öÀ´¡£´Ó2016Äêµ½2018Ä꣬ʹÓà Spring Boot µÄÆóÒµºÍ¸öÈË¿ª·¢ÕßÔ½À´Ô½¶à£¬ÎÒÃÇ´Ó Spring Boot ¹Ø¼ü×ֵİٶÈÖ¸Êý¾Í¿ÉÒÔ¿´³ö¡£
+
+
+
+ÉÏͼΪ2014Äêµ½2018Äê Spring Boot µÄ°Ù¶ÈÖ¸Êý£¬¿ÉÒÔ¿´³ö Spring Boot 2.0 µÄÍÆ³öÒý·¢ÁËËÑË÷¸ß·å¡£
+
+µ±È» Spring Boot ²»ÊÇΪÁËÈ¡´ú Spring ,Spring Boot »ùÓÚ Spring ¿ª·¢£¬ÊÇΪÁËÈÃÈËÃǸüÈÝÒ×µÄʹÓà Spring¡£¿´µ½ Spring Boot µÄÊг¡·´Ó¦£¬Spring ¹Ù·½Ò²·Ç³£ÖØÊÓ Spring Boot µÄºóÐø·¢Õ¹£¬ÒѾ½« Spring Boot ×÷Ϊ¹«Ë¾×î¶¥¼¶µÄÏîÄ¿À´Íƹ㣬·Åµ½Á˹ÙÍøÉϵÚÒ»µÄλÖã¬Òò´ËºóÐø Spring Boot µÄ³ÖÐø·¢Õ¹Ò²±»¿´ºÃ¡£
+
+# »ù±¾½éÉÜ
+
+
+
+ÕâÊÇspring¹ÙÍø¶ÔÓÚspringbootµÄ»ù±¾½éÉÜ
+
+Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".
+
+We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need minimal Spring configuration.
+
+¼ò¶øÑÔÖ®£¬¾ÍÊÇÔÚ¸æËßÎÒÃÇ£¬springboot¿ÉÒÔ°ïÖúÎÒÃÇ¿ìËÙ¹¹½¨¶ÀÁ¢²¿ÊðµÄÉú²ú¼¶Ó¦ÓÃ
+
+£¬Ö»ÐèÒªÒ»¸ö´øÓÐ@SpringBootApplication ×¢½âµÄÓ¦ÓÃÈë¿Ú£¬¼´¿É±»Ê¶±ðΪһ¸öspringbootÓ¦ÓÃ
+
+²¢ÇÒ£¬springboot¼Ì³ÐÁË´óÁ¿µÄµÚÈý·½¿â£¬ÎÒÃǽöÐèºÜÉÙÉõÖÁÊÇÍêÈ«²»ÐèÒª¶îÍâµÄÅäÖ㬾ͿÉÒÔ½øÐÐÓ¦Óô£¬ÒòΪspringboot¿ò¼Ü±¾ÉíÒѾ°ïÎÒÃÇÉèÖúÃÁË´óÁ¿µÄĬÈÏÅäÖá£
+
+# »ù±¾ÌØÐÔ
+
+Features
+
+* Create stand-alone Spring applications
+* Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
+* Provide opinionated 'starter' dependencies to simplify your build configuration
+* Automatically configure Spring and 3rd party libraries whenever possible
+* Provide production-ready features such as metrics, health checks, and externalized configuration
+* Absolutely no code generation and no requirement for XML configuration
+
+¹Ù·½¶ÔÓÚspringboot¼¸´óÌØÐÔµÄÃèÊöÈçÉÏ
+
+1¡¢´´½¨Ò»¸ö¶ÀÁ¢²¿ÊðµÄspringÓ¦Óã¬Ëü³£ÓÃÓÚ¶¨Òå΢·þÎñ£¬»òÕßÊÇÒ»¸öwebÓ¦ÓÃ
+
+2¡¢ÄÚÖõÄtomcatÈÝÆ÷£¬ÎÒÃÇÔÙÒ²ÐèÒª°ÑspringÓ¦Óôò°ü³Éwar°ü£¬¶øÊÇÖ»ÐèÒª½«Æä´ò°ü³Éjar°ü½øÐв¿Êð¼´¿É¡£
+
+3¡¢ÌṩstarterÒÀÀµ£¬¸ü¼Ó¼ò»¯ÁËspringbootÉú̬ÖеÄÒÀÀµºÍÅäÖã¬ÀýÈçµ±ÎÒÃÇʹÓÃspringwebÏà¹ØÒÀÀµÊ±£¬ÎÒÃDz»ÐèÒªµ¥¶ÀµØÌí¼Ó¶à¸öspringmvcÏà¹ØµÄmavenÒÀÀµ£¬¶øÊÇÖ±½ÓÒýÓÃspring-boot-starter-web¾Í¿ÉÒÔÁË£¬Õâ¸östarter»á×Ô¶¯ÒýÈëÏà¹ØµÄÒÀÀµ£¬²¢ÇÒ°ïÄã¹ÜÀí°æ±¾ºÅ£¬»á´óÁ¿µØ¼ò»¯ºÍÓÅ»¯ÄãµÄmavenÅäÖÃ
+
+4¡¢×Ô¶¯×°ÅäspringºÍµÚÈý·½¿â£¬ÕâÀïÖ÷ÒªÊÇָͨ¹ý×¢½âºÍÅäÖÃÎļþ½øÐÐ×Ô¶¯×°Å䣬²¢ÇÒ»¹ÓÐһЩÊÇ»ùÓÚÔ¼¶¨µÄ×Ô¶¯×°Åä»úÖÆ£¬Õâ¿ÉÒÔ°ïÎÒÃǽÚÊ¡´óÁ¿µÄ¶îÍâÅäÖã¬Ò²¿ÉÒÔ×Ô¶¯×°ÅäÍⲿjar°üÌṩµÄspringÏà¹ØbeanºÍÅäÖá£
+
+5¡¢ÌṩÁËÉú²ú»·¾³Ïà¹ØµÄÌØÐÔ£¬±ÈÈç¼à¿Ø¡¢Ö¸±ê´òµã¡¢½¡¿µ¼ì²éµÈ¹¦ÄÜ£¬springbootÌṩÁËÇ¿´óµÄÉú̬×é¼þ£¬ÕâÀï²»½ö°üÀ¨springboot×Ô¼ºµÄ×é¼þ£¬Ò²°üÀ¨Ò»Ð©ÍⲿµÄÉú̬×é¼þ¡£
+
+6¡¢²»²»´æÔÚ´úÂëÉú³É£¬Ò²²»ÐèÒªxmlÅäÖÃÎļþ£¬ÕâÖ¤Ã÷ÁËspringbootµÄ¿ò¼ÜÍêÕû¶È£¬ÒÔ¼°¶ÔÓÚÅäÖüò»¯µÄ¼«ÖÂ×·Çó£¬ÎÒÃǽöÐèÒªapplication.properties½øÐлù±¾ÅäÖòÎÊý¹ÜÀí£¬ÄãÒ²²»»áÔÚspringboot±àÒëÆ÷ÕÒµ½¶¯Ì¬Éú³ÉµÄ¶àÓàclassÎļþ¡£
+
+# ºÍSpringµÄ¹ØÏµ
+
+
+
+## SpringFramework½â¾öÁËʲôÎÊÌ⣿
+
+SpringÊÇJavaÆóÒµ°æ£¨Java Enterprise Edition£¬JEE£¬Ò²³ÆJ2EE£©µÄÇáÁ¿¼¶´úÌæÆ·¡£ÎÞÐ迪·¢ÖØÁ¿¼¶µÄEnterpriseJavaBean£¨EJB£©£¬SpringΪÆóÒµ¼¶Java¿ª·¢ÌṩÁËÒ»ÖÖÏà¶Ô¼òµ¥µÄ·½·¨£¬Í¨¹ýÒÀÀµ×¢ÈëºÍÃæÏòÇÐÃæ±à³Ì£¬Óüòµ¥µÄJava¶ÔÏó£¨Plain Old Java Object£¬POJO£©ÊµÏÖÁËEJBµÄ¹¦ÄÜ¡£
+
+1.ʹÓÃSpringµÄIOCÈÝÆ÷,½«¶ÔÏóÖ®¼äµÄÒÀÀµ¹ØÏµ½»¸øSpring,½µµÍ×é¼þÖ®¼äµÄñîºÏÐÔ,ÈÃÎÒÃǸüרעÓÚÓ¦ÓÃÂß¼
+
+2.¿ÉÒÔÌṩÖÚ¶à·þÎñ,ÊÂÎñ¹ÜÀí,WSµÈ¡£
+
+3.ºÜºÃµØÖ§³ÖAOP,·½±ãÃæÏòÇÐÃæ±à³Ì¡£
+
+4.¶ÔÖ÷Á÷µÄ¿ò¼ÜÌṩÁ˺ܺõÉÖ§³Ö,ÈçHibernate,Struts2,JPAµÈ
+
+5.Spring DI»úÖÆ½µµÍÁËÒµÎñ¶ÔÏóÌæ»»µÄ¸´ÔÓÐÔ¡£
+
+6.SpringÊôÓÚµÍÇÖÈë,´úÂëÎÛȾ¼«µÍ¡£
+
+7.SpringµÄ¸ß¶È¿É¿ª·ÅÐÔ,²¢²»Ç¿ÖÆÒÀÀµÓÚSpring,¿ª·¢Õß¿ÉÒÔ×ÔÓÉÑ¡ÔñSpring²¿·Ö»òÈ«²¿
+
+## SpringFrameworkûÓнâ¾öÁËʲôÎÊÌ⣿
+
+ËäÈ»SpringµÄ×é¼þ´úÂëÊÇÇáÁ¿¼¶µÄ£¬µ«ËüµÄÅäÖÃÈ´ÊÇÖØÁ¿¼¶µÄ¡£Ò»¿ªÊ¼£¬SpringÓÃXMLÅäÖ㬶øÇÒÊǺܶàXMLÅäÖá£Spring 2.5ÒýÈëÁË»ùÓÚ×¢½âµÄ×é¼þɨÃ裬ÕâÏû³ýÁË´óÁ¿Õë¶ÔÓ¦ÓóÌÐò×ÔÉí×é¼þµÄÏÔʽXMLÅäÖá£Spring 3.0ÒýÈëÁË»ùÓÚJavaµÄÅäÖã¬ÕâÊÇÒ»ÖÖÀàÐͰ²È«µÄ¿ÉÖØ¹¹ÅäÖ÷½Ê½£¬¿ÉÒÔ´úÌæXML¡£
+
+ËùÓÐÕâЩÅäÖö¼´ú±íÁË¿ª·¢Ê±µÄËðºÄ¡£ÒòΪÔÚ˼¿¼SpringÌØÐÔÅäÖúͽâ¾öÒµÎñÎÊÌâÖ®¼äÐèÒª½øÐÐ˼άÇл»£¬ËùÒÔ±àдÅäÖü·Õ¼Á˱àдӦÓóÌÐòÂß¼µÄʱ¼ä¡£ºÍËùÓпò¼ÜÒ»Ñù£¬SpringʵÓ㬵«Óë´ËͬʱËüÒªÇóµÄ»Ø±¨Ò²²»ÉÙ¡£
+
+³ý´ËÖ®Í⣬ÏîÄ¿µÄÒÀÀµ¹ÜÀíÒ²ÊÇÒ»¼þºÄʱºÄÁ¦µÄÊÂÇé¡£ÔÚ»·¾³´î½¨Ê±£¬ÐèÒª·ÖÎöÒªµ¼ÈëÄÄЩ¿âµÄ×ø±ê£¬¶øÇÒ»¹ÐèÒª·ÖÎöµ¼ÈëÓëÖ®ÓÐÒÀÀµ¹ØÏµµÄÆäËû¿âµÄ×ø±ê£¬Ò»µ©Ñ¡´íÁËÒÀÀµµÄ°æ±¾£¬ËæÖ®¶øÀ´µÄ²»¼æÈÝÎÊÌâ¾Í»áÑÏÖØ×è°ÏîÄ¿µÄ¿ª·¢½ø¶È¡£
+
+## SpringBoot½â¾öÉÏÊöSpringµÄȱµã
+
+SpringBoot¶ÔÉÏÊöSpringµÄȱµã½øÐеĸÄÉÆºÍÓÅ»¯£¬»ùÓÚÔ¼¶¨ÓÅÓÚÅäÖõÄ˼Ï룬¿ÉÒÔÈÿª·¢ÈËÔ±²»±ØÔÚÅäÖÃÓëÂß¼ÒµÎñÖ®¼ä½øÐÐ˼άµÄÇл»£¬È«ÉíÐĵÄͶÈëµ½Âß¼ÒµÎñµÄ´úÂë±àдÖУ¬´Ó¶ø´ó´óÌá¸ßÁË¿ª·¢µÄЧÂÊ£¬Ò»¶¨³Ì¶ÈÉÏËõ¶ÌÁËÏîÄ¿ÖÜÆÚ¡£
+
+ÔÚʹÓÃSpring¿ò¼Ü½øÐпª·¢µÄ¹ý³ÌÖУ¬ÐèÒªÅäÖúܶàSpring¿ò¼Ü°üµÄÒÀÀµ£¬Èçspring-core¡¢spring-bean¡¢spring-contextµÈ£¬¶øÕâЩÅäÖÃͨ³£¶¼ÊÇÖØ¸´Ìí¼ÓµÄ£¬¶øÇÒÐèÒª×öºÜ¶à¿ò¼ÜʹÓü°»·¾³²ÎÊýµÄÖØ¸´ÅäÖã¬È翪Æô×¢½â¡¢ÅäÖÃÈÕÖ¾µÈ¡£Spring BootÖÂÁ¦ÓÚÈõ»¯ÕâЩ²»±ØÒªµÄ²Ù×÷£¬ÌṩĬÈÏÅäÖ㬵±È»ÕâЩĬÈÏÅäÖÃÊÇ¿ÉÒÔ°´ÐèÐ޸ĵģ¬¿ìËٴ¡¢¿ª·¢ºÍÔËÐÐSpringÓ¦ÓÃ
+
+# ºÍSpringMVCµÄ¹ØÏµ
+
+
+
+Spring Boot£ºSpring Bootʹ¿ìËÙÒýµ¼ºÍ¿ªÊ¼¿ª·¢»ùÓÚSpringµÄÓ¦ÓóÌÐò±äµÃÈÝÒס£ Ëü±ÜÃâÁ˺ܶàÑù°å´úÂë¡£ ËüÔÚÄ»ºóÒþ²ØÁ˺ܶิÔÓÐÔ£¬Òò´Ë¿ª·¢ÈËÔ±¿ÉÒÔ¿ìËÙÉÏÊÖ²¢ÇáËÉ¿ª·¢»ùÓÚSpringµÄÓ¦ÓóÌÐò¡£
+
+Spring MVC£ºSpring MVCÊÇÓÃÓÚ¹¹½¨WebÓ¦ÓóÌÐòµÄWeb MVC¿ò¼Ü¡£ Ëü°üº¬Ðí¶àÓÃÓÚ¸÷ÖÖ¹¦ÄܵÄÅäÖÃÎļþ¡£ ÕâÊÇÒ»¸öÃæÏòHTTPµÄWebÓ¦ÓóÌÐò¿ª·¢¿ò¼Ü¡£
+
+
+
+Spring BootºÍSpring MVC³öÓÚ²»Í¬µÄÄ¿µÄ¶ø´æÔÚ¡£ ÏÂÃæÌÖÂÛÁËSpring BootºÍSpring MVCÖ®¼äµÄÖ÷񻂿±ð£º
+
+
+
+| Spring Boot | Spring MVC |
+| --- | --- |
+| Spring BootÓÃÓÚʹÓúÏÀíµÄĬÈÏÖµ´ò°ü»ùÓÚSpringµÄÓ¦ÓóÌÐò¡£ | Spring MVCÊÇSpring¿ò¼ÜÏ»ùÓÚÄ£ÐÍÊÓͼ¿ØÖÆÆ÷µÄWeb¿ò¼Ü¡£ |
+| ËüÌṩÁËĬÈÏÅäÖÃÀ´¹¹½¨SpringÖ§³ÖµÄ¿ò¼Ü¡£ | ËüÌṩÁËÓÃÓÚ¹¹½¨WebÓ¦ÓóÌÐòµÄ¼´ÓÃÐ͹¦ÄÜ¡£ |
+| ÎÞÐèÊÖ¶¯¹¹½¨ÅäÖᣠ| ËüÐèÒªÊÖ¶¯½øÐй¹½¨ÅäÖᣠ|
+| ²»ÐèÒª²¿ÊðÃèÊö·û¡£ | ²¿ÊðÃèÊö·ûÊDZØÐèµÄ¡£ |
+| Ëü±ÜÃâÁËÑù°å´úÂ룬²¢½«ÒÀÀµÏî°ü×°ÔÚÒ»¸öµ¥ÔªÖС£ | Ëü·Ö±ðÖ¸¶¨Ã¿¸öÒÀÀµÏî¡£ |
+| Ëü¼õÉÙÁË¿ª·¢Ê±¼ä²¢Ìá¸ßÁËÉú²úÂÊ¡£ | ʵÏÖÏàͬĿµÄÐèÒª¸ü¶àʱ¼ä¡£ |
+
+# ºÍ΢·þÎñ¡¢SpringCloudµÄ¹ØÏµ
+
+Spring BootÊÇSpring¼Ò×åµÄ³ÉÔ±£¬ËüÊÇÒ»¸öȫеĿò¼Ü£¬ËüµÄÉè¼ÆÄ¿µÄÊǾ¡¿ÉÄܼòµ¥ºÍ¿ìËٵĿª·¢¡¢ÔËÐÐSpringÓ¦ÓóÌÐò£¬¼ò»¯ÅäÖá£ËüΪ¿ª·¢Õß¿ì½ÝµÄʹÓÃSpring¼°Ïà¹Ø¿ª·¢¿ò¼ÜÌṩÁ˱ãÀû£¬µ«ÊÇËü²¢²»ÊÇ΢·þÎñµÄ¿ò¼Ü£¬ËüÖ»ÊÇΪ΢·þÎñ¿ò¼ÜµÄʹÓÃÒ²ÌṩÁ˺ܺõĽÅÊּܡ£
+
+
+
+
+ÉÏÃæÁ½ÕÅͼ±íÃ÷ÁËÁ½ÕߵĻù±¾Çø±ð£¬springbootÓÃÓÚ¹¹½¨µ¥¸ö·þÎñÓ¦Óã¬Ò²¾ÍÊÇÎÒÃdz£ËµµÄ΢·þÎñ
+
+¶øspringcloudÓÃÓÚ·þÎñÖÎÀí£¬Ò²¾ÍÊÇ´®Áª¡¢¹ÜÀíºÍе÷¶à¸ö΢·þÎñ£¨springbootÓ¦ÓóÌÐò£©
+
+springcloudÖаüº¬ÁËÖÚ¶à·þÎñÖÎÀíÏà¹ØµÄ×é¼þ£º·þÎñAPIÍø¹ØSpringcloud Gateway£¬ÅäÖÃÖÐÐÄ×é¼þConfig Serever£¬¶Ï·Æ÷Circuit Breaker¡¢·þÎñ×¢²áÖÐÐÄService Registty£¬¼à¿Ø×é¼þSleuthµÈ
+
+# ʹÓÃSpringbootµÄ8¸öÔÒò
+
+## ¸ü¿ìµÄ¿ª·¢
+
+Spring Boot ÔÚ Spring Éú̬ϵͳÉÏ×ö³öÁ˺ܶà¾ö¶¨ºÍ¹ÌÖ´¼º¼ûµÄĬÈÏÉèÖᣠÕâÖÖÐÔÖÊÓÐÖúÓÚ¿ª·¢ÈËÔ±¿ìËÙÉèÖò¢Í¶È뿪·¢¡£
+
+ÀýÈ磬Spring MVC ¿ÉÒÔͨ¹ý´óÁ¿ XML bean ¶¨ÒåºÍ×Ô¶¨Òå servlet ÀàʵÏÖ¡£ µ«ÊÇʹÓà Spring Boot£¬Ëü¾ÍÏñÌí¼ÓÆô¶¯Æ÷ÒÀÀµÏîÒ»Ñù¼òµ¥¡£ ¾ø¶Ô²»ÐèÒª´úÂëÉú³É XML ÅäÖá£
+
+## Ò»ÇнÔÓÐÏÈ»ú
+
+Spring Boot Starters Êǰüº¬¿âºÍËüÃǵÄһЩ×Ô¶¯ÅäÖÃµÄ Maven ÃèÊö·û¡£ ¶øÇÒ£¬ÕâЩÆô¶¯Æ÷ÓÐÖúÓÚΪ Spring Boot Ó¦ÓóÌÐòÌṩ¹¦ÄÜ¡£ ÏëÒª½¨Á¢Êý¾Ý¿âÁ¬½Ó£¿ ÓÐÒ»¸öÆô¶¯Æ÷ÒÀÀµÏî¡£ ÏëÓëÏûÏ¢¶ÓÁÐͨ»°»ò·¢Ë͵ç×ÓÓʼþ£¿ Spring Boot º¸ÇÁËÕâÒ»ÇС£
+
+¶ÔÓÚ¼¸ºõËùÓÐµÄ Spring Ä£¿é£¬¶¼ÓÐÒ»¸öÆô¶¯Æ÷ÒÀÀµÏî¿ÉÒÔΪÄúÅäÖÃËùÓÐÄÚÈÝ¡£ ÉõÖÁһЩµÚÈý·½¿âҲͨ¹ýËûÃÇµÄÆô¶¯Ä£¿éÌṩ¶Ô Spring µÄÖ§³Ö¡£ Èç¹ûûÓÐÕâЩÆô¶¯Æ÷£¬Äú×÷Ϊ¿ª·¢ÈËÔ±½«²»µÃ²»Î¬»¤ÒÀÀµÏîºÍ XML ÅäÖᣠÕâÊÇÄúÓ¦¸ÃʹÓà Spring Boot µÄÁíÒ»¸öÔÒò¡£
+
+## ǶÈëʽ·þÎñÆ÷
+
+Spring Boot ΪǶÈëʽ Tomcat¡¢Jetty ºÍ Undertow ·þÎñÆ÷Ìṩ¿ªÏä¼´ÓõÄÖ§³Ö¡£ ÕâÑù£¬¿ª·¢ÈËÔ±¾Í²»±Øµ£ÐÄÔÚ´«Í³Ó¦Ó÷þÎñÆ÷Öв¿Êð Web Ó¦ÓóÌÐò¡£ ͨ¹ýÊʵ±µÄÆô¶¯Æ÷ÒÀÀµÏÄúÉõÖÁ¿ÉÒÔ½«Ò»ÖÖ·þÎñÆ÷¼¼ÊõÓëÆäËû·þÎñÆ÷¼¼Êõ½»»»¡£ ËùÒÔÄãʵ¼ÊÉÏ×îÖյõ½ÁËÒ»¸ö¿ÉÒÔÏñÈκΠJAR Ò»ÑùÔËÐÐµÄ JAR Îļþ¡£ ÔÚÆô¶¯Ê±£¬JAR °üº¬×ã¹»µÄ¿âºÍÅäÖÃÒÔ×÷ΪӦÓóÌÐò·þÎñÆ÷Æô¶¯²¢ÕìÌýÇëÇó¡£
+
+Èç¹ûÄú¶ÔǶÈëʽ·þÎñÆ÷²»¸ÐÐËȤ£¬Äú¿ÉÒÔËæÊ±½« Spring Boot Ó¦ÓóÌÐò´Ó JAR ת»»Îª WAR£¬²¢½«ËüÃDz¿Êðµ½´«Í³·þÎñÆ÷¡£
+
+## IDE ¶Ô Spring Boot µÄÖ§³Ö
+
+ËùÓÐÖ÷ÒªµÄ IDE ¶¼Ìṩ¶Ô Spring Boot ´úÂë°ïÖúµÄÖ§³Ö¡£ ÀýÈ磬IntelliJ IDEA Ultimate Ϊ Spring Boot ÏîÄ¿ÌṩÁ˳öÉ«µÄ´úÂëÍê³ÉºÍµ¼º½¹¦ÄÜ¡£³ý´ËÖ®Í⣬VSCode ºÍ Eclipse Ò²¶ÔÆäÌṩÁ˷ḻµÄ¹¦ÄÜÖ§³Ö¡£
+
+## Éú²ú»·¾³³£Óù¦ÄÜ
+
+Spring Boot ÌṩÁËÉú²ú¾ÍÐ÷µÄÌØÐÔ£¬ÀýÈç¼à¿Ø¡¢Ö¸±êºÍ¿ªÏä¼´ÓõÄ×¢Ïú¡£ ÓÐÁËÕâÐ©ÌØÐÔ£¬¿ª·¢ÈËÔ±¿ÉÒÔ±ÜÃâ¶îÍâµÄÅäÖᣠÀýÈ磬½¡¿µÖ´ÐÐÆ÷¶ËµãµÈ¹¦ÄÜʹӦÓóÌÐò״̬¼à¿Ø³ÉΪ¿ÉÄÜ¡£ ÀýÈ磬
+
+Äú¿ÉÒÔÈÃÏñ Prometheus ÕâÑùµÄ¹¤¾ßÊÕ¼¯Ó¦ÓóÌÐòÖ¸±ê
+
+ÔÚÄúµÄ Kubernetes »ò Openshift »·¾³ÖÐʹÓþÍÐ÷ÐԺͻîÔ¾¶È½¡¿µ¶Ëµã¡£
+
+Ö»ÐèÌí¼ÓÆäËûÊôÐÔ»òͨ¹ý /actuator/logging ¶Ëµã¼´¿É¸ü¸ÄÈÕÖ¾¼Ç¼¼¶±ð¡£
+
+´ËÍ⣬¿ª·¢ÈËÔ±¿ÉÒÔʹÓÃ×Ô¼ºµÄ×Ô¶¨Ò彡¿µ¶ËµãÅäÖÃÕâЩִÐÐÆ÷¶Ëµã¡£
+
+## ¿ªÏä¼´ÓÃµÄ JUnit Ö§³Ö
+
+ĬÈÏÇé¿öÏ£¬ËùÓÐ Spring Boot ÏîÄ¿¶¼´øÓÐ JUnit 5¡£ ´ËÍ⣬Spring Boot ÌṩÁË@SpringBootTest ×¢½âÀ´ÔÚÎÒÃÇÐèҪʱ³õʼ»¯²âÊÔÉÏÏÂÎÄ¡£ ËùÒÔ¿ª·¢ÈËÔ±Ö»ÐèÒª±àд²âÊÔÓÃÀý¡£ ËûÃDz»±ØÔÙµ£ÐIJâÊÔÓÃÀýµÄ¸´ÔÓ spring ÉÏÏÂÎÄ¡£
+
+ÀýÈ磬ÏÂÃæ×Ô¶¯Éú³ÉµÄ²âÊÔ½«¼ì²éÉÏÏÂÎÄÊÇ·ñÕýÈ·¼ÓÔØ¡£
+
+````
+@SpringBootTest
+class SpringBootDerbyDatabaseApplicationTests {
+
+ @²âÊÔ
+ void contextLoads() {
+ }
+
+}
+````
+
+## Spring Profiles
+
+Spring Profiles ÊÇ spring Boot µÄÒ»¸öÇ¿´óÌØÐÔ£¬ÓÐÖúÓÚ¸ôÀëÓ¦ÓóÌÐòÖеIJ»Í¬×é¼þ¡£ ʹÓÃÅäÖÃÎļþ£¬Äú¿ÉÒÔÔÚÌØ¶¨»·¾³ÖÐÆôÓûò½ûÓÃ×é¼þ¡£ µ±Äú±ØÐë¸ù¾ÝÌØ¶¨Ìõ¼þʹÓò»Í¬µÄ×é¼þʱ£¬Õâ¿ÉÄÜ»áÅÉÉÏÓó¡¡£
+````
+@Profile(value = {"prod","uat"})
+class RabbitMQConfig {
+
+// ÌýÖÚ
+
+}
+````
+
+ÔÚÉÏÃæµÄ´úÂëÖУ¬ÉÏÏÂÎĽ«ÏÞÖÆÍÃ×ÓÕìÌýÆ÷½öÔÚ¾ßÓÐ prod »ò uat ×÷Ϊ»î¶¯ÅäÖÃÎļþµÄ»·¾³ÖÐÔËÐС£
+
+## ¶àÖÖ´ò°üºÍ²¿ÊðÑ¡Ïî
+
+¸Ã¿ò¼ÜÌṩÁ˶àÖÖ·½Ê½À´´ò°üÄúµÄÓ¦ÓóÌÐò¡£ ÕýÈçÎÒÃÇ֮ǰËù˵£¬Ó¦ÓóÌÐò¿ÉÒÔÊÇ JAR »ò WAR Îļþ¡£ ͨ¹ýһЩ¶îÍâµÄÅäÖúͲÎÊý£¬Äú»¹¿ÉÒÔ´´½¨¿ªÏä¼´ÓõĸßÐÔÄÜ docker ¾µÏñ¡£
+
+Æô¶¯ºÍÍ£Ö¹ Spring Boot Ó¦ÓóÌÐò·Ç³£¼òµ¥¡£ ´ËÍ⣬Äú¿ÉÒÔͨ¹ý¼¸¸ö¶îÍâµÄ²½Ö轫ÕâЩ JAR Îļþ²¿ÊðΪ linux ·þÎñ¡£ JAR Îļþ³ÆÎª FAT jar£¬ËüÃǰüº¬ÓëÓ¦ÓóÌÐòÏà¹ØµÄËùÓÐÒÀÀµÏî¡£ ÕâʹµÃ²¿Êð¹ý³Ì²»ÄÇô¸´ÔÓ¡£ ʵ¼ÊÉÏ£¬ÕâЩ¹¹½¨¿ÉÒÔÔÚÈκÎ×°ÓÐ Java 8 »ò¸ü¸ß°æ±¾µÄ»úÆ÷ÉÏÔËÐС£
+
+# ²Î¿¼ÎÄÕÂ
+
+[https://spring.io/](https://spring.io/)
+
+[https://pdai.tech/md/spring/springboot/springboot-x-overview.html](https://pdai.tech/md/spring/springboot/springboot-x-overview.html)
+
+[https://springhow.com/why-use-spring-boot/](https://springhow.com/why-use-spring-boot/)
+
+[https://dzone.com/articles/why-springboot](https://dzone.com/articles/why-springboot)
+
+[https://scand.com/company/blog/pros-and-cons-of-using-spring-boot/](https://scand.com/company/blog/pros-and-cons-of-using-spring-boot/)
+
+[https://cloud.tencent.com/developer/article/1620255](https://cloud.tencent.com/developer/article/1620255)
+
+[https://www.yiibai.com/spring-boot/spring-vs-spring-boot-vs-spring-mvc.html](https://www.yiibai.com/spring-boot/spring-vs-spring-boot-vs-spring-mvc.html)
\ No newline at end of file
diff --git "a/docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
similarity index 100%
rename from "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
diff --git "a/docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md"
similarity index 100%
rename from "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md"
diff --git "a/docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md"
diff --git "a/docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md"
similarity index 100%
rename from "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md"
diff --git "a/docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md"
diff --git "a/docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md"
similarity index 100%
rename from "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md"
diff --git "a/docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md"
diff --git "a/docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md"
similarity index 100%
rename from "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md"
diff --git "a/docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md"
similarity index 100%
rename from "docs/java-web/Spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md"
diff --git "a/docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md" "b/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md"
similarity index 100%
rename from "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md"
rename to "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md"
diff --git "a/docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md" "b/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md"
similarity index 100%
rename from "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md"
rename to "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md"
diff --git "a/docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md" "b/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md"
rename to "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md"
diff --git "a/docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md" "b/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md"
similarity index 100%
rename from "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md"
rename to "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md"
diff --git "a/docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md" "b/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md"
similarity index 100%
rename from "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md"
rename to "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md"
diff --git "a/docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md" "b/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md"
similarity index 100%
rename from "docs/java-web/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md"
rename to "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md"
diff --git "a/docs/java-web/Spring/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md" "b/docs/spring/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md"
similarity index 100%
rename from "docs/java-web/Spring/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md"
rename to "docs/spring/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md"
From 525265639ede5463e64125a6f82ababf1c609ef1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=BB=84=E5=B0=8F=E6=96=9C?= <362294931@qq.com>
Date: Sat, 15 Apr 2023 22:19:42 +0800
Subject: [PATCH 02/32] add spring content
---
ReadMe.md | 4 +
...65\344\270\216\344\275\234\347\224\250.md" | 621 +++++++++
...10\346\240\270\345\277\203\357\274\211.md" | 182 +++
...70\350\247\201\346\263\250\350\247\243.md" | 158 +++
...72\346\234\254\344\275\277\347\224\250.md" | 152 +++
...45\220\253Spring+SpringMVC+SpringBoot).md" | 1112 ++++++++++++++++
...23\347\232\204\350\256\277\351\227\256.md" | 1183 +++++++++++++++++
...75\347\232\204\346\224\257\346\214\201.md" | 715 ++++++++++
...57\345\242\203\345\217\230\351\207\217.md" | 852 ++++++++++++
...04\347\220\206\346\234\272\345\210\266.md" | 270 ++++
...04\346\272\220\347\256\241\347\220\206.md" | 309 +++++
...54\346\225\260\346\215\256\357\274\211.md" | 298 +++++
...72\346\234\254\347\224\250\346\263\225.md" | 430 ++++++
.../spring/Spring\345\220\210\351\233\206.md" | 22 +
...345\256\271\345\231\250\344\270\216IOC.md" | 157 +++
...70\350\247\201\346\263\250\350\247\243.md" | 724 ++++++++++
.../spring/Spring\346\246\202\350\277\260.md" | 145 ++
...70\350\247\201\346\263\250\350\247\243.md" | 232 ++++
...\270\252Spring\345\272\224\347\224\250.md" | 70 +
pom.xml | 28 +
src/main/java/Test.java | 22 +
21 files changed, 7686 insertions(+)
create mode 100644 "docs/spring/SpringAOP\347\232\204\346\246\202\345\277\265\344\270\216\344\275\234\347\224\250.md"
create mode 100644 "docs/spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md"
create mode 100644 "docs/spring/SpringBoot/SpringBoot\345\270\270\350\247\201\346\263\250\350\247\243.md"
create mode 100644 "docs/spring/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md"
create mode 100644 "docs/spring/SpringBoot/Spring\345\270\270\350\247\201\346\263\250\350\247\243\344\275\277\347\224\250\346\214\207\345\215\227(\345\214\205\345\220\253Spring+SpringMVC+SpringBoot).md"
create mode 100644 "docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\225\260\346\215\256\345\272\223\347\232\204\350\256\277\351\227\256.md"
create mode 100644 "docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md"
create mode 100644 "docs/spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md"
create mode 100644 "docs/spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md"
create mode 100644 "docs/spring/Spring\344\270\255\347\232\204\350\265\204\346\272\220\347\256\241\347\220\206.md"
create mode 100644 "docs/spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md"
create mode 100644 "docs/spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md"
create mode 100644 "docs/spring/Spring\345\220\210\351\233\206.md"
create mode 100644 "docs/spring/Spring\345\256\271\345\231\250\344\270\216IOC.md"
create mode 100644 "docs/spring/Spring\345\270\270\350\247\201\346\263\250\350\247\243.md"
create mode 100644 "docs/spring/Spring\346\246\202\350\277\260.md"
create mode 100644 "docs/spring/springMVC/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
create mode 100644 "docs/spring/\347\254\254\344\270\200\344\270\252Spring\345\272\224\347\224\250.md"
create mode 100644 src/main/java/Test.java
diff --git a/ReadMe.md b/ReadMe.md
index c83ee64..c8ec78e 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -144,6 +144,10 @@
### Spring
+* [Spring常�注解.md](docs/spring/Spring常�注解.md)
+
+
+
* [Springæº�ç �剖æž�:Spring概述](docs/spring/Springæº�ç �剖æž�:Spring概述.md)
* [Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程](docs/spring/Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程.md)
* [Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹ ](docs/spring/Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹.md)
diff --git "a/docs/spring/SpringAOP\347\232\204\346\246\202\345\277\265\344\270\216\344\275\234\347\224\250.md" "b/docs/spring/SpringAOP\347\232\204\346\246\202\345\277\265\344\270\216\344\275\234\347\224\250.md"
new file mode 100644
index 0000000..26e828a
--- /dev/null
+++ "b/docs/spring/SpringAOP\347\232\204\346\246\202\345\277\265\344\270\216\344\275\234\347\224\250.md"
@@ -0,0 +1,621 @@
+# Spring ¿ò¼ÜµÄ AOP
+
+## Spring ¿ò¼ÜµÄ AOP
+
+Spring ¿ò¼ÜµÄÒ»¸ö¹Ø¼ü×é¼þÊÇ**ÃæÏòÇÐÃæµÄ±à³Ì**(AOP)¿ò¼Ü¡£ÃæÏòÇÐÃæµÄ±à³ÌÐèÒª°Ñ³ÌÐòÂß¼·Ö½â³É²»Í¬µÄ²¿·Ö³ÆÎªËùνµÄ¹Ø×¢µã¡£¿çÒ»¸öÓ¦ÓóÌÐòµÄ¶à¸öµãµÄ¹¦Äܱ»³ÆÎª**ºáÇйØ×¢µã**£¬ÕâЩºáÇйØ×¢µãÔÚ¸ÅÄîÉ϶ÀÁ¢ÓÚÓ¦ÓóÌÐòµÄÒµÎñÂß¼¡£ÔÚÈí¼þ¿ª·¢¹ý³ÌÖÐÓи÷ÖÖ¸÷ÑùµÄºÜºÃµÄÇÐÃæµÄÀý×Ó£¬ÈçÈÕÖ¾¼Ç¼¡¢É󼯡¢ÉùÃ÷ʽÊÂÎñ¡¢°²È«ÐԺͻº´æµÈ¡£
+
+ÔÚ OOP ÖУ¬¹Ø¼üµ¥ÔªÄ£¿é¶ÈÊÇÀ࣬¶øÔÚ AOP Öе¥ÔªÄ£¿é¶ÈÊÇÇÐÃæ¡£ÒÀÀµ×¢Èë°ïÖúÄã¶ÔÓ¦ÓóÌÐò¶ÔÏóÏ໥½âñîºÏ£¬AOP ¿ÉÒÔ°ïÖúÄã´ÓËüÃÇËùÓ°ÏìµÄ¶ÔÏóÖжԺáÇйØ×¢µã½âñî¡£AOP ÏñÊDZà³ÌÓïÑԵĴ¥·¢ÎÈç Perl£¬.NET£¬Java »òÕ߯äËûÓïÑÔ¡£
+
+Spring AOP Ä£¿éÌṩÀ¹½ØÆ÷À´À¹½ØÒ»¸öÓ¦ÓóÌÐò£¬ÀýÈ磬µ±Ö´ÐÐÒ»¸ö·½·¨Ê±£¬Äã¿ÉÒÔÔÚ·½·¨Ö´ÐÐ֮ǰ»òÖ®ºóÌí¼Ó¶îÍâµÄ¹¦ÄÜ¡£
+
+## AOP ÊõÓï
+
+ÔÚÎÒÃÇ¿ªÊ¼Ê¹Óà AOP ¹¤×÷֮ǰ£¬ÈÃÎÒÃÇÊìϤһÏ AOP ¸ÅÄîºÍÊõÓï¡£ÕâЩÊõÓï²¢²»Ìض¨ÓÚ Spring£¬¶øÊÇÓë AOP Óйصġ£
+
+| Ïî | ÃèÊö |
+| --- | --- |
+| Aspect | Ò»¸öÄ£¿é¾ßÓÐÒ»×éÌṩºáÇÐÐèÇóµÄ APIs¡£ÀýÈ磬һ¸öÈÕ־ģ¿éΪÁ˼ǼÈÕÖ¾½«±» AOP ·½Ãæµ÷Óá£Ó¦ÓóÌÐò¿ÉÒÔÓµÓÐÈÎÒâÊýÁ¿µÄ·½Ã棬ÕâÈ¡¾öÓÚÐèÇó¡£ |
+| Join point | ÔÚÄãµÄÓ¦ÓóÌÐòÖÐËü´ú±íÒ»¸öµã£¬Äã¿ÉÒÔÔÚ²å¼þ AOP ·½Ãæ¡£ÄãÒ²ÄÜ˵£¬ËüÊÇÔÚʵ¼ÊµÄÓ¦ÓóÌÐòÖУ¬ÆäÖÐÒ»¸ö²Ù×÷½«Ê¹Óà Spring AOP ¿ò¼Ü¡£ |
+| Advice | ÕâÊÇʵ¼ÊÐж¯Ö®Ç°»òÖ®ºóÖ´Ðеķ½·¨¡£ÕâÊÇÔÚ³ÌÐòÖ´ÐÐÆÚ¼äͨ¹ý Spring AOP ¿ò¼Üʵ¼Ê±»µ÷ÓõĴúÂë¡£ |
+| Pointcut | ÕâÊÇÒ»×éÒ»¸ö»ò¶à¸öÁ¬½Óµã£¬Í¨ÖªÓ¦¸Ã±»Ö´ÐС£Äã¿ÉÒÔʹÓñí´ïʽ»òģʽָ¶¨ÇÐÈëµãÕýÈçÎÒÃǽ«ÔÚ AOP µÄÀý×ÓÖп´µ½µÄ¡£ |
+| Introduction | ÒýÓÃÔÊÐíÄãÌí¼Óз½·¨»òÊôÐÔµ½ÏÖÓеÄÀàÖС£ |
+| Target object | ±»Ò»¸ö»òÕß¶à¸ö·½ÃæËù֪ͨµÄ¶ÔÏó£¬Õâ¸ö¶ÔÏóÓÀÔ¶ÊÇÒ»¸ö±»´úÀí¶ÔÏó¡£Ò²³ÆÎª±»Í¨Öª¶ÔÏó¡£ |
+| Weaving | Weaving °Ñ·½ÃæÁ¬½Óµ½ÆäËüµÄÓ¦ÓóÌÐòÀàÐÍ»òÕß¶ÔÏóÉÏ£¬²¢´´½¨Ò»¸ö±»Í¨ÖªµÄ¶ÔÏó¡£ÕâЩ¿ÉÒÔÔÚ±àÒëʱ£¬Àà¼ÓÔØÊ±ºÍÔËÐÐʱÍê³É¡£ |
+
+## ֪ͨµÄÀàÐÍ
+
+Spring ·½Ãæ¿ÉÒÔʹÓÃÏÂÃæÌáµ½µÄÎåÖÖ֪ͨ¹¤×÷£º
+
+| ֪ͨ | ÃèÊö |
+| --- | --- |
+| ǰÖÃ֪ͨ | ÔÚÒ»¸ö·½·¨Ö´ÐÐ֮ǰ£¬Ö´ÐÐ֪ͨ¡£ |
+| ºóÖÃ֪ͨ | ÔÚÒ»¸ö·½·¨Ö´ÐÐÖ®ºó£¬²»¿¼ÂÇÆä½á¹û£¬Ö´ÐÐ֪ͨ¡£ |
+| ·µ»Øºó֪ͨ | ÔÚÒ»¸ö·½·¨Ö´ÐÐÖ®ºó£¬Ö»ÓÐÔÚ·½·¨³É¹¦Íê³Éʱ£¬²ÅÄÜÖ´ÐÐ֪ͨ¡£ |
+| Å׳öÒì³£ºó֪ͨ | ÔÚÒ»¸ö·½·¨Ö´ÐÐÖ®ºó£¬Ö»ÓÐÔÚ·½·¨Í˳öÅ׳öÒ쳣ʱ£¬²ÅÄÜÖ´ÐÐ֪ͨ¡£ |
+| »·ÈÆÍ¨Öª | ÔÚ½¨Òé·½·¨µ÷ÓÃ֮ǰºÍÖ®ºó£¬Ö´ÐÐ֪ͨ¡£ |
+
+## ʵÏÖ×Ô¶¨Òå·½Ãæ
+
+Spring Ö§³Ö **@AspectJ annotation style** µÄ·½·¨ºÍ**»ùÓÚģʽ**µÄ·½·¨À´ÊµÏÖ×Ô¶¨Òå·½Ãæ¡£ÕâÁ½ÖÖ·½·¨ÒѾÔÚÏÂÃæÁ½¸ö×Ó½Ú½øÐÐÁËÏêϸ½âÊÍ¡£
+
+| ·½·¨ | ÃèÊö |
+| --- | --- |
+| [XML Schema based](https://www.w3cschool.cn/wkspring/omps1mm6.html) | ·½ÃæÊÇʹÓ󣹿ÀàÒÔ¼°»ùÓÚÅäÖÃµÄ XML À´ÊµÏֵġ£ |
+| [@AspectJ based](https://www.w3cschool.cn/wkspring/k4q21mm8.html) | @AspectJ ÒýÓÃÒ»ÖÖÉùÃ÷·½ÃæµÄ·ç¸ñ×÷Ϊ´øÓÐ Java 5 ×¢Ê͵ij£¹æ Java Àà×¢ÊÍ¡£ |
+
+
+
+## Spring ÖлùÓÚ AOP µÄ XML¼Ü¹¹
+
+ΪÁËÔÚ±¾½ÚµÄÃèÊöÖÐʹÓà aop ÃüÃû¿Õ¼ä±êÇ©£¬ÄãÐèÒªµ¼Èë spring-aop ¼Ü¹¹£¬ÈçÏÂËùÊö£º
+
+```
+
+
+
+
+
+
+
+```
+
+Ä㻹ÐèÒªÔÚÄãµÄÓ¦ÓóÌÐòµÄ CLASSPATH ÖÐʹÓÃÒÔÏ AspectJ ¿âÎļþ¡£ÕâЩ¿âÎļþÔÚÒ»¸ö AspectJ ×°ÖÃµÄ ¡®lib¡¯ Ŀ¼ÖÐÊÇ¿ÉÓõ쬷ñÔòÄã¿ÉÒÔÔÚ Internet ÖÐÏÂÔØËüÃÇ¡£(×¢£ºaspectjweaver.jar ÒѰüº¬ÆäËû°ü)
+
+* aspectjrt.jar
+
+* aspectjweaver.jar
+
+* aspectj.jar
+
+* aopalliance.jar
+
+## ¡¡ÉùÃ÷Ò»¸ö aspect
+
+Ò»¸ö **aspect** ÊÇʹÓÃ ÔªËØÉùÃ÷µÄ£¬Ö§³ÖµÄ bean ÊÇʹÓà **ref** ÊôÐÔÒýÓõģ¬ÈçÏÂËùʾ£º
+
+```
+
+
+ ...
+
+
+
+...
+
+```
+
+ÕâÀ¡°aBean¡± ½«±»ÅäÖúÍÒÀÀµ×¢È룬¾ÍÏñÇ°ÃæµÄÕ½ÚÖÐÄã¿´µ½µÄÆäËûµÄ Spring bean Ò»Ñù¡£
+
+## ÉùÃ÷Ò»¸öÇÐÈëµã
+
+Ò»¸ö**ÇÐÈëµã**ÓÐÖúÓÚÈ·¶¨Ê¹Óò»Í¬½¨ÒéÖ´ÐеĸÐÐËȤµÄÁ¬½Óµã£¨¼´·½·¨£©¡£ÔÚ´¦Àí»ùÓÚÅäÖÃµÄ XML ¼Ü¹¹Ê±£¬ÇÐÈëµã½«»á°´ÕÕÈçÏÂËùʾ¶¨Ò壺
+
+```
+
+
+
+ ...
+
+
+
+...
+
+```
+
+ÏÂÃæµÄʾÀý¶¨ÒåÁËÒ»¸öÃûΪ ¡°businessService¡± µÄÇÐÈëµã£¬¸ÃÇÐÈëµã½«Óë com.tutorialspoint °üÏ嵀 Student ÀàÖÐµÄ getName() ·½·¨ÏàÆ¥Å䣺
+
+```
+
+
+
+ ...
+
+
+
+...
+
+```
+
+## ÉùÃ÷½¨Òé
+
+Äã¿ÉÒÔÔÚÖÐʹÓÃÔªËØÉùÃ÷ÈÎÒâÎåÖÖÀàÐ͵Ä֪ͨ£¬ÈçÏ£º
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ...
+
+
+
+...
+
+```
+
+Äã¿ÉÒÔ¶Ô²»Í¬µÄ½¨ÒéʹÓÃÏàͬµÄ **doRequiredTask** »òÕß²»Í¬µÄ·½·¨¡£ÕâЩ·½·¨½«»á×÷Ϊ aspect Ä£¿éµÄÒ»²¿·ÖÀ´¶¨Òå¡£
+
+## »ùÓÚ AOP µÄ XML ¼Ü¹¹µÄʾÀý
+
+ΪÁËÀí½âÉÏÃæÌáµ½µÄ»ùÓÚ AOP µÄ XML ¼Ü¹¹µÄ¸ÅÄÈÃÎÒÃDZàдһ¸öʾÀý£¬¿ÉÒÔʵÏÖ¼¸¸ö½¨Ò顣ΪÁËÔÚÎÒÃǵÄʾÀýÖÐʹÓü¸¸ö½¨Ò飬ÈÃÎÒÃÇʹ Eclipse IDE ´¦ÓÚ¹¤×÷״̬£¬È»ºó°´ÕÕÈçϲ½Öè´´½¨Ò»¸ö Spring Ó¦ÓóÌÐò£º
+
+| ²½Öè | ÃèÊö |
+| --- | --- |
+| 1 | ´´½¨Ò»¸öÃûΪ _SpringExample_ µÄÏîÄ¿£¬²¢ÇÒÔÚËù´´½¨ÏîÄ¿µÄ **src** Îļþ¼ÐÏ´´½¨Ò»¸öÃûΪ _com.tutorialspoint_ µÄ°ü¡£ |
+| 2 | ʹÓà _Add External JARs_ Ñ¡ÏîÌí¼ÓËùÐèµÄ Spring ¿âÎļþ£¬¾ÍÈçÔÚ _Spring Hello World Example_ Õ½ÚÖнâÊ͵ÄÄÇÑù¡£ |
+| 3 | ÔÚÏîÄ¿ÖÐÌí¼Ó Spring AOP Ö¸¶¨µÄ¿âÎļþ **aspectjrt.jar£¬ aspectjweaver.jar** ºÍ **aspectj.jar**¡£ |
+| 4 | ÔÚ _com.tutorialspoint_ °üÏ´´½¨ Java Àà **Logging**£¬ _Student_ ºÍ _MainApp_¡£ |
+| 5 | ÔÚ **src** Îļþ¼ÐÏ´´½¨ Beans ÅäÖÃÎļþ _Beans.xml_¡£ |
+| 6 | ×îºóÒ»²½ÊÇ´´½¨ËùÓÐ Java ÎļþºÍ Bean ÅäÖÃÎļþµÄÄÚÈÝ£¬²¢ÇÒ°´ÈçϽâÊ͵ÄÄÇÑùÔËÐÐÓ¦ÓóÌÐò¡£ |
+
+ÕâÀïÊÇ **Logging.java** ÎļþµÄÄÚÈÝ¡£Õâʵ¼ÊÉÏÊÇ aspect Ä£¿éµÄÒ»¸öʾÀý£¬Ëü¶¨ÒåÁËÔÚ¸÷¸öµãµ÷Óõķ½·¨¡£
+
+```
+package com.tutorialspoint;
+public class Logging {
+ /**
+ * This is the method which I would like to execute
+ * before a selected method execution.
+ */
+ public void beforeAdvice(){
+ System.out.println("Going to setup student profile.");
+ }
+ /**
+ * This is the method which I would like to execute
+ * after a selected method execution.
+ */
+ public void afterAdvice(){
+ System.out.println("Student profile has been setup.");
+ }
+ /**
+ * This is the method which I would like to execute
+ * when any method returns.
+ */
+ public void afterReturningAdvice(Object retVal){
+ System.out.println("Returning:" + retVal.toString() );
+ }
+ /**
+ * This is the method which I would like to execute
+ * if there is an exception raised.
+ */
+ public void AfterThrowingAdvice(IllegalArgumentException ex){
+ System.out.println("There has been an exception: " + ex.toString());
+ }
+}
+```
+
+ÏÂÃæÊÇ **Student.java** ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+public class Student {
+ private Integer age;
+ private String name;
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+ public Integer getAge() {
+ System.out.println("Age : " + age );
+ return age;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+ public String getName() {
+ System.out.println("Name : " + name );
+ return name;
+ }
+ public void printThrowException(){
+ System.out.println("Exception raised");
+ throw new IllegalArgumentException();
+ }
+}
+```
+
+ÏÂÃæÊÇ **MainApp.java** ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+public class MainApp {
+ public static void main(String[] args) {
+ ApplicationContext context =
+ new ClassPathXmlApplicationContext("Beans.xml");
+ Student student = (Student) context.getBean("student");
+ student.getName();
+ student.getAge();
+ student.printThrowException();
+ }
+}
+```
+
+ÏÂÃæÊÇÅäÖÃÎļþ **Beans.xml**£º
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Ò»µ©ÄãÒѾÍê³ÉµÄ´´½¨ÁËÔ´ÎļþºÍ bean ÅäÖÃÎļþ£¬ÈÃÎÒÃÇÔËÐÐÒ»ÏÂÓ¦ÓóÌÐò¡£Èç¹ûÄãµÄÓ¦ÓóÌÐòÒ»Çж¼Õý³£µÄ»°£¬Õ⽫»áÊä³öÒÔÏÂÏûÏ¢£º
+
+```
+Going to setup student profile.
+Name : Zara
+Student profile has been setup.
+Returning:Zara
+Going to setup student profile.
+Age : 11
+Student profile has been setup.
+Returning:11
+Going to setup student profile.
+Exception raised
+Student profile has been setup.
+There has been an exception: java.lang.IllegalArgumentException
+.....
+other exception content
+```
+
+ÈÃÎÒÃÇÀ´½âÊÍÒ»ÏÂÉÏÃæ¶¨ÒåµÄÔÚ com.tutorialspoint ÖÐ Ñ¡ÔñËùÓз½·¨µÄ ¡£ÈÃÎÒÃǼÙÉèһϣ¬ÄãÏëÒªÔÚÒ»¸öÌØÊâµÄ·½·¨Ö®Ç°»òÕßÖ®ºóÖ´ÐÐÄãµÄ½¨Ò飬Äã¿ÉÒÔͨ¹ýÌæ»»Ê¹ÓÃÕæÊµÀàºÍ·½·¨Ãû³ÆµÄÇÐÈëµã¶¨ÒåÖеÄÐǺţ¨*£©À´¶¨ÒåÄãµÄÇÐÈëµãÀ´Ëõ¶ÌÄãµÄÖ´ÐС£
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Èç¹ûÄãÏëÒªÖ´ÐÐͨ¹ýÕâЩ¸ü¸ÄÖ®ºóµÄʾÀýÓ¦ÓóÌÐò£¬Õ⽫»áÊä³öÒÔÏÂÏûÏ¢£º
+
+```
+Going to setup student profile.
+Name : Zara
+Student profile has been setup.
+Age : 11
+Exception raised
+.....
+other exception content
+```
+
+
+
+## Spring ÖлùÓÚ AOP µÄ @AspectJ
+
+@AspectJ ×÷Ϊͨ¹ý Java 5 ×¢ÊÍ×¢ÊÍµÄÆÕͨµÄ Java À࣬ËüÖ¸µÄÊÇÉùÃ÷ aspects µÄÒ»ÖÖ·ç¸ñ¡£Í¨¹ýÔÚÄãµÄ»ùÓڼܹ¹µÄ XML ÅäÖÃÎļþÖаüº¬ÒÔÏÂÔªËØ£¬@AspectJ Ö§³ÖÊÇ¿ÉÓõġ£
+
+```
+
+```
+
+Ä㻹ÐèÒªÔÚÄãµÄÓ¦ÓóÌÐòµÄ CLASSPATH ÖÐʹÓÃÒÔÏ AspectJ ¿âÎļþ¡£ÕâЩ¿âÎļþÔÚÒ»¸ö AspectJ ×°ÖÃµÄ ¡®lib¡¯ Ŀ¼ÖÐÊÇ¿ÉÓõģ¬Èç¹ûûÓУ¬Äã¿ÉÒÔÔÚ Internet ÖÐÏÂÔØËüÃÇ¡£
+
+* aspectjrt.jar
+
+* aspectjweaver.jar
+
+* aspectj.jar
+
+* aopalliance.jar
+
+## ¡¡ÉùÃ÷Ò»¸ö aspect
+
+Aspects ÀàºÍÆäËûÈκÎÕý³£µÄ bean Ò»Ñù£¬³ýÁËËüÃǽ«»áÓà @AspectJ ×¢ÊÍÖ®Í⣬ËüºÍÆäËûÀàÒ»Ñù¿ÉÄÜÓз½·¨ºÍ×ֶΣ¬ÈçÏÂËùʾ£º
+
+```
+package org.xyz;
+import org.aspectj.lang.annotation.Aspect;
+@Aspect
+public class AspectModule {
+}
+```
+
+ËüÃǽ«ÔÚ XML Öа´ÕÕÈçϽøÐÐÅäÖã¬¾ÍºÍÆäËûÈκΠbean Ò»Ñù£º
+
+```
+
+
+
+
+```
+
+## ÉùÃ÷Ò»¸öÇÐÈëµã
+
+Ò»¸ö**ÇÐÈëµã**ÓÐÖúÓÚÈ·¶¨Ê¹Óò»Í¬½¨ÒéÖ´ÐеĸÐÐËȤµÄÁ¬½Óµã£¨¼´·½·¨£©¡£ÔÚ´¦Àí»ùÓÚÅäÖÃµÄ XML ¼Ü¹¹Ê±£¬ÇÐÈëµãµÄÉùÃ÷ÓÐÁ½¸ö²¿·Ö£º
+
+* Ò»¸öÇÐÈëµã±í´ïʽ¾ö¶¨ÁËÎÒÃǸÐÐËȤµÄÄĸö·½·¨»áÕæÕý±»Ö´ÐС£
+
+* Ò»¸öÇÐÈëµã±êÇ©°üº¬Ò»¸öÃû³ÆºÍÈÎÒâÊýÁ¿µÄ²ÎÊý¡£·½·¨µÄÕæÕýÄÚÈÝÊDz»Ïà¸ÉµÄ£¬²¢ÇÒʵ¼ÊÉÏËüÓ¦¸ÃÊǿյġ£
+
+ÏÂÃæµÄʾÀýÖж¨ÒåÁËÒ»¸öÃûΪ ¡®businessService¡¯ µÄÇÐÈëµã£¬¸ÃÇÐÈëµã½«Óë com.xyz.myapp.service °üϵÄÀàÖпÉÓõÄÿһ¸ö·½·¨ÏàÆ¥Å䣺
+
+```
+import org.aspectj.lang.annotation.Pointcut;
+@Pointcut("execution(* com.xyz.myapp.service.*.*(..))") // expression
+private void businessService() {} // signature
+```
+
+ÏÂÃæµÄʾÀýÖж¨ÒåÁËÒ»¸öÃûΪ ¡®getname¡¯ µÄÇÐÈëµã£¬¸ÃÇÐÈëµã½«Óë com.tutorialspoint °üÏ嵀 Student ÀàÖÐµÄ getName() ·½·¨ÏàÆ¥Å䣺
+
+```
+import org.aspectj.lang.annotation.Pointcut;
+@Pointcut("execution(* com.tutorialspoint.Student.getName(..))")
+private void getname() {}
+```
+
+## ÉùÃ÷½¨Òé
+
+Äã¿ÉÒÔʹÓà @{ADVICE-NAME} ×¢ÊÍÉùÃ÷Îå¸ö½¨ÒéÖеÄÈÎÒâÒ»¸ö£¬ÈçÏÂËùʾ¡£Õâ¼ÙÉèÄãÒѾ¶¨ÒåÁËÒ»¸öÇÐÈëµã±êÇ©·½·¨ businessService()£º
+
+```
+@Before("businessService()")
+public void doBeforeTask(){
+ ...
+}
+@After("businessService()")
+public void doAfterTask(){
+ ...
+}
+@AfterReturning(pointcut = "businessService()", returning="retVal")
+public void doAfterReturnningTask(Object retVal){
+ // you can intercept retVal here.
+ ...
+}
+@AfterThrowing(pointcut = "businessService()", throwing="ex")
+public void doAfterThrowingTask(Exception ex){
+ // you can intercept thrown exception here.
+ ...
+}
+@Around("businessService()")
+public void doAroundTask(){
+ ...
+}
+```
+
+Äã¿ÉÒÔΪÈÎÒâÒ»¸ö½¨Ò鶨ÒåÄãµÄÇÐÈëµãÄÚÁª¡£ÏÂÃæÊÇÔÚ½¨Òé֮ǰ¶¨ÒåÄÚÁªÇÐÈëµãµÄÒ»¸öʾÀý£º
+
+```
+@Before("execution(* com.xyz.myapp.service.*.*(..))")
+public doBeforeTask(){
+ ...
+}
+```
+
+## »ùÓÚ AOP µÄ @AspectJ ʾÀý
+
+ΪÁËÀí½âÉÏÃæÌáµ½µÄ¹ØÓÚ»ùÓÚ AOP µÄ @AspectJ µÄ¸ÅÄÈÃÎÒÃDZàдһ¸öʾÀý£¬¿ÉÒÔʵÏÖ¼¸¸ö½¨Ò顣ΪÁËÔÚÎÒÃǵÄʾÀýÖÐʹÓü¸¸ö½¨Ò飬ÈÃÎÒÃÇʹ Eclipse IDE ´¦ÓÚ¹¤×÷״̬£¬È»ºó°´ÕÕÈçϲ½Öè´´½¨Ò»¸ö Spring Ó¦ÓóÌÐò£º
+
+| ²½Öè | ÃèÊö |
+| --- | --- |
+| 1 | ´´½¨Ò»¸öÃûΪ _SpringExample_ µÄÏîÄ¿£¬²¢ÇÒÔÚËù´´½¨ÏîÄ¿µÄ **src** Îļþ¼ÐÏ´´½¨Ò»¸öÃûΪ _com.tutorialspoint_ µÄ°ü¡£ |
+| 2 | ʹÓà _Add External JARs_ Ñ¡ÏîÌí¼ÓËùÐèµÄ Spring ¿âÎļþ£¬¾ÍÈçÔÚ _Spring Hello World Example_ Õ½ÚÖнâÊ͵ÄÄÇÑù¡£ |
+| 3 | ÔÚÏîÄ¿ÖÐÌí¼Ó Spring AOP Ö¸¶¨µÄ¿âÎļþ **aspectjrt.jar£¬ aspectjweaver.jar** ºÍ **aspectj.jar**¡£ |
+| 4 | ÔÚ _com.tutorialspoint_ °üÏ´´½¨ Java Àà **Logging**£¬ _Student_ ºÍ _MainApp_¡£ |
+| 5 | ÔÚ **src** Îļþ¼ÐÏ´´½¨ Beans ÅäÖÃÎļþ _Beans.xml_¡£ |
+| 6 | ×îºóÒ»²½ÊÇ´´½¨ËùÓÐ Java ÎļþºÍ Bean ÅäÖÃÎļþµÄÄÚÈÝ£¬²¢ÇÒ°´ÈçϽâÊ͵ÄÄÇÑùÔËÐÐÓ¦ÓóÌÐò¡£ |
+
+ÕâÀïÊÇ **Logging.java** ÎļþµÄÄÚÈÝ¡£Õâʵ¼ÊÉÏÊÇ aspect Ä£¿éµÄÒ»¸öʾÀý£¬Ëü¶¨ÒåÁËÔÚ¸÷¸öµãµ÷Óõķ½·¨¡£
+
+```
+package com.tutorialspoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.After;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Around;
+@Aspect
+public class Logging {
+ /** Following is the definition for a pointcut to select
+ * all the methods available. So advice will be called
+ * for all the methods.
+ */
+ @Pointcut("execution(* com.tutorialspoint.*.*(..))")
+ private void selectAll(){}
+ /**
+ * This is the method which I would like to execute
+ * before a selected method execution.
+ */
+ @Before("selectAll()")
+ public void beforeAdvice(){
+ System.out.println("Going to setup student profile.");
+ }
+ /**
+ * This is the method which I would like to execute
+ * after a selected method execution.
+ */
+ @After("selectAll()")
+ public void afterAdvice(){
+ System.out.println("Student profile has been setup.");
+ }
+ /**
+ * This is the method which I would like to execute
+ * when any method returns.
+ */
+ @AfterReturning(pointcut = "selectAll()", returning="retVal")
+ public void afterReturningAdvice(Object retVal){
+ System.out.println("Returning:" + retVal.toString() );
+ }
+ /**
+ * This is the method which I would like to execute
+ * if there is an exception raised by any method.
+ */
+ @AfterThrowing(pointcut = "selectAll()", throwing = "ex")
+ public void AfterThrowingAdvice(IllegalArgumentException ex){
+ System.out.println("There has been an exception: " + ex.toString());
+ }
+}
+```
+
+ÏÂÃæÊÇ **Student.java** ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+public class Student {
+ private Integer age;
+ private String name;
+ public void setAge(Integer age) {
+ this.age = age;
+ }
+ public Integer getAge() {
+ System.out.println("Age : " + age );
+ return age;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+ public String getName() {
+ System.out.println("Name : " + name );
+ return name;
+ }
+ public void printThrowException(){
+ System.out.println("Exception raised");
+ throw new IllegalArgumentException();
+ }
+}
+```
+
+ÏÂÃæÊÇ **MainApp.java** ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+public class MainApp {
+ public static void main(String[] args) {
+ ApplicationContext context =
+ new ClassPathXmlApplicationContext("Beans.xml");
+ Student student = (Student) context.getBean("student");
+ student.getName();
+ student.getAge();
+ student.printThrowException();
+ }
+}
+```
+
+ÏÂÃæÊÇÅäÖÃÎļþ **Beans.xml**£º
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Ò»µ©ÄãÒѾÍê³ÉµÄ´´½¨ÁËÔ´ÎļþºÍ bean ÅäÖÃÎļþ£¬ÈÃÎÒÃÇÔËÐÐÒ»ÏÂÓ¦ÓóÌÐò¡£Èç¹ûÄãµÄÓ¦ÓóÌÐòÒ»Çж¼Õý³£µÄ»°£¬Õ⽫»áÊä³öÒÔÏÂÏûÏ¢£º
+
+```
+Going to setup student profile.
+Name : Zara
+Student profile has been setup.
+Returning:Zara
+Going to setup student profile.
+Age : 11
+Student profile has been setup.
+Returning:11
+Going to setup student profile.
+Exception raised
+Student profile has been setup.
+There has been an exception: java.lang.IllegalArgumentException
+.....
+other exception content
+```
+
+
+
+
+
+# ²Î¿¼ÎÄÕÂ
+https://www.w3cschool.cn/wkspring
+https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
+http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
+https://dunwu.github.io/spring-tutorial
+https://mszlu.com/java/spring
+http://c.biancheng.net/spring/aop-module.html
\ No newline at end of file
diff --git "a/docs/spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md" "b/docs/spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md"
new file mode 100644
index 0000000..a684554
--- /dev/null
+++ "b/docs/spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md"
@@ -0,0 +1,182 @@
+### ÒÀÀµ×¢Èë
+
+Spring¿ò¼ÜµÄºËÐŦÄÜÓÐÁ½¸ö£º
+
+* SpringÈÝÆ÷×÷Ϊ³¬¼¶´ó¹¤³§£¬¸ºÔð´´½¨¡¢¹ÜÀíËùÓеÄJava¶ÔÏó£¬ÕâЩJava¶ÔÏó±»³ÆÎªBean¡£
+* SpringÈÝÆ÷¹ÜÀíÈÝÆ÷ÖÐBeanÖ®¼äµÄÒÀÀµ¹ØÏµ£¬SpringʹÓÃÒ»ÖÖ±»³ÆÎª"ÒÀÀµ×¢Èë"µÄ·½Ê½À´¹ÜÀíBeanÖ®¼äµÄÒÀÀµ¹ØÏµ¡£
+
+ʹÓÃÒÀÀµ×¢È룬²»½ö¿ÉÒÔΪBean×¢ÈëÆÕͨµÄÊôÐÔÖµ£¬»¹¿ÉÒÔ×¢ÈëÆäËûBeanµÄÒýÓá£ÒÀÀµ×¢ÈëÊÇÒ»ÖÖÓÅÐãµÄ½âñʽ£¬Æä¿ÉÒÔÈÃBeanÒÔÅäÖÃÎļþ×éÖ¯ÔÚÒ»Æð£¬¶ø²»ÊÇÒÔÓ²±àÂëµÄ·½Ê½ñîºÏÔÚÒ»Æð¡£
+
+#### Àí½âÒÀÀµ×¢Èë
+
+Rod JohnsonÊǵÚÒ»¸ö¸ß¶ÈÖØÊÓÒÔÅäÖÃÎļþÀ´¹ÜÀíJavaʵÀýµÄÐ×÷¹ØÏµµÄÈË£¬Ëû¸øÕâÖÖ·½Ê½ÆðÁËÒ»¸öÃû×Ö£º¿ØÖÆ·´×ª£¨Inverse of Control£¬IoC£©¡£ºóÀ´Martine FowlerΪÕâÖÖ·½Ê½ÆðÁËÁíÒ»¸öÃû³Æ£ºÒÀÀµ×¢È루Dependency Injection£©£¬Òò´Ë²»¹ÜÊÇÒÀÀµ×¢È룬»¹ÊÇ¿ØÖÆ·´×ª£¬Æäº¬ÒåÍêÈ«Ïàͬ¡£µ±Ä³¸öJava¶ÔÏ󣨵÷ÓÃÕߣ©ÐèÒªµ÷ÓÃÁíÒ»¸öJava¶ÔÏ󣨱»ÒÀÀµ¶ÔÏ󣩵ķ½·¨Ê±£¬ÔÚ´«Í³Ä£Ê½ÏÂͨ³£ÓÐÁ½ÖÖ×ö·¨£º
+
+1. Ôʼ×ö·¨: µ÷ÓÃÕß**Ö÷¶¯**´´½¨±»ÒÀÀµ¶ÔÏó£¬È»ºóÔÙµ÷Óñ»ÒÀÀµ¶ÔÏóµÄ·½·¨¡£
+2. ¼òµ¥¹¤³§Ä£Ê½: µ÷ÓÃÕßÏÈÕÒµ½±»ÒÀÀµ¶ÔÏóµÄ¹¤³§£¬È»ºó**Ö÷¶¯**ͨ¹ý¹¤³§È¥»ñÈ¡±»ÒÀÀµ¶ÔÏó£¬×îºóÔÙµ÷Óñ»ÒÀÀµ¶ÔÏóµÄ·½·¨¡£
+
+×¢ÒâÉÏÃæµÄ**Ö÷¶¯**¶þ×Ö£¬Õâ±ØÈ»»áµ¼Öµ÷ÓÃÕßÓë±»ÒÀÀµ¶ÔÏóʵÏÖÀàµÄÓ²±àÂëñîºÏ£¬·Ç³£²»ÀûÓÚÏîÄ¿Éý¼¶µÄά»¤¡£Ê¹ÓÃSpring¿ò¼ÜÖ®ºó£¬µ÷ÓÃÕßÎÞÐè**Ö÷¶¯**»ñÈ¡±»ÒÀÀµ¶ÔÏ󣬵÷ÓÃÕßÖ»Òª**±»¶¯**½ÓÊÜSpringÈÝÆ÷Ϊµ÷ÓÃÕߵijÉÔ±±äÁ¿¸³Öµ¼´¿É£¬Óɴ˿ɼû£¬Ê¹ÓÃSpringºó£¬µ÷ÓÃÕß»ñÈ¡±»ÒÀÀµ¶ÔÏóµÄ·½Ê½ÓÉÔÀ´µÄÖ÷¶¯»ñÈ¡£¬±ä³ÉÁ˱»¶¯½ÓÊÜ¡ª¡ªËùÒÔRod Johnson³ÆÖ®Îª¿ØÖÆ·´×ª¡£
+
+ÁíÍâ´ÓSpringÈÝÆ÷µÄ½Ç¶ÈÀ´¿´£¬SpringÈÝÆ÷¸ºÔ𽫱»ÒÀÀµ¶ÔÏó¸³Öµ¸øµ÷ÓÃÕߵijÉÔ±±äÁ¿¡ª¡ªÏ൱ÓÚΪµ÷ÓÃÕß×¢ÈëËüÒÀÀµµÄʵÀý£¬Òò´ËMartine Fowler³ÆÖ®ÎªÒÀÀµ×¢Èë¡£
+
+#### ÉèÖµ×¢Èë
+
+ÉèÖµ×¢ÈëÊÇÖ¸IoCÈÝÆ÷ͨ¹ý³ÉÔ±±äÁ¿µÄsetter·½·¨À´×¢Èë±»ÒÀÀµ¶ÔÏó¡£ÕâÖÖ×¢È뷽ʽ¼òµ¥¡¢Ö±¹Û£¬Òò¶øÔÚSpringµÄÒÀÀµ×¢ÈëÀï´óÁ¿Ê¹Óá£
+
+#### ¹¹Ôì×¢Èë
+
+ÀûÓù¹ÔìÆ÷À´ÉèÖÃÒÀÀµ¹ØÏµµÄ·½Ê½£¬±»³ÆÎª¹¹Ôì×¢È롣ͨË×À´Ëµ£¬¾ÍÊÇÇý¶¯SpringÔڵײãÒÔ·´É䷽ʽִÐдøÖ¸¶¨²ÎÊýµÄ¹¹ÔìÆ÷£¬µ±Ö´Ðдø²ÎÊýµÄ¹¹ÔìÆ÷ʱ£¬¾Í¿ÉÀûÓù¹ÔìÆ÷²ÎÊý¶Ô³ÉÔ±±äÁ¿Ö´Ðгõʼ»¯¡ª¡ªÕâ¾ÍÊǹ¹Ôì×¢ÈëµÄ±¾ÖÊ¡£
+
+#### Á½ÖÖ×¢È뷽ʽµÄ¶Ô±È
+
+ÉèÖµ×¢ÈëÓÐÈçÏÂÓŵ㣺
+
+* Ó봫ͳµÄJavaBeanµÄд·¨¸üÏàËÆ£¬³ÌÐò¿ª·¢ÈËÔ±¸üÈÝÒ×Àí½â¡¢½ÓÊÜ¡£Í¨¹ýsetter·½·¨É趨ÒÀÀµ¹ØÏµÏԵøü¼ÓÖ±¹Û¡¢×ÔÈ»¡£
+* ¶ÔÓÚ¸´ÔÓµÄÒÀÀµ¹ØÏµ£¬Èç¹û²ÉÓù¹Ôì×¢È룬»áµ¼Ö¹¹ÔìÆ÷¹ýÓÚÓ·Ö×£¬ÄÑÒÔÔĶÁ¡£SpringÔÚ´´½¨BeanʵÀýʱ£¬ÐèҪͬʱʵÀý»¯ÆäÒÀÀµµÄÈ«²¿ÊµÀý£¬Òò¶øµ¼ÖÂÐÔÄÜϽµ¡£¶øÊ¹ÓÃÉèÖµ×¢È룬ÔòÄܱÜÃâÕâЩÎÊÌâ¡£
+* ÓÈÆäÔÚijЩ³ÉÔ±±äÁ¿¿ÉÑ¡µÄÇé¿öÏ£¬¶à²ÎÊýµÄ¹¹ÔìÆ÷¸ü¼Ó±¿ÖØ¡£
+
+¹¹Ôì×¢ÈëÓÅÊÆÈçÏ£º
+
+* ¹¹Ôì×¢Èë¿ÉÒÔÔÚ¹¹ÔìÆ÷Öоö¶¨ÒÀÀµ¹ØÏµµÄ×¢Èë˳Ðò£¬ÓÅÏÈÒÀÀµµÄÓÅÏÈ×¢Èë¡£
+* ¶ÔÓÚÒÀÀµ¹ØÏµÎÞÐè±ä»¯µÄBean£¬¹¹Ôì×¢Èë¸üÓÐÓô¦¡£ÒòΪûÓÐsetter·½·¨£¬ËùÓеÄÒÀÀµ¹ØÏµÈ«²¿ÔÚ¹¹ÔìÆ÷ÄÚÉ趨£¬ÎÞÐëµ£ÐĺóÐøµÄ´úÂë¶ÔÒÀÀµ¹ØÏµ²úÉúÆÆ»µ¡£
+* ÒÀÀµ¹ØÏµÖ»ÄÜÔÚ¹¹ÔìÆ÷ÖÐÉ趨£¬ÔòÖ»ÓÐ×é¼þµÄ´´½¨Õß²ÅÄܸıä×é¼þµÄÒÀÀµ¹ØÏµ£¬¶Ô×é¼þµÄµ÷ÓÃÕß¶øÑÔ£¬×é¼þÄÚ²¿µÄÒÀÀµ¹ØÏµÍêȫ͸Ã÷£¬¸ü·ûºÏ¸ßÄÚ¾ÛµÄÔÔò¡£
+
+**_×¢Ò⣺_**
+½¨Òé²ÉÓÃÉèÖµ×¢ÈëΪÖ÷£¬¹¹Ôì×¢ÈëΪ¸¨µÄ×¢Èë²ßÂÔ¡£¶ÔÓÚÒÀÀµ¹ØÏµÎÞÐë±ä»¯µÄ×¢È룬¾¡Á¿²ÉÓù¹Ôì×¢È룻¶øÆäËûÒÀÀµ¹ØÏµµÄ×¢È룬Ôò¿¼ÂDzÉÓÃÉèÖµ×¢Èë¡£
+
+### SpringÈÝÆ÷ÖеÄBean
+
+¶ÔÓÚ¿ª·¢ÕßÀ´Ëµ£¬¿ª·¢ÕßʹÓÃSpring¿ò¼ÜÖ÷ÒªÊÇ×öÁ½¼þÊ£º¢Ù¿ª·¢Bean£»¢ÚÅäÖÃBean¡£¶ÔÓÚSpring¿ò¼ÜÀ´Ëµ£¬ËüÒª×öµÄ¾ÍÊǸù¾ÝÅäÖÃÎļþÀ´´´½¨BeanʵÀý£¬²¢µ÷ÓÃBeanʵÀýµÄ·½·¨Íê³É"ÒÀÀµ×¢Èë"¡ª¡ªÕâ¾ÍÊÇËùνIoCµÄ±¾ÖÊ¡£
+
+#### ÈÝÆ÷ÖÐBeanµÄ×÷ÓÃÓò
+
+µ±Í¨¹ýSpringÈÝÆ÷´´½¨Ò»¸öBeanʵÀýʱ£¬²»½ö¿ÉÒÔÍê³ÉBeanʵÀýµÄʵÀý»¯£¬»¹¿ÉÒÔΪBeanÖ¸¶¨Ìض¨µÄ×÷ÓÃÓò¡£SpringÖ§³ÖÈçÏÂÎåÖÖ×÷ÓÃÓò£º
+
+1. singleton: µ¥Àýģʽ£¬ÔÚÕû¸öSpring IoCÈÝÆ÷ÖУ¬singleton×÷ÓÃÓòµÄBean½«Ö»Éú³ÉÒ»¸öʵÀý¡£
+2. prototype: ÿ´Îͨ¹ýÈÝÆ÷µÄgetBean()·½·¨»ñÈ¡prototype×÷ÓÃÓòµÄBeanʱ£¬¶¼½«²úÉúÒ»¸öеÄBeanʵÀý¡£
+3. request: ¶ÔÓÚÒ»´ÎHTTPÇëÇó£¬request×÷ÓÃÓòµÄBean½«Ö»Éú³ÉÒ»¸öʵÀý£¬ÕâÒâζ×Å£¬ÔÚͬһ´ÎHTTPÇëÇóÄÚ£¬³ÌÐòÿ´ÎÇëÇó¸ÃBean£¬µÃµ½µÄ×ÜÊÇͬһ¸öʵÀý¡£Ö»ÓÐÔÚWebÓ¦ÓÃÖÐʹÓÃSpringʱ£¬¸Ã×÷ÓÃÓò²ÅÕæÕýÓÐЧ¡£
+4. session£º¸Ã×÷ÓÃÓò½« bean µÄ¶¨ÒåÏÞÖÆÎª HTTP »á»°¡£ Ö»ÔÚweb-aware Spring ApplicationContextµÄÉÏÏÂÎÄÖÐÓÐЧ¡£
+5. global session: ÿ¸öÈ«¾ÖµÄHTTP Session¶ÔÓ¦Ò»¸öBeanʵÀý¡£ÔÚµäÐ͵ÄÇé¿öÏ£¬½öÔÚʹÓÃportlet contextµÄʱºòÓÐЧ£¬Í¬ÑùÖ»ÔÚWebÓ¦ÓÃÖÐÓÐЧ¡£
+
+Èç¹û²»Ö¸¶¨BeanµÄ×÷ÓÃÓò£¬SpringĬÈÏʹÓÃsingleton×÷ÓÃÓò¡£prototype×÷ÓÃÓòµÄBeanµÄ´´½¨¡¢Ïú»Ù´ú¼Û±È½Ï´ó¡£¶øsingleton×÷ÓÃÓòµÄBeanʵÀýÒ»µ©´´½¨³É¹û£¬¾Í¿ÉÒÔÖØ¸´Ê¹Óá£Òò´Ë£¬Ó¦¸Ã¾¡Á¿±ÜÃ⽫BeanÉèÖóÉprototype×÷ÓÃÓò¡£
+
+### ʹÓÃ×Ô¶¯×°Åä×¢ÈëºÏ×÷ÕßBean
+
+SpringÄÜ×Ô¶¯×°ÅäBeanÓëBeanÖ®¼äµÄÒÀÀµ¹ØÏµ£¬¼´ÎÞÐëʹÓÃrefÏÔʽָ¶¨ÒÀÀµBean£¬¶øÊÇÓÉSpringÈÝÆ÷¼ì²éXMLÅäÖÃÎļþÄÚÈÝ£¬¸ù¾ÝijÖÖ¹æÔò£¬Îªµ÷ÓÃÕßBean×¢Èë±»ÒÀÀµµÄBean¡£
+Spring×Ô¶¯×°Åä¿Éͨ¹ý` `ÔªËØµÄ`default-autowire`ÊôÐÔÖ¸¶¨£¬¸ÃÊôÐÔ¶ÔÅäÖÃÎļþÖÐËùÓеÄBeanÆð×÷Óã»Ò²¿Éͨ¹ý¶Ô` `ÔªËØµÄ`autowire`ÊôÐÔÖ¸¶¨£¬¸ÃÊôÐÔÖ»¶Ô¸ÃBeanÆð×÷Óá£
+
+`autowire`ºÍ`default-autowire`¿ÉÒÔ½ÓÊÜÈçÏÂÖµ£º
+
+* `no`: ²»Ê¹ÓÃ×Ô¶¯×°Åä¡£BeanÒÀÀµ±ØÐëͨ¹ýrefÔªËØ¶¨Òå¡£ÕâÊÇĬÈÏÅäÖã¬ÔڽϴóµÄ²¿Êð»·¾³Öв»¹ÄÀø¸Ä±äÕâ¸öÅäÖã¬ÏÔʽÅäÖúÏ×÷ÕßÄܹ»µÃµ½¸üÇåÎúµÄÒÀÀµ¹ØÏµ¡£
+* `byName`: ¸ù¾Ýsetter·½·¨Ãû½øÐÐ×Ô¶¯×°Åä¡£SpringÈÝÆ÷²éÕÒÈÝÆ÷ÖÐÈ«²¿Bean£¬ÕÒ³öÆäidÓësetter·½·¨ÃûÈ¥µôsetǰ׺£¬²¢Ð¡Ð´Ê××ÖĸºóͬÃûµÄBeanÀ´Íê³É×¢Èë¡£Èç¹ûûÓÐÕÒµ½Æ¥ÅäµÄBeanʵÀý£¬ÔòSpring²»»á½øÐÐÈκÎ×¢Èë¡£
+* `byType`: ¸ù¾Ýsetter·½·¨µÄÐβÎÀàÐÍÀ´×Ô¶¯×°Åä¡£SpringÈÝÆ÷²éÕÒÈÝÆ÷ÖеÄÈ«²¿Bean£¬Èç¹ûÕýºÃÓÐÒ»¸öBeanÀàÐÍÓësetter·½·¨µÄÐβÎÀàÐÍÆ¥Å䣬¾Í×Ô¶¯×¢ÈëÕâ¸öBean£»Èç¹ûÕÒµ½¶à¸öÕâÑùµÄBean£¬¾ÍÅ׳öÒ»¸öÒì³££»Èç¹ûûÓÐÕÒµ½ÕâÑùµÄBean£¬Ôòʲô¶¼²»»á·¢Éú£¬setter·½·¨²»»á±»µ÷Óá£
+* `constructor`: ÓëbyTypeÀàËÆ£¬Çø±ðÊÇÓÃÓÚ×Ô¶¯Æ¥Åä¹¹ÔìÆ÷µÄ²ÎÊý¡£Èç¹ûÈÝÆ÷²»ÄÜÇ¡ºÃÕÒµ½Ò»¸öÓë¹¹ÔìÆ÷²ÎÊýÀàÐÍÆ¥ÅäµÄBean£¬Ôò»áÅ׳öÒ»¸öÒì³£¡£
+* `autodetect`: SpringÈÝÆ÷¸ù¾ÝBeanÄÚ²¿½á¹¹£¬×ÔÐоö¶¨Ê¹ÓÃconstructor»òbyType²ßÂÔ¡£Èç¹ûÕÒµ½Ò»¸öĬÈϵĹ¹Ô캯Êý£¬ÄÇô¾Í»áÓ¦ÓÃbyType²ßÂÔ¡£
+
+**µ±Ò»¸öBean¼ÈʹÓÃ×Ô¶¯×°ÅäÒÀÀµ£¬ÓÖʹÓÃrefÏÔʽָ¶¨ÒÀÀµÊ±£¬ÔòÏÔʽָ¶¨µÄÒÀÀµ¸²¸Ç×Ô¶¯×°ÅäÒÀÀµ£»¶ÔÓÚ´óÐ͵ÄÓ¦Ó㬲»¹ÄÀøÊ¹ÓÃ×Ô¶¯×°Åä¡£ËäȻʹÓÃ×Ô¶¯×°Åä¿É¼õÉÙÅäÖÃÎļþµÄ¹¤×÷Á¿£¬µ«´ó´ó½«ËÀÁËÒÀÀµ¹ØÏµµÄÇåÎúÐÔºÍ͸Ã÷ÐÔ¡£ÒÀÀµ¹ØÏµµÄ×°ÅäÒÀÀµÓÚÔ´ÎļþµÄÊôÐÔÃûºÍÊôÐÔÀàÐÍ£¬µ¼ÖÂBeanÓëBeanÖ®¼äµÄñîºÏ½µµÍµ½´úÂë²ã´Î£¬²»ÀûÓڸ߲ã´Î½âñî¡£**
+
+
+
+## ´´½¨BeanµÄ3ÖÖ·½Ê½
+
+### ʹÓù¹ÔìÆ÷´´½¨BeanʵÀý
+
+ʹÓù¹ÔìÆ÷À´´´½¨BeanʵÀýÊÇ×î³£¼ûµÄÇé¿ö£¬Èç¹û²»²ÉÓù¹Ôì×¢È룬Springµ×²ã»áµ÷ÓÃBeanÀàµÄÎÞ²ÎÊý¹¹ÔìÆ÷À´´´½¨ÊµÀý£¬Òò´ËÒªÇó¸ÃBeanÀàÌṩÎÞ²ÎÊýµÄ¹¹ÔìÆ÷¡£
+
+²ÉÓÃĬÈϵĹ¹ÔìÆ÷´´½¨BeanʵÀý£¬Spring¶ÔBeanʵÀýµÄËùÓÐÊôÐÔÖ´ÐÐĬÈϳõʼ»¯£¬¼´ËùÓеĻù±¾ÀàÐ͵ÄÖµ³õʼ»¯Îª0»òfalse£»ËùÓеÄÒýÓÃÀàÐ͵ÄÖµ³õʼ»¯Îªnull¡£
+
+### ʹÓþ²Ì¬¹¤³§·½·¨´´½¨Bean
+
+ʹÓþ²Ì¬¹¤³§·½·¨´´½¨BeanʵÀýʱ£¬classÊôÐÔÒ²±ØÐëÖ¸¶¨£¬µ«´ËʱclassÊôÐÔ²¢²»ÊÇÖ¸¶¨BeanʵÀýµÄʵÏÖÀ࣬¶øÊǾ²Ì¬¹¤³§À࣬Springͨ¹ý¸ÃÊôÐÔÖªµÀÓÉÄĸö¹¤³§ÀàÀ´´´½¨BeanʵÀý¡£
+
+³ý´ËÖ®Í⣬»¹ÐèҪʹÓÃfactory-methodÊôÐÔÀ´Ö¸¶¨¾²Ì¬¹¤³§·½·¨£¬Spring½«µ÷Óþ²Ì¬¹¤³§·½·¨·µ»ØÒ»¸öBeanʵÀý£¬Ò»µ©»ñµÃÁËÖ¸¶¨BeanʵÀý£¬SpringºóÃæµÄ´¦Àí²½ÖèÓë²ÉÓÃÆÕͨ·½·¨´´½¨BeanʵÀýÍêȫһÑù¡£Èç¹û¾²Ì¬¹¤³§·½·¨ÐèÒª²ÎÊý£¬ÔòʹÓÃ` `ÔªËØÖ¸¶¨¾²Ì¬¹¤³§·½·¨µÄ²ÎÊý¡£
+
+### µ÷ÓÃʵÀý¹¤³§·½·¨´´½¨Bean
+
+ʵÀý¹¤³§·½·¨Ó뾲̬¹¤³§·½·¨Ö»ÓÐÒ»¸ö²»Í¬£ºµ÷Óþ²Ì¬¹¤³§·½·¨Ö»ÐèʹÓù¤³§À༴¿É£¬¶øµ÷ÓÃʵÀý¹¤³§·½·¨ÔòÐèÒª¹¤³§ÊµÀý¡£Ê¹ÓÃʵÀý¹¤³§·½·¨Ê±£¬ÅäÖÃBeanʵÀýµÄ` `ÔªËØÎÞÐëclassÊôÐÔ£¬ÅäÖÃʵÀý¹¤³§·½·¨Ê¹ÓÃ`factory-bean`Ö¸¶¨¹¤³§ÊµÀý¡£
+²ÉÓÃʵÀý¹¤³§·½·¨´´½¨BeanµÄ` `ÔªËØÊ±ÐèÒªÖ¸¶¨ÈçÏÂÁ½¸öÊôÐÔ£º
+
+* factory-bean: ¸ÃÊôÐÔµÄֵΪ¹¤³§BeanµÄid¡£
+* factory-method: ¸ÃÊôÐÔÖ¸¶¨ÊµÀý¹¤³§µÄ¹¤³§·½·¨¡£
+
+Èôµ÷ÓÃʵÀý¹¤³§·½·¨Ê±ÐèÒª´«Èë²ÎÊý£¬ÔòʹÓÃ` `ÔªËØÈ·¶¨²ÎÊýÖµ¡£
+
+## е÷×÷ÓÃÓò²»Í¬²½µÄBean
+
+µ±singleton×÷ÓÃÓòµÄBeanÒÀÀµÓÚprototype×÷ÓÃÓòµÄBeanʱ£¬»á²úÉú²»Í¬²½µÄÏÖÏó£¬ÔÒòÊÇÒòΪµ±SpringÈÝÆ÷³õʼ»¯Ê±£¬ÈÝÆ÷»áÔ¤³õʼ»¯ÈÝÆ÷ÖÐËùÓеÄ`singleton Bean`£¬ÓÉÓÚ`singleton Bean`ÒÀÀµÓÚ`prototype Bean`£¬Òò´ËSpringÔÚ³õʼ»¯`singleton Bean`֮ǰ£¬»áÏÈ´´½¨`prototypeBean`¡ª¡ªÈ»ºó²Å´´½¨`singleton Bean`£¬½ÓÏÂÀォ`prototype Bean`×¢Èë`singleton Bean`¡£
+½â¾ö²»Í¬²½µÄ·½·¨ÓÐÁ½ÖÖ£º
+
+* ·ÅÆúÒÀÀµ×¢Èë: singleton×÷ÓÃÓòµÄBeanÿ´ÎÐèÒªprototype×÷ÓÃÓòµÄBeanʱ£¬Ö÷¶¯ÏòÈÝÆ÷ÇëÇóеÄBeanʵÀý£¬¼´¿É±£Ö¤Ã¿´Î×¢ÈëµÄ`prototype Bean`ʵÀý¶¼ÊÇ×îеÄʵÀý¡£
+* ÀûÓ÷½·¨×¢Èë: ·½·¨×¢Èëͨ³£Ê¹ÓÃlookup·½·¨×¢È룬ʹÓÃlookup·½·¨×¢Èë¿ÉÒÔÈÃSpringÈÝÆ÷ÖØÐ´ÈÝÆ÷ÖÐBeanµÄ³éÏó»ò¾ßÌå·½·¨£¬·µ»Ø²éÕÒÈÝÆ÷ÖÐÆäËûBeanµÄ½á¹û£¬±»²éÕÒµÄBeanͨ³£ÊÇÒ»¸ö`non-singleton Bean`¡£Springͨ¹ýʹÓÃJDK¶¯Ì¬´úÀí»òcglib¿âÐ޸Ŀͻ§¶ËµÄ¶þ½øÖÆÂ룬´Ó¶øÊµÏÖÉÏÊöÒªÇó¡£
+
+½¨Òé²ÉÓõڶþÖÖ·½·¨£¬Ê¹Ó÷½·¨×¢È롣ΪÁËʹÓÃlookup·½·¨×¢È룬´óÖÂÐèÒªÈçÏÂÁ½²½£º
+
+1. ½«µ÷ÓÃÕßBeanµÄʵÏÖÀඨÒåΪ³éÏóÀ࣬²¢¶¨ÒåÒ»¸ö³éÏó·½·¨À´»ñÈ¡±»ÒÀÀµµÄBean¡£
+2. ÔÚ` `ÔªËØÖÐÌí¼Ó` `×ÓÔªËØÈÃSpringΪµ÷ÓÃÕßBeanµÄʵÏÖÀàʵÏÖÖ¸¶¨µÄ³éÏó·½·¨¡£
+
+**_×¢Ò⣺_**
+
+> Spring»á²ÉÓÃÔËÐÐʱ¶¯Ì¬ÔöÇ¿µÄ·½Ê½À´ÊµÏÖ` `ÔªËØËùÖ¸¶¨µÄ³éÏó·½·¨£¬Èç¹ûÄ¿±ê³éÏóÀàʵÏÖ¹ý½Ó¿Ú£¬Spring»á²ÉÓÃJDK¶¯Ì¬´úÀíÀ´ÊµÏָóéÏóÀ࣬²¢ÎªÖ®ÊµÏÖ³éÏó·½·¨£»Èç¹ûÄ¿±ê³éÏóÀàûÓÐʵÏÖ¹ý½Ó¿Ú£¬Spring»á²ÉÓÃcglibʵÏָóéÏóÀ࣬²¢ÎªÖ®ÊµÏÖ³éÏó·½·¨¡£Spring4.0µÄspring-core-xxx.jar°üÖÐÒѾ¼¯³ÉÁËcglibÀà¿â¡£
+
+## Á½ÖÖºó´¦ÀíÆ÷
+
+SpringÌṩÁËÁ½ÖÖ³£Óõĺó´¦ÀíÆ÷£º
+
+* Beanºó´¦ÀíÆ÷: ÕâÖÖºó´¦ÀíÆ÷»á¶ÔÈÝÆ÷ÖÐBean½øÐкó´¦Àí£¬¶ÔBean½øÐжîÍâ¼ÓÇ¿¡£
+* ÈÝÆ÷ºó´¦ÀíÆ÷: ÕâÖÖºó´¦ÀíÆ÷»á¶ÔIoCÈÝÆ÷½øÐкó´¦Àí£¬ÓÃÓÚÔöÇ¿ÈÝÆ÷¹¦ÄÜ¡£
+
+### Beanºó´¦ÀíÆ÷
+
+Beanºó´¦ÀíÆ÷ÊÇÒ»ÖÖÌØÊâµÄBean£¬ÕâÖÖÌØÊâµÄBean²¢²»¶ÔÍâÌṩ·þÎñ£¬ËüÉõÖÁ¿ÉÒÔÎÞÐëidÊôÐÔ£¬ËüÖ÷Òª¸ºÔð¶ÔÈÝÆ÷ÖÐµÄÆäËûBeanÖ´Ðкó´¦Àí£¬ÀýÈçΪÈÝÆ÷ÖеÄÄ¿±êBeanÉú³É´úÀíµÈ£¬ÕâÖÖBean³ÆÎªBeanºó´¦ÀíÆ÷¡£Beanºó´¦ÀíÆ÷»áÔÚBeanʵÀý´´½¨³É¹¦Ö®ºó£¬¶ÔBeanʵÀý½øÐнøÒ»²½µÄÔöÇ¿´¦Àí¡£Beanºó´¦ÀíÆ÷±ØÐëʵÏÖ`BeanPostProcessor`½Ó¿Ú£¬Í¬Ê±±ØÐëʵÏָýӿڵÄÁ½¸ö·½·¨¡£
+
+1. `Object postProcessBeforeInitialization(Object bean, String name) throws BeansException`: ¸Ã·½·¨µÄµÚÒ»¸ö²ÎÊýÊÇϵͳ¼´½«½øÐкó´¦ÀíµÄBeanʵÀý£¬µÚ¶þ¸ö²ÎÊýÊǸÃBeanµÄÅäÖÃid
+2. `Object postProcessAfterinitialization(Object bean, String name) throws BeansException`: ¸Ã·½·¨µÄµÚÒ»¸ö²ÎÊýÊÇϵͳ¼´½«½øÐкó´¦ÀíµÄBeanʵÀý£¬µÚ¶þ¸ö²ÎÊýÊǸÃBeanµÄÅäÖÃid
+
+ÈÝÆ÷ÖÐÒ»µ©×¢²áÁËBeanºó´¦ÀíÆ÷£¬Beanºó´¦ÀíÆ÷¾Í»á×Ô¶¯Æô¶¯£¬ÔÚÈÝÆ÷ÖÐÿ¸öBean´´½¨Ê±×Ô¶¯¹¤×÷£¬Beanºó´¦ÀíÆ÷Á½¸ö·½·¨µÄ»Øµ÷ʱ»úÈçÏÂͼ£º
+
+
+
+×¢ÒâÒ»µã£¬Èç¹ûʹÓÃ`BeanFactory`×÷ΪSpringÈÝÆ÷£¬Ôò±ØÐëÊÖ¶¯×¢²áBeanºó´¦ÀíÆ÷£¬³ÌÐò±ØÐë»ñÈ¡Beanºó´¦ÀíÆ÷ʵÀý£¬È»ºóÊÖ¶¯×¢²á¡£
+
+ BeanPostProcessor bp = (BeanPostProcessor)beanFactory.getBean("bp"); beanFactory.addBeanPostProcessor(bp); Person p = (Person)beanFactory.getBean("person");
+
+### ÈÝÆ÷ºó´¦ÀíÆ÷
+
+Beanºó´¦ÀíÆ÷¸ºÔð´¦ÀíÈÝÆ÷ÖеÄËùÓÐBeanʵÀý£¬¶øÈÝÆ÷ºó´¦ÀíÆ÷Ôò¸ºÔð´¦ÀíÈÝÆ÷±¾Éí¡£ÈÝÆ÷ºó´¦ÀíÆ÷±ØÐëʵÏÖ`BeanFactoryPostProcessor`½Ó¿Ú£¬²¢ÊµÏָýӿڵÄÒ»¸ö·½·¨`postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)`ʵÏָ÷½·¨µÄ·½·¨Ìå¾ÍÊǶÔSpringÈÝÆ÷½øÐеĴ¦Àí£¬ÕâÖÖ´¦Àí¿ÉÒÔ¶ÔSpringÈÝÆ÷½øÐÐ×Ô¶¨ÒåÀ©Õ¹£¬µ±È»Ò²¿ÉÒÔ¶ÔSpringÈÝÆ÷²»½øÐÐÈκδ¦Àí¡£
+
+ÀàËÆÓÚ`BeanPostProcessor`£¬`ApplicationContext`¿É×Ô¶¯¼ì²âµ½ÈÝÆ÷ÖеÄÈÝÆ÷ºó´¦ÀíÆ÷£¬²¢ÇÒ×Ô¶¯×¢²áÈÝÆ÷ºó´¦ÀíÆ÷¡£µ«ÈôʹÓÃ`BeanFactory`×÷ΪSpringÈÝÆ÷£¬Ôò±ØÐëÊÖ¶¯µ÷ÓøÃÈÝÆ÷ºó´¦ÀíÆ÷À´´¦Àí`BeanFactory`ÈÝÆ÷¡£
+
+## SpringµÄ"ÁãÅäÖÃ"Ö§³Ö
+
+### ËÑË÷BeanÀà
+
+SpringÌṩÈçϼ¸¸öAnnotationÀ´±ê×¢Spring Bean£º
+
+* `@Component`: ±ê×¢Ò»¸öÆÕͨµÄSpring BeanÀà
+* `@Controller`: ±ê×¢Ò»¸ö¿ØÖÆÆ÷×é¼þÀà
+* `@Service`: ±ê×¢Ò»¸öÒµÎñÂß¼×é¼þÀà
+* `@Repository`: ±ê×¢Ò»¸öDAO×é¼þÀà
+
+ÔÚSpringÅäÖÃÎļþÖÐ×öÈçÏÂÅäÖã¬Ö¸¶¨×Ô¶¯É¨ÃèµÄ°ü£º
+
+
+
+### ʹÓÃ@ResourceÅäÖÃÒÀÀµ
+
+`@Resource`λÓÚ`javax.annotation`°üÏ£¬ÊÇÀ´×ÔJavaEE¹æ·¶µÄÒ»¸ö`Annotation`£¬SpringÖ±½Ó½è¼øÁ˸Ã`Annotation`£¬Í¨¹ýʹÓøÃ`Annotation`ΪĿ±êBeanÖ¸¶¨Ð×÷ÕßBean¡£Ê¹ÓÃ`@Resource`Óë` `ÔªËØµÄrefÊôÐÔÓÐÏàͬµÄЧ¹û¡£
+`@Resource`²»½ö¿ÉÒÔÐÞÊÎsetter·½·¨£¬Ò²¿ÉÒÔÖ±½ÓÐÞÊÎʵÀý±äÁ¿£¬Èç¹ûʹÓÃ`@Resource`ÐÞÊÎʵÀý±äÁ¿½«»á¸ü¼Ó¼òµ¥£¬´ËʱSpring½«»áÖ±½ÓʹÓÃJavaEE¹æ·¶µÄField×¢È룬´ËʱÁ¬setter·½·¨¶¼¿ÉÒÔ²»Òª¡£
+
+### ʹÓÃ@PostConstructºÍ@PreDestroy¶¨ÖÆÉúÃüÖÜÆÚÐÐΪ
+
+`@PostConstruct`ºÍ`@PreDestroy`ͬÑùλÓÚjavax.annotation°üÏ£¬Ò²ÊÇÀ´×ÔJavaEE¹æ·¶µÄÁ½¸öAnnotation£¬SpringÖ±½Ó½è¼øÁËËüÃÇ£¬ÓÃÓÚ¶¨ÖÆSpringÈÝÆ÷ÖÐBeanµÄÉúÃüÖÜÆÚÐÐΪ¡£ËüÃǶ¼ÓÃÓÚÐÞÊη½·¨£¬ÎÞÐëÈκÎÊôÐÔ¡£ÆäÖÐǰÕßÐÞÊεķ½·¨Ê±BeanµÄ³õʼ»¯·½·¨£»¶øºóÕßÐÞÊεķ½·¨Ê±BeanÏú»Ù֮ǰµÄ·½·¨¡£
+
+### Spring4.0ÔöÇ¿µÄ×Ô¶¯×°ÅäºÍ¾«È·×°Åä
+
+SpringÌṩÁË`@Autowired`×¢½âÀ´Ö¸¶¨×Ô¶¯×°Å䣬`@Autowired`¿ÉÒÔÐÞÊÎsetter·½·¨¡¢ÆÕͨ·½·¨¡¢ÊµÀý±äÁ¿ºÍ¹¹ÔìÆ÷µÈ¡£µ±Ê¹ÓÃ`@Autowired`±ê×¢setter·½·¨Ê±£¬Ä¬ÈϲÉÓÃbyType×Ô¶¯×°Åä²ßÂÔ¡£ÔÚÕâÖÖ²ßÂÔÏ£¬·ûºÏ×Ô¶¯×°ÅäÀàÐ͵ĺòÑ¡BeanʵÀý³£³£Óжà¸ö£¬Õâ¸öʱºò¾Í¿ÉÄÜÒýÆðÒì³££¬ÎªÁËʵÏÖ¾«È·µÄ×Ô¶¯×°Å䣬SpringÌṩÁË`@Qualifier`×¢½â£¬Í¨¹ýʹÓÃ`@Qualifier`£¬ÔÊÐí¸ù¾ÝBeanµÄidÀ´Ö´ÐÐ×Ô¶¯×°Åä¡£
+
+# ²Î¿¼ÎÄÕÂ
+https://www.w3cschool.cn/wkspring
+https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
+http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
+https://dunwu.github.io/spring-tutorial
+https://mszlu.com/java/spring
+http://c.biancheng.net/spring/aop-module.html
\ No newline at end of file
diff --git "a/docs/spring/SpringBoot/SpringBoot\345\270\270\350\247\201\346\263\250\350\247\243.md" "b/docs/spring/SpringBoot/SpringBoot\345\270\270\350\247\201\346\263\250\350\247\243.md"
new file mode 100644
index 0000000..c699974
--- /dev/null
+++ "b/docs/spring/SpringBoot/SpringBoot\345\270\270\350\247\201\346\263\250\350\247\243.md"
@@ -0,0 +1,158 @@
+## 1 ¸ÅÊö
+Spring Boot ͨ¹ýÆä×Ô¶¯ÅäÖù¦ÄÜʹÅäÖà Spring ±äµÃ¸ü¼ÓÈÝÒס£
+
+ÔÚ±¾¿ìËٽ̳ÌÖУ¬ÎÒÃǽ«Ì½Ë÷ org.springframework.boot.autoconfigure ºÍ org.springframework.boot.autoconfigure.condition °üÖеÄ×¢½â¡£
+
+## 2 @SpringBootApplication
+ÎÒÃÇʹÓÃÕâ¸ö×¢½âÀ´±ê¼Ç Spring Boot Ó¦ÓóÌÐòµÄÖ÷Àࣺ
+
+@SpringBootApplication
+ÎÒÃÇʹÓÃÕâ¸ö×¢½âÀ´±ê¼Ç Spring Boot Ó¦ÓóÌÐòµÄÖ÷Àࣺ
+````
+@SpringBootApplication
+class VehicleFactoryApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(VehicleFactoryApplication.class, args);
+ }
+}
+````
+@SpringBootApplication ·â×°ÁË@Configuration¡¢@EnableAutoConfiguration ºÍ@ComponentScan ×¢½â¼°ÆäĬÈÏÊôÐÔ¡£
+
+## 3 @EnableAutoConfiguration
+
+@EnableAutoConfiguration£¬¹ËÃû˼Ò壬ÆôÓÃ×Ô¶¯ÅäÖᣠÕâÒâζ×Å Spring Boot ÔÚÆäÀà·¾¶ÖвéÕÒ×Ô¶¯ÅäÖà bean ²¢×Ô¶¯Ó¦ÓÃËüÃÇ¡£
+
+Çë×¢Ò⣬ÎÒÃDZØÐ뽫´Ë×¢ÊÍÓë@Configuration Ò»ÆðʹÓãº
+
+````
+@Configuration
+@EnableAutoConfiguration
+class VehicleFactoryConfig {}
+````
+
+## 4 @ConfigurationÒÔ¼°Ïà¹ØÀà
+
+@ConfigurationµÄ×÷Ó㺱ê×¢ÔÚÀàÉÏ£¬ÅäÖÃspringÈÝÆ÷(Ó¦ÓÃÉÏÏÂÎÄ)¡£
+
+ÒÔÍùÎÒÃÇÔÚspringÖÐÅäÖÃbean»áʹÓõ½xmlÅäÖÃÎļþ£¬¶¨ÒåÒ»¸ö¸öbean£¬ÔÚspringbootÖУ¬ÎªÁË×öµ½ÁãÅäÖã¬spring¿ò¼ÜÌṩÁË@ConfigurationÕâÒ»×¢½â
+
+Ï൱ÓڰѸÃÀà×÷ΪspringµÄxmlÅäÖÃÎļþÖеÄ
+
+@Configuration×¢½âµÄÀàÖУ¬Ê¹ÓÃ@Bean×¢½â±ê×¢µÄ·½·¨£¬·µ»ØµÄÀàÐͶ¼»áÖ±½Ó×¢²áΪbean¡£
+
+@Configure×¢½âµÄ¶¨ÒåÈçÏ£º
+````
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Component
+public @interface Configuration {
+String value() default "";
+}
+````
+´Ó¶¨ÒåÀ´¿´£¬µ×²ãÊǺ¬ÓÐ@Component £¬ËùÒÔ@Configuration ¾ßÓÐºÍ @Component µÄ×÷Óá£Òò´Ëcontext:component-scan/»òÕß@ComponentScan¶¼ÄÜ´¦Àí@Configuration×¢½âµÄÀà¡£
+
+ͨ³££¬µ±ÎÒÃDZàд×Ô¶¨Òå×Ô¶¯ÅäÖÃʱ£¬ÎÒÃÇÏ£Íû Spring ÓÐÌõ¼þµØÊ¹ÓÃËüÃÇ¡£ ÎÒÃÇ¿ÉÒÔͨ¹ý±¾½ÚÖеÄ×¢ÊÍÀ´ÊµÏÖÕâÒ»µã¡£
+
+ÎÒÃÇ¿ÉÒÔ½«´Ë²¿·ÖÖеÄ×¢ÊÍ·ÅÔÚ@Configuration Àà»ò@Bean ·½·¨ÉÏ¡£
+
+ÔÚ½ÓÏÂÀ´µÄ²¿·ÖÖУ¬ÎÒÃǽ«Ö»½éÉÜÿ¸öÌõ¼þ±³ºóµÄ»ù±¾¸ÅÄî¡£ ÓûÁ˽â¸ü¶àÐÅÏ¢£¬Çë·ÃÎÊÕâÆªÎÄÕ¡£
+
+### 4.1 @ConditionalOnClass and @ConditionalOnMissingClass
+ºÜÃ÷ÏÔÕâÊÇÒ»¸ö´øÓÐÌõ¼þÅжϵÄÅäÖÃ×¢½â£¬ÒªÖªµÀ£¬ºÜ¶àʱºòÎÒÃǰ´Ðè¼ÓÔØbeanµÄ£¬ÉõÖÁÊǸù¾ÝÍⲿjar°üÊÇ·ñ´æÔÚÀ´½øÐмÓÔØºÍÅжϵġ£
+
+ÕâÖÖʱºò£¬¾ÍÒª¸ù¾ÝÍⲿÀàÊÇ·ñ´æÔÚÀ´¾ö¶¨ÊÇ·ñÊÇ·ñ¼ÓÔØ¸Ãbean
+
+ʹÓÃÕâЩÌõ¼þ£¬Èç¹û×¢ÊͲÎÊýÖеÄÀà´æÔÚ/²»´æÔÚ£¬Spring ½«½öʹÓñê¼ÇµÄ×Ô¶¯ÅäÖà bean£º
+
+````
+@Configuration
+@ConditionalOnClass(DataSource.class)
+class MySQLAutoconfiguration {
+//...
+}
+````
+
+### 4.2 @ConditionalOnBean and @ConditionalOnMissingBean
+
+µ±ÎÒÃÇÏëÒª¸ù¾ÝÌØ¶¨ bean µÄ´æÔÚ»ò²»´æÔÚÀ´¶¨ÒåÌõ¼þʱ£¬ÎÒÃÇ¿ÉÒÔʹÓÃÕâЩעÊÍ£º
+
+ºÍÉÏÃæÒ»¸ö×¢½âÉÔÓÐЩ²»Í¬£¬ÒòΪÎÒÃǵÄÅжÏÌõ¼þ±ä³ÉÁËbean
+
+````
+@Bean
+@ConditionalOnBean(name = "dataSource")
+LocalContainerEntityManagerFactoryBean entityManagerFactory() {
+// ...
+}
+````
+### 4.3 @ConditionalOnProperty
+ͨ¹ýÕâ¸ö×¢½â£¬ÎÒÃÇ¿ÉÒÔ¶ÔÊôÐÔµÄÖµÉèÖÃÌõ¼þ
+
+ҪעÒ⣬ÕâÀïµÄÊôÐÔÖµÀ´Ô´ÓÚapplication.propertiesÎļþÖеÄÅäÖÃ
+
+````
+@Bean
+@ConditionalOnProperty(
+name = "usemysql",
+havingValue = "local"
+)
+DataSource dataSource() {
+// ...
+}
+````
+
+### 4.4 @ConditionalOnResource
+
+ÎÒÃÇ¿ÉÒÔÈà Spring ½öÔÚ´æÔÚÌØ¶¨×ÊԴʱʹÓö¨Ò壺
+¹ËÃû˼Ò壬ҪÇóclasspath´æÔÚÕâ¸ö×ÊÔ´Îļþʱ²Å½øÐмÓÔØ£¬ÕâÒ²ÊǺܳ£ÓõÄÒ»¸ö×¢½â¡£
+
+````
+
+@ConditionalOnResource(resources = "classpath:mysql.properties")
+Properties ditionalProperties() {
+// ...
+}
+````
+
+### 4.5 @ConditionalOnWebApplication and @ConditionalOnNotWebApplication
+Õâ¸ö×¢½âͨ³£ÓÃÓÚºÍwebÓÐÇ¿¹ØÁª£¬»òÕßÍêÈ«ÎÞ¹ØÁªµÄÅäÖÃÉÏ
+
+ʹÓÃÕâЩעÊÍ£¬ÎÒÃÇ¿ÉÒÔ¸ù¾Ýµ±Ç°Ó¦ÓóÌÐòÊÇ·ñÊÇ Web Ó¦ÓóÌÐòÀ´´´½¨Ìõ¼þ£º
+````
+
+@ConditionalOnWebApplication
+HealthCheckController healthCheckController() {
+// ...
+}
+````
+
+### 4.6 @ConditionalExpression
+springbootÕæµÄΪÎÒÃÇÏëµ½ÁËËùÓÐÇé¿ö£¬Èç¹ûÉÏÃæµÄ×¢½â»¹²»ÄÜÂú×ãÄãµÄÒªÇó£¬ÄÇô¸É´à¾ÍÈÃÄã×Ô¼ºÐ´£¬ÕâÏÂÓ¦¸ÃûÓÐÎÊÌâ°É£¿
+
+ÎÒÃÇ¿ÉÒÔÔÚ¸ü¸´ÔÓµÄÇé¿öÏÂʹÓÃÕâ¸ö×¢½â¡£ µ± SpEL ±í´ïʽ±»ÆÀ¹ÀÎªÕæÊ±£¬Spring ½«Ê¹Óñê¼ÇµÄ¶¨Ò壺
+
+````
+@Bean
+@ConditionalOnExpression("${usemysql} && ${mysqlserver == 'local'}")
+DataSource dataSource() {
+// ...
+}
+````
+
+### 4.7 @Conditional
+ʲô£¬»¹ÓÐÎÊÌ⣿
+ÄÇspringbootÒ²²»ÔÙÌṩʲô±í´ïʽ¸øÄãÁË£¬Ö±½ÓÈÃÓû§Ð´Ò»¸öÅжÏÌõ¼þ£¬¸æËßÎÒtrue»òÕßfalse¾ÍÐÐÁË
+
+¶ÔÓÚ¸ü¸´ÔÓµÄÌõ¼þ£¬ÎÒÃÇ¿ÉÒÔ´´½¨Ò»¸öÆÀ¹À×Ô¶¨ÒåÌõ¼þµÄÀà¡£ ÎÒÃǸæËß Spring ½«Õâ¸ö×Ô¶¨ÒåÌõ¼þÓë @Conditional Ò»ÆðʹÓãº
+
+````
+@Conditional(HibernateCondition.class)
+Properties ditionalProperties() {
+//...
+}
+````
+
+## 5 ×ܽá
+ÔÚ±¾ÎÄÖУ¬ÎÒÃǸÅÊöÁËÈçºÎ΢µ÷×Ô¶¯ÅäÖùý³Ì²¢Îª×Ô¶¨Òå×Ô¶¯ÅäÖà bean ÌṩÌõ¼þ¡£
\ No newline at end of file
diff --git "a/docs/spring/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md" "b/docs/spring/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md"
new file mode 100644
index 0000000..36a2500
--- /dev/null
+++ "b/docs/spring/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md"
@@ -0,0 +1,152 @@
+# ¿ìËÙ¹¹½¨SpringBootÓ¦ÓÃ
+
+Õâ¸ö½Ì³ÌÀ´×ÔÓÚspringboot¹ÙÍø£¬×㹻ȨÍþ£¬Ò²×ã¹»¼òµ¥¡£
+
+## µÚÒ»¸ö hello world ³ÌÐò
+
+Äú½«¹¹½¨Ò»¸ö¾µäµÄ¡°Hello World£¡¡±ÈκÎä¯ÀÀÆ÷¶¼¿ÉÒÔÁ¬½Óµ½µÄ¶Ëµã¡£ÄãÉõÖÁ¿ÉÒÔ¸æËßËüÄãµÄÃû×Ö£¬Ëü»áÒÔ¸üÓѺõķ½Ê½»ØÓ¦¡£
+
+## »ù±¾»·¾³ÒªÇó
+
+1¡¢Ê×ÏÈÄã×îºÃÓÐÒ»¸ö³ÃÊÖµÄIDE,ÈÈÃÅÑ¡Ôñ°üÀ¨ IntelliJ IDEA¡¢Spring Tools¡¢Visual Studio Code »ò Eclipse µÈµÈ¡£
+
+2¡¢JDK£¬ÖÁÓÚ°æ±¾µÄ»°£¬8-17¶¼ÊDz»´íµÄÑ¡Ôñ
+
+3¡¢µ±È»ÕâÀﻹÐèÒªµ¼ÈëmavenµÄpomÒÀÀµ£¬ËùÒÔÎÒÃÇÒ²ÐèÒªmaven£¬maven²å¼þÔÚidea×Ô´øÁË¡£ÎÒÃÇ»áÔÚ½ÓÏÂÀ´µÄ²¿·Ö½øÐнéÉÜ£¬ÐèÒªÒýÈëÄÄЩÒÀÀµ
+
+## µÚÒ»²½£ºÆô¶¯Ò»¸öеÄSpring BootÏîÄ¿
+
+ʹÓÃ[start.spring.io](http://start.spring.io/)´´½¨Ò»¸ö¡°web¡±ÏîÄ¿¡£ÔÚ¡°dependencies¡±¶Ô»°¿òÖÐËÑË÷²¢Ìí¼Ó¡°web¡±ÒÀÀµÏÈçÆÁÄ»½ØÍ¼Ëùʾ¡£
+
+µã»÷¡°Éú³É¡±°´Å¥£¬ÏÂÔØ zip Îļþ£¬²¢½«Æä½âѹµ½Äú¼ÆËã»úÉϵÄÒ»¸öÎļþ¼ÐÖС£
+
+
+
+[start.spring.io](http://start.spring.io/)´´½¨µÄÏîÄ¿°üº¬[Spring Boot](https://spring.io/projects/spring-boot)£¬Ò»¸öÈÃSpring×¼±¸ºÃÔÚÄúµÄÓ¦ÓóÌÐòÄÚ²¿¹¤×÷£¬µ«²»ÐèҪ̫¶à´úÂë»òÅäÖᣠSpring Boot ÊÇÆô¶¯ Spring ÏîÄ¿µÄ×î¿ìºÍ×îÁ÷Ðеķ½Ê½¡£
+
+ÕâÀïÎÒÃÇÑ¡ÔñʹÓÃmaven×÷Ϊ°ü¹ÜÀí¹¤¾ß£¬ÏÂÔØÏÂÀ´µÄÏîÄ¿Àï»á°üº¬pomÎļþ£¬pomÎļþÀï°üº¬ÁËÄãµÄÌí¼ÓµÄÒÀÀµ¡£
+
+````
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.0.5
+
+
+ com.example
+ demo
+ 0.0.1-SNAPSHOT
+ demo
+ Demo project for Spring Boot
+
+ 17
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+````
+
+
+## µÚ¶þ²½£ºÌí¼ÓÄãµÄ´úÂë
+
+ÔÚÄúµÄ IDE Öдò¿ªÏîÄ¿²¢ÔÚ `src/main/java/com/example/demo` Îļþ¼ÐÖÐÕÒµ½ `DemoApplication.java` Îļþ¡£
+
+ÏÖÔÚͨ¹ýÌí¼ÓÏÂÃæ´úÂëÖÐÏÔʾµÄ¶îÍâ·½·¨ºÍ×¢ÊÍÀ´¸ü¸ÄÎļþµÄÄÚÈÝ¡£Äú¿ÉÒÔ¸´ÖƲ¢Õ³Ìù´úÂë»òÖ±½Ó¼üÈë´úÂë¡£
+```
+package com.example.demo;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@SpringBootApplication
+@RestController
+public class DemoApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(DemoApplication.class, args);
+ }
+ @GetMapping("/hello")
+ public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
+ return String.format("Hello %s!", name);
+ }
+}
+
+```
+
+ÕâÊÇÔÚ Spring Boot Öд´½¨Ò»¸ö¼òµ¥µÄ¡°Hello World¡± Web ·þÎñËùÐèµÄËùÓдúÂë¡£
+
+ÎÒÃÇÌí¼ÓµÄ`hello()`·½·¨Ö¼ÔÚ»ñȡһ¸öÃûΪnameµÄString²ÎÊý£¬È»ºó½«´Ë²ÎÊýÓë´úÂëÖеĵ¥´Ê`"Hello"`½áºÏÆðÀ´¡£
+
+ÕâÒâζ×ÅÈç¹ûÄúÔÚÇëÇóÖн«ÄúµÄÃû×ÖÉèÖÃΪ¡°Amy¡±£¬ÔòÏìÓ¦½«ÊÇ¡°Hello Amy¡±¡£
+
+`@RestController` ×¢Ê͸æËß Spring£¬´Ë´úÂëÃèÊöÁËÒ»¸ö¶Ëµã£¬¸Ã¶ËµãÓ¦ÔÚ Web ÉÏ¿ÉÓá£
+
+@GetMapping(¡°/hello¡±) ¸æËß Spring ʹÓÃÎÒÃÇµÄ hello() ·½·¨À´ÏìÓ¦·¢Ë͵½ http://localhost:8080/hello µØÖ·µÄÇëÇó¡£
+
+×îºó£¬@RequestParam ¸æËß Spring ÔÚÇëÇóÖÐÆÚÍûÒ»¸öÃû³ÆÖµ£¬µ«Èç¹û²»´æÔÚ£¬Ëü½«Ä¬ÈÏʹÓõ¥´Ê¡°World¡±¡£
+
+## µÚÈý²½£ºÆô¶¯
+
+ÈÃÎÒÃǹ¹½¨²¢ÔËÐгÌÐò¡£´ò¿ªÃüÁîÐУ¨»òÖÕ¶Ë£©²¢µ¼º½µ½ÄúÓµÓÐÏîÄ¿ÎļþµÄÎļþ¼Ð¡£
+
+ÎÒÃÇ¿ÉÒÔͨ¹ý·¢³öÒÔÏÂÃüÁîÀ´¹¹½¨ºÍÔËÐÐÓ¦ÓóÌÐò£º
+
+**MacOS/Linux:**
+
+```
+COPY./gradlew bootRun
+
+```
+
+**Windows:**
+
+```
+COPY.\gradlew.bat bootRun
+
+```
+
+ÄúÓ¦¸Ã»á¿´µ½Ò»Ð©Óë´Ë·Ç³£ÏàËÆµÄÊä³ö£º
+
+
+ÕâÀïµÄ×îºó¼¸ÐиæËßÎÒÃÇ£¬SpringÓ¦ÓÃÒѾ¿ªÊ¼ÔËÐÐÁË¡£
+Spring Boot µÄǶÈëʽ Apache Tomcat ·þÎñÆ÷³äµ±ÍøÂç·þÎñÆ÷£¬²¢ÕýÔÚ¼àÌý¡°localhost¡±¶Ë¿Ú¡°8080¡±ÉϵÄÇëÇó¡£
+
+´ò¿ªä¯ÀÀÆ÷£¬ÔÚ¶¥²¿µÄµØÖ·À¸ÖÐÊäÈë`http://localhost:8080/hello`¡£
+
+ÄãÓ¦¸ÃµÃµ½ÕâÑùÒ»¸öÓѺõĻØÓ¦£º
+
+
+# ×ܽá
+¾ÍÊÇÈç´Ë¼òµ¥£¬µÚÒ»¸öSpringBootÓ¦ÓþÍÕâô¹¹½¨Íê³ÉÁË£¬Äã²»ÐèÒª¶îÍâµÄÅäÖÃÎļþ£¬¶îÍâµÄÒÀÀµ£¬ÉõÖÁÊǶîÍâµÄ·þÎñÆ÷¡£
+Ö»ÐèÒªÒ»¸öÆô¶¯À࣬¾Í¿ÉÒÔʵÏÖÒ»¸ö×î»ù±¾µÄSpringBootµÄÓ¦Óá£
+
+ÕâÒ²ÊÇΪʲôspringboot¿ÉÒÔÓÃÀ´¿ìËÙ¹¹½¨Ò»¸ö΢·þÎñ£¬ÒòΪËüʵÔÚÊÇÌ«·½±ãÁË¡£
+µ±È»£¬Êµ¼Ê¿ª·¢ÖÐÎÒÃÇÐèÒªÓõ½¸ü¶àspringbootµÄ¹¦ÄܺÍÌØÐÔ£¬ÎÒÃǽ«»áÔÚ½ÓÏÂÀ´µÄÕ½ÚÖÐÖð½¥Õ¹¿ª½éÉÜ¡£
+
+# ²Î¿¼ÎÄÕÂ
+https://spring.io/quickstart
\ No newline at end of file
diff --git "a/docs/spring/SpringBoot/Spring\345\270\270\350\247\201\346\263\250\350\247\243\344\275\277\347\224\250\346\214\207\345\215\227(\345\214\205\345\220\253Spring+SpringMVC+SpringBoot).md" "b/docs/spring/SpringBoot/Spring\345\270\270\350\247\201\346\263\250\350\247\243\344\275\277\347\224\250\346\214\207\345\215\227(\345\214\205\345\220\253Spring+SpringMVC+SpringBoot).md"
new file mode 100644
index 0000000..813fabe
--- /dev/null
+++ "b/docs/spring/SpringBoot/Spring\345\270\270\350\247\201\346\263\250\350\247\243\344\275\277\347\224\250\346\214\207\345\215\227(\345\214\205\345\220\253Spring+SpringMVC+SpringBoot).md"
@@ -0,0 +1,1112 @@
+# Spring×¢½â
+## 1 ¸ÅÊö
+
+ÎÒÃǶ¼ÖªµÀSpring×îºËÐĵÄÌØÐÔ¾ÍÊÇIOC+AOP£¬IOCµÄÔÀí¾ÍÊÇʵÏÖÁËÒ»¸öSpringÈÝÆ÷£¬ÓÃÀ´¹ÜÀíËùÓÐSpring BeanʵÀý
+DI£¬Ò²¾ÍÊÇÒÀÀµ×¢È룬ÊÇÎÒÃÇ×÷Ϊ¿ª·¢ÕßÐèÒª¹ØÐĵĺËÐÄ»°Ì⣬ÈçºÎ×¢ÈëÒÀÀµ£¬×¢ÈëÄĸöÒÀÀµ£¬ÊÇÎÒÃÇÐèÒªÃ÷È·ÖªµÀµÄ¡£
+ÔÚÒÔǰ£¬ÎÒÃÇϰ¹ßÓÚÓÃxmlÅäÖÃÎļþÀ´ÉùÃ÷Ò»¸öbean£¬µ«ÏÖÔÚ£¬ÎÒÃǸü¶àµØÊ¹ÓÃ×¢½âºÍ´úÂëÀ´Íê³ÉDIµÄ¹ý³Ì
+
+
+ÎÒÃÇ¿ÉÒÔʹÓà org.springframework.beans.factory.annotation ºÍ org.springframework.context.annotation °üÖеÄ×¢ÊÍÀ´ÆôÓà Spring DI ÒýÇæµÄ¹¦ÄÜ¡£
+
+ÎÒÃÇͨ³£½«ÕâЩ³ÆÎª¡°Spring ºËÐÄ×¢ÊÍ¡±£¬ÎÒÃǽ«ÔÚ±¾½Ì³ÌÖÐ¶ÔÆä½øÐлعˡ£
+
+
+## 2 DIÏà¹Ø×¢½â
+
+### 2.1 @Autowired
+
+ÎÒÃÇ¿ÉÒÔʹÓà @Autowired À´±ê¼Ç Spring ½«Òª½âÎöºÍ×¢ÈëµÄÒÀÀµÏî¡£
+ÎÒÃÇ¿ÉÒÔ½«´Ë×¢ÊÍÓë¹¹Ô캯Êý¡¢setter »ò×Ö¶Î×¢ÈëÒ»ÆðʹÓá£
+Constructor injection:
+
+**¹¹ÔìÆ÷×¢Èë**
+
+````
+class Car {
+ Engine engine;
+
+ @Autowired
+ Car(Engine engine) {
+ this.engine = engine;
+ }
+}
+````
+
+**Setter×¢Èë**
+````
+class Car {
+ Engine engine;
+
+ @Autowired
+ void setEngine(Engine engine) {
+ this.engine = engine;
+ }
+}
+````
+**±äÁ¿×¢Èë**
+````
+class Car {
+ @Autowired
+ Engine engine;
+}
+````
+
+@Autowired ÓÐÒ»¸öÃûΪ required µÄ²¼¶û²ÎÊý£¬Ä¬ÈÏֵΪ true¡£
+
+µ±ËüÕÒ²»µ½ºÏÊ浀 bean À´Á¬½Óʱ£¬Ëü»áµ÷Õû Spring µÄÐÐΪ¡£ µ±Îª true ʱ£¬½«Å׳öÒì³££¬·ñÔò²»Á¬½ÓÈκÎÄÚÈÝ¡£
+
+Çë×¢Ò⣬Èç¹ûÎÒÃÇʹÓù¹Ô캯Êý×¢È룬ÔòËùÓй¹Ô캯Êý²ÎÊý¶¼ÊÇÇ¿ÖÆÐԵġ£
+
+´Ó 4.3 °æ±¾¿ªÊ¼£¬ÎÒÃDz»ÐèÒªÏÔʽµØÊ¹Óà @Autowired ×¢½â¹¹Ô캯Êý£¬³ý·ÇÎÒÃÇÉùÃ÷ÖÁÉÙÁ½¸ö¹¹Ô캯Êý¡£
+
+### 2.2 @Bean
+
+@Bean ±ê¼ÇʵÀý»¯ Spring bean µÄ¹¤³§·½·¨£º
+
+```
+@Bean
+Engine engine() {
+ return new Engine();
+}
+````
+
+µ±ÐèÒª·µ»ØÀàÐ͵ÄÐÂʵÀýʱ£¬Spring »áµ÷ÓÃÕâЩ·½·¨¡£
+
+Éú³ÉµÄ bean Ó빤³§·½·¨Í¬Ãû¡£ Èç¹ûÎÒÃÇÏëÒÔ²»Í¬µÄ·½Ê½ÃüÃû£¬ÎÒÃÇ¿ÉÒÔʹÓôË×¢Ê͵ÄÃû³Æ»òÖµ²ÎÊý£¨²ÎÊýÖµÊDzÎÊýÃû³ÆµÄ±ðÃû£©£º
+
+````
+@Bean("engine")
+Engine getEngine() {
+ return new Engine();
+}
+````
+ÕâÊÇÒ»Öַdz£³£¼ûµÄbeanÉùÃ÷·½Ê½£¬ÒòΪºÜ¶àµÄbean²¢²»ÊÇÎÒÃÇÒ»¿ªÊ¼¾ÍÔÚ´úÂëÀﶨÒåºÃµÄ£¬Ëü¿ÉÄÜÐèÒª»ùÓÚÔËÐÐʱ»·¾³À´½øÐа´Ðè¹¹½¨¡£
+
+ÎÒÃÇ¿ÉÒÔ×ÔÓɵØÉùÃ÷ºÍ¶¨ÒåBean£¬²¢ÇÒÒ²¿ÉÒÔ¸³ÓèËü×Ô¶¨ÒåµÄbeanÃû³Æ¡£
+
+×¢Ò⣬ËùÓÐÓÃ@Bean ×¢Ê͵ķ½·¨¶¼±ØÐëÔÚ@Configuration ÀàÖС£
+
+### 2.3 @Qualifier
+
+ÎÒÃÇʹÓÃ@Qualifier ºÍ@Autowired À´ÌṩÎÒÃÇÏëÒªÔÚ²»Ã÷È·Çé¿öÏÂʹÓõÄbean id »òbean Ãû³Æ¡£
+
+ÀýÈ磬ÒÔÏÂÁ½¸ö bean ʵÏÖÏàͬµÄ½Ó¿Ú£º
+````
+class Bike implements Vehicle {}
+
+class Car implements Vehicle {}
+
+````
+
+Èç¹û Spring ÐèҪעÈëÒ»¸ö Vehicle bean£¬Ëü»áÒÔ¶à¸öÆ¥Å䶨Òå½áÊø¡£ ÔÚÕâÖÖÇé¿öÏ£¬ÎÒÃÇ¿ÉÒÔʹÓà @Qualifier ×¢ÊÍÏÔʽÌṩ bean µÄÃû³Æ¡£
+
+**¹¹ÔìÆ÷×¢Èë**
+````
+@Autowired
+Biker(@Qualifier("bike") Vehicle vehicle) {
+this.vehicle = vehicle;
+}
+````
+
+**Setter×¢Èë**
+
+````
+@Autowired
+void setVehicle(@Qualifier("bike") Vehicle vehicle) {
+this.vehicle = vehicle;
+}
+````
+»òÕß:
+
+````
+@Autowired
+@Qualifier("bike")
+void setVehicle(Vehicle vehicle) {
+this.vehicle = vehicle;
+````
+**±äÁ¿×¢Èë**
+
+````
+@Autowired
+@Qualifier("bike")
+Vehicle vehicle;
+````
+Õâ¸ö×¢½âÎÒÃÇ¿ÉÄÜÆ½³£ÓõIJ»¶à£¬µ«Êǵ±Ò»¸ö½Ó¿ÚÓжà¸öʵÏÖÀàʱ£¬Ëü¾Í»á¾³£ÅÉÉÏÓ󡣡
+
+### 2.4 @Required
+
+@Required ÔÚ setter ·½·¨Éϱê¼ÇÎÒÃÇÏëҪͨ¹ý XML Ìî³äµÄÒÀÀµÏ
+````
+@Required
+void setColor(String color) {
+this.color = color;
+}
+````
+xml
+````
+
+
+
+````
+·ñÔò£¬½«Å׳ö BeanInitializationException¡£
+·Ç³£ÉÙ¼ûµÄÓ÷¨£¬ÖªµÀһϾÍÐÐÁË
+
+### 2.5 @Value
+ÎÒÃÇ¿ÉÒÔʹÓà @Value ½«ÊôÐÔÖµ×¢Èë bean¡£ ËüÓë¹¹Ô캯Êý¡¢setter ºÍ×Ö¶Î×¢Èë¼æÈÝ¡£
+
+ÕâÒ²ÊǷdz£³£ÓõÄÒ»¸ö×¢½â£¬ÒòΪÎÒÃǺܶàʱºò¶¼ÐèÒª´Óapplication.properties»òÕ߯äËûÅäÖÃÎļþÖÐÀ´¶ÁÈ¡ÅäÖÃÊôÐÔÖµ¡£
+
+**¹¹ÔìÆ÷×¢Èë**
+````
+Engine(@Value("8") int cylinderCount) {
+this.cylinderCount = cylinderCount;
+}
+````
+
+**setter×¢Èë**
+
+````
+@Autowired
+void setCylinderCount(@Value("8") int cylinderCount) {
+this.cylinderCount = cylinderCount;
+}
+````
+
+»òÕß:
+````
+
+@Value("8")
+void setCylinderCount(int cylinderCount) {
+this.cylinderCount = cylinderCount;
+}
+````
+
+**±äÁ¿×¢Èë**
+````
+@Value("8")
+int cylinderCount;
+````
+
+µ±È»£¬×¢È뾲ֵ̬ÊÇûÓÐÓõġ£ Òò´Ë£¬ÎÒÃÇ¿ÉÒÔÔÚ @Value ÖÐʹÓÃռλ·û×Ö·û´®À´Á¬½ÓÔÚÍⲿԴÖж¨ÒåµÄÖµ£¬ÀýÈçÔÚ .properties »ò .yaml ÎļþÖС£
+````
+
+engine.fuelType=petrol
+````
+
+ÎÒÃÇ¿ÉÒÔͨ¹ýÒÔÏ·½Ê½×¢Èë engine.fuelType µÄÖµ£º
+
+````
+@Value("${engine.fuelType}")
+String fuelType;
+````
+
+ÎÒÃÇÉõÖÁ¿ÉÒÔʹÓà SpEL À´Ê¹ÓÃ@Value¡£ ¸ü¶à¸ß¼¶Ê¾Àý¿ÉÒÔÔÚÎÒÃǹØÓÚ@Value µÄÎÄÕÂÖÐÕÒµ½¡£
+
+### 2.6 @DependsOn
+ÎÒÃÇ¿ÉÒÔʹÓôË×¢½âÈà Spring ÔÚ×¢½âµÄ bean ֮ǰ³õʼ»¯ÆäËû bean¡£ ͨ³££¬´ËÐÐΪÊÇ×Ô¶¯µÄ£¬»ùÓÚ bean Ö®¼äµÄÏÔʽÒÀÀµ¹ØÏµ¡£
+
+ÎÒÃÇÖ»ÓÐÔÚÒÀÀµÊÇÒþʽµÄʱºò²ÅÐèÒªÕâ¸ö×¢½â£¬±ÈÈçJDBCÇý¶¯¼ÓÔØ»òÕß¾²Ì¬±äÁ¿³õʼ»¯¡£
+
+ÎÒÃÇ¿ÉÒÔÔÚÖ¸¶¨ÒÀÀµ bean Ãû³ÆµÄÒÀÀµÀàÉÏʹÓà @DependsOn¡£ ×¢Ê͵ÄÖµ²ÎÊýÐèÒªÒ»¸ö°üº¬ÒÀÀµ bean Ãû³ÆµÄÊý×飺
+
+````
+@DependsOn("engine")
+class Car implements Vehicle {}
+````
+Alternatively, if we define a bean with the @Bean annotation, the factory method should be annotated with @DependsOn:
+````
+@Bean
+@DependsOn("fuel")
+Engine engine() {
+return new Engine();
+}
+````
+### 2.7 @Lazy
+µ±ÎÒÃÇÏëÀÁ¶èµØ³õʼ»¯ÎÒÃÇµÄ bean ʱ£¬ÎÒÃÇʹÓà @Lazy¡£ ĬÈÏÇé¿öÏ£¬Spring ÔÚÓ¦ÓóÌÐòÉÏÏÂÎĵįô¶¯/Òýµ¼Ê±¼±Çеش´½¨ËùÓе¥Àý bean¡£
+
+µ«ÊÇ£¬ÓÐЩÇé¿öÏÂÎÒÃÇÐèÒªÔÚÇëÇóʱ´´½¨ bean£¬¶ø²»ÊÇÔÚÓ¦ÓóÌÐòÆô¶¯Ê±´´½¨¡£
+
+Õâ¸ö×¢½âµÄÐÐΪ»á¸ù¾ÝÎÒÃÇ·ÅÖÃËüµÄÈ·ÇÐλÖöøÓÐËù²»Í¬¡£ ÎÒÃÇ¿ÉÒÔ°ÑËü·ÅÔÚ£º
+
+Ò»¸ö @Bean ×¢Ê굀 bean ¹¤³§·½·¨£¬ÒÔÑÓ³Ù·½·¨µ÷Óã¨Òò´Ë´´½¨ bean£©
+@Configuration ÀàºÍËùÓаüº¬µÄ@Bean ·½·¨¶¼»áÊܵ½Ó°Ïì
+
+Ò»¸ö @Component À࣬Ëü²»ÊÇ @Configuration À࣬Õâ¸ö bean ½«±»ÑÓ³Ù³õʼ»¯
+
+@Autowired ¹¹Ô캯Êý¡¢setter »ò×ֶΣ¬ÓÃÓÚÑÓ³Ù¼ÓÔØÒÀÀµÏî±¾Éí£¨Í¨¹ý´úÀí£©
+
+````
+@Configuration
+@Lazy
+class VehicleFactoryConfig {
+
+ @Bean
+ @Lazy(false)
+ Engine engine() {
+ return new Engine();
+ }
+}
+````
+ÕâͬÑù²»ÊÇÒ»¸ö³£ÓõÄ×¢½â¡£
+
+µ±ÎÒÃÇά»¤Ò»¸öÓдóÁ¿beanµÄÏîĿʱ£¬»á·¢ÏÖÓкܶàbean¿ÉÄܶ¼Êǰ´ÐèʹÓõ쬲»Ò»¶¨ÐèÒªÔÚÈÝÆ÷³õʼ»¯Ê±¾Í½øÐгõʼ»¯£¬Õâ¿ÉÒÔ°ïÎÒÃǽÚÊ¡ºÜ¶àʱ¼äºÍÐÔÄÜ¡£
+
+
+### 2.8 @Lookup
+ͬÑùÊÇÒ»¸ö±È½ÏÉÙÓõ½µÄ×¢½â
+
+@Lookup »á¸æËß Spring ÔÚÎÒÃǵ÷ÓÃËüʱ·µ»Ø·½·¨·µ»ØÀàÐ͵ÄʵÀý¡£
+
+±¾ÖÊÉÏ£¬Spring ½«¸²¸ÇÎÒÃÇ´ø×¢Ê͵ķ½·¨²¢Ê¹ÓÃÎÒÃÇ·½·¨µÄ·µ»ØÀàÐͺͲÎÊý×÷Ϊ BeanFactory#getBean µÄ²ÎÊý¡£
+
+@Lookup ÊÊÓÃÓÚ£º
+
+½«ÔÐÍ bean ×¢ÈëÎÒÃÇ×Ô¼ºµÄbean£¨ÀàËÆÓÚ Provider£©
+
+Èç¹ûÎÒÃÇÅöÇɾö¶¨ÓµÓÐÒ»¸öÔÐÍ Spring bean£¬ÄÇôÎÒÃǼ¸ºõ»áÁ¢¼´ÃæÁÙÕâÑùµÄÎÊÌ⣺
+
+ÎÒÃǵĵ¥Àý Spring bean ½«ÈçºÎ·ÃÎÊÕâЩÔÐÍ Spring bean£¿
+
+ÏÖÔÚ£¬Provider ¿Ï¶¨ÊÇÒ»ÖÖ·½Ê½£¬¾¡¹Ü @Lookup ÔÚijЩ·½Ãæ¸ü¼ÓͨÓá£
+
+ҪעÒâµÄÊÇ£¬springĬÈÏʹÓõĵ¥Àýbean£¬ËùÒÔÈç¹ûÎÒÃÇҪעÈëÔÐÍbean£¬ÎÒÃDzÅÐèÒª×öÕâÑùµÄ¶îÍ⹤×÷
+
+Ê×ÏÈ£¬ÈÃÎÒÃÇ´´½¨Ò»¸öÔÐÍ bean£¬ÉÔºóÎÒÃǽ«Æä×¢Èëµ½µ¥Àý bean ÖУº
+````
+@Component
+@Scope("prototype")
+public class SchoolNotification {
+// ... prototype-scoped state
+}
+````
+ʹÓÃ@Lookup£¬ÎÒÃÇ¿ÉÒÔͨ¹ýµ¥Àý bean »ñÈ¡ SchoolNotification µÄʵÀý£º
+
+````
+@Component
+public class StudentServices {
+
+ // ... member variables, etc.
+
+ @Lookup
+ public SchoolNotification getNotification() {
+ return null;
+ }
+
+ // ... getters and setters
+}
+````
+Using @Lookup, we can get an instance of SchoolNotification through our singleton bean:
+````
+@Test
+public void whenLookupMethodCalled_thenNewInstanceReturned() {
+// ... initialize context
+StudentServices first = this.context.getBean(StudentServices.class);
+StudentServices second = this.context.getBean(StudentServices.class);
+
+ assertEquals(first, second);
+ assertNotEquals(first.getNotification(), second.getNotification());
+}
+````
+Çë×¢Ò⣬ÔÚ StudentServices ÖУ¬ÎÒÃǽ« getNotification ·½·¨±£ÁôΪ´æ¸ù¡£
+
+ÕâÊÇÒòΪ Spring ͨ¹ýµ÷Óà beanFactory.getBean(StudentNotification.class) ¸²¸ÇÁ˸÷½·¨£¬Òò´ËÎÒÃÇ¿ÉÒÔ½«ÆäÁô¿Õ¡£
+
+
+### 2.9 @Primary
+ÓÐʱÎÒÃÇÐèÒª¶¨Òå¶à¸öÏàͬÀàÐ͵Äbean¡£ ÔÚÕâЩÇé¿öÏ£¬×¢È뽫²»³É¹¦£¬ÒòΪ Spring ²»ÖªµÀÎÒÃÇÐèÒªÄĸö bean¡£
+
+ÎÒÃÇÒѾ¿´µ½ÁË´¦ÀíÕâÖÖÇé¿öµÄÑ¡ÏÓÃ@Qualifier ±ê¼ÇËùÓнÓÏߵ㲢ָ¶¨ËùÐè bean µÄÃû³Æ¡£
+
+È»¶ø£¬´ó¶àÊýʱºòÎÒÃÇÐèÒªÒ»¸öÌØ¶¨µÄ bean£¬ºÜÉÙÐèÒªÆäËû bean¡£
+
+ÎÒÃÇ¿ÉÒÔʹÓÃ@Primary À´¼ò»¯ÕâÖÖÇé¿ö£ºÈç¹ûÎÒÃÇÓÃ@Primary ±ê¼Ç×î³£ÓõÄbean£¬Ëü½«ÔÚunqualifiedµÄ×¢ÈëµãÉϱ»Ñ¡Ôñ£º
+
+````
+@Component
+@Primary
+class Car implements Vehicle {}
+
+@Component
+class Bike implements Vehicle {}
+
+@Component
+class Driver {
+@Autowired
+Vehicle vehicle;
+}
+
+@Component
+class Biker {
+@Autowired
+@Qualifier("bike")
+Vehicle vehicle;
+}
+````
+ÔÚÇ°ÃæµÄʾÀýÖУ¬Æû³µÊÇÖ÷Òª³µÁ¾¡£ Òò´Ë£¬ÔÚ Driver ÀàÖУ¬Spring ×¢ÈëÁËÒ»¸ö Car bean¡£ µ±È»£¬ÔÚ Biker bean ÖУ¬×Ö¶Î vehicle µÄÖµ½«ÊÇÒ»¸ö Bike ¶ÔÏó£¬ÒòΪËüÊÇqualifiedµÄ¡£
+
+### 2.10 @Scope
+
+¶ÔÓÚͨ³£µÄÓ¦ÓÃÀ´Ëµ£¬ÎÒÃÇbeanµÄscopeĬÈ϶¼Êǵ¥ÀýµÄ£¬µ«Êµ¼ÊÉÏspring bean¿ÉÒÔÖ§³Ö¶àÖÖ¶àÑùµÄ×÷Ó÷¶Î§£¬ËüÃÇÓÐ×Ų»Í¬µÄÉúÃüÖÜÆÚ¡£
+
+ÎÒÃÇʹÓÃ@Scope À´¶¨Òå@Component Àà»ò@Bean ¶¨ÒåµÄ·¶Î§¡£ Ëü¿ÉÒÔÊǵ¥Àý¡¢ÔÐÍ¡¢ÇëÇ󡢻Ự¡¢globalSession »òһЩ×Ô¶¨Ò巶Χ¡£
+
+¶ÔÓ¦µÄö¾ÙֵΪ
+````
+singleton
+prototype
+request
+session
+application
+websocket
+````
+
+Àý×Ó
+````
+@Component
+@Scope("prototype")
+class Engine {}
+````
+ÎÒÃÇ¿ÉÒÔÏëÏóһЩ³¡¾°£¬±ÈÈçrequest¡¢session¡¢websocketÕâÀà×÷ÓÃÓòµÄbean£¬Í¨³£Ó¦¸ÃÊǺÍÍøÂçÇëÇóÏà¹ØµÄ£¬±ÈÈçÓô洢Óû§ÐÅÏ¢¡¢sessionÖ®ÀàµÄbean¡£
+
+¾ßÌåÔõôʹÓ㬾ÍÒª¸ù¾ÝÄãµÄ¾ßÌ峡¾°À´Ñ¡ÔñÁË£¬Õâ»áÊÇÒ»¸öºÜ´óµÄ»°Ì⣬ÕâÀï¾ÍÏȲ»Õ¹¿ªÁË£¬ÒÔºó¿ÉÒÔÔÚµ¥¶ÀµÄÎÄÕÂÀï¼ÌÐø½éÉÜ¡£
+
+## 3 ÉÏÏÂÎÄÅäÖÃ×¢½â
+ÎÒÃÇ¿ÉÒÔʹÓñ¾½ÚÖÐÃèÊöµÄ×¢ÊÍÀ´ÅäÖÃÓ¦ÓóÌÐòÉÏÏÂÎÄ¡£
+
+
+### 3.1 @Profile
+
+Èç¹ûÎÒÃÇÏ£Íû Spring ½öÔÚÌØ¶¨ÅäÖÃÎļþ´¦Óڻ״̬ʱʹÓÃ@Component Àà»ò@Bean ·½·¨£¬ÎÒÃÇ¿ÉÒÔʹÓÃ@Profile ¶ÔÆä½øÐбê¼Ç¡£
+
+ÎÒÃÇ¿ÉÒÔʹÓÃ×¢Ê͵ÄÖµ²ÎÊýÅäÖÃÅäÖÃÎļþµÄÃû³Æ£º
+
+ÎÒÃÇͨ³£Õâ¸ö×¢½âÀ´ÅäÖò»Í¬»·¾³µÄÅäÖá£
+±ÈÈçÏÂÃæÕâ¸öÀý×Ó
+
+````
+public interface DatasourceConfig {
+public void setup();
+}
+````
+
+ÏÂÃæÊÇ¿ª·¢»·¾³µÄÅäÖãº
+
+````
+@Component
+@Profile("dev")
+public class DevDatasourceConfig implements DatasourceConfig {
+@Override
+public void setup() {
+System.out.println("Setting up datasource for DEV environment. ");
+}
+}
+````
+ÏÂÃæÊÇÉú²ú»·¾³µÄÅäÖãº
+
+````
+@Component
+@Profile("production")
+public class ProductionDatasourceConfig implements DatasourceConfig {
+@Override
+public void setup() {
+System.out.println("Setting up datasource for PRODUCTION environment. ");
+}
+}
+````
+µ±È»ÎÒÃÇÒ²¿ÉÒÔʹÓÃxml»òÕ߯äËûÀàÐ͵ÄÅäÖÃÎļþÀ´ÃèÊöÕâ¸öÅäÖÃbean
+
+xml
+````
+
+
+
+````
+### 3.2 @Import
+
+ÎÒÃÇ¿ÉÒÔʹÓÃÌØ¶¨µÄ @Configuration À࣬¶øÎÞÐèʹÓôË×¢½â½øÐÐ×é¼þɨÃè¡£ ÎÒÃÇ¿ÉÒÔΪÕâЩÀàÌṩ@Import µÄÖµ²ÎÊý
+
+Õý³£À´Ëµ£¬Èç¹ûÒªÓõ½@Configuration×¢½âµÄbean£¬ÄÇôspringÓ¦ÓñØÐëҪɨÃèµ½¸ÃĿ¼£¬Èç¹ûÇ¡ºÃûÓжԸ÷¾¶½øÐÐɨÃ裬»òÕßÎÒÃÇÖ»ÊÇÏëʹÓ÷¾¶Ïµĵ¥¸öÅäÖÃÀ࣬ÄÇôÎÒÃǾͿÉÒÔʹÓÃ@ImportÀ´µ¼ÈëÕâ¸öÅäÖÃÀàÁË¡£
+
+Õâ¸ö×¢½â»¹ÊǷdz£³£Óõģ¬¿´Ò»ÏÂÏÂÃæÕâ¸öÀý×Ó
+
+````
+@Import(VehiclePartSupplier.class)
+class VehicleFactoryConfig {}
+
+@Configuration
+class VehiclePartSupplier{
+}
+````
+
+### 3.3 @ImportResource
+
+±ÈÈç˵£ºÏÖÔÚÓÐÒ»¸ö bean.xml µÄÅäÖÃÎļþ£¬ÐèÒª½«¸Ã beans.xml Öж¨ÒåµÄ bean¶ÔÏó ¶¼µ¼Èëµ½ Spring Boot »·¾³µÄÈÝÆ÷ÖУ¬¸ÃÈçºÎ²Ù×÷ÄØ£¿
+
+1.Spring ·½Ê½µÄÅäÖÃÎļþ bean.xml ´Ë´¦Ëæ±ã¾Ù¸öʾÀý£¬±ÈÈç˵ xml ÖÐÅäÖÃÁËÒ»¸ö helloService£¬ÈçÏÂËùʾ
+````
+
+
+
+
+
+
+````
+2.ʹÓÃ@ImportResource×¢½â£¬ÒýÈë xml ÅäÖÃ
+````
+/**
+ * Spring BootÀïÃæÃ»ÓÐSpringµÄÅäÖÃÎļþ£¬ÎÒÃÇ×Ô¼º±àдµÄÅäÖÃÎļþ£¬Ò²²»ÄÜ×Ô¶¯Ê¶±ð£»
+ * Èç¹ûÏëÈÃSpringµÄÅäÖÃÎļþÉúЧ£¬¼ÓÔØµ½Spring ÈÝÆ÷ÖÐÀ´£»
+ * ʹÓÃ@ImportResource×¢½â£¬½«Æä±ê×¢ÔÚÒ»¸öÅäÖÃÀàÉÏ(´Ë´¦ÅäÖÃÔÚÆô¶¯Àà)
+ */
+@SpringBootApplication
+@ImportResource(locations = {"classpath:beans.xml"})
+public class BootApplication {
+
+ public static void main(String[] args) {
+ // SpringÓ¦ÓÃÆô¶¯ÆðÀ´
+ SpringApplication.run(BootApplication.class,args);
+
+ }
+}
+
+````
+### 3.4 @PropertySource
+ͨ¹ýÕâ¸ö×¢½â£¬ÎÒÃÇ¿ÉÒÔΪӦÓóÌÐòÉèÖö¨ÒåÊôÐÔÎļþ£º
+
+@PropertySource ×¢½âÌṩÁËÒ»ÖÖ·½±ãµÄÉùÃ÷ÐÔ»úÖÆ£¬ÓÃÓÚ½« PropertySource Ìí¼Óµ½ Spring µÄ Environment ÖУ¬Óë @Configuration ÀàÒ»ÆðʹÓá£
+
+Äã¿ÉÒÔʹÓà @Value È¥ÒýÓö¨ÒåµÄÊôÐÔ£¬ÀýÈ磺@Value("testbean.name")£»Ò²¿ÉÒÔÖ¸¶¨Ä¬ÈÏÖµ£¬È磺@Value("testbean.name:defaultValue")¡£
+
+Ó÷¨Ê¾Àý
+
+¸ø¶¨Ò»¸öÅäÖÃÎļþapp.properties
+````
+testbean.name=myTestBean
+````
+ÒÔÏ @Configuration ÀàʹÓà @PropertySource ½« app.properties ÉèÖøø Environment µÄ PropertySources ¼¯ºÏ¡£
+````
+@Configuration
+@PropertySource("classpath:/com/myco/app.properties")
+public class AppConfig {
+
+ @Autowired
+ Environment env;
+
+ @Bean
+ public TestBean testBean() {
+ TestBean testBean = new TestBean();
+ testBean.setName(env.getProperty("testbean.name"));
+ return testBean;
+ }
+}
+````
+
+×¢Ò⣺ʹÓà @Autowired ½« Environment ¶ÔÏó×¢Èëµ½ÅäÖÃÀàÖУ¬È»ºóÔÚ testBean() ·½·¨ÖÐʹÓá£
+ÒÔÉÏÅäÖÃÖУ¬µ÷Óà testBean.getName() ·½·¨½«·µ»Ø¡°myTestBean¡±×Ö·û´®¡£
+
+@PropertySource ÀûÓÃÁË Java 8 µÄÖØ¸´×¢½âÌØÐÔ£¬ÕâÒâζ×ÅÎÒÃÇ¿ÉÒÔÓÃËü¶à´Î±ê¼ÇÒ»¸öÀࣺ
+
+````
+@Configuration
+@PropertySource("classpath:/annotations.properties")
+@PropertySource("classpath:/vehicle-factory.properties")
+class VehicleFactoryConfig {}
+````
+
+### 3.5 @PropertySources
+Ó÷¨Í¬ÉÏ£¬Ö»²»¹ý£¬ÕâÒ»´ÎÎÒÃÇ¿ÉÒÔʹÓÃÕâ¸ö×¢½âÖ¸¶¨¶à¸ö@PropertySource ÅäÖãº
+````
+@Configuration
+@PropertySources({
+@PropertySource("classpath:/annotations.properties"),
+@PropertySource("classpath:/vehicle-factory.properties")
+})
+class VehicleFactoryConfig {}
+````
+Çë×¢Ò⣬×Ô Java 8 ÒÔÀ´£¬ÎÒÃÇ¿ÉÒÔͨ¹ýÉÏÊöÖØ¸´×¢Ê͹¦ÄÜʵÏÖÏàͬµÄ¹¦ÄÜ¡£
+
+## 4.½áÂÛ
+
+ÔÚ±¾ÎÄÖУ¬ÎÒÃÇ¿´µ½ÁË×î³£¼ûµÄ Spring ºËÐÄ×¢Ê͵ĸÅÊö¡£ ÎÒÃÇ¿´µ½ÁËÈçºÎÅäÖà bean Á¬½ÓºÍÓ¦ÓÃÉÏÏÂÎÄ£¬ÒÔ¼°ÈçºÎΪ×é¼þɨÃè±ê¼ÇÀà¡£
+
+springÌåϵÖеij£¼û×¢½â»¹Óкܶ࣬һƪÎÄÕ²»¿ÉÄÜÈ«²¿¸²¸Ç£¬ÈçÓÐÒÅ©£¬»¶Ó²¹³ä¡£
+
+# Spring Bean×¢½â
+
+## 1 ¸ÅÊö
+ÔÚ±¾½Ì³ÌÖУ¬ÎÒÃǽ«ÌÖÂÛÓÃÓÚ¶¨Ò岻ͬÀàÐÍ bean µÄ×î³£¼ûµÄ Spring bean ×¢ÊÍ¡£
+
+Óм¸ÖÖ·½·¨¿ÉÒÔÔÚ Spring ÈÝÆ÷ÖÐÅäÖà bean¡£ Ê×ÏÈ£¬ÎÒÃÇ¿ÉÒÔʹÓà XML ÅäÖÃÉùÃ÷ËüÃÇ¡£ ÎÒÃÇ»¹¿ÉÒÔÔÚÅäÖÃÀàÖÐʹÓÃ@Bean ×¢½âÀ´ÉùÃ÷ bean¡£
+
+×îºó£¬ÎÒÃÇ¿ÉÒÔʹÓà org.springframework.stereotype °üÖеÄ×¢ÊÍÖ®Ò»À´±ê¼Ç¸ÃÀ࣬²¢½«ÆäÓಿ·ÖÁô¸ø×é¼þɨÃè¡£
+
+## 2 @ComponentScan
+ÕâÊÇÎÒÃǾ³£»áʹÓõÄÒ»¸ö×¢½â£¬ÔÚÎÒÃǵÄÓ¦ÓÃÖУ¬ÓÐʱºò²»Ò»¶¨»áɨÃèËùÓеİü£¬ÌرðÊǵ±ÎÒÃÇҪɨÃèÍⲿjar°üÖеÄbeanʱ£¬Ëü·Ç³£ÓÐÓá£
+
+Ëü¿ÉÒÔ¼ÓÔÚSpringBootApplicationÉÏ£¬Ò²¿ÉÒÔ¼ÓÔÚ@configuration×¢½âÉϵÄÅäÖÃÀàÉÏ
+
+Èç¹ûÆôÓÃÁË×é¼þɨÃ裬Spring ¿ÉÒÔ×Ô¶¯É¨Ãè°üÖÐµÄ bean¡£
+
+@ComponentScan ÅäÖÃʹÓÃ×¢½âÅäÖÃɨÃèÄÄЩ°üµÄÀà¡£
+
+ÎÒÃÇ¿ÉÒÔÖ±½ÓʹÓà basePackages »ò value ²ÎÊýÖ®Ò»Ö¸¶¨»ù±¾°üÃû³Æ£¨value ÊÇ basePackages µÄ±ðÃû£©
+
+````
+@Configuration
+@ComponentScan(basePackages = "com.baeldung.annotations")
+class VehicleFactoryConfig {}
+````
+´ËÍ⣬ÎÒÃÇ¿ÉÒÔʹÓà basePackageClasses ²ÎÊýÖ¸Ïò»ù´¡°üÖеÄÀࣺ
+
+````
+@Configuration
+@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
+class VehicleFactoryConfig {}
+````
+
+ÕâÁ½¸ö²ÎÊý¶¼ÊÇÊý×飬Òò´ËÎÒÃÇ¿ÉÒÔΪÿ¸ö²ÎÊýÌṩ¶à¸ö°ü¡£
+
+Èç¹ûδָ¶¨²ÎÊý£¬ÔòɨÃè·¢ÉúÔÚ´æÔÚ @ComponentScan ×¢ÊÍÀàµÄͬһ°üÖС£
+
+@ComponentScan ÀûÓÃÁË Java 8 µÄÖØ¸´×¢½âÌØÐÔ£¬ÕâÒâζ×ÅÎÒÃÇ¿ÉÒÔÓÃËü¶à´Î±ê¼ÇÒ»¸öÀࣺ
+
+````
+@Configuration
+@ComponentScan(basePackages = "com.baeldung.annotations")
+@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
+class VehicleFactoryConfig {}
+````
+
+»òÕߣ¬ÎÒÃÇ¿ÉÒÔʹÓà @ComponentScans Ö¸¶¨¶à¸ö @ComponentScan ÅäÖãº
+
+````
+@Configuration
+@ComponentScans({
+@ComponentScan(basePackages = "com.baeldung.annotations"),
+@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
+})
+````
+````
+class VehicleFactoryConfig {
+}
+````
+ʹÓà XML ÅäÖÃʱ£¬ÅäÖÃ×é¼þɨÃèͬÑù¼òµ¥£º
+
+````
+
+````
+
+### 3 @Component
+
+@Component ÊÇÀ༶±ðµÄ×¢½â¡£ ÔÚ×é¼þɨÃèÆÚ¼ä£¬Spring Framework »á×Ô¶¯¼ì²âʹÓÃ@Component ×¢½âµÄÀࣺ
+````
+@Component
+class CarUtility {
+// ...
+}
+````
+
+ĬÈÏÇé¿öÏ£¬´ËÀàµÄ bean ʵÀýÓëÀàÃûͬÃû£¬Ê××ÖĸСд¡£ ´ËÍ⣬ÎÒÃÇ¿ÉÒÔʹÓôË×¢Ê͵ĿÉѡֵ²ÎÊýÖ¸¶¨²»Í¬µÄÃû³Æ¡£
+
+ÓÉÓÚ@Repository¡¢@Service¡¢@Configuration ºÍ@Controller ¶¼ÊÇ´øÓÐ@Component µÄ×¢½â£¬ËüÃǹ²ÏíÏàͬµÄbean ÃüÃûÐÐΪ¡£
+
+Spring »¹»áÔÚ×é¼þɨÃè¹ý³ÌÖÐ×Ô¶¯¼ì²âËüÃÇ¡£
+
+ͨ³£À´Ëµ£¬ÎÒÃÇ»áÔÚmvcÓ¦ÓÃÖÐÎÒÃÇ»áÓõ½ÉÏÊö¼¸ÖÖ×¢½â£¬¶øÎÒÃÇÔÚ·ÇwebÓ¦ÓÃÖиü¶àµØ¿ÉÒÔʹÓÃ@componentÀ´×¢½âbean
+
+### 4 @Repository
+
+DAO or Repository classes usually represent the database access layer in an application, and should be annotated with @Repository:
+````
+@Repository
+class VehicleRepository {
+// ...
+}
+````
+ʹÓôË×¢Ê͵ÄÒ»¸öÓŵãÊÇËüÆôÓÃÁË×Ô¶¯³Ö¾ÃÐÔÒ쳣ת»»¡£ µ±Ê¹Óó־ÃÐÔ¿ò¼Ü£¨Èç Hibernate£©Ê±£¬ÔÚʹÓà @Repository ×¢Ê͵ÄÀàÖÐÅ׳öµÄ±¾»úÒì³£½«×Ô¶¯×ª»»Îª Spring µÄ DataAccessExeption µÄ×ÓÀà¡£
+
+ÒªÆôÓÃÒ쳣ת»»£¬ÎÒÃÇÐèÒªÉùÃ÷ÎÒÃÇ×Ô¼ºµÄ PersistenceExceptionTranslationPostProcessor bean£º
+````
+@Bean
+public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
+return new PersistenceExceptionTranslationPostProcessor();
+}
+````
+Çë×¢Ò⣬ÔÚ´ó¶àÊýÇé¿öÏ£¬Spring »á×Ô¶¯Ö´ÐÐÉÏÊö²½Öè¡£
+
+»òÕßͨ¹ý XML ÅäÖãº
+````
+
+````
+
+### 5 @Service
+Ó¦ÓóÌÐòµÄÒµÎñÂ߼ͨ³£×¤ÁôÔÚ·þÎñ²ãÖУ¬Òò´ËÎÒÃǽ«Ê¹ÓÃ@Service ×¢ÊÍÀ´Ö¸Ê¾Ò»¸öÀàÊôÓڸò㣺
+
+````
+@Service
+public class VehicleService {
+// ...
+}
+````
+### 6 @Controller
+@Controller ÊÇÒ»¸öÀ༶±ðµÄ×¢½â£¬Ëü¸æËß Spring Framework Õâ¸öÀà×÷Ϊ Spring MVC ÖеĿØÖÆÆ÷£º
+
+spring»á¶Ô@Controller ×¢½âµÄbean×öºÜ¶àÊÂÇ飬¾ßÌåÄÚÈÝÎÒÃÇ»áÔÚSpringMVCÏà¹ØµÄÄÚÈÝÀ´½²Êö
+
+````
+@Controller
+public class VehicleController {
+// ...
+}
+
+````
+## 7 @Configuration
+
+ÅäÖÃÀà¿ÉÒÔ°üº¬ÓÃ@Bean ×¢Ê굀 bean ¶¨Òå·½·¨£º
+````
+@Configuration
+class VehicleFactoryConfig {
+
+ @Bean
+ Engine engine() {
+ return new Engine();
+ }
+
+}
+````
+## 8 AOP×¢½â
+µ±ÎÒÃÇʹÓà Spring ¹¹ÔìÐÍ×¢ÊÍʱ£¬ºÜÈÝÒ×´´½¨Ò»¸öÇÐÈëµã£¬¸ÃÇÐÈëµãÒÔËùÓоßÓÐÌØ¶¨¹¹ÔìÐ͵ÄÀàΪĿ±ê¡£
+
+ÀýÈ磬¼ÙÉèÎÒÃÇÏë²âÁ¿ DAO ²ã·½·¨µÄÖ´ÐÐʱ¼ä¡£ ÎÒÃǽ«´´½¨ÒÔÏ·½Ã棨ʹÓà AspectJ ×¢ÊÍ£©£¬ÀûÓà @Repository ¹¹ÔìÐÍ£º
+
+```
+@Aspect
+@Component
+public class PerformanceAspect {
+@Pointcut("within(@org.springframework.stereotype.Repository *)")
+public void repositoryClassMethods() {};
+
+ @Around("repositoryClassMethods()")
+ public Object measureMethodExecutionTime(ProceedingJoinPoint joinPoint)
+ throws Throwable {
+ long start = System.nanoTime();
+ Object returnValue = joinPoint.proceed();
+ long end = System.nanoTime();
+ String methodName = joinPoint.getSignature().getName();
+ System.out.println(
+ "Execution of " + methodName + " took " +
+ TimeUnit.NANOSECONDS.toMillis(end - start) + " ms");
+ return returnValue;
+ }
+}
+````
+
+ÔÚ´ËʾÀýÖУ¬ÎÒÃÇ´´½¨ÁËÒ»¸öÇÐÈëµã£¬¸ÃÇÐÈëµãÆ¥ÅäʹÓÃ@Repository ×¢Ê͵ÄÀàÖеÄËùÓз½·¨¡£ È»ºóÎÒÃÇʹÓÃ@Around ֪ͨÀ´¶¨Î»ÄǸöÇÐÈëµã£¬²¢È·¶¨À¹½Ø·½·¨µ÷ÓõÄÖ´ÐÐʱ¼ä¡£
+
+´ËÍ⣬ʹÓÃÕâÖÖ·½·¨£¬ÎÒÃÇ¿ÉÒÔΪÿ¸öÓ¦ÓóÌÐò²ãÌí¼ÓÈÕÖ¾¼Ç¼¡¢ÐÔÄܹÜÀí¡¢Éó¼ÆºÍÆäËûÐÐΪ¡£
+
+µ±È»ÁË£¬aspectJµÄÏà¹Ø×¢½â»¹ºÜ¶à£¬¿ÉÒÔÓÃÀ´ÉùÃ÷ÇÐÃæ£¬Î´À´ÎÒÃÇÒ²»áµ¥¶ÀдÎĽéÉÜ¡£
+
+## 9 ½áÂÛ
+
+ÔÚ±¾ÎÄÖУ¬ÎÒÃǼì²éÁË Spring ¹¹ÔìÐÍ×¢ÊͲ¢ÌÖÂÛÁËËüÃǸ÷×Ô´ú±íµÄÓïÒåÀàÐÍ¡£
+
+ÎÒÃÇ»¹Ñ§Ï°ÁËÈçºÎʹÓÃ×é¼þɨÃèÀ´¸æËßÈÝÆ÷ÔÚÄÄÀï¿ÉÒÔÕÒµ½´ø×¢Ê͵ÄÀà¡£
+
+×îºó£¬ÎÒÃÇÁ˽âÁËÕâЩעÊÍÈçºÎµ¼Ö¸ɾ»¡¢·Ö²ãµÄÉè¼ÆÒÔ¼°Ó¦ÓóÌÐò¹Ø×¢µãÖ®¼äµÄ·ÖÀë¡£ ËüÃÇ»¹Ê¹ÅäÖøüС£¬ÒòΪÎÒÃDz»ÔÙÐèÒªÊÖ¶¯ÏÔʽ¶¨Òå bean¡£
+# SpringMVC×¢½â
+## 1. ¸ÅÊö
+ÔÚ±¾½Ì³ÌÖУ¬ÎÒÃǽ«Ì½Ë÷ org.springframework.web.bind.annotation °üÖÐµÄ Spring Web ×¢ÊÍ¡£
+
+## 2. @RequestMapping
+
+¼òµ¥µØËµ£¬@RequestMapping ±ê¼Ç@Controller ÀàÄÚ²¿µÄÇëÇó´¦Àí³ÌÐò·½·¨£» Ëü¿ÉÒÔʹÓÃÅäÖãº
+
+·¾¶£¬»òÆä±ðÃû¡¢Ãû³ÆºÍÖµ£º·½·¨Ó³Éäµ½Äĸö URL
+·½·¨£º¼æÈÝµÄ HTTP ·½·¨
+params£º¸ù¾Ý HTTP ²ÎÊýµÄ´æÔÚ¡¢²»´æÔÚ»òÖµ¹ýÂËÇëÇó
+headers£º¸ù¾Ý HTTP ±êÍ·µÄ´æÔÚ¡¢²»´æÔÚ»òÖµ¹ýÂËÇëÇó
+ÏûºÄ£º¸Ã·½·¨¿ÉÒÔÔÚ HTTP ÇëÇóÕýÎÄÖÐÏûºÄÄÄЩýÌåÀàÐÍ
+produces£º¸Ã·½·¨¿ÉÒÔÔÚ HTTP ÏìÓ¦ÕýÎÄÖÐÉú³ÉÄÄЩýÌåÀàÐÍ
+ÕâÊÇÒ»¸ö¼òµ¥µÄʾÀý£º
+
+````
+@Controller
+class VehicleController {
+
+ @RequestMapping(value = "/vehicles/home", method = RequestMethod.GET)
+ String home() {
+ return "home";
+ }
+}
+````
+Èç¹ûÎÒÃÇÔÚÀ༶±ðÓ¦ÓôË×¢ÊÍ£¬ÎÒÃÇ¿ÉÒÔΪ @Controller ÀàÖеÄËùÓд¦Àí³ÌÐò·½·¨ÌṩĬÈÏÉèÖᣠΨһµÄÀýÍâÊÇ Spring ²»»áʹÓ÷½·¨¼¶±ðÉèÖø²¸Çµ«»á¸½¼ÓÁ½¸ö·¾¶²¿·ÖµÄ URL¡£
+
+ÀýÈ磬ÏÂÃæµÄÅäÖúÍÉÏÃæµÄЧ¹ûÊÇÒ»ÑùµÄ£º
+
+````
+@Controller
+@RequestMapping(value = "/vehicles", method = RequestMethod.GET)
+class VehicleController {
+
+ @RequestMapping("/home")
+ String home() {
+ return "home";
+ }
+}
+````
+
+´ËÍ⣬@GetMapping¡¢@PostMapping¡¢@PutMapping¡¢@DeleteMapping ºÍ@PatchMapping ÊÇ@RequestMapping µÄ²»Í¬±äÌ壬ÆäHTTP ·½·¨ÒÑ·Ö±ðÉèÖÃΪGET¡¢POST¡¢PUT¡¢DELETE ºÍPATCH¡£
+
+ÕâЩ´Ó Spring 4.3 °æ±¾¿ªÊ¼¿ÉÓá£
+
+## 3 @RequestBody
+
+ÈÃÎÒÃǼÌÐø@RequestBody¡ª¡ªËü½« HTTP ÇëÇóµÄÖ÷ÌåÓ³Éäµ½Ò»¸ö¶ÔÏó£º
+
+````
+@PostMapping("/save")
+void saveVehicle(@RequestBody Vehicle vehicle) {
+// ...
+}
+````
+·´ÐòÁл¯ÊÇ×Ô¶¯µÄ£¬È¡¾öÓÚÇëÇóµÄÄÚÈÝÀàÐÍ¡£
+
+## 4 @PathVariable
+½ÓÏÂÀ´ËµËµ@PathVariable¡£
+
+´Ë×¢ÊÍָʾ·½·¨²ÎÊý°ó¶¨µ½ URI Ä£°å±äÁ¿¡£ ÎÒÃÇ¿ÉÒÔʹÓà @RequestMapping ×¢ÊÍÖ¸¶¨ URI Ä£°å£¬²¢Ê¹Óà @PathVariable ½«·½·¨²ÎÊý°ó¶¨µ½Ä£°å²¿·ÖÖ®Ò»¡£
+
+ÎÒÃÇ¿ÉÒÔʹÓÃÃû³Æ»òÆä±ðÃû£¬¼´Öµ²ÎÊýÀ´ÊµÏÖÕâÒ»µã£º
+
+````
+@RequestMapping("/{id}")
+Vehicle getVehicle(@PathVariable("id") long id) {
+// ...
+}
+````
+Èç¹ûÄ£°åÖв¿·ÖµÄÃû³ÆÓë·½·¨²ÎÊýµÄÃû³ÆÏàÆ¥Å䣬ÎÒÃǾͲ»±ØÔÚ×¢ÊÍÖÐÖ¸¶¨Ëü£º
+
+````
+@RequestMapping("/{id}")
+Vehicle getVehicle(@PathVariable long id) {
+// ...
+}
+````
+´ËÍ⣬ÎÒÃÇ¿ÉÒÔͨ¹ý½«ËùÐèµÄ²ÎÊýÉèÖÃΪ false À´½«Â·¾¶±äÁ¿±ê¼ÇΪ¿ÉÑ¡£º
+
+````
+@RequestMapping("/{id}")
+Vehicle getVehicle(@PathVariable(required = false) long id) {
+// ...
+}
+````
+## 5. @RequestParam
+We use @RequestParam for accessing HTTP request parameters:
+````
+@RequestMapping
+Vehicle getVehicleByParam(@RequestParam("id") long id) {
+// ...
+}
+````
+Ëü¾ßÓÐÓë @PathVariable ×¢ÊÍÏàͬµÄÅäÖÃÑ¡Ïî¡£
+
+³ýÁËÕâЩÉèÖÃÖ®Í⣬µ± Spring ÔÚÇëÇóÖз¢ÏÖûÓÐÖµ»òΪ¿Õֵʱ£¬ÎÒÃÇ¿ÉÒÔʹÓà @RequestParam Ö¸¶¨×¢ÈëÖµ¡£ Ϊ´Ë£¬ÎÒÃDZØÐëÉèÖà defaultValue ²ÎÊý¡£
+
+ÌṩĬÈÏÖµÒþʽÉèÖà required Ϊ false£º
+````
+@RequestMapping("/buy")
+Car buyCar(@RequestParam(defaultValue = "5") int seatCount) {
+// ...
+}
+````
+³ýÁ˲ÎÊýÖ®Í⣬ÎÒÃÇ»¹¿ÉÒÔ·ÃÎÊÆäËû HTTP ÇëÇ󲿷֣ºcookie ºÍ±êÍ·¡£
+
+ÎÒÃÇ¿ÉÒÔ·Ö±ðʹÓÃ×¢½â@CookieValue ºÍ@RequestHeader À´·ÃÎÊËüÃÇ¡£
+
+
+## 6. Response Handling Annotations
+ÔÚ½ÓÏÂÀ´µÄ²¿·ÖÖУ¬ÎÒÃǽ«¿´µ½ÔÚ Spring MVC ÖвÙ×÷ HTTP ÏìÓ¦µÄ×î³£¼û×¢ÊÍ¡£
+
+### 6.1 @ResponseBody
+Èç¹ûÎÒÃÇÓÃ@ResponseBody ±ê¼ÇÇëÇó´¦Àí³ÌÐò·½·¨£¬Spring »á½«·½·¨µÄ½á¹ûÊÓΪÏìÓ¦±¾Éí£º
+
+````
+@ResponseBody
+@RequestMapping("/hello")
+String hello() {
+return "Hello World!";
+}
+````
+Èç¹ûÎÒÃÇÓÃÕâ¸ö×¢½âÀ´×¢½â @Controller À࣬ËùÓÐÇëÇó´¦Àí³ÌÐò·½·¨¶¼½«Ê¹ÓÃËü¡£
+
+### 6.2 @ExceptionHandler
+
+ʹÓôË×¢ÊÍ£¬ÎÒÃÇ¿ÉÒÔÉùÃ÷Ò»¸ö×Ô¶¨Òå´íÎó´¦Àí³ÌÐò·½·¨¡£ µ±ÇëÇó´¦Àí³ÌÐò·½·¨Å׳öÈκÎÖ¸¶¨µÄÒ쳣ʱ£¬Spring µ÷Óô˷½·¨¡£
+
+²¶»ñµÄÒì³£¿ÉÒÔ×÷Ϊ²ÎÊý´«µÝ¸ø·½·¨£º
+````
+@ExceptionHandler(IllegalArgumentException.class)
+void onIllegalArgumentException(IllegalArgumentException exception) {
+// ...
+}
+````
+
+### 6.3 @ResponseStatus
+Èç¹ûÎÒÃÇʹÓôË×¢ÊͶÔÇëÇó´¦Àí³ÌÐò·½·¨½øÐÐ×¢ÊÍ£¬Ôò¿ÉÒÔÖ¸¶¨ÏìÓ¦µÄËùÐè HTTP ״̬¡£ ÎÒÃÇ¿ÉÒÔʹÓà code ²ÎÊý»òÆä±ðÃû value ²ÎÊýÀ´ÉùÃ÷״̬´úÂë¡£
+
+´ËÍ⣬ÎÒÃÇ¿ÉÒÔʹÓà reason ²ÎÊýÌṩÔÒò¡£
+
+ÎÒÃÇÒ²¿ÉÒÔ½«ËüÓë@ExceptionHandler Ò»ÆðʹÓãº
+
+@ExceptionHandler(IllegalArgumentException.class)
+@ResponseStatus(HttpStatus.BAD_REQUEST)
+void onIllegalArgumentException(IllegalArgumentException exception) {
+// ...
+}
+
+ÓÐ¹Ø HTTP ÏìӦ״̬µÄ¸ü¶àÐÅÏ¢£¬Çë·ÃÎʱ¾ÎÄ¡£
+
+## 7 ÆäËû Web×¢½â
+һЩעÊͲ»Ö±½Ó¹ÜÀí HTTP ÇëÇó»òÏìÓ¦¡£ ÔÚ½ÓÏÂÀ´µÄ²¿·ÖÖУ¬ÎÒÃǽ«½éÉÜ×î³£¼ûµÄ¡£
+
+### 7.1 @Controller
+ÎÒÃÇ¿ÉÒÔʹÓÃ@Controller ¶¨ÒåÒ»¸öSpring MVC ¿ØÖÆÆ÷¡£ Óйظü¶àÐÅÏ¢£¬Çë·ÃÎÊÎÒÃǹØÓÚ Spring Bean Annotations µÄÎÄÕ¡£
+
+### 7.2 @RestController
+@RestController ½áºÏÁË@Controller ºÍ@ResponseBody¡£
+
+Òò´Ë£¬ÒÔÏÂÉùÃ÷ÊǵÈЧµÄ£º
+
+````
+@Controller
+@ResponseBody
+class VehicleRestController {
+// ...
+}
+````
+
+````
+@RestController
+class VehicleRestController {
+// ...
+}
+````
+### 7.3 @ModelAttribute
+ͨ¹ýÕâ¸ö×¢½â£¬ÎÒÃÇ¿ÉÒÔͨ¹ýÌṩģÐͼüÀ´·ÃÎÊÒѾ´æÔÚÓÚ MVC @Controller Ä£ÐÍÖеÄÔªËØ£º
+
+````
+@PostMapping("/assemble")
+void assembleVehicle(@ModelAttribute("vehicle") Vehicle vehicleInModel) {
+// ...
+}
+````
+Óë@PathVariable ºÍ@RequestParam Ò»Ñù£¬Èç¹û²ÎÊý¾ßÓÐÏàͬµÄÃû³Æ£¬ÎÒÃDz»±ØÖ¸¶¨Ä£Ðͼü£º
+
+````
+@PostMapping("/assemble")
+void assembleVehicle(@ModelAttribute Vehicle vehicle) {
+// ...
+}
+````
+´ËÍ⣬@ModelAttribute»¹ÓÐÒ»¸öÓÃ;£ºÈç¹ûÎÒÃÇÓÃËü×¢½âÒ»¸ö·½·¨£¬Spring»á×Ô¶¯½«·½·¨µÄ·µ»ØÖµÌí¼Óµ½Ä£ÐÍÖУº
+
+````
+@ModelAttribute("vehicle")
+Vehicle getVehicle() {
+// ...
+}
+````
+ºÍÒÔǰһÑù£¬ÎÒÃDz»±ØÖ¸¶¨Ä£Ðͼü£¬Spring ĬÈÏʹÓ÷½·¨µÄÃû³Æ£º
+````
+@ModelAttribute
+Vehicle vehicle() {
+// ...
+}
+````
+ÔÚ Spring µ÷ÓÃÇëÇó´¦Àí³ÌÐò·½·¨Ö®Ç°£¬Ëü»áµ÷ÓÃÀàÖÐËùÓÐ @ModelAttribute ×¢Ê͵ķ½·¨¡£
+
+ÓÐ¹Ø @ModelAttribute µÄ¸ü¶àÐÅÏ¢£¬Çë²ÎÔı¾ÎÄ¡£
+
+### 7.4 @CrossOrigin
+@CrossOrigin Ϊ´ø×¢Ê͵ÄÇëÇó´¦Àí³ÌÐò·½·¨ÆôÓÿçÓòͨÐÅ£º
+
+````
+@CrossOrigin
+@RequestMapping("/hello")
+String hello() {
+return "Hello World!";
+}
+````
+Èç¹ûÎÒÃÇÓÃËü±ê¼ÇÒ»¸öÀ࣬ËüÊÊÓÃÓÚÆäÖеÄËùÓÐÇëÇó´¦Àí³ÌÐò·½·¨¡£
+
+ÎÒÃÇ¿ÉÒÔʹÓôË×¢Ê͵IJÎÊý΢µ÷ CORS ÐÐΪ¡£
+
+ÓйØÏêϸÐÅÏ¢£¬Çë·ÃÎʱ¾ÎÄ¡£
+
+# SpringBoot×¢½â
+## 1 ¸ÅÊö
+Spring Boot ͨ¹ýÆä×Ô¶¯ÅäÖù¦ÄÜʹÅäÖà Spring ±äµÃ¸ü¼ÓÈÝÒס£
+
+ÔÚ±¾¿ìËٽ̳ÌÖУ¬ÎÒÃǽ«Ì½Ë÷ org.springframework.boot.autoconfigure ºÍ org.springframework.boot.autoconfigure.condition °üÖеÄ×¢½â¡£
+
+## 2 @SpringBootApplication
+ÎÒÃÇʹÓÃÕâ¸ö×¢½âÀ´±ê¼Ç Spring Boot Ó¦ÓóÌÐòµÄÖ÷Àࣺ
+
+@SpringBootApplication
+ÎÒÃÇʹÓÃÕâ¸ö×¢½âÀ´±ê¼Ç Spring Boot Ó¦ÓóÌÐòµÄÖ÷Àࣺ
+````
+@SpringBootApplication
+class VehicleFactoryApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(VehicleFactoryApplication.class, args);
+ }
+}
+````
+@SpringBootApplication ·â×°ÁË@Configuration¡¢@EnableAutoConfiguration ºÍ@ComponentScan ×¢½â¼°ÆäĬÈÏÊôÐÔ¡£
+
+## 3 @EnableAutoConfiguration
+
+@EnableAutoConfiguration£¬¹ËÃû˼Ò壬ÆôÓÃ×Ô¶¯ÅäÖᣠÕâÒâζ×Å Spring Boot ÔÚÆäÀà·¾¶ÖвéÕÒ×Ô¶¯ÅäÖà bean ²¢×Ô¶¯Ó¦ÓÃËüÃÇ¡£
+
+Çë×¢Ò⣬ÎÒÃDZØÐ뽫´Ë×¢ÊÍÓë@Configuration Ò»ÆðʹÓãº
+
+````
+@Configuration
+@EnableAutoConfiguration
+class VehicleFactoryConfig {}
+````
+
+## 4 @ConfigurationÒÔ¼°Ïà¹ØÀà
+
+@ConfigurationµÄ×÷Ó㺱ê×¢ÔÚÀàÉÏ£¬ÅäÖÃspringÈÝÆ÷(Ó¦ÓÃÉÏÏÂÎÄ)¡£
+
+ÒÔÍùÎÒÃÇÔÚspringÖÐÅäÖÃbean»áʹÓõ½xmlÅäÖÃÎļþ£¬¶¨ÒåÒ»¸ö¸öbean£¬ÔÚspringbootÖУ¬ÎªÁË×öµ½ÁãÅäÖã¬spring¿ò¼ÜÌṩÁË@ConfigurationÕâÒ»×¢½â
+
+Ï൱ÓڰѸÃÀà×÷ΪspringµÄxmlÅäÖÃÎļþÖеÄ
+
+@Configuration×¢½âµÄÀàÖУ¬Ê¹ÓÃ@Bean×¢½â±ê×¢µÄ·½·¨£¬·µ»ØµÄÀàÐͶ¼»áÖ±½Ó×¢²áΪbean¡£
+
+@Configure×¢½âµÄ¶¨ÒåÈçÏ£º
+````
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Component
+public @interface Configuration {
+String value() default "";
+}
+````
+´Ó¶¨ÒåÀ´¿´£¬µ×²ãÊǺ¬ÓÐ@Component £¬ËùÒÔ@Configuration ¾ßÓÐºÍ @Component µÄ×÷Óá£Òò´Ëcontext:component-scan/»òÕß@ComponentScan¶¼ÄÜ´¦Àí@Configuration×¢½âµÄÀà¡£
+
+ͨ³££¬µ±ÎÒÃDZàд×Ô¶¨Òå×Ô¶¯ÅäÖÃʱ£¬ÎÒÃÇÏ£Íû Spring ÓÐÌõ¼þµØÊ¹ÓÃËüÃÇ¡£ ÎÒÃÇ¿ÉÒÔͨ¹ý±¾½ÚÖеÄ×¢ÊÍÀ´ÊµÏÖÕâÒ»µã¡£
+
+ÎÒÃÇ¿ÉÒÔ½«´Ë²¿·ÖÖеÄ×¢ÊÍ·ÅÔÚ@Configuration Àà»ò@Bean ·½·¨ÉÏ¡£
+
+ÔÚ½ÓÏÂÀ´µÄ²¿·ÖÖУ¬ÎÒÃǽ«Ö»½éÉÜÿ¸öÌõ¼þ±³ºóµÄ»ù±¾¸ÅÄî¡£ ÓûÁ˽â¸ü¶àÐÅÏ¢£¬Çë·ÃÎÊÕâÆªÎÄÕ¡£
+
+### 4.1 @ConditionalOnClass and @ConditionalOnMissingClass
+ºÜÃ÷ÏÔÕâÊÇÒ»¸ö´øÓÐÌõ¼þÅжϵÄÅäÖÃ×¢½â£¬ÒªÖªµÀ£¬ºÜ¶àʱºòÎÒÃǰ´Ðè¼ÓÔØbeanµÄ£¬ÉõÖÁÊǸù¾ÝÍⲿjar°üÊÇ·ñ´æÔÚÀ´½øÐмÓÔØºÍÅжϵġ£
+
+ÕâÖÖʱºò£¬¾ÍÒª¸ù¾ÝÍⲿÀàÊÇ·ñ´æÔÚÀ´¾ö¶¨ÊÇ·ñÊÇ·ñ¼ÓÔØ¸Ãbean
+
+ʹÓÃÕâЩÌõ¼þ£¬Èç¹û×¢ÊͲÎÊýÖеÄÀà´æÔÚ/²»´æÔÚ£¬Spring ½«½öʹÓñê¼ÇµÄ×Ô¶¯ÅäÖà bean£º
+
+````
+@Configuration
+@ConditionalOnClass(DataSource.class)
+class MySQLAutoconfiguration {
+//...
+}
+````
+
+### 4.2 @ConditionalOnBean and @ConditionalOnMissingBean
+
+µ±ÎÒÃÇÏëÒª¸ù¾ÝÌØ¶¨ bean µÄ´æÔÚ»ò²»´æÔÚÀ´¶¨ÒåÌõ¼þʱ£¬ÎÒÃÇ¿ÉÒÔʹÓÃÕâЩעÊÍ£º
+
+ºÍÉÏÃæÒ»¸ö×¢½âÉÔÓÐЩ²»Í¬£¬ÒòΪÎÒÃǵÄÅжÏÌõ¼þ±ä³ÉÁËbean
+
+````
+@Bean
+@ConditionalOnBean(name = "dataSource")
+LocalContainerEntityManagerFactoryBean entityManagerFactory() {
+// ...
+}
+````
+### 4.3 @ConditionalOnProperty
+ͨ¹ýÕâ¸ö×¢½â£¬ÎÒÃÇ¿ÉÒÔ¶ÔÊôÐÔµÄÖµÉèÖÃÌõ¼þ
+
+ҪעÒ⣬ÕâÀïµÄÊôÐÔÖµÀ´Ô´ÓÚapplication.propertiesÎļþÖеÄÅäÖÃ
+
+````
+@Bean
+@ConditionalOnProperty(
+name = "usemysql",
+havingValue = "local"
+)
+DataSource dataSource() {
+// ...
+}
+````
+
+### 4.4 @ConditionalOnResource
+
+ÎÒÃÇ¿ÉÒÔÈà Spring ½öÔÚ´æÔÚÌØ¶¨×ÊԴʱʹÓö¨Ò壺
+¹ËÃû˼Ò壬ҪÇóclasspath´æÔÚÕâ¸ö×ÊÔ´Îļþʱ²Å½øÐмÓÔØ£¬ÕâÒ²ÊǺܳ£ÓõÄÒ»¸ö×¢½â¡£
+
+````
+
+@ConditionalOnResource(resources = "classpath:mysql.properties")
+Properties ditionalProperties() {
+// ...
+}
+````
+
+### 4.5 @ConditionalOnWebApplication and @ConditionalOnNotWebApplication
+Õâ¸ö×¢½âͨ³£ÓÃÓÚºÍwebÓÐÇ¿¹ØÁª£¬»òÕßÍêÈ«ÎÞ¹ØÁªµÄÅäÖÃÉÏ
+
+ʹÓÃÕâЩעÊÍ£¬ÎÒÃÇ¿ÉÒÔ¸ù¾Ýµ±Ç°Ó¦ÓóÌÐòÊÇ·ñÊÇ Web Ó¦ÓóÌÐòÀ´´´½¨Ìõ¼þ£º
+````
+
+@ConditionalOnWebApplication
+HealthCheckController healthCheckController() {
+// ...
+}
+````
+
+### 4.6 @ConditionalExpression
+springbootÕæµÄΪÎÒÃÇÏëµ½ÁËËùÓÐÇé¿ö£¬Èç¹ûÉÏÃæµÄ×¢½â»¹²»ÄÜÂú×ãÄãµÄÒªÇó£¬ÄÇô¸É´à¾ÍÈÃÄã×Ô¼ºÐ´£¬ÕâÏÂÓ¦¸ÃûÓÐÎÊÌâ°É£¿
+
+ÎÒÃÇ¿ÉÒÔÔÚ¸ü¸´ÔÓµÄÇé¿öÏÂʹÓÃÕâ¸ö×¢½â¡£ µ± SpEL ±í´ïʽ±»ÆÀ¹ÀÎªÕæÊ±£¬Spring ½«Ê¹Óñê¼ÇµÄ¶¨Ò壺
+
+````
+@Bean
+@ConditionalOnExpression("${usemysql} && ${mysqlserver == 'local'}")
+DataSource dataSource() {
+// ...
+}
+````
+
+### 4.7 @Conditional
+ʲô£¬»¹ÓÐÎÊÌ⣿
+ÄÇspringbootÒ²²»ÔÙÌṩʲô±í´ïʽ¸øÄãÁË£¬Ö±½ÓÈÃÓû§Ð´Ò»¸öÅжÏÌõ¼þ£¬¸æËßÎÒtrue»òÕßfalse¾ÍÐÐÁË
+
+¶ÔÓÚ¸ü¸´ÔÓµÄÌõ¼þ£¬ÎÒÃÇ¿ÉÒÔ´´½¨Ò»¸öÆÀ¹À×Ô¶¨ÒåÌõ¼þµÄÀà¡£ ÎÒÃǸæËß Spring ½«Õâ¸ö×Ô¶¨ÒåÌõ¼þÓë @Conditional Ò»ÆðʹÓãº
+
+````
+@Conditional(HibernateCondition.class)
+Properties ditionalProperties() {
+//...
+}
+````
+
+## 5 ×ܽá
+ÔÚ±¾ÎÄÖУ¬ÎÒÃǸÅÊöÁËÈçºÎ΢µ÷×Ô¶¯ÅäÖùý³Ì²¢Îª×Ô¶¨Òå×Ô¶¯ÅäÖà bean ÌṩÌõ¼þ¡£
+
+# ²Î¿¼ÎÄÕÂ
+https://www.baeldung.com/spring-annotations
diff --git "a/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\225\260\346\215\256\345\272\223\347\232\204\350\256\277\351\227\256.md" "b/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\225\260\346\215\256\345\272\223\347\232\204\350\256\277\351\227\256.md"
new file mode 100644
index 0000000..69bfc96
--- /dev/null
+++ "b/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\225\260\346\215\256\345\272\223\347\232\204\350\256\277\351\227\256.md"
@@ -0,0 +1,1183 @@
+
+## ÅäÖÃÊý¾ÝÔ´
+
+### Spring ÅäÖÃÊý¾ÝÔ´
+
+Spring ÅäÖÃÊý¾ÝÔ´ÓжàÖÖ·½Ê½£¬ÏÂÃæÒ»Ò»Áо٣º
+
+#### [#](https://dunwu.github.io/spring-tutorial/pages/1b774c/#%E4%BD%BF%E7%94%A8-jndi-%E6%95%B0%E6%8D%AE%E6%BA%90)ʹÓà JNDI Êý¾ÝÔ´
+
+Èç¹û Spring Ó¦Óò¿ÊðÔÚÖ§³Ö JNDI µÄ WEB ·þÎñÆ÷ÉÏ£¨Èç WebSphere¡¢JBoss¡¢Tomcat µÈ£©£¬¾Í¿ÉÒÔʹÓà JNDI »ñÈ¡Êý¾ÝÔ´¡£
+
+
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+
+
+#### [#](https://dunwu.github.io/spring-tutorial/pages/1b774c/#%E4%BD%BF%E7%94%A8%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0)ʹÓÃÊý¾Ý¿âÁ¬½Ó³Ø
+
+Spring ±¾Éí²¢Ã»ÓÐÌṩÊý¾Ý¿âÁ¬½Ó³ØµÄʵÏÖ£¬ÐèÒª×ÔÐÐÑ¡ÔñºÏÊʵÄÊý¾Ý¿âÁ¬½Ó³Ø¡£ÏÂÃæÊÇÒ»¸öʹÓà [Druid (opens new window)](https://github.com/alibaba/druid)×÷ΪÊý¾Ý¿âÁ¬½Ó³ØµÄʾÀý£º
+
+
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+
+
+#### [#](https://dunwu.github.io/spring-tutorial/pages/1b774c/#%E5%9F%BA%E4%BA%8E-jdbc-%E9%A9%B1%E5%8A%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E6%BA%90)»ùÓÚ JDBC Çý¶¯µÄÊý¾ÝÔ´
+
+
+
+```
+
+
+
+
+
+
+```
+
+
+#### ʹÓÃJDBC
+
+×îºó¸üÐÂ: 2022/11/16 20:10 / ÔĶÁ: 946668
+
+* * *
+
+
+
+ÎÒÃÇÔÚÇ°Ãæ½éÉÜ[JDBC±à³Ì](https://www.liaoxuefeng.com/wiki/1252599548343744/1255943820274272)ʱÒѾ½²¹ý£¬Java³ÌÐòʹÓÃJDBC½Ó¿Ú·ÃÎʹØÏµÊý¾Ý¿âµÄʱºò£¬ÐèÒªÒÔϼ¸²½£º
+
+* ´´½¨È«¾Ö`DataSource`ʵÀý£¬±íʾÊý¾Ý¿âÁ¬½Ó³Ø£»
+* ÔÚÐèÒª¶ÁдÊý¾Ý¿âµÄ·½·¨ÄÚ²¿£¬°´Èçϲ½Öè·ÃÎÊÊý¾Ý¿â£º
+ * ´ÓÈ«¾Ö`DataSource`ʵÀý»ñÈ¡`Connection`ʵÀý£»
+ * ͨ¹ý`Connection`ʵÀý´´½¨`PreparedStatement`ʵÀý£»
+ * Ö´ÐÐSQLÓï¾ä£¬Èç¹ûÊDzéѯ£¬Ôòͨ¹ý`ResultSet`¶ÁÈ¡½á¹û¼¯£¬Èç¹ûÊÇÐ޸ģ¬Ôò»ñµÃ`int`½á¹û¡£
+
+ÕýÈ·±àдJDBC´úÂëµÄ¹Ø¼üÊÇʹÓÃ`try ... finally`ÊÍ·Å×ÊÔ´£¬Éæ¼°µ½ÊÂÎñµÄ´úÂëÐèÒªÕýÈ·Ìá½»»ò»Ø¹öÊÂÎñ¡£
+
+ÔÚSpringʹÓÃJDBC£¬Ê×ÏÈÎÒÃÇͨ¹ýIoCÈÝÆ÷´´½¨²¢¹ÜÀíÒ»¸ö`DataSource`ʵÀý£¬È»ºó£¬SpringÌṩÁËÒ»¸ö`JdbcTemplate`£¬¿ÉÒÔ·½±ãµØÈÃÎÒÃDzÙ×÷JDBC£¬Òò´Ë£¬Í¨³£Çé¿öÏ£¬ÎÒÃÇ»áʵÀý»¯Ò»¸ö`JdbcTemplate`¡£¹ËÃû˼Ò壬Õâ¸öÀàÖ÷ҪʹÓÃÁË[Templateģʽ](https://www.liaoxuefeng.com/wiki/1252599548343744/1281319636041762)¡£
+
+±àдʾÀý´úÂë»òÕß²âÊÔ´úÂëʱ£¬ÎÒÃÇÇ¿ÁÒÍÆ¼öʹÓÃ[HSQLDB](http://hsqldb.org/)Õâ¸öÊý¾Ý¿â£¬ËüÊÇÒ»¸öÓÃJava±àдµÄ¹ØÏµÊý¾Ý¿â£¬¿ÉÒÔÒÔÄÚ´æÄ£Ê½»òÕßÎļþģʽÔËÐУ¬±¾ÉíÖ»ÓÐÒ»¸öjar°ü£¬·Ç³£ÊʺÏÑÝʾ´úÂë»òÕß²âÊÔ´úÂë¡£
+
+ÎÒÃÇÒÔʵ¼Ê¹¤³ÌΪÀý£¬ÏÈ´´½¨Maven¹¤³Ì`spring-data-jdbc`£¬È»ºóÒýÈëÒÔÏÂÒÀÀµ£º
+
+* org.springframework:spring-context:6.0.0
+* org.springframework:spring-jdbc:6.0.0
+* jakarta.annotation:jakarta.annotation-api:2.1.1
+* com.zaxxer:HikariCP:5.0.1
+* org.hsqldb:hsqldb:2.7.1
+
+ÔÚ`AppConfig`ÖУ¬ÎÒÃÇÐèÒª´´½¨ÒÔϼ¸¸ö±ØÐëµÄBean£º
+
+```
+@Configuration
+@ComponentScan
+@PropertySource("jdbc.properties")
+public class AppConfig {
+
+ @Value("${jdbc.url}")
+ String jdbcUrl;
+
+ @Value("${jdbc.username}")
+ String jdbcUsername;
+
+ @Value("${jdbc.password}")
+ String jdbcPassword;
+
+ @Bean
+ DataSource createDataSource() {
+ HikariConfig config = new HikariConfig();
+ config.setJdbcUrl(jdbcUrl);
+ config.setUsername(jdbcUsername);
+ config.setPassword(jdbcPassword);
+ config.addDataSourceProperty("autoCommit", "true");
+ config.addDataSourceProperty("connectionTimeout", "5");
+ config.addDataSourceProperty("idleTimeout", "60");
+ return new HikariDataSource(config);
+ }
+
+ @Bean
+ JdbcTemplate createJdbcTemplate(@Autowired DataSource dataSource) {
+ return new JdbcTemplate(dataSource);
+ }
+}
+
+```
+
+ÔÚÉÏÊöÅäÖÃÖУº
+
+1. ͨ¹ý`@PropertySource("jdbc.properties")`¶ÁÈ¡Êý¾Ý¿âÅäÖÃÎļþ£»
+2. ͨ¹ý`@Value("${jdbc.url}")`×¢ÈëÅäÖÃÎļþµÄÏà¹ØÅäÖã»
+3. ´´½¨Ò»¸öDataSourceʵÀý£¬ËüµÄʵ¼ÊÀàÐÍÊÇ`HikariDataSource`£¬´´½¨Ê±ÐèÒªÓõ½×¢ÈëµÄÅäÖã»
+4. ´´½¨Ò»¸öJdbcTemplateʵÀý£¬ËüÐèҪעÈë`DataSource`£¬ÕâÊÇͨ¹ý·½·¨²ÎÊýÍê³É×¢ÈëµÄ¡£
+
+×îºó£¬Õë¶ÔHSQLDBдһ¸öÅäÖÃÎļþ`jdbc.properties`£º
+
+```
+# Êý¾Ý¿âÎļþÃûΪtestdb:
+jdbc.url=jdbc:hsqldb:file:testdb
+
+# HsqldbĬÈϵÄÓû§ÃûÊÇsa£¬¿ÚÁîÊÇ¿Õ×Ö·û´®:
+jdbc.username=sa
+jdbc.password=
+
+```
+
+¿ÉÒÔͨ¹ýHSQLDB×Ô´øµÄ¹¤¾ßÀ´³õʼ»¯Êý¾Ý¿â±í£¬ÕâÀïÎÒÃÇдһ¸öBean£¬ÔÚSpringÈÝÆ÷Æô¶¯Ê±×Ô¶¯´´½¨Ò»¸ö`users`±í£º
+
+```
+@Component
+public class DatabaseInitializer {
+ @Autowired
+ JdbcTemplate jdbcTemplate;
+
+ @PostConstruct
+ public void init() {
+ jdbcTemplate.update("CREATE TABLE IF NOT EXISTS users (" //
+ + "id BIGINT IDENTITY NOT NULL PRIMARY KEY, " //
+ + "email VARCHAR(100) NOT NULL, " //
+ + "password VARCHAR(100) NOT NULL, " //
+ + "name VARCHAR(100) NOT NULL, " //
+ + "UNIQUE (email))");
+ }
+}
+
+```
+
+ÏÖÔÚ£¬ËùÓÐ×¼±¸¹¤×÷¶¼ÒÑÍê±Ï¡£ÎÒÃÇÖ»ÐèÒªÔÚÐèÒª·ÃÎÊÊý¾Ý¿âµÄBeanÖУ¬×¢Èë`JdbcTemplate`¼´¿É£º
+
+```
+@Component
+public class UserService {
+ @Autowired
+ JdbcTemplate jdbcTemplate;
+ ...
+}
+
+```
+
+### JdbcTemplateÓ÷¨
+
+SpringÌṩµÄ`JdbcTemplate`²ÉÓÃTemplateģʽ£¬ÌṩÁËһϵÁÐÒԻص÷ÎªÌØµãµÄ¹¤¾ß·½·¨£¬Ä¿µÄÊDZÜÃâ·±ËöµÄ`try...catch`Óï¾ä¡£
+
+ÎÒÃÇÒÔ¾ßÌåµÄʾÀýÀ´ËµÃ÷JdbcTemplateµÄÓ÷¨¡£
+
+Ê×ÏÈÎÒÃÇ¿´`T execute(ConnectionCallback action)`·½·¨£¬ËüÌṩÁËJdbcµÄ`Connection`¹©ÎÒÃÇʹÓãº
+
+```
+public User getUserById(long id) {
+ // ×¢Òâ´«ÈëµÄÊÇConnectionCallback:
+ return jdbcTemplate.execute((Connection conn) -> {
+ // ¿ÉÒÔÖ±½ÓʹÓÃconnʵÀý£¬²»ÒªÊÍ·ÅËü£¬»Øµ÷½áÊøºóJdbcTemplate×Ô¶¯ÊÍ·Å:
+ // ÔÚÄÚ²¿ÊÖ¶¯´´½¨µÄPreparedStatement¡¢ResultSet±ØÐëÓÃtry(...)ÊÍ·Å:
+ try (var ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?")) {
+ ps.setObject(1, id);
+ try (var rs = ps.executeQuery()) {
+ if (rs.next()) {
+ return new User( // new User object:
+ rs.getLong("id"), // id
+ rs.getString("email"), // email
+ rs.getString("password"), // password
+ rs.getString("name")); // name
+ }
+ throw new RuntimeException("user not found by id.");
+ }
+ }
+ });
+}
+
+```
+
+Ò²¾ÍÊÇ˵£¬ÉÏÊö»Øµ÷·½·¨ÔÊÐí»ñÈ¡Connection£¬È»ºó×öÈκλùÓÚConnectionµÄ²Ù×÷¡£
+
+ÎÒÃÇÔÙ¿´`T execute(String sql, PreparedStatementCallback action)`µÄÓ÷¨£º
+
+```
+public User getUserByName(String name) {
+ // ÐèÒª´«ÈëSQLÓï¾ä£¬ÒÔ¼°PreparedStatementCallback:
+ return jdbcTemplate.execute("SELECT * FROM users WHERE name = ?", (PreparedStatement ps) -> {
+ // PreparedStatementʵÀýÒѾÓÉJdbcTemplate´´½¨£¬²¢Ôڻص÷ºó×Ô¶¯ÊÍ·Å:
+ ps.setObject(1, name);
+ try (var rs = ps.executeQuery()) {
+ if (rs.next()) {
+ return new User( // new User object:
+ rs.getLong("id"), // id
+ rs.getString("email"), // email
+ rs.getString("password"), // password
+ rs.getString("name")); // name
+ }
+ throw new RuntimeException("user not found by id.");
+ }
+ });
+}
+
+```
+
+×îºó£¬ÎÒÃÇ¿´`T queryForObject(String sql, RowMapper rowMapper, Object... args)`·½·¨£º
+
+```
+public User getUserByEmail(String email) {
+ // ´«ÈëSQL£¬²ÎÊýºÍRowMapperʵÀý:
+ return jdbcTemplate.queryForObject("SELECT * FROM users WHERE email = ?",
+ (ResultSet rs, int rowNum) -> {
+ // ½«ResultSetµÄµ±Ç°ÐÐÓ³ÉäΪһ¸öJavaBean:
+ return new User( // new User object:
+ rs.getLong("id"), // id
+ rs.getString("email"), // email
+ rs.getString("password"), // password
+ rs.getString("name")); // name
+ },
+ email);
+}
+
+```
+
+ÔÚ`queryForObject()`·½·¨ÖУ¬´«ÈëSQLÒÔ¼°SQL²ÎÊýºó£¬`JdbcTemplate`»á×Ô¶¯´´½¨`PreparedStatement`£¬×Ô¶¯Ö´Ðвéѯ²¢·µ»Ø`ResultSet`£¬ÎÒÃÇÌṩµÄ`RowMapper`ÐèÒª×öµÄÊÂÇé¾ÍÊǰÑ`ResultSet`µÄµ±Ç°ÐÐÓ³Éä³ÉÒ»¸öJavaBean²¢·µ»Ø¡£Õû¸ö¹ý³ÌÖУ¬Ê¹ÓÃ`Connection`¡¢`PreparedStatement`ºÍ`ResultSet`¶¼²»ÐèÒªÎÒÃÇÊÖ¶¯¹ÜÀí¡£
+
+`RowMapper`²»Ò»¶¨·µ»ØJavaBean£¬Êµ¼ÊÉÏËü¿ÉÒÔ·µ»ØÈκÎJava¶ÔÏó¡£ÀýÈ磬ʹÓÃ`SELECT COUNT(*)`²éѯʱ£¬¿ÉÒÔ·µ»Ø`Long`£º
+
+```
+public long getUsers() {
+ return jdbcTemplate.queryForObject("SELECT COUNT(*) FROM users", (ResultSet rs, int rowNum) -> {
+ // SELECT COUNT(*)²éѯֻÓÐÒ»ÁУ¬È¡µÚÒ»ÁÐÊý¾Ý:
+ return rs.getLong(1);
+ });
+}
+
+```
+
+Èç¹ûÎÒÃÇÆÚÍû·µ»Ø¶àÐмǼ£¬¶ø²»ÊÇÒ»ÐУ¬¿ÉÒÔÓÃ`query()`·½·¨£º
+
+```
+public List getUsers(int pageIndex) {
+ int limit = 100;
+ int offset = limit * (pageIndex - 1);
+ return jdbcTemplate.query("SELECT * FROM users LIMIT ? OFFSET ?",
+ new BeanPropertyRowMapper<>(User.class),
+ limit, offset);
+}
+
+```
+
+ÉÏÊö`query()`·½·¨´«ÈëµÄ²ÎÊýÈÔÈ»ÊÇSQL¡¢SQL²ÎÊýÒÔ¼°`RowMapper`ʵÀý¡£ÕâÀïÎÒÃÇÖ±½ÓʹÓÃSpringÌṩµÄ`BeanPropertyRowMapper`¡£Èç¹ûÊý¾Ý¿â±íµÄ½á¹¹Ç¡ºÃºÍJavaBeanµÄÊôÐÔÃû³ÆÒ»Ö£¬ÄÇô`BeanPropertyRowMapper`¾Í¿ÉÒÔÖ±½Ó°ÑÒ»ÐмǼ°´ÁÐÃûת»»ÎªJavaBean¡£
+
+Èç¹ûÎÒÃÇÖ´ÐеIJ»ÊDzéѯ£¬¶øÊDzåÈë¡¢¸üкÍɾ³ý²Ù×÷£¬ÄÇôÐèҪʹÓÃ`update()`·½·¨£º
+
+```
+public void updateUser(User user) {
+ // ´«ÈëSQL£¬SQL²ÎÊý£¬·µ»Ø¸üеÄÐÐÊý:
+ if (1 != jdbcTemplate.update("UPDATE users SET name = ? WHERE id = ?", user.getName(), user.getId())) {
+ throw new RuntimeException("User not found by id");
+ }
+}
+
+```
+
+Ö»ÓÐÒ»ÖÖ`INSERT`²Ù×÷±È½ÏÌØÊ⣬ÄǾÍÊÇÈç¹ûijһÁÐÊÇ×ÔÔöÁУ¨ÀýÈç×ÔÔöÖ÷¼ü£©£¬Í¨³££¬ÎÒÃÇÐèÒª»ñÈ¡²åÈëºóµÄ×ÔÔöÖµ¡£`JdbcTemplate`ÌṩÁËÒ»¸ö`KeyHolder`À´¼ò»¯ÕâÒ»²Ù×÷£º
+
+```
+public User register(String email, String password, String name) {
+ // ´´½¨Ò»¸öKeyHolder:
+ KeyHolder holder = new GeneratedKeyHolder();
+ if (1 != jdbcTemplate.update(
+ // ²ÎÊý1:PreparedStatementCreator
+ (conn) -> {
+ // ´´½¨PreparedStatementʱ£¬±ØÐëÖ¸¶¨RETURN_GENERATED_KEYS:
+ var ps = conn.prepareStatement("INSERT INTO users(email, password, name) VALUES(?, ?, ?)",
+ Statement.RETURN_GENERATED_KEYS);
+ ps.setObject(1, email);
+ ps.setObject(2, password);
+ ps.setObject(3, name);
+ return ps;
+ },
+ // ²ÎÊý2:KeyHolder
+ holder)
+ ) {
+ throw new RuntimeException("Insert failed.");
+ }
+ // ´ÓKeyHolderÖлñÈ¡·µ»ØµÄ×ÔÔöÖµ:
+ return new User(holder.getKey().longValue(), email, password, name);
+}
+
+```
+
+`JdbcTemplate`»¹ÓÐÐí¶àÖØÔØ·½·¨£¬ÕâÀïÎÒÃDz»Ò»Ò»½éÉÜ¡£ÐèҪǿµ÷µÄÊÇ£¬`JdbcTemplate`Ö»ÊǶÔJDBC²Ù×÷µÄÒ»¸ö¼òµ¥·â×°£¬ËüµÄÄ¿µÄÊǾ¡Á¿¼õÉÙÊÖ¶¯±àд`try(resource) {...}`µÄ´úÂ룬¶ÔÓÚ²éѯ£¬Ö÷Ҫͨ¹ý`RowMapper`ʵÏÖÁËJDBC½á¹û¼¯µ½Java¶ÔÏóµÄת»»¡£
+
+ÎÒÃÇ×ܽáÒ»ÏÂ`JdbcTemplate`µÄÓ÷¨£¬ÄǾÍÊÇ£º
+
+* Õë¶Ô¼òµ¥²éѯ£¬ÓÅÑ¡`query()`ºÍ`queryForObject()`£¬ÒòΪֻÐèÌṩSQLÓï¾ä¡¢²ÎÊýºÍ`RowMapper`£»
+* Õë¶Ô¸üвÙ×÷£¬ÓÅÑ¡`update()`£¬ÒòΪֻÐèÌṩSQLÓï¾äºÍ²ÎÊý£»
+* Èκθ´ÔӵIJÙ×÷£¬×îÖÕÒ²¿ÉÒÔͨ¹ý`execute(ConnectionCallback)`ʵÏÖ£¬ÒòΪÄõ½`Connection`¾Í¿ÉÒÔ×öÈκÎJDBC²Ù×÷¡£
+
+ʵ¼ÊÉÏÎÒÃÇʹÓÃ×î¶àµÄÈÔÈ»ÊǸ÷ÖÖ²éѯ¡£Èç¹ûÔÚÉè¼Æ±í½á¹¹µÄʱºò£¬Äܹ»ºÍJavaBeanµÄÊôÐÔÒ»Ò»¶ÔÓ¦£¬ÄÇôֱ½ÓʹÓÃ`BeanPropertyRowMapper`¾ÍºÜ·½±ã¡£Èç¹û±í½á¹¹ºÍJavaBean²»Ò»ÖÂÔõô°ì£¿ÄǾÍÐèÒªÉÔ΢¸Äдһϲéѯ£¬Ê¹½á¹û¼¯µÄ½á¹¹ºÍJavaBean±£³ÖÒ»Ö¡£
+
+ÀýÈ磬±íµÄÁÐÃûÊÇ`office_address`£¬¶øJavaBeanÊôÐÔÊÇ`workAddress`£¬¾ÍÐèÒªÖ¸¶¨±ðÃû£¬¸Äд²éѯÈçÏ£º
+
+```
+SELECT id, email, office_address AS workAddress, name FROM users WHERE email = ?
+```
+
+ʹÓÃ`JdbcTemplate`µÄʱºò£¬ÎÒÃÇÓõÃ×î¶àµÄ·½·¨¾ÍÊÇ`List query(String, RowMapper, Object...)`¡£Õâ¸ö`RowMapper`µÄ×÷ÓþÍÊǰÑ`ResultSet`µÄÒ»ÐмǼӳÉäΪJava Bean¡£
+
+ÕâÖְѹØÏµÊý¾Ý¿âµÄ±í¼Ç¼ӳÉäΪJava¶ÔÏóµÄ¹ý³Ì¾ÍÊÇORM£ºObject-Relational Mapping¡£ORM¼È¿ÉÒ԰ѼǼת»»³ÉJava¶ÔÏó£¬Ò²¿ÉÒÔ°ÑJava¶ÔÏóת»»ÎªÐмǼ¡£
+
+ʹÓÃ`JdbcTemplate`ÅäºÏ`RowMapper`¿ÉÒÔ¿´×÷ÊÇ×îÔʼµÄORM¡£Èç¹ûҪʵÏÖ¸ü×Ô¶¯»¯µÄORM£¬¿ÉÒÔÑ¡Ôñ³ÉÊìµÄORM¿ò¼Ü£¬ÀýÈç[Hibernate](https://hibernate.org/)¡£
+
+ÎÒÃÇÀ´¿´¿´ÈçºÎÔÚSpringÖм¯³ÉHibernate¡£
+
+Hibernate×÷ΪORM¿ò¼Ü£¬Ëü¿ÉÒÔÌæ´ú`JdbcTemplate`£¬µ«HibernateÈÔÈ»ÐèÒªJDBCÇý¶¯£¬ËùÒÔ£¬ÎÒÃÇÐèÒªÒýÈëJDBCÇý¶¯¡¢Á¬½Ó³Ø£¬ÒÔ¼°Hibernate±¾Éí¡£ÔÚMavenÖУ¬ÎÒÃǼÓÈëÒÔÏÂÒÀÀµÏ
+
+* org.springframework:spring-context:6.0.0
+* org.springframework:spring-orm:6.0.0
+* jakarta.annotation:jakarta.annotation-api:2.1.1
+* jakarta.persistence:jakarta.persistence-api:3.1.0
+* org.hibernate:hibernate-core:6.1.4.Final
+* com.zaxxer:HikariCP:5.0.1
+* org.hsqldb:hsqldb:2.7.1
+
+ÔÚ`AppConfig`ÖУ¬ÎÒÃÇÈÔÈ»ÐèÒª´´½¨`DataSource`¡¢ÒýÈëJDBCÅäÖÃÎļþ£¬ÒÔ¼°ÆôÓÃÉùÃ÷ʽÊÂÎñ£º
+
+```
+@Configuration
+@ComponentScan
+@EnableTransactionManagement
+@PropertySource("jdbc.properties")
+public class AppConfig {
+ @Bean
+ DataSource createDataSource() {
+ ...
+ }
+}
+
+```
+
+ΪÁËÆôÓÃHibernate£¬ÎÒÃÇÐèÒª´´½¨Ò»¸ö`LocalSessionFactoryBean`£º
+
+```
+public class AppConfig {
+ @Bean
+ LocalSessionFactoryBean createSessionFactory(@Autowired DataSource dataSource) {
+ var props = new Properties();
+ props.setProperty("hibernate.hbm2ddl.auto", "update"); // Éú²ú»·¾³²»ÒªÊ¹ÓÃ
+ props.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
+ props.setProperty("hibernate.show_sql", "true");
+ var sessionFactoryBean = new LocalSessionFactoryBean();
+ sessionFactoryBean.setDataSource(dataSource);
+ // ɨÃèÖ¸¶¨µÄpackage»ñÈ¡ËùÓÐentity class:
+ sessionFactoryBean.setPackagesToScan("com.itranswarp.learnjava.entity");
+ sessionFactoryBean.setHibernateProperties(props);
+ return sessionFactoryBean;
+ }
+}
+
+```
+
+×¢ÒâÎÒÃÇÔÚ[¶¨ÖÆBean](https://www.liaoxuefeng.com/wiki/1252599548343744/1308043627200545)Öн²µ½¹ý`FactoryBean`£¬`LocalSessionFactoryBean`ÊÇÒ»¸ö`FactoryBean`£¬Ëü»áÔÙ×Ô¶¯´´½¨Ò»¸ö`SessionFactory`£¬ÔÚHibernateÖУ¬`Session`ÊÇ·â×°ÁËÒ»¸öJDBC `Connection`µÄʵÀý£¬¶ø`SessionFactory`ÊÇ·â×°ÁËJDBC `DataSource`µÄʵÀý£¬¼´`SessionFactory`³ÖÓÐÁ¬½Ó³Ø£¬Ã¿´ÎÐèÒª²Ù×÷Êý¾Ý¿âµÄʱºò£¬`SessionFactory`´´½¨Ò»¸öеÄ`Session`£¬Ï൱ÓÚ´ÓÁ¬½Ó³Ø»ñÈ¡µ½Ò»¸öеÄ`Connection`¡£`SessionFactory`¾ÍÊÇHibernateÌṩµÄ×îºËÐĵÄÒ»¸ö¶ÔÏ󣬵«`LocalSessionFactoryBean`ÊÇSpringÌṩµÄΪÁËÈÃÎÒÃÇ·½±ã´´½¨`SessionFactory`µÄÀà¡£
+
+×¢Òâµ½ÉÏÃæ´´½¨`LocalSessionFactoryBean`µÄ´úÂ룬Ê×ÏÈÓÃ`Properties`³ÖÓÐHibernate³õʼ»¯`SessionFactory`ʱÓõ½µÄËùÓÐÉèÖ㬳£ÓõÄÉèÖÃÇë²Î¿¼[HibernateÎĵµ](https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#configurations)£¬ÕâÀïÎÒÃÇÖ»¶¨ÒåÁË3¸öÉèÖãº
+
+* `hibernate.hbm2ddl.auto=update`£º±íʾ×Ô¶¯´´½¨Êý¾Ý¿âµÄ±í½á¹¹£¬×¢Òâ²»ÒªÔÚÉú²ú»·¾³ÖÐÆôÓã»
+* `hibernate.dialect=org.hibernate.dialect.HSQLDialect`£ºÖ¸Ê¾HibernateʹÓõÄÊý¾Ý¿âÊÇHSQLDB¡£HibernateʹÓÃÒ»ÖÖHQLµÄ²éѯÓï¾ä£¬ËüºÍSQLÀàËÆ£¬µ«ÕæÕýÔÚ¡°·Ò롱³ÉSQLʱ£¬»á¸ù¾ÝÉ趨µÄÊý¾Ý¿â¡°·½ÑÔ¡±À´Éú³ÉÕë¶ÔÊý¾Ý¿âÓÅ»¯µÄSQL£»
+* `hibernate.show_sql=true`£ºÈÃHibernate´òÓ¡Ö´ÐеÄSQL£¬Õâ¶ÔÓÚµ÷ÊԷdz£ÓÐÓã¬ÎÒÃÇ¿ÉÒÔ·½±ãµØ¿´µ½HibernateÉú³ÉµÄSQLÓï¾äÊÇ·ñ·ûºÏÎÒÃǵÄÔ¤ÆÚ¡£
+
+³ýÁËÉèÖÃ`DataSource`ºÍ`Properties`Ö®Í⣬עÒâµ½`setPackagesToScan()`ÎÒÃÇ´«ÈëÁËÒ»¸ö`package`Ãû³Æ£¬ËüָʾHibernateɨÃèÕâ¸ö°üÏÂÃæµÄËùÓÐJavaÀ࣬×Ô¶¯ÕÒ³öÄÜÓ³ÉäΪÊý¾Ý¿â±í¼Ç¼µÄJavaBean¡£ºóÃæÎÒÃÇ»á×ÐϸÌÖÂÛÈçºÎ±àд·ûºÏHibernateÒªÇóµÄJavaBean¡£
+
+½ô½Ó×Å£¬ÎÒÃÇ»¹ÐèÒª´´½¨`HibernateTransactionManager`£º
+
+```
+public class AppConfig {
+ @Bean
+ PlatformTransactionManager createTxManager(@Autowired SessionFactory sessionFactory) {
+ return new HibernateTransactionManager(sessionFactory);
+ }
+}
+
+```
+
+`HibernateTransactionManager`ÊÇÅäºÏHibernateʹÓÃÉùÃ÷ʽÊÂÎñËù±ØÐëµÄ¡£µ½´ËΪֹ£¬ËùÓеÄÅäÖö¼¶¨ÒåÍê±Ï£¬ÎÒÃÇÀ´¿´¿´ÈçºÎ½«Êý¾Ý¿â±í½á¹¹Ó³ÉäΪJava¶ÔÏó¡£
+
+¿¼²ìÈçϵÄÊý¾Ý¿â±í£º
+
+```
+CREATE TABLE user
+ id BIGINT NOT NULL AUTO_INCREMENT,
+ email VARCHAR(100) NOT NULL,
+ password VARCHAR(100) NOT NULL,
+ name VARCHAR(100) NOT NULL,
+ createdAt BIGINT NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `email` (`email`)
+);
+
+```
+
+ÆäÖУ¬`id`ÊÇ×ÔÔöÖ÷¼ü£¬`email`¡¢`password`¡¢`name`ÊÇ`VARCHAR`ÀàÐÍ£¬`email`´øÎ¨Ò»Ë÷ÒýÒÔÈ·±£Î¨Ò»ÐÔ£¬`createdAt`´æ´¢ÕûÐÍÀàÐ͵Äʱ¼ä´Á¡£ÓÃJavaBean±íʾÈçÏ£º
+
+```
+public class User {
+ private Long id;
+ private String email;
+ private String password;
+ private String name;
+ private Long createdAt;
+
+ // getters and setters
+ ...
+}
+
+```
+
+ÕâÖÖÓ³Éä¹ØÏµÊ®·ÖÒ×¶®£¬µ«ÎÒÃÇÐèÒªÌí¼ÓһЩע½âÀ´¸æËßHibernateÈçºÎ°Ñ`User`ÀàÓ³Éäµ½±í¼Ç¼£º
+
+```
+@Entity
+public class User {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(nullable = false, updatable = false)
+ public Long getId() { ... }
+
+ @Column(nullable = false, unique = true, length = 100)
+ public String getEmail() { ... }
+
+ @Column(nullable = false, length = 100)
+ public String getPassword() { ... }
+
+ @Column(nullable = false, length = 100)
+ public String getName() { ... }
+
+ @Column(nullable = false, updatable = false)
+ public Long getCreatedAt() { ... }
+}
+
+```
+
+Èç¹ûÒ»¸öJavaBean±»ÓÃÓÚÓ³É䣬ÎÒÃǾͱê¼ÇÒ»¸ö`@Entity`¡£Ä¬ÈÏÇé¿öÏ£¬Ó³ÉäµÄ±íÃûÊÇ`user`£¬Èç¹ûʵ¼ÊµÄ±íÃû²»Í¬£¬ÀýÈçʵ¼Ê±íÃûÊÇ`users`£¬¿ÉÒÔ×·¼ÓÒ»¸ö`@Table(name="users")`±íʾ£º
+
+```
+@Entity
+@Table(name="users)
+public class User {
+ ...
+}
+
+```
+
+ÿ¸öÊôÐÔµ½Êý¾Ý¿âÁеÄÓ³ÉäÓÃ`@Column()`±êʶ£¬`nullable`ָʾÁÐÊÇ·ñÔÊÐíΪ`NULL`£¬`updatable`ָʾ¸ÃÁÐÊÇ·ñÔÊÐí±»ÓÃÔÚ`UPDATE`Óï¾ä£¬`length`ָʾ`String`ÀàÐ͵ÄÁеij¤¶È£¨Èç¹ûûÓÐÖ¸¶¨£¬Ä¬ÈÏÊÇ`255`£©¡£
+
+¶ÔÓÚÖ÷¼ü£¬»¹ÐèÒªÓÃ`@Id`±êʶ£¬×ÔÔöÖ÷¼üÔÙ×·¼ÓÒ»¸ö`@GeneratedValue`£¬ÒÔ±ãHibernateÄܶÁÈ¡µ½×ÔÔöÖ÷¼üµÄÖµ¡£
+
+ϸÐĵÄͯЬ¿ÉÄÜ»¹×¢Òâµ½£¬Ö÷¼ü`id`¶¨ÒåµÄÀàÐͲ»ÊÇ`long`£¬¶øÊÇ`Long`¡£ÕâÊÇÒòΪHibernateÈç¹û¼ì²âµ½Ö÷¼üΪ`null`£¬¾Í²»»áÔÚ`INSERT`Óï¾äÖÐÖ¸¶¨Ö÷¼üµÄÖµ£¬¶øÊÇ·µ»ØÓÉÊý¾Ý¿âÉú³ÉµÄ×ÔÔöÖµ£¬·ñÔò£¬HibernateÈÏΪÎÒÃǵijÌÐòÖ¸¶¨ÁËÖ÷¼üµÄÖµ£¬»áÔÚ`INSERT`Óï¾äÖÐÖ±½ÓÁгö¡£`long`ÐÍ×Ö¶Î×ÜÊǾßÓÐĬÈÏÖµ`0`£¬Òò´Ë£¬Ã¿´Î²åÈëµÄÖ÷¼üÖµ×ÜÊÇ0£¬µ¼Ö³ýµÚÒ»´ÎÍâºóÐø²åÈë¶¼½«Ê§°Ü¡£
+
+`createdAt`ËäÈ»ÊÇÕûÐÍ£¬µ«ÎÒÃDz¢Ã»ÓÐʹÓÃ`long`£¬¶øÊÇ`Long`£¬ÕâÊÇÒòΪʹÓûù±¾ÀàÐͻᵼÖÂfindByExample²éѯ»áÌí¼ÓÒâÍâµÄÌõ¼þ£¬ÕâÀïÖ»ÐèÀμǣ¬×÷ΪӳÉäʹÓõÄJavaBean£¬ËùÓÐÊôÐÔ¶¼Ê¹Óðü×°ÀàÐͶø²»ÊÇ»ù±¾ÀàÐÍ¡£
+
+ʹÓÃHibernateʱ£¬²»ÒªÊ¹Óûù±¾ÀàÐ͵ÄÊôÐÔ£¬×ÜÊÇʹÓðü×°ÀàÐÍ£¬ÈçLong»òInteger¡£
+
+ÀàËÆµÄ£¬ÎÒÃÇÔÙ¶¨ÒåÒ»¸ö`Book`Àࣺ
+
+```
+@Entity
+public class Book {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(nullable = false, updatable = false)
+ public Long getId() { ... }
+
+ @Column(nullable = false, length = 100)
+ public String getTitle() { ... }
+
+ @Column(nullable = false, updatable = false)
+ public Long getCreatedAt() { ... }
+}
+
+```
+
+Èç¹û×Ðϸ¹Û²ì`User`ºÍ`Book`£¬»á·¢ÏÖËüÃǶ¨ÒåµÄ`id`¡¢`createdAt`ÊôÐÔÊÇÒ»ÑùµÄ£¬ÕâÔÚÊý¾Ý¿â±í½á¹¹µÄÉè¼ÆÖкܳ£¼û£º¶ÔÓÚÿ¸ö±í£¬Í¨³£ÎÒÃÇ»áͳһʹÓÃÒ»ÖÖÖ÷¼üÉú³É»úÖÆ£¬²¢Ìí¼Ó`createdAt`±íʾ´´½¨Ê±¼ä£¬`updatedAt`±íʾÐÞ¸Äʱ¼äµÈͨÓÃ×ֶΡ£
+
+²»±ØÔÚ`User`ºÍ`Book`ÖÐÖØ¸´¶¨ÒåÕâЩͨÓÃ×ֶΣ¬ÎÒÃÇ¿ÉÒÔ°ÑËüÃÇÌáµ½Ò»¸ö³éÏóÀàÖУº
+
+```
+@MappedSuperclass
+public abstract class AbstractEntity {
+
+ private Long id;
+ private Long createdAt;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(nullable = false, updatable = false)
+ public Long getId() { ... }
+
+ @Column(nullable = false, updatable = false)
+ public Long getCreatedAt() { ... }
+
+ @Transient
+ public ZonedDateTime getCreatedDateTime() {
+ return Instant.ofEpochMilli(this.createdAt).atZone(ZoneId.systemDefault());
+ }
+
+ @PrePersist
+ public void preInsert() {
+ setCreatedAt(System.currentTimeMillis());
+ }
+}
+
+```
+
+¶ÔÓÚ`AbstractEntity`À´Ëµ£¬ÎÒÃÇÒª±ê×¢Ò»¸ö`@MappedSuperclass`±íʾËüÓÃÓڼ̳С£´ËÍ⣬עÒâµ½ÎÒÃǶ¨ÒåÁËÒ»¸ö`@Transient`·½·¨£¬Ëü·µ»ØÒ»¸ö¡°ÐéÄ⡱µÄÊôÐÔ¡£ÒòΪ`getCreatedDateTime()`ÊǼÆËãµÃ³öµÄÊôÐÔ£¬¶ø²»ÊÇ´ÓÊý¾Ý¿â±í¶Á³öµÄÖµ£¬Òò´Ë±ØÐëÒª±ê×¢`@Transient`£¬·ñÔòHibernate»á³¢ÊÔ´ÓÊý¾Ý¿â¶ÁÈ¡ÃûΪ`createdDateTime`Õâ¸ö²»´æÔÚµÄ×ֶδӶø³ö´í¡£
+
+ÔÙ×¢Òâµ½`@PrePersist`±êʶµÄ·½·¨£¬Ëü±íʾÔÚÎÒÃǽ«Ò»¸öJavaBean³Ö¾Ã»¯µ½Êý¾Ý¿â֮ǰ£¨¼´Ö´ÐÐINSERTÓï¾ä£©£¬Hibernate»áÏÈÖ´Ðи÷½·¨£¬ÕâÑùÎÒÃǾͿÉÒÔ×Ô¶¯ÉèÖúÃ`createdAt`ÊôÐÔ¡£
+
+ÓÐÁË`AbstractEntity`£¬ÎÒÃǾͿÉÒÔ´ó·ù¼ò»¯`User`ºÍ`Book`£º
+
+```
+@Entity
+public class User extends AbstractEntity {
+
+ @Column(nullable = false, unique = true, length = 100)
+ public String getEmail() { ... }
+
+ @Column(nullable = false, length = 100)
+ public String getPassword() { ... }
+
+ @Column(nullable = false, length = 100)
+ public String getName() { ... }
+}
+
+```
+
+×¢Ò⵽ʹÓõÄËùÓÐ×¢½â¾ùÀ´×Ô`jakarta.persistence`£¬ËüÊÇJPA¹æ·¶µÄÒ»²¿·Ö¡£ÕâÀïÎÒÃÇÖ»½éÉÜʹÓÃ×¢½âµÄ·½Ê½ÅäÖÃHibernateÓ³Éä¹ØÏµ£¬²»ÔÙ½éÉÜ´«Í³µÄ±È½Ï·±ËöµÄXMLÅäÖá£Í¨¹ýSpring¼¯³ÉHibernateʱ£¬Ò²²»ÔÙÐèÒª`hibernate.cfg.xml`ÅäÖÃÎļþ£¬ÓÃÒ»¾ä»°×ܽ᣺
+
+ʹÓÃSpring¼¯³ÉHibernate£¬ÅäºÏJPA×¢½â£¬ÎÞÐèÈκζîÍâµÄXMLÅäÖá£
+
+ÀàËÆ`User`¡¢`Book`ÕâÑùµÄÓÃÓÚORMµÄJava Bean£¬ÎÒÃÇͨ³£³ÆÖ®ÎªEntity Bean¡£
+
+×îºó£¬ÎÒÃÇÀ´¿´¿´Èç¹û¶Ô`user`±í½øÐÐÔöɾ¸Ä²é¡£ÒòΪʹÓÃÁËHibernate£¬Òò´Ë£¬ÎÒÃÇÒª×öµÄ£¬Êµ¼ÊÉÏÊǶÔ`User`Õâ¸öJavaBean½øÐС°Ôöɾ¸Ä²é¡±¡£ÎÒÃDZàдһ¸ö`UserService`£¬×¢Èë`SessionFactory`£º
+
+```
+@Component
+@Transactional
+public class UserService {
+ @Autowired
+ SessionFactory sessionFactory;
+}
+
+```
+
+### Insert²Ù×÷
+
+Òª³Ö¾Ã»¯Ò»¸ö`User`ʵÀý£¬ÎÒÃÇÖ»Ðèµ÷ÓÃ`persist()`·½·¨¡£ÒÔ`register()`·½·¨ÎªÀý£¬´úÂëÈçÏ£º
+
+```
+public User register(String email, String password, String name) {
+ // ´´½¨Ò»¸öUser¶ÔÏó:
+ User user = new User();
+ // ÉèÖúø÷¸öÊôÐÔ:
+ user.setEmail(email);
+ user.setPassword(password);
+ user.setName(name);
+ // ²»ÒªÉèÖÃid£¬ÒòΪʹÓÃÁË×ÔÔöÖ÷¼ü
+ // ±£´æµ½Êý¾Ý¿â:
+ sessionFactory.getCurrentSession().persist(user);
+ // ÏÖÔÚÒѾ×Ô¶¯»ñµÃÁËid:
+ System.out.println(user.getId());
+ return user;
+}
+
+```
+
+### Delete²Ù×÷
+
+ɾ³ýÒ»¸ö`User`Ï൱ÓÚ´Ó±íÖÐɾ³ý¶ÔÓ¦µÄ¼Ç¼¡£×¢ÒâHibernate×ÜÊÇÓÃ`id`À´É¾³ý¼Ç¼£¬Òò´Ë£¬ÒªÕýÈ·ÉèÖÃ`User`µÄ`id`ÊôÐÔ²ÅÄÜÕý³£É¾³ý¼Ç¼£º
+
+```
+public boolean deleteUser(Long id) {
+ User user = sessionFactory.getCurrentSession().byId(User.class).load(id);
+ if (user != null) {
+ sessionFactory.getCurrentSession().remove(user);
+ return true;
+ }
+ return false;
+}
+
+```
+
+ͨ¹ýÖ÷¼üɾ³ý¼Ç¼ʱ£¬Ò»¸ö³£¼ûµÄÓ÷¨ÊÇÏȸù¾ÝÖ÷¼ü¼ÓÔØ¸Ã¼Ç¼£¬ÔÙɾ³ý¡£×¢Òâµ½µ±¼Ç¼²»´æÔÚʱ£¬`load()`·µ»Ø`null`¡£
+
+### Update²Ù×÷
+
+¸üмǼÏ൱ÓÚÏȸüÐÂ`User`µÄÖ¸¶¨ÊôÐÔ£¬È»ºóµ÷ÓÃ`merge()`·½·¨£º
+
+```
+public void updateUser(Long id, String name) {
+ User user = sessionFactory.getCurrentSession().byId(User.class).load(id);
+ user.setName(name);
+ sessionFactory.getCurrentSession().merge(user);
+}
+
+```
+
+Ç°ÃæÎÒÃÇÔÚ¶¨Òå`User`ʱ£¬¶ÔÓеÄÊôÐÔ±ê×¢ÁË`@Column(updatable=false)`¡£HibernateÔÚ¸üмǼʱ£¬ËüÖ»»á°Ñ`@Column(updatable=true)`µÄÊôÐÔ¼ÓÈëµ½`UPDATE`Óï¾äÖУ¬ÕâÑù¿ÉÒÔÌṩһ²ã¶îÍâµÄ°²È«ÐÔ£¬¼´Èç¹û²»Ð¡ÐÄÐÞ¸ÄÁË`User`µÄ`email`¡¢`createdAt`µÈÊôÐÔ£¬Ö´ÐÐ`update()`ʱ²¢²»»á¸üжÔÓ¦µÄÊý¾Ý¿âÁС£µ«Ò²±ØÐëÀμǣºÕâ¸ö¹¦ÄÜÊÇHibernateÌṩµÄ£¬Èç¹ûÈÆ¹ýHibernateÖ±½Óͨ¹ýJDBCÖ´ÐÐ`UPDATE`Óï¾äÈÔÈ»¿ÉÒÔ¸üÐÂÊý¾Ý¿âµÄÈÎÒâÁеÄÖµ¡£
+
+×îºó£¬ÎÒÃDZàдµÄ´ó²¿·Ö·½·¨¶¼ÊǸ÷ÖÖ¸÷ÑùµÄ²éѯ¡£¸ù¾Ý`id`²éѯÎÒÃÇ¿ÉÒÔÖ±½Óµ÷ÓÃ`load()`£¬Èç¹ûҪʹÓÃÌõ¼þ²éѯ£¬ÀýÈ磬¼ÙÉèÎÒÃÇÏëÖ´ÐÐÒÔϲéѯ£º
+
+```
+SELECT * FROM user WHERE email = ? AND password = ?
+
+```
+
+ÎÒÃÇÀ´¿´¿´¿ÉÒÔʹÓÃʲô²éѯ¡£
+
+### ʹÓÃHQL²éѯ
+
+Ò»ÖÖ³£ÓõIJéѯÊÇÖ±½Ó±àдHibernateÄÚÖõÄHQL²éѯ£º
+
+```
+List list = sessionFactory.getCurrentSession()
+ .createQuery("from User u where u.email = ?1 and u.password = ?2", User.class)
+ .setParameter(1, email).setParameter(2, password)
+ .list();
+
+```
+
+ºÍSQLÏà±È£¬HQLʹÓÃÀàÃûºÍÊôÐÔÃû£¬ÓÉHibernate×Ô¶¯×ª»»ÎªÊµ¼ÊµÄ±íÃûºÍÁÐÃû¡£ÏêϸµÄHQLÓï·¨¿ÉÒԲο¼[HibernateÎĵµ](https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#query-language)¡£
+
+³ýÁË¿ÉÒÔÖ±½Ó´«ÈëHQL×Ö·û´®Í⣬Hibernate»¹¿ÉÒÔʹÓÃÒ»ÖÖ`NamedQuery`£¬Ëü¸ø²éѯÆð¸öÃû×Ö£¬È»ºó±£´æÔÚ×¢½âÖС£Ê¹ÓÃ`NamedQuery`ʱ£¬ÎÒÃÇÒªÏÈÔÚ`User`Àà±ê×¢£º
+
+```
+@NamedQueries(
+ @NamedQuery(
+ // ²éѯÃû³Æ:
+ name = "login",
+ // ²éѯÓï¾ä:
+ query = "SELECT u FROM User u WHERE u.email = :e AND u.password = :pwd"
+ )
+)
+@Entity
+public class User extends AbstractEntity {
+ ...
+}
+
+```
+
+×¢Òâµ½ÒýÈëµÄ`NamedQuery`ÊÇ`jakarta.persistence.NamedQuery`£¬ËüºÍÖ±½Ó´«ÈëHQLÓе㲻ͬµÄÊÇ£¬Õ¼Î»·ûʹÓÃ`:e`ºÍ`:pwd`¡£
+
+ʹÓÃ`NamedQuery`Ö»ÐèÒªÒýÈë²éѯÃûºÍ²ÎÊý£º
+
+```
+public User login(String email, String password) {
+ List list = sessionFactory.getCurrentSession()
+ .createNamedQuery("login", User.class) // ´´½¨NamedQuery
+ .setParameter("e", email) // °ó¶¨e²ÎÊý
+ .setParameter("pwd", password) // °ó¶¨pwd²ÎÊý
+ .list();
+ return list.isEmpty() ? null : list.get(0);
+}
+
+```
+
+Ö±½ÓдHQLºÍʹÓÃ`NamedQuery`¸÷ÓÐÓÅÁÓ¡£Ç°Õß¿ÉÒÔÔÚ´úÂëÖÐÖ±¹ÛµØ¿´µ½²éѯÓï¾ä£¬ºóÕß¿ÉÒÔÔÚ`User`Ààͳһ¹ÜÀíËùÓÐÏà¹Ø²éѯ¡£
+
+ÉÏÒ»½ÚÎÒÃǽ²ÁËÔÚSpringÖм¯³ÉHibernate¡£HibernateÊǵÚÒ»¸ö±»¹ã·ºÊ¹ÓõÄORM¿ò¼Ü£¬µ«ÊǺܶàС»ï°é»¹Ìý˵¹ýJPA£ºJava Persistence API£¬ÕâÓÖÊÇɶ£¿
+
+ÔÚÌÖÂÛJPA֮ǰ£¬ÎÒÃÇҪעÒâµ½JavaEEÔçÔÚ1999Äê¾Í·¢²¼ÁË£¬²¢ÇÒÓÐServlet¡¢JMSµÈÖî¶à±ê×¼¡£ºÍÆäËûƽ̨²»Í¬£¬JavaÊÀ½çÔçÆÚ·Ç³£ÈÈÖÔÓÚ±ê×¼ÏÈÐУ¬¸÷¼Ò¸ú½ø£º´ó¼ÒÏÈ×øÏÂÀ´°Ñ½Ó¿Ú¶¨ÁË£¬È»ºó£¬¸÷×ԻؼҸɻîȥʵÏÖ½Ó¿Ú£¬ÕâÑù£¬Óû§¾Í¿ÉÒÔÔÚ²»Í¬µÄ³§¼ÒÌṩµÄ²úÆ·½øÐÐÑ¡Ôñ£¬»¹¿ÉÒÔËæÒâÇл»£¬ÒòΪÓû§±àд´úÂëµÄʱºòÖ»ÐèÒªÒýÓýӿڣ¬²¢²»ÐèÒªÒýÓþßÌåµÄµ×²ãʵÏÖ£¨ÏëÏëJDBC£©¡£
+
+JPA¾ÍÊÇJavaEEµÄÒ»¸öORM±ê×¼£¬ËüµÄʵÏÖÆäʵºÍHibernateûɶ±¾ÖÊÇø±ð£¬µ«ÊÇÓû§Èç¹ûʹÓÃJPA£¬ÄÇôÒýÓõľÍÊÇ`jakarta.persistence`Õâ¸ö¡°±ê×¼¡±°ü£¬¶ø²»ÊÇ`org.hibernate`ÕâÑùµÄµÚÈý·½°ü¡£ÒòΪJPAÖ»Êǽӿڣ¬ËùÒÔ£¬»¹ÐèҪѡÔñÒ»¸öʵÏÖ²úÆ·£¬¸úJDBC½Ó¿ÚºÍMySQLÇý¶¯Ò»¸öµÀÀí¡£
+
+ÎÒÃÇʹÓÃJPAʱҲÍêÈ«¿ÉÒÔÑ¡ÔñHibernate×÷Ϊµ×²ãʵÏÖ£¬µ«Ò²¿ÉÒÔÑ¡ÔñÆäËüµÄJPAÌṩ·½£¬±ÈÈç[EclipseLink](https://www.eclipse.org/eclipselink/)¡£SpringÄÚÖÃÁËJPAµÄ¼¯³É£¬²¢Ö§³ÖÑ¡ÔñHibernate»òEclipseLink×÷ΪʵÏÖ¡£ÕâÀïÎÒÃÇÈÔÈ»ÒÔÖ÷Á÷µÄHibernate×÷ΪJPAʵÏÖΪÀý×Ó£¬ÑÝʾJPAµÄ»ù±¾Ó÷¨¡£
+
+ºÍʹÓÃHibernateÒ»Ñù£¬ÎÒÃÇÖ»ÐèÒªÒýÈëÈçÏÂÒÀÀµ£º
+
+* org.springframework:spring-context:6.0.0
+* org.springframework:spring-orm:6.0.0
+* jakarta.annotation:jakarta.annotation-api:2.1.1
+* jakarta.persistence:jakarta.persistence-api:3.1.0
+* org.hibernate:hibernate-core:6.1.4.Final
+* com.zaxxer:HikariCP:5.0.1
+* org.hsqldb:hsqldb:2.7.1
+
+ʵ¼ÊÉÏÎÒÃÇÕâÀïÒýÈëµÄÒÀÀµºÍÉÏÒ»½Ú¼¯³ÉHibernateÒýÈëµÄÒÀÀµÍêȫһÑù£¬ÒòΪHibernate¼ÈÌṩÁËËü×Ô¼ºµÄ½Ó¿Ú£¬Ò²ÌṩÁËJPA½Ó¿Ú£¬ÎÒÃÇÓÃJPA½Ó¿Ú¾ÍÏ൱ÓÚͨ¹ýJPA²Ù×÷Hibernate¡£
+
+È»ºó£¬ÔÚ`AppConfig`ÖÐÆôÓÃÉùÃ÷ʽÊÂÎñ¹ÜÀí£¬´´½¨`DataSource`£º
+
+```
+@Configuration
+@ComponentScan
+@EnableTransactionManagement
+@PropertySource("jdbc.properties")
+public class AppConfig {
+ @Bean
+ DataSource createDataSource() { ... }
+}
+
+```
+
+ʹÓÃHibernateʱ£¬ÎÒÃÇÐèÒª´´½¨Ò»¸ö`LocalSessionFactoryBean`£¬²¢ÈÃËüÔÙ×Ô¶¯´´½¨Ò»¸ö`SessionFactory`¡£Ê¹ÓÃJPAÒ²ÊÇÀàËÆµÄ£¬ÎÒÃÇÒ²´´½¨Ò»¸ö`LocalContainerEntityManagerFactoryBean`£¬²¢ÈÃËüÔÙ×Ô¶¯´´½¨Ò»¸ö`EntityManagerFactory`£º
+
+```
+@Bean
+public LocalContainerEntityManagerFactoryBean createEntityManagerFactory(@Autowired DataSource dataSource) {
+ var emFactory = new LocalContainerEntityManagerFactoryBean();
+ // ×¢ÈëDataSource:
+ emFactory.setDataSource(dataSource);
+ // ɨÃèÖ¸¶¨µÄpackage»ñÈ¡ËùÓÐentity class:
+ emFactory.setPackagesToScan(AbstractEntity.class.getPackageName());
+ // ʹÓÃHibernate×÷ΪJPAʵÏÖ:
+ emFactory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
+ // ÆäËûÅäÖÃÏî:
+ var props = new Properties();
+ props.setProperty("hibernate.hbm2ddl.auto", "update"); // Éú²ú»·¾³²»ÒªÊ¹ÓÃ
+ props.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
+ props.setProperty("hibernate.show_sql", "true");
+ emFactory.setJpaProperties(props);
+ return emFactory;
+}
+
+```
+
+¹Û²ìÉÏÊö´úÂ룬³ýÁËÐèҪעÈë`DataSource`ºÍÉ趨×Ô¶¯É¨ÃèµÄ`package`Í⣬»¹ÐèÒªÖ¸¶¨JPAµÄÌṩÉÌ£¬ÕâÀïʹÓÃSpringÌṩµÄÒ»¸ö`HibernateJpaVendorAdapter`£¬×îºó£¬Õë¶ÔHibernate×Ô¼ºÐèÒªµÄÅäÖã¬ÒÔ`Properties`µÄÐÎʽעÈë¡£
+
+×îºó£¬ÎÒÃÇ»¹ÐèҪʵÀý»¯Ò»¸ö`JpaTransactionManager`£¬ÒÔʵÏÖÉùÃ÷ʽÊÂÎñ£º
+
+```
+@Bean
+PlatformTransactionManager createTxManager(@Autowired EntityManagerFactory entityManagerFactory) {
+ return new JpaTransactionManager(entityManagerFactory);
+}
+
+```
+
+ÕâÑù£¬ÎÒÃǾÍÍê³ÉÁËJPAµÄÈ«²¿³õʼ»¯¹¤×÷¡£ÓÐЩͯЬ¿ÉÄÜ´ÓÍøÉÏËÑË÷µÃÖªJPAÐèÒª`persistence.xml`ÅäÖÃÎļþ£¬ÒÔ¼°¸´ÔÓµÄ`orm.xml`Îļþ¡£ÕâÀïÎÒÃǸºÔðµØ¸æËß´ó¼Ò£¬Ê¹ÓÃSpring+Hibernate×÷ΪJPAʵÏÖ£¬ÎÞÐèÈκÎÅäÖÃÎļþ¡£
+
+ËùÓÐEntity BeanµÄÅäÖúÍÉÏÒ»½ÚÍêÈ«Ïàͬ£¬È«²¿²ÉÓÃAnnotation±ê×¢¡£ÎÒÃÇÏÖÔÚÖ»Ðè¹ØÐľßÌåµÄÒµÎñÀàÈçºÎͨ¹ýJPA½Ó¿Ú²Ù×÷Êý¾Ý¿â¡£
+
+»¹ÊÇÒÔ`UserService`ΪÀý£¬³ýÁ˱ê×¢`@Component`ºÍ`@Transactional`Í⣬ÎÒÃÇÐèҪעÈëÒ»¸ö`EntityManager`£¬µ«ÊDz»ÒªÊ¹ÓÃ`Autowired`£¬¶øÊÇ`@PersistenceContext`£º
+
+```
+@Component
+@Transactional
+public class UserService {
+ @PersistenceContext
+ EntityManager em;
+}
+
+```
+
+ÎÒÃǻعËÒ»ÏÂJDBC¡¢HibernateºÍJPAÌṩµÄ½Ó¿Ú£¬Êµ¼ÊÉÏ£¬ËüÃǵĹØÏµÈçÏ£º
+
+| JDBC | Hibernate | JPA |
+| --- | --- | --- |
+| DataSource | SessionFactory | EntityManagerFactory |
+| Connection | Session | EntityManager |
+
+`SessionFactory`ºÍ`EntityManagerFactory`Ï൱ÓÚ`DataSource`£¬`Session`ºÍ`EntityManager`Ï൱ÓÚ`Connection`¡£Ã¿´ÎÐèÒª·ÃÎÊÊý¾Ý¿âµÄʱºò£¬ÐèÒª»ñȡеÄ`Session`ºÍ`EntityManager`£¬ÓÃÍêºóÔٹرա£
+
+µ«ÊÇ£¬×¢Òâµ½`UserService`×¢ÈëµÄ²»ÊÇ`EntityManagerFactory`£¬¶øÊÇ`EntityManager`£¬²¢ÇÒ±ê×¢ÁË`@PersistenceContext`¡£ÄѵÀʹÓÃJPA¿ÉÒÔÔÊÐí¶àÏ̲߳Ù×÷ͬһ¸ö`EntityManager`£¿
+
+ʵ¼ÊÉÏÕâÀï×¢ÈëµÄ²¢²»ÊÇÕæÕýµÄ`EntityManager`£¬¶øÊÇÒ»¸ö`EntityManager`µÄ´úÀíÀ࣬Ï൱ÓÚ£º
+
+```
+public class EntityManagerProxy implements EntityManager {
+ private EntityManagerFactory emf;
+}
+
+```
+
+SpringÓöµ½±ê×¢ÁË`@PersistenceContext`µÄ`EntityManager`»á×Ô¶¯×¢Èë´úÀí£¬¸Ã´úÀí»áÔÚ±ØÒªµÄʱºò×Ô¶¯´ò¿ª`EntityManager`¡£»»¾ä»°Ëµ£¬¶àÏß³ÌÒýÓõÄ`EntityManager`ËäÈ»ÊÇͬһ¸ö´úÀíÀ࣬µ«¸Ã´úÀíÀàÄÚ²¿Õë¶Ô²»Í¬Ï̻߳ᴴ½¨²»Í¬µÄ`EntityManager`ʵÀý¡£
+
+¼òµ¥×ܽáһϣ¬±ê×¢ÁË`@PersistenceContext`µÄ`EntityManager`¿ÉÒÔ±»¶àḬ̈߳²È«µØ¹²Ïí¡£
+
+Òò´Ë£¬ÔÚ`UserService`µÄÿ¸öÒµÎñ·½·¨Àֱ½ÓʹÓÃ`EntityManager`¾ÍºÜ·½±ã¡£ÒÔÖ÷¼ü²éѯΪÀý£º
+
+```
+public User getUserById(long id) {
+ User user = this.em.find(User.class, id);
+ if (user == null) {
+ throw new RuntimeException("User not found by id: " + id);
+ }
+ return user;
+}
+
+```
+
+ÓëHQL²éѯÀàËÆ£¬JPAʹÓÃJPQL²éѯ£¬ËüµÄÓï·¨ºÍHQL»ù±¾²î²»¶à£º
+
+```
+public User fetchUserByEmail(String email) {
+ // JPQL²éѯ:
+ TypedQuery query = em.createQuery("SELECT u FROM User u WHERE u.email = :e", User.class);
+ query.setParameter("e", email);
+ List list = query.getResultList();
+ if (list.isEmpty()) {
+ return null;
+ }
+ return list.get(0);
+}
+
+```
+
+ͬÑùµÄ£¬JPAÒ²Ö§³Ö`NamedQuery`£¬¼´Ïȸø²éѯÆð¸öÃû×Ö£¬ÔÙ°´Ãû×Ö´´½¨²éѯ£º
+
+```
+public User login(String email, String password) {
+ TypedQuery query = em.createNamedQuery("login", User.class);
+ query.setParameter("e", email);
+ query.setParameter("pwd", password);
+ List list = query.getResultList();
+ return list.isEmpty() ? null : list.get(0);
+}
+
+```
+
+`NamedQuery`ͨ¹ý×¢½â±ê×¢ÔÚ`User`ÀàÉÏ£¬ËüµÄ¶¨ÒåºÍÉÏÒ»½ÚµÄ`User`ÀàÒ»Ñù£º
+
+```
+@NamedQueries(
+ @NamedQuery(
+ name = "login",
+ query = "SELECT u FROM User u WHERE u.email=:e AND u.password=:pwd"
+ )
+)
+@Entity
+public class User {
+ ...
+}
+
+```
+
+¶ÔÊý¾Ý¿â½øÐÐÔöɾ¸ÄµÄ²Ù×÷£¬¿ÉÒÔ·Ö±ðʹÓÃ`persist()`¡¢`remove()`ºÍ`merge()`·½·¨£¬²ÎÊý¾ùΪEntity Bean±¾Éí£¬Ê¹Ó÷dz£¼òµ¥£¬ÕâÀï²»ÔÙ¶àÊö¡£
+
+#### ¼¯³ÉMyBatis
+
+×îºó¸üÐÂ: 2022/11/16 21:07 / ÔĶÁ: 601258
+
+* * *
+
+
+
+ʹÓÃHibernate»òJPA²Ù×÷Êý¾Ý¿âʱ£¬ÕâÀàORM¸ÉµÄÖ÷Òª¹¤×÷¾ÍÊǰÑResultSetµÄÿһÐбä³ÉJava Bean£¬»òÕß°ÑJava Bean×Ô¶¯×ª»»µ½INSERT»òUPDATEÓï¾äµÄ²ÎÊýÖУ¬´Ó¶øÊµÏÖORM¡£
+
+¶øORM¿ò¼ÜÖ®ËùÒÔÖªµÀÈçºÎ°ÑÐÐÊý¾ÝÓ³Éäµ½Java Bean£¬ÊÇÒòΪÎÒÃÇÔÚJava BeanµÄÊôÐÔÉϸøÁË×ã¹»µÄ×¢½â×÷ΪԪÊý¾Ý£¬ORM¿ò¼Ü»ñÈ¡Java BeanµÄ×¢½âºó£¬¾ÍÖªµÀÈçºÎ½øÐÐË«ÏòÓ³Éä¡£
+
+ÄÇô£¬ORM¿ò¼ÜÊÇÈçºÎ¸ú×ÙJava BeanµÄÐ޸ģ¬ÒÔ±ãÔÚ`update()`²Ù×÷ÖиüбØÒªµÄÊôÐÔ£¿
+
+´ð°¸ÊÇʹÓÃ[Proxyģʽ](https://www.liaoxuefeng.com/wiki/1252599548343744/1281319432618017)£¬´ÓORM¿ò¼Ü¶ÁÈ¡µÄUserʵÀýʵ¼ÊÉϲ¢²»ÊÇUserÀ࣬¶øÊÇ´úÀíÀ࣬´úÀíÀà¼Ì³Ð×ÔUserÀ࣬µ«Õë¶Ôÿ¸ösetter·½·¨×öÁ˸²Ð´£º
+
+```
+public class UserProxy extends User {
+ boolean _isNameChanged;
+
+ public void setName(String name) {
+ super.setName(name);
+ _isNameChanged = true;
+ }
+}
+
+```
+
+ÕâÑù£¬´úÀíÀà¿ÉÒÔ¸ú×Ùµ½Ã¿¸öÊôÐԵı仯¡£
+
+Õë¶ÔÒ»¶Ô¶à»ò¶à¶ÔÒ»¹ØÏµÊ±£¬´úÀíÀà¿ÉÒÔÖ±½Óͨ¹ýgetter·½·¨²éѯÊý¾Ý¿â£º
+
+```
+public class UserProxy extends User {
+ Session _session;
+ boolean _isNameChanged;
+
+ public void setName(String name) {
+ super.setName(name);
+ _isNameChanged = true;
+ }
+
+ /**
+ * »ñÈ¡User¶ÔÏó¹ØÁªµÄAddress¶ÔÏó:
+ */
+ public Address getAddress() {
+ Query q = _session.createQuery("from Address where userId = :userId");
+ q.setParameter("userId", this.getId());
+ List list = query.list();
+ return list.isEmpty() ? null : list(0);
+ }
+}
+
+```
+
+ΪÁËʵÏÖÕâÑùµÄ²éѯ£¬UserProxy±ØÐë±£´æHibernateµÄµ±Ç°Session¡£µ«ÊÇ£¬µ±ÊÂÎñÌá½»ºó£¬Session×Ô¶¯¹Ø±Õ£¬´ËʱÔÙ»ñÈ¡`getAddress()`½«ÎÞ·¨·ÃÎÊÊý¾Ý¿â£¬»òÕß»ñÈ¡µÄ²»ÊÇÊÂÎñÒ»ÖµÄÊý¾Ý¡£Òò´Ë£¬ORM¿ò¼Ü×ÜÊÇÒýÈëÁËAttached/Detached״̬£¬±íʾµ±Ç°´ËJava Beanµ½µ×ÊÇÔÚSessionµÄ·¶Î§ÄÚ£¬»¹ÊÇÍÑÀëÁËSession±ä³ÉÁËÒ»¸ö¡°ÓÎÀ롱¶ÔÏ󡣺ܶà³õѧÕßÎÞ·¨ÕýÈ·Àí½â״̬±ä»¯ºÍÊÂÎñ±ß½ç£¬¾Í»áÔì³É´óÁ¿µÄ`PersistentObjectException`Òì³£¡£ÕâÖÖÒþʽ״̬ʹµÃÆÕͨJava BeanµÄÉúÃüÖÜÆÚ±äµÃ¸´ÔÓ¡£
+
+´ËÍ⣬HibernateºÍJPAΪÁËʵÏÖ¼æÈݶàÖÖÊý¾Ý¿â£¬ËüʹÓÃHQL»òJPQL²éѯ£¬¾¹ýÒ»µÀת»»£¬±ä³ÉÌØ¶¨Êý¾Ý¿âµÄSQL£¬ÀíÂÛÉÏÕâÑù¿ÉÒÔ×öµ½ÎÞ·ìÇл»Êý¾Ý¿â£¬µ«ÕâÒ»²ã×Ô¶¯×ª»»³ýÁËÉÙÐíµÄÐÔÄÜ¿ªÏúÍ⣬¸øSQL¼¶±ðµÄÓÅ»¯´øÀ´ÁËÂé·³¡£
+
+×îºó£¬ORM¿ò¼Üͨ³£ÌṩÁË»º´æ£¬²¢ÇÒ»¹·ÖΪһ¼¶»º´æºÍ¶þ¼¶»º´æ¡£Ò»¼¶»º´æÊÇÖ¸ÔÚÒ»¸öSession·¶Î§ÄڵĻº´æ£¬³£¼ûµÄÇé¾°ÊǸù¾ÝÖ÷¼ü²éѯʱ£¬Á½´Î²éѯ¿ÉÒÔ·µ»ØÍ¬Ò»ÊµÀý£º
+
+```
+User user1 = session.load(User.class, 123);
+User user2 = session.load(User.class, 123);
+
+```
+
+¶þ¼¶»º´æÊÇÖ¸¿çSessionµÄ»º´æ£¬Ò»°ãĬÈϹرգ¬ÐèÒªÊÖ¶¯ÅäÖ᣶þ¼¶»º´æ¼«´óµÄÔö¼ÓÁËÊý¾ÝµÄ²»Ò»ÖÂÐÔ£¬ÔÒòÔÚÓÚSQL·Ç³£Áé»î£¬³£³£»áµ¼ÖÂÒâÍâµÄ¸üС£ÀýÈ磺
+
+```
+// Ïß³Ì1¶ÁÈ¡:
+User user1 = session1.load(User.class, 123);
+...
+// Ò»¶Îʱ¼äºó£¬Ïß³Ì2¶ÁÈ¡:
+User user2 = session2.load(User.class, 123);
+
+```
+
+µ±¶þ¼¶»º´æÉúЧµÄʱºò£¬Á½¸öÏ̶߳ÁÈ¡µÄUserʵÀýÊÇÒ»ÑùµÄ£¬µ«ÊÇ£¬Êý¾Ý¿â¶ÔÓ¦µÄÐмǼÍêÈ«¿ÉÄܱ»Ð޸ģ¬ÀýÈ磺
+
+```
+-- ¸øÀÏÓû§Ôö¼Ó100»ý·Ö:
+UPDATE users SET bonus = bonus + 100 WHERE createdAt <= ?
+
+```
+
+ORMÎÞ·¨ÅжÏ`id=123`µÄÓû§ÊÇ·ñÊܸÃ`UPDATE`Óï¾äÓ°Ïì¡£¿¼Âǵ½Êý¾Ý¿âͨ³£»áÖ§³Ö¶à¸öÓ¦ÓóÌÐò£¬´ËUPDATEÓï¾ä¿ÉÄÜÓÉÆäËû½ø³ÌÖ´ÐУ¬ORM¿ò¼Ü¾Í¸ü²»ÖªµÀÁË¡£
+
+ÎÒÃǰÑÕâÖÖORM¿ò¼Ü³ÆÖ®ÎªÈ«×Ô¶¯ORM¿ò¼Ü¡£
+
+¶Ô±ÈSpringÌṩµÄJdbcTemplate£¬ËüºÍORM¿ò¼ÜÏà±È£¬Ö÷ÒªÓм¸µã²î±ð£º
+
+1. ²éѯºóÐèÒªÊÖ¶¯ÌṩMapperʵÀýÒÔ±ã°ÑResultSetµÄÿһÐбäΪJava¶ÔÏó£»
+2. Ôöɾ¸Ä²Ù×÷ËùÐèµÄ²ÎÊýÁÐ±í£¬ÐèÒªÊÖ¶¯´«È룬¼´°ÑUserʵÀý±äΪ[user.id, user.name, user.email]ÕâÑùµÄÁÐ±í£¬±È½ÏÂé·³¡£
+
+µ«ÊÇJdbcTemplateµÄÓÅÊÆÔÚÓÚËüµÄÈ·¶¨ÐÔ£º¼´Ã¿´Î¶ÁÈ¡²Ù×÷Ò»¶¨ÊÇÊý¾Ý¿â²Ù×÷¶ø²»ÊÇ»º´æ£¬ËùÖ´ÐеÄSQLÊÇÍêȫȷ¶¨µÄ£¬È±µã¾ÍÊÇ´úÂë±È½Ï·±Ëö£¬¹¹Ôì`INSERT INTO users VALUES (?,?,?)`¸üÊǸ´ÔÓ¡£
+
+ËùÒÔ£¬½éÓÚÈ«×Ô¶¯ORMÈçHibernateºÍÊÖдȫ²¿ÈçJdbcTemplateÖ®¼ä£¬»¹ÓÐÒ»ÖÖ°ë×Ô¶¯µÄORM£¬ËüÖ»¸ºÔð°ÑResultSet×Ô¶¯Ó³Éäµ½Java Bean£¬»òÕß×Ô¶¯Ìî³äJava Bean²ÎÊý£¬µ«ÈÔÐè×Ô¼ºÐ´³öSQL¡£[MyBatis](https://mybatis.org/)¾ÍÊÇÕâÑùÒ»ÖÖ°ë×Ô¶¯»¯ORM¿ò¼Ü¡£
+
+ÎÒÃÇÀ´¿´¿´ÈçºÎÔÚSpringÖм¯³ÉMyBatis¡£
+
+Ê×ÏÈ£¬ÎÒÃÇÒªÒýÈëMyBatis±¾Éí£¬Æä´Î£¬ÓÉÓÚSpring²¢Ã»ÓÐÏñHibernateÄÇÑùÄÚÖöÔMyBatisµÄ¼¯³É£¬ËùÒÔ£¬ÎÒÃÇÐèÒªÔÙÒýÈëMyBatis¹Ù·½×Ô¼º¿ª·¢µÄÒ»¸öÓëSpring¼¯³ÉµÄ¿â£º
+
+* org.mybatis:mybatis:3.5.11
+* org.mybatis:mybatis-spring:3.0.0
+
+ºÍÇ°ÃæÒ»Ñù£¬ÏÈ´´½¨`DataSource`ÊDZز»¿ÉÉٵģº
+
+```
+@Configuration
+@ComponentScan
+@EnableTransactionManagement
+@PropertySource("jdbc.properties")
+public class AppConfig {
+ @Bean
+ DataSource createDataSource() { ... }
+}
+
+```
+
+ÔٻعËÒ»ÏÂHibernateºÍJPAµÄ`SessionFactory`Óë`EntityManagerFactory`£¬MyBatisÓëÖ®¶ÔÓ¦µÄÊÇ`SqlSessionFactory`ºÍ`SqlSession`£º
+
+| JDBC | Hibernate | JPA | MyBatis |
+| --- | --- | --- | --- |
+| DataSource | SessionFactory | EntityManagerFactory | SqlSessionFactory |
+| Connection | Session | EntityManager | SqlSession |
+
+¿É¼û£¬ORMµÄÉè¼ÆÌ×·¶¼ÊÇÀàËÆµÄ¡£Ê¹ÓÃMyBatisµÄºËÐľÍÊÇ´´½¨`SqlSessionFactory`£¬ÕâÀïÎÒÃÇÐèÒª´´½¨µÄÊÇ`SqlSessionFactoryBean`£º
+
+```
+@Bean
+SqlSessionFactoryBean createSqlSessionFactoryBean(@Autowired DataSource dataSource) {
+ var sqlSessionFactoryBean = new SqlSessionFactoryBean();
+ sqlSessionFactoryBean.setDataSource(dataSource);
+ return sqlSessionFactoryBean;
+}
+
+```
+
+ÒòΪMyBatis¿ÉÒÔÖ±½ÓʹÓÃSpring¹ÜÀíµÄÉùÃ÷ʽÊÂÎñ£¬Òò´Ë£¬´´½¨ÊÂÎñ¹ÜÀíÆ÷ºÍʹÓÃJDBCÊÇÒ»ÑùµÄ£º
+
+```
+@Bean
+PlatformTransactionManager createTxManager(@Autowired DataSource dataSource) {
+ return new DataSourceTransactionManager(dataSource);
+}
+
+```
+
+ºÍHibernate²»Í¬µÄÊÇ£¬MyBatisʹÓÃMapperÀ´ÊµÏÖÓ³É䣬¶øÇÒMapper±ØÐëÊǽӿڡ£ÎÒÃÇÒÔ`User`ÀàΪÀý£¬ÔÚ`User`ÀàºÍ`users`±íÖ®¼äÓ³ÉäµÄ`UserMapper`±àдÈçÏ£º
+
+```
+public interface UserMapper {
+ @Select("SELECT * FROM users WHERE id = #{id}")
+ User getById(@Param("id") long id);
+}
+
+```
+
+×¢Ò⣺ÕâÀïµÄMapper²»ÊÇ`JdbcTemplate`µÄ`RowMapper`µÄ¸ÅÄËüÊǶ¨Òå·ÃÎÊ`users`±íµÄ½Ó¿Ú·½·¨¡£±ÈÈçÎÒÃǶ¨ÒåÁËÒ»¸ö`User getById(long)`µÄÖ÷¼ü²éѯ·½·¨£¬²»½öÒª¶¨Òå½Ó¿Ú·½·¨±¾Éí£¬»¹ÒªÃ÷ȷд³ö²éѯµÄSQL£¬ÕâÀïÓÃ×¢½â`@Select`±ê¼Ç¡£SQLÓï¾äµÄÈκβÎÊý£¬¶¼Óë·½·¨²ÎÊý°´Ãû³Æ¶ÔÓ¦¡£ÀýÈ磬·½·¨²ÎÊýidµÄÃû×Öͨ¹ý×¢½â`@Param()`±ê¼ÇΪ`id`£¬ÔòSQLÓï¾äÀォÀ´Ìæ»»µÄռλ·û¾ÍÊÇ`#{id}`¡£
+
+Èç¹ûÓжà¸ö²ÎÊý£¬ÄÇôÿ¸ö²ÎÊýÃüÃûºóÖ±½ÓÔÚSQLÖÐд³ö¶ÔÓ¦µÄռλ·û¼´¿É£º
+
+```
+@Select("SELECT * FROM users LIMIT #{offset}, #{maxResults}")
+List getAll(@Param("offset") int offset, @Param("maxResults") int maxResults);
+
+```
+
+×¢Ò⣺MyBatisÖ´Ðвéѯºó£¬½«¸ù¾Ý·½·¨µÄ·µ»ØÀàÐÍ×Ô¶¯°ÑResultSetµÄÿһÐÐת»»ÎªUserʵÀý£¬×ª»»¹æÔòµ±È»Êǰ´ÁÐÃûºÍÊôÐÔÃû¶ÔÓ¦¡£Èç¹ûÁÐÃûºÍÊôÐÔÃû²»Í¬£¬×î¼òµ¥µÄ·½Ê½ÊDZàдSELECTÓï¾äµÄ±ðÃû£º
+
+```
+-- ÁÐÃûÊÇcreated_time£¬ÊôÐÔÃûÊÇcreatedAt:
+SELECT id, name, email, created_time AS createdAt FROM users
+
+```
+
+Ö´ÐÐINSERTÓï¾ä¾ÍÉÔ΢Âé·³µã£¬ÒòΪÎÒÃÇÏ£Íû´«ÈëUserʵÀý£¬Òò´Ë£¬¶¨ÒåµÄ·½·¨½Ó¿ÚÓë`@Insert`×¢½âÈçÏ£º
+
+```
+@Insert("INSERT INTO users (email, password, name, createdAt) VALUES (#{user.email}, #{user.password}, #{user.name}, #{user.createdAt})")
+void insert(@Param("user") User user);
+
+```
+
+ÉÏÊö·½·¨´«ÈëµÄ²ÎÊýÃû³ÆÊÇ`user`£¬²ÎÊýÀàÐÍÊÇUserÀ࣬ÔÚSQLÖÐÒýÓõÄʱºò£¬ÒÔ`#{obj.property}`µÄ·½Ê½Ð´Õ¼Î»·û¡£ºÍHibernateÕâÑùµÄÈ«×Ô¶¯»¯ORMÏà±È£¬MyBatis±ØÐëд³öÍêÕûµÄINSERTÓï¾ä¡£
+
+Èç¹û`users`±íµÄ`id`ÊÇ×ÔÔöÖ÷¼ü£¬ÄÇô£¬ÎÒÃÇÔÚSQLÖв»´«Èë`id`£¬µ«Ï£Íû»ñÈ¡²åÈëºóµÄÖ÷¼ü£¬ÐèÒªÔÙ¼ÓÒ»¸ö`@Options`×¢½â£º
+
+```
+@Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
+@Insert("INSERT INTO users (email, password, name, createdAt) VALUES (#{user.email}, #{user.password}, #{user.name}, #{user.createdAt})")
+void insert(@Param("user") User user);
+
+```
+
+`keyProperty`ºÍ`keyColumn`·Ö±ðÖ¸³öJavaBeanµÄÊôÐÔºÍÊý¾Ý¿âµÄÖ÷¼üÁÐÃû¡£
+
+Ö´ÐÐ`UPDATE`ºÍ`DELETE`Óï¾äÏà¶Ô±È½Ï¼òµ¥£¬ÎÒÃǶ¨Òå·½·¨ÈçÏ£º
+
+```
+@Update("UPDATE users SET name = #{user.name}, createdAt = #{user.createdAt} WHERE id = #{user.id}")
+void update(@Param("user") User user);
+
+@Delete("DELETE FROM users WHERE id = #{id}")
+void deleteById(@Param("id") long id);
+
+```
+
+ÓÐÁË`UserMapper`½Ó¿Ú£¬»¹ÐèÒª¶ÔÓ¦µÄʵÏÖÀà²ÅÄÜÕæÕýÖ´ÐÐÕâЩÊý¾Ý¿â²Ù×÷µÄ·½·¨¡£ËäÈ»¿ÉÒÔ×Ô¼ºÐ´ÊµÏÖÀ࣬µ«ÎÒÃdzýÁ˱àд`UserMapper`½Ó¿ÚÍ⣬»¹ÓÐ`BookMapper`¡¢`BonusMapper`¡¡Ò»¸öÒ»¸öд̫Âé·³£¬Òò´Ë£¬MyBatisÌṩÁËÒ»¸ö`MapperFactoryBean`À´×Ô¶¯´´½¨ËùÓÐMapperµÄʵÏÖÀà¡£¿ÉÒÔÓÃÒ»¸ö¼òµ¥µÄ×¢½âÀ´ÆôÓÃËü£º
+
+```
+@MapperScan("com.itranswarp.learnjava.mapper")
+...ÆäËû×¢½â...
+public class AppConfig {
+ ...
+}
+
+```
+
+ÓÐÁË`@MapperScan`£¬¾Í¿ÉÒÔÈÃMyBatis×Ô¶¯É¨ÃèÖ¸¶¨°üµÄËùÓÐMapper²¢´´½¨ÊµÏÖÀà¡£ÔÚÕæÕýµÄÒµÎñÂß¼ÖУ¬ÎÒÃÇ¿ÉÒÔÖ±½Ó×¢È룺
+
+```
+@Component
+@Transactional
+public class UserService {
+ // ×¢ÈëUserMapper:
+ @Autowired
+ UserMapper userMapper;
+
+ public User getUserById(long id) {
+ // µ÷ÓÃMapper·½·¨:
+ User user = userMapper.getById(id);
+ if (user == null) {
+ throw new RuntimeException("User not found by id.");
+ }
+ return user;
+ }
+}
+
+```
+
+¿É¼û£¬ÒµÎñÂß¼Ö÷Òª¾ÍÊÇͨ¹ý`XxxMapper`¶¨ÒåµÄÊý¾Ý¿â·½·¨À´·ÃÎÊÊý¾Ý¿â¡£
+
+### XMLÅäÖÃ
+
+ÉÏÊöÔÚSpringÖм¯³ÉMyBatisµÄ·½Ê½£¬ÎÒÃÇÖ»ÐèÒªÓõ½×¢½â£¬²¢Ã»ÓÐÈκÎXMLÅäÖÃÎļþ¡£MyBatisÒ²ÔÊÐíʹÓÃXMLÅäÖÃÓ³Éä¹ØÏµºÍSQLÓï¾ä£¬ÀýÈ磬¸üÐÂ`User`ʱ¸ù¾ÝÊôÐÔÖµ¹¹Ô춯̬SQL£º
+
+```
+
+ UPDATE users SET
+
+ name = #{user.name}
+ hobby = #{user.hobby}
+ summary = #{user.summary}
+
+ WHERE id = #{user.id}
+
+
+```
+
+±àдXMLÅäÖõÄÓŵãÊÇ¿ÉÒÔ×é×°³ö¶¯Ì¬SQL£¬²¢ÇÒ°ÑËùÓÐSQL²Ù×÷¼¯ÖÐÔÚÒ»Æð¡£È±µãÊÇÅäÖÃÆðÀ´Ì«·±Ëö£¬µ÷Ó÷½·¨Ê±Èç¹ûÏë²é¿´SQL»¹ÐèÒª¶¨Î»µ½XMLÅäÖÃÖС£ÕâÀïÎÒÃDz»½éÉÜXMLµÄÅäÖ÷½Ê½£¬ÐèÒªÁ˽âµÄͯЬÇë×ÔÐÐÔĶÁ[¹Ù·½Îĵµ](https://mybatis.org/mybatis-3/zh/configuration.html)¡£
+
+ʹÓÃMyBatis×î´óµÄÎÊÌâÊÇËùÓÐSQL¶¼ÐèҪȫ²¿ÊÖд£¬ÓŵãÊÇÖ´ÐеÄSQL¾ÍÊÇÎÒÃÇ×Ô¼ºÐ´µÄSQL£¬¶ÔSQL½øÐÐÓÅ»¯·Ç³£¼òµ¥£¬Ò²¿ÉÒÔ±àдÈÎÒ⸴ÔÓµÄSQL£¬»òÕßʹÓÃÊý¾Ý¿âµÄÌØ¶¨Óï·¨£¬µ«Çл»Êý¾Ý¿â¿ÉÄܾͲ»Ì«ÈÝÒס£ºÃÏûÏ¢ÊǴ󲿷ÖÏîÄ¿²¢Ã»ÓÐÇл»Êý¾Ý¿âµÄÐèÇó£¬ÍêÈ«¿ÉÒÔÕë¶Ôij¸öÊý¾Ý¿â±àд¾¡¿ÉÄÜÓÅ»¯µÄSQL¡£
+
+# ²Î¿¼ÎÄÕÂ
+https://www.w3cschool.cn/wkspring
+https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
+http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
+https://dunwu.github.io/spring-tutorial
+https://mszlu.com/java/spring
+http://c.biancheng.net/spring/aop-module.html
\ No newline at end of file
diff --git "a/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md" "b/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md"
new file mode 100644
index 0000000..a77e4a0
--- /dev/null
+++ "b/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md"
@@ -0,0 +1,715 @@
+# Spring УÑé
+
+
+
+Java API ¹æ·¶(`JSR303`)¶¨ÒåÁË`Bean`УÑéµÄ±ê×¼`validation-api`£¬µ«Ã»ÓÐÌṩʵÏÖ¡£`hibernate validation`ÊǶÔÕâ¸ö¹æ·¶µÄʵÏÖ£¬²¢Ôö¼ÓÁËУÑé×¢½âÈç`@Email`¡¢`@Length`µÈ¡£`Spring Validation`ÊǶÔ`hibernate validation`µÄ¶þ´Î·â×°£¬ÓÃÓÚÖ§³Ö`spring mvc`²ÎÊý×Ô¶¯Ð£Ñé¡£
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8)¿ìËÙÈëÃÅ
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E5%BC%95%E5%85%A5%E4%BE%9D%E8%B5%96)ÒýÈëÒÀÀµ
+
+Èç¹û spring-boot °æ±¾Ð¡ÓÚ 2.3.x£¬spring-boot-starter-web »á×Ô¶¯´«Èë hibernate-validator ÒÀÀµ¡£Èç¹û spring-boot °æ±¾´óÓÚ 2.3.x£¬ÔòÐèÒªÊÖ¶¯ÒýÈëÒÀÀµ£º
+
+
+
+```
+
+ org.hibernate.validator
+ hibernate-validator-parent
+ 6.2.5.Final
+
+
+```
+
+
+
+¶ÔÓÚ web ·þÎñÀ´Ëµ£¬Îª·ÀÖ¹·Ç·¨²ÎÊý¶ÔÒµÎñÔì³ÉÓ°Ï죬ÔÚ Controller ²ãÒ»¶¨Òª×ö²ÎÊýУÑéµÄ£¡´ó²¿·ÖÇé¿öÏ£¬ÇëÇó²ÎÊý·ÖΪÈçÏÂÁ½ÖÖÐÎʽ£º
+
+* POST¡¢PUT ÇëÇó£¬Ê¹Óà requestBody ´«µÝ²ÎÊý£»
+* GET ÇëÇó£¬Ê¹Óà requestParam/PathVariable ´«µÝ²ÎÊý¡£
+
+ʵ¼ÊÉÏ£¬²»¹ÜÊÇ requestBody ²ÎÊýУÑ黹ÊÇ·½·¨¼¶±ðµÄУÑ飬×îÖÕ¶¼Êǵ÷Óà Hibernate Validator Ö´ÐÐУÑ飬Spring Validation Ö»ÊÇ×öÁËÒ»²ã·â×°¡£
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E6%A0%A1%E9%AA%8C%E7%A4%BA%E4%BE%8B)УÑéʾÀý
+
+£¨1£©ÔÚʵÌåÉϱê¼ÇУÑé×¢½â
+
+
+
+```
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class User implements Serializable {
+
+ @NotNull
+ private Long id;
+
+ @NotBlank
+ @Size(min = 2, max = 10)
+ private String name;
+
+ @Min(value = 1)
+ @Max(value = 100)
+ private Integer age;
+
+}
+
+```
+
+
+
+£¨2£©ÔÚ·½·¨²ÎÊýÉÏÉùÃ÷УÑé×¢½â
+
+
+
+```
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("validate1")
+public class ValidatorController {
+
+ /**
+ * {@link RequestBody} ²ÎÊýУÑé
+ */
+ @PostMapping(value = "save")
+ public DataResult save(@Valid @RequestBody User entity) {
+ log.info("±£´æÒ»Ìõ¼Ç¼£º{}", JSONUtil.toJsonStr(entity));
+ return DataResult.ok(true);
+ }
+
+ /**
+ * {@link RequestParam} ²ÎÊýУÑé
+ */
+ @GetMapping(value = "queryByName")
+ public DataResult queryByName(
+ @RequestParam("username")
+ @NotBlank
+ @Size(min = 2, max = 10)
+ String name
+ ) {
+ User user = new User(1L, name, 18);
+ return DataResult.ok(user);
+ }
+
+ /**
+ * {@link PathVariable} ²ÎÊýУÑé
+ */
+ @GetMapping(value = "detail/{id}")
+ public DataResult detail(@PathVariable("id") @Min(1L) Long id) {
+ User user = new User(id, "ÀîËÄ", 18);
+ return DataResult.ok(user);
+ }
+
+}
+
+```
+
+
+
+£¨3£©Èç¹ûÇëÇó²ÎÊý²»Âú×ãУÑ鹿Ôò£¬Ôò»áÅ׳ö?`ConstraintViolationException`?»ò?`MethodArgumentNotValidException`?Òì³£¡£
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E7%BB%9F%E4%B8%80%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86)ͳһÒì³£´¦Àí
+
+ÔÚʵ¼ÊÏîÄ¿¿ª·¢ÖУ¬Í¨³£»áÓÃͳһÒì³£´¦ÀíÀ´·µ»ØÒ»¸ö¸üÓѺõÄÌáʾ¡£
+
+
+
+```
+@Slf4j
+@ControllerAdvice
+public class GlobalExceptionHandler {
+
+ /**
+ * ´¦ÀíËùÓв»¿ÉÖªµÄÒì³£
+ */
+ @ResponseBody
+ @ResponseStatus(HttpStatus.OK)
+ @ExceptionHandler(Throwable.class)
+ public Result handleException(Throwable e) {
+ log.error("δ֪Òì³£", e);
+ return new Result(ResultStatus.HTTP_SERVER_ERROR.getCode(), e.getMessage());
+ }
+
+ /**
+ * ͳһ´¦ÀíÇëÇó²ÎÊýУÑéÒì³£(ÆÕͨ´«²Î)
+ *
+ * @param e ConstraintViolationException
+ * @return {@link DataResult}
+ */
+ @ResponseBody
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ @ExceptionHandler({ ConstraintViolationException.class })
+ public Result handleConstraintViolationException(final ConstraintViolationException e) {
+ log.error("ConstraintViolationException", e);
+ List errors = new ArrayList<>();
+ for (ConstraintViolation> violation : e.getConstraintViolations()) {
+ Path path = violation.getPropertyPath();
+ List pathArr = StrUtil.split(path.toString(), ',');
+ errors.add(pathArr.get(0) + " " + violation.getMessage());
+ }
+ return new Result(ResultStatus.REQUEST_ERROR.getCode(), CollectionUtil.join(errors, ","));
+ }
+
+ /**
+ * ´¦Àí²ÎÊýУÑéÒì³£
+ *
+ * @param e MethodArgumentNotValidException
+ * @return {@link DataResult}
+ */
+ @ResponseBody
+ @ResponseStatus(HttpStatus.BAD_REQUEST)
+ @ExceptionHandler({ MethodArgumentNotValidException.class })
+ private Result handleMethodArgumentNotValidException(final MethodArgumentNotValidException e) {
+ log.error("MethodArgumentNotValidException", e);
+ List errors = new ArrayList<>();
+ for (ObjectError error : e.getBindingResult().getAllErrors()) {
+ errors.add(((FieldError) error).getField() + " " + error.getDefaultMessage());
+ }
+ return new Result(ResultStatus.REQUEST_ERROR.getCode(), CollectionUtil.join(errors, ","));
+ }
+
+}
+
+```
+
+
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E8%BF%9B%E9%98%B6%E4%BD%BF%E7%94%A8)½ø½×ʹÓÃ
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E5%88%86%E7%BB%84%E6%A0%A1%E9%AA%8C)·Ö×éУÑé
+
+ÔÚʵ¼ÊÏîÄ¿ÖУ¬¿ÉÄܶà¸ö·½·¨ÐèҪʹÓÃͬһ¸ö DTO ÀàÀ´½ÓÊÕ²ÎÊý£¬¶ø²»Í¬·½·¨µÄУÑ鹿ÔòºÜ¿ÉÄÜÊDz»Ò»ÑùµÄ¡£Õâ¸öʱºò£¬¼òµ¥µØÔÚ DTO ÀàµÄ×Ö¶ÎÉϼÓÔ¼Êø×¢½âÎÞ·¨½â¾öÕâ¸öÎÊÌâ¡£Òò´Ë£¬spring-validation Ö§³ÖÁË·Ö×éУÑéµÄ¹¦ÄÜ£¬×¨ÃÅÓÃÀ´½â¾öÕâÀàÎÊÌâ¡£
+
+£¨1£©¶¨Òå·Ö×é
+
+
+
+```
+@Target({ ElementType.FIELD, ElementType.PARAMETER })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AddCheck { }
+
+@Target({ ElementType.FIELD, ElementType.PARAMETER })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EditCheck { }
+
+```
+
+
+
+£¨2£©ÔÚʵÌåÉϱê¼ÇУÑé×¢½â
+
+
+
+```
+@Data
+public class User2 {
+
+ @NotNull(groups = EditCheck.class)
+ private Long id;
+
+ @NotNull(groups = { AddCheck.class, EditCheck.class })
+ @Size(min = 2, max = 10, groups = { AddCheck.class, EditCheck.class })
+ private String name;
+
+ @IsMobile(message = "²»ÊÇÓÐЧÊÖ»úºÅ", groups = { AddCheck.class, EditCheck.class })
+ private String mobile;
+
+}
+
+```
+
+
+
+£¨3£©ÔÚ·½·¨Éϸù¾Ý²»Í¬³¡¾°½øÐÐУÑé·Ö×é
+
+
+
+```
+@Slf4j
+@Validated
+@RestController
+@RequestMapping("validate2")
+public class ValidatorController2 {
+
+ /**
+ * {@link RequestBody} ²ÎÊýУÑé
+ */
+ @PostMapping(value = "add")
+ public DataResult add(@Validated(AddCheck.class) @RequestBody User2 entity) {
+ log.info("Ìí¼ÓÒ»Ìõ¼Ç¼£º{}", JSONUtil.toJsonStr(entity));
+ return DataResult.ok(true);
+ }
+
+ /**
+ * {@link RequestBody} ²ÎÊýУÑé
+ */
+ @PostMapping(value = "edit")
+ public DataResult edit(@Validated(EditCheck.class) @RequestBody User2 entity) {
+ log.info("±à¼Ò»Ìõ¼Ç¼£º{}", JSONUtil.toJsonStr(entity));
+ return DataResult.ok(true);
+ }
+
+}
+
+```
+
+
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E5%B5%8C%E5%A5%97%E6%A0%A1%E9%AA%8C)ǶÌ×УÑé
+
+Ç°ÃæµÄʾÀýÖУ¬DTO ÀàÀïÃæµÄ×ֶζ¼ÊÇ»ù±¾Êý¾ÝÀàÐÍºÍ String ÀàÐÍ¡£µ«ÊÇʵ¼Ê³¡¾°ÖУ¬ÓпÉÄÜij¸ö×Ö¶ÎÒ²ÊÇÒ»¸ö¶ÔÏó£¬ÕâÖÖÇé¿öÏÈ£¬¿ÉÒÔʹÓÃǶÌ×УÑé¡£ post ±ÈÈ磬ÉÏÃæ±£´æ User ÐÅÏ¢µÄʱºòͬʱ»¹´øÓÐ Job ÐÅÏ¢¡£ÐèҪעÒâµÄÊÇ£¬´Ëʱ DTO ÀàµÄ¶ÔÓ¦×ֶαØÐë±ê¼Ç@Valid ×¢½â¡£
+
+
+
+```
+@Data
+public class UserDTO {
+
+ @Min(value = 10000000000000000L, groups = Update.class)
+ private Long userId;
+
+ @NotNull(groups = {Save.class, Update.class})
+ @Length(min = 2, max = 10, groups = {Save.class, Update.class})
+ private String userName;
+
+ @NotNull(groups = {Save.class, Update.class})
+ @Length(min = 6, max = 20, groups = {Save.class, Update.class})
+ private String account;
+
+ @NotNull(groups = {Save.class, Update.class})
+ @Length(min = 6, max = 20, groups = {Save.class, Update.class})
+ private String password;
+
+ @NotNull(groups = {Save.class, Update.class})
+ @Valid
+ private Job job;
+
+ @Data
+ public static class Job {
+
+ @Min(value = 1, groups = Update.class)
+ private Long jobId;
+
+ @NotNull(groups = {Save.class, Update.class})
+ @Length(min = 2, max = 10, groups = {Save.class, Update.class})
+ private String jobName;
+
+ @NotNull(groups = {Save.class, Update.class})
+ @Length(min = 2, max = 10, groups = {Save.class, Update.class})
+ private String position;
+ }
+
+ /**
+ * ±£´æµÄʱºòУÑé·Ö×é
+ */
+ public interface Save {
+ }
+
+ /**
+ * ¸üеÄʱºòУÑé·Ö×é
+ */
+ public interface Update {
+ }
+}
+¸´ÖÆ´úÂë
+
+```
+
+
+
+ǶÌ×УÑé¿ÉÒÔ½áºÏ·Ö×éУÑéÒ»ÆðʹÓ᣻¹ÓоÍÊÇǶÌ×¼¯ºÏУÑé»á¶Ô¼¯ºÏÀïÃæµÄÿһÏî¶¼½øÐÐУÑ飬ÀýÈç`List`×ֶλá¶ÔÕâ¸ö list ÀïÃæµÄÿһ¸ö Job ¶ÔÏó¶¼½øÐÐУÑé
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%A1%E9%AA%8C%E6%B3%A8%E8%A7%A3)×Ô¶¨ÒåУÑé×¢½â
+
+£¨1£©×Ô¶¨ÒåУÑé×¢½â?`@IsMobile`
+
+
+
+```
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
+@Retention(RUNTIME)
+@Constraint(validatedBy = MobileValidator.class)
+public @interface IsMobile {
+
+ String message();
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+}
+
+```
+
+
+
+£¨2£©ÊµÏÖ?`ConstraintValidator`?½Ó¿Ú£¬±àд?`@IsMobile`?УÑé×¢½âµÄ½âÎöÆ÷
+
+
+
+```
+import cn.hutool.core.util.StrUtil;
+import io.github.dunwu.spring.core.validation.annotation.IsMobile;
+import io.github.dunwu.tool.util.ValidatorUtil;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class MobileValidator implements ConstraintValidator {
+
+ @Override
+ public void initialize(IsMobile isMobile) { }
+
+ @Override
+ public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
+ if (StrUtil.isBlank(s)) {
+ return false;
+ } else {
+ return ValidatorUtil.isMobile(s);
+ }
+ }
+
+}
+
+```
+
+
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%A1%E9%AA%8C)×Ô¶¨ÒåУÑé
+
+¿ÉÒÔͨ¹ýʵÏÖ?`org.springframework.validation.Validator`?½Ó¿ÚÀ´×Ô¶¨ÒåУÑé¡£
+
+ÓÐÒÔÏÂÒªµã
+
+* ʵÏÖ?`supports`?·½·¨
+* ʵÏÖ?`validate`?·½·¨
+ * ͨ¹ý?`Errors`?¶ÔÏóÊÕ¼¯´íÎó
+ * `ObjectError`£º¶ÔÏó£¨Bean£©´íÎó£º
+ * `FieldError`£º¶ÔÏó£¨Bean£©ÊôÐÔ£¨Property£©´íÎó
+ * ͨ¹ý?`ObjectError`?ºÍ?`FieldError`?¹ØÁª?`MessageSource`?ʵÏÖ»ñÈ¡×îÖյĴíÎóÎݸ
+
+
+
+```
+package io.github.dunwu.spring.core.validation;
+
+import io.github.dunwu.spring.core.validation.annotation.Valid;
+import io.github.dunwu.spring.core.validation.config.CustomValidatorConfig;
+import io.github.dunwu.spring.core.validation.entity.Person;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.Errors;
+import org.springframework.validation.ValidationUtils;
+import org.springframework.validation.Validator;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Component
+public class CustomValidator implements Validator {
+
+ private final CustomValidatorConfig validatorConfig;
+
+ public CustomValidator(CustomValidatorConfig validatorConfig) {
+ this.validatorConfig = validatorConfig;
+ }
+
+ /**
+ * ±¾Ð£ÑéÆ÷Ö»Õë¶Ô Person ¶ÔÏó½øÐÐУÑé
+ */
+ @Override
+ public boolean supports(Class> clazz) {
+ return Person.class.equals(clazz);
+ }
+
+ @Override
+ public void validate(Object target, Errors errors) {
+ ValidationUtils.rejectIfEmpty(errors, "name", "name.empty");
+
+ List fields = getFields(target.getClass());
+ for (Field field : fields) {
+ Annotation[] annotations = field.getAnnotations();
+ for (Annotation annotation : annotations) {
+ if (annotation.annotationType().getAnnotation(Valid.class) != null) {
+ try {
+ ValidatorRule validatorRule = validatorConfig.findRule(annotation);
+ if (validatorRule != null) {
+ validatorRule.valid(annotation, target, field, errors);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+ private List getFields(Class> clazz) {
+ // ÉùÃ÷FieldÊý×é
+ List fields = new ArrayList<>();
+ // Èç¹ûclassÀàÐͲ»Îª¿Õ
+ while (clazz != null) {
+ // Ìí¼ÓÊôÐÔµ½ÊôÐÔÊý×é
+ Collections.addAll(fields, clazz.getDeclaredFields());
+ clazz = clazz.getSuperclass();
+ }
+ return fields;
+ }
+
+}
+
+```
+
+
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E5%BF%AB%E9%80%9F%E5%A4%B1%E8%B4%A5-fail-fast)¿ìËÙʧ°Ü(Fail Fast)
+
+Spring Validation ĬÈÏ»áУÑéÍêËùÓÐ×ֶΣ¬È»ºó²ÅÅ׳öÒì³£¡£¿ÉÒÔͨ¹ýһЩ¼òµ¥µÄÅäÖ㬿ªÆô Fali Fast ģʽ£¬Ò»µ©Ð£Ñéʧ°Ü¾ÍÁ¢¼´·µ»Ø¡£
+
+
+
+```
+@Bean
+public Validator validator() {
+ ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
+ .configure()
+ // ¿ìËÙʧ°Üģʽ
+ .failFast(true)
+ .buildValidatorFactory();
+ return validatorFactory.getValidator();
+}
+
+```
+
+
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#spring-%E6%A0%A1%E9%AA%8C%E5%8E%9F%E7%90%86)Spring УÑéÔÀí
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#spring-%E6%A0%A1%E9%AA%8C%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF)Spring УÑéʹÓó¡¾°
+
+* Spring ³£¹æÐ£Ñ飨Validator£©
+* Spring Êý¾Ý°ó¶¨£¨DataBinder£©
+* Spring Web ²ÎÊý°ó¶¨£¨WebDataBinder£©
+* Spring WebMVC/WebFlux ´¦Àí·½·¨²ÎÊýУÑé
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#validator-%E6%8E%A5%E5%8F%A3%E8%AE%BE%E8%AE%A1)Validator ½Ó¿ÚÉè¼Æ
+
+* ½Ó¿ÚÖ°Ôð
+ * Spring ÄÚ²¿Ð£ÑéÆ÷½Ó¿Ú£¬Í¨¹ý±à³ÌµÄ·½Ê½Ð£ÑéÄ¿±ê¶ÔÏó
+* ºËÐÄ·½·¨
+ * `supports(Class)`£ºÐ£ÑéÄ¿±êÀàÄÜ·ñУÑé
+ * `validate(Object,Errors)`£ºÐ£ÑéÄ¿±ê¶ÔÏ󣬲¢½«Ð£Ñéʧ°ÜµÄÄÚÈÝÊä³öÖÁ Errors ¶ÔÏó
+* ÅäÌ××é¼þ
+ * ´íÎóÊÕ¼¯Æ÷£º`org.springframework.validation.Errors`
+ * Validator ¹¤¾ßÀࣺ`org.springframework.validation.ValidationUtils`
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#errors-%E6%8E%A5%E5%8F%A3%E8%AE%BE%E8%AE%A1)Errors ½Ó¿ÚÉè¼Æ
+
+* ½Ó¿ÚÖ°Ôð
+ * Êý¾Ý°ó¶¨ºÍУÑé´íÎóÊÕ¼¯½Ó¿Ú£¬Óë Java Bean ºÍÆäÊôÐÔÓÐÇ¿¹ØÁªÐÔ
+* ºËÐÄ·½·¨
+ * `reject`?·½·¨£¨ÖØÔØ£©£ºÊÕ¼¯´íÎóÎݸ
+ * `rejectValue`?·½·¨£¨ÖØÔØ£©£ºÊÕ¼¯¶ÔÏó×Ö¶ÎÖеĴíÎóÎݸ
+* ÅäÌ××é¼þ
+ * Java Bean ´íÎóÃèÊö£º`org.springframework.validation.ObjectError`
+ * Java Bean ÊôÐÔ´íÎóÃèÊö£º`org.springframework.validation.FieldError`
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#errors-%E6%96%87%E6%A1%88%E6%9D%A5%E6%BA%90)Errors ÎݸÀ´Ô´
+
+Errors ÎݸÉú³É²½Öè
+
+* Ñ¡Ôñ Errors ʵÏÖ£¨È磺`org.springframework.validation.BeanPropertyBindingResult`£©
+* µ÷ÓÃ reject »ò rejectValue ·½·¨
+* »ñÈ¡ Errors ¶ÔÏóÖÐ ObjectError »ò FieldError
+* ½« ObjectError »ò FieldError ÖÐµÄ code ºÍ args£¬¹ØÁª MessageSource ʵÏÖ£¨È磺`ResourceBundleMessageSource`£©
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#spring-web-%E6%A0%A1%E9%AA%8C%E5%8E%9F%E7%90%86)spring web УÑéÔÀí
+
+#### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#requestbody-%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86)RequestBody ²ÎÊýУÑéʵÏÖÔÀí
+
+ÔÚ spring-mvc ÖУ¬`RequestResponseBodyMethodProcessor`?ÊÇÓÃÓÚ½âÎö?`@RequestBody`?±ê×¢µÄ²ÎÊýÒÔ¼°´¦Àí`@ResponseBody`?±ê×¢·½·¨µÄ·µ»ØÖµµÄ¡£ÆäÖУ¬Ö´ÐвÎÊýУÑéµÄÂß¼¿Ï¶¨¾ÍÔÚ½âÎö²ÎÊýµÄ·½·¨?`resolveArgument()`?ÖУº
+
+
+
+```
+@Override
+public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
+ NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
+
+ parameter = parameter.nestedIfOptional();
+ Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
+ String name = Conventions.getVariableNameForParameter(parameter);
+
+ if (binderFactory != null) {
+ WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
+ if (arg != null) {
+ // ³¢ÊÔ½øÐвÎÊýУÑé
+ validateIfApplicable(binder, parameter);
+ if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
+ // Èç¹û´æÔÚУÑé´íÎó£¬ÔòÅ׳ö MethodArgumentNotValidException
+ throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
+ }
+ }
+ if (mavContainer != null) {
+ mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
+ }
+ }
+
+ return adaptArgumentIfNecessary(arg, parameter);
+}
+
+```
+
+
+
+¿ÉÒÔ¿´µ½£¬resolveArgument()µ÷ÓÃÁË validateIfApplicable()½øÐвÎÊýУÑé¡£
+
+
+
+```
+protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
+ // »ñÈ¡²ÎÊý×¢½â£¬Èç @RequestBody¡¢@Valid¡¢@Validated
+ Annotation[] annotations = parameter.getParameterAnnotations();
+ for (Annotation ann : annotations) {
+ // Ïȳ¢ÊÔ»ñÈ¡ @Validated ×¢½â
+ Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
+ // Èç¹û±ê×¢ÁË @Validated£¬Ö±½Ó¿ªÊ¼Ð£Ñé¡£
+ // Èç¹ûûÓУ¬ÄÇôÅжϲÎÊýǰÊÇ·ñÓÐ Valid ¿ªÍ·µÄ×¢½â¡£
+ if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
+ Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
+ Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
+ // Ö´ÐÐУÑé
+ binder.validate(validationHints);
+ break;
+ }
+ }
+}
+
+```
+
+
+
+ÒÔÉÏ´úÂ룬¾Í½âÊÍÁË Spring ΪʲôÄÜͬʱ֧³Ö?`@Validated`¡¢`@Valid`?Á½¸ö×¢½â¡£
+
+½ÓÏÂÀ´£¬¿´Ò»Ï WebDataBinder.validate() µÄʵÏÖ£º
+
+
+
+```
+@Override
+public void validate(Object target, Errors errors, Object... validationHints) {
+ if (this.targetValidator != null) {
+ processConstraintViolations(
+ // ´Ë´¦µ÷Óà Hibernate Validator Ö´ÐÐÕæÕýµÄУÑé
+ this.targetValidator.validate(target, asValidationGroups(validationHints)), errors);
+ }
+}
+
+```
+
+
+
+ͨ¹ýÉÏÃæ´úÂ룬¿ÉÒÔ¿´³ö Spring УÑéʵ¼ÊÉÏÊÇ»ùÓÚ Hibernate Validator µÄ·â×°¡£
+
+#### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E6%96%B9%E6%B3%95%E7%BA%A7%E5%88%AB%E7%9A%84%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86)·½·¨¼¶±ðµÄ²ÎÊýУÑéʵÏÖÔÀí
+
+Spring Ö§³Ö¸ù¾Ý·½·¨È¥½øÐÐÀ¹½Ø¡¢Ð£Ñ飬ÔÀí¾ÍÔÚÓÚÓ¦ÓÃÁË AOP ¼¼Êõ¡£¾ßÌåÀ´Ëµ£¬ÊÇͨ¹ý?`MethodValidationPostProcessor`?¶¯Ì¬×¢²á AOP ÇÐÃæ£¬È»ºóʹÓÃ?`MethodValidationInterceptor`?¶ÔÇе㷽·¨Ö¯ÈëÔöÇ¿¡£
+
+
+
+```
+public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessorimplements InitializingBean {
+ @Override
+ public void afterPropertiesSet() {
+ // ΪËùÓÐ @Validated ±ê×¢µÄ Bean ´´½¨ÇÐÃæ
+ Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
+ // ´´½¨ Advisor ½øÐÐÔöÇ¿
+ this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator));
+ }
+
+ // ´´½¨ Advice£¬±¾ÖʾÍÊÇÒ»¸ö·½·¨À¹½ØÆ÷
+ protected Advice createMethodValidationAdvice(@Nullable Validator validator) {
+ return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor());
+ }
+}
+
+```
+
+
+
+½Ó×Å¿´Ò»ÏÂ?`MethodValidationInterceptor`£º
+
+
+
+```
+public class MethodValidationInterceptor implements MethodInterceptor {
+ @Override
+ public Object invoke(MethodInvocation invocation) throws Throwable {
+ // ÎÞÐèÔöÇ¿µÄ·½·¨£¬Ö±½ÓÌø¹ý
+ if (isFactoryBeanMetadataMethod(invocation.getMethod())) {
+ return invocation.proceed();
+ }
+ // »ñÈ¡·Ö×éÐÅÏ¢
+ Class>[] groups = determineValidationGroups(invocation);
+ ExecutableValidator execVal = this.validator.forExecutables();
+ Method methodToValidate = invocation.getMethod();
+ Set> result;
+ try {
+ // ·½·¨Èë²ÎУÑ飬×îÖÕ»¹ÊÇίÍиø Hibernate Validator À´Ð£Ñé
+ result = execVal.validateParameters(
+ invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
+ }
+ catch (IllegalArgumentException ex) {
+ ...
+ }
+ // ÓÐÒì³£Ö±½ÓÅ׳ö
+ if (!result.isEmpty()) {
+ throw new ConstraintViolationException(result);
+ }
+ // ÕæÕýµÄ·½·¨µ÷ÓÃ
+ Object returnValue = invocation.proceed();
+ // ¶Ô·µ»ØÖµ×öУÑ飬×îÖÕ»¹ÊÇίÍиøHibernate ValidatorÀ´Ð£Ñé
+ result = execVal.validateReturnValue(invocation.getThis(), methodToValidate, returnValue, groups);
+ // ÓÐÒì³£Ö±½ÓÅ׳ö
+ if (!result.isEmpty()) {
+ throw new ConstraintViolationException(result);
+ }
+ return returnValue;
+ }
+}
+
+```
+
+
+
+ʵ¼ÊÉÏ£¬²»¹ÜÊÇ requestBody ²ÎÊýУÑ黹ÊÇ·½·¨¼¶±ðµÄУÑ飬×îÖÕ¶¼Êǵ÷Óà Hibernate Validator Ö´ÐÐУÑ飬Spring Validation Ö»ÊÇ×öÁËÒ»²ã·â×°¡£
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E9%97%AE%E9%A2%98)ÎÊÌâ
+
+**Spring ÓÐÄÄЩУÑéºËÐÄ×é¼þ**£¿
+
+* ¼ìÑéÆ÷£º`org.springframework.validation.Validator`
+* ´íÎóÊÕ¼¯Æ÷£º`org.springframework.validation.Errors`
+* Java Bean ´íÎóÃèÊö£º`org.springframework.validation.ObjectError`
+* Java Bean ÊôÐÔ´íÎóÃèÊö£º`org.springframework.validation.FieldError`
+* Bean Validation ÊÊÅ䣺`org.springframework.validation.beanvalidation.LocalValidatorFactoryBean`
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99)²Î¿¼×ÊÁÏ
+
+* [Spring ¹Ù·½ÎĵµÖ® Core Technologies(opens new window)](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans)
+* [¡¶Ð¡Âí¸ç½² Spring ºËÐıà³Ì˼Ïë¡·(opens new window)](https://time.geekbang.org/course/intro/265)
+* https://juejin.cn/post/6856541106626363399
+
+
+# ²Î¿¼ÎÄÕÂ
+https://www.w3cschool.cn/wkspring
+https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
+http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
+https://dunwu.github.io/spring-tutorial
+https://mszlu.com/java/spring
+http://c.biancheng.net/spring/aop-module.html
\ No newline at end of file
diff --git "a/docs/spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md" "b/docs/spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md"
new file mode 100644
index 0000000..2c2f21a
--- /dev/null
+++ "b/docs/spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md"
@@ -0,0 +1,852 @@
+
+
+
+
+Èç½ñ£¬ÖÂÁ¦ÓÚ°ïÖú¿ª·¢ÕßÓøüÉٵĴúÂë¡¢¸ü¿ìµØÐ´³öÉú²ú¼¶ÏµÍ³µÄ Spring Boot ÒÑÈ»³ÉΪ Java Ó¦Óÿª·¢µÄÊÂʵ±ê×¼¡£ÔÚ Spring Boot ÌṩµÄÖÚ¶àÌØÐÔÖУ¬**×Ô¶¯ÅäÖÃ**ÎÞÒÉÊǶÔÌáÉý¿ª·¢ÌåÑé×îÏÔÖøµÄÒ»¸öÌØÐÔ£¬Spring Boot »ùÓÚÕâÒ»ÌØÐÔΪ¿ª·¢ÈËÔ±×Ô¶¯ÉùÃ÷ÁËÈô¸É¿ªÏä¼´Óᢾ߱¸Ä³Ò»¹¦ÄÜµÄ Bean¡£´ó¶àÊýÇé¿öÏ£¬×Ô¶¯ÅäÖÃµÄ Bean ¸ÕºÃÄÜÂú×ã´ó¼ÒµÄÐèÇ󣬵«ÔÚijЩÇé¿öÏ£¬²»µÃ²»ÍêÕûµØ¸²¸ÇËüÃÇ£¬Õâ¸öʱºòÖ»ÐèÒªÖØÐÂÉùÃ÷Ïà¹ØÀàÐ굀 Bean ¼´¿É£¬ÒòΪ¾ø´ó¶àÊý×Ô¶¯ÅäÖÃµÄ Bean ¶¼»áÓÉ`@ConditionalOnMissingBean`×¢½âÐÞÊΡ£ÐÒÔ˵ÄÊÇ£¬Èç¹ûÖ»ÊÇÏë΢µ÷һЩϸ½Ú£¬±ÈÈç¸Ä¸Ä¶Ë¿ÚºÅ (server.port) ºÍÊý¾ÝÔ´ URL (spring.datasource.url) £¬ÄÇѹ¸ùû±ØÒªÖØÐÂÉùÃ÷`ServerProperties`ºÍ`DataSourceProperties`ÕâÁ© Bean À´¸²¸Ç×Ô¶¯ÅäÖÃµÄ Bean¡£ Spring Boot Ϊ×Ô¶¯ÅäÖÃµÄ Bean ÌṩÁË1000¶à¸öÓÃÓÚ΢µ÷µÄÊôÐÔ£¬µ±ÐèÒªµ÷ÕûÉèÖÃʱ£¬Ö»ÐèÒªÔÚ»·¾³±äÁ¿¡¢ÃüÁîÐвÎÊý»òÅäÖÃÎļþ (application.properties/application.yml) ÖнøÐÐÖ¸¶¨¼´¿É£¬Õâ¾ÍÊÇ Spring Boot µÄ`Externalized Configuration` (ÅäÖÃÍ⻯) ÌØÐÔ¡£
+
+µ±È»£¬ÍⲿÅäÖÃÔ´²¢²»¾ÖÏÞÓÚ»·¾³±äÁ¿¡¢ÃüÁîÐвÎÊýºÍÅäÖÃÎļþÕâÈýÖÖ£¬¸ÐÐËȤµÄ¶ÁÕß¿ÉÒÔ×ÔÐÐÔĶÁ Spring Boot ¹Ù·½Îĵµ¡£ÔÚ Spring ÖУ¬`BeanFactory`°çÑÝ×Å Bean ÈÝÆ÷µÄ½ÇÉ«£¬¶ø`Environment`ͬÑù¶¨Î»ÎªÒ»¸öÈÝÆ÷£¬¼´ÍⲿÅäÖÃÔ´ÖеÄÊôÐÔ¶¼»á±»Ìí¼Óµ½ _Environment_ ÖС£**ÔÚ΢·þÎñ´óÐÐÆäµÀµÄ½ñÌ죬ÍⲿÅäÖÃÔ´ÓÖÑÜÉú³öÁË_Disconf_¡¢_Apollo_ ºÍ _Nacos_ µÈ·Ö²¼Ê½ÅäÖÃÖÐÐÄ£¬µ«ÔÚ Spring µÄµØÅÌ£¬»¹ÊÇÒªÈëÏçËæË×£¬´ÓÅäÖÃÖÐÐÄÖжÁÈ¡µ½µÄÊôÐÔÒÀÈ»»á±»×·¼Óµ½ _Environment_ ÖÐ**¡£
+
+±ÊÕßÖ®ËùÒÔдÕâÆªÎÄÕ£¬ÊÇÊÜ`jasypt`×é¼þµÄÆô·¢¡£µÚÒ»´Î½Ó´¥ËüÊÇÔÚ2018Ä꣬µ±Ê±¾ÍºÜºÃÆæÕâÍæÒâ¶ù¾¿¾¹ÊÇÈçºÎʵÏÖ¶ÔÃô¸ÐÊôÐÔ¼Ó½âÃܵģ»ÏÖÔÚÀ´¿´£¬ÒªÏëʵÏÖÕâôһ¸ö¶«¶«£¬²»½öÐèÒªÊìϤ Bean µÄÉúÃüÖÜÆÚ¡¢IoC ÈÝÆ÷ÍØÕ¹µã (IoC Container Extension Points) ºÍ Spring Boot µÄÆô¶¯Á÷³ÌµÈ֪ʶ£¬»¹ÐèÒªÕÆÎÕ _Environment_¡£
+
+> jasypt ÉÏÊÖÊ®·Ö¼òµ¥¡£Ê×ÏÈͨ¹ý`jasypt-maven-plugin`ÕâÒ» maven ²å¼þΪÃô¸ÐÊôÐÔÖµÉú³ÉÃÜÎÄ£¬È»ºóÓÃ`ENC(ÃÜÎÄ)`Ìæ»»Ãô¸ÐÊôÐÔÖµ¼´¿É¡£ÈçÏ£º
+>
+> ```
+> jasypt.encryptor.password=crimson_typhoon
+>
+> spring.datasource.url=jdbc:mysql://HOST:PORT/db_sql_boy?characterEncoding=UTF-8
+> spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
+> spring.datasource.hikari.username=root
+> spring.datasource.hikari.password=ENC(qS8+DEIlHxvhPHgn1VaW3oHkn2twrmwNOHewWLIfquAXiCDBrKwvIhDoqalKyhIF)
+> ¸´ÖÆ´úÂë
+> ```
+
+## 1 ÈÏʶ Environmnent
+
+ÔÚʵ¼Ê¹¤×÷ÖУ¬ÎÒÃÇÓë _Environment_ ´ò½»µÀµÄ»ú»á²¢²»¶à£»Èç¹ûÒµÎñ Bean ȷʵÐèÒª»ñÈ¡ÍⲿÅäÖÃÔ´ÖеÄijһÊôÐÔÖµ£¬¿ÉÒÔÊÖ¶¯½« _Environment_ ×¢Èëµ½¸ÃÒµÎñ Bean ÖУ¬Ò²¿ÉÒÔÖ±½ÓʵÏÖ`EnvironmentAware`½Ó¿Ú£¬µÃµ½ _Environment_ ÀàÐ굀 Bean ʵÀýÖ®ºó¿ÉÒÔͨ¹ý`getProperty()`»ñÈ¡¾ßÌåÊôÐÔÖµ¡£_Environment_ ½Ó¿ÚÄÚÈÝÈçÏÂËùʾ£º
+
+```
+public interface Environment extends PropertyResolver {
+ String[] getActiveProfiles();
+ String[] getDefaultProfiles();
+ boolean acceptsProfiles(Profiles profiles);
+}
+
+public interface PropertyResolver {
+ boolean containsProperty(String key);
+ String getProperty(String key);
+ String getProperty(String key, String defaultValue);
+ T getProperty(String key, Class targetType);
+ T getProperty(String key, Class targetType, T defaultValue);
+ String resolvePlaceholders(String text);
+}
+¸´ÖÆ´úÂë
+```
+
+**´ó¼Ò²»ÒªÊÜ _Environment_ ÖÐ _getProperty()_ ·½·¨µÄÎóµ¼£¬ÍⲿÅäÖÃÔ´ÖеÄÊôÐÔ²¢²»ÊÇÒÔµ¥¸öÊôÐÔΪά¶È±»Ìí¼Óµ½ _Environment_ Öе쬶øÊÇÒÔ`PropertySource`Ϊά¶È**¡£_PropertySource_ ÊǶÔÊôÐÔÔ´Ãû³ÆºÍ¸ÃÊôÐÔÔ´ÖÐÒ»×éÊôÐԵijéÏó£¬`MapPropertySource`ÊÇÒ»ÖÖ×î¼òµ¥µÄʵÏÖ£¬Ëüͨ¹ý _Map_ À´³ÐÔØÏà¹ØµÄÊôÐÔ¡£_PropertySource_ ÄÚÈÝÈçÏ£º
+
+```
+public abstract class PropertySource {
+ protected final String name;
+ protected final T source;
+
+ public PropertySource(String name, T source) {
+ this.name = name;
+ this.source = source;
+ }
+
+ public String getName() { return this.name; }
+ public T getSource() { return this.source; }
+ public abstract Object getProperty(String name);
+}
+¸´ÖÆ´úÂë
+```
+
+´ÓÉÏÊö _PropertySource_ ÄÚÈÝÀ´¿´£¬_PropertySource_ ×ÔÉíÊǾ߱¸¸ù¾ÝÊôÐÔÃû»ñÈ¡ÊôÐÔÖµÕâÒ»ÄÜÁ¦µÄ¡£
+
+#### ****getProperty()ÄÚ²¿Ö´ÐÐÂß¼****
+
+
+
+Ò»°ã£¬_Environment_ ʵÏÖÀàÖлá³ÖÓÐÒ»¸ö`PropertyResolver`ÀàÐ͵ijÉÔ±±äÁ¿£¬½ø¶ø½»ÓÉ _PropertyResolver_ ¸ºÔðÖ´ÐÐ _getProperty()_ Âß¼¡£_PropertyResolver_ ʵÏÖÀàÖÐÓÖ»á³ÖÓÐÁ½¸ö³ÉÔ±±äÁ¿£¬·Ö±ðÊÇ£º`ConversionService`Óë`PropertySources`£»Ê×ÏÈ£¬_PropertyResolver_ ±éÀú `PropertySources` ÖÐµÄ _PropertySource_£¬»ñÈ¡ÔÉúÊôÐÔÖµ£»È»ºóίÅÉ _ConversionService_ ¶ÔÔÉúÊôÐÔÖµ½øÐÐÊý¾ÝÀàÐÍת»» (Èç¹ûÓбØÒªµÄ»°)¡£**ËäÈ» PropertySource ×ÔÉíÊǾ߱¸¸ù¾ÝÊôÐÔÃû»ñÈ¡ÊôÐÔÖµÕâÒ»ÄÜÁ¦µÄ£¬µ«²»¾ß±¸Õ¼Î»·û½âÎöÓëÀàÐÍת»»ÄÜÁ¦£¬ÓÚÊÇÔÚÖмäÒýÈë¾ß±¸ÕâÁ½ÖÖÄÜÁ¦µÄ PropertyResolver£¬ ÕâÒ²Ó¡Ö¤ÁËÒ»¸ö¶Î×Ó£ºÔÚ¼ÆËã»ú¿ÆÑ§ÖУ¬Ã»ÓÐʲôÎÊÌâÊÇÔÚÖмä¼ÓÒ»²ã½â¾ö²»Á˵ģ¬Èç¹ûÓУ¬ÄǾÍÔÙ¼ÓÒ»²ã**¡£
+
+#### ****PropertySourceÄÚ²¿¸üÐÂÂß¼****
+
+
+
+_Environment_ ʵÏÖÀàÖгýÁ˳ÖÓÐ`PropertyResolver`ÀàÐ͵ijÉÔ±±äÁ¿Í⣬»¹ÓÐÒ»¸ö`MutablePropertySources`ÀàÐ͵ijÉÔ±±äÁ¿£¬µ«²¢²»Ìṩֱ½Ó²Ù×÷¸Ã _MutablePropertySources_ µÄ·½·¨£¬ÎÒÃÇÖ»ÄÜͨ¹ý`getPropertySources()`·½·¨»ñÈ¡ _MutablePropertySources_ ʵÀý£¬È»ºó½èÖú _MutablePropertySources_ ÖеÄ`addFirst()`¡¢`addLast()`ºÍ`replace()`µÈ·½·¨È¥¸üР_PropertySource_¡£_MutablePropertySources_ ÊÇ _PropertySources_ Ψһһ¸öʵÏÖÀ࣬ÈçÏÂͼËùʾ£º
+
+
+
+×ܵÄÀ´Ëµ£¬_Environment_ ÊÇ¶Ô _PropertySource_ ºÍ _Profile_ µÄ¶¥¼¶³éÏó£¬ÏÂÃæ½éÉÜ _Profile_ µÄ¸ÅÄî¡£µ±Ó¦ÓóÌÐòÐèÒª²¿Êðµ½²»Í¬µÄÔËÐл·¾³Ê±£¬Ò»Ð©ÊôÐÔÏîͨ³£»áÓÐËù²»Í¬£¬±ÈÈ磬Êý¾ÝÔ´ URL ÔÚ¿ª·¢»·¾³ºÍ²âÊÔ»·¾³¾Í»á²»Ò»Ñù¡£Spring ´Ó3.1°æ±¾¿ªÊ¼Ö§³Ö»ùÓÚ _Profile_ µÄÌõ¼þ»¯ÅäÖá£
+
+**Profile in Spring 3.1**
+
+ÔÚ Spring ·¢²¼3.1°æ±¾Ê±£¬Spring Boot »¹Î´ÎÊÊÀ£¬¿ÉÒÔ˵´ËʱµÄ _Profile_ ÌØÐÔ»¹ÊÇÓÐЩ**覴Ã**µÄ£¬µ«è¦²»ÑÚ褡£Ö÷ÒªÌåÏÖÔÚ£ºÕë¶ÔͬһÀàÐ굀 Bean£¬±ØÐëÉùÃ÷¶à´Î¡£Ò»ÆðÀ´¸ÐÊÜÏÂÕâÖÖС覴ãº
+
+```
+@Configuration(proxyBeanMethods = false)
+public class DataSourceConfig {
+ @Bean
+ @Profile("dev")
+ public DataSource devDataSource () {
+ return DataSourceBuilder.create()
+ .driverClassName("com.mysql.jdbc.Driver")
+ .url("jdbc:mysql://DEV_HOST:PORT/db_sql_boy?characterEncoding=UTF-8")
+ .username("dev")
+ .password("dev")
+ .build();
+ }
+
+ @Bean
+ @Profile("test")
+ public DataSource testDataSource () {
+ return DataSourceBuilder.create()
+ .driverClassName("com.mysql.jdbc.Driver")
+ .url("jdbc:mysql://TEST_HOST:PORT/db_sql_boy?characterEncoding=UTF-8")
+ .username("test")
+ .password("test")
+ .build();
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+**Profile in Spring Boot**
+
+Spring Boot ·¢²¼ºó£¬`@Profile`×¢½â¿ÉÒÔÈÓµ½¾ÅÏöÔÆÍâÁË¡£¹Ù·½¿ª·¢´óÀп϶¨Ò²Òâʶµ½ _Profile in Spring 3.1_ ÖÐÕâÖÖ覴ã¬ÓÚÊÇÔÚ Spring Boot µÄµÚÒ»°æ±¾ _(1.0.0.RELEASE)_ ÖÐ¾ÍÆÈ²»¼°´ýµØÖ§³ÖΪ _application.properties_ ºÍ _application.yml_ ÀïµÄÊôÐÔÏîÅäÖà _Profile_ ÁË¡£»»¸ö¿Ú棬һÆðÀ´¸ÐÊÜÏÂÕâÖÖÓÅÑÅ£º
+
+```
+@Configuration(proxyBeanMethods = false)
+public class DataSourceConfig {
+ @Bean
+ public DataSource devDataSource (DataSourceProperties dataSourceProperties) {
+ return DataSourceBuilder.create()
+ .driverClassName(dataSourceProperties.getDriverClassName())
+ .url(dataSourceProperties.getUrl())
+ .username(dataSourceProperties.getUsername())
+ .password(dataSourceProperties.getPassword())
+ .build();
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+_application-dev.properties_ ÄÚÈÝÈçÏ£º
+
+```
+spring.datasource.url=jdbc:mysql://DEV_HOST:PORT/db_sql_boy?characterEncoding=UTF-8
+spring.datasource.hikari.driver-class-name=com.mysql.jdbc.Driver
+spring.datasource.hikari.password=dev
+spring.datasource.hikari.username=dev
+¸´ÖÆ´úÂë
+```
+
+_application-test.properties_ ÄÚÈÝÈçÏ£º
+
+```
+spring.datasource.url=jdbc:mysql://TEST_HOST:PORT/db_sql_boy?characterEncoding=UTF-8
+spring.datasource.hikari.driver-class-name=com.mysql.jdbc.Driver
+spring.datasource.hikari.password=test
+spring.datasource.hikari.username=test
+¸´ÖÆ´úÂë
+```
+
+ÔÚÔÉú Spring 3.1 ºÍ Spring Boot ÖУ¬¾ùÊÇͨ¹ý`spring.profiles.active`À´Îª _Environment_ Ö¸¶¨¼¤»îµÄ _Profile_£¬·ñÔò_Environment_ ÖÐĬÈϼ¤»îµÄ _Profile_ Ãû³ÆÎª`default`¡£Ð´µ½ÕâÀ±ÊÕßÄÔº£ÖÐÉÁÏÖÒ»¸öÎÊÌ⣺һ°ã£¬`@Profile` ×¢½âÖ÷ÒªÓë _@Configuration_ ×¢½â»ò _@Bean_ ×¢½â´îÅäʹÓã¬Èç¹û _spring.profiles.active_ µÄֵΪ _dev_ ʱ£¬ÄÇôÄÇЩÓÉ _@Configuration_ »ò _@Bean_ ×¢½â±ê¼Ç (µ«Ã»ÓÐ`@Profile`×¢½âµÄÉíÓ°¹þ) µÄ Bean »¹»á±»½âÎöΪÈô¸É`BeanDefinition`ʵÀýÂ𣿴ð°¸ÊÇ»áµÄ¡£`ConfigurationClassPostProcessor`¸ºÔ𽫠_@Configuration_ ÅäÖÃÀà½âÎöΪ _BeanDefinition_£¬Ôڴ˹ý³ÌÖлáÖ´ÐÐ`ConditionEvaluator`µÄ`shouldSkip()`·½·¨£¬Ö÷ÒªÄÚÈÝÈçÏ£º
+
+```
+public class ConditionEvaluator {
+ public boolean shouldSkip(AnnotatedTypeMetadata metadata, ConfigurationCondition.ConfigurationPhase phase) {
+ if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
+ return false;
+ }
+
+ if (phase == null) {
+ if (metadata instanceof AnnotationMetadata &&
+ ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
+ return shouldSkip(metadata, ConfigurationCondition.ConfigurationPhase.PARSE_CONFIGURATION);
+ }
+ return shouldSkip(metadata, ConfigurationCondition.ConfigurationPhase.REGISTER_BEAN);
+ }
+
+ List conditions = new ArrayList<>();
+ for (String[] conditionClasses : getConditionClasses(metadata)) {
+ for (String conditionClass : conditionClasses) {
+ Condition condition = getCondition(conditionClass, this.context.getClassLoader());
+ conditions.add(condition);
+ }
+ }
+
+ AnnotationAwareOrderComparator.sort(conditions);
+
+ for (Condition condition : conditions) {
+ ConfigurationCondition.ConfigurationPhase requiredPhase = null;
+ if (condition instanceof ConfigurationCondition) {
+ requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
+ }
+ if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+`shouldSkip()`·½·¨µÚÒ»ÐÐ _if_ Óï¾ä¾ÍÊǴ𰸣¬`@Profile`×¢½âÓÉ`@Conditional(ProfileCondition.class)`ÐÞÊΣ¬ÄÇÈç¹ûÒ»¸öÅäÖÃÀàÍ·ÉÏûÓÐ`Condition`µÄÉíÓ°£¬Ö±½Ó·µ»Ø`false`ÁË£¬ÄǾÍÊDz»Ìø¹ý¸ÃÅäÖÃÀàµÄÒâ˼ඣ¡
+
+_Environment_ ÖеÄÕâЩ _PropertySource_ ¾¿¾¹ÓÐɶÓ𡣿µ±È»ÊÇΪÁËÌî³ä _Bean_ à¶£¬·Ï»°²»¶à˵£¬ÉÏͼ¡£
+
+
+
+> ±ÊÕßÒÔǰ¶¼ÊÇÓà visio ºÍ processOn »Í¼£¬µÚÒ»´ÎÌåÑé draw.io£¬Ã»Ïëµ½Èç´ËÓÅÐ㣬ǿÁÒ°²ÀûÒ»²¨£¡
+
+## 2 Environmnent ³õʼ»¯Á÷³Ì
+
+±¾½ÚÖ÷Òª½éÉÜ Spring Boot ÔÚÆô¶¯¹ý³ÌÖÐÏò _Environmnt_ Öо¿¾¹×¢²áÁËÄÄЩ _PropertySource_¡£Æô¶¯Èë¿ÚλÓÚ`SpringApplication`ÖеÄ`run(String... args)`·½·¨£¬ÈçÏ£º
+
+```
+public class SpringApplication {
+ public ConfigurableApplicationContext run(String... args) {
+ StopWatch stopWatch = new StopWatch();
+ stopWatch.start();
+ DefaultBootstrapContext bootstrapContext = createBootstrapContext();
+ ConfigurableApplicationContext context = null;
+ configureHeadlessProperty();
+ SpringApplicationRunListeners listeners = getRunListeners(args);
+ listeners.starting(bootstrapContext, this.mainApplicationClass);
+ try {
+ ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
+ ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
+ configureIgnoreBeanInfo(environment);
+ Banner printedBanner = printBanner(environment);
+ context = createApplicationContext();
+ context.setApplicationStartup(this.applicationStartup);
+ prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
+ refreshContext(context);
+ afterRefresh(context, applicationArguments);
+ stopWatch.stop();
+ if (this.logStartupInfo) {
+ new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
+ }
+ listeners.started(context);
+ callRunners(context, applicationArguments);
+ } catch (Throwable ex) {
+ handleRunFailure(context, ex, listeners);
+ throw new IllegalStateException(ex);
+ }
+
+ try {
+ listeners.running(context);
+ } catch (Throwable ex) {
+ handleRunFailure(context, ex, null);
+ throw new IllegalStateException(ex);
+ }
+ return context;
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+¿ÉÒÔÃ÷ÏÔ¿´³ö£¬_Environmnt_ µÄ³õʼ»¯ÊÇÔÚ`refreshContext(context)`֮ǰÍê³ÉµÄ£¬ÕâÊǺÁÎÞÒÉÎʵġ£_run()_ ·½·¨ºÜ¸´ÔÓ£¬µ«Óë±¾ÎÄÖ÷ÌâÆõºÏµÄÂß¼Ö»ÓÐ**Ò»**´¦£º
+
+```
+prepareEnvironment(listeners, bootstrapContext, applicationArguments);
+¸´ÖÆ´úÂë
+```
+
+ÏÂÃæ·Ö±ð·ÖÎöÕâÁ½´¦ºËÐÄÂß¼¡£
+
+### 2.1 prepareEnvironment()
+
+ÏÔÈ»£¬ºËÐÄÄÚÈݶ¼ÔÚ`prepareEnvironment()`·½·¨ÄÚ£¬ÏÂÃæ·ÖС½ÚÖðÒ»·ÖÎö¡£
+
+```
+public class SpringApplication {
+ private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
+ DefaultBootstrapContext bootstrapContext,
+ ApplicationArguments applicationArguments) {
+ // 2.1.1
+ ConfigurableEnvironment environment = getOrCreateEnvironment();
+ // 2.1.2
+ configureEnvironment(environment, applicationArguments.getSourceArgs());
+ // 2.1.3
+ ConfigurationPropertySources.attach(environment);
+ // 2.1.4
+ listeners.environmentPrepared(bootstrapContext, environment);
+ DefaultPropertiesPropertySource.moveToEnd(environment);
+ bindToSpringApplication(environment);
+ ConfigurationPropertySources.attach(environment);
+ return environment;
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+#### 2.1.1 getOrCreateEnvironment()
+
+`getOrCreateEnvironment()`Ö÷Òª¸ºÔð¹¹½¨ _Environment_ ʵÀý¡£Èç¹ûµ±Ç°Ó¦ÓÃÊÇ»ùÓÚ`ͬ²½×èÈûI/O`Ä£Ð͵ģ¬Ôò _Environment_ Ñ¡ÓÃ`ApplicationServletEnvironment`£»Ïà·´µØ£¬Èç¹ûµ±Ç°Ó¦ÓÃÊÇ»ùÓÚ`Òì²½·Ç×èÈûI/O`Ä£Ð͵ģ¬Ôò _Environment_ Ñ¡ÓÃ`ApplicationReactiveWebEnvironment`¡£ÎÒÃǹ¤×÷Öлù±¾¶¼ÊÇ»ùÓÚ Spring MVC ¿ª·¢Ó¦Óã¬Spring MVC ÊÇÒ»¿î¹¹½¨ÓÚ`Servlet API`Ö®ÉÏ¡¢»ùÓÚͬ²½×èÈû I/O Ä£Ð͵ÄÖ÷Á÷ Java Web ¿ª·¢¿ò¼Ü£¬ÕâÖÖ I/O Ä£ÐÍÒâζ×ÅÒ»¸ö HTTP ÇëÇó¶ÔÓ¦Ò»¸öỊ̈߳¬¼´Ã¿Ò»¸ö HTTP ÇëÇó¶¼ÊÇÔÚ¸÷×ÔÏß³ÌÉÏÏÂÎÄÖÐÍê³É´¦ÀíµÄ¡£_ApplicationServletEnvironment_ ¼Ì³Ð¹ØÏµÈçÏÂͼËùʾ£º
+
+
+
+´ÓÉÏͼ¿ÉÒÔ¿´³ö _ApplicationServletEnvironment_ ¼Ò×åÏ൱ÅÓ´ó£¬ÔÚÖ´ÐÐ _ApplicationServletEnvironment_ ¹¹Ôì·½·¨µÄʱºò±ØÈ»»á´¥·¢¸÷¼¶¸¸À๹Ôì·½·¨ÖеÄÂß¼£¬**ÒÀ´ÎΪ**£º
+
+```
+public abstract class AbstractEnvironment implements ConfigurableEnvironment {
+ public AbstractEnvironment() {
+ this(new MutablePropertySources());
+ }
+
+ protected AbstractEnvironment(MutablePropertySources propertySources) {
+ this.propertySources = propertySources;
+ // createPropertyResolver(propertySources)
+ // |___ ConfigurationPropertySources.createPropertyResolver(propertySources)
+ // |___ new ConfigurationPropertySourcesPropertyResolver(propertySources)
+ this.propertyResolver = createPropertyResolver(propertySources);
+ customizePropertySources(propertySources);
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+```
+public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
+ @Override
+ protected void customizePropertySources(MutablePropertySources propertySources) {
+ propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
+ propertySources.addLast(new StubPropertySource("servletContextInitParams"));
+ super.customizePropertySources(propertySources);
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+```
+public class StandardEnvironment extends AbstractEnvironment {
+ @Override
+ protected void customizePropertySources(MutablePropertySources propertySources) {
+ propertySources.addLast(
+ new PropertiesPropertySource("systemProperties", (Map) System.getProperties()));
+ propertySources.addLast(
+ new SystemEnvironmentPropertySource("systemEnvironment", (Map) System.getenv()));
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+Ëæ×Å _ApplicationServletEnvironment_ ¹¹Ôì·½·¨µÄÖ´ÐУ¬´ËʱÔÚ _Environment_ Àï _MutablePropertySources_ ÀàÐ͵ijÉÔ±±äÁ¿`propertySources`ÖÐÒѾÓÐÁË**ËÄ**¸ö _PropertySource_ ÁË£¬Ãû³ÆÒÀ´ÎÊÇ£º`servletConfigInitParams`¡¢`servletContextInitParams`¡¢`systemProperties`ºÍ`systemEnvironment`¡£´ËÍ⣬ҲҪ¼Çס _ApplicationServletEnvironment_ ÖеÄÁ½¸öÖØÒª³ÉÔ±±äÁ¿£¬¼´`MutablePropertySources`ºÍ`ConfigurationPropertySourcesPropertyResolver`¡£
+
+#### 2.1.2 configureEnvironment()
+
+`configureEnvironment()`·½·¨ÖеÄÂß¼Ò²ºÜ¼òµ¥¹þ¡£Ê×ÏÈ£¬Îª _Environment_ ÖÐµÄ _PropertySourcesPropertyResolver_ É趨 _ConversionService_£»È»ºó£¬Ïò _Environment_ ÖÐµÄ _MutablePropertySources_ ×·¼ÓÒ»¸öÃû³ÆÎª`commandLineArgs`µÄ _PropertySource_ ʵÀý£¬×¢ÒâʹÓõÄÊÇ`addFirst()`·½·¨Å¶£¬ÕâÒâζ×ÅÕâ¸öÃû³ÆÎª`commandLineArgs`µÄ _PropertySource_ ÓÅÏȼ¶ÊÇ×î¸ßµÄ¡£Ö÷ÒªÂß¼ÈçÏ£º
+
+```
+public class SpringApplication {
+ protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
+ if (this.addConversionService) {
+ environment.getPropertyResolver().setConversionService(new ApplicationConversionService());
+ }
+ if (this.addCommandLineProperties && args.length > 0) {
+ MutablePropertySources sources = environment.getPropertySources();
+ sources.addFirst(new SimpleCommandLinePropertySource(args));
+ }
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+¼ÌÐø`SimpleCommandLinePropertySource`£º
+
+```
+public class SimpleCommandLinePropertySource extends CommandLinePropertySource {
+ public SimpleCommandLinePropertySource(String... args) {
+ // Æä¸¸À๹Ôì·½·¨Îª£ºsuper("commandLineArgs", source)
+ super(new SimpleCommandLineArgsParser().parse(args));
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+ÃüÁîÐвÎÊý»¹ÊDZȽϳ£Óõ쬱ÈÈçÎÒÃÇÔÚÆô¶¯ Spring Boot Ó¦ÓÃʱ»áÕâÑùÉùÃ÷ÃüÁîÐвÎÊý£º`java -jar app.jar --server.port=8088`¡£
+
+#### 2.1.3 ConfigurationPropertySources.attach()
+
+`attach()`·½·¨Ö÷Òª¾ÍÊÇÔÚ _Environment_ ÖÐ _MutablePropertySources_ µÄÍ·²¿Î»ÖòåÈë¼ÓÒ»¸öÃû³ÆÎª`configurationProperties`µÄ _PropertySource_ ʵÀý¡£Ö÷ÒªÂß¼ÈçÏ£º
+
+```
+public final class ConfigurationPropertySources {
+ public static void attach(org.springframework.core.env.Environment environment) {
+ MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
+ PropertySource> attached = getAttached(sources);
+ if (attached != null && attached.getSource() != sources) {
+ sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
+ attached = null;
+ }
+ if (attached == null) {
+ sources.addFirst(new ConfigurationPropertySourcesPropertySource("configurationProperties", new SpringConfigurationPropertySources(sources)));
+ }
+ }
+
+ static PropertySource> getAttached(MutablePropertySources sources) {
+ return (sources != null) ? sources.get("configurationProperties") : null;
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+±ÊÕß¶¢×ÅÕâÍæÒâ¶ù¿´Á˺þã¬Ñ¹¸ùû¿´³öÕâ¸öÃû³ÆÎª`configurationProperties`µÄ _PropertySource_ ¾¿¾¹ÓÐɶÓá£×îºó£¬»¹ÊÇÔÚ¹Ù·½ÎĵµÖйØÓÚ`Relaxed Binding` (¿íËɰó¶¨) µÄÃèÊöÖв³öÁËЩ¶ËÄß¡£»¹ÊÇͨ¹ý´úÂëÀ´½â¶Á±È½ÏÖ±½Ó¡£Ê×ÏÈ£¬ÔÚ _application.properties_ ÖÐ×·¼ÓÒ»¸öÅäÖÃÏ`a.b.my-first-key=hello spring environment`£»È»ºó£¬Í¨¹ý _Environment_ È¡³öÕâ¸öÅäÖÃÏîµÄÖµ£¬ÈçÏ£º
+
+```
+@SpringBootApplication
+public class DemoApplication {
+ public static void main(String[] args) {
+ ConfigurableApplicationContext configurableApplicationContext = SpringApplication.run(DemoApplication.class, args);
+ ConfigurableWebEnvironment environment = (ConfigurableWebEnvironment)
+ configurableApplicationContext.getBean(Environment.class);
+ System.out.println(environment.getProperty("a.b.my-first-key"));
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+Æô¶¯Ó¦Óú󣬿ØÖÆÌ¨´òÓ¡³öÁË _hello spring environment_ ×ÖÑù£¬ÕâÓëÔ¤ÆÚÊÇÏà·ûµÄ¡£¿Éµ±ÎÒÃÇͨ¹ý`environment.getProperty("a.b.myfirstkey")`»òÕß`environment.getProperty("a.b.my-firstkey")`ÒÀÈ»Äܹ»»ñÈ¡µ½ÅäÖÃÏîµÄÄÚÈÝ¡£`a.b.myfirstkey`ºÍ`a.b.my-firstkey`²¢²»ÊÇÅäÖÃÎļþÖеÄÊôÐÔÃû³Æ£¬Ö»ÊÇÏàËÆ¶øÒÑ£¬ÕâµÄÈ·ºÜ**¿íËÉ**°¡£¬¹þ¹þ¡£¸ÐÐËȤµÄ¶ÁÕß¿ÉÒÔ×ÔÐÐ DEBUG ¿´¿´ÆäÖеÄÔÀí¡£
+
+#### 2.1.4 listeners.environmentPrepared()
+
+Çúڰ壬¸÷λ´óÀУ¬Õâ¸öÒª¿¼µÄ £¡`environmentPrepared()`·½·¨»á¹ã²¥Ò»¸ö`ApplicationEnvironmentPreparedEvent`ʼþ£¬½Ó×ÅÓÉ`EnvironmentPostProcessorApplicationListener`ÏìÓ¦¸Ãʼþ£¬ÕâÓ¦¸ÃÊǵäÐ͵Ä**¹Û²ìÕßģʽ**¡£Ö÷ÒªÄÚÈÝÈçÏ£º
+
+```
+public class SpringApplicationRunListeners {
+ private final List listeners;
+
+ void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
+ doWithListeners("spring.boot.application.environment-prepared",
+ (listener) -> listener.environmentPrepared(bootstrapContext, environment));
+ }
+
+ private void doWithListeners(String stepName, Consumer listenerAction) {
+ StartupStep step = this.applicationStartup.start(stepName);
+ this.listeners.forEach(listenerAction);
+ step.end();
+ }
+}
+
+public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
+ @Override
+ public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
+ ConfigurableEnvironment environment) {
+ this.initialMulticaster.multicastEvent(
+ new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
+ }
+}
+
+public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
+ @Override
+ public void multicastEvent(ApplicationEvent event) {
+ multicastEvent(event, resolveDefaultEventType(event));
+ }
+
+ @Override
+ public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
+ ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
+ Executor executor = getTaskExecutor();
+ for (ApplicationListener> listener : getApplicationListeners(event, type)) {
+ if (executor != null) {
+ executor.execute(() -> invokeListener(listener, event));
+ } else {
+ invokeListener(listener, event);
+ }
+ }
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+ÏÂÃæÀ´¿´Ò»ÏÂ`EnvironmentPostProcessorApplicationListener`µÄÂ®É½ÕæÃæÄ¿£º
+
+```
+public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener, Ordered {
+ @Override
+ public void onApplicationEvent(ApplicationEvent event) {
+ if (event instanceof ApplicationEnvironmentPreparedEvent) {
+ onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
+ }
+ if (event instanceof ApplicationPreparedEvent) {
+ onApplicationPreparedEvent();
+ }
+ if (event instanceof ApplicationFailedEvent) {
+ onApplicationFailedEvent();
+ }
+ }
+ private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
+ ConfigurableEnvironment environment = event.getEnvironment();
+ SpringApplication application = event.getSpringApplication();
+ for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(), event.getBootstrapContext())) {
+ postProcessor.postProcessEnvironment(environment, application);
+ }
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+`EnvironmentPostProcessor`ÊÇ Spring Boot Ϊ _Environment_ Á¿Éí´òÔìµÄÀ©Õ¹µã¡£ÕâÀïÒýÓùٷ½ÎĵµÖбȽϾ«Á¶µÄÒ»¾ä»°£º_Allows for customization of the application's Environment prior to the application context being refreshed_¡£_EnvironmentPostProcessor_ ÊÇÒ»¸öº¯ÊýÐÔ½Ó¿Ú£¬ÄÚÈÝÈçÏ£º
+
+```
+public interface EnvironmentPostProcessor {
+ void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application);
+}
+¸´ÖÆ´úÂë
+```
+
+ÔÚÉÏÊö _EnvironmentPostProcessorApplicationListener_ ʼþ´¦ÀíÂß¼ÖУ¬`getEnvironmentPostProcessors`¸ºÔð¼ÓÔØ³öËùÓÐµÄ _EnvironmentPostProcessor_ ¡£¿´Ò»ÏÂÄÚ²¿¼ÓÔØÂß¼£º
+
+```
+public interface EnvironmentPostProcessorsFactory {
+ static EnvironmentPostProcessorsFactory fromSpringFactories(ClassLoader classLoader) {
+ return new ReflectionEnvironmentPostProcessorsFactory(
+ classLoader,
+ SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, classLoader)
+ );
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+¼ÌÐø½øÈë`SpringFactoriesLoader`һ̽¾¿¾¹£º
+
+```
+public final class SpringFactoriesLoader {
+
+ public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
+
+ public static List loadFactoryNames(Class> factoryType, ClassLoader classLoader) {
+ ClassLoader classLoaderToUse = classLoader;
+ if (classLoaderToUse == null) {
+ classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
+ }
+ String factoryTypeName = factoryType.getName();
+ return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
+ }
+
+ private static Map> loadSpringFactories(ClassLoader classLoader) {
+ Map> result = cache.get(classLoader);
+ if (result != null) {
+ return result;
+ }
+
+ result = new HashMap<>();
+ try {
+ Enumeration urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
+ while (urls.hasMoreElements()) {
+ URL url = urls.nextElement();
+ UrlResource resource = new UrlResource(url);
+ Properties properties = PropertiesLoaderUtils.loadProperties(resource);
+ for (Map.Entry, ?> entry : properties.entrySet()) {
+ String factoryTypeName = ((String) entry.getKey()).trim();
+ String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
+ for (String factoryImplementationName : factoryImplementationNames) {
+ result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
+ .add(factoryImplementationName.trim());
+ }
+ }
+ }
+ result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
+ .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
+ cache.put(classLoader, result);
+ } catch (IOException ex) {
+ throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
+ }
+ return result;
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+> **Spring SPI**
+>
+> > _SpringFactoriesLoader_ ÕâÒ»Ì×Âß¼¾ÍÊÇ Spring ÖеÄ`SPI`»úÖÆ£»Ö±°×µã˵£¬¾ÍÊÇ´Ó`classpath`ϵÄ`META-INF/spring.factories` ÎļþÖмÓÔØ _EnvironmentPostProcessor_ £¬Èç¹û´ó¼ÒÓÐÐèÇó¾Í½«×Ô¼ºÊµÏÖµÄ _EnvironmentPostProcessor_ ·Åµ½¸ÃÎļþÖоÍÐÐÁË¡£ÆäʵÓë`JDK`ÖеÄ`SPI`»úÖÆºÜÀàËÆ¹þ¡£
+
+ÔÚµ±Ç°°æ±¾£¬Spring Boot ÄÚÖÃÁË7¸ö _EnvironmentPostProcessor_ ʵÏÖÀà¡£½ÓÏÂÀ´Ìô¼¸¸ö±È½ÏµäÐ͵ķÖÎöÏ¡£
+
+**RandomValuePropertySourceEnvironmentPostProcessor**
+
+`RandomValuePropertySourceEnvironmentPostProcessor`Ïò _Environment_ ÖÐ×·¼ÓÁËÒ»¸öÃû³ÆÎª`random`µÄ _PropertySource_£¬¼´`RandomValuePropertySource`¡£ÄÚÈÝÈçÏ£º
+
+```
+public class RandomValuePropertySourceEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
+ public static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 1;
+ private final Log logger;
+
+ public RandomValuePropertySourceEnvironmentPostProcessor(Log logger) {
+ this.logger = logger;
+ }
+
+ @Override
+ public int getOrder() {
+ return ORDER;
+ }
+
+ @Override
+ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
+ RandomValuePropertySource.addToEnvironment(environment, this.logger);
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+ÄÇôÕâ¸ö _RandomValuePropertySource_ ÓÐɶ×÷ÓÃÄØ£¿Ö÷Òª¾ÍÊÇÓÃÓÚÉú³ÉËæ»úÊý£¬±ÈÈ磺`environment.getProperty("random.int(5,10)")`¿ÉÒÔ»ñȡһ¸öËæ»úÊý¡£ÒÔ`random.int`ΪÊôÐÔÃû¿ÉÒÔ»ñȡһ¸ö _int_ ÀàÐ͵ÄËæ»úÊý£»ÒÔ`random.long`ΪÊôÐÔÃû¿ÉÒÔ»ñȡһ¸ö _long_ ÀàÐ͵ÄËæ»úÊý£»ÒÔ`random.int(5,10)`ΪÊôÐÔÃû¿ÉÒÔ»ñȡһ¸ö _[5, 10}_ Çø¼äÄÚ _int_ ÀàÐ͵ÄËæ»úÊý£¬¸ü¶àÍæ·¨´ó¼Ò×ÔÐÐ̽Ë÷¡£
+
+_SystemEnvironmentPropertySourceEnvironmentPostProcessor_
+
+µ±Ç°£¬_Environment_ ÖÐÒѾ´æÔÚÒ»¸öÃû³ÆÎª`systemEnvironment`µÄ _PropertySource_£¬¼´`SystemEnvironmentPropertySource`¡£`SystemEnvironmentPropertySourceEnvironmentPostProcessor`ÓÃÓÚ½«¸Ã _SystemEnvironmentPropertySource_ Ìæ»»Îª`OriginAwareSystemEnvironmentPropertySource`£¬Õ¦Óе㡰ÍÑ¿ã×Ó·ÅÆ¨£¬¶à´ËÒ»¾Ù¡±µÄ¸Ð¾õÄØ£¬¹þ¹þ¡£
+
+```
+public class SystemEnvironmentPropertySourceEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
+ public static final int DEFAULT_ORDER = SpringApplicationJsonEnvironmentPostProcessor.DEFAULT_ORDER - 1;
+ private int order = DEFAULT_ORDER;
+
+ @Override
+ public int getOrder() {
+ return this.order;
+ }
+
+ @Override
+ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
+ String sourceName = "systemEnvironment";
+ PropertySource> propertySource = environment.getPropertySources().get(sourceName);
+ if (propertySource != null) {
+ replacePropertySource(environment, sourceName, propertySource, application.getEnvironmentPrefix());
+ }
+ }
+ private void replacePropertySource(ConfigurableEnvironment environment, String sourceName,
+ PropertySource> propertySource, String environmentPrefix) {
+ Map originalSource = (Map) propertySource.getSource();
+ SystemEnvironmentPropertySource source = new OriginAwareSystemEnvironmentPropertySource(sourceName, originalSource, environmentPrefix);
+ environment.getPropertySources().replace(sourceName, source);
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+**SpringApplicationJsonEnvironmentPostProcessor**
+
+ÎÒÃÇÔÚͨ¹ý`java -jar -Dspring.application.json={"name":"duxiaotou"} app.jar`Æô¶¯ Spring Boot Ó¦ÓõÄʱºò£¬¸ÃÊôÐԻᱻ×Ô¶¯Ìí¼Óµ½ JVM ϵͳÊôÐÔÖÐ (Æäʵ _-Dkey=value_ ÕâÖÖÐÎʽµÄÊôÐÔ¾ùÊÇÈç´Ë)£¬ÆäµÈЧÓÚ`System.setProperty(key, value)`£»¶øµ±´æÔÚ`SPRING_APPLICATION_JSON`Õâһϵͳ±äÁ¿Ê±£¬×ÔȻҲ»áÔÚ`System.getenv()`ÖгöÏÖ¡£Ç°ÃæÔø¾Ìáµ½¹ý`System.getProperties()`´ú±íµÄÊÇ`systemProperties`ÕâÒ» _PropertySource_£¬¶ø`System.getenv()`Ôò´ú±íµÄÊÇ`systemEnvironment`ÕâÒ» _PropertySource_¡£`SpringApplicationJsonEnvironmentPostProcessor`¾ÍÊÇÓÃÓÚ´ÓÕâÁ½¸ö _PropertySource_ ÖгéÈ¡³ö _spring.application.json_ »ò _SPRING_APPLICATION_JSON_ µÄ _JSON_ ´®£¬½ø¶øµ¥¶ÀÏò _Environment_ ÖÐ×·¼ÓÒ»¸öÃû³ÆÎª`spring.application.json`µÄ _PropertySource_£¬¼´`JsonPropertySource`¡£
+
+**ConfigDataEnvironmentPostProcessor**
+
+`ConfigDataEnvironmentPostProcessor`¸ºÔð½«`optional:classpath:/`¡¢`optional:classpath:/config/`¡¢`optional:file:./`¡¢`optional:file:./config/`ºÍ`optional:file:./config/*/`ÕâЩĿ¼Ï嵀 _application.properties_ ÅäÖÃÎļþ¼ÓÔØ³öÀ´£»Èç¹û»¹Ö¸¶¨ÁË _spring.profiles.active_µÄ»°£¬Í¬Ê±Ò²»á½«ÕâЩĿ¼Ï嵀 _application-{profile}.properties_ ÅäÖÃÎļþ¼ÓÔØ³öÀ´¡£×îÖÕ£¬_ConfigDataEnvironmentPostProcessor_ ½«»áÏò _Environment_ ÖÐ×·¼ÓÁ½¸ö`OriginTrackedMapPropertySource`£¬ÕâÁ© _PropertySource_ λÓÚ _Environment_ µÄβ²¿£»ÆäÖÐ _application-{profile}.properties_ Ëù´ú±íµÄ _OriginTrackedMapPropertySource_ ÊÇÅÅÔÚ _application.properties_ Ëù´ú±íµÄ _OriginTrackedMapPropertySource_ Ç°ÃæµÄ£¬ÕâÒ»µãÍ¦ÖØÒª¡£
+
+## 3 jasypt ºËÐÄÔÀí½â¶Á
+
+> `jasypt`»ù´¡×é¼þ¿âÓë`jasypt-spring-boot-starter`ÊDz»Í¬×÷ÕßдµÄ£¬ºóÕßÖ»ÊÇΪ jasypt ×é¼þ¿ª·¢ÁË Spring Boot µÄÆð²½ÒÀÀµ×é¼þ¶øÒÑ¡£±¾ÎÄËù·ÖÎöµÄÆäʵ¾ÍÊÇÕâ¸öÆð²½ÒÀÀµ×é¼þ¡£
+
+_application.properties_ ÅäÖÃÎļþÖйØÓÚÊý¾ÝÔ´µÄÃÜÂëÊÇÒ»¸ö¼ÓÃܺóµÄÃÜÎÄ£¬ÈçÏ£º
+
+```
+spring.datasource.hikari.password=ENC(4+t9a5QG8NkNdWVS6UjIX3dj18UtYRMqU6eb3wUKjivOiDHFLZC/RTK7HuWWkUtV)
+¸´ÖÆ´úÂë
+```
+
+µ±`HikariDataSource`Íê³ÉÊôÐÔÌî³ä²Ù×÷ºó£¬¸Ã Bean ÖÐ _password_ ×ֶεÄÖµÕ¦¾Í±äΪ½âÃܺóµÄ _qwe@1234_ ÕâÒ»Ã÷ÎÄÁËÄØ£¿ÏÔÈ»£¬Spring Boot Ϊ _Environment_ ÌṩµÄ`EnvironmentPostProcessor`ÕâÒ»ÍØÕ¹µã¿ÉÒÔʵÏÖ͵Ìì»»ÈÕ£¡µ«×÷ÕßûÓÐÓÃËü£¬¶øÊÇʹÓÃÁË Spring ÖеÄÒ»¸ö _IoC ÍØÕ¹µã_£¬¼´`BeanFactoryPostProcessor`£¬ÕâÒ²ÊÇÍêÈ«¿ÉÒԵģ¬ÒòΪµ±Ö´Ðе½ _BeanFactoryPostProcessor_ ÖеÄ`postProcessBeanFactory()`Â߼ʱ£¬Ö»ÊÇÍê³ÉÁËËùÓÐ`BeanDefinition`µÄ¼ÓÔØ£¬µ«»¹Ã»ÓÐʵÀý»¯ _BeanDefinition_ ¸÷×ÔËù¶ÔÓ¦µÄ Bean¡£
+
+ÏÂÃæ¿´Ò»ÏÂ`EnableEncryptablePropertiesBeanFactoryPostProcessor`ÖеÄÄÚÈÝ£º
+
+```
+public class EnableEncryptablePropertiesBeanFactoryPostProcessor implements BeanFactoryPostProcessor, Ordered {
+
+ private final ConfigurableEnvironment environment;
+ private final EncryptablePropertySourceConverter converter;
+
+ public EnableEncryptablePropertiesBeanFactoryPostProcessor(ConfigurableEnvironment environment, EncryptablePropertySourceConverter converter) {
+ this.environment = environment;
+ this.converter = converter;
+ }
+
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ MutablePropertySources propSources = environment.getPropertySources();
+ converter.convertPropertySources(propSources);
+ }
+
+ @Override
+ public int getOrder() {
+ return Ordered.LOWEST_PRECEDENCE - 100;
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+ÉÏÊöÔ´Âë±íÃ÷¸Ã _BeanFactoryPostProcessor_ ½èÖú`EncryptablePropertySourceConverter`¶Ô _MutablePropertySources_ ×öÁËÒ»²ãת»»£¬ÄÇôת»»³ÉɶÁËÄØ£¿
+
+½Ó×Å£¬¸ú½ø _EncryptablePropertySourceConverter_£¬ºËÐÄÄÚÈÝÈçÏ£º
+
+```
+public class EncryptablePropertySourceConverter {
+
+ public void convertPropertySources(MutablePropertySources propSources) {
+ propSources.stream()
+ .filter(ps -> !(ps instanceof EncryptablePropertySource))
+ .map(this::makeEncryptable)
+ .collect(toList())
+ .forEach(ps -> propSources.replace(ps.getName(), ps));
+ }
+
+ public PropertySource makeEncryptable(PropertySource propertySource) {
+ if (propertySource instanceof EncryptablePropertySource
+ || skipPropertySourceClasses.stream().anyMatch(skipClass -> skipClass.equals(propertySource.getClass()))) {
+ return propertySource;
+ }
+ PropertySource encryptablePropertySource = convertPropertySource(propertySource);
+ return encryptablePropertySource;
+ }
+
+ private PropertySource convertPropertySource(PropertySource propertySource) {
+ PropertySource encryptablePropertySource;
+ if (propertySource instanceof SystemEnvironmentPropertySource) {
+ encryptablePropertySource = (PropertySource) new EncryptableSystemEnvironmentPropertySourceWrapper((SystemEnvironmentPropertySource) propertySource, propertyResolver, propertyFilter);
+ } else if (propertySource instanceof MapPropertySource) {
+ encryptablePropertySource = (PropertySource) new EncryptableMapPropertySourceWrapper((MapPropertySource) propertySource, propertyResolver, propertyFilter);
+ } else if (propertySource instanceof EnumerablePropertySource) {
+ encryptablePropertySource = new EncryptableEnumerablePropertySourceWrapper<>((EnumerablePropertySource) propertySource, propertyResolver, propertyFilter);
+ } else {
+ encryptablePropertySource = new EncryptablePropertySourceWrapper<>(propertySource, propertyResolver, propertyFilter);
+ }
+ return encryptablePropertySource;
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+ÏÔÈ»£¬Ëü½«Ïà¹ØÔÉú _PropertySource_ ת»»ÎªÁËÒ»¸ö`EncryptablePropertySourceWrapper`£¬ÄÇÕâ¸ö¿Ï¶¨¿ÉÒÔʵÏÖÃÜÎĽâÃÜ£¬±ØÐëµÄ£¡
+
+¼ÌÐø£¬¸ú½ø`EncryptablePropertySourceWrapper`£¬ÄÚÈÝÈçÏ£º
+
+```
+public class EncryptablePropertySourceWrapper extends PropertySource implements EncryptablePropertySource {
+ private final CachingDelegateEncryptablePropertySource encryptableDelegate;
+
+ public EncryptablePropertySourceWrapper(PropertySource delegate, EncryptablePropertyResolver resolver, EncryptablePropertyFilter filter) {
+ super(delegate.getName(), delegate.getSource());
+ encryptableDelegate = new CachingDelegateEncryptablePropertySource<>(delegate, resolver, filter);
+ }
+
+ @Override
+ public Object getProperty(String name) {
+ return encryptableDelegate.getProperty(name);
+ }
+
+ @Override
+ public PropertySource getDelegate() {
+ return encryptableDelegate;
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+ʧÍû£¡Ã»¿´³öɶ½âÃÜÂß¼£¬µ«´ÓÆä _getProperty_ ·½·¨À´¿´£¬½«¾ßÌå½âÎöÂ߼ίÅɸøÁË`CachingDelegateEncryptablePropertySource`¡£
+
+û°ì·¨£¬Ö»Äܵ½ _CachingDelegateEncryptablePropertySource_ ÖÐһ̽¾¿¾¹ÁË£º
+
+```
+public class CachingDelegateEncryptablePropertySource extends PropertySource implements EncryptablePropertySource {
+ private final PropertySource delegate;
+ private final EncryptablePropertyResolver resolver;
+ private final EncryptablePropertyFilter filter;
+ private final Map cache;
+
+ public CachingDelegateEncryptablePropertySource(PropertySource delegate, EncryptablePropertyResolver resolver, EncryptablePropertyFilter filter) {
+ super(delegate.getName(), delegate.getSource());
+ this.delegate = delegate;
+ this.resolver = resolver;
+ this.filter = filter;
+ this.cache = new HashMap<>();
+ }
+
+ @Override
+ public PropertySource getDelegate() {
+ return delegate;
+ }
+
+ @Override
+ public Object getProperty(String name) {
+ if (cache.containsKey(name)) {
+ return cache.get(name);
+ }
+ synchronized (name.intern()) {
+ if (!cache.containsKey(name)) {
+ Object resolved = getProperty(resolver, filter, delegate, name);
+ if (resolved != null) {
+ cache.put(name, resolved);
+ }
+ }
+ return cache.get(name);
+ }
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+ÖÕÓÚ£¬¸ú½øµ½`EncryptablePropertySource`Öп´µ½Á˽âÃܵÄ×îÖÕÂß¼¡£ÆäÖУ¬`EncryptablePropertyDetector`¸ºÔð̽²âÏà¹ØÊôÐÔÊÇ·ñÐèÒª¶ÔÆä½âÃÜ£¬Ö÷Ҫͨ¹ýÅжϸÃÊôÐÔÖµÊÇ·ñÓÉ`ENC()`°ü¹ü¡£
+
+```
+public interface EncryptablePropertySource extends OriginLookup {
+ default Object getProperty(EncryptablePropertyResolver resolver, EncryptablePropertyFilter filter, PropertySource source, String name) {
+ Object value = source.getProperty(name);
+ if (value != null && filter.shouldInclude(source, name) && value instanceof String) {
+ String stringValue = String.valueOf(value);
+ return resolver.resolvePropertyValue(stringValue);
+ }
+ return value;
+ }
+}
+
+public class DefaultPropertyResolver implements EncryptablePropertyResolver {
+
+ private final Environment environment;
+ private StringEncryptor encryptor;
+ private EncryptablePropertyDetector detector;
+
+ @Override
+ public String resolvePropertyValue(String value) {
+ return Optional.ofNullable(value)
+ .map(environment::resolvePlaceholders)
+ .filter(detector::isEncrypted)
+ .map(resolvedValue -> {
+ try {
+ String unwrappedProperty = detector.unwrapEncryptedValue(resolvedValue.trim());
+ String resolvedProperty = environment.resolvePlaceholders(unwrappedProperty);
+ return encryptor.decrypt(resolvedProperty);
+ } catch (EncryptionOperationNotPossibleException e) {
+ throw new DecryptionException("Unable to decrypt property: " + value + " resolved to: " + resolvedValue + ". Decryption of Properties failed, make sure encryption/decryption " +
+ "passwords match", e);
+ }
+ })
+ .orElse(value);
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+## 4 ×ܽá
+
+×ܽáÐÔµÄÎÄ×־Ͳ»ÔÙ˵ÁË£¬±ÊÕßÏÖÔÚÎÄ˼Ȫӿ£¬·ñÔòÓÖÄÜË®300×Ö¡£×îºó£¬Ï£Íû´ó¼Ò¼ÇסÔÚµ±Ç° Spring Boot °æ±¾ÖУ¬ÓÉ`ApplicationServletEnvironment`°çÑÝ _Environment_£¬Æä×îÖÕ½«Î¯ÅÉ`ConfigurationPropertySourcesPropertyResolver`È¥»ñÈ¡ÊôÐÔÖµ¡£
+
+## 5 ²Î¿¼Îĵµ
+
+1. [docs.spring.io/spring-boot¡](https://link.juejin.cn?target=https%3A%2F%2Fdocs.spring.io%2Fspring-boot%2Fdocs%2F2.5.7%2Freference%2Fhtml%2Ffeatures.html "https://docs.spring.io/spring-boot/docs/2.5.7/reference/html/features.html")
+
+
+
+×÷Õߣº³ÌÐòÔ³¶ÅСͷ
+Á´½Ó£ºhttps://juejin.cn/post/7098299623759937543
+À´Ô´£ºÏ¡ÍÁ¾ò½ð
+Öø×÷Ȩ¹é×÷ÕßËùÓС£ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£
+
+# ²Î¿¼ÎÄÕÂ
+https://www.w3cschool.cn/wkspring
+https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
+http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
+https://dunwu.github.io/spring-tutorial
+https://mszlu.com/java/spring
+http://c.biancheng.net/spring/aop-module.html
\ No newline at end of file
diff --git "a/docs/spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md" "b/docs/spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md"
new file mode 100644
index 0000000..6acb8a1
--- /dev/null
+++ "b/docs/spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md"
@@ -0,0 +1,270 @@
+
+
+
+
+# Spring ÖеÄʼþ´¦Àí
+
+
+
+2022-05-16 15:29 ¸üÐÂ
+
+
+
+
+
+
+
+
+
+## Spring ÖеÄʼþ´¦Àí
+
+ÄãÒѾ¿´µ½ÁËÔÚËùÓÐÕ½ÚÖÐ Spring µÄºËÐÄÊÇ?**ApplicationContext**£¬Ëü¸ºÔð¹ÜÀí beans µÄÍêÕûÉúÃüÖÜÆÚ¡£µ±¼ÓÔØ beans ʱ£¬ApplicationContext ·¢²¼Ä³Ð©ÀàÐ͵Äʼþ¡£ÀýÈ磬µ±ÉÏÏÂÎÄÆô¶¯Ê±£¬ContextStartedEvent ·¢²¼£¬µ±ÉÏÏÂÎÄֹͣʱ£¬ContextStoppedEvent ·¢²¼¡£
+
+ͨ¹ý ApplicationEvent ÀàºÍ ApplicationListener ½Ó¿ÚÀ´ÌṩÔÚ ApplicationContext Öд¦Àíʼþ¡£Èç¹ûÒ»¸ö bean ʵÏÖ ApplicationListener£¬ÄÇôÿ´Î ApplicationEvent ±»·¢²¼µ½ ApplicationContext ÉÏ£¬ÄǸö bean »á±»Í¨Öª¡£
+
+Spring ÌṩÁËÒÔϵıê׼ʼþ£º
+
+| ÐòºÅ | Spring ÄÚÖÃʼþ & ÃèÊö |
+| --- | --- |
+| 1 | **ContextRefreshedEvent**ApplicationContext ±»³õʼ»¯»òË¢ÐÂʱ£¬¸Ãʼþ±»·¢²¼¡£ÕâÒ²¿ÉÒÔÔÚ ConfigurableApplicationContext ½Ó¿ÚÖÐʹÓà refresh() ·½·¨À´·¢Éú¡£ |
+| 2 | **ContextStartedEvent**µ±Ê¹Óà ConfigurableApplicationContext ½Ó¿ÚÖÐµÄ start() ·½·¨Æô¶¯ ApplicationContext ʱ£¬¸Ãʼþ±»·¢²¼¡£Äã¿ÉÒÔµ÷²éÄãµÄÊý¾Ý¿â£¬»òÕßÄã¿ÉÒÔÔÚ½ÓÊܵ½Õâ¸öʼþºóÖØÆôÈκÎÍ£Ö¹µÄÓ¦ÓóÌÐò¡£ |
+| 3 | **ContextStoppedEvent**µ±Ê¹Óà ConfigurableApplicationContext ½Ó¿ÚÖÐµÄ stop() ·½·¨Í£Ö¹ ApplicationContext ʱ£¬·¢²¼Õâ¸öʼþ¡£Äã¿ÉÒÔÔÚ½ÓÊܵ½Õâ¸öʼþºó×ö±ØÒªµÄÇåÀíµÄ¹¤×÷¡£ |
+| 4 | **ContextClosedEvent**µ±Ê¹Óà ConfigurableApplicationContext ½Ó¿ÚÖÐµÄ close() ·½·¨¹Ø±Õ ApplicationContext ʱ£¬¸Ãʼþ±»·¢²¼¡£Ò»¸öÒѹرյÄÉÏÏÂÎĵ½´ïÉúÃüÖÜÆÚÄ©¶Ë£»Ëü²»Äܱ»Ë¢Ð»òÖØÆô¡£ |
+| 5 | **RequestHandledEvent**ÕâÊÇÒ»¸ö web-specific ʼþ£¬¸æËßËùÓÐ bean HTTP ÇëÇóÒѾ±»·þÎñ¡£ |
+
+ÓÉÓÚ Spring µÄʼþ´¦ÀíÊǵ¥Ï̵߳ģ¬ËùÒÔÈç¹ûÒ»¸öʼþ±»·¢²¼£¬Ö±ÖÁ²¢ÇÒ³ý·ÇËùÓеĽÓÊÕÕߵõ½µÄ¸ÃÏûÏ¢£¬¸Ã½ø³Ì±»×èÈû²¢ÇÒÁ÷³Ì½«²»»á¼ÌÐø¡£Òò´Ë£¬Èç¹ûʼþ´¦Àí±»Ê¹Óã¬ÔÚÉè¼ÆÓ¦ÓóÌÐòʱӦעÒâ¡£
+
+## ¼àÌýÉÏÏÂÎÄʼþ
+
+ΪÁ˼àÌýÉÏÏÂÎÄʼþ£¬Ò»¸ö bean Ó¦¸ÃʵÏÖÖ»ÓÐÒ»¸ö·½·¨?**onApplicationEvent()**?µÄ ApplicationListener ½Ó¿Ú¡£Òò´Ë£¬ÎÒÃÇдһ¸öÀý×ÓÀ´¿´¿´Ê¼þÊÇÈçºÎ´«²¥µÄ£¬ÒÔ¼°ÈçºÎ¿ÉÒÔÓôúÂëÀ´Ö´ÐлùÓÚijЩʼþËùÐèµÄÈÎÎñ¡£
+
+ÈÃÎÒÃÇÔÚÇ¡µ±µÄλÖÃʹÓà Eclipse IDE£¬È»ºó°´ÕÕÏÂÃæµÄ²½ÖèÀ´´´½¨Ò»¸ö Spring Ó¦ÓóÌÐò£º
+
+| ²½Öè | ÃèÊö |
+| --- | --- |
+| 1 | ´´½¨Ò»¸öÃû³ÆÎª SpringExample µÄÏîÄ¿£¬²¢ÇÒÔÚ´´½¨ÏîÄ¿µÄ?**src**?Îļþ¼ÐÖд´½¨Ò»¸ö°ü com.tutorialspoint¡£ |
+| 2 | ʹÓà Add External JARs Ñ¡ÏÌí¼ÓËùÐèµÄ Spring ¿â£¬½âÊͼû Spring Hello World Example Õ½ڡ£ |
+| 3 | ÔÚ com.tutorialspoint °üÖд´½¨ Java Àà HelloWorld¡¢CStartEventHandler¡¢CStopEventHandler ºÍ MainApp¡£ |
+| 4 | ÔÚ?**src**?Îļþ¼ÐÖд´½¨ Bean µÄÅäÖÃÎļþ Beans.xml¡£ |
+| 5 | ×îºóÒ»²½ÊÇ´´½¨µÄËùÓÐ Java ÎļþºÍ Bean ÅäÖÃÎļþµÄÄÚÈÝ£¬²¢ÔËÐÐÓ¦ÓóÌÐò£¬½âÊÍÈçÏÂËùʾ¡£ |
+
+ÕâÀïÊÇ?**HelloWorld.java**?ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+public class HelloWorld {
+ private String message;
+ public void setMessage(String message){
+ this.message = message;
+ }
+ public void getMessage(){
+ System.out.println("Your Message : " + message);
+ }
+}
+```
+
+ÏÂÃæÊÇ?**CStartEventHandler.java**?ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextStartedEvent;
+public class CStartEventHandler
+ implements ApplicationListener{
+ public void onApplicationEvent(ContextStartedEvent event) {
+ System.out.println("ContextStartedEvent Received");
+ }
+}
+```
+
+ÏÂÃæÊÇ?**CStopEventHandler.java**?ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextStoppedEvent;
+public class CStopEventHandler
+ implements ApplicationListener{
+ public void onApplicationEvent(ContextStoppedEvent event) {
+ System.out.println("ContextStoppedEvent Received");
+ }
+}
+```
+
+ÏÂÃæÊÇ?**MainApp.java**?ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class MainApp {
+ public static void main(String[] args) {
+ ConfigurableApplicationContext context =
+ new ClassPathXmlApplicationContext("Beans.xml");
+
+ // Let us raise a start event.
+ context.start();
+
+ HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
+
+ obj.getMessage();
+
+ // Let us raise a stop event.
+ context.stop();
+ }
+}
+```
+
+ÏÂÃæÊÇÅäÖÃÎļþ?**Beans.xml**?Îļþ£º
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Ò»µ©ÄãÍê³ÉÁË´´½¨Ô´ºÍ bean µÄÅäÖÃÎļþ£¬ÎÒÃǾͿÉÒÔÔËÐиÃÓ¦ÓóÌÐò¡£Èç¹ûÄãµÄÓ¦ÓóÌÐòÒ»Çж¼Õý³££¬½«Êä³öÒÔÏÂÏûÏ¢£º
+
+```
+ContextStartedEvent Received
+Your Message : Hello World!
+ContextStoppedEvent Received
+```
+
+
+
+
+
+
+
+## Spring ÖеÄ×Ô¶¨Òåʼþ
+
+±àдºÍ·¢²¼×Ô¼ºµÄ×Ô¶¨ÒåʼþÓÐÐí¶à²½Öè¡£°´ÕÕÔÚÕâÒ»Õ¸ø³öµÄ˵Ã÷À´±àд£¬·¢²¼ºÍ´¦Àí×Ô¶¨Òå Spring ʼþ¡£
+
+| ²½Öè | ÃèÊö |
+| --- | --- |
+| 1 | ´´½¨Ò»¸öÃû³ÆÎª SpringExample µÄÏîÄ¿£¬²¢ÇÒÔÚ´´½¨ÏîÄ¿µÄ?**src**?Îļþ¼ÐÖд´½¨Ò»¸ö°ü com.tutorialspoint¡£ |
+| 2 | ʹÓà Add External JARs Ñ¡ÏÌí¼ÓËùÐèµÄ Spring ¿â£¬½âÊͼû Spring Hello World Example Õ½ڡ£ |
+| 3 | ͨ¹ýÀ©Õ¹?**ApplicationEvent**,´´½¨Ò»¸öʼþÀà CustomEvent¡£Õâ¸öÀà±ØÐ붨ÒåÒ»¸öĬÈϵĹ¹Ô캯Êý£¬ËüÓ¦¸Ã´Ó ApplicationEvent ÀàÖм̳еĹ¹Ô캯Êý¡£ |
+| 4 | Ò»µ©¶¨ÒåʼþÀ࣬Äã¿ÉÒÔ´ÓÈκÎÀàÖз¢²¼Ëü£¬¼Ù¶¨ EventClassPublisher ʵÏÖÁË ApplicationEventPublisherAware¡£Ä㻹ÐèÒªÔÚ XML ÅäÖÃÎļþÖÐÉùÃ÷Õâ¸öÀà×÷Ϊһ¸ö bean£¬Ö®ËùÒÔÈÝÆ÷¿ÉÒÔʶ±ð bean ×÷Ϊʼþ·¢²¼Õߣ¬ÊÇÒòΪËüʵÏÖÁË ApplicationEventPublisherAware ½Ó¿Ú¡£ |
+| 5 | ·¢²¼µÄʼþ¿ÉÒÔÔÚÒ»¸öÀàÖб»´¦Àí£¬¼Ù¶¨ EventClassHandler ʵÏÖÁË ApplicationListener ½Ó¿Ú£¬¶øÇÒʵÏÖÁË×Ô¶¨ÒåʼþµÄ onApplicationEvent ·½·¨¡£ |
+| 6 | ÔÚ?**src**?Îļþ¼ÐÖд´½¨ bean µÄÅäÖÃÎļþ Beans.xml ºÍ MainApp À࣬Ëü¿ÉÒÔ×÷Ϊһ¸ö Spring Ó¦ÓóÌÐòÀ´ÔËÐС£ |
+| 7 | ×îºóÒ»²½ÊÇ´´½¨µÄËùÓÐ Java ÎļþºÍ Bean ÅäÖÃÎļþµÄÄÚÈÝ£¬²¢ÔËÐÐÓ¦ÓóÌÐò£¬½âÊÍÈçÏÂËùʾ¡£ |
+
+Õâ¸öÊÇ?**CustomEvent.java**?ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+import org.springframework.context.ApplicationEvent;
+public class CustomEvent extends ApplicationEvent{
+ public CustomEvent(Object source) {
+ super(source);
+ }
+ public String toString(){
+ return "My Custom Event";
+ }
+}
+
+```
+
+ÏÂÃæÊÇ?**CustomEventPublisher.java**?ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ApplicationEventPublisherAware;
+public class CustomEventPublisher
+ implements ApplicationEventPublisherAware {
+ private ApplicationEventPublisher publisher;
+ public void setApplicationEventPublisher
+ (ApplicationEventPublisher publisher){
+ this.publisher = publisher;
+ }
+ public void publish() {
+ CustomEvent ce = new CustomEvent(this);
+ publisher.publishEvent(ce);
+ }
+}
+```
+
+ÏÂÃæÊÇ?**CustomEventHandler.java**?ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+import org.springframework.context.ApplicationListener;
+public class CustomEventHandler
+ implements ApplicationListener{
+ public void onApplicationEvent(CustomEvent event) {
+ System.out.println(event.toString());
+ }
+}
+```
+
+ÏÂÃæÊÇ?**MainApp.java**?ÎļþµÄÄÚÈÝ£º
+
+```
+package com.tutorialspoint;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+public class MainApp {
+ public static void main(String[] args) {
+ ConfigurableApplicationContext context =
+ new ClassPathXmlApplicationContext("Beans.xml");
+ CustomEventPublisher cvp =
+ (CustomEventPublisher) context.getBean("customEventPublisher");
+ cvp.publish();
+ cvp.publish();
+ }
+}
+```
+
+ÏÂÃæÊÇÅäÖÃÎļþ?**Beans.xml**£º
+
+```
+
+
+
+
+
+
+
+
+
+```
+
+Ò»µ©ÄãÍê³ÉÁË´´½¨Ô´ºÍ bean µÄÅäÖÃÎļþºó£¬ÎÒÃǾͿÉÒÔÔËÐиÃÓ¦ÓóÌÐò¡£Èç¹ûÄãµÄÓ¦ÓóÌÐòÒ»Çж¼Õý³££¬½«Êä³öÒÔÏÂÐÅÏ¢£º
+
+```
+My Custom Event
+My Custom Event
+```
+
+# ²Î¿¼ÎÄÕÂ
+https://www.w3cschool.cn/wkspring
+https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
+http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
+https://dunwu.github.io/spring-tutorial
+https://mszlu.com/java/spring
+http://c.biancheng.net/spring/aop-module.html
\ No newline at end of file
diff --git "a/docs/spring/Spring\344\270\255\347\232\204\350\265\204\346\272\220\347\256\241\347\220\206.md" "b/docs/spring/Spring\344\270\255\347\232\204\350\265\204\346\272\220\347\256\241\347\220\206.md"
new file mode 100644
index 0000000..09874af
--- /dev/null
+++ "b/docs/spring/Spring\344\270\255\347\232\204\350\265\204\346\272\220\347\256\241\347\220\206.md"
@@ -0,0 +1,309 @@
+## Resource ½Ó¿Ú
+
+Ïà¶Ô±ê×¼ URL ·ÃÎÊ»úÖÆ£¬Spring µÄ `org.springframework.core.io.Resource` ½Ó¿Ú³éÏóÁ˶Եײã×ÊÔ´µÄ·ÃÎʽӿڣ¬ÌṩÁËÒ»Ì׸üºÃµÄ·ÃÎÊ·½Ê½¡£
+
+
+
+```
+public interface Resource extends InputStreamSource {
+
+ boolean exists();
+
+ boolean isReadable();
+
+ boolean isOpen();
+
+ boolean isFile();
+
+ URL getURL() throws IOException;
+
+ URI getURI() throws IOException;
+
+ File getFile() throws IOException;
+
+ ReadableByteChannel readableChannel() throws IOException;
+
+ long contentLength() throws IOException;
+
+ long lastModified() throws IOException;
+
+ Resource createRelative(String relativePath) throws IOException;
+
+ String getFilename();
+
+ String getDescription();
+}
+
+```
+
+
+
+ÕýÈç `Resource` ½Ó¿ÚµÄ¶¨ÒåËùʾ£¬ËüÀ©Õ¹ÁË `InputStreamSource` ½Ó¿Ú¡£`Resource` ×îºËÐĵķ½·¨ÈçÏ£º
+
+* `getInputStream()` - ¶¨Î»²¢ÇÒ´ò¿ªµ±Ç°×ÊÔ´£¬·µ»Øµ±Ç°×ÊÔ´µÄ `InputStream`¡£Ã¿´Îµ÷Óö¼»á·µ»ØÒ»¸öÐ嵀 `InputStream`¡£µ÷ÓÃÕßÐèÒª¸ºÔð¹Ø±ÕÁ÷¡£
+* `exists()` - Åжϵ±Ç°×ÊÔ´ÊÇ·ñÕæµÄ´æÔÚ¡£
+* `isOpen()` - Åжϵ±Ç°×ÊÔ´ÊÇ·ñÊÇÒ»¸öÒÑ´ò¿ªµÄ `InputStream`¡£Èç¹ûΪ true£¬Ôò `InputStream` ²»Äܱ»¶à´Î¶ÁÈ¡£¬±ØÐëÖ»¶Áȡһ´ÎÈ»ºó¹Ø±ÕÒÔ±ÜÃâ×ÊԴй©¡£¶ÔËùÓг£ÓÃ×ÊԴʵÏÖ·µ»Ø false£¬`InputStreamResource` ³ýÍâ¡£
+* `getDescription()` - ·µ»Øµ±Ç°×ÊÔ´µÄÃèÊö£¬µ±´¦Àí×ÊÔ´³ö´íʱ£¬×ÊÔ´µÄÃèÊö»áÓÃÓÚ´íÎóÐÅÏ¢µÄÊä³ö¡£Ò»°ãÀ´Ëµ£¬×ÊÔ´µÄÃèÊöÊÇÒ»¸öÍêÈ«ÏÞ¶¨µÄÎļþÃû³Æ£¬»òÕßÊǵ±Ç°×ÊÔ´µÄÕæÊµ URL¡£
+
+³£¼û Spring ×ÊÔ´½Ó¿Ú£º
+
+| ÀàÐÍ | ½Ó¿Ú |
+| --- | --- |
+| ÊäÈëÁ÷ | `org.springframework.core.io.InputStreamSource` |
+| Ö»¶Á×ÊÔ´ | `org.springframework.core.io.Resource` |
+| ¿Éд×ÊÔ´ | `org.springframework.core.io.WritableResource` |
+| ±àÂë×ÊÔ´ | `org.springframework.core.io.support.EncodedResource` |
+| ÉÏÏÂÎÄ×ÊÔ´ | `org.springframework.core.io.ContextResource` |
+
+
+
+
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/a1549f/#%E5%86%85%E7%BD%AE%E7%9A%84-resource-%E5%AE%9E%E7%8E%B0)ÄÚÖÃµÄ Resource ʵÏÖ
+
+Spring °üÀ¨¼¸¸öÄÚÖÃµÄ Resource ʵÏÖ£º
+
+| ×ÊÔ´À´Ô´ | ǰ׺ | ˵Ã÷ |
+| --- | --- | --- |
+| [`UrlResource`(opens new window)](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-urlresource) | `file:`¡¢`https:`¡¢`ftp:` µÈ | `UrlResource` ·â×°ÁËÒ»¸ö `java.net.URL` ¶ÔÏó£¬**ÓÃÓÚ·ÃÎÊ¿Éͨ¹ý URL ·ÃÎʵÄÈκζÔÏó**£¬ÀýÈçÎļþ¡¢HTTPS Ä¿±ê¡¢FTP Ä¿±êµÈ¡£ËùÓÐ URL ¶¼¿ÉÒÔͨ¹ý±ê×¼»¯µÄ×Ö·û´®ÐÎʽ±íʾ£¬Òò´Ë¿ÉÒÔʹÓÃÊʵ±µÄ±ê×¼»¯Ç°×ºÀ´Ö¸Ê¾Ò»ÖÖ URL ÀàÐÍÓëÁíÒ»ÖÖ URL ÀàÐ͵ÄÇø±ð¡£ Õâ°üÀ¨£º`file`£ºÓÃÓÚ·ÃÎÊÎļþϵͳ·¾¶£»`https`£ºÓÃÓÚͨ¹ý HTTPS ÐÒé·ÃÎÊ×ÊÔ´£»`ftp`£ºÓÃÓÚͨ¹ý FTP ·ÃÎÊ×ÊÔ´µÈµÈ¡£ |
+| [`ClassPathResource`(opens new window)](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-classpathresource) | `classpath:` | `ClassPathResource` **´ÓÀà·¾¶ÉϼÓÔØ×ÊÔ´**¡£ËüʹÓÃÏß³ÌÉÏÏÂÎļÓÔØÆ÷¡¢¸ø¶¨µÄÀà¼ÓÔØÆ÷»òÖ¸¶¨µÄ class ÀàÐÍÖеÄÈÎÒâÒ»¸öÀ´¼ÓÔØ×ÊÔ´¡£ |
+| [`FileSystemResource`(opens new window)](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-filesystemresource) | `file:` | `FileSystemResource` **ÊÇ `java.io.File` µÄ×ÊԴʵÏÖ**¡£Ëü»¹Ö§³Ö `java.nio.file.Path` £¬Ó¦Óà Spring µÄ±ê×¼¶Ô×Ö·û´®Â·¾¶½øÐÐת»»¡£`FileSystemResource` Ö§³Ö½âÎöΪÎļþºÍ URL¡£ |
+| [`PathResource`(opens new window)](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-pathresource) | ÎÞ | `PathResource` ÊÇ `java.nio.file.Path` µÄ×ÊԴʵÏÖ¡£ |
+| [`ServletContextResource`(opens new window)](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-servletcontextresource) | ÎÞ | `ServletContextResource` **ÊÇ `ServletContext` µÄ×ÊԴʵÏÖ**¡£Ëü±íʾÏàÓ¦ Web Ó¦ÓóÌÐò¸ùĿ¼ÖеÄÏà¶Ô·¾¶¡£ |
+| [`InputStreamResource`(opens new window)](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-inputstreamresource) | ÎÞ | `InputStreamResource` **ÊÇÖ¸¶¨ `InputStream` µÄ×ÊԴʵÏÖ**¡£×¢Ò⣺Èç¹û¸Ã `InputStream` Òѱ»´ò¿ª£¬Ôò²»¿ÉÒÔ¶à´Î¶ÁÈ¡¸ÃÁ÷¡£ |
+| [`ByteArrayResource`(opens new window)](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#resources-implementations-bytearrayresource) | ÎÞ | `ByteArrayResource` ÊÇÖ¸¶¨µÄ¶þ½øÖÆÊý×éµÄ×ÊԴʵÏÖ¡£Ëü»áΪ¸ø¶¨µÄ×Ö½ÚÊý×é´´½¨Ò»¸ö `ByteArrayInputStream`¡£ |
+
+
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/a1549f/#resourceloader-%E6%8E%A5%E5%8F%A3)ResourceLoader ½Ó¿Ú
+
+`ResourceLoader` ½Ó¿ÚÓÃÓÚ¼ÓÔØ `Resource` ¶ÔÏ󡣯䶍ÒåÈçÏ£º
+
+
+
+```
+public interface ResourceLoader {
+
+ Resource getResource(String location);
+
+ ClassLoader getClassLoader();
+}
+
+```
+
+
+
+Spring ÖÐÖ÷ÒªµÄ ResourceLoader ʵÏÖ£º
+
+
+
+Spring ÖУ¬ËùÓÐµÄ `ApplicationContext` ¶¼ÊµÏÖÁË `ResourceLoader` ½Ó¿Ú¡£Òò´Ë£¬ËùÓÐ `ApplicationContext` ¶¼¿ÉÒÔͨ¹ý `getResource()` ·½·¨»ñÈ¡ `Resource` ʵÀý¡£
+
+¡¾Ê¾Àý¡¿
+
+
+
+```
+// Èç¹ûûÓÐÖ¸¶¨×ÊԴǰ׺£¬Spring »á³¢ÊÔ·µ»ØºÏÊʵÄ×ÊÔ´
+Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
+// Èç¹ûÖ¸¶¨ classpath: ǰ׺£¬Spring »áÇ¿ÖÆÊ¹Óà ClassPathResource
+Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
+// Èç¹ûÖ¸¶¨ file:¡¢http µÈ URL ǰ׺£¬Spring »áÇ¿ÖÆÊ¹Óà UrlResource
+Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
+Resource template = ctx.getResource("http://myhost.com/resource/path/myTemplate.txt");
+
+```
+
+
+
+ϱíÁоÙÁË Spring ¸ù¾Ý¸÷ÖÖλÖ÷¾¶¼ÓÔØ×ÊÔ´µÄ²ßÂÔ£º
+
+| ǰ׺ | ÑùÀý | ˵Ã÷ |
+| --- | --- | --- |
+| `classpath:` | `classpath:com/myapp/config.xml` | ´ÓÀà·¾¶¼ÓÔØ |
+| `file:` | `file:///data/config.xml` | ÒÔ URL ÐÎʽ´ÓÎļþϵͳ¼ÓÔØ |
+| `http:` | `http://myserver/logo.png` | ÒÔ URL ÐÎʽ¼ÓÔØ |
+| ÎÞ | `/data/config.xml` | ÓɵײãµÄ ApplicationContext ʵÏÖ¾ö¶¨ |
+
+
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/a1549f/#resourcepatternresolver-%E6%8E%A5%E5%8F%A3)ResourcePatternResolver ½Ó¿Ú
+
+`ResourcePatternResolver` ½Ó¿ÚÊÇ `ResourceLoader` ½Ó¿ÚµÄÀ©Õ¹£¬ËüµÄ×÷ÓÃÊǶ¨Òå²ßÂÔ£¬¸ù¾ÝλÖÃģʽ½âÎö `Resource` ¶ÔÏó¡£
+
+
+
+```
+public interface ResourcePatternResolver extends ResourceLoader {
+
+ String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
+
+ Resource[] getResources(String locationPattern) throws IOException;
+}
+
+```
+
+
+
+`PathMatchingResourcePatternResolver` ÊÇÒ»¸ö¶ÀÁ¢µÄʵÏÖ£¬¿ÉÒÔÔÚ `ApplicationContext` Ö®ÍâʹÓã¬Ò²¿ÉÒÔ±» `ResourceArrayPropertyEditor` ÓÃÓÚÌî³ä `Resource[]` bean ÊôÐÔ¡£`PathMatchingResourcePatternResolver` Äܹ»½«Ö¸¶¨µÄ×ÊԴλÖ÷¾¶½âÎöΪһ¸ö»ò¶à¸öÆ¥ÅäµÄ `Resource` ¶ÔÏó¡£
+
+> ×¢Ò⣺Èκαê×¼ `ApplicationContext` ÖеÄĬÈÏ `ResourceLoader` ʵ¼ÊÉÏÊÇ `PathMatchingResourcePatternResolver` µÄÒ»¸öʵÀý£¬ËüʵÏÖÁË `ResourcePatternResolver` ½Ó¿Ú¡£
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/a1549f/#resourceloaderaware-%E6%8E%A5%E5%8F%A3)ResourceLoaderAware ½Ó¿Ú
+
+`ResourceLoaderAware` ½Ó¿ÚÊÇÒ»¸öÌØÊâµÄ»Øµ÷½Ó¿Ú£¬ÓÃÀ´±ê¼ÇÌṩ `ResourceLoader` ÒýÓõĶÔÏó¡£`ResourceLoaderAware` ½Ó¿Ú¶¨ÒåÈçÏ£º
+
+
+
+```
+public interface ResourceLoaderAware {
+ void setResourceLoader(ResourceLoader resourceLoader);
+}
+
+```
+
+
+
+µ±Ò»¸öÀàʵÏÖ `ResourceLoaderAware` ²¢²¿Êðµ½Ó¦ÓóÌÐòÉÏÏÂÎÄÖУ¨×÷Ϊ Spring ¹ÜÀíµÄ bean£©Ê±£¬Ëü»á±»Ó¦ÓóÌÐòÉÏÏÂÎÄʶ±ðΪ `ResourceLoaderAware`£¬È»ºó£¬Ó¦ÓóÌÐòÉÏÏÂÎÄ»áµ÷Óà `setResourceLoader(ResourceLoader)`£¬½«×ÔÉí×÷Ϊ²ÎÊýÌṩ£¨Çë¼Çס£¬Spring ÖеÄËùÓÐÓ¦ÓóÌÐòÉÏÏÂÎĶ¼ÊµÏÖ `ResourceLoader` ½Ó¿Ú£©¡£
+
+ÓÉÓÚ `ApplicationContext` ÊÇÒ»¸ö `ResourceLoader`£¬¸Ã bean »¹¿ÉÒÔʵÏÖ `ApplicationContextAware` ½Ó¿Ú²¢Ö±½ÓʹÓÃÌṩµÄÓ¦ÓóÌÐòÉÏÏÂÎÄÀ´¼ÓÔØ×ÊÔ´¡£ µ«ÊÇ£¬Ò»°ãÀ´Ëµ£¬Èç¹ûÄúÖ»ÐèÒªÕâЩ£¬×îºÃʹÓÃרÃÅµÄ `ResourceLoader` ½Ó¿Ú¡£ ¸Ã´úÂ뽫½öñîºÏµ½×ÊÔ´¼ÓÔØ½Ó¿Ú£¨¿ÉÒÔ±»ÊÓΪʵÓóÌÐò½Ó¿Ú£©£¬¶ø²»ñîºÏµ½Õû¸ö Spring `ApplicationContext` ½Ó¿Ú¡£
+
+ÔÚÓ¦ÓóÌÐòÖУ¬»¹¿ÉÒÔʹÓà `ResourceLoader` µÄ×Ô¶¯×°Åä×÷ΪʵÏÖ `ResourceLoaderAware` ½Ó¿ÚµÄÌæ´ú·½·¨¡£´«Í³µÄ¹¹Ô캯ÊýºÍ `byType` ×Ô¶¯×°ÅäģʽÄܹ»·Ö±ðΪ¹¹Ô캯Êý²ÎÊý»ò setter ·½·¨²ÎÊýÌṩ `ResourceLoader`¡£ ΪÁË»ñµÃ¸ü´óµÄÁé»îÐÔ£¨°üÀ¨×Ô¶¯×°Åä×ֶκͶà²ÎÊý·½·¨µÄÄÜÁ¦£©£¬Ç뿼ÂÇʹÓûùÓÚ×¢½âµÄ×Ô¶¯×°Å书ÄÜ¡£ ÔÚÕâÖÖÇé¿öÏ£¬`ResourceLoader` »á×Ô¶¯Á¬½Óµ½ÐèÒª `ResourceLoader` ÀàÐ͵Ä×ֶΡ¢¹¹Ô캯Êý²ÎÊý»ò·½·¨²ÎÊýÖУ¬Ö»ÒªÏà¹Ø×ֶΡ¢¹¹Ô캯Êý»ò·½·¨´øÓÐ `@Autowired` ×¢½â¼´¿É¡£
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/a1549f/#%E8%B5%84%E6%BA%90%E4%BE%9D%E8%B5%96)×ÊÔ´ÒÀÀµ
+
+Èç¹û bean ±¾ÉíҪͨ¹ýijÖÖ¶¯Ì¬¹ý³ÌÀ´È·¶¨ºÍÌṩ×ÊԴ·¾¶£¬ÄÇô bean ¿ÉÒÔʹÓà `ResourceLoader` »ò `ResourcePatternResolver` ½Ó¿ÚÀ´¼ÓÔØ×ÊÔ´¡£ ÀýÈ磬¿¼ÂǼÓÔØÄ³ÖÖÄ£°å£¬ÆäÖÐËùÐèµÄÌØ¶¨×ÊÔ´È¡¾öÓÚÓû§µÄ½ÇÉ«¡£ Èç¹û×ÊÔ´ÊǾ²Ì¬µÄ£¬ÍêÈ«Ïû³ý `ResourceLoader` ½Ó¿Ú£¨»ò `ResourcePatternResolver` ½Ó¿Ú£©µÄʹÓã¬Èà bean ¹«¿ªËüÐèÒªµÄ `Resource` ÊôÐÔ£¬²¢ÆÚÍû½«ËüÃÇ×¢ÈëÆäÖÐÊÇÓÐÒâÒåµÄ¡£
+
+ʹעÈëÕâЩÊôÐÔ±äµÃ¼òµ¥µÄÔÒòÊÇËùÓÐÓ¦ÓóÌÐòÉÏÏÂÎͼע²á²¢Ê¹ÓÃÒ»¸öÌØÊâµÄ JavaBeans `PropertyEditor`£¬Ëü¿ÉÒÔ½« `String` ·¾¶×ª»»Îª `Resource` ¶ÔÏó¡£ ÀýÈ磬ÏÂÃæµÄ MyBean ÀàÓÐÒ»¸ö `Resource` ÀàÐ͵ÄÄ£°åÊôÐÔ¡£
+
+¡¾Ê¾Àý¡¿
+
+
+
+```
+
+
+
+
+```
+
+
+
+Çë×¢Ò⣬ÅäÖÃÖÐÒýÓõÄÄ£°å×ÊԴ·¾¶Ã»ÓÐǰ׺£¬ÒòΪӦÓóÌÐòÉÏÏÂÎı¾Éí½«ÓÃ×÷ `ResourceLoader`£¬×ÊÔ´±¾Éí½«¸ù¾ÝÐèҪͨ¹ý `ClassPathResource`£¬`FileSystemResource` »ò ServletContextResource ¼ÓÔØ£¬¾ßÌåÈ¡¾öÓÚÉÏÏÂÎĵÄÈ·ÇÐÀàÐÍ¡£
+
+Èç¹ûÐèÒªÇ¿ÖÆÊ¹ÓÃÌØ¶¨µÄ×ÊÔ´ÀàÐÍ£¬Ôò¿ÉÒÔʹÓÃǰ׺¡£ ÒÔÏÂÁ½¸öʾÀýÏÔʾÈçºÎÇ¿ÖÆÊ¹Óà `ClassPathResource` ºÍ `UrlResource`£¨ºóÕßÓÃÓÚ·ÃÎÊÎļþϵͳÎļþ£©¡£
+
+
+
+```
+
+
+
+```
+
+
+
+¿ÉÒÔͨ¹ý `@Value` ×¢½â¼ÓÔØ×ÊÔ´Îļþ `myTemplate.txt`£¬Ê¾ÀýÈçÏ£º
+
+
+
+```
+@Component
+public class MyBean {
+
+ private final Resource template;
+
+ public MyBean(@Value("${template.path}") Resource template) {
+ this.template = template;
+ }
+
+ // ...
+}
+
+```
+
+
+
+Spring µÄ `PropertyEditor` »á¸ù¾Ý×ÊÔ´ÎļþµÄ·¾¶×Ö·û´®£¬¼ÓÔØ `Resource` ¶ÔÏ󣬲¢½«Æä×¢Èëµ½ MyBean µÄ¹¹Ôì·½·¨¡£
+
+Èç¹ûÏëÒª¼ÓÔØ¶à¸ö×ÊÔ´Îļþ£¬¿ÉÒÔʹÓà `classpath*:` ǰ׺£¬ÀýÈ磺`classpath*:/config/templates/*.txt`¡£
+
+
+
+```
+@Component
+public class MyBean {
+
+ private final Resource[] templates;
+
+ public MyBean(@Value("${templates.path}") Resource[] templates) {
+ this.templates = templates;
+ }
+
+ // ...
+}
+
+```
+
+
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/a1549f/#%E5%BA%94%E7%94%A8%E4%B8%8A%E4%B8%8B%E6%96%87%E5%92%8C%E8%B5%84%E6%BA%90%E8%B7%AF%E5%BE%84)Ó¦ÓÃÉÏÏÂÎĺÍ×ÊԴ·¾¶
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/a1549f/#%E6%9E%84%E9%80%A0%E5%BA%94%E7%94%A8%E4%B8%8A%E4%B8%8B%E6%96%87)¹¹ÔìÓ¦ÓÃÉÏÏÂÎÄ
+
+Ó¦ÓÃÉÏÏÂÎĹ¹Ô캯Êý£¨Õë¶ÔÌØ¶¨µÄÓ¦ÓÃÉÏÏÂÎÄÀàÐÍ£©Í¨³£½«×Ö·û´®»ò×Ö·û´®Êý×é×÷Ϊ×ÊÔ´µÄλÖ÷¾¶£¬ÀýÈç¹¹³ÉÉÏÏÂÎ͍ÒåµÄ XML Îļþ¡£
+
+¡¾Ê¾Àý¡¿
+
+
+
+```
+ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
+ApplicationContext ctx = new FileSystemXmlApplicationContext("conf/appContext.xml");
+ApplicationContext ctx = new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
+ApplicationContext ctx = new ClassPathXmlApplicationContext(
+ new String[] {"services.xml", "daos.xml"}, MessengerService.class);
+
+```
+
+
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/a1549f/#%E4%BD%BF%E7%94%A8%E9%80%9A%E9%85%8D%E7%AC%A6%E6%9E%84%E9%80%A0%E5%BA%94%E7%94%A8%E4%B8%8A%E4%B8%8B%E6%96%87)ʹÓÃͨÅä·û¹¹ÔìÓ¦ÓÃÉÏÏÂÎÄ
+
+ApplicationContext ¹¹ÔìÆ÷µÄÖеÄ×ÊԴ·¾¶¿ÉÒÔÊǵ¥Ò»µÄ·¾¶£¨¼´Ò»¶ÔÒ»µØÓ³É䵽Ŀ±ê×ÊÔ´£©£»Ò²¿ÉÒÔÊÇͨÅä·ûÐÎʽ¡ª¡ª¿É°üº¬ classpath*£ºÒ²¿ÉÒÔÊÇǰ׺»ò ant ·ç¸ñµÄÕýÔò±í´ïʽ£¨Ê¹Óà spring µÄ PathMatcher À´Æ¥Å䣩¡£
+
+ʾÀý£º
+
+
+
+```
+ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
+
+```
+
+
+
+ʹÓà `classpath*` ±íʾÀà·¾¶ÏÂËùÓÐÆ¥ÅäÎļþÃû³ÆµÄ×ÊÔ´¶¼»á±»»ñÈ¡(±¾ÖÊÉϾÍÊǵ÷ÓÃÁË ClassLoader.getResources(¡) ·½·¨£©£¬½Ó׎«»ñÈ¡µ½µÄ×ÊÔ´×é×°³É×îÖÕµÄÓ¦ÓÃÉÏÏÂÎÄ¡£
+
+ÔÚλÖ÷¾¶µÄÆäÓಿ·Ö£¬`classpath*:` ǰ׺¿ÉÒÔÓë PathMatcher ½áºÏʹÓã¬È磺`classpath*:META-INF/*-beans.xml`¡£
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/a1549f/#%E9%97%AE%E9%A2%98)ÎÊÌâ
+
+Spring ÅäÖÃ×ÊÔ´ÖÐÓÐÄÄЩ³£¼ûÀàÐÍ£¿
+
+* XML ×ÊÔ´
+* Properties ×ÊÔ´
+* YAML ×ÊÔ´
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/a1549f/#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99)²Î¿¼×ÊÁÏ
+
+* [Spring ¹Ù·½ÎĵµÖ® Core Technologies(opens new window)](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans)
+* [¡¶Ð¡Âí¸ç½² Spring ºËÐıà³Ì˼Ïë¡·](https://time.geekbang.org/course/intro/265)
+
+# ²Î¿¼ÎÄÕÂ
+https://www.w3cschool.cn/wkspring
+https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
+http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
+https://dunwu.github.io/spring-tutorial
+https://mszlu.com/java/spring
+http://c.biancheng.net/spring/aop-module.html
\ No newline at end of file
diff --git "a/docs/spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md" "b/docs/spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md"
new file mode 100644
index 0000000..8589b50
--- /dev/null
+++ "b/docs/spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md"
@@ -0,0 +1,298 @@
+
+
+# Spring ÅäÖÃÔªÊý¾Ý
+
+
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#spring-%E9%85%8D%E7%BD%AE%E5%85%83%E4%BF%A1%E6%81%AF)Spring ÅäÖÃÔªÐÅÏ¢
+
+* Spring Bean ÅäÖÃÔªÐÅÏ¢ - BeanDefinition
+* Spring Bean ÊôÐÔÔªÐÅÏ¢ - PropertyValues
+* Spring ÈÝÆ÷ÅäÖÃÔªÐÅÏ¢
+* Spring Íⲿ»¯ÅäÖÃÔªÐÅÏ¢ - PropertySource
+* Spring Profile ÔªÐÅÏ¢ - @Profile
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#spring-bean-%E9%85%8D%E7%BD%AE%E5%85%83%E4%BF%A1%E6%81%AF)Spring Bean ÅäÖÃÔªÐÅÏ¢
+
+Bean ÅäÖÃÔªÐÅÏ¢ - BeanDefinition
+
+* GenericBeanDefinition£ºÍ¨ÓÃÐÍ BeanDefinition
+* RootBeanDefinition£ºÎÞ Parent µÄ BeanDefinition »òÕߺϲ¢ºó BeanDefinition
+* AnnotatedBeanDefinition£º×¢½â±ê×¢µÄ BeanDefinition
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#spring-bean-%E5%B1%9E%E6%80%A7%E5%85%83%E4%BF%A1%E6%81%AF)Spring Bean ÊôÐÔÔªÐÅÏ¢
+
+* Bean ÊôÐÔÔªÐÅÏ¢ - PropertyValues
+ * ¿ÉÐÞ¸ÄʵÏÖ - MutablePropertyValues
+ * ÔªËØ³ÉÔ± - PropertyValue
+* Bean ÊôÐÔÉÏÏÂÎÄ´æ´¢ - AttributeAccessor
+* Bean ÔªÐÅÏ¢ÔªËØ - BeanMetadataElement
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#spring-%E5%AE%B9%E5%99%A8%E9%85%8D%E7%BD%AE%E5%85%83%E4%BF%A1%E6%81%AF)Spring ÈÝÆ÷ÅäÖÃÔªÐÅÏ¢
+
+Spring XML ÅäÖÃÔªÐÅÏ¢ - beans ÔªËØÏà¹Ø
+
+| beans ÔªËØÊôÐÔ | ĬÈÏÖµ | ʹÓó¡¾° |
+| --- | --- | --- |
+| profile | null£¨Áô¿Õ£© | Spring Profiles ÅäÖÃÖµ |
+| default-lazy-init | default | µ± outter beans ¡°default-lazy-init¡± ÊôÐÔ´æÔÚʱ£¬¼Ì³Ð¸ÃÖµ£¬·ñÔòΪ¡°false¡± |
+| default-merge | default | µ± outter beans ¡°default-merge¡± ÊôÐÔ´æÔÚʱ£¬¼Ì³Ð¸ÃÖµ£¬·ñÔòΪ¡°false¡± |
+| default-autowire | default | µ± outter beans ¡°default-autowire¡± ÊôÐÔ´æÔÚʱ£¬¼Ì³Ð¸ÃÖµ£¬·ñÔòΪ¡°no¡± |
+| default-autowire-candidates | null£¨Áô¿Õ£© | ĬÈÏ Spring Beans Ãû³Æ pattern |
+| default-init-method | null£¨Áô¿Õ£© | ĬÈÏ Spring Beans ×Ô¶¨Òå³õʼ»¯·½·¨ |
+| default-destroy-method | null£¨Áô¿Õ£© | ĬÈÏ Spring Beans ×Ô¶¨ÒåÏú»Ù·½·¨ |
+
+Spring XML ÅäÖÃÔªÐÅÏ¢ - Ó¦ÓÃÉÏÏÂÎÄÏà¹Ø
+
+| XML ÔªËØ | ʹÓó¡¾° |
+| --- | --- |
+| ` ` | ¼¤»î Spring ×¢½âÇý¶¯ |
+| ` ` | Spring @Component ÒÔ¼°×Ô¶¨Òå×¢½âɨÃè |
+| ` ` | ¼¤»î Spring LoadTimeWeaver |
+| ` ` | ±©Â¶ Spring Beans ×÷Ϊ JMX Beans |
+| ` ` | ½«µ±Ç°Æ½Ì¨×÷Ϊ MBeanServer |
+| ` ` | ¼ÓÔØÍⲿ»¯ÅäÖÃ×ÊÔ´×÷Ϊ Spring ÊôÐÔÅä |
+| ` ` | ÀûÓÃÍⲿ»¯ÅäÖÃ×ÊÔ´¸²¸Ç Spring Êô |
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E5%9F%BA%E4%BA%8E-xml-%E6%96%87%E4%BB%B6%E8%A3%85%E8%BD%BD-spring-bean-%E9%85%8D%E7%BD%AE%E5%85%83%E4%BF%A1%E6%81%AF)»ùÓÚ XML Îļþ×°ÔØ Spring Bean ÅäÖÃÔªÐÅÏ¢
+
+µ×²ãʵÏÖ - XmlBeanDefinitionReader
+
+| XML ÔªËØ | ʹÓó¡¾° |
+| --- | --- |
+| ` ` | µ¥ XML ×ÊԴϵĶà¸ö Spring Beans ÅäÖà |
+| ` ` | µ¥¸ö Spring Bean ¶¨Ò壨BeanDefinition£©ÅäÖà |
+| ` ` | Ϊ Spring Bean ¶¨Ò壨BeanDefinition£©Ó³Éä±ðÃû |
+| ` ` | ¼ÓÔØÍⲿ Spring XML ÅäÖÃ×ÊÔ´ |
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E5%9F%BA%E4%BA%8E-properties-%E6%96%87%E4%BB%B6%E8%A3%85%E8%BD%BD-spring-bean-%E9%85%8D%E7%BD%AE%E5%85%83%E4%BF%A1%E6%81%AF)»ùÓÚ Properties Îļþ×°ÔØ Spring Bean ÅäÖÃÔªÐÅÏ¢
+
+µ×²ãʵÏÖ - PropertiesBeanDefinitionReader
+
+| Properties ÊôÐÔÃû | ʹÓó¡¾° |
+| --- | --- |
+| `class` | Bean ÀàÈ«³ÆÏÞ¶¨Ãû |
+| `abstract` | ÊÇ·ñΪ³éÏóµÄ BeanDefinition |
+| `parent` | Ö¸¶¨ parent BeanDefinition Ãû³Æ |
+| `lazy-init` | ÊÇ·ñΪÑÓ³Ù³õʼ»¯ |
+| `ref` | ÒýÓÃÆäËû Bean µÄÃû³Æ |
+| `scope` | ÉèÖà Bean µÄ scope ÊôÐÔ |
+| ${n} | n ±íʾµÚ n+1 ¸ö¹¹ÔìÆ÷²ÎÊý |
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E5%9F%BA%E4%BA%8E-java-%E6%B3%A8%E8%A7%A3%E8%A3%85%E8%BD%BD-spring-bean-%E9%85%8D%E7%BD%AE%E5%85%83%E4%BF%A1%E6%81%AF)»ùÓÚ Java ×¢½â×°ÔØ Spring Bean ÅäÖÃÔªÐÅÏ¢
+
+Spring ģʽע½â
+
+| Spring ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
+| --- | --- | --- |
+| `@Repository` | Êý¾Ý²Ö´¢Ä£Ê½×¢½â | 2.0 |
+| `@Component` | ͨÓÃ×é¼þģʽע½â | 2.5 |
+| `@Service` | ·þÎñģʽע½â | 2.5 |
+| `@Controller` | Web ¿ØÖÆÆ÷ģʽע½â | 2.5 |
+| `@Configuration` | ÅäÖÃÀàģʽע½â | 3.0 |
+
+Spring Bean ¶¨Òå×¢½â
+
+| Spring ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
+| --- | --- | --- |
+| `@Bean` | Ìæ»» XML ÔªËØ?`` | 3.0 |
+| `@DependsOn` | Ìæ´ú XML ÊôÐÔ?` ` | 3.0 |
+| `@Lazy` | Ìæ´ú XML ÊôÐÔ?` ` | 3.0 |
+| `@Primary` | Ìæ»» XML ÔªËØ?` ` | 3.0 |
+| `@Role` | Ìæ»» XML ÔªËØ?` ` | 3.1 |
+| `@Lookup` | Ìæ´ú XML ÊôÐÔ?`` | 4.1 |
+
+Spring Bean ÒÀÀµ×¢Èë×¢½â
+
+| Spring ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
+| --- | --- | --- |
+| `@Autowired` | Bean ÒÀÀµ×¢È룬֧³Ö¶àÖÖÒÀÀµ²éÕÒ·½Ê½ | 2.5 |
+| `@Qualifier` | ϸÁ£¶ÈµÄ @Autowired ÒÀÀµ²éÕÒ | 2.5 |
+
+?
+
+| Java ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
+| --- | --- | --- |
+| @Resource | ÀàËÆÓÚ @Autowired | 2.5 |
+| @Inject | ÀàËÆÓÚ @Autowired | 2.5 |
+
+Spring Bean Ìõ¼þ×°Åä×¢½â
+
+| Spring ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
+| --- | --- | --- |
+| @Profile | ÅäÖû¯Ìõ¼þ×°Åä | 3.1 |
+| @Conditional | ±à³ÌÌõ¼þ×°Åä | 4.0 |
+
+Spring Bean ÉúÃüÖÜÆÚ»Øµ÷×¢½â
+
+| Spring ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
+| --- | --- | --- |
+| @PostConstruct | Ìæ»» XML ÔªËØ? »ò InitializingBean | 2.5 |
+| @PreDestroy | Ìæ»» XML ÔªËØ? »ò DisposableBean | 2.5 |
+
+Spring BeanDefinition ½âÎöÓë×¢²á
+
+| Spring ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
+| --- | --- | --- |
+| XML ×ÊÔ´ | XmlBeanDefinitionReader | 1.0 |
+| Properties ×ÊÔ´ | PropertiesBeanDefinitionReader | 1.0 |
+| Java ×¢½â | AnnotatedBeanDefinitionReader | 3.0 |
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#spring-bean-%E9%85%8D%E7%BD%AE%E5%85%83%E4%BF%A1%E6%81%AF%E5%BA%95%E5%B1%82%E5%AE%9E%E7%8E%B0)Spring Bean ÅäÖÃÔªÐÅÏ¢µ×²ãʵÏÖ
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#spring-xml-%E8%B5%84%E6%BA%90-beandefinition-%E8%A7%A3%E6%9E%90%E4%B8%8E%E6%B3%A8%E5%86%8C)Spring XML ×ÊÔ´ BeanDefinition ½âÎöÓë×¢²á
+
+ºËÐÄ API - XmlBeanDefinitionReader
+
+* ×ÊÔ´ - Resource
+* µ×²ã - BeanDefinitionDocumentReader
+ * XML ½âÎö - Java DOM Level 3 API
+ * BeanDefinition ½âÎö - BeanDefinitionParserDelegate
+ * BeanDefinition ×¢²á - BeanDefinitionRegistry
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#spring-properties-%E8%B5%84%E6%BA%90-beandefinition-%E8%A7%A3%E6%9E%90%E4%B8%8E%E6%B3%A8%E5%86%8C)Spring Properties ×ÊÔ´ BeanDefinition ½âÎöÓë×¢²á
+
+ºËÐÄ API - PropertiesBeanDefinitionReader
+
+* ×ÊÔ´
+ * ×Ö½ÚÁ÷ - Resource
+ * ×Ö·ûÁ÷ - EncodedResouce
+* µ×²ã
+ * ´æ´¢ - java.util.Properties
+ * BeanDefinition ½âÎö - API ÄÚ²¿ÊµÏÖ
+ * BeanDefinition ×¢²á - BeanDefinitionRegistry
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#spring-java-%E6%B3%A8%E5%86%8C-beandefinition-%E8%A7%A3%E6%9E%90%E4%B8%8E%E6%B3%A8%E5%86%8C)Spring Java ×¢²á BeanDefinition ½âÎöÓë×¢²á
+
+ºËÐÄ API - AnnotatedBeanDefinitionReader
+
+* ×ÊÔ´
+ * Àà¶ÔÏó - java.lang.Class
+* µ×²ã
+ * Ìõ¼þÆÀ¹À - ConditionEvaluator
+ * Bean ·¶Î§½âÎö - ScopeMetadataResolver
+ * BeanDefinition ½âÎö - ÄÚ²¿ API ʵÏÖ
+ * BeanDefinition ´¦Àí - AnnotationConfigUtils.processCommonDefinitionAnnotations
+ * BeanDefinition ×¢²á - BeanDefinitionRegistry
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E5%9F%BA%E4%BA%8E-xml-%E6%96%87%E4%BB%B6%E8%A3%85%E8%BD%BD-spring-ioc-%E5%AE%B9%E5%99%A8%E9%85%8D%E7%BD%AE%E5%85%83%E4%BF%A1%E6%81%AF)»ùÓÚ XML Îļþ×°ÔØ Spring IoC ÈÝÆ÷ÅäÖÃÔªÐÅÏ¢
+
+Spring IoC ÈÝÆ÷Ïà¹Ø XML ÅäÖÃ
+
+| ÃüÃû¿Õ¼ä | ËùÊôÄ£¿é | Schema ×ÊÔ´ URL |
+| --- | --- | --- |
+| beans | spring-beans | https://www.springframework.org/schema/beans/spring-beans.xsd |
+| context | spring-context | https://www.springframework.org/schema/context/spring-context.xsd |
+| aop | spring-aop | https://www.springframework.org/schema/aop/spring-aop.xsd |
+| tx | spring-tx | https://www.springframework.org/schema/tx/spring-tx.xsd |
+| util | spring-beans | beans https://www.springframework.org/schema/util/spring-util.xsd |
+| tool | spring-beans | https://www.springframework.org/schema/tool/spring-tool.xsd |
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E5%9F%BA%E4%BA%8E-java-%E6%B3%A8%E8%A7%A3%E8%A3%85%E8%BD%BD-spring-ioc-%E5%AE%B9%E5%99%A8%E9%85%8D%E7%BD%AE%E5%85%83%E4%BF%A1%E6%81%AF)»ùÓÚ Java ×¢½â×°ÔØ Spring IoC ÈÝÆ÷ÅäÖÃÔªÐÅÏ¢
+
+Spring IoC ÈÝÆ÷×°Åä×¢½â
+
+| Spring ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
+| --- | --- | --- |
+| @ImportResource | Ìæ»» XML ÔªËØ?`` | 3.0 |
+| @Import | µ¼Èë Configuration Class | 3.0 |
+| @ComponentScan | ɨÃèÖ¸¶¨ package ϱê×¢ Spring ģʽע½âµÄÀà | 3.1 |
+
+Spring IoC ÅäÊôÊôÐÔ×¢½â
+
+| Spring ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
+| --- | --- | --- |
+| @PropertySource | ÅäÖÃÊôÐÔ³éÏó PropertySource ×¢½â | 3.1 |
+| @PropertySources | @PropertySource ¼¯ºÏ×¢½â | 4.0 |
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E5%9F%BA%E4%BA%8E-extensible-xml-authoring-%E6%89%A9%E5%B1%95-springxml-%E5%85%83%E7%B4%A0)»ùÓÚ Extensible XML authoring À©Õ¹ SpringXML ÔªËØ
+
+Spring XML À©Õ¹
+
+* ±àд XML Schema Îļþ£º¶¨Òå XML ½á¹¹
+* ×Ô¶¨Òå NamespaceHandler ʵÏÖ£ºÃüÃû¿Õ¼ä°ó¶¨
+* ×Ô¶¨Òå BeanDefinitionParser ʵÏÖ£ºXML ÔªËØÓë BeanDefinition ½âÎö
+* ×¢²á XML À©Õ¹£ºÃüÃû¿Õ¼äÓë XML Schema Ó³Éä
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#extensible-xml-authoring-%E6%89%A9%E5%B1%95%E5%8E%9F%E7%90%86)Extensible XML authoring À©Õ¹ÔÀí
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E8%A7%A6%E5%8F%91%E6%97%B6%E6%9C%BA)´¥·¢Ê±»ú
+
+* AbstractApplicationContext#obtainFreshBeanFactory
+ * AbstractRefreshableApplicationContext#refreshBeanFactory
+ * AbstractXmlApplicationContext#loadBeanDefinitions
+ * ...
+ * XmlBeanDefinitionReader#doLoadBeanDefinitions
+ * ...
+ * BeanDefinitionParserDelegate#parseCustomElement
+
+### [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E6%A0%B8%E5%BF%83%E6%B5%81%E7%A8%8B)ºËÐÄÁ÷³Ì
+
+BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element, BeanDefinition)
+
+* »ñÈ¡ namespace
+* ͨ¹ý namespace ½âÎö NamespaceHandler
+* ¹¹Ôì ParserContext
+* ½âÎöÔªËØ£¬»ñÈ¡ BeanDefinintion
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E5%9F%BA%E4%BA%8E-properties-%E6%96%87%E4%BB%B6%E8%A3%85%E8%BD%BD%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE)»ùÓÚ Properties Îļþ×°ÔØÍⲿ»¯ÅäÖÃ
+
+×¢½âÇý¶¯
+
+* @org.springframework.context.annotation.PropertySource
+* @org.springframework.context.annotation.PropertySources
+
+API ±à³Ì
+
+* org.springframework.core.env.PropertySource
+* org.springframework.core.env.PropertySources
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E5%9F%BA%E4%BA%8E-yaml-%E6%96%87%E4%BB%B6%E8%A3%85%E8%BD%BD%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE)»ùÓÚ YAML Îļþ×°ÔØÍⲿ»¯ÅäÖÃ
+
+API ±à³Ì
+
+* org.springframework.beans.factory.config.YamlProcessor
+ * org.springframework.beans.factory.config.YamlMapFactoryBean
+ * org.springframework.beans.factory.config.YamlPropertiesFactoryBean
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E9%97%AE%E9%A2%98)ÎÊÌâ
+
+**Spring ƒÈ½¨ XML Schema ³£¼ûÓÐÄÄЩ**£¿
+
+| ÃüÃû¿Õ¼ä | ËùÊôÄ£¿é | Schema ×ÊÔ´ URL |
+| --- | --- | --- |
+| beans | spring-beans | https://www.springframework.org/schema/beans/spring-beans.xsd |
+| context | spring-context | https://www.springframework.org/schema/context/spring-context.xsd |
+| aop | spring-aop | https://www.springframework.org/schema/aop/spring-aop.xsd |
+| tx | spring-tx | https://www.springframework.org/schema/tx/spring-tx.xsd |
+| util | spring-beans | beans https://www.springframework.org/schema/util/spring-util.xsd |
+| tool | spring-beans | https://www.springframework.org/schema/tool/spring-tool.xsd |
+
+**Spring ÅäÖÃÔªÐÅÏ¢¾ßÌåÓÐÄÄЩ**£¿
+
+* Bean ÅäÖÃÔªÐÅÏ¢£ºÍ¨¹ýý½é£¨Èç XML¡¢Proeprties µÈ£©£¬½âÎö BeanDefinition
+* IoC ÈÝÆ÷ÅäÖÃÔªÐÅÏ¢£ºÍ¨¹ýý½é£¨Èç XML¡¢Proeprties µÈ£©£¬¿ØÖÆ IoC ÈÝÆ÷ÐÐΪ£¬±ÈÈç×¢½âÇý¶¯¡¢AOP µÈ
+* Íⲿ»¯ÅäÖãºÍ¨¹ý×ÊÔ´³éÏó£¨Èç Proeprties¡¢YAML µÈ£©£¬¿ØÖÆ PropertySource
+* Spring Profile£ºÍ¨¹ýÍⲿ»¯ÅäÖã¬ÌṩÌõ¼þ·ÖÖ§Á÷³Ì
+
+**Extensible XML authoring µÄȱµã**£¿
+
+* ¸ß¸´ÔÓ¶È£º¿ª·¢ÈËÔ±ÐèÒªÊìϤ XML Schema£¬spring.handlers£¬spring.schemas ÒÔ¼° Spring API
+* ǶÌ×ÔªËØÖ§³Ö½ÏÈõ£ºÍ¨³£ÐèҪʹÓ÷½·¨µÝ¹é»òÕ߯äǶÌ×½âÎöµÄ·½Ê½´¦ÀíǶÌ×£¨×Ó£©ÔªËØ
+* XML ´¦ÀíÐÔÄܽϲSpring XML »ùÓÚ DOM Level 3 API ʵÏÖ£¬¸Ã API ±ãÓÚÀí½â£¬È»¶øÐÔÄܽϲî
+* XML ¿ò¼ÜÒÆÖ²ÐԲºÜÄÑÊÊÅä¸ßÐÔÄܺͱãÀûÐ﵀ XML ¿ò¼Ü£¬Èç JAXB
+
+## [#](https://dunwu.github.io/spring-tutorial/pages/55f315/#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99)²Î¿¼×ÊÁÏ
+
+* [Spring ¹Ù·½ÎĵµÖ® Core Technologies(opens new window)](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans)
+* [¡¶Ð¡Âí¸ç½² Spring ºËÐıà³Ì˼Ïë¡·(opens new window)](https://time.geekbang.org/course/intro/265)
+
+
+
+# ²Î¿¼ÎÄÕÂ
+https://www.w3cschool.cn/wkspring
+https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
+http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
+https://dunwu.github.io/spring-tutorial
+https://mszlu.com/java/spring
+http://c.biancheng.net/spring/aop-module.html
\ No newline at end of file
diff --git "a/docs/spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md" "b/docs/spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md"
new file mode 100644
index 0000000..85723ac
--- /dev/null
+++ "b/docs/spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md"
@@ -0,0 +1,430 @@
+# SpringÊÂÎñºËÐĽӿÚ
+
+[Spring](http://www.voidme.com/spring) µÄÊÂÎñ¹ÜÀíÊÇ»ùÓÚ AOP ʵÏֵ쬶ø AOP ÊÇÒÔ·½·¨Îªµ¥Î»µÄ¡£Spring µÄÊÂÎñÊôÐÔ·Ö±ðΪ´«²¥ÐÐΪ¡¢¸ôÀë¼¶±ð¡¢Ö»¶ÁºÍ³¬Ê±ÊôÐÔ£¬ÕâЩÊôÐÔÌṩÁËÊÂÎñÓ¦Óõķ½·¨ºÍÃèÊö²ßÂÔ¡£
+
+ÔÚ [Java](http://www.voidme.com/java) EE ¿ª·¢¾³£²ÉÓõķֲãģʽÖУ¬Spring µÄÊÂÎñ´¦ÀíλÓÚÒµÎñÂß¼²ã£¬ËüÌṩÁËÕë¶ÔÊÂÎñµÄ½â¾ö·½°¸¡£
+
+ÔÚ Spring ½âѹ°üµÄ libs Ŀ¼ÖУ¬°üº¬Ò»¸öÃû³ÆÎª spring-tx-3.2.13.RELEASE.jar µÄÎļþ£¬¸ÃÎļþÊÇ Spring ÌṩµÄÓÃÓÚÊÂÎñ¹ÜÀíµÄ JAR °ü£¬ÆäÖаüÀ¨ÊÂÎñ¹ÜÀíµÄÈý¸öºËÐĽӿڣºPlatformTransactionManager¡¢TransactionDefinition ºÍ TransactionStatus¡£
+
+½«¸Ã JAR °üµÄºó׺Ãû jar ¸Ä³É zip µÄÐÎʽºó£¬½âѹѹËõ°ü£¬½øÈë½âѹÎļþ¼ÐÖÐµÄ \org\springframework\transaction Ŀ¼ºó£¬¸ÃĿ¼ÖеÄÎļþÈçͼ 1 Ëùʾ¡£
+
+
+ͼ 1 ÊÂÎñ¹ÜÀíºËÐĽӿÚ
+
+ÔÚͼ 1 ÖУ¬·½¿òËù±ê×¢µÄÈý¸öÎļþ¾ÍÊDZ¾½Ú½«Òª½²½âµÄºËÐĽӿڡ£ÕâÈý¸öºËÐĽӿڵÄ×÷Óü°ÆäÌṩµÄ·½·¨ÈçÏ¡£
+
+#### 1\. PlatformTransactionManager
+
+PlatformTransactionManager ½Ó¿ÚÊÇ Spring ÌṩµÄƽ̨ÊÂÎñ¹ÜÀíÆ÷£¬ÓÃÓÚ¹ÜÀíÊÂÎñ¡£¸Ã½Ó¿ÚÖÐÌṩÁËÈý¸öÊÂÎñ²Ù×÷·½·¨£¬¾ßÌåÈçÏ¡£
+
+* TransactionStatus getTransaction£¨TransactionDefinition definition£©£ºÓÃÓÚ»ñÈ¡ÊÂÎñ״̬ÐÅÏ¢¡£
+* void commit£¨TransactionStatus status£©£ºÓÃÓÚÌá½»ÊÂÎñ¡£
+* void rollback£¨TransactionStatus status£©£ºÓÃÓڻعöÊÂÎñ¡£
+
+ÔÚÏîÄ¿ÖУ¬Spring ½« xml ÖÐÅäÖõÄÊÂÎñÏêϸÐÅÏ¢·â×°µ½¶ÔÏó TransactionDefinition ÖУ¬È»ºóͨ¹ýÊÂÎñ¹ÜÀíÆ÷µÄ getTransaction() ·½·¨»ñµÃÊÂÎñµÄ״̬£¨TransactionStatus£©£¬²¢¶ÔÊÂÎñ½øÐÐÏÂÒ»²½µÄ²Ù×÷¡£
+
+#### 2\. TransactionDefinition
+
+TransactionDefinition ½Ó¿ÚÊÇÊÂÎñ¶¨Ò壨ÃèÊö£©µÄ¶ÔÏó£¬ËüÌṩÁËÊÂÎñÏà¹ØÐÅÏ¢»ñÈ¡µÄ·½·¨£¬ÆäÖаüÀ¨Îå¸ö²Ù×÷£¬¾ßÌåÈçÏ¡£
+
+* String getName()£º»ñÈ¡ÊÂÎñ¶ÔÏóÃû³Æ¡£
+* int getIsolationLevel()£º»ñÈ¡ÊÂÎñµÄ¸ôÀë¼¶±ð¡£
+* int getPropagationBehavior()£º»ñÈ¡ÊÂÎñµÄ´«²¥ÐÐΪ¡£
+* int getTimeout()£º»ñÈ¡ÊÂÎñµÄ³¬Ê±Ê±¼ä¡£
+* boolean isReadOnly()£º»ñÈ¡ÊÂÎñÊÇ·ñÖ»¶Á¡£
+
+ÔÚÉÏÊöÎå¸ö·½·¨µÄÃèÊöÖУ¬ÊÂÎñµÄ´«²¥ÐÐΪÊÇÖ¸ÔÚͬһ¸ö·½·¨ÖУ¬²»Í¬²Ù×÷ǰºóËùʹÓõÄÊÂÎñ¡£´«²¥ÐÐΪµÄÖÖÀàÈç±í 1 Ëùʾ¡£
+
+±í 1 ´«²¥ÐÐΪµÄÖÖÀà
+| ÊôÐÔÃû³Æ | Öµ | Ãè Êö |
+| --- | --- | --- |
+| PROPAGATION_REQUIRED | required | Ö§³Öµ±Ç°ÊÂÎñ¡£Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò B ÊÂÎñ½«Ö±½ÓʹÓ᣷ñÔò½«´´½¨ÐÂÊÂÎñ |
+| PROPAGATION_SUPPORTS | supports | Ö§³Öµ±Ç°ÊÂÎñ¡£Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò B ÊÂÎñ½«Ö±½ÓʹÓ᣷ñÔò½«ÒÔ·ÇÊÂÎñ״ִ̬ÐÐ |
+| PROPAGATION_MANDATORY | mandatory | Ö§³Öµ±Ç°ÊÂÎñ¡£Èç¹û A ·½·¨Ã»ÓÐÊÂÎñ£¬ÔòÅ׳öÒì³£ |
+| PROPAGATION_REQUIRES_NEW | requires_new | ½«´´½¨ÐµÄÊÂÎñ£¬Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò½« A ÊÂÎñ¹ÒÆð |
+| PROPAGATION_NOT_SUPPORTED | not_supported | ²»Ö§³Öµ±Ç°ÊÂÎñ£¬×ÜÊÇÒÔ·ÇÊÂÎñ״ִ̬ÐС£Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò½«Æä¹ÒÆð |
+| PROPAGATION_NEVER | never | ²»Ö§³Öµ±Ç°ÊÂÎñ£¬Èç¹û A ·½·¨ÔÚÊÂÎñÖУ¬ÔòÅ׳öÒì³£ |
+| PROPAGATION.NESTED | nested | ǶÌ×ÊÂÎñ£¬µ×²ã½«Ê¹Óà Savepoint ÐγÉǶÌ×ÊÂÎñ |
+
+ÔÚÊÂÎñ¹ÜÀí¹ý³ÌÖУ¬´«²¥ÐÐΪ¿ÉÒÔ¿ØÖÆÊÇ·ñÐèÒª´´½¨ÊÂÎñÒÔ¼°ÈçºÎ´´½¨ÊÂÎñ¡£
+
+ͨ³£Çé¿öÏ£¬Êý¾ÝµÄ²éѯ²»»á¸Ä±äÔÊý¾Ý£¬ËùÒÔ²»ÐèÒª½øÐÐÊÂÎñ¹ÜÀí£¬¶ø¶ÔÓÚÊý¾ÝµÄÔö¼Ó¡¢Ð޸ĺÍɾ³ýµÈ²Ù×÷£¬±ØÐë½øÐÐÊÂÎñ¹ÜÀí¡£Èç¹ûûÓÐÖ¸¶¨ÊÂÎñµÄ´«²¥ÐÐΪ£¬Ôò Spring3 ĬÈϵĴ«²¥ÐÐΪÊÇ required¡£
+
+#### 3\. TransactionStatus
+
+TransactionStatus ½Ó¿ÚÊÇÊÂÎñµÄ״̬£¬ËüÃèÊöÁËijһʱ¼äµãÉÏÊÂÎñµÄ״̬ÐÅÏ¢¡£ÆäÖаüº¬Áù¸ö²Ù×÷£¬¾ßÌåÈç±í 2 Ëùʾ¡£
+
+±í 2 ÊÂÎñµÄ²Ù×÷
+| Ãû³Æ | ˵Ã÷ |
+| --- | --- |
+| void flush() | Ë¢ÐÂÊÂÎñ |
+| boolean hasSavepoint() | »ñÈ¡ÊÇ·ñ´æÔÚ±£´æµã |
+| boolean isCompleted() | »ñÈ¡ÊÂÎñÊÇ·ñÍê³É |
+| boolean isNewTransaction() | »ñÈ¡ÊÇ·ñÊÇÐÂÊÂÎñ |
+| boolean isRollbackOnly() | »ñÈ¡ÊÇ·ñ»Ø¹ö |
+| void setRollbackOnly() | ÉèÖÃÊÂÎñ»Ø¹ö |
+
+# SpringÉùÃ÷ʽÊÂÎñ¹ÜÀí£¨»ùÓÚXML·½Ê½ÊµÏÖ£©
+
+[Spring](http://www.voidme.com/spring) µÄÊÂÎñ¹ÜÀíÓÐÁ½ÖÖ·½Ê½£ºÒ»ÖÖÊÇ´«Í³µÄ±à³ÌʽÊÂÎñ¹ÜÀí£¬¼´Í¨¹ý±àд´úÂëʵÏÖµÄÊÂÎñ¹ÜÀí£»ÁíÒ»ÖÖÊÇ»ùÓÚ AOP ¼¼ÊõʵÏÖµÄÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£ÓÉÓÚÔÚʵ¼Ê¿ª·¢ÖУ¬±à³ÌʽÊÂÎñ¹ÜÀíºÜÉÙʹÓã¬ËùÒÔÎÒÃÇÖ»¶Ô Spring µÄÉùÃ÷ʽÊÂÎñ¹ÜÀí½øÐÐÏêϸ½²½â¡£
+
+Spring ÉùÃ÷ʽÊÂÎñ¹ÜÀíÔڵײã²ÉÓÃÁË AOP ¼¼Êõ£¬Æä×î´óµÄÓŵãÔÚÓÚÎÞÐëͨ¹ý±à³ÌµÄ·½Ê½¹ÜÀíÊÂÎñ£¬Ö»ÐèÒªÔÚÅäÖÃÎļþÖнøÐÐÏà¹ØµÄ¹æÔòÉùÃ÷£¬¾Í¿ÉÒÔ½«ÊÂÎñ¹æÔòÓ¦Óõ½ÒµÎñÂß¼ÖС£
+
+Spring ʵÏÖÉùÃ÷ʽÊÂÎñ¹ÜÀíÖ÷ÒªÓÐÁ½ÖÖ·½Ê½£º
+
+* »ùÓÚ XML ·½Ê½µÄÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£
+* ͨ¹ý Annotation ×¢½â·½Ê½µÄÊÂÎñ¹ÜÀí¡£
+
+±¾½Úͨ¹ýÒøÐÐתÕ˵ݸÀý½²½âÈçºÎʹÓà XML µÄ·½Ê½ÊµÏÖ Spring µÄÉùÃ÷ʽÊÂÎñ´¦Àí¡£
+
+#### 1\. ´´½¨ÏîÄ¿
+
+ÔÚ MyEclipse Öд´½¨Ò»¸öÃûΪ springDemo03 µÄ Web ÏîÄ¿£¬½« Spring Ö§³ÖºÍÒÀÀµµÄ JAR °ü¸´ÖƵ½ Web ÏîÄ¿µÄ lib Ŀ¼ÖУ¬²¢Ìí¼Óµ½Àà·¾¶Ï¡£ËùÌí¼ÓµÄ JAR °üÈçͼ 1 Ëùʾ¡£
+
+
+ͼ 1 ÐèÒªµ¼ÈëµÄJAR°ü
+
+´Óͼ 1 ÖпÉÒÔ¿´³ö£¬ÕâÀïÔö¼Óµ¼ÈëÁË spring-tx-3.2.13.RELEASE.jar£¨ÊÂÎñ¹ÜÀí£©£¬ÒÔ¼° [MySQL](http://www.voidme.com/mysql) Çý¶¯¡¢JDBC ºÍ C3P0 µÄ JAR °ü¡£
+
+#### 2\. ´´½¨Êý¾Ý¿â¡¢±íÒÔ¼°²åÈëÊý¾Ý
+
+ÔÚ MySQL Öд´½¨Ò»¸öÃûΪ spring µÄÊý¾Ý¿â£¬È»ºóÔÚ¸ÃÊý¾Ý¿âÖд´½¨Ò»¸ö account ±í£¬²¢Ïò±íÖвåÈëÁ½ÌõÊý¾Ý£¬Æä SQL Ö´ÐÐÓï¾äÈçÏÂËùʾ£º
+
+ CREATE DATABASE spring;
+USE spring;
+CREATE TABLE account (
+ id INT (11) PRIMARY KEY AUTO_INCREMENT,
+ username VARCHAR(20) NOT NULL,
+ money INT DEFAULT NULL
+);
+INSERT INTO account VALUES (1,'zhangsan',1000);
+INSERT INTO account VALUES (2,'lisi',1000);
+
+Ö´ÐкóµÄ account ±íÖеÄÊý¾ÝÈçͼ 2 Ëùʾ¡£
+
+
+ͼ 2 Ö´Ðнá¹û
+
+#### 3\. ´´½¨ c3p0-db.properties
+
+ÔÚÏîÄ¿µÄ src Ï´´½¨Ò»¸öÃûΪ c3p0-db.properties µÄÅäÖÃÎļþ£¬ÕâÀïʹÓà C3P0 Êý¾ÝÔ´£¬ÐèÒªÔÚ¸ÃÎļþÖÐÌí¼ÓÈçÏÂÅäÖãº
+
+jdbc.driverClass = com.mysql.jdbc.Driver
+jdbc.jdbcUrl = jdbc:mysql://localhost:3306/spring
+jdbc.user = root
+jdbc.password = root
+
+#### 4\. ʵÏÖ DAO
+
+#### 1£©´´½¨ AccountDao ½Ó¿Ú
+
+ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨Ò»¸öÃûΪ com.mengma.dao µÄ°ü£¬ÔڸðüÏ´´½¨Ò»¸ö½Ó¿Ú AccountDao£¬²¢ÔÚ½Ó¿ÚÖд´½¨»ã¿îºÍÊÕ¿îµÄ·½·¨£¬ÈçÏÂËùʾ¡£
+
+ package com.mengma.dao;
+
+public interface AccountDao {
+ // »ã¿î
+ public void out(String outUser, int money);
+
+ // ÊÕ¿î
+ public void in(String inUser, int money);
+}
+
+ÉÏÊö´úÂëÖУ¬¶¨ÒåÁË out() ºÍ in() Á½¸ö·½·¨£¬·Ö±ðÓÃÓÚ±íʾ»ã¿îºÍÊÕ¿î¡£
+
+#### 2£©´´½¨DAO²ã½Ó¿ÚʵÏÖÀà
+
+ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨Ò»¸öÃûΪ com.mengma.dao.impl µÄ°ü£¬ÔڸðüÏ´´½¨ÊµÏÖÀà AccountDaoImpl£¬ÈçÏÂËùʾ¡£
+
+ package com.mengma.dao.impl;
+
+import org.springframework.jdbc.core.JdbcTemplate;
+import com.mengma.dao.AccountDao;
+
+public class AccountDaoImpl implements AccountDao {
+ private JdbcTemplate jdbcTemplate;
+
+ public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ // »ã¿îµÄʵÏÖ·½·¨
+ public void out(String outUser, int money) {
+ this.jdbcTemplate.update("update account set money =money-?"
+ + "where username =?", money, outUser);
+ }
+
+ // ÊÕ¿îµÄʵÏÖ·½·¨
+ public void in(String inUser, int money) {
+ this.jdbcTemplate.update("update account set money =money+?"
+ + "where username =?", money, inUser);
+ }
+}
+
+ÉÏÊö´úÂëÖУ¬Ê¹Óà JdbcTemplate ÀàµÄ update() ·½·¨ÊµÏÖÁ˸üвÙ×÷¡£
+
+#### 5\. ʵÏÖ Service
+
+#### 1£©´´½¨ Service ²ã½Ó¿Ú
+
+ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨Ò»¸öÃûΪ com.mengma.service µÄ°ü£¬ÔڸðüÏ´´½¨½Ó¿Ú AccountService£¬ÈçÏÂËùʾ¡£
+
+ package com.mengma.service;
+
+public interface AccountService {
+ // תÕË
+ public void transfer(String outUser, String inUser, int money);
+}
+
+#### 2£©´´½¨ Service ²ã½Ó¿ÚʵÏÖÀà
+
+ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨Ò»¸öÃûΪ com.mengma.service.impl µÄ°ü£¬ÔڸðüÏ´´½¨ÊµÏÖÀà AccountServiceImpl£¬ÈçÏÂËùʾ¡£
+
+ package com.mengma.service.impl;
+
+import com.mengma.dao.AccountDao;
+
+public class AccountServiceImpl {
+ private AccountDao accountDao;
+
+ public void setAccountDao(AccountDao accountDao) {
+ this.accountDao = accountDao;
+ }
+
+ public void transfer(String outUser, String inUser, int money) {
+ this.accountDao.out(outUser, money);
+ this.accountDao.in(inUser, money);
+ }
+}
+
+ÉÏÊö´úÂëÖпÉÒÔ¿´³ö£¬¸ÃÀàʵÏÖÁË AccountService ½Ó¿Ú£¬²¢¶ÔתÕ˵ķ½·¨½øÐÐÁËʵÏÖ£¬¸ù¾Ý²ÎÊýµÄ²»Í¬µ÷Óà DAO ²ãÏàÓ¦µÄ·½·¨¡£
+
+#### 6\. ´´½¨ Spring ÅäÖÃÎļþ
+
+ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨ Spirng ÅäÖÃÎļþ applicationContext.xml£¬±à¼ºóÈçÏÂËùʾ¡£
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ÉÏÊö´úÂëÖУ¬Ê×ÏÈÔÚ ±ê¼ÇµÄµÚ 6¡¢13 ºÍ 14 ÐдúÂë·Ö±ðÌí¼ÓÁË AOP ËùÐèµÄÃüÃû¿Õ¼äÉùÃ÷¡£µÚ 42¡«50 ÐдúÂëʹÓà ±ê¼ÇÅäÖÃÊÂÎñ֪ͨÄÚÈÝ¡£
+
+µÚ 52¡«58 ÐдúÂëʹÓà ±ê¼Ç¶¨ÒåÇÐÃæ£¬ÆäÖÐµÚ 54 ÐдúÂëÓ¦ÓÃÁË AspectJ ±í´ïʽ£¬´ú±í com.mengma.service °üÏÂËùÓÐÀàµÄËùÓз½·¨¶¼Ó¦ÓÃÊÂÎñ¹æÔò£¬µÚ 57 ÐдúÂëʹÓà ±ê¼Ç½«ÇÐÈëµãÓëÊÂÎñ֪ͨÕûºÏ£¬»ùÓÚ AOP µÄÉùÃ÷ʽÊÂÎñÅäÖÃÍê³É¡£
+
+#### 7\. ´´½¨²âÊÔÀà
+
+ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨ com.mengma.test µÄ°ü£¬ÔڸðüÏ´´½¨²âÊÔÀà AccountTest£¬ÈçÏÂËùʾ¡£
+
+ package com.mengma.test;
+import org.junit.Test;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import com.mengma.service.AccountService;
+public class AccountTest {
+ @Test
+ public void test() {
+ // »ñµÃSpringÈÝÆ÷£¬²¢²Ù×÷
+ String xmlPath = "applicationContext.xml";
+ ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
+ xmlPath);
+ AccountService accountService = (AccountService) applicationContext
+ .getBean("accountService");
+ accountService.transfer("zhangsan", "lisi", 100);
+ }
+}
+
+ÉÏÊö´úÂëÖÐÄ£ÄâÁËÒøÐÐתÕËÒµÎñ£¬´Ó zhangsan µÄÕË»§Ïò lisi µÄÕË»§ÖÐתÈë 100 Ôª¡£Ê¹Óà JUnit ²âÊÔÔËÐÐ test() ·½·¨£¬ÔËÐгɹ¦ºó£¬²éѯ account ±í£¬Èçͼ 3 Ëùʾ¡£
+
+´Óͼ 3 µÄ²éѯ½á¹ûÖпÉÒÔ¿´³ö£¬zhangsan ³É¹¦Ïò lisi תÕË 100 Ôª¡£
+
+
+ͼ 3 ²éѯ½á¹û
+
+ÏÂÃæÍ¨¹ýÐ޸ݸÀýÄ£ÄâתÕËʧ°ÜµÄÇé¿ö£¬ÔÚµÄ transfer() ·½·¨ÖÐÌí¼ÓÒ»ÐдúÂë¡°int i=1/0£»¡±Ä£Äâϵͳ¶ÏµçµÄÇé¿ö£¬¾ßÌå´úÂëÈçÏÂËùʾ£º
+
+ public void transfer(String outUser, String inUser, int money) {
+ this.accountDao.out(outUser, money);
+ //Ä£Äâ¶Ïµç
+ int i = 1/0;
+ this.accountDao.in(inUser, money);
+}
+
+ÖØÐ²âÊÔÔËÐÐ test() ·½·¨£¬JUnit ¿ØÖÆÌ¨Êä³öµÄÐÅÏ¢Èçͼ 4 Ëùʾ¡£
+
+
+ͼ 4 ¿ØÖÆÌ¨Êä³ö½á¹û
+
+´Óͼ 4 ÖпÉÒÔ¿´³ö£¬ÔÚÖ´ÐвâÊÔ·½·¨Ê±£¬³öÏÖÁ˳ýÒÔ 0 µÄÒì³£ÐÅÏ¢¡£´ËʱÔٴβéѯ account ±í£¬Æä²éѯ½á¹ûÈçͼ 5 Ëùʾ¡£
+
+´Óͼ 5 µÄ²éѯ½á¹ûÖпÉÒÔ¿´³ö£¬±íÖеÄÊý¾Ý²¢Ã»Óз¢Éú±ä»¯¡£ÓÉÓÚ³ÌÐòÔÚÖ´Ðйý³ÌÖÐÅ׳öÁËÒì³££¬ÊÂÎñ²»ÄÜÕý³£±»Ìá½»£¬ËùÒÔתÕËʧ°Ü¡£ÓÉ´Ë¿ÉÖª£¬Spring µÄÊÂÎñ¹ÜÀíÉúЧÁË¡£
+
+
+ͼ 5 ²éѯ½á¹û
+
+# SpringÉùÃ÷ʽÊÂÎñ¹ÜÀí£¨»ùÓÚAnnotation×¢½â·½Ê½ÊµÏÖ£©
+
+ÔÚ [Spring](http://www.voidme.com/spring) ÖУ¬³ýÁËʹÓûùÓÚ XML µÄ·½Ê½¿ÉÒÔʵÏÖÉùÃ÷ʽÊÂÎñ¹ÜÀíÒÔÍ⣬»¹¿ÉÒÔͨ¹ý Annotation ×¢½âµÄ·½Ê½ÊµÏÖÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£
+
+ʹÓà Annotation µÄ·½Ê½·Ç³£¼òµ¥£¬Ö»ÐèÒªÔÚÏîÄ¿ÖÐ×öÁ½¼þÊ£¬¾ßÌåÈçÏ¡£
+
+#### 1£©ÔÚ Spring ÈÝÆ÷ÖÐ×¢²áÇý¶¯£¬´úÂëÈçÏÂËùʾ£º
+
+
+
+#### 2£©ÔÚÐèҪʹÓÃÊÂÎñµÄÒµÎñÀà»òÕß·½·¨ÖÐÌí¼Ó×¢½â @Transactional£¬²¢ÅäÖà @Transactional µÄ²ÎÊý¡£¹ØÓÚ @Transactional µÄ²ÎÊýÈçͼ 1 Ëùʾ¡£
+
+
+ͼ 1 @Transactional²ÎÊýÁбí
+
+ÏÂÃæÍ¨¹ýÐ޸ġ¶ [Spring»ùÓÚXMLʵÏÖÊÂÎñ¹ÜÀí](http://www.voidme.com/spring/spring-transaction-management-by-xml)¡·½Ì³ÌÖÐÒøÐÐתÕ˵ݸÀý½²½âÈçºÎʹÓà Annotation ×¢½âµÄ·½Ê½ÊµÏÖ Spring ÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£
+
+#### 1\. ×¢²áÇý¶¯
+
+ÐÞ¸Ä Spring ÅäÖÃÎļþ applicationContext.xml£¬Ð޸ĺóÈçÏÂËùʾ¡£
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ÉÏÊö´úÂëÖпÉÒÔ¿´³ö£¬ÓëÔÀ´µÄÅäÖÃÎļþÏà±È£¬ÕâÀïÖ»ÐÞ¸ÄÁËÊÂÎñ¹ÜÀíÆ÷²¿·Ö£¬ÐÂÌí¼Ó²¢×¢²áÁËÊÂÎñ¹ÜÀíÆ÷µÄÇý¶¯¡£
+
+ÐèҪעÒâµÄÊÇ£¬ÔÚѧϰ AOP ×¢½â·½Ê½¿ª·¢Ê±£¬ÐèÒªÔÚÅäÖÃÎļþÖпªÆô×¢½â´¦ÀíÆ÷£¬Ö¸¶¨É¨ÃèÄÄЩ°üϵÄ×¢½â£¬ÕâÀïûÓпªÆô×¢½â´¦ÀíÆ÷ÊÇÒòΪÔÚµÚ 33¡«35 ÐÐÊÖ¶¯ÅäÖÃÁË AccountServiceImpl£¬¶ø @Transactional ×¢½â¾ÍÅäÖÃÔÚ¸ÃÀàÖУ¬ËùÒÔ»áÖ±½ÓÉúЧ¡£
+
+#### 2\. Ìí¼Ó @Transactional ×¢½â
+
+ÐÞ¸Ä AccountServiceImpl£¬ÔÚÎļþÖÐÌí¼Ó @Transactional ×¢½â¼°²ÎÊý£¬Ìí¼ÓºóÈçÏÂËùʾ¡£
+
+ package com.mengma.service.impl;
+
+import org.springframework.transaction.annotation.Isolation;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.mengma.dao.AccountDao;
+
+@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
+public class AccountServiceImpl {
+ private AccountDao accountDao;
+
+ public void setAccountDao(AccountDao accountDao) {
+ this.accountDao = accountDao;
+ }
+
+ public void transfer(String outUser, String inUser, int money) {
+ this.accountDao.out(outUser, money);
+ // Ä£Äâ¶Ïµç
+ int i = 1 / 0;
+ this.accountDao.in(inUser, money);
+ }
+}
+
+ÐèҪעÒâµÄÊÇ£¬ÔÚʹÓà @Transactional ×¢½âʱ£¬²ÎÊýÖ®¼äÓá°£¬¡±½øÐзָô¡£
+
+ʹÓà JUnit ²âÊÔÔÙ´ÎÔËÐÐ test() ·½·¨Ê±£¬¿ØÖÆÌ¨Í¬Ñù»áÊä³öÈçͼ 2 ËùʾµÄÒì³£ÐÅÏ¢£¬Õâ˵Ã÷ʹÓûùÓÚ Annotation ×¢½âµÄ·½Ê½Í¬ÑùʵÏÖÁË Spring µÄÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£Èç¹û×¢Ê͵ôÄ£Äâ¶ÏµçµÄ´úÂë½øÐвâÊÔ£¬ÔòתÕ˲Ù×÷¿ÉÒÔÕý³£Íê³É¡£
+
+
+ͼ 2 ÔËÐнá¹û
+
+# ²Î¿¼ÎÄÕÂ
+https://www.w3cschool.cn/wkspring
+https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
+http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
+https://dunwu.github.io/spring-tutorial
+https://mszlu.com/java/spring
+http://c.biancheng.net/spring/aop-module.html
\ No newline at end of file
diff --git "a/docs/spring/Spring\345\220\210\351\233\206.md" "b/docs/spring/Spring\345\220\210\351\233\206.md"
new file mode 100644
index 0000000..931264e
--- /dev/null
+++ "b/docs/spring/Spring\345\220\210\351\233\206.md"
@@ -0,0 +1,22 @@
+# Spring
+
+
+# SpringÔ´Âë·ÖÎö
+
+# SpringMVC
+
+# SpringMVC Ô´Âë·ÖÎö
+
+# SpringBoot
+## springbootµÄǰÊÀ½ñÉú
+## springbootµÄ»ù±¾Ê¹ÓÃ
+## springbootµÄ³£¼û×¢½â
+## springbootµÄºËÐÄ×é¼þ
+## springbootµÄ»ù±¾ÔÀí
+## springbootÔ´Âë½âÎö
+
+# SpringBoot Ô´Âë·ÖÎö
+
+# SpringCloud
+# SpringCloud Ô´Âë·ÖÎö
+
diff --git "a/docs/spring/Spring\345\256\271\345\231\250\344\270\216IOC.md" "b/docs/spring/Spring\345\256\271\345\231\250\344\270\216IOC.md"
new file mode 100644
index 0000000..35623db
--- /dev/null
+++ "b/docs/spring/Spring\345\256\271\345\231\250\344\270\216IOC.md"
@@ -0,0 +1,157 @@
+IoC ÊÇ Inversion of Control µÄ¼òд£¬ÒëΪ¡°¿ØÖÆ·´×ª¡±£¬Ëü²»ÊÇÒ»Ãż¼Êõ£¬¶øÊÇÒ»ÖÖÉè¼ÆË¼Ï룬ÊÇÒ»¸öÖØÒªµÄÃæÏò¶ÔÏó±à³Ì·¨Ôò£¬Äܹ»Ö¸µ¼ÎÒÃÇÈçºÎÉè¼Æ³öËÉñîºÏ¡¢¸üÓÅÁ¼µÄ³ÌÐò¡£
+
+Spring ͨ¹ý IoC ÈÝÆ÷À´¹ÜÀíËùÓÐ Java ¶ÔÏóµÄʵÀý»¯ºÍ³õʼ»¯£¬¿ØÖƶÔÏóÓë¶ÔÏóÖ®¼äµÄÒÀÀµ¹ØÏµ¡£ÎÒÃǽ«ÓÉ IoC ÈÝÆ÷¹ÜÀíµÄ Java ¶ÔÏó³ÆÎª Spring Bean£¬ËüÓëʹÓùؼü×Ö new ´´½¨µÄ Java ¶ÔÏóûÓÐÈκÎÇø±ð¡£
+
+IoC ÈÝÆ÷ÊÇ Spring ¿ò¼ÜÖÐ×îÖØÒªµÄºËÐÄ×é¼þÖ®Ò»£¬Ëü¹á´©ÁË Spring ´Óµ®Éúµ½³É³¤µÄÕû¸ö¹ý³Ì¡£
+
+## ¿ØÖÆ·´×ª£¨IoC£©
+
+ÔÚ´«Í³µÄ Java Ó¦ÓÃÖУ¬Ò»¸öÀàÏëÒªµ÷ÓÃÁíÒ»¸öÀàÖеÄÊôÐÔ»ò·½·¨£¬Í¨³£»áÏÈÔÚÆä´úÂëÖÐͨ¹ý new Object() µÄ·½Ê½½«ºóÕߵĶÔÏó´´½¨³öÀ´£¬È»ºó²ÅÄÜʵÏÖÊôÐÔ»ò·½·¨µÄµ÷Óá£ÎªÁË·½±ãÀí½âºÍÃèÊö£¬ÎÒÃÇ¿ÉÒÔ½«Ç°Õß³ÆÎª¡°µ÷ÓÃÕß¡±£¬½«ºóÕß³ÆÎª¡°±»µ÷ÓÃÕß¡±¡£Ò²¾ÍÊÇ˵£¬µ÷ÓÃÕßÕÆÎÕ×ű»µ÷ÓÃÕß¶ÔÏó´´½¨µÄ¿ØÖÆÈ¨¡£
+
+µ«ÔÚ Spring Ó¦ÓÃÖУ¬Java ¶ÔÏó´´½¨µÄ¿ØÖÆÈ¨ÊÇÕÆÎÕÔÚ IoC ÈÝÆ÷ÊÖÀïµÄ£¬Æä´óÖ²½ÖèÈçÏ¡£
+
+¿ª·¢ÈËԱͨ¹ý XML ÅäÖÃÎļþ¡¢×¢½â¡¢Java ÅäÖÃÀàµÈ·½Ê½£¬¶Ô Java ¶ÔÏó½øÐж¨Ò壬ÀýÈçÔÚ XML ÅäÖÃÎļþÖÐʹÓà ±êÇ©¡¢ÔÚ Java ÀàÉÏʹÓà @Component ×¢½âµÈ¡£
+Spring Æô¶¯Ê±£¬IoC ÈÝÆ÷»á×Ô¶¯¸ù¾Ý¶ÔÏó¶¨Ò壬½«ÕâЩ¶ÔÏó´´½¨²¢¹ÜÀíÆðÀ´¡£ÕâЩ±» IoC ÈÝÆ÷´´½¨²¢¹ÜÀíµÄ¶ÔÏó±»³ÆÎª Spring Bean¡£
+µ±ÎÒÃÇÏëҪʹÓÃij¸ö Bean ʱ£¬¿ÉÒÔÖ±½Ó´Ó IoC ÈÝÆ÷ÖлñÈ¡£¨ÀýÈçͨ¹ý ApplicationContext µÄ getBean() ·½·¨£©£¬¶ø²»ÐèÒªÊÖ¶¯Í¨¹ý´úÂ루ÀýÈç new Obejct() µÄ·½Ê½£©´´½¨¡£
+
+IoC ´øÀ´µÄ×î´ó¸Ä±ä²»ÊÇ´úÂë²ãÃæµÄ£¬¶øÊÇ´Ó˼Ïë²ãÃæÉÏ·¢ÉúÁË¡°Ö÷´Ó»»Î»¡±µÄ¸Ä±ä¡£Ô±¾µ÷ÓÃÕßÊÇÖ÷¶¯µÄÒ»·½£¬ËüÏëҪʹÓÃʲô×ÊÔ´¾Í»áÖ÷¶¯³ö»÷£¬×Ô¼º´´½¨£»µ«ÔÚ Spring Ó¦ÓÃÖУ¬IoC ÈÝÆ÷ÕÆÎÕ×ÅÖ÷¶¯È¨£¬µ÷ÓÃÕßÔò±ä³ÉÁ˱»¶¯µÄÒ»·½£¬±»¶¯µÄµÈ´ý IoC ÈÝÆ÷´´½¨ËüËùÐèÒªµÄ¶ÔÏó£¨Bean£©¡£
+
+Õâ¸ö¹ý³ÌÔÚÖ°Ôð²ãÃæ·¢ÉúÁË¿ØÖÆÈ¨µÄ·´×ª£¬°ÑÔ±¾µ÷ÓÃÕßͨ¹ý´úÂëʵÏֵĶÔÏóµÄ´´½¨£¬·´×ª¸ø IoC ÈÝÆ÷À´°ïæʵÏÖ£¬Òò´ËÎÒÃǽ«Õâ¸ö¹ý³Ì³ÆÎª Spring µÄ¡°¿ØÖÆ·´×ª¡±¡£
+
+## ÒÀÀµ×¢È루DI£©
+
+ÔÚÁ˽âÁË IoC Ö®ºó£¬ÎÒÃÇ»¹ÐèÒªÁ˽âÁíÍâÒ»¸ö·Ç³£ÖØÒªµÄ¸ÅÄÒÀÀµ×¢Èë¡£
+
+ÒÀÀµ×¢È루Denpendency Injection£¬¼òдΪ DI£©ÊÇ Martin Fowler ÔÚ 2004 ÄêÔÚ¶Ô¡°¿ØÖÆ·´×ª¡±½øÐнâÊÍʱÌá³öµÄ¡£Martin Fowler ÈÏΪ¡°¿ØÖÆ·´×ª¡±Ò»´ÊºÜ»Þɬ£¬ÎÞ·¨ÈÃÈ˺ÜÖ±½ÓµÄÀí½â¡°µ½µ×ÊÇÄÄÀﷴתÁË¡±£¬Òò´ËËû½¨ÒéʹÓá°ÒÀÀµ×¢È롱À´´úÌæ¡°¿ØÖÆ·´×ª¡±¡£
+
+ÔÚÃæÏò¶ÔÏóÖУ¬¶ÔÏóºÍ¶ÔÏóÖ®¼äÊÇ´æÔÚÒ»ÖÖ½Ð×ö¡°ÒÀÀµ¡±µÄ¹ØÏµ¡£¼òµ¥À´Ëµ£¬ÒÀÀµ¹ØÏµ¾ÍÊÇÔÚÒ»¸ö¶ÔÏóÖÐÐèÒªÓõ½ÁíÍâÒ»¸ö¶ÔÏ󣬼´¶ÔÏóÖдæÔÚÒ»¸öÊôÐÔ£¬¸ÃÊôÐÔÊÇÁíÍâÒ»¸öÀàµÄ¶ÔÏó¡£
+
+ÀýÈ磬ÓÐÒ»¸öÃûΪ B µÄ Java À࣬ËüµÄ´úÂëÈçÏ¡£
+
+
+
+
+
+
+
+public class B {
+String bid;
+A a;
+}
+
+
+
+
+
+
+
+´Ó´úÂë¿ÉÒÔ¿´³ö£¬B ÖдæÔÚÒ»¸ö A ÀàÐ͵ĶÔÏóÊôÐÔ a£¬´ËʱÎÒÃǾͿÉÒÔ˵ B µÄ¶ÔÏóÒÀÀµÓÚ¶ÔÏó a¡£¶øÒÀÀµ×¢Èë¾ÍÊǾÍÊÇ»ùÓÚÕâÖÖ¡°ÒÀÀµ¹ØÏµ¡±¶ø²úÉúµÄ¡£
+
+ÎÒÃÇÖªµÀ£¬¿ØÖÆ·´×ªºËÐÄ˼Ïë¾ÍÊÇÓÉ Spring ¸ºÔð¶ÔÏóµÄ´´½¨¡£ÔÚ¶ÔÏó´´½¨¹ý³ÌÖУ¬Spring »á×Ô¶¯¸ù¾ÝÒÀÀµ¹ØÏµ£¬½«ËüÒÀÀµµÄ¶ÔÏó×¢Èëµ½µ±Ç°¶ÔÏóÖУ¬Õâ¾ÍÊÇËùνµÄ¡°ÒÀÀµ×¢È롱¡£
+
+ÒÀÀµ×¢Èë±¾ÖÊÉÏÊÇ [Spring Bean ÊôÐÔ×¢Èë](http://c.biancheng.net/spring/attr-injection.html)µÄÒ»ÖÖ£¬Ö»²»¹ýÕâ¸öÊôÐÔÊÇÒ»¸ö¶ÔÏóÊôÐÔ¶øÒÑ¡£
+
+## IoC µÄ¹¤×÷ÔÀí
+
+ÔÚ Java Èí¼þ¿ª·¢¹ý³ÌÖУ¬ÏµÍ³Öеĸ÷¸ö¶ÔÏóÖ®¼ä¡¢¸÷¸öÄ£¿éÖ®¼ä¡¢Èí¼þϵͳºÍÓ²¼þϵͳ֮¼ä£¬»ò¶à»òÉÙ¶¼´æÔÚÒ»¶¨µÄñîºÏ¹ØÏµ¡£
+
+ÈôÒ»¸öϵͳµÄñîºÏ¶È¹ý¸ß£¬ÄÇô¾Í»áÔì³ÉÄÑÒÔά»¤µÄÎÊÌ⣬µ«ÍêȫûÓÐñîºÏµÄ´úÂ뼸ºõÎÞ·¨Íê³ÉÈκι¤×÷£¬ÕâÊÇÓÉÓÚ¼¸ºõËùÓеŦÄܶ¼ÐèÒª´úÂëÖ®¼äÏ໥Ð×÷¡¢Ï໥ÒÀÀµ²ÅÄÜÍê³É¡£Òò´ËÎÒÃÇÔÚ³ÌÐòÉè¼ÆÊ±£¬Ëù±ü³ÐµÄ˼ÏëÒ»°ã¶¼ÊÇÔÚ²»Ó°Ïìϵͳ¹¦ÄܵÄǰÌáÏ£¬×î´óÏ޶ȵĽµµÍñîºÏ¶È¡£
+
+IoC µ×²ãͨ¹ý¹¤³§Ä£Ê½¡¢Java µÄ·´Éä»úÖÆ¡¢XML ½âÎöµÈ¼¼Êõ£¬½«´úÂëµÄñîºÏ¶È½µµÍµ½×îµÍÏÞ¶È£¬ÆäÖ÷Òª²½ÖèÈçÏ¡£
+
+ÔÚÅäÖÃÎļþ£¨ÀýÈç Bean.xml£©ÖУ¬¶Ô¸÷¸ö¶ÔÏóÒÔ¼°ËüÃÇÖ®¼äµÄÒÀÀµ¹ØÏµ½øÐÐÅäÖã»
+ÎÒÃÇ¿ÉÒÔ°Ñ IoC ÈÝÆ÷µ±×öÒ»¸ö¹¤³§£¬Õâ¸ö¹¤³§µÄ²úÆ·¾ÍÊÇ Spring Bean£»
+ÈÝÆ÷Æô¶¯Ê±»á¼ÓÔØ²¢½âÎöÕâЩÅäÖÃÎļþ£¬µÃµ½¶ÔÏóµÄ»ù±¾ÐÅÏ¢ÒÔ¼°ËüÃÇÖ®¼äµÄÒÀÀµ¹ØÏµ£»
+IoC ÀûÓà Java µÄ·´Éä»úÖÆ£¬¸ù¾ÝÀàÃûÉú³ÉÏàÓ¦µÄ¶ÔÏ󣨼´ Spring Bean£©£¬²¢¸ù¾ÝÒÀÀµ¹ØÏµ½«Õâ¸ö¶ÔÏó×¢Èëµ½ÒÀÀµËüµÄ¶ÔÏóÖС£
+
+ÓÉÓÚ¶ÔÏóµÄ»ù±¾ÐÅÏ¢¡¢¶ÔÏóÖ®¼äµÄÒÀÀµ¹ØÏµ¶¼ÊÇÔÚÅäÖÃÎļþÖж¨ÒåµÄ£¬²¢Ã»ÓÐÔÚ´úÂëÖнôÃÜñîºÏ£¬Òò´Ë¼´Ê¹¶ÔÏó·¢Éú¸Ä±ä£¬ÎÒÃÇÒ²Ö»ÐèÒªÔÚÅäÖÃÎļþÖнøÐÐÐ޸ļ´¿É£¬¶øÎÞÐë¶Ô Java ´úÂë½øÐÐÐ޸ģ¬Õâ¾ÍÊÇ Spring IoC ʵÏÖ½âñîµÄÔÀí¡£
+
+## IoC ÈÝÆ÷µÄÁ½ÖÖʵÏÖ
+
+IoC ˼Ïë»ùÓÚ IoC ÈÝÆ÷ʵÏֵģ¬IoC ÈÝÆ÷µ×²ãÆäʵ¾ÍÊÇÒ»¸ö Bean ¹¤³§¡£Spring ¿ò¼ÜΪÎÒÃÇÌṩÁËÁ½ÖÖ²»Í¬ÀàÐÍ IoC ÈÝÆ÷£¬ËüÃÇ·Ö±ðÊÇ BeanFactory ºÍ ApplicationContext¡£
+
+### BeanFactory
+
+BeanFactory ÊÇ IoC ÈÝÆ÷µÄ»ù±¾ÊµÏÖ£¬Ò²ÊÇ Spring ÌṩµÄ×î¼òµ¥µÄ IoC ÈÝÆ÷£¬ËüÌṩÁË IoC ÈÝÆ÷×î»ù±¾µÄ¹¦ÄÜ£¬ÓÉ org.springframework.beans.factory.BeanFactory ½Ó¿Ú¶¨Òå¡£
+
+BeanFactory ²ÉÓÃÀÁ¼ÓÔØ£¨lazy-load£©»úÖÆ£¬ÈÝÆ÷ÔÚ¼ÓÔØÅäÖÃÎļþʱ²¢²»»áÁ¢¿Ì´´½¨ Java ¶ÔÏó£¬Ö»ÓгÌÐòÖлñÈ¡£¨Ê¹Óã©Õâ¸ö¶Ô¶ÔÏóʱ²Å»á´´½¨¡£
+
+#### ʾÀý 1
+
+ÏÂÃæÎÒÃÇͨ¹ýÒ»¸öʵÀýÑÝʾ£¬À´ÑÝʾÏ BeanFactory µÄʹÓá£
+
+1\. ÔÚ HelloSpring ÏîÄ¿ÖУ¬½« MainApp µÄ´úÂëÐÞ¸ÄΪʹÓà BeanFactory »ñÈ¡ HelloWorld µÄ¶ÔÏ󣬾ßÌå´úÂëÈçÏ¡£
+
+
+
+
+
+
+
+public static void main(String[] args) {
+BeanFactory context = new ClassPathXmlApplicationContext("Beans.xml");
+HelloWorld obj = context.getBean("helloWorld", HelloWorld.class);
+obj.getMessage();
+}
+
+
+
+
+
+
+
+2. ÔËÐÐ MainApp.java£¬¿ØÖÆÌ¨Êä³öÈçÏ¡£
+
+ message : Hello World!
+
+> ×¢Ò⣺BeanFactory ÊÇ Spring ÄÚ²¿Ê¹Óýӿڣ¬Í¨³£Çé¿öϲ»Ìṩ¸ø¿ª·¢ÈËԱʹÓá£
+
+### ApplicationContext
+
+ApplicationContext ÊÇ BeanFactory ½Ó¿ÚµÄ×Ó½Ó¿Ú£¬ÊÇ¶Ô BeanFactory µÄÀ©Õ¹¡£ApplicationContext ÔÚ BeanFactory µÄ»ù´¡ÉÏÔö¼ÓÁËÐí¶àÆóÒµ¼¶µÄ¹¦ÄÜ£¬ÀýÈç AOP£¨ÃæÏòÇÐÃæ±à³Ì£©¡¢¹ú¼Ê»¯¡¢ÊÂÎñÖ§³ÖµÈ¡£
+
+ApplicationContext ½Ó¿ÚÓÐÁ½¸ö³£ÓõÄʵÏÖÀ࣬¾ßÌåÈçÏÂ±í¡£
+
+| ʵÏÖÀà | ÃèÊö | ʾÀý´úÂë |
+| --- | --- | --- |
+| ClassPathXmlApplicationContext | ¼ÓÔØÀà·¾¶ ClassPath ÏÂÖ¸¶¨µÄ XML ÅäÖÃÎļþ£¬²¢Íê³É ApplicationContext µÄʵÀý»¯¹¤×÷ | ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation); |
+| FileSystemXmlApplicationContext | ¼ÓÔØÖ¸¶¨µÄÎļþϵͳ·¾¶ÖÐÖ¸¶¨µÄ XML ÅäÖÃÎļþ£¬²¢Íê³É ApplicationContext µÄʵÀý»¯¹¤×÷ | ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation); |
+
+> ÔÚÉϱíµÄʾÀý´úÂëÖУ¬²ÎÊý configLocation ÓÃÓÚÖ¸¶¨ Spring ÅäÖÃÎļþµÄÃû³ÆºÍλÖã¬Èç Beans.xml¡£
+
+#### ʾÀý 2
+
+ÏÂÃæÎÒÃǾÍͨ¹ýÒ»¸öʵÀý£¬À´ÑÝʾ ApplicationContext µÄʹÓá£
+
+1. ÐÞ¸Ä HelloSpring ÏîÄ¿ MainApp ÀàÖÐ main() ·½·¨µÄ´úÂ룬¾ßÌå´úÂëÈçÏ¡£
+
+
+
+
+
+
+````
+public static void main(String[] args) {
+//ʹÓà FileSystemXmlApplicationContext ¼ÓÔØÖ¸¶¨Â·¾¶ÏµÄÅäÖÃÎļþ Bean.xml
+BeanFactory context = new FileSystemXmlApplicationContext("D:\\eclipe workspace\\spring workspace\\HelloSpring\\src\\Beans.xml");
+HelloWorld obj = context.getBean("helloWorld", HelloWorld.class);
+obj.getMessage();
+}
+````
+
+
+
+
+
+
+2. ÔËÐÐ MainApp.java£¬¿ØÖÆÌ¨Êä³öÈçÏ¡£
+
+ message : Hello World!
+
+# ²Î¿¼ÎÄÕÂ
+https://www.w3cschool.cn/wkspring
+https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
+http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
+https://dunwu.github.io/spring-tutorial
+https://mszlu.com/java/spring
+http://c.biancheng.net/spring/aop-module.html
\ No newline at end of file
diff --git "a/docs/spring/Spring\345\270\270\350\247\201\346\263\250\350\247\243.md" "b/docs/spring/Spring\345\270\270\350\247\201\346\263\250\350\247\243.md"
new file mode 100644
index 0000000..c5b2238
--- /dev/null
+++ "b/docs/spring/Spring\345\270\270\350\247\201\346\263\250\350\247\243.md"
@@ -0,0 +1,724 @@
+# Spring×¢½â
+## 1 ¸ÅÊö
+
+ÎÒÃǶ¼ÖªµÀSpring×îºËÐĵÄÌØÐÔ¾ÍÊÇIOC+AOP£¬IOCµÄÔÀí¾ÍÊÇʵÏÖÁËÒ»¸öSpringÈÝÆ÷£¬ÓÃÀ´¹ÜÀíËùÓÐSpring BeanʵÀý
+DI£¬Ò²¾ÍÊÇÒÀÀµ×¢È룬ÊÇÎÒÃÇ×÷Ϊ¿ª·¢ÕßÐèÒª¹ØÐĵĺËÐÄ»°Ì⣬ÈçºÎ×¢ÈëÒÀÀµ£¬×¢ÈëÄĸöÒÀÀµ£¬ÊÇÎÒÃÇÐèÒªÃ÷È·ÖªµÀµÄ¡£
+ÔÚÒÔǰ£¬ÎÒÃÇϰ¹ßÓÚÓÃxmlÅäÖÃÎļþÀ´ÉùÃ÷Ò»¸öbean£¬µ«ÏÖÔÚ£¬ÎÒÃǸü¶àµØÊ¹ÓÃ×¢½âºÍ´úÂëÀ´Íê³ÉDIµÄ¹ý³Ì
+
+
+ÎÒÃÇ¿ÉÒÔʹÓà org.springframework.beans.factory.annotation ºÍ org.springframework.context.annotation °üÖеÄ×¢ÊÍÀ´ÆôÓà Spring DI ÒýÇæµÄ¹¦ÄÜ¡£
+
+ÎÒÃÇͨ³£½«ÕâЩ³ÆÎª¡°Spring ºËÐÄ×¢ÊÍ¡±£¬ÎÒÃǽ«ÔÚ±¾½Ì³ÌÖÐ¶ÔÆä½øÐлعˡ£
+
+
+## 2 DIÏà¹Ø×¢½â
+
+### 2.1 @Autowired
+
+ÎÒÃÇ¿ÉÒÔʹÓà @Autowired À´±ê¼Ç Spring ½«Òª½âÎöºÍ×¢ÈëµÄÒÀÀµÏî¡£
+ÎÒÃÇ¿ÉÒÔ½«´Ë×¢ÊÍÓë¹¹Ô캯Êý¡¢setter »ò×Ö¶Î×¢ÈëÒ»ÆðʹÓá£
+Constructor injection:
+
+**¹¹ÔìÆ÷×¢Èë**
+
+````
+class Car {
+ Engine engine;
+
+ @Autowired
+ Car(Engine engine) {
+ this.engine = engine;
+ }
+}
+````
+
+**Setter×¢Èë**
+````
+class Car {
+ Engine engine;
+
+ @Autowired
+ void setEngine(Engine engine) {
+ this.engine = engine;
+ }
+}
+````
+**±äÁ¿×¢Èë**
+````
+class Car {
+ @Autowired
+ Engine engine;
+}
+````
+
+@Autowired ÓÐÒ»¸öÃûΪ required µÄ²¼¶û²ÎÊý£¬Ä¬ÈÏֵΪ true¡£
+
+µ±ËüÕÒ²»µ½ºÏÊ浀 bean À´Á¬½Óʱ£¬Ëü»áµ÷Õû Spring µÄÐÐΪ¡£ µ±Îª true ʱ£¬½«Å׳öÒì³££¬·ñÔò²»Á¬½ÓÈκÎÄÚÈÝ¡£
+
+Çë×¢Ò⣬Èç¹ûÎÒÃÇʹÓù¹Ô캯Êý×¢È룬ÔòËùÓй¹Ô캯Êý²ÎÊý¶¼ÊÇÇ¿ÖÆÐԵġ£
+
+´Ó 4.3 °æ±¾¿ªÊ¼£¬ÎÒÃDz»ÐèÒªÏÔʽµØÊ¹Óà @Autowired ×¢½â¹¹Ô캯Êý£¬³ý·ÇÎÒÃÇÉùÃ÷ÖÁÉÙÁ½¸ö¹¹Ô캯Êý¡£
+
+### 2.2 @Bean
+
+@Bean ±ê¼ÇʵÀý»¯ Spring bean µÄ¹¤³§·½·¨£º
+
+```
+@Bean
+Engine engine() {
+ return new Engine();
+}
+````
+
+µ±ÐèÒª·µ»ØÀàÐ͵ÄÐÂʵÀýʱ£¬Spring »áµ÷ÓÃÕâЩ·½·¨¡£
+
+Éú³ÉµÄ bean Ó빤³§·½·¨Í¬Ãû¡£ Èç¹ûÎÒÃÇÏëÒÔ²»Í¬µÄ·½Ê½ÃüÃû£¬ÎÒÃÇ¿ÉÒÔʹÓôË×¢Ê͵ÄÃû³Æ»òÖµ²ÎÊý£¨²ÎÊýÖµÊDzÎÊýÃû³ÆµÄ±ðÃû£©£º
+
+````
+@Bean("engine")
+Engine getEngine() {
+ return new Engine();
+}
+````
+ÕâÊÇÒ»Öַdz£³£¼ûµÄbeanÉùÃ÷·½Ê½£¬ÒòΪºÜ¶àµÄbean²¢²»ÊÇÎÒÃÇÒ»¿ªÊ¼¾ÍÔÚ´úÂëÀﶨÒåºÃµÄ£¬Ëü¿ÉÄÜÐèÒª»ùÓÚÔËÐÐʱ»·¾³À´½øÐа´Ðè¹¹½¨¡£
+
+ÎÒÃÇ¿ÉÒÔ×ÔÓɵØÉùÃ÷ºÍ¶¨ÒåBean£¬²¢ÇÒÒ²¿ÉÒÔ¸³ÓèËü×Ô¶¨ÒåµÄbeanÃû³Æ¡£
+
+×¢Ò⣬ËùÓÐÓÃ@Bean ×¢Ê͵ķ½·¨¶¼±ØÐëÔÚ@Configuration ÀàÖС£
+
+### 2.3 @Qualifier
+
+ÎÒÃÇʹÓÃ@Qualifier ºÍ@Autowired À´ÌṩÎÒÃÇÏëÒªÔÚ²»Ã÷È·Çé¿öÏÂʹÓõÄbean id »òbean Ãû³Æ¡£
+
+ÀýÈ磬ÒÔÏÂÁ½¸ö bean ʵÏÖÏàͬµÄ½Ó¿Ú£º
+````
+class Bike implements Vehicle {}
+
+class Car implements Vehicle {}
+
+````
+
+Èç¹û Spring ÐèҪעÈëÒ»¸ö Vehicle bean£¬Ëü»áÒÔ¶à¸öÆ¥Å䶨Òå½áÊø¡£ ÔÚÕâÖÖÇé¿öÏ£¬ÎÒÃÇ¿ÉÒÔʹÓà @Qualifier ×¢ÊÍÏÔʽÌṩ bean µÄÃû³Æ¡£
+
+**¹¹ÔìÆ÷×¢Èë**
+````
+@Autowired
+Biker(@Qualifier("bike") Vehicle vehicle) {
+this.vehicle = vehicle;
+}
+````
+
+**Setter×¢Èë**
+
+````
+@Autowired
+void setVehicle(@Qualifier("bike") Vehicle vehicle) {
+this.vehicle = vehicle;
+}
+````
+»òÕß:
+
+````
+@Autowired
+@Qualifier("bike")
+void setVehicle(Vehicle vehicle) {
+this.vehicle = vehicle;
+````
+**±äÁ¿×¢Èë**
+
+````
+@Autowired
+@Qualifier("bike")
+Vehicle vehicle;
+````
+Õâ¸ö×¢½âÎÒÃÇ¿ÉÄÜÆ½³£ÓõIJ»¶à£¬µ«Êǵ±Ò»¸ö½Ó¿ÚÓжà¸öʵÏÖÀàʱ£¬Ëü¾Í»á¾³£ÅÉÉÏÓ󡣡
+
+### 2.4 @Required
+
+@Required ÔÚ setter ·½·¨Éϱê¼ÇÎÒÃÇÏëҪͨ¹ý XML Ìî³äµÄÒÀÀµÏ
+````
+@Required
+void setColor(String color) {
+this.color = color;
+}
+````
+xml
+````
+
+
+
+````
+·ñÔò£¬½«Å׳ö BeanInitializationException¡£
+·Ç³£ÉÙ¼ûµÄÓ÷¨£¬ÖªµÀһϾÍÐÐÁË
+
+### 2.5 @Value
+ÎÒÃÇ¿ÉÒÔʹÓà @Value ½«ÊôÐÔÖµ×¢Èë bean¡£ ËüÓë¹¹Ô캯Êý¡¢setter ºÍ×Ö¶Î×¢Èë¼æÈÝ¡£
+
+ÕâÒ²ÊǷdz£³£ÓõÄÒ»¸ö×¢½â£¬ÒòΪÎÒÃǺܶàʱºò¶¼ÐèÒª´Óapplication.properties»òÕ߯äËûÅäÖÃÎļþÖÐÀ´¶ÁÈ¡ÅäÖÃÊôÐÔÖµ¡£
+
+**¹¹ÔìÆ÷×¢Èë**
+````
+Engine(@Value("8") int cylinderCount) {
+this.cylinderCount = cylinderCount;
+}
+````
+
+**setter×¢Èë**
+
+````
+@Autowired
+void setCylinderCount(@Value("8") int cylinderCount) {
+this.cylinderCount = cylinderCount;
+}
+````
+
+»òÕß:
+````
+
+@Value("8")
+void setCylinderCount(int cylinderCount) {
+this.cylinderCount = cylinderCount;
+}
+````
+
+**±äÁ¿×¢Èë**
+````
+@Value("8")
+int cylinderCount;
+````
+
+µ±È»£¬×¢È뾲ֵ̬ÊÇûÓÐÓõġ£ Òò´Ë£¬ÎÒÃÇ¿ÉÒÔÔÚ @Value ÖÐʹÓÃռλ·û×Ö·û´®À´Á¬½ÓÔÚÍⲿԴÖж¨ÒåµÄÖµ£¬ÀýÈçÔÚ .properties »ò .yaml ÎļþÖС£
+````
+
+engine.fuelType=petrol
+````
+
+ÎÒÃÇ¿ÉÒÔͨ¹ýÒÔÏ·½Ê½×¢Èë engine.fuelType µÄÖµ£º
+
+````
+@Value("${engine.fuelType}")
+String fuelType;
+````
+
+ÎÒÃÇÉõÖÁ¿ÉÒÔʹÓà SpEL À´Ê¹ÓÃ@Value¡£ ¸ü¶à¸ß¼¶Ê¾Àý¿ÉÒÔÔÚÎÒÃǹØÓÚ@Value µÄÎÄÕÂÖÐÕÒµ½¡£
+
+### 2.6 @DependsOn
+ÎÒÃÇ¿ÉÒÔʹÓôË×¢½âÈà Spring ÔÚ×¢½âµÄ bean ֮ǰ³õʼ»¯ÆäËû bean¡£ ͨ³££¬´ËÐÐΪÊÇ×Ô¶¯µÄ£¬»ùÓÚ bean Ö®¼äµÄÏÔʽÒÀÀµ¹ØÏµ¡£
+
+ÎÒÃÇÖ»ÓÐÔÚÒÀÀµÊÇÒþʽµÄʱºò²ÅÐèÒªÕâ¸ö×¢½â£¬±ÈÈçJDBCÇý¶¯¼ÓÔØ»òÕß¾²Ì¬±äÁ¿³õʼ»¯¡£
+
+ÎÒÃÇ¿ÉÒÔÔÚÖ¸¶¨ÒÀÀµ bean Ãû³ÆµÄÒÀÀµÀàÉÏʹÓà @DependsOn¡£ ×¢Ê͵ÄÖµ²ÎÊýÐèÒªÒ»¸ö°üº¬ÒÀÀµ bean Ãû³ÆµÄÊý×飺
+
+````
+@DependsOn("engine")
+class Car implements Vehicle {}
+````
+Alternatively, if we define a bean with the @Bean annotation, the factory method should be annotated with @DependsOn:
+````
+@Bean
+@DependsOn("fuel")
+Engine engine() {
+return new Engine();
+}
+````
+### 2.7 @Lazy
+µ±ÎÒÃÇÏëÀÁ¶èµØ³õʼ»¯ÎÒÃÇµÄ bean ʱ£¬ÎÒÃÇʹÓà @Lazy¡£ ĬÈÏÇé¿öÏ£¬Spring ÔÚÓ¦ÓóÌÐòÉÏÏÂÎĵįô¶¯/Òýµ¼Ê±¼±Çеش´½¨ËùÓе¥Àý bean¡£
+
+µ«ÊÇ£¬ÓÐЩÇé¿öÏÂÎÒÃÇÐèÒªÔÚÇëÇóʱ´´½¨ bean£¬¶ø²»ÊÇÔÚÓ¦ÓóÌÐòÆô¶¯Ê±´´½¨¡£
+
+Õâ¸ö×¢½âµÄÐÐΪ»á¸ù¾ÝÎÒÃÇ·ÅÖÃËüµÄÈ·ÇÐλÖöøÓÐËù²»Í¬¡£ ÎÒÃÇ¿ÉÒÔ°ÑËü·ÅÔÚ£º
+
+Ò»¸ö @Bean ×¢Ê굀 bean ¹¤³§·½·¨£¬ÒÔÑÓ³Ù·½·¨µ÷Óã¨Òò´Ë´´½¨ bean£©
+@Configuration ÀàºÍËùÓаüº¬µÄ@Bean ·½·¨¶¼»áÊܵ½Ó°Ïì
+
+Ò»¸ö @Component À࣬Ëü²»ÊÇ @Configuration À࣬Õâ¸ö bean ½«±»ÑÓ³Ù³õʼ»¯
+
+@Autowired ¹¹Ô캯Êý¡¢setter »ò×ֶΣ¬ÓÃÓÚÑÓ³Ù¼ÓÔØÒÀÀµÏî±¾Éí£¨Í¨¹ý´úÀí£©
+
+````
+@Configuration
+@Lazy
+class VehicleFactoryConfig {
+
+ @Bean
+ @Lazy(false)
+ Engine engine() {
+ return new Engine();
+ }
+}
+````
+ÕâͬÑù²»ÊÇÒ»¸ö³£ÓõÄ×¢½â¡£
+
+µ±ÎÒÃÇά»¤Ò»¸öÓдóÁ¿beanµÄÏîĿʱ£¬»á·¢ÏÖÓкܶàbean¿ÉÄܶ¼Êǰ´ÐèʹÓõ쬲»Ò»¶¨ÐèÒªÔÚÈÝÆ÷³õʼ»¯Ê±¾Í½øÐгõʼ»¯£¬Õâ¿ÉÒÔ°ïÎÒÃǽÚÊ¡ºÜ¶àʱ¼äºÍÐÔÄÜ¡£
+
+
+### 2.8 @Lookup
+ͬÑùÊÇÒ»¸ö±È½ÏÉÙÓõ½µÄ×¢½â
+
+@Lookup »á¸æËß Spring ÔÚÎÒÃǵ÷ÓÃËüʱ·µ»Ø·½·¨·µ»ØÀàÐ͵ÄʵÀý¡£
+
+±¾ÖÊÉÏ£¬Spring ½«¸²¸ÇÎÒÃÇ´ø×¢Ê͵ķ½·¨²¢Ê¹ÓÃÎÒÃÇ·½·¨µÄ·µ»ØÀàÐͺͲÎÊý×÷Ϊ BeanFactory#getBean µÄ²ÎÊý¡£
+
+@Lookup ÊÊÓÃÓÚ£º
+
+½«ÔÐÍ bean ×¢ÈëÎÒÃÇ×Ô¼ºµÄbean£¨ÀàËÆÓÚ Provider£©
+
+Èç¹ûÎÒÃÇÅöÇɾö¶¨ÓµÓÐÒ»¸öÔÐÍ Spring bean£¬ÄÇôÎÒÃǼ¸ºõ»áÁ¢¼´ÃæÁÙÕâÑùµÄÎÊÌ⣺
+
+ÎÒÃǵĵ¥Àý Spring bean ½«ÈçºÎ·ÃÎÊÕâЩÔÐÍ Spring bean£¿
+
+ÏÖÔÚ£¬Provider ¿Ï¶¨ÊÇÒ»ÖÖ·½Ê½£¬¾¡¹Ü @Lookup ÔÚijЩ·½Ãæ¸ü¼ÓͨÓá£
+
+ҪעÒâµÄÊÇ£¬springĬÈÏʹÓõĵ¥Àýbean£¬ËùÒÔÈç¹ûÎÒÃÇҪעÈëÔÐÍbean£¬ÎÒÃDzÅÐèÒª×öÕâÑùµÄ¶îÍ⹤×÷
+
+Ê×ÏÈ£¬ÈÃÎÒÃÇ´´½¨Ò»¸öÔÐÍ bean£¬ÉÔºóÎÒÃǽ«Æä×¢Èëµ½µ¥Àý bean ÖУº
+````
+@Component
+@Scope("prototype")
+public class SchoolNotification {
+// ... prototype-scoped state
+}
+````
+ʹÓÃ@Lookup£¬ÎÒÃÇ¿ÉÒÔͨ¹ýµ¥Àý bean »ñÈ¡ SchoolNotification µÄʵÀý£º
+
+````
+@Component
+public class StudentServices {
+
+ // ... member variables, etc.
+
+ @Lookup
+ public SchoolNotification getNotification() {
+ return null;
+ }
+
+ // ... getters and setters
+}
+````
+Using @Lookup, we can get an instance of SchoolNotification through our singleton bean:
+````
+@Test
+public void whenLookupMethodCalled_thenNewInstanceReturned() {
+// ... initialize context
+StudentServices first = this.context.getBean(StudentServices.class);
+StudentServices second = this.context.getBean(StudentServices.class);
+
+ assertEquals(first, second);
+ assertNotEquals(first.getNotification(), second.getNotification());
+}
+````
+Çë×¢Ò⣬ÔÚ StudentServices ÖУ¬ÎÒÃǽ« getNotification ·½·¨±£ÁôΪ´æ¸ù¡£
+
+ÕâÊÇÒòΪ Spring ͨ¹ýµ÷Óà beanFactory.getBean(StudentNotification.class) ¸²¸ÇÁ˸÷½·¨£¬Òò´ËÎÒÃÇ¿ÉÒÔ½«ÆäÁô¿Õ¡£
+
+
+### 2.9 @Primary
+ÓÐʱÎÒÃÇÐèÒª¶¨Òå¶à¸öÏàͬÀàÐ͵Äbean¡£ ÔÚÕâЩÇé¿öÏ£¬×¢È뽫²»³É¹¦£¬ÒòΪ Spring ²»ÖªµÀÎÒÃÇÐèÒªÄĸö bean¡£
+
+ÎÒÃÇÒѾ¿´µ½ÁË´¦ÀíÕâÖÖÇé¿öµÄÑ¡ÏÓÃ@Qualifier ±ê¼ÇËùÓнÓÏߵ㲢ָ¶¨ËùÐè bean µÄÃû³Æ¡£
+
+È»¶ø£¬´ó¶àÊýʱºòÎÒÃÇÐèÒªÒ»¸öÌØ¶¨µÄ bean£¬ºÜÉÙÐèÒªÆäËû bean¡£
+
+ÎÒÃÇ¿ÉÒÔʹÓÃ@Primary À´¼ò»¯ÕâÖÖÇé¿ö£ºÈç¹ûÎÒÃÇÓÃ@Primary ±ê¼Ç×î³£ÓõÄbean£¬Ëü½«ÔÚunqualifiedµÄ×¢ÈëµãÉϱ»Ñ¡Ôñ£º
+
+````
+@Component
+@Primary
+class Car implements Vehicle {}
+
+@Component
+class Bike implements Vehicle {}
+
+@Component
+class Driver {
+@Autowired
+Vehicle vehicle;
+}
+
+@Component
+class Biker {
+@Autowired
+@Qualifier("bike")
+Vehicle vehicle;
+}
+````
+ÔÚÇ°ÃæµÄʾÀýÖУ¬Æû³µÊÇÖ÷Òª³µÁ¾¡£ Òò´Ë£¬ÔÚ Driver ÀàÖУ¬Spring ×¢ÈëÁËÒ»¸ö Car bean¡£ µ±È»£¬ÔÚ Biker bean ÖУ¬×Ö¶Î vehicle µÄÖµ½«ÊÇÒ»¸ö Bike ¶ÔÏó£¬ÒòΪËüÊÇqualifiedµÄ¡£
+
+### 2.10 @Scope
+
+¶ÔÓÚͨ³£µÄÓ¦ÓÃÀ´Ëµ£¬ÎÒÃÇbeanµÄscopeĬÈ϶¼Êǵ¥ÀýµÄ£¬µ«Êµ¼ÊÉÏspring bean¿ÉÒÔÖ§³Ö¶àÖÖ¶àÑùµÄ×÷Ó÷¶Î§£¬ËüÃÇÓÐ×Ų»Í¬µÄÉúÃüÖÜÆÚ¡£
+
+ÎÒÃÇʹÓÃ@Scope À´¶¨Òå@Component Àà»ò@Bean ¶¨ÒåµÄ·¶Î§¡£ Ëü¿ÉÒÔÊǵ¥Àý¡¢ÔÐÍ¡¢ÇëÇ󡢻Ự¡¢globalSession »òһЩ×Ô¶¨Ò巶Χ¡£
+
+¶ÔÓ¦µÄö¾ÙֵΪ
+````
+singleton
+prototype
+request
+session
+application
+websocket
+````
+
+Àý×Ó
+````
+@Component
+@Scope("prototype")
+class Engine {}
+````
+ÎÒÃÇ¿ÉÒÔÏëÏóһЩ³¡¾°£¬±ÈÈçrequest¡¢session¡¢websocketÕâÀà×÷ÓÃÓòµÄbean£¬Í¨³£Ó¦¸ÃÊǺÍÍøÂçÇëÇóÏà¹ØµÄ£¬±ÈÈçÓô洢Óû§ÐÅÏ¢¡¢sessionÖ®ÀàµÄbean¡£
+
+¾ßÌåÔõôʹÓ㬾ÍÒª¸ù¾ÝÄãµÄ¾ßÌ峡¾°À´Ñ¡ÔñÁË£¬Õâ»áÊÇÒ»¸öºÜ´óµÄ»°Ì⣬ÕâÀï¾ÍÏȲ»Õ¹¿ªÁË£¬ÒÔºó¿ÉÒÔÔÚµ¥¶ÀµÄÎÄÕÂÀï¼ÌÐø½éÉÜ¡£
+
+## 3 ÉÏÏÂÎÄÅäÖÃ×¢½â
+ÎÒÃÇ¿ÉÒÔʹÓñ¾½ÚÖÐÃèÊöµÄ×¢ÊÍÀ´ÅäÖÃÓ¦ÓóÌÐòÉÏÏÂÎÄ¡£
+
+
+### 3.1 @Profile
+
+Èç¹ûÎÒÃÇÏ£Íû Spring ½öÔÚÌØ¶¨ÅäÖÃÎļþ´¦Óڻ״̬ʱʹÓÃ@Component Àà»ò@Bean ·½·¨£¬ÎÒÃÇ¿ÉÒÔʹÓÃ@Profile ¶ÔÆä½øÐбê¼Ç¡£
+
+ÎÒÃÇ¿ÉÒÔʹÓÃ×¢Ê͵ÄÖµ²ÎÊýÅäÖÃÅäÖÃÎļþµÄÃû³Æ£º
+
+ÎÒÃÇͨ³£Õâ¸ö×¢½âÀ´ÅäÖò»Í¬»·¾³µÄÅäÖá£
+±ÈÈçÏÂÃæÕâ¸öÀý×Ó
+
+````
+public interface DatasourceConfig {
+public void setup();
+}
+````
+
+ÏÂÃæÊÇ¿ª·¢»·¾³µÄÅäÖãº
+
+````
+@Component
+@Profile("dev")
+public class DevDatasourceConfig implements DatasourceConfig {
+@Override
+public void setup() {
+System.out.println("Setting up datasource for DEV environment. ");
+}
+}
+````
+ÏÂÃæÊÇÉú²ú»·¾³µÄÅäÖãº
+
+````
+@Component
+@Profile("production")
+public class ProductionDatasourceConfig implements DatasourceConfig {
+@Override
+public void setup() {
+System.out.println("Setting up datasource for PRODUCTION environment. ");
+}
+}
+````
+µ±È»ÎÒÃÇÒ²¿ÉÒÔʹÓÃxml»òÕ߯äËûÀàÐ͵ÄÅäÖÃÎļþÀ´ÃèÊöÕâ¸öÅäÖÃbean
+
+xml
+````
+
+
+
+````
+### 3.2 @Import
+
+ÎÒÃÇ¿ÉÒÔʹÓÃÌØ¶¨µÄ @Configuration À࣬¶øÎÞÐèʹÓôË×¢½â½øÐÐ×é¼þɨÃè¡£ ÎÒÃÇ¿ÉÒÔΪÕâЩÀàÌṩ@Import µÄÖµ²ÎÊý
+
+Õý³£À´Ëµ£¬Èç¹ûÒªÓõ½@Configuration×¢½âµÄbean£¬ÄÇôspringÓ¦ÓñØÐëҪɨÃèµ½¸ÃĿ¼£¬Èç¹ûÇ¡ºÃûÓжԸ÷¾¶½øÐÐɨÃ裬»òÕßÎÒÃÇÖ»ÊÇÏëʹÓ÷¾¶Ïµĵ¥¸öÅäÖÃÀ࣬ÄÇôÎÒÃǾͿÉÒÔʹÓÃ@ImportÀ´µ¼ÈëÕâ¸öÅäÖÃÀàÁË¡£
+
+Õâ¸ö×¢½â»¹ÊǷdz£³£Óõģ¬¿´Ò»ÏÂÏÂÃæÕâ¸öÀý×Ó
+
+````
+@Import(VehiclePartSupplier.class)
+class VehicleFactoryConfig {}
+
+@Configuration
+class VehiclePartSupplier{
+}
+````
+
+### 3.3 @ImportResource
+
+±ÈÈç˵£ºÏÖÔÚÓÐÒ»¸ö bean.xml µÄÅäÖÃÎļþ£¬ÐèÒª½«¸Ã beans.xml Öж¨ÒåµÄ bean¶ÔÏó ¶¼µ¼Èëµ½ Spring Boot »·¾³µÄÈÝÆ÷ÖУ¬¸ÃÈçºÎ²Ù×÷ÄØ£¿
+
+1.Spring ·½Ê½µÄÅäÖÃÎļþ bean.xml ´Ë´¦Ëæ±ã¾Ù¸öʾÀý£¬±ÈÈç˵ xml ÖÐÅäÖÃÁËÒ»¸ö helloService£¬ÈçÏÂËùʾ
+````
+
+
+
+
+
+
+````
+2.ʹÓÃ@ImportResource×¢½â£¬ÒýÈë xml ÅäÖÃ
+````
+/**
+ * Spring BootÀïÃæÃ»ÓÐSpringµÄÅäÖÃÎļþ£¬ÎÒÃÇ×Ô¼º±àдµÄÅäÖÃÎļþ£¬Ò²²»ÄÜ×Ô¶¯Ê¶±ð£»
+ * Èç¹ûÏëÈÃSpringµÄÅäÖÃÎļþÉúЧ£¬¼ÓÔØµ½Spring ÈÝÆ÷ÖÐÀ´£»
+ * ʹÓÃ@ImportResource×¢½â£¬½«Æä±ê×¢ÔÚÒ»¸öÅäÖÃÀàÉÏ(´Ë´¦ÅäÖÃÔÚÆô¶¯Àà)
+ */
+@SpringBootApplication
+@ImportResource(locations = {"classpath:beans.xml"})
+public class BootApplication {
+
+ public static void main(String[] args) {
+ // SpringÓ¦ÓÃÆô¶¯ÆðÀ´
+ SpringApplication.run(BootApplication.class,args);
+
+ }
+}
+
+````
+### 3.4 @PropertySource
+ͨ¹ýÕâ¸ö×¢½â£¬ÎÒÃÇ¿ÉÒÔΪӦÓóÌÐòÉèÖö¨ÒåÊôÐÔÎļþ£º
+
+@PropertySource ×¢½âÌṩÁËÒ»ÖÖ·½±ãµÄÉùÃ÷ÐÔ»úÖÆ£¬ÓÃÓÚ½« PropertySource Ìí¼Óµ½ Spring µÄ Environment ÖУ¬Óë @Configuration ÀàÒ»ÆðʹÓá£
+
+Äã¿ÉÒÔʹÓà @Value È¥ÒýÓö¨ÒåµÄÊôÐÔ£¬ÀýÈ磺@Value("testbean.name")£»Ò²¿ÉÒÔÖ¸¶¨Ä¬ÈÏÖµ£¬È磺@Value("testbean.name:defaultValue")¡£
+
+Ó÷¨Ê¾Àý
+
+¸ø¶¨Ò»¸öÅäÖÃÎļþapp.properties
+````
+testbean.name=myTestBean
+````
+ÒÔÏ @Configuration ÀàʹÓà @PropertySource ½« app.properties ÉèÖøø Environment µÄ PropertySources ¼¯ºÏ¡£
+````
+@Configuration
+@PropertySource("classpath:/com/myco/app.properties")
+public class AppConfig {
+
+ @Autowired
+ Environment env;
+
+ @Bean
+ public TestBean testBean() {
+ TestBean testBean = new TestBean();
+ testBean.setName(env.getProperty("testbean.name"));
+ return testBean;
+ }
+}
+````
+
+×¢Ò⣺ʹÓà @Autowired ½« Environment ¶ÔÏó×¢Èëµ½ÅäÖÃÀàÖУ¬È»ºóÔÚ testBean() ·½·¨ÖÐʹÓá£
+ÒÔÉÏÅäÖÃÖУ¬µ÷Óà testBean.getName() ·½·¨½«·µ»Ø¡°myTestBean¡±×Ö·û´®¡£
+
+@PropertySource ÀûÓÃÁË Java 8 µÄÖØ¸´×¢½âÌØÐÔ£¬ÕâÒâζ×ÅÎÒÃÇ¿ÉÒÔÓÃËü¶à´Î±ê¼ÇÒ»¸öÀࣺ
+
+````
+@Configuration
+@PropertySource("classpath:/annotations.properties")
+@PropertySource("classpath:/vehicle-factory.properties")
+class VehicleFactoryConfig {}
+````
+
+### 3.5 @PropertySources
+Ó÷¨Í¬ÉÏ£¬Ö»²»¹ý£¬ÕâÒ»´ÎÎÒÃÇ¿ÉÒÔʹÓÃÕâ¸ö×¢½âÖ¸¶¨¶à¸ö@PropertySource ÅäÖãº
+````
+@Configuration
+@PropertySources({
+@PropertySource("classpath:/annotations.properties"),
+@PropertySource("classpath:/vehicle-factory.properties")
+})
+class VehicleFactoryConfig {}
+````
+Çë×¢Ò⣬×Ô Java 8 ÒÔÀ´£¬ÎÒÃÇ¿ÉÒÔͨ¹ýÉÏÊöÖØ¸´×¢Ê͹¦ÄÜʵÏÖÏàͬµÄ¹¦ÄÜ¡£
+
+## 4.½áÂÛ
+
+ÔÚ±¾ÎÄÖУ¬ÎÒÃÇ¿´µ½ÁË×î³£¼ûµÄ Spring ºËÐÄ×¢Ê͵ĸÅÊö¡£ ÎÒÃÇ¿´µ½ÁËÈçºÎÅäÖà bean Á¬½ÓºÍÓ¦ÓÃÉÏÏÂÎÄ£¬ÒÔ¼°ÈçºÎΪ×é¼þɨÃè±ê¼ÇÀà¡£
+
+springÌåϵÖеij£¼û×¢½â»¹Óкܶ࣬һƪÎÄÕ²»¿ÉÄÜÈ«²¿¸²¸Ç£¬ÈçÓÐÒÅ©£¬»¶Ó²¹³ä¡£
+
+# Spring Bean×¢½â
+
+## 1 ¸ÅÊö
+ÔÚ±¾½Ì³ÌÖУ¬ÎÒÃǽ«ÌÖÂÛÓÃÓÚ¶¨Ò岻ͬÀàÐÍ bean µÄ×î³£¼ûµÄ Spring bean ×¢ÊÍ¡£
+
+Óм¸ÖÖ·½·¨¿ÉÒÔÔÚ Spring ÈÝÆ÷ÖÐÅäÖà bean¡£ Ê×ÏÈ£¬ÎÒÃÇ¿ÉÒÔʹÓà XML ÅäÖÃÉùÃ÷ËüÃÇ¡£ ÎÒÃÇ»¹¿ÉÒÔÔÚÅäÖÃÀàÖÐʹÓÃ@Bean ×¢½âÀ´ÉùÃ÷ bean¡£
+
+×îºó£¬ÎÒÃÇ¿ÉÒÔʹÓà org.springframework.stereotype °üÖеÄ×¢ÊÍÖ®Ò»À´±ê¼Ç¸ÃÀ࣬²¢½«ÆäÓಿ·ÖÁô¸ø×é¼þɨÃè¡£
+
+## 2 @ComponentScan
+ÕâÊÇÎÒÃǾ³£»áʹÓõÄÒ»¸ö×¢½â£¬ÔÚÎÒÃǵÄÓ¦ÓÃÖУ¬ÓÐʱºò²»Ò»¶¨»áɨÃèËùÓеİü£¬ÌرðÊǵ±ÎÒÃÇҪɨÃèÍⲿjar°üÖеÄbeanʱ£¬Ëü·Ç³£ÓÐÓá£
+
+Ëü¿ÉÒÔ¼ÓÔÚSpringBootApplicationÉÏ£¬Ò²¿ÉÒÔ¼ÓÔÚ@configuration×¢½âÉϵÄÅäÖÃÀàÉÏ
+
+Èç¹ûÆôÓÃÁË×é¼þɨÃ裬Spring ¿ÉÒÔ×Ô¶¯É¨Ãè°üÖÐµÄ bean¡£
+
+@ComponentScan ÅäÖÃʹÓÃ×¢½âÅäÖÃɨÃèÄÄЩ°üµÄÀà¡£
+
+ÎÒÃÇ¿ÉÒÔÖ±½ÓʹÓà basePackages »ò value ²ÎÊýÖ®Ò»Ö¸¶¨»ù±¾°üÃû³Æ£¨value ÊÇ basePackages µÄ±ðÃû£©
+
+````
+@Configuration
+@ComponentScan(basePackages = "com.baeldung.annotations")
+class VehicleFactoryConfig {}
+````
+´ËÍ⣬ÎÒÃÇ¿ÉÒÔʹÓà basePackageClasses ²ÎÊýÖ¸Ïò»ù´¡°üÖеÄÀࣺ
+
+````
+@Configuration
+@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
+class VehicleFactoryConfig {}
+````
+
+ÕâÁ½¸ö²ÎÊý¶¼ÊÇÊý×飬Òò´ËÎÒÃÇ¿ÉÒÔΪÿ¸ö²ÎÊýÌṩ¶à¸ö°ü¡£
+
+Èç¹ûδָ¶¨²ÎÊý£¬ÔòɨÃè·¢ÉúÔÚ´æÔÚ @ComponentScan ×¢ÊÍÀàµÄͬһ°üÖС£
+
+@ComponentScan ÀûÓÃÁË Java 8 µÄÖØ¸´×¢½âÌØÐÔ£¬ÕâÒâζ×ÅÎÒÃÇ¿ÉÒÔÓÃËü¶à´Î±ê¼ÇÒ»¸öÀࣺ
+
+````
+@Configuration
+@ComponentScan(basePackages = "com.baeldung.annotations")
+@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
+class VehicleFactoryConfig {}
+````
+
+»òÕߣ¬ÎÒÃÇ¿ÉÒÔʹÓà @ComponentScans Ö¸¶¨¶à¸ö @ComponentScan ÅäÖãº
+
+````
+@Configuration
+@ComponentScans({
+@ComponentScan(basePackages = "com.baeldung.annotations"),
+@ComponentScan(basePackageClasses = VehicleFactoryConfig.class)
+})
+````
+````
+class VehicleFactoryConfig {
+}
+````
+ʹÓà XML ÅäÖÃʱ£¬ÅäÖÃ×é¼þɨÃèͬÑù¼òµ¥£º
+
+````
+
+````
+
+### 3 @Component
+
+@Component ÊÇÀ༶±ðµÄ×¢½â¡£ ÔÚ×é¼þɨÃèÆÚ¼ä£¬Spring Framework »á×Ô¶¯¼ì²âʹÓÃ@Component ×¢½âµÄÀࣺ
+````
+@Component
+class CarUtility {
+// ...
+}
+````
+
+ĬÈÏÇé¿öÏ£¬´ËÀàµÄ bean ʵÀýÓëÀàÃûͬÃû£¬Ê××ÖĸСд¡£ ´ËÍ⣬ÎÒÃÇ¿ÉÒÔʹÓôË×¢Ê͵ĿÉѡֵ²ÎÊýÖ¸¶¨²»Í¬µÄÃû³Æ¡£
+
+ÓÉÓÚ@Repository¡¢@Service¡¢@Configuration ºÍ@Controller ¶¼ÊÇ´øÓÐ@Component µÄ×¢½â£¬ËüÃǹ²ÏíÏàͬµÄbean ÃüÃûÐÐΪ¡£
+
+Spring »¹»áÔÚ×é¼þɨÃè¹ý³ÌÖÐ×Ô¶¯¼ì²âËüÃÇ¡£
+
+ͨ³£À´Ëµ£¬ÎÒÃÇ»áÔÚmvcÓ¦ÓÃÖÐÎÒÃÇ»áÓõ½ÉÏÊö¼¸ÖÖ×¢½â£¬¶øÎÒÃÇÔÚ·ÇwebÓ¦ÓÃÖиü¶àµØ¿ÉÒÔʹÓÃ@componentÀ´×¢½âbean
+
+### 4 @Repository
+
+DAO or Repository classes usually represent the database access layer in an application, and should be annotated with @Repository:
+````
+@Repository
+class VehicleRepository {
+// ...
+}
+````
+ʹÓôË×¢Ê͵ÄÒ»¸öÓŵãÊÇËüÆôÓÃÁË×Ô¶¯³Ö¾ÃÐÔÒ쳣ת»»¡£ µ±Ê¹Óó־ÃÐÔ¿ò¼Ü£¨Èç Hibernate£©Ê±£¬ÔÚʹÓà @Repository ×¢Ê͵ÄÀàÖÐÅ׳öµÄ±¾»úÒì³£½«×Ô¶¯×ª»»Îª Spring µÄ DataAccessExeption µÄ×ÓÀà¡£
+
+ÒªÆôÓÃÒ쳣ת»»£¬ÎÒÃÇÐèÒªÉùÃ÷ÎÒÃÇ×Ô¼ºµÄ PersistenceExceptionTranslationPostProcessor bean£º
+````
+@Bean
+public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
+return new PersistenceExceptionTranslationPostProcessor();
+}
+````
+Çë×¢Ò⣬ÔÚ´ó¶àÊýÇé¿öÏ£¬Spring »á×Ô¶¯Ö´ÐÐÉÏÊö²½Öè¡£
+
+»òÕßͨ¹ý XML ÅäÖãº
+````
+
+````
+
+### 5 @Service
+Ó¦ÓóÌÐòµÄÒµÎñÂ߼ͨ³£×¤ÁôÔÚ·þÎñ²ãÖУ¬Òò´ËÎÒÃǽ«Ê¹ÓÃ@Service ×¢ÊÍÀ´Ö¸Ê¾Ò»¸öÀàÊôÓڸò㣺
+
+````
+@Service
+public class VehicleService {
+// ...
+}
+````
+### 6 @Controller
+@Controller ÊÇÒ»¸öÀ༶±ðµÄ×¢½â£¬Ëü¸æËß Spring Framework Õâ¸öÀà×÷Ϊ Spring MVC ÖеĿØÖÆÆ÷£º
+
+spring»á¶Ô@Controller ×¢½âµÄbean×öºÜ¶àÊÂÇ飬¾ßÌåÄÚÈÝÎÒÃÇ»áÔÚSpringMVCÏà¹ØµÄÄÚÈÝÀ´½²Êö
+
+````
+@Controller
+public class VehicleController {
+// ...
+}
+
+````
+## 7 @Configuration
+
+ÅäÖÃÀà¿ÉÒÔ°üº¬ÓÃ@Bean ×¢Ê굀 bean ¶¨Òå·½·¨£º
+````
+@Configuration
+class VehicleFactoryConfig {
+
+ @Bean
+ Engine engine() {
+ return new Engine();
+ }
+
+}
+````
+## 8 AOP×¢½â
+µ±ÎÒÃÇʹÓà Spring ¹¹ÔìÐÍ×¢ÊÍʱ£¬ºÜÈÝÒ×´´½¨Ò»¸öÇÐÈëµã£¬¸ÃÇÐÈëµãÒÔËùÓоßÓÐÌØ¶¨¹¹ÔìÐ͵ÄÀàΪĿ±ê¡£
+
+ÀýÈ磬¼ÙÉèÎÒÃÇÏë²âÁ¿ DAO ²ã·½·¨µÄÖ´ÐÐʱ¼ä¡£ ÎÒÃǽ«´´½¨ÒÔÏ·½Ã棨ʹÓà AspectJ ×¢ÊÍ£©£¬ÀûÓà @Repository ¹¹ÔìÐÍ£º
+
+```
+@Aspect
+@Component
+public class PerformanceAspect {
+@Pointcut("within(@org.springframework.stereotype.Repository *)")
+public void repositoryClassMethods() {};
+
+ @Around("repositoryClassMethods()")
+ public Object measureMethodExecutionTime(ProceedingJoinPoint joinPoint)
+ throws Throwable {
+ long start = System.nanoTime();
+ Object returnValue = joinPoint.proceed();
+ long end = System.nanoTime();
+ String methodName = joinPoint.getSignature().getName();
+ System.out.println(
+ "Execution of " + methodName + " took " +
+ TimeUnit.NANOSECONDS.toMillis(end - start) + " ms");
+ return returnValue;
+ }
+}
+````
+
+ÔÚ´ËʾÀýÖУ¬ÎÒÃÇ´´½¨ÁËÒ»¸öÇÐÈëµã£¬¸ÃÇÐÈëµãÆ¥ÅäʹÓÃ@Repository ×¢Ê͵ÄÀàÖеÄËùÓз½·¨¡£ È»ºóÎÒÃÇʹÓÃ@Around ֪ͨÀ´¶¨Î»ÄǸöÇÐÈëµã£¬²¢È·¶¨À¹½Ø·½·¨µ÷ÓõÄÖ´ÐÐʱ¼ä¡£
+
+´ËÍ⣬ʹÓÃÕâÖÖ·½·¨£¬ÎÒÃÇ¿ÉÒÔΪÿ¸öÓ¦ÓóÌÐò²ãÌí¼ÓÈÕÖ¾¼Ç¼¡¢ÐÔÄܹÜÀí¡¢Éó¼ÆºÍÆäËûÐÐΪ¡£
+
+µ±È»ÁË£¬aspectJµÄÏà¹Ø×¢½â»¹ºÜ¶à£¬¿ÉÒÔÓÃÀ´ÉùÃ÷ÇÐÃæ£¬Î´À´ÎÒÃÇÒ²»áµ¥¶ÀдÎĽéÉÜ¡£
+
+## 9 ½áÂÛ
+
+ÔÚ±¾ÎÄÖУ¬ÎÒÃǼì²éÁË Spring ¹¹ÔìÐÍ×¢ÊͲ¢ÌÖÂÛÁËËüÃǸ÷×Ô´ú±íµÄÓïÒåÀàÐÍ¡£
+
+ÎÒÃÇ»¹Ñ§Ï°ÁËÈçºÎʹÓÃ×é¼þɨÃèÀ´¸æËßÈÝÆ÷ÔÚÄÄÀï¿ÉÒÔÕÒµ½´ø×¢Ê͵ÄÀà¡£
+
+×îºó£¬ÎÒÃÇÁ˽âÁËÕâЩעÊÍÈçºÎµ¼Ö¸ɾ»¡¢·Ö²ãµÄÉè¼ÆÒÔ¼°Ó¦ÓóÌÐò¹Ø×¢µãÖ®¼äµÄ·ÖÀë¡£ ËüÃÇ»¹Ê¹ÅäÖøüС£¬ÒòΪÎÒÃDz»ÔÙÐèÒªÊÖ¶¯ÏÔʽ¶¨Òå bean¡£
+
+# ²Î¿¼ÎÄÕÂ
+https://www.baeldung.com/spring-annotations
+
diff --git "a/docs/spring/Spring\346\246\202\350\277\260.md" "b/docs/spring/Spring\346\246\202\350\277\260.md"
new file mode 100644
index 0000000..1152df8
--- /dev/null
+++ "b/docs/spring/Spring\346\246\202\350\277\260.md"
@@ -0,0 +1,145 @@
+Spring ÊÇ Java EE ±à³ÌÁìÓòµÄÒ»¿îÇáÁ¿¼¶µÄ¿ªÔ´¿ò¼Ü£¬Óɱ»³ÆÎª¡°Spring Ö®¸¸¡±µÄ Rod Johnson ÓÚ 2002 ÄêÌá³ö²¢´´Á¢£¬ËüµÄÄ¿±ê¾ÍÊÇÒª¼ò»¯ Java ÆóÒµ¼¶Ó¦ÓóÌÐòµÄ¿ª·¢ÄѶȺÍÖÜÆÚ¡£
+
+Spring ×Ôµ®ÉúÒÔÀ´±¸ÊÜÇàíù£¬Ò»Ö±±»¹ã´ó¿ª·¢ÈËÔ±×÷Ϊ Java ÆóÒµ¼¶Ó¦ÓóÌÐò¿ª·¢µÄÊ×Ñ¡¡£Ê±ÖÁ½ñÈÕ£¬Spring ٲȻ³ÉΪÁË Java EE ´úÃû´Ê£¬³ÉΪÁ˹¹½¨ Java EE Ó¦ÓõÄÊÂʵ±ê×¼¡£
+
+## Spring µÄµ®ÉúÓë·¢Õ¹
+
+ÔçÆÚµÄ J2EE£¨Java EE ƽ̨£©ÍƳçÒÔ EJB ΪºËÐĵĿª·¢·½Ê½£¬µ«ÕâÖÖ¿ª·¢·½Ê½ÔÚʵ¼ÊµÄ¿ª·¢¹ý³ÌÖдæÔÚÖÖÖÖ±×¶Ë£¬ÀýÈçʹÓø´ÔÓ¡¢´úÂëÓ·Öס¢´úÂëÇÖÈëÐÔÇ¿¡¢¿ª·¢ÖÜÆÚ³¤¡¢ÒÆÖ²ÄѶȴóµÈ¡£
+
+Rod Johnson ÔÚÆä 2004 Äê±àÖøµÄ³©ÏúÊé¡¶Expert One-on-One J2EE Development without EJB¡·ÖУ¬Õë¶Ô EJB ¸÷ÖÖÓ·Ö׵Ľṹ½øÐÐÁËÖðÒ»µÄ·ÖÎöºÍ·ñ¶¨£¬²¢·Ö±ðÒÔ¸ü¼Ó¼ò½àµÄ·½Ê½½øÐÐÁËÌæ»»¡£
+
+ÔÚÕâ±¾ÊéÖУ¬Rod Johnson ͨ¹ýÒ»¸ö°üº¬ 3 ÍòÐдúÂëµÄ¸½¼þ£¬Õ¹Ê¾ÁËÈçºÎÔÚ²»Ê¹Óà EJB µÄÇé¿öϹ¹½¨Ò»¸ö¸ßÖÊÁ¿¡¢¿ÉÀ©Õ¹µÄ Java Ó¦ÓóÌÐò¡£ÔÚÕâ¸ö¸½¼þÖУ¬Rod Johnson ±àдÁËÉÏÍòÐлù´¡½á¹¹´úÂ룬ÆäÖаüº¬ÁËÐí¶à¿ÉÖØÓÃµÄ Java ½Ó¿ÚºÍÀ࣬ÀýÈç ApplicationContext¡¢BeanFactory µÈ¡£ÕâЩÀàµÄ¸ù°ü±»ÃüÃûΪ com.interface21£¬º¬ÒåΪ£ºÕâÊÇÌṩ¸ø 21 ÊÀ¼ÍµÄÒ»¸ö²Î¿¼¡£
+
+Õâ±¾ÊéÓ°ÏìÉõÔ¶£¬ºóÀ´ Rod Johnson ½« com.interface21 µÄ´úÂ뿪Դ£¬²¢°ÑÕâ¸öпò¼Ü²¢ÃüÃûΪ¡°Spring¡±£¬º¬ÒåΪ£ºSpring ÏñÒ»ÂÆ´º·çÒ»Ñù£¬É¨Æ½´«Í³ J2EE µÄº®¶¬¡£
+
+2003 Äê 2 Ô£¬Spring 0.9 °æ±¾·¢²¼£¬Ëü²ÉÓÃÁË Apache 2.0 ¿ªÔ´ÐÒ飻2004 Äê 4 Ô£¬Spring 1.0 °æ±¾Õýʽ·¢²¼¡£µ½Ä¿Ç°ÎªÖ¹£¬Spring ÒѾ²½Èëµ½ÁËµÚ 5 ¸ö´ó°æ±¾£¬Ò²¾ÍÊÇÎÒÃdz£ËµµÄ Spring 5¡£
+
+## Spring µÄÏÁÒåºÍ¹ãÒå
+
+ÔÚ²»Í¬µÄÓï¾³ÖУ¬Spring Ëù´ú±íµÄº¬ÒåÊDz»Í¬µÄ¡£ÏÂÃæÎÒÃǾͷֱð´Ó¡°¹ãÒ塱ºÍ¡°ÏÁÒ塱Á½¸ö½Ç¶È£¬¶Ô Spring ½øÐнéÉÜ¡£
+
+### ¹ãÒåµÄ Spring£ºSpring ¼¼ÊõÕ»
+
+¹ãÒåÉ쵀 Spring ·ºÖ¸ÒÔ Spring Framework ΪºËÐÄµÄ Spring ¼¼ÊõÕ»¡£
+
+¾¹ýÊ®¶àÄêµÄ·¢Õ¹£¬Spring ÒѾ²»ÔÙÊÇÒ»¸öµ¥´¿µÄÓ¦Óÿò¼Ü£¬¶øÊÇÖð½¥·¢Õ¹³ÉΪһ¸öÓɶà¸ö²»Í¬×ÓÏîÄ¿£¨Ä£¿é£©×é³ÉµÄ³ÉÊì¼¼Êõ£¬ÀýÈç Spring Framework¡¢Spring MVC¡¢SpringBoot¡¢Spring Cloud¡¢Spring Data¡¢Spring Security µÈ£¬ÆäÖÐ Spring Framework ÊÇÆäËû×ÓÏîÄ¿µÄ»ù´¡¡£
+
+ÕâЩ×ÓÏîÄ¿º¸ÇÁË´ÓÆóÒµ¼¶Ó¦Óÿª·¢µ½ÔƼÆËãµÈ¸÷·½ÃæµÄÄÚÈÝ£¬Äܹ»°ïÖú¿ª·¢ÈËÔ±½â¾öÈí¼þ·¢Õ¹¹ý³ÌÖв»¶Ï²úÉúµÄ¸÷ÖÖʵ¼ÊÎÊÌ⣬¸ø¿ª·¢ÈËÔ±´øÀ´Á˸üºÃµÄ¿ª·¢ÌåÑé¡£
+
+| ÏîÄ¿Ãû³Æ | ÃèÊö |
+| --- | --- |
+| Spring Data | Spring ÌṩµÄÊý¾Ý·ÃÎÊÄ£¿é£¬¶Ô JDBC ºÍ ORM ÌṩÁ˺ܺõÄÖ§³Ö¡£Í¨¹ýËü£¬¿ª·¢ÈËÔ±¿ÉÒÔʹÓÃÒ»ÖÖÏà¶ÔͳһµÄ·½Ê½£¬À´·ÃÎÊλÓÚ²»Í¬ÀàÐÍÊý¾Ý¿âÖеÄÊý¾Ý¡£ |
+| Spring Batch | Ò»¿îרÃÅÕë¶ÔÆóÒµ¼¶ÏµÍ³ÖеÄÈÕ³£Åú´¦ÀíÈÎÎñµÄÇáÁ¿¼¶¿ò¼Ü£¬Äܹ»°ïÖú¿ª·¢ÈËÔ±·½±ãµÄ¿ª·¢³ö½¡×³¡¢¸ßЧµÄÅú´¦ÀíÓ¦ÓóÌÐò¡£ |
+| Spring Security | ǰÉíΪ Acegi£¬ÊÇ Spring ÖнϳÉÊìµÄ×ÓÄ£¿éÖ®Ò»¡£ËüÊÇÒ»¿î¿ÉÒÔ¶¨ÖÆ»¯µÄÉí·ÝÑéÖ¤ºÍ·ÃÎÊ¿ØÖÆ¿ò¼Ü¡£ |
+| Spring Mobile | ÊÇ¶Ô Spring MVC µÄÀ©Õ¹£¬ÓÃÀ´¼ò»¯Òƶ¯¶Ë Web Ó¦ÓõĿª·¢¡£ |
+| Spring Boot | ÊÇ Spring ÍŶÓÌṩµÄȫпò¼Ü£¬ËüΪ Spring ÒÔ¼°µÚÈý·½¿âһЩ¿ªÏä¼´ÓõÄÅäÖ㬿ÉÒÔ¼ò»¯ Spring Ó¦ÓõĴ¼°¿ª·¢¹ý³Ì¡£ |
+| Spring Cloud | Ò»¿î»ùÓÚ Spring Boot ʵÏÖµÄ΢·þÎñ¿ò¼Ü¡£Ëü²¢²»ÊÇijһÃż¼Êõ£¬¶øÊÇһϵÁÐ΢·þÎñ½â¾ö·½°¸»ò¿ò¼ÜµÄÓÐÐò¼¯ºÏ¡£Ëü½«ÊÐÃæÉϳÉÊìµÄ¡¢¾¹ýÑéÖ¤µÄ΢·þÎñ¿ò¼ÜÕûºÏÆðÀ´£¬²¢Í¨¹ý Spring Boot µÄ˼Ïë½øÐÐÔÙ·â×°£¬ÆÁ±Îµ÷ÆäÖи´ÔÓµÄÅäÖúÍʵÏÖÔÀí£¬×îÖÕΪ¿ª·¢ÈËÔ±ÌṩÁËÒ»Ì×¼òµ¥Ò×¶®¡¢Òײ¿ÊðºÍÒ×ά»¤µÄ·Ö²¼Ê½ÏµÍ³¿ª·¢¹¤¾ß°ü¡£ |
+
+### ÏÁÒåµÄ Spring£ºSpring Framework
+
+ÏÁÒåµÄ Spring ÌØÖ¸ Spring Framework£¬Í¨³£ÎÒÃǽ«Ëü³ÆÎª Spring ¿ò¼Ü¡£
+
+Spring ¿ò¼ÜÊÇÒ»¸ö·Ö²ãµÄ¡¢ÃæÏòÇÐÃæµÄ Java Ó¦ÓóÌÐòµÄһվʽÇáÁ¿¼¶½â¾ö·½°¸£¬ËüÊÇ Spring ¼¼ÊõÕ»µÄºËÐĺͻù´¡£¬ÊÇΪÁ˽â¾öÆóÒµ¼¶Ó¦Óÿª·¢µÄ¸´ÔÓÐÔ¶ø´´½¨µÄ¡£
+
+Spring ÓÐÁ½¸öºËÐIJ¿·Ö£º IoC ºÍ AOP¡£
+
+| ºËÐÄ | ÃèÊö |
+| --- | --- |
+| IOC | Inverse of Control µÄ¼òд£¬ÒëΪ¡°¿ØÖÆ·´×ª¡±£¬Ö¸°Ñ´´½¨¶ÔÏó¹ý³Ì½»¸ø Spring ½øÐйÜÀí¡£ |
+| AOP | Aspect Oriented Programming µÄ¼òд£¬ÒëΪ¡°ÃæÏòÇÐÃæ±à³Ì¡±¡£AOP ÓÃÀ´·â×°¶à¸öÀàµÄ¹«¹²ÐÐΪ£¬½«ÄÇЩÓëÒµÎñÎ޹أ¬È´ÎªÒµÎñÄ£¿éËù¹²Í¬µ÷ÓõÄÂß¼·â×°ÆðÀ´£¬¼õÉÙϵͳµÄÖØ¸´´úÂ룬½µµÍÄ£¿é¼äµÄñîºÏ¶È¡£ÁíÍ⣬AOP »¹½â¾öһЩϵͳ²ãÃæÉϵÄÎÊÌ⣬±ÈÈçÈÕÖ¾¡¢ÊÂÎñ¡¢È¨Ï޵ȡ£ |
+
+Spring ÊÇÒ»ÖÖ»ùÓÚ Bean µÄ±à³Ì¼¼Êõ£¬ËüÉî¿ÌµØ¸Ä±ä×Å Java ¿ª·¢ÊÀ½ç¡£Spring ʹÓüòµ¥¡¢»ù±¾µÄ Java Bean À´Íê³ÉÒÔǰֻÓÐ EJB ²ÅÄÜÍê³ÉµÄ¹¤×÷£¬Ê¹µÃºÜ¶à¸´ÔӵĴúÂë±äµÃÓÅÑźͼò½à£¬±ÜÃâÁË EJB Ó·Öס¢µÍЧµÄ¿ª·¢Ä£Ê½£¬¼«´óµÄ·½±ãÏîÄ¿µÄºóÆÚά»¤¡¢Éý¼¶ºÍÀ©Õ¹¡£
+
+ÔÚʵ¼Ê¿ª·¢ÖУ¬·þÎñÆ÷¶ËÓ¦ÓóÌÐòͨ³£²ÉÓÃÈý²ãÌåϵ¼Ü¹¹£¬·Ö±ðΪ±íÏֲ㣨web£©¡¢ÒµÎñÂß¼²ã£¨service£©¡¢³Ö¾Ã²ã£¨dao£©¡£
+
+Spring ÖÂÁ¦ÓÚ Java EE Ó¦Óø÷²ãµÄ½â¾ö·½°¸£¬¶Ôÿһ²ã¶¼ÌṩÁ˼¼ÊõÖ§³Ö¡£
+
+* ÔÚ±íÏÖ²ãÌṩÁË¶Ô Spring MVC¡¢Struts2 µÈ¿ò¼ÜµÄÕûºÏ£»
+* ÔÚÒµÎñÂß¼²ãÌṩÁ˹ÜÀíÊÂÎñºÍ¼Ç¼ÈÕÖ¾µÄ¹¦ÄÜ£»
+* Ôڳ־ò㻹¿ÉÒÔÕûºÏ MyBatis¡¢Hibernate ºÍ JdbcTemplate µÈ¼¼Êõ£¬¶ÔÊý¾Ý¿â½øÐзÃÎÊ¡£
+
+Õâ³ä·ÖµØÌåÏÖÁË Spring ÊÇÒ»¸öÈ«ÃæµÄ½â¾ö·½°¸£¬¶ÔÓÚÄÇЩÒѾÓнϺýâ¾ö·½°¸µÄÁìÓò£¬Spring ¾ø²»×öÖØ¸´µÄÊÂÇé¡£
+
+´ÓÉè¼ÆÉÏ¿´£¬Spring ¿ò¼Ü¸øÓèÁË Java ³ÌÐòÔ±¸ü¸ßµÄ×ÔÓɶȣ¬¶ÔÒµ½çµÄ³£¼ûÎÊÌâÒ²ÌṩÁËÁ¼ºÃµÄ½â¾ö·½°¸£¬Òò´ËÔÚ¿ªÔ´ÉçÇøÊܵ½Á˹㷺µÄ»¶Ó£¬²¢ÇÒ±»´ó²¿·Ö¹«Ë¾×÷Ϊ Java ÏîÄ¿¿ª·¢µÄÊ×Ñ¡¿ò¼Ü¡£
+
+## Spring Framework µÄÌØµã
+
+Spring ¿ò¼Ü¾ßÓÐÒÔϼ¸¸öÌØµã¡£
+
+### **·½±ã½âñ¼ò»¯¿ª·¢**
+
+Spring ¾ÍÊÇÒ»¸ö´ó¹¤³§£¬¿ÉÒÔ½«ËùÓжÔÏóµÄ´´½¨ºÍÒÀÀµ¹ØÏµµÄά»¤½»¸ø Spring ¹ÜÀí¡£
+
+### **·½±ã¼¯³É¸÷ÖÖÓÅÐã¿ò¼Ü**
+
+Spring ²»Åųâ¸÷ÖÖÓÅÐãµÄ¿ªÔ´¿ò¼Ü£¬ÆäÄÚ²¿ÌṩÁ˶Ը÷ÖÖÓÅÐã¿ò¼Ü£¨Èç Struts2¡¢Hibernate¡¢MyBatis µÈ£©µÄÖ±½ÓÖ§³Ö¡£
+
+### **½µµÍ Java EE API µÄʹÓÃÄѶÈ**
+
+Spring ¶Ô Java EE ¿ª·¢Öзdz£ÄÑÓõÄһЩ API£¨JDBC¡¢JavaMail¡¢Ô¶³Ìµ÷Óõȣ©¶¼ÌṩÁË·â×°£¬Ê¹ÕâЩ API Ó¦ÓõÄÄѶȴó´ó½µµÍ¡£
+
+### **·½±ã³ÌÐòµÄ²âÊÔ**
+
+Spring Ö§³Ö JUnit4£¬¿ÉÒÔͨ¹ý×¢½â·½±ãµØ²âÊÔ Spring ³ÌÐò¡£
+
+### **AOP ±à³ÌµÄÖ§³Ö**
+
+Spring Ìá¹©ÃæÏòÇÐÃæ±à³Ì£¬¿ÉÒÔ·½±ãµØÊµÏÖ¶Ô³ÌÐò½øÐÐȨÏÞÀ¹½ØºÍÔËÐÐ¼à¿ØµÈ¹¦ÄÜ¡£
+
+### **ÉùÃ÷ʽÊÂÎñµÄÖ§³Ö**
+
+Ö»ÐèҪͨ¹ýÅäÖþͿÉÒÔÍê³É¶ÔÊÂÎñµÄ¹ÜÀí£¬¶øÎÞÐëÊÖ¶¯±à³Ì¡£
+
+Spring ¿ò¼Ü»ù±¾º¸ÇÁËÆóÒµ¼¶Ó¦Óÿª·¢µÄ¸÷¸ö·½Ã棬Ëü°üº¬ÁË 20 ¶à¸ö²»Í¬µÄÄ£¿é¡£
+
+spring-aop spring-context-indexer spring-instrument spring-orm spring-web
+spring-aspects spring-context-support spring-jcl spring-oxm spring-webflux
+spring-beans spring-core spring-jdbc spring-r2dbc spring-webmvc
+spring-context spring-expression spring-jms spring-test spring-websocket
+spring-messaging spring-tx
+
+
+ͼ1£ºSpring¼Ü¹¹Í¼
+
+ÉÏͼÖаüº¬ÁË Spring ¿ò¼ÜµÄËùÓÐÄ£¿é£¬ÕâЩģ¿é¿ÉÒÔÂú×ãÒ»ÇÐÆóÒµ¼¶Ó¦Óÿª·¢µÄÐèÇó£¬ÔÚ¿ª·¢¹ý³ÌÖпÉÒÔ¸ù¾ÝÐèÇóÓÐÑ¡ÔñÐÔµØÊ¹ÓÃËùÐèÒªµÄÄ£¿é¡£ÏÂÃæ·Ö±ð¶ÔÕâЩģ¿éµÄ×÷ÓýøÐмòµ¥½éÉÜ¡£
+
+## 1\. Data Access/Integration£¨Êý¾Ý·ÃÎÊ£¯¼¯³É£©
+
+Êý¾Ý·ÃÎÊ£¯¼¯³É²ã°üÀ¨ JDBC¡¢ORM¡¢OXM¡¢JMS ºÍ Transactions Ä£¿é£¬¾ßÌå½éÉÜÈçÏ¡£
+
+* JDBC Ä£¿é£ºÌṩÁËÒ»¸ö JBDC µÄÑùÀýÄ£°å£¬Ê¹ÓÃÕâЩģ°åÄÜÏû³ý´«Í³Èß³¤µÄ JDBC ±àÂ뻹ÓбØÐëµÄÊÂÎñ¿ØÖÆ£¬¶øÇÒÄÜÏíÊܵ½ Spring ¹ÜÀíÊÂÎñµÄºÃ´¦¡£
+* ORM Ä£¿é£ºÌṩÓëÁ÷Ðеġ°¶ÔÏó-¹ØÏµ¡±Ó³Éä¿ò¼ÜÎ޷켯³ÉµÄ API£¬°üÀ¨ JPA¡¢JDO¡¢Hibernate ºÍ MyBatis µÈ¡£¶øÇÒ»¹¿ÉÒÔʹÓà Spring ÊÂÎñ¹ÜÀí£¬ÎÞÐè¶îÍâ¿ØÖÆÊÂÎñ¡£
+* OXM Ä£¿é£ºÌṩÁËÒ»¸öÖ§³Ö Object /XML Ó³ÉäµÄ³éÏó²ãʵÏÖ£¬Èç JAXB¡¢Castor¡¢XMLBeans¡¢JiBX ºÍ XStream¡£½« Java ¶ÔÏóÓ³Éä³É XML Êý¾Ý£¬»òÕß½«XML Êý¾ÝÓ³Éä³É Java ¶ÔÏó¡£
+* JMS Ä£¿é£ºÖ¸ Java ÏûÏ¢·þÎñ£¬ÌṩһÌ× ¡°ÏûÏ¢Éú²úÕß¡¢ÏûÏ¢Ïû·ÑÕß¡±Ä£°åÓÃÓÚ¸ü¼Ó¼òµ¥µÄʹÓà JMS£¬JMS ÓÃÓÚÓÃÓÚÔÚÁ½¸öÓ¦ÓóÌÐòÖ®¼ä£¬»ò·Ö²¼Ê½ÏµÍ³Öз¢ËÍÏûÏ¢£¬½øÐÐÒ첽ͨÐÅ¡£
+* Transactions ÊÂÎñÄ£¿é£ºÖ§³Ö±à³ÌºÍÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£
+
+## 2\. Web Ä£¿é
+
+Spring µÄ Web ²ã°üÀ¨ Web¡¢Servlet¡¢WebSocket ºÍ Portlet ×é¼þ£¬¾ßÌå½éÉÜÈçÏ¡£
+
+* Web Ä£¿é£ºÌṩÁË»ù±¾µÄ Web ¿ª·¢¼¯³ÉÌØÐÔ£¬ÀýÈç¶àÎļþÉÏ´«¹¦ÄÜ¡¢Ê¹ÓÃµÄ Servlet ¼àÌýÆ÷µÄ IOC ÈÝÆ÷³õʼ»¯ÒÔ¼° Web Ó¦ÓÃÉÏÏÂÎÄ¡£
+* Servlet Ä£¿é£ºÌṩÁËÒ»¸ö Spring MVC Web ¿ò¼ÜʵÏÖ¡£Spring MVC ¿ò¼ÜÌṩÁË»ùÓÚ×¢½âµÄÇëÇó×ÊÔ´×¢Èë¡¢¸ü¼òµ¥µÄÊý¾Ý°ó¶¨¡¢Êý¾ÝÑéÖ¤µÈ¼°Ò»Ì׷dz£Ò×ÓÃµÄ JSP ±êÇ©£¬ÍêÈ«ÎÞ·ìÓë Spring ÆäËû¼¼ÊõÐ×÷¡£
+* WebSocket Ä£¿é£ºÌṩÁ˼òµ¥µÄ½Ó¿Ú£¬Óû§Ö»ÒªÊµÏÖÏìÓ¦µÄ½Ó¿Ú¾Í¿ÉÒÔ¿ìËٵĴ WebSocket Server£¬´Ó¶øÊµÏÖË«ÏòͨѶ¡£
+* Portlet Ä£¿é£ºÌṩÁËÔÚ Portlet »·¾³ÖÐʹÓà MVC ʵÏÖ£¬ÀàËÆ Web-Servlet Ä£¿éµÄ¹¦ÄÜ¡£
+
+## 3\. Core Container£¨Spring µÄºËÐÄÈÝÆ÷£©
+
+Spring µÄºËÐÄÈÝÆ÷ÊÇÆäËûÄ£¿é½¨Á¢µÄ»ù´¡£¬ÓÉ Beans Ä£¿é¡¢Core ºËÐÄÄ£¿é¡¢Context ÉÏÏÂÎÄÄ£¿éºÍ SpEL ±í´ïʽÓïÑÔÄ£¿é×é³É£¬Ã»ÓÐÕâЩºËÐÄÈÝÆ÷£¬Ò²²»¿ÉÄÜÓÐ AOP¡¢Web µÈÉϲãµÄ¹¦ÄÜ¡£¾ßÌå½éÉÜÈçÏ¡£
+
+* Beans Ä£¿é£ºÌṩÁË¿ò¼ÜµÄ»ù´¡²¿·Ö£¬°üÀ¨¿ØÖÆ·´×ªºÍÒÀÀµ×¢Èë¡£
+* Core ºËÐÄÄ£¿é£º·â×°ÁË Spring ¿ò¼ÜµÄµ×²ã²¿·Ö£¬°üÀ¨×ÊÔ´·ÃÎÊ¡¢ÀàÐÍת»»¼°Ò»Ð©³£Óù¤¾ßÀà¡£
+* Context ÉÏÏÂÎÄÄ£¿é£º½¨Á¢ÔÚ Core ºÍ Beans Ä£¿éµÄ»ù´¡Ö®ÉÏ£¬¼¯³É Beans Ä£¿é¹¦Äܲ¢Ìí¼Ó×ÊÔ´°ó¶¨¡¢Êý¾ÝÑéÖ¤¡¢¹ú¼Ê»¯¡¢Java EE Ö§³Ö¡¢ÈÝÆ÷ÉúÃüÖÜÆÚ¡¢Ê¼þ´«²¥µÈ¡£ApplicationContext ½Ó¿ÚÊÇÉÏÏÂÎÄÄ£¿éµÄ½¹µã¡£
+* SpEL Ä£¿é£ºÌṩÁËÇ¿´óµÄ±í´ïʽÓïÑÔÖ§³Ö£¬Ö§³Ö·ÃÎʺÍÐÞ¸ÄÊôÐÔÖµ£¬·½·¨µ÷Óã¬Ö§³Ö·ÃÎʼ°ÐÞ¸ÄÊý×é¡¢ÈÝÆ÷ºÍË÷ÒýÆ÷£¬ÃüÃû±äÁ¿£¬Ö§³ÖËãÊýºÍÂß¼ÔËË㣬֧³Ö´Ó Spring ÈÝÆ÷»ñÈ¡ Bean£¬ËüÒ²Ö§³ÖÁбíͶӰ¡¢Ñ¡ÔñºÍÒ»°ãµÄÁбí¾ÛºÏµÈ¡£
+
+## 4\. AOP¡¢Aspects¡¢Instrumentation ºÍ Messaging
+
+ÔÚ Core Container Ö®ÉÏÊÇ AOP¡¢Aspects µÈÄ£¿é£¬¾ßÌå½éÉÜÈçÏ£º
+
+* AOP Ä£¿é£ºÌṩÁËÃæÏòÇÐÃæ±à³ÌʵÏÖ£¬Ìṩ±ÈÈçÈÕÖ¾¼Ç¼¡¢È¨ÏÞ¿ØÖÆ¡¢ÐÔÄÜͳ¼ÆµÈͨÓù¦ÄܺÍÒµÎñÂß¼·ÖÀëµÄ¼¼Êõ£¬²¢ÇÒÄܶ¯Ì¬µÄ°ÑÕâЩ¹¦ÄÜÌí¼Óµ½ÐèÒªµÄ´úÂëÖУ¬ÕâÑù¸÷˾ÆäÖ°£¬½µµÍÒµÎñÂß¼ºÍͨÓù¦ÄܵÄñîºÏ¡£
+* Aspects Ä£¿é£ºÌṩÓë AspectJ µÄ¼¯³É£¬ÊÇÒ»¸ö¹¦ÄÜÇ¿´óÇÒ³ÉÊìµÄÃæÏòÇÐÃæ±à³Ì£¨AOP£©¿ò¼Ü¡£
+* Instrumentation Ä£¿é£ºÌṩÁËÀ๤¾ßµÄÖ§³ÖºÍÀà¼ÓÔØÆ÷µÄʵÏÖ£¬¿ÉÒÔÔÚÌØ¶¨µÄÓ¦Ó÷þÎñÆ÷ÖÐʹÓá£
+* messaging Ä£¿é£ºSpring 4.0 ÒÔºóÐÂÔöÁËÏûÏ¢£¨Spring-messaging£©Ä£¿é£¬¸ÃÄ£¿éÌṩÁ˶ÔÏûÏ¢´«µÝÌåϵ½á¹¹ºÍÐÒéµÄÖ§³Ö¡£
+
+## 5\. Test Ä£¿é
+
+Test Ä£¿é£ºSpring Ö§³Ö Junit ºÍ TestNG ²âÊÔ¿ò¼Ü£¬¶øÇÒ»¹¶îÍâÌṩÁËһЩ»ùÓÚ Spring µÄ²âÊÔ¹¦ÄÜ£¬±ÈÈçÔÚ²âÊÔ Web ¿ò¼Üʱ£¬Ä£Äâ Http ÇëÇóµÄ¹¦ÄÜ¡£
\ No newline at end of file
diff --git "a/docs/spring/springMVC/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md" "b/docs/spring/springMVC/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
new file mode 100644
index 0000000..6bd5272
--- /dev/null
+++ "b/docs/spring/springMVC/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
@@ -0,0 +1,232 @@
+## 1. ¸ÅÊö
+ ÔÚ±¾½Ì³ÌÖУ¬ÎÒÃǽ«Ì½Ë÷ org.springframework.web.bind.annotation °üÖÐµÄ Spring Web ×¢ÊÍ¡£
+
+## 2. @RequestMapping
+
+¼òµ¥µØËµ£¬@RequestMapping ±ê¼Ç@Controller ÀàÄÚ²¿µÄÇëÇó´¦Àí³ÌÐò·½·¨£» Ëü¿ÉÒÔʹÓÃÅäÖãº
+
+·¾¶£¬»òÆä±ðÃû¡¢Ãû³ÆºÍÖµ£º·½·¨Ó³Éäµ½Äĸö URL
+·½·¨£º¼æÈÝµÄ HTTP ·½·¨
+params£º¸ù¾Ý HTTP ²ÎÊýµÄ´æÔÚ¡¢²»´æÔÚ»òÖµ¹ýÂËÇëÇó
+headers£º¸ù¾Ý HTTP ±êÍ·µÄ´æÔÚ¡¢²»´æÔÚ»òÖµ¹ýÂËÇëÇó
+ÏûºÄ£º¸Ã·½·¨¿ÉÒÔÔÚ HTTP ÇëÇóÕýÎÄÖÐÏûºÄÄÄЩýÌåÀàÐÍ
+produces£º¸Ã·½·¨¿ÉÒÔÔÚ HTTP ÏìÓ¦ÕýÎÄÖÐÉú³ÉÄÄЩýÌåÀàÐÍ
+ÕâÊÇÒ»¸ö¼òµ¥µÄʾÀý£º
+
+````
+@Controller
+class VehicleController {
+
+ @RequestMapping(value = "/vehicles/home", method = RequestMethod.GET)
+ String home() {
+ return "home";
+ }
+}
+````
+Èç¹ûÎÒÃÇÔÚÀ༶±ðÓ¦ÓôË×¢ÊÍ£¬ÎÒÃÇ¿ÉÒÔΪ @Controller ÀàÖеÄËùÓд¦Àí³ÌÐò·½·¨ÌṩĬÈÏÉèÖᣠΨһµÄÀýÍâÊÇ Spring ²»»áʹÓ÷½·¨¼¶±ðÉèÖø²¸Çµ«»á¸½¼ÓÁ½¸ö·¾¶²¿·ÖµÄ URL¡£
+
+ÀýÈ磬ÏÂÃæµÄÅäÖúÍÉÏÃæµÄЧ¹ûÊÇÒ»ÑùµÄ£º
+
+````
+@Controller
+@RequestMapping(value = "/vehicles", method = RequestMethod.GET)
+class VehicleController {
+
+ @RequestMapping("/home")
+ String home() {
+ return "home";
+ }
+}
+````
+
+´ËÍ⣬@GetMapping¡¢@PostMapping¡¢@PutMapping¡¢@DeleteMapping ºÍ@PatchMapping ÊÇ@RequestMapping µÄ²»Í¬±äÌ壬ÆäHTTP ·½·¨ÒÑ·Ö±ðÉèÖÃΪGET¡¢POST¡¢PUT¡¢DELETE ºÍPATCH¡£
+
+ÕâЩ´Ó Spring 4.3 °æ±¾¿ªÊ¼¿ÉÓá£
+
+## 3 @RequestBody
+
+ÈÃÎÒÃǼÌÐø@RequestBody¡ª¡ªËü½« HTTP ÇëÇóµÄÖ÷ÌåÓ³Éäµ½Ò»¸ö¶ÔÏó£º
+
+````
+@PostMapping("/save")
+void saveVehicle(@RequestBody Vehicle vehicle) {
+// ...
+}
+````
+·´ÐòÁл¯ÊÇ×Ô¶¯µÄ£¬È¡¾öÓÚÇëÇóµÄÄÚÈÝÀàÐÍ¡£
+
+## 4 @PathVariable
+½ÓÏÂÀ´ËµËµ@PathVariable¡£
+
+´Ë×¢ÊÍָʾ·½·¨²ÎÊý°ó¶¨µ½ URI Ä£°å±äÁ¿¡£ ÎÒÃÇ¿ÉÒÔʹÓà @RequestMapping ×¢ÊÍÖ¸¶¨ URI Ä£°å£¬²¢Ê¹Óà @PathVariable ½«·½·¨²ÎÊý°ó¶¨µ½Ä£°å²¿·ÖÖ®Ò»¡£
+
+ÎÒÃÇ¿ÉÒÔʹÓÃÃû³Æ»òÆä±ðÃû£¬¼´Öµ²ÎÊýÀ´ÊµÏÖÕâÒ»µã£º
+
+````
+@RequestMapping("/{id}")
+Vehicle getVehicle(@PathVariable("id") long id) {
+// ...
+}
+````
+Èç¹ûÄ£°åÖв¿·ÖµÄÃû³ÆÓë·½·¨²ÎÊýµÄÃû³ÆÏàÆ¥Å䣬ÎÒÃǾͲ»±ØÔÚ×¢ÊÍÖÐÖ¸¶¨Ëü£º
+
+````
+@RequestMapping("/{id}")
+Vehicle getVehicle(@PathVariable long id) {
+// ...
+}
+````
+´ËÍ⣬ÎÒÃÇ¿ÉÒÔͨ¹ý½«ËùÐèµÄ²ÎÊýÉèÖÃΪ false À´½«Â·¾¶±äÁ¿±ê¼ÇΪ¿ÉÑ¡£º
+
+````
+@RequestMapping("/{id}")
+Vehicle getVehicle(@PathVariable(required = false) long id) {
+// ...
+}
+````
+## 5. @RequestParam
+ We use @RequestParam for accessing HTTP request parameters:
+````
+@RequestMapping
+Vehicle getVehicleByParam(@RequestParam("id") long id) {
+// ...
+}
+````
+Ëü¾ßÓÐÓë @PathVariable ×¢ÊÍÏàͬµÄÅäÖÃÑ¡Ïî¡£
+
+³ýÁËÕâЩÉèÖÃÖ®Í⣬µ± Spring ÔÚÇëÇóÖз¢ÏÖûÓÐÖµ»òΪ¿Õֵʱ£¬ÎÒÃÇ¿ÉÒÔʹÓà @RequestParam Ö¸¶¨×¢ÈëÖµ¡£ Ϊ´Ë£¬ÎÒÃDZØÐëÉèÖà defaultValue ²ÎÊý¡£
+
+ÌṩĬÈÏÖµÒþʽÉèÖà required Ϊ false£º
+````
+@RequestMapping("/buy")
+Car buyCar(@RequestParam(defaultValue = "5") int seatCount) {
+// ...
+}
+````
+³ýÁ˲ÎÊýÖ®Í⣬ÎÒÃÇ»¹¿ÉÒÔ·ÃÎÊÆäËû HTTP ÇëÇ󲿷֣ºcookie ºÍ±êÍ·¡£
+
+ÎÒÃÇ¿ÉÒÔ·Ö±ðʹÓÃ×¢½â@CookieValue ºÍ@RequestHeader À´·ÃÎÊËüÃÇ¡£
+
+
+## 6. Response Handling Annotations
+ÔÚ½ÓÏÂÀ´µÄ²¿·ÖÖУ¬ÎÒÃǽ«¿´µ½ÔÚ Spring MVC ÖвÙ×÷ HTTP ÏìÓ¦µÄ×î³£¼û×¢ÊÍ¡£
+
+### 6.1 @ResponseBody
+Èç¹ûÎÒÃÇÓÃ@ResponseBody ±ê¼ÇÇëÇó´¦Àí³ÌÐò·½·¨£¬Spring »á½«·½·¨µÄ½á¹ûÊÓΪÏìÓ¦±¾Éí£º
+
+````
+@ResponseBody
+@RequestMapping("/hello")
+String hello() {
+return "Hello World!";
+}
+````
+Èç¹ûÎÒÃÇÓÃÕâ¸ö×¢½âÀ´×¢½â @Controller À࣬ËùÓÐÇëÇó´¦Àí³ÌÐò·½·¨¶¼½«Ê¹ÓÃËü¡£
+
+### 6.2 @ExceptionHandler
+
+ʹÓôË×¢ÊÍ£¬ÎÒÃÇ¿ÉÒÔÉùÃ÷Ò»¸ö×Ô¶¨Òå´íÎó´¦Àí³ÌÐò·½·¨¡£ µ±ÇëÇó´¦Àí³ÌÐò·½·¨Å׳öÈκÎÖ¸¶¨µÄÒ쳣ʱ£¬Spring µ÷Óô˷½·¨¡£
+
+²¶»ñµÄÒì³£¿ÉÒÔ×÷Ϊ²ÎÊý´«µÝ¸ø·½·¨£º
+````
+@ExceptionHandler(IllegalArgumentException.class)
+void onIllegalArgumentException(IllegalArgumentException exception) {
+// ...
+}
+````
+
+### 6.3 @ResponseStatus
+Èç¹ûÎÒÃÇʹÓôË×¢ÊͶÔÇëÇó´¦Àí³ÌÐò·½·¨½øÐÐ×¢ÊÍ£¬Ôò¿ÉÒÔÖ¸¶¨ÏìÓ¦µÄËùÐè HTTP ״̬¡£ ÎÒÃÇ¿ÉÒÔʹÓà code ²ÎÊý»òÆä±ðÃû value ²ÎÊýÀ´ÉùÃ÷״̬´úÂë¡£
+
+´ËÍ⣬ÎÒÃÇ¿ÉÒÔʹÓà reason ²ÎÊýÌṩÔÒò¡£
+
+ÎÒÃÇÒ²¿ÉÒÔ½«ËüÓë@ExceptionHandler Ò»ÆðʹÓãº
+
+@ExceptionHandler(IllegalArgumentException.class)
+@ResponseStatus(HttpStatus.BAD_REQUEST)
+void onIllegalArgumentException(IllegalArgumentException exception) {
+// ...
+}
+
+ÓÐ¹Ø HTTP ÏìӦ״̬µÄ¸ü¶àÐÅÏ¢£¬Çë·ÃÎʱ¾ÎÄ¡£
+
+## 7 ÆäËû Web×¢½â
+һЩעÊͲ»Ö±½Ó¹ÜÀí HTTP ÇëÇó»òÏìÓ¦¡£ ÔÚ½ÓÏÂÀ´µÄ²¿·ÖÖУ¬ÎÒÃǽ«½éÉÜ×î³£¼ûµÄ¡£
+
+### 7.1 @Controller
+ÎÒÃÇ¿ÉÒÔʹÓÃ@Controller ¶¨ÒåÒ»¸öSpring MVC ¿ØÖÆÆ÷¡£ Óйظü¶àÐÅÏ¢£¬Çë·ÃÎÊÎÒÃǹØÓÚ Spring Bean Annotations µÄÎÄÕ¡£
+
+### 7.2 @RestController
+@RestController ½áºÏÁË@Controller ºÍ@ResponseBody¡£
+
+Òò´Ë£¬ÒÔÏÂÉùÃ÷ÊǵÈЧµÄ£º
+
+````
+@Controller
+@ResponseBody
+class VehicleRestController {
+// ...
+}
+````
+
+````
+@RestController
+class VehicleRestController {
+// ...
+}
+````
+### 7.3 @ModelAttribute
+ͨ¹ýÕâ¸ö×¢½â£¬ÎÒÃÇ¿ÉÒÔͨ¹ýÌṩģÐͼüÀ´·ÃÎÊÒѾ´æÔÚÓÚ MVC @Controller Ä£ÐÍÖеÄÔªËØ£º
+
+````
+@PostMapping("/assemble")
+void assembleVehicle(@ModelAttribute("vehicle") Vehicle vehicleInModel) {
+// ...
+}
+````
+Óë@PathVariable ºÍ@RequestParam Ò»Ñù£¬Èç¹û²ÎÊý¾ßÓÐÏàͬµÄÃû³Æ£¬ÎÒÃDz»±ØÖ¸¶¨Ä£Ðͼü£º
+
+````
+@PostMapping("/assemble")
+void assembleVehicle(@ModelAttribute Vehicle vehicle) {
+// ...
+}
+````
+´ËÍ⣬@ModelAttribute»¹ÓÐÒ»¸öÓÃ;£ºÈç¹ûÎÒÃÇÓÃËü×¢½âÒ»¸ö·½·¨£¬Spring»á×Ô¶¯½«·½·¨µÄ·µ»ØÖµÌí¼Óµ½Ä£ÐÍÖУº
+
+````
+@ModelAttribute("vehicle")
+Vehicle getVehicle() {
+// ...
+}
+````
+ºÍÒÔǰһÑù£¬ÎÒÃDz»±ØÖ¸¶¨Ä£Ðͼü£¬Spring ĬÈÏʹÓ÷½·¨µÄÃû³Æ£º
+````
+@ModelAttribute
+Vehicle vehicle() {
+// ...
+}
+````
+ÔÚ Spring µ÷ÓÃÇëÇó´¦Àí³ÌÐò·½·¨Ö®Ç°£¬Ëü»áµ÷ÓÃÀàÖÐËùÓÐ @ModelAttribute ×¢Ê͵ķ½·¨¡£
+
+ÓÐ¹Ø @ModelAttribute µÄ¸ü¶àÐÅÏ¢£¬Çë²ÎÔı¾ÎÄ¡£
+
+### 7.4 @CrossOrigin
+@CrossOrigin Ϊ´ø×¢Ê͵ÄÇëÇó´¦Àí³ÌÐò·½·¨ÆôÓÿçÓòͨÐÅ£º
+
+````
+@CrossOrigin
+@RequestMapping("/hello")
+String hello() {
+return "Hello World!";
+}
+````
+Èç¹ûÎÒÃÇÓÃËü±ê¼ÇÒ»¸öÀ࣬ËüÊÊÓÃÓÚÆäÖеÄËùÓÐÇëÇó´¦Àí³ÌÐò·½·¨¡£
+
+ÎÒÃÇ¿ÉÒÔʹÓôË×¢Ê͵IJÎÊý΢µ÷ CORS ÐÐΪ¡£
+
+ÓйØÏêϸÐÅÏ¢£¬Çë·ÃÎʱ¾ÎÄ¡£
+
+
+# ²Î¿¼ÎÄÕÂ
+https://www.baeldung.com/spring-annotations
diff --git "a/docs/spring/\347\254\254\344\270\200\344\270\252Spring\345\272\224\347\224\250.md" "b/docs/spring/\347\254\254\344\270\200\344\270\252Spring\345\272\224\347\224\250.md"
new file mode 100644
index 0000000..b40a369
--- /dev/null
+++ "b/docs/spring/\347\254\254\344\270\200\344\270\252Spring\345\272\224\347\224\250.md"
@@ -0,0 +1,70 @@
+## Ìí¼ÓÒÀÀµ
+ÕâÀïÎÒÃÇ¿ÉÒÔÏ顄 Spring »ù´¡ Jar °üÒÔ¼° Commons-loggin µ¼Èëµ½ÏîÄ¿ÖУ¬ÈôºóÐø¹¦ÄÜÔö¼Ó£¬Ôò¸ù¾ÝÐèÒªÔÙµ¼Èë Spring µÄÆäËû Jar¡£
+
+````
+org.springframework.core-5.3.13.jar
+org.springframework.beans-5.3.13.jar
+spring-context-5.3.13.jar
+spring-expression-5.3.13.jar
+commons.logging-1.2.jar
+````
+µ±È»ÕâÀïÎÒÃÇÍÆ¼öʹÓÃmaven¹ÜÀíÒÀÀµ
+
+## ´´½¨ Java Àà
+ ÔÚ HelloSpring Öд´½¨ net.biancheng.c °ü£¬È»ºóÔÚÕâ¸ö°üÏ´´½¨ HelloWorld.java ºÍ MainApp.java Àà¡£
+
+HelloWorld.java ÀàµÄ´úÂëÈçÏÂ
+````
+package net.biancheng.c;
+public class HelloWorld {
+ private String message;
+ public void setMessage(String message) {
+ this.message = message;
+ }
+ public void getMessage() {
+ System.out.println("message : " + message);
+ }
+}
+````
+MainApp.java ÀàµÄ´úÂëÈçÏÂ
+````
+package net.biancheng.c;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+ public class MainApp {
+ public static void main(String[] args) {
+ ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
+ HelloWorld obj = context.getBean("helloWorld",HelloWorld.class);
+ obj.getMessage();
+ }
+ }
+````
+¹ØÓÚÒÔÉÏ´úÂ룬ÐèҪעÒâÒÔÏÂÁ½µã£º
+
+´´½¨ ApplicationContext ¶ÔÏóʱʹÓÃÁË ClassPathXmlApplicationContext À࣬Õâ¸öÀàÓÃÓÚ¼ÓÔØ Spring ÅäÖÃÎļþ¡¢´´½¨ºÍ³õʼ»¯ËùÓжÔÏó£¨Bean£©¡£
+ApplicationContext.getBean() ·½·¨ÓÃÀ´»ñÈ¡ Bean£¬¸Ã·½·¨·µ»ØÖµÀàÐÍΪ Object£¬Í¨¹ýÇ¿ÖÆÀàÐÍת»»Îª HelloWorld µÄʵÀý¶ÔÏ󣬵÷ÓÃÆäÖÐµÄ getMessage() ·½·¨¡£
+
+## ´´½¨ÅäÖÃÎļþ
+
+ÔÚ src Ŀ¼Ï£¬´´½¨Ò»¸ö Spring ÅäÖÃÎļþ Beans.xml£¬ÄÚÈÝÈçÏ¡£
+````
+
+
+
+
+
+
+````
+ÎÒÃÇÒ²¿ÉÒÔ½«¸ÃÅäÖÃÎļþÃüÃûΪÆäËüÓÐЧµÄÃû³Æ£¬µ«ÐèҪעÒâµÄÊÇ£¬¸ÃÎļþÃû±ØÐëÓë MainApp.java ÖжÁÈ¡µÄÅäÖÃÎļþÃû³ÆÒ»Ö¡£
+
+Beans.xml ÓÃÓÚ¸ø²»Í¬µÄ Bean ·ÖÅäΨһµÄ ID£¬²¢¸øÏàÓ¦µÄ Bean ÊôÐÔ¸³Öµ¡£ÀýÈ磬ÔÚÒÔÉÏ´úÂëÖУ¬ÎÒÃÇ¿ÉÒÔÔÚ²»Ó°ÏìÆäËüÀàµÄÇé¿öÏ£¬¸ø message ±äÁ¿¸³Öµ¡£
+## ÔËÐгÌÐò
+
+ ÔËÐÐ MainApp.java£¬Eclipse IDE ¿ØÖÆÌ¨ÖÐÏÔʾÐÅÏ¢ÈçÏ¡£
+ message : Hello World!
+
+ÖÁ´Ë£¬ÎÒÃǾͳɹ¦´´½¨Á˵ÚÒ»¸ö Spring Ó¦ÓóÌÐò¡£
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index de1628d..a91c75e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,8 +7,28 @@
groupId
JavaTutorial
1.0-SNAPSHOT
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.0.5
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
com.github.houbb
markdown-toc
@@ -51,5 +71,13 @@
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
\ No newline at end of file
diff --git a/src/main/java/Test.java b/src/main/java/Test.java
new file mode 100644
index 0000000..269694c
--- /dev/null
+++ b/src/main/java/Test.java
@@ -0,0 +1,22 @@
+import org.springframework.beans.factory.annotation.Lookup;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author hpl
+ * @date 2023/4/15 14:40
+ */
+@Service
+public class Test {
+
+
+
+
+ public static void main(String[] args) {
+
+ }
+
+
+ public void test(){
+
+ }
+}
From 84e1254e8691ae7e4dad0803dc17c2c8ef33b29a Mon Sep 17 00:00:00 2001
From: h2pl <362294931@qq.com>
Date: Thu, 20 Apr 2023 21:35:59 +0800
Subject: [PATCH 03/32] done
---
ReadMe.md | 69 +-
...10\346\240\270\345\277\203\357\274\211.md" | 7 +-
...\260\203\345\272\246\344\270\216@Async.md" | 240 +
...45\345\277\227\347\256\241\347\220\206.md" | 806 +++
...\210\260\345\244\226\351\203\250Tomcat.md" | 302 +
...42\203\345\267\245\345\205\267Actuator.md" | 5832 +++++++++++++++++
...232\204Starter\346\234\272\345\210\266.md" | 262 +
...72\346\234\254\344\275\277\347\224\250.md" | 122 +-
...07\344\273\266\347\256\241\347\220\206.md" | 2989 +++++++++
...50\347\275\262\345\267\245\345\205\267.md" | 345 +
...52\345\212\250\347\224\237\346\210\220.md" | 625 ++
...345\267\245\345\205\267SpringBootAdmin.md" | 294 +
...45\350\257\206\346\270\205\345\215\225.md" | 0
...05\345\214\226\345\212\237\350\203\275.md" | 179 +
...70\347\224\250\345\212\237\350\203\275.md" | 594 ++
...70\345\244\204\347\220\206\345\231\250.md" | 235 +
...04\346\213\246\346\210\252\345\231\250.md" | 88 +
...76\350\247\243\346\236\220\345\231\250.md" | 181 +
...\277\207\346\273\244\345\231\250Filter.md" | 151 +
...53\351\200\237\345\205\245\351\227\250.md" | 1153 ++++
...07\344\273\266\344\270\212\344\274\240.md" | 237 +
...70\350\247\201\346\263\250\350\247\243.md" | 0
...\243\347\241\256\347\232\204Controller.md" | 0
...67\346\261\202\350\275\254\345\217\221.md" | 0
...4\232SpringMVC\346\246\202\350\277\260.md" | 0
...43\346\236\220\345\216\237\347\220\206.md" | 0
...5\277\265\344\270\216DispatcherServlet.md" | 0
...6@ResponseBody\346\263\250\350\247\243.md" | 0
...75\347\232\204\346\224\257\346\214\201.md" | 32 +-
...57\345\242\203\345\217\230\351\207\217.md" | 15 +-
...04\347\220\206\346\234\272\345\210\266.md" | 34 +-
...54\346\225\260\346\215\256\357\274\211.md" | 20 +-
...72\346\234\254\347\224\250\346\263\225.md" | 488 +-
.../spring/Spring\346\246\202\350\277\260.md" | 36 +-
...37\347\220\206\350\257\246\350\247\243.md" | 0
...37\347\220\206\350\257\246\350\247\243.md" | 0
...4\232SpringAOP\346\246\202\350\277\260.md" | 0
...40\350\275\275\350\277\207\347\250\213.md" | 0
...13\345\212\241\346\246\202\350\277\260.md" | 0
...20\347\240\201\345\211\226\346\236\220.md" | 0
...\274\232Spring\346\246\202\350\277\260.md" | 0
...70\345\277\203\346\265\201\347\250\213.md" | 0
...07\347\250\213\345\210\206\346\236\220.md" | 0
43 files changed, 14849 insertions(+), 487 deletions(-)
create mode 100644 "docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\344\273\273\345\212\241\350\260\203\345\272\246\344\270\216@Async.md"
create mode 100644 "docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\346\227\245\345\277\227\347\256\241\347\220\206.md"
create mode 100644 "docs/spring/SpringBoot/SpringBoot\345\272\224\347\224\250\344\271\237\345\217\257\344\273\245\351\203\250\347\275\262\345\210\260\345\244\226\351\203\250Tomcat.md"
create mode 100644 "docs/spring/SpringBoot/SpringBoot\347\224\237\344\272\247\347\216\257\345\242\203\345\267\245\345\205\267Actuator.md"
create mode 100644 "docs/spring/SpringBoot/SpringBoot\347\232\204Starter\346\234\272\345\210\266.md"
create mode 100644 "docs/spring/SpringBoot/SpringBoot\347\232\204\351\205\215\347\275\256\346\226\207\344\273\266\347\256\241\347\220\206.md"
create mode 100644 "docs/spring/SpringBoot/SpringBoot\350\207\252\345\270\246\347\232\204\347\203\255\351\203\250\347\275\262\345\267\245\345\205\267.md"
create mode 100644 "docs/spring/SpringBoot/SpringBoot\351\233\206\346\210\220Swagger\345\256\236\347\216\260API\346\226\207\346\241\243\350\207\252\345\212\250\347\224\237\346\210\220.md"
create mode 100644 "docs/spring/SpringBoot/\345\237\272\344\272\216SpringBoot\344\270\255\347\232\204\345\274\200\346\272\220\347\233\221\346\216\247\345\267\245\345\205\267SpringBootAdmin.md"
rename "docs/spring/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md" => "docs/spring/SpringBoot/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md" (100%)
create mode 100644 "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\233\275\351\231\205\345\214\226\345\212\237\350\203\275.md"
create mode 100644 "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\270\270\347\224\250\345\212\237\350\203\275.md"
create mode 100644 "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\274\202\345\270\270\345\244\204\347\220\206\345\231\250.md"
create mode 100644 "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\346\213\246\346\210\252\345\231\250.md"
create mode 100644 "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\231\250.md"
create mode 100644 "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\277\207\346\273\244\345\231\250Filter.md"
create mode 100644 "docs/spring/SpringMVC/SpringMVC\345\237\272\346\234\254\344\273\213\347\273\215\344\270\216\345\277\253\351\200\237\345\205\245\351\227\250.md"
create mode 100644 "docs/spring/SpringMVC/SpringMVC\345\246\202\344\275\225\345\256\236\347\216\260\346\226\207\344\273\266\344\270\212\344\274\240.md"
rename "docs/spring/springMVC/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md" => "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md" (100%)
rename "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md" => "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md" (100%)
rename "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md" => "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md" (100%)
rename "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md" => "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md" (100%)
rename "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md" => "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md" (100%)
rename "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md" => "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md" (100%)
rename "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md" => "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" => "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md" => "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md" => "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md" => "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md" => "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md" => "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md" => "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md" => "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md" => "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md" (100%)
diff --git a/ReadMe.md b/ReadMe.md
index c8ec78e..c73d49b 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -144,32 +144,67 @@
### Spring
-* [Spring常�注解.md](docs/spring/Spring常�注解.md)
+* [SpringAOP的概念与作用](docs/spring/Spring常�注解.md)
+* [SpringBean的定义与管ç�†ï¼ˆæ ¸å¿ƒï¼‰](docs/spring/Spring常è§�注解.md)
+* [Springä¸å¯¹äºŽæ•°æ�®åº“的访问](docs/spring/Spring常è§�注解.md)
+* [Springä¸å¯¹äºŽæ ¡éªŒåŠŸèƒ½çš„æ”¯æŒ�](docs/spring/Spring常è§�注解.md)
+* [Springä¸çš„Environment环境å�˜é‡�](docs/spring/Spring常è§�注解.md)
+* [Springä¸çš„事件处ç�†æœºåˆ¶](docs/spring/Spring常è§�注解.md)
+* [Springä¸çš„资æº�管ç�†](docs/spring/Spring常è§�注解.md)
+* [Springä¸çš„é…�置元数æ�®ï¼ˆç®¡ç�†é…�置的基本数æ�®ï¼‰](docs/spring/Spring常è§�注解.md)
+* [Spring事务基本用法](docs/spring/Spring常�注解.md)
+* [Spring�集](docs/spring/Spring常�注解.md)
+* [Spring容器与IOC](docs/spring/Spring常�注解.md)
+* [Spring常�注解](docs/spring/Spring常�注解.md)
+* [Spring概述](docs/spring/Spring常�注解.md)
+* [第一个Spring应用](docs/spring/Spring常�注解.md)
+
+* [Springæº�ç �剖æž�:Spring概述](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring概述.md)
+* [Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程.md)
+* [Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹ ](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹.md)
+* [Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�.md)
+* [Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£ ](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£.md)
+* [Springæº�ç �剖æž�:SpringAOP概述](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:SpringAOP概述.md)
+* [Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£ ](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£.md)
+* [Springæº�ç �剖æž�:Spring事务概述](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring事务概述.md)
+* [Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�.md)
+### SpringMVC
-* [Springæº�ç �剖æž�:Spring概述](docs/spring/Springæº�ç �剖æž�:Spring概述.md)
-* [Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程](docs/spring/Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程.md)
-* [Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹ ](docs/spring/Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹.md)
-* [Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�](docs/spring/Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�.md)
-* [Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£ ](docs/spring/Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£.md)
-* [Springæº�ç �剖æž�:SpringAOP概述](docs/spring/Springæº�ç �剖æž�:SpringAOP概述.md)
-* [Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£ ](docs/spring/Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£.md)
-* [Springæº�ç �剖æž�:Spring事务概述](docs/spring/Springæº�ç �剖æž�:Spring事务概述.md)
-* [Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�](docs/spring/Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�.md)
+* [SpringMVCä¸çš„国际化功能](docs/spring/SpringMVC/SpringMVCä¸çš„国际化功能.md)
+* [SpringMVCä¸çš„异常处ç�†å™¨](docs/spring/SpringMVC/SpringMVCä¸çš„异常处ç�†å™¨.md)
+* [SpringMVCä¸çš„æ‹¦æˆªå™¨](docs/spring/SpringMVC/SpringMVCä¸çš„æ‹¦æˆªå™¨.md)
+* [SpringMVCä¸çš„视图解æž�器](docs/spring/SpringMVC/SpringMVCä¸çš„视图解æž�器.md)
+* [SpringMVCä¸çš„过滤器Filter](docs/spring/SpringMVC/SpringMVCä¸çš„过滤器Filter.md)
+* [SpringMVC基本介�与快速入门](docs/spring/SpringMVC/SpringMVC基本介�与快速入门.md)
+* [SpringMVCå¦‚ä½•å®žçŽ°æ–‡ä»¶ä¸Šä¼ ](docs/spring/SpringMVC/SpringMVCå¦‚ä½•å®žçŽ°æ–‡ä»¶ä¸Šä¼ .md)
+* [SpringMVCä¸çš„常用功能](docs/spring/SpringMVC/SpringMVCä¸çš„常用功能.md)
-### SpringMVC
-* [SpringMVCæº�ç �分æž�:SpringMVC概述](docs/spring/springMVC/SpringMVCæº�ç �分æž�:SpringMVC概述.md)
-* [SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet](docs/spring/springMVC/SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet.md)
-* [SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘ ](docs/spring/springMVC/SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘.md)
-* [SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller ](docs/spring/springMVC/SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller.md)
-* [SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解](docs/spring/springMVC/SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解.md)
-* [SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�† ](docs/spring/springMVC/SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�†.md)
+* [SpringMVCæº�ç �分æž�:SpringMVC概述](docs/spring/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC概述.md)
+* [SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet](docs/spring/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet.md)
+* [SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘ ](docs/spring/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘.md)
+* [SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller ](docs/spring/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller.md)
+* [SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解](docs/spring/SpringMVC/SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解.md)
+* [SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�† ](docs/spring/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�†.md)
### SpringBoot
* [SpringBoot系列:SpringBoot的�世今生](docs/spring/SpringBoot/SpringBoot的�世今生.md)
+* [ç»™ä½ ä¸€ä»½SpringBoot知识清å�•.md](docs/spring/SpringBoot/ç»™ä½ ä¸€ä»½SpringBoot知识清å�•.md)
+* [Spring常�注解使用指�(包�Spring+SpringMVC+SpringBoot)](docs/spring/SpringBoot/Spring常�注解使用指�(包�Spring+SpringMVC+SpringBoot).md)
+* [SpringBootä¸çš„æ—¥å¿—管ç�†](docs/spring/SpringBoot/SpringBootä¸çš„æ—¥å¿—管ç�†.md)
+* [SpringBoot常�注解](docs/spring/SpringBoot/SpringBoot常�注解.md)
+* [SpringBoot应用也�以部署到外部Tomcat](docs/spring/SpringBoot/SpringBoot应用也�以部署到外部Tomcat.md)
+* [SpringBoot生产环境工具Actuator](docs/spring/SpringBoot/SpringBoot生产环境工具Actuator.md)
+* [SpringBoot的Starter机制](docs/spring/SpringBoot/SpringBoot的Starter机制.md)
+* [SpringBoot的�世今生](docs/spring/SpringBoot/SpringBoot的�世今生.md)
+* [SpringBoot的基本使用](docs/spring/SpringBoot/SpringBoot的基本使用.md)
+* [SpringBoot的�置文件管�](docs/spring/SpringBoot/SpringBoot的�置文件管�.md)
+* [SpringBoot自带的çƒéƒ¨ç½²å·¥å…·](docs/spring/SpringBoot/SpringBoot自带的çƒéƒ¨ç½²å·¥å…·.md)
+* [SpringBootä¸çš„任务调度与@Async](docs/spring/SpringBoot/SpringBootä¸çš„任务调度与@Async.md)
+* [基于SpringBootä¸çš„å¼€æº�监控工具SpringBootAdmin](docs/spring/SpringBoot/基于SpringBootä¸çš„å¼€æº�监控工具SpringBootAdmin.md)
### SpringCloud
diff --git "a/docs/spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md" "b/docs/spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md"
index a684554..c4de431 100644
--- "a/docs/spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md"
+++ "b/docs/spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md"
@@ -133,11 +133,11 @@ Bean
ÈÝÆ÷ÖÐÒ»µ©×¢²áÁËBeanºó´¦ÀíÆ÷£¬Beanºó´¦ÀíÆ÷¾Í»á×Ô¶¯Æô¶¯£¬ÔÚÈÝÆ÷ÖÐÿ¸öBean´´½¨Ê±×Ô¶¯¹¤×÷£¬Beanºó´¦ÀíÆ÷Á½¸ö·½·¨µÄ»Øµ÷ʱ»úÈçÏÂͼ£º
-
+
×¢ÒâÒ»µã£¬Èç¹ûʹÓÃ`BeanFactory`×÷ΪSpringÈÝÆ÷£¬Ôò±ØÐëÊÖ¶¯×¢²áBeanºó´¦ÀíÆ÷£¬³ÌÐò±ØÐë»ñÈ¡Beanºó´¦ÀíÆ÷ʵÀý£¬È»ºóÊÖ¶¯×¢²á¡£
- BeanPostProcessor bp = (BeanPostProcessor)beanFactory.getBean("bp"); beanFactory.addBeanPostProcessor(bp); Person p = (Person)beanFactory.getBean("person");
+BeanPostProcessor bp = (BeanPostProcessor)beanFactory.getBean("bp"); beanFactory.addBeanPostProcessor(bp); Person p = (Person)beanFactory.getBean("person");
### ÈÝÆ÷ºó´¦ÀíÆ÷
@@ -158,7 +158,7 @@ Spring
ÔÚSpringÅäÖÃÎļþÖÐ×öÈçÏÂÅäÖã¬Ö¸¶¨×Ô¶¯É¨ÃèµÄ°ü£º
-
+
### ʹÓÃ@ResourceÅäÖÃÒÀÀµ
@@ -174,6 +174,7 @@ Spring
SpringÌṩÁË`@Autowired`×¢½âÀ´Ö¸¶¨×Ô¶¯×°Å䣬`@Autowired`¿ÉÒÔÐÞÊÎsetter·½·¨¡¢ÆÕͨ·½·¨¡¢ÊµÀý±äÁ¿ºÍ¹¹ÔìÆ÷µÈ¡£µ±Ê¹ÓÃ`@Autowired`±ê×¢setter·½·¨Ê±£¬Ä¬ÈϲÉÓÃbyType×Ô¶¯×°Åä²ßÂÔ¡£ÔÚÕâÖÖ²ßÂÔÏ£¬·ûºÏ×Ô¶¯×°ÅäÀàÐ͵ĺòÑ¡BeanʵÀý³£³£Óжà¸ö£¬Õâ¸öʱºò¾Í¿ÉÄÜÒýÆðÒì³££¬ÎªÁËʵÏÖ¾«È·µÄ×Ô¶¯×°Å䣬SpringÌṩÁË`@Qualifier`×¢½â£¬Í¨¹ýʹÓÃ`@Qualifier`£¬ÔÊÐí¸ù¾ÝBeanµÄidÀ´Ö´ÐÐ×Ô¶¯×°Åä¡£
# ²Î¿¼ÎÄÕÂ
+
https://www.w3cschool.cn/wkspring
https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
diff --git "a/docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\344\273\273\345\212\241\350\260\203\345\272\246\344\270\216@Async.md" "b/docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\344\273\273\345\212\241\350\260\203\345\272\246\344\270\216@Async.md"
new file mode 100644
index 0000000..c3bce06
--- /dev/null
+++ "b/docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\344\273\273\345\212\241\350\260\203\345\272\246\344\270\216@Async.md"
@@ -0,0 +1,240 @@
+
+
+
+
+# Spring Bootµ÷¶È
+
+ÒÔÏÂÄÚÈݽöÊÇÕ¾³¤»òÍøÓѸöÈËѧϰ±Ê¼Ç¡¢×ܽáºÍÑо¿Êղء£²»±£Ö¤ÕýÈ·ÐÔ£¬ÒòʹÓöø´øÀ´µÄ·çÏÕÓë±¾Õ¾Î޹أ¡
+
+
+
+
+
+
+
+
+
+µ÷¶ÈÊÇÖ´ÐÐÌØ¶¨Ê±¼ä¶ÎµÄÈÎÎñµÄ¹ý³Ì¡£Spring BootΪÔÚSpringÓ¦ÓóÌÐòÉϱàдµ÷¶È³ÌÐòÌṩÁ˺ܺõÄÖ§³Ö¡£
+
+## Java Cron±í´ïʽ
+
+Java Cron±í´ïʽÓÃÓÚÅäÖÃCronTriggerµÄʵÀý£¬ËüÊÇ`org.quartz.Trigger`µÄ×ÓÀà¡£ ÓйØJava cron±í´ïʽµÄ¸ü¶àÐÅÏ¢£¬Çë²ÎÔÄ´ËÁ´½Ó -
+
+* [https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.html](https://docs.oracle.com/cd/E12058_01/doc/doc.1014/e12030/cron_expressions.html)
+
+`[@EnableScheduling](https://github.com/EnableScheduling "@EnableScheduling")`×¢½âÓÃÓÚΪӦÓóÌÐòÆôÓõ÷¶È³ÌÐò¡£½«´ËÅú×¢Ìí¼Óµ½Ö÷Spring BootÓ¦ÓóÌÐòÀàÎļþÖС£
+
+```
+@SpringBootApplication
+@EnableScheduling
+
+public class DemoApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(DemoApplication.class, args);
+ }
+}
+
+```
+
+`[@Scheduled](https://github.com/Scheduled "@Scheduled")`×¢½âÓÃÓÚÔÚÌØ¶¨Ê±¼ä¶ÎÄÚ´¥·¢µ÷¶È³ÌÐò¡£
+
+```
+@Scheduled(cron = "0 * 9 * * ?")
+public void cronJobSch() throws Exception {
+}
+
+```
+
+ÒÔÏÂÊÇÒ»¸öʾÀý´úÂ룬ÑÝʾÈçºÎÔÚÿÌìÉÏÎç9:00¿ªÊ¼µ½Ã¿ÌìÉÏÎç9:59½áÊøÖ´ÐÐÈÎÎñ¡£
+
+```
+package com.yiibai.demo.scheduler;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Component
+public class Scheduler {
+ @Scheduled(cron = "0 * 9 * * ?")
+ public void cronJobSch() {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+ Date now = new Date();
+ String strDate = sdf.format(now);
+ System.out.println("Java cron job expression:: " + strDate);
+ }
+}
+
+```
+
+ÒÔÏÂÆÁÄ»½ØÍ¼ÏÔʾÁËÓ¦ÓóÌÐòÈçºÎÔÚ`09:03:23`Æô¶¯£¬²¢ÇÒ´ÓÄÇʱÆðÿ¸ôÒ»·ÖÖÓÖ´ÐÐÒ»´Îcron×÷Òµµ÷¶È³ÌÐòÈÎÎñ¡£
+
+
+
+## ¹Ì¶¨ËÙÂÊ
+
+¹Ì¶¨ËÙÂʵ÷¶È³ÌÐòÓÃÓÚÔÚÌØ¶¨Ê±¼äÖ´ÐÐÈÎÎñ¡£Ëü²»µÈ´ýǰһ¸öÈÎÎñµÄÍê³É¡£ ÖµÊÇÒÔºÁÃëΪµ¥Î»¡£ ʾÀý´úÂëÏÔʾÔÚ´Ë´¦ -
+
+```
+@Scheduled(fixedRate = 1000)
+public void fixedRateSch() {
+}
+
+```
+
+´Ë´¦ÏÔʾÁËÓ¦ÓóÌÐòÆô¶¯Ê±Ã¿ÃëÖ´ÐÐÈÎÎñµÄʾÀý´úÂë -
+
+```
+package com.yiibai.demo.scheduler;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Component
+public class Scheduler {
+ @Scheduled(fixedRate = 1000)
+ public void fixedRateSch() {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+
+ Date now = new Date();
+ String strDate = sdf.format(now);
+ System.out.println("Fixed Rate scheduler:: " + strDate);
+ }
+}
+
+```
+
+Çë×¢ÒâÒÔÏÂÆÁÄ»½ØÍ¼£¬ÆäÖÐÏÔʾÁËÔÚ`09:12:00`Æô¶¯µÄÓ¦ÓóÌÐò£¬Ö®ºóÿ¸ôÒ»¸ö¹Ì¶¨ËÙÂʵ÷¶È³ÌÐòÖ´ÐÐÈÎÎñ¡£
+
+
+
+## ¹Ì¶¨ÑÓ³Ù
+
+¹Ì¶¨ÑÓ³Ùµ÷¶È³ÌÐòÓÃÓÚÔÚÌØ¶¨Ê±¼äÖ´ÐÐÈÎÎñ¡£ ËüÓ¦¸ÃµÈ´ýÉÏÒ»¸öÈÎÎñÍê³É¡£ ÖµÓ¦ÒÔºÁÃëΪµ¥Î»¡£ ´Ë´¦ÏÔʾʾÀý´úÂë -
+
+```
+@Scheduled(fixedDelay = 1000, initialDelay = 1000)
+public void fixedDelaySch() {
+}
+
+```
+
+ÕâÀ`initialDelay`ÊÇÔÚ³õʼÑÓ³ÙÖµÖ®ºóµÚÒ»´ÎÖ´ÐÐÈÎÎñµÄʱ¼ä¡£
+
+´ÓÓ¦ÓóÌÐòÆô¶¯Íê³É`3`ÃëºóÿÃëÖ´ÐÐÒ»´ÎÈÎÎñµÄʾÀýÈçÏÂËùʾ -
+
+```
+package com.yiibai.demo.scheduler;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Component
+public class Scheduler {
+ @Scheduled(fixedDelay = 1000, initialDelay = 3000)
+ public void fixedDelaySch() {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+ Date now = new Date();
+ String strDate = sdf.format(now);
+ System.out.println("Fixed Delay scheduler:: " + strDate);
+ }
+}
+
+```
+
+Ö´ÐÐÉÏÃæ´úÂëºó£¬Ëü»áÏÔʾÔÚ`09:18:39`¿ªÊ¼µÄÓ¦ÓóÌÐò£¬Ã¿`3`Ãëºó£¬¹Ì¶¨Ñӳټƻ®³ÌÐòÈÎÎñ(ÿÃëÖ´ÐÐÒ»´Î)¡£
+
+
+
+
+
+//¸ü¶àÇëÔĶÁ£ºhttps://www.yiibai.com/spring-boot/spring_boot_scheduling.html
+
+@EnableAsync ×¢½â
+ҪʹÓà @Async£¬Ê×ÏÈÐèҪʹÓà @EnableAsync ×¢½â¿ªÆô Spring Boot ÖеÄÒì²½ÌØÐÔ¡£
+
+@Configuration
+@EnableAsync
+public class AppConfig {
+}
+¸üÏêϸµÄÅäÖÃ˵Ã÷£¬¿ÉÒԲο¼£ºAsyncConfigurer(opens new window)
+
+#@Async ×¢½â
+#Ö§³ÖµÄÓ÷¨
+£¨1£©ÎÞÈë²ÎÎÞ·µ»ØÖµ·½·¨
+
+Äú¿ÉÒÔÓà @Async ×¢½âÐÞÊη½·¨£¬Õâ±íÃ÷Õâ¸ö·½·¨ÊÇÒì²½·½Ê½µ÷Ó᣻»¾ä»°Ëµ£¬³ÌÐòÔÚµ÷Óô˷½·¨Ê±»áÁ¢¼´·µ»Ø£¬¶ø·½·¨µÄʵ¼ÊÖ´Ðз¢ÉúÔÚÒÑÌá½»¸ø Spring TaskExecutor µÄÈÎÎñÖС£ÔÚ×î¼òµ¥µÄÇé¿öÏ£¬Äú¿ÉÒÔ½«×¢½âÓ¦ÓÃÓÚ·µ»Ø void µÄ·½·¨£¬ÈçÒÔÏÂʾÀýËùʾ£º
+
+@Async
+void doSomething() {
+// this will be executed asynchronously
+}
+£¨2£©ÓÐÈë²ÎÎÞ·µ»ØÖµ·½·¨
+
+ÓëʹÓà @Scheduled ×¢ÊÍ×¢Ê͵ķ½·¨²»Í¬£¬ÕâЩ·½·¨¿ÉÒÔÖ¸¶¨²ÎÊý£¬ÒòΪËüÃÇÔÚÔËÐÐʱÓɵ÷ÓÃÕßÒÔ¡°Õý³£¡±·½Ê½µ÷Ó㬶ø²»ÊÇÓÉÈÝÆ÷¹ÜÀíµÄµ÷¶ÈÈÎÎñµ÷Óá£ÀýÈ磬ÒÔÏ´úÂëÊÇ @Async ×¢½âµÄºÏ·¨Ó¦Óãº
+
+@Async
+void doSomething(String s) {
+// this will be executed asynchronously
+}
+£¨3£©ÓÐÈë²ÎÓзµ»ØÖµ·½·¨
+
+ÉõÖÁ¿ÉÒÔÒì²½µ÷Ó÷µ»ØÖµµÄ·½·¨¡£µ«ÊÇ£¬ÕâЩ·½·¨ÐèÒª¾ßÓÐ Future ÀàÐ͵ķµ»ØÖµ¡£ÕâÈÔÈ»ÌṩÁËÒì²½Ö´Ðеĺô¦£¬ÒÔ±ãµ÷ÓÃÕß¿ÉÒÔÔÚµ÷Óà Future É쵀 get() ֮ǰִÐÐÆäËûÈÎÎñ¡£ÒÔÏÂʾÀýÏÔʾÈçºÎÔÚ·µ»ØÖµµÄ·½·¨ÉÏʹÓÃ@Async£º
+
+@Async
+Future returnSomething(int i) {
+// this will be executed asynchronously
+}
+#²»Ö§³ÖµÄÓ÷¨
+@Async ²»ÄÜÓëÉúÃüÖÜÆÚ»Øµ÷Ò»ÆðʹÓã¬ÀýÈç @PostConstruct¡£
+
+ÒªÒì²½³õʼ»¯ Spring bean£¬±ØÐëʹÓõ¥¶ÀµÄ³õʼ»¯ Spring bean£¬È»ºóÔÚÄ¿±êÉϵ÷Óà @Async ´ø×¢Ê͵ķ½·¨£¬ÈçÒÔÏÂʾÀýËùʾ£º
+
+public class SampleBeanImpl implements SampleBean {
+
+ @Async
+ void doSomething() {
+ // ...
+ }
+
+}
+
+public class SampleBeanInitializer {
+
+ private final SampleBean bean;
+
+ public SampleBeanInitializer(SampleBean bean) {
+ this.bean = bean;
+ }
+
+ @PostConstruct
+ public void initialize() {
+ bean.doSomething();
+ }
+
+}
+#Ã÷È·Ö¸¶¨Ö´ÐÐÆ÷
+ĬÈÏÇé¿öÏ£¬ÔÚ·½·¨ÉÏÖ¸¶¨ @Async ʱ£¬Ê¹ÓõÄÖ´ÐÐÆ÷ÊÇÔÚÆôÓÃÒì²½Ö§³ÖʱÅäÖõÄÖ´ÐÐÆ÷£¬¼´Èç¹ûʹÓà XML »ò AsyncConfigurer ʵÏÖ£¨Èç¹ûÓУ©£¬ÔòΪ annotation-driven ÔªËØ¡£µ«ÊÇ£¬Èç¹ûÐèҪָʾÔÚÖ´Ðиø¶¨·½·¨Ê±Ó¦Ê¹ÓÃĬÈÏÖµÒÔÍâµÄÖ´ÐÐÆ÷£¬Ôò¿ÉÒÔʹÓà @Async ×¢½âµÄ value ÊôÐÔ¡£ÒÔÏÂʾÀýÏÔʾÁËÈçºÎÖ´Ðд˲Ù×÷£º
+
+@Async("otherExecutor")
+void doSomething(String s) {
+// this will be executed asynchronously by "otherExecutor"
+}
+ÔÚÕâÖÖÇé¿öÏ£¬¡°otherExecutor¡±¿ÉÒÔÊÇ Spring ÈÝÆ÷ÖÐÈκΠExecutor bean µÄÃû³Æ£¬Ò²¿ÉÒÔÊÇÓëÈκΠExecutor ¹ØÁªµÄÏÞ¶¨·ûµÄÃû³Æ£¨ÀýÈ磬ʹÓÃ ÔªËØ»ò Spring µÄ @Qualifier ×¢ÊÍÖ¸¶¨£© £©¡£
+
+#¹ÜÀí @Async µÄÒì³£
+µ± @Async ·½·¨µÄ·µ»ØÖµÀàÐÍΪ Future ÐÍʱ£¬ºÜÈÝÒ×¹ÜÀíÔÚ·½·¨Ö´ÐÐÆÚ¼äÅ׳öµÄÒì³££¬ÒòΪÔÚµ÷Óà get ½á¹ûʱ»áÅ׳ö´ËÒì³£¡£µ«ÊÇ£¬¶ÔÓÚ·µ»ØÖµÀàÐÍΪ void Ð͵ķ½·¨£¬Òì³£²»»á±»²¶»ñÇÒÎÞ·¨´«Êä¡£Äú¿ÉÒÔÌṩ AsyncUncaughtExceptionHandler À´´¦Àí´ËÀàÒì³£¡£ÒÔÏÂʾÀýÏÔʾÁËÈçºÎÖ´Ðд˲Ù×÷£º
+
+public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
+
+ @Override
+ public void handleUncaughtException(Throwable ex, Method method, Object... params) {
+ // handle exception
+ }
+}
+ĬÈÏÇé¿öÏ£¬½ö¼Ç¼Òì³£¡£Äú¿ÉÒÔʹÓà AsyncConfigurer »ò XML ÔªËØ¶¨Òå×Ô¶¨Òå AsyncUncaughtExceptionHandler¡£
\ No newline at end of file
diff --git "a/docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\346\227\245\345\277\227\347\256\241\347\220\206.md" "b/docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\346\227\245\345\277\227\347\256\241\347\220\206.md"
new file mode 100644
index 0000000..009576d
--- /dev/null
+++ "b/docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\346\227\245\345\277\227\347\256\241\347\220\206.md"
@@ -0,0 +1,806 @@
+## 4\. ÈÕÖ¾
+
+
+
+
+
+Spring BootÔÚËùÓÐÄÚ²¿ÈÕÖ¾ÖÐʹÓà [Commons Logging](https://commons.apache.org/logging) £¬µ«¶Ôµ×²ãÈÕÖ¾µÄʵÏÖ±£³Ö¿ª·Å¡£ Ϊ [Java Util Logging](https://docs.oracle.com/javase/17/docs/api/java/util/logging/package-summary.html) ¡¢ [Log4j2](https://logging.apache.org/log4j/2.x/) ¡¢ [Logback](https://logback.qos.ch/) ÌṩÁËĬÈÏÅäÖᣠÔÚÿһÖÖÇé¿öÏ£¬¼Ç¼Æ÷£¨logger£©¶¼±»Ô¤ÉèΪʹÓÿØÖÆÌ¨Êä³ö£¬Ò²¿ÉÒÔÑ¡ÔñÊä³öµ½Îļþ¡£
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬Èç¹ûÄãʹÓà ¡°Starter¡±£¬ÔòĬÈÏʹÓÃLogback¡£ Êʵ±µÄLogback·ÓÉÒ²°üÀ¨ÔÚÄÚ£¬ÒÔÈ·±£Ê¹ÓÃJava Util Logging¡¢Commons Logging¡¢Log4J»òSLF4JµÄÒÀÀµ¿â¶¼ÄÜÕýÈ·¹¤×÷¡£
+
+
+
+
+
+| | ÓкܶàÊÊÓÃÓÚJavaµÄÈÕÖ¾¿ò¼Ü¡£ Èç¹ûÉÏÃæµÄÁÐ±í¿´ÆðÀ´ºÜ»ìÂÒ£¬Çë²»Òªµ£ÐÄ¡£ Ò»°ãÀ´Ëµ£¬Äã²»ÐèÒª¸Ä±äÄãµÄÈÕÖ¾ÒÀÀµ£¬Spring BootµÄĬÈÏÖµ¾ÍºÜºÃÓᣠ|
+| --- | --- |
+
+
+
+
+
+| | µ±Äã°ÑÄãµÄÓ¦ÓóÌÐò²¿Êðµ½Ò»¸öservletÈÝÆ÷»òÓ¦Ó÷þÎñÆ÷ʱ£¬ÓÃJava Util Logging APIÖ´ÐеÄÈÕÖ¾²»»á±»´«Ë͵½ÄãµÄÓ¦ÓóÌÐòµÄÈÕÖ¾ÖС£ Õâ¿ÉÒÔ·ÀÖ¹ÓÉÈÝÆ÷»òÆäËûÒѾ²¿Êðµ½ËüµÄÓ¦ÓóÌÐòÖ´ÐеÄÈÕÖ¾³öÏÖÔÚÄãµÄÓ¦ÓóÌÐòµÄÈÕÖ¾ÖС£ |
+| --- | --- |
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.logging.log-format)4.1\. ÈÕÖ¾¸ñʽ
+
+
+
+Spring BootµÄĬÈϵÄÈÕÖ¾Êä³ö¸ñʽÀàËÆÓÚÏÂÃæµÄÀý×Ó¡£
+
+
+
+
+
+
+
+ 2023-03-03T21:18:18.827+08:00 INFO 19388 --- [ main] o.s.b.d.f.s.MyApplication : Starting MyApplication using Java 17 with PID 19388 (/opt/apps/myapp.jar started by myuser in /opt/apps/)
+2023-03-03T21:18:18.834+08:00 INFO 19388 --- [ main] o.s.b.d.f.s.MyApplication : No active profile set, falling back to 1 default profile: "default"
+2023-03-03T21:18:20.439+08:00 INFO 19388 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2023-03-03T21:18:20.461+08:00 INFO 19388 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2023-03-03T21:18:20.461+08:00 INFO 19388 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.5]
+2023-03-03T21:18:20.600+08:00 INFO 19388 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2023-03-03T21:18:20.602+08:00 INFO 19388 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1685 ms
+2023-03-03T21:18:21.078+08:00 INFO 19388 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2023-03-03T21:18:21.093+08:00 INFO 19388 --- [ main] o.s.b.d.f.s.MyApplication : Started MyApplication in 2.998 seconds (process running for 3.601)
+
+
+
+
+
+
+
+Êä³öµÄÏîÄ¿ÈçÏ¡£
+
+
+
+
+
+* DateºÍʱTime£º¾«È·µ½ºÁÃ룬Ò×ÓÚÅÅÐò¡£
+
+* ÈÕÖ¾¼¶±ð: `ERROR`, `WARN`, `INFO`, `DEBUG`, »ò `TRACE`.
+
+* ½ø³ÌID¡£
+
+* Ò»¸ö `---` ·Ö¸ô·û£¬ÒÔÇø·Öʵ¼ÊÈÕÖ¾ÐÅÏ¢µÄ¿ªÊ¼¡£
+
+* Ïß³ÌÃû³Æ£º°üº¬ÔÚ·½À¨ºÅÖУ¨¶ÔÓÚ¿ØÖÆÌ¨Êä³ö¿ÉÄܻᱻ½Ø¶Ï£©¡£
+
+* ¼Ç¼Æ÷Ãû³Æ£ºÕâͨ³£ÊÇÔ´ÀàµÄÃû³Æ£¨Í¨³£ÊÇËõд£©¡£
+
+* ÈÕÖ¾ÏûÏ¢¡£
+
+
+
+
+
+| | LogbackûÓÐ `FATAL` ¼¶±ð¡£ Ëü±»Ó³Éäµ½ `ERROR`¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.logging.console-output)4.2\. ¿ØÖÆÌ¨Êä³ö
+
+
+
+ĬÈÏÇé¿öÏ£¬ÈÕÖ¾»áÊä³ö `ERROR`¡¢`WARN` ºÍ `INFO` ¼¶±ðµÄÏûÏ¢µ½¿ØÖÆÌ¨¡£ ÄãÒ²¿ÉÒÔͨ¹ýÓà `--debug` ±êÖ¾Æô¶¯ÄãµÄÓ¦ÓóÌÐò£¬À´ÆôÓà `debug` ģʽ¡£
+
+
+
+
+
+
+
+```
+$ java -jar myapp.jar --debug
+```
+
+
+
+
+
+
+
+| | ÄãÒ²¿ÉÒÔÔÚÄãµÄ `application.properties` ÖÐÖ¸¶¨ `debug=true`¡£ |
+| --- | --- |
+
+
+
+
+
+µ±debugģʽ±»ÆôÓÃʱ£¬Ò»Ð©ºËÐļǼÆ÷£¨Ç¶ÈëʽÈÝÆ÷¡¢HibernateºÍSpring Boot£©±»ÅäÖÃΪÊä³ö¸ü¶àÐÅÏ¢¡£ ÆôÓÃdebugģʽ²¢²»Òâζ׎«ÄãµÄÓ¦ÓóÌÐòÅäÖÃΪÒÔ `DEBUG` ¼¶±ð¼Ç¼ËùÓÐÐÅÏ¢¡£
+
+
+
+
+
+ÁíÍ⣬Äã¿ÉÒÔͨ¹ýÔÚÆô¶¯Ó¦ÓóÌÐòʱʹÓà `--trace` ±êÖ¾£¨»òÔÚ `application.properties` ÖÐʹÓà `trace=true` £©À´ÆôÓà ¡°trace¡± ģʽ¡£ ÕâÑù×ö¿ÉÒÔ¶ÔһЩºËÐļǼÆ÷£¨Ç¶ÈëʽÈÝÆ÷¡¢Hibernate schemaÉú³ÉºÍÕû¸öSpring×éºÏ£©½øÐиú×ټǼ¡£
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.logging.console-output.color-coded)4.2.1\. ²ÊÉ«±àÂëµÄÊä³ö
+
+
+
+Èç¹ûÄãµÄÖÕ¶ËÖ§³ÖANSI£¬¾Í»áʹÓòÊÉ«Êä³öÀ´°ïÖúÔĶÁ¡£ Äã¿ÉÒÔ½« `spring.output.ansi.enabled` ÉèÖÃΪ [Ö§³ÖµÄÖµ](https://docs.spring.io/spring-boot/docs/3.1.0-SNAPSHOT/api/org/springframework/boot/ansi/AnsiOutput.Enabled.html)£¬ÒÔ¸²¸Ç×Ô¶¯¼ì²â¡£
+
+
+
+
+
+ÑÕÉ«±àÂëÊÇͨ¹ýʹÓà `%clr` ת»»¹Ø¼ü×ÖÀ´ÅäÖõġ£ ÔÚÆä×î¼òµ¥µÄÐÎʽÖУ¬×ª»»Æ÷¸ù¾ÝÈÕÖ¾¼¶±ð¶ÔÊä³ö½øÐÐ×ÅÉ«£¬ÈçÏÂÃæµÄÀý×ÓÖÐËùʾ¡£
+
+
+
+
+
+
+
+```
+%clr(%5p)
+```
+
+
+
+
+
+
+
+ϱíÃèÊöÁËÈÕÖ¾¼¶±ðÓëÑÕÉ«µÄÓ³Éä¹ØÏµ¡£
+
+
+
+
+| ÈÕÖ¾¼¶±ð | ÑÕÉ« |
+| --- | --- |
+| `FATAL` | ºì |
+| `ERROR` | ºì |
+| `WARN` | Ȯ |
+| `INFO` | ÂÌ |
+| `DEBUG` | ÂÌ |
+| `TRACE` | ÂÌ |
+
+
+
+ÁíÍ⣬ÄãÒ²¿ÉÒÔͨ¹ýΪת»»Ìṩһ¸öÑ¡ÏîÀ´Ö¸¶¨Ó¦¸ÃʹÓõÄÑÕÉ«»òÑùʽ¡£ ÀýÈ磬ҪʹÎı¾Îª»ÆÉ«£¬ÇëʹÓÃÒÔÏÂÉèÖá£
+
+
+
+
+
+
+
+```
+%clr(%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX}){yellow}
+```
+
+
+
+
+
+
+
+Ö§³ÖÒÔÏÂÑÕÉ«ºÍÑùʽ¡£
+
+
+
+
+
+* `blue`
+
+* `cyan`
+
+* `faint`
+
+* `green`
+
+* `magenta`
+
+* `red`
+
+* `yellow`
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.logging.file-output)4.3\. Êä³öµ½Îļþ
+
+
+
+ĬÈÏÇé¿öÏ£¬Spring BootÖ»Ïò¿ØÖÆÌ¨¼Ç¼ÈÕÖ¾£¬²»Ð´ÈÕÖ¾Îļþ¡£ Èç¹ûÄãÏëÔÚ¿ØÖÆÌ¨Êä³öÖ®ÍâдÈÕÖ¾Îļþ£¬ÄãÐèÒªÉèÖà `logging.file.name` »ò `logging.file.path` ÊôÐÔ£¨ÀýÈ磬ÔÚÄãµÄ `application.properties` ÖУ©¡£
+
+
+
+
+
+ϱíÏÔʾÁË `logging.*` ÊôÐÔÈçºÎ±»Ò»ÆðʹÓá£
+
+
+
+Table 5\. Logging properties
+| `logging.file.name` | `logging.file.path` | Example | Description |
+| --- | --- | --- | --- |
+| _(none)_ | _(none)_ | | Ö»ÔÚ¿ØÖÆÌ¨½øÐмǼ¡£ |
+| Ö¸¶¨Îļþ | _(none)_ | `my.log` | дÈëÖ¸¶¨µÄÈÕÖ¾Îļþ¡£ Ãû³Æ¿ÉÒÔÊÇÒ»¸öÈ·ÇеÄλÖã¬Ò²¿ÉÒÔÊÇÓ뵱ǰĿ¼µÄÏà¶ÔλÖᣠ|
+| _(none)_ | Ö¸¶¨Ä¿Â¼ | `/var/log` | ½« `spring.log` дµ½Ö¸¶¨Ä¿Â¼¡£ Ãû³Æ¿ÉÒÔÊÇÒ»¸öÈ·ÇеÄλÖã¬Ò²¿ÉÒÔÊÇÓ뵱ǰĿ¼µÄÏà¶ÔλÖᣠ|
+
+
+
+ÈÕÖ¾ÎļþÔÚ´ïµ½10MBʱ¾Í»áÂÖ»»£¬Óë¿ØÖÆÌ¨Êä³öÒ»Ñù£¬Ä¬ÈÏÇé¿öÏ»á¼Ç¼ `ERROR` ¡¢`WARN` ¼¶ºÍ `INFO` ¼¶±ðµÄÐÅÏ¢¡£
+
+
+
+
+
+| | ÈÕÖ¾ÊôÐÔ¶ÀÁ¢ÓÚʵ¼ÊµÄÈÕÖ¾»ù´¡ÉèÊ©¡£ Òò´Ë£¬Ìض¨µÄÅäÖÃÊôÐÔ£¨ÈçLogbackµÄ `logback.configurationFile` £©²»ÓÉspring Boot¹ÜÀí¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.logging.file-rotation)4.4\. ÎļþÂÖ»»£¨¹ö¶¯ÈÕÖ¾£©
+
+
+
+Èç¹ûÄãʹÓÃLogback£¬¿ÉÒÔʹÓÃÄãµÄ `application.properties` »ò `application.yaml` ÎļþÀ´Î¢µ÷ÈÕÖ¾ÂÖ»»ÉèÖᣠ¶ÔÓÚËùÓÐÆäËûµÄÈÕ־ϵͳ£¬Ä㽫ÐèÒª×Ô¼ºÖ±½ÓÅäÖÃÂÖ»»ÉèÖã¨ÀýÈ磬Èç¹ûÄãʹÓÃLog4J2£¬ÄÇôÄã¿ÉÒÔÌí¼ÓÒ»¸ö `log4j2.xml` »ò `log4j2-spring.xml` Îļþ£©¡£
+
+
+
+
+
+Ö§³ÖÒÔÏÂÂÖ»»²ßÂÔÊôÐÔ¡£
+
+
+
+
+| ÊôÐÔ | ˵Ã÷ |
+| --- | --- |
+| `logging.logback.rollingpolicy.file-name-pattern` | ÓÃÓÚ´´½¨ÈÕÖ¾¹éµµµÄÎļþÃûģʽ¡£ |
+| `logging.logback.rollingpolicy.clean-history-on-start` | Ó¦ÓóÌÐòÆô¶¯Ê±£¬ÊÇ·ñÐÐÈÕÖ¾¹éµµÇåÀí¡£ |
+| `logging.logback.rollingpolicy.max-file-size` | ÈÕÖ¾Îļþ¹éµµÇ°µÄ×î´ó³ß´ç£¨Îļþ×î´óÌå»ý£¬´ïµ½Õâ¸öÌå»ý¾Í»á¹éµµ£©¡£ |
+| `logging.logback.rollingpolicy.total-size-cap` | ÈÕÖ¾µµ°¸ÔÚ±»É¾³ýǰµÄ×î´ó³ß´ç£¨¹éµµÎļþ×î´óÕ¼ÓôóС£¬³¬¹ýÕâ¸ö´óСºó»á±»É¾³ý£©¡£ |
+| `logging.logback.rollingpolicy.max-history` | Òª±£ÁôµÄ¹éµµÈÕÖ¾ÎļþµÄ×î´óÊýÁ¿£¨Ä¬ÈÏΪ7£©¡£ |
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.logging.log-levels)4.5\. ÈÕÖ¾¼¶±ð
+
+
+
+ËùÓÐÖ§³ÖµÄÈÕ־ϵͳ¶¼¿ÉÒÔͨ¹ýʹÓà `logging.level.=` ÔÚSpringµÄ `Environment`£¨ÀýÈ磬ÔÚ `application.properties`£©ÖÐÉèÖÃÈÕÖ¾¼¶±ð£¬ÆäÖÐ `level` ÊÇ `TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL`, »ò `OFF` Ö®Ò»¡£ `root` ¼Ç¼Æ÷£¨logger£©µÄ¼¶±ð¿ÉÒÔͨ¹ý `logging.level.root` À´ÅäÖá£
+
+
+
+
+
+ÏÂÃæµÄÀý×ÓÏÔʾÁË `application.properties` ÖÐDZÔÚµÄÈÕÖ¾ÉèÖá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+logging.level.root=warn
+logging.level.org.springframework.web=debug
+logging.level.org.hibernate=error
+```
+
+
+
+
+
+
+
+Ò²¿ÉÒÔʹÓû·¾³±äÁ¿À´ÉèÖÃÈÕÖ¾¼¶±ð¡£ ÀýÈ磬`LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_WEB=DEBUG` ½«ÉèÖà `org.springframework.web` Ϊ `DEBUG` ¡£
+
+
+
+
+
+| | ÉÏÊö·½·¨Ö»ÊÊÓÃÓÚ°ü¼¶ÈÕÖ¾¡£ ÓÉÓÚ¿íËɰó¶¨×ÜÊǽ«»·¾³±äÁ¿×ª»»ÎªÐ¡Ð´×Öĸ£¬ËùÒÔ²»¿ÉÄÜÓÃÕâÖÖ·½Ê½Îªµ¥¸öÀàÅäÖÃÈÕÖ¾¡£ Èç¹ûÄãÐèҪΪһ¸öÀàÅäÖÃÈÕÖ¾£¬Äã¿ÉÒÔʹÓÃ[`SPRING_APPLICATION_JSON`](https://springdoc.cn/spring-boot/features.html#features.external-config.application-json)±äÁ¿¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.logging.log-groups)4.6\. ÈÕÖ¾×飨Log Groups£©
+
+
+
+Äܹ»½«Ïà¹ØµÄÈÕÖ¾¼Ç¼Æ÷·Ö×飬ÒÔ±ãͬʱ¶ÔËüÃǽøÐÐÅäÖã¬Õâͨ³£ºÜÓÐÓᣠÀýÈ磬Äã¿ÉÄܾ³£¸Ä±ä _ËùÓÐ_ ÓëTomcatÏà¹ØµÄ¼Ç¼Æ÷µÄ¼Ç¼¼¶±ð£¬µ«Äã²»ÈÝÒ×¼Çס×î¸ß¼¶±ðµÄ°ü¡£
+
+
+
+
+
+ΪÁ˰ïÖú½â¾öÕâ¸öÎÊÌ⣬Spring BootÔÊÐíÄãÔÚSpring `Environment` Öж¨ÒåÈÕÖ¾×é¡£ ÀýÈ磬Äã¿ÉÒÔͨ¹ýÔÚ `application.properties` ÖмÓÈë ¡°tomcat¡± group À´¶¨ÒåËü¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+logging.group.tomcat=org.apache.catalina,org.apache.coyote,org.apache.tomcat
+
+```
+
+
+
+
+
+
+
+Ò»µ©¶¨ÒåºÃºó£¬¾Í¿ÉÒÔÓÃÒ»ÐдúÂëÀ´¸Ä±ä×éÖÐËùÓÐloggerµÄ¼¶±ð¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+logging.level.tomcat=trace
+
+```
+
+
+
+
+
+
+
+Spring Boot°üÀ¨ÒÔÏÂÔ¤¶¨ÒåµÄÈÕÖ¾×飬¿ÉÒÔ¿ªÏä¼´Óá£
+
+
+
+
+| ×éÃû | ×éÖеÄlogger |
+| --- | --- |
+| web | `org.springframework.core.codec`, `org.springframework.http`, `org.springframework.web`, `org.springframework.boot.actuate.endpoint.web`, `org.springframework.boot.web.servlet.ServletContextInitializerBeans` |
+| sql | `org.springframework.jdbc.core`, `org.hibernate.SQL`, `org.jooq.tools.LoggerListener` |
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.logging.shutdown-hook)4.7\. ʹÓÃÈÕÖ¾ Shutdown Hook
+
+
+
+ΪÁËÔÚÄãµÄÓ¦ÓóÌÐòÖÕֹʱÊÍ·ÅÈÕÖ¾×ÊÔ´£¬ÎÒÃÇÌṩÁËÒ»¸öShutdown Hook£¬Ëü½«ÔÚJVMÍ˳öʱ´¥·¢ÈÕ־ϵͳÇåÀí¡£ ³ý·ÇÄãµÄÓ¦ÓóÌÐòÊÇÒÔwarÎļþµÄÐÎʽ²¿ÊðµÄ£¬·ñÔòÕâ¸öShutdown Hook»á×Ô¶¯×¢²á¡£ Èç¹ûÄãµÄÓ¦ÓóÌÐòÓи´ÔÓµÄÉÏÏÂÎIJã´Î½á¹¹£¬Shutdown Hook¿ÉÄÜÎÞ·¨Âú×ãÄãµÄÐèÇó¡£ Èç¹û²»ÄÜ£¬Çë½ûÓùػú¹³×Ó£¬²¢Ñо¿µ×²ãÈÕ־ϵͳֱ½ÓÌṩµÄÑ¡Ïî¡£ ÀýÈ磬LogbackÌṩÁË [context selectors](https://logback.qos.ch/manual/loggingSeparation.html)£¬ÔÊÐíÿ¸ö¼Ç¼Æ÷ÔÚËü×Ô¼ºµÄÉÏÏÂÎÄÖб»´´½¨¡£ Äã¿ÉÒÔʹÓà `logging.register-shutdown-hook` ÊôÐÔÀ´½ûÓÃShutdown Hook¡£ ½«ÆäÉèÖÃΪ `false` ½«½ûÓÃ×¢²á¡£ Äã¿ÉÒÔÔÚÄãµÄ `application.properties` »ò `application.yaml` ÎļþÖÐÉèÖøÃÊôÐÔ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+logging.register-shutdown-hook=false
+
+```
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.logging.custom-log-configuration)4.8\. ×Ô¶¨ÒåÈÕÖ¾ÅäÖÃ
+
+
+
+¸÷ÖÖÈÕ־ϵͳ¿ÉÒÔͨ¹ýÔÚclasspathÉϰüº¬Êʵ±µÄ¿âÀ´¼¤»î£¬²¢ÇÒ¿ÉÒÔͨ¹ýÔÚclasspathµÄ¸ùĿ¼Ï»òÔÚ Spring `Environment` ÊôÐÔÖ¸¶¨µÄλÖÃÌṩһ¸öºÏÊʵÄÅäÖÃÎļþÀ´½øÒ»²½¶¨ÖÆ£º `logging.config`¡£
+
+
+
+
+
+Äú¿ÉÒÔͨ¹ýʹÓà `org.springframework.boot.logging.LoggingSystem` ϵͳÊôÐÔ£¬Ç¿ÖÆSpring BootʹÓÃÌØ¶¨µÄÈÕ־ϵͳ¡£ ¸ÃÖµÓ¦¸ÃÊÇ `LoggingSystem` ʵÏÖµÄÈ«ÀàÃû¡£ ÄãÒ²¿ÉÒÔͨ¹ýʹÓà `none` µÄÖµÀ´ÍêÈ«½ûÓÃSpring BootµÄÈÕÖ¾ÅäÖá£
+
+
+
+
+
+| | SÓÉÓÚÈÕÖ¾ÊÇÔÚ´´½¨ `ApplicationContext` ֮ǰ³õʼ»¯µÄ£¬ËùÒÔ²»¿ÉÄÜ´ÓSpring `@Configuration` ÎļþÖÐµÄ `@PropertySources` ¿ØÖÆÈÕÖ¾¡£ ¸Ä±äÈÕ־ϵͳ»òÍêȫͣÓÃËüµÄΨһ·½·¨ÊÇͨ¹ýSystem properties¡£ |
+| --- | --- |
+
+
+
+
+
+¸ù¾ÝÄãµÄÈÕ־ϵͳ£¬»á¼ÓÔØÒÔÏÂÎļþ¡£
+
+
+
+
+| ÈÕ־ϵͳ | ÅäÖÃÎļþ |
+| --- | --- |
+| Logback | `logback-spring.xml`, `logback-spring.groovy`, `logback.xml` »òÕß `logback.groovy` |
+| Log4j2 | `log4j2-spring.xml` »òÕß `log4j2.xml` |
+| JDK (Java Util Logging) | `logging.properties` |
+
+
+
+| | ÔÚ¿ÉÄܵÄÇé¿öÏ£¬ÎÒÃǽ¨ÒéÄãʹÓà `-spring` ±äÌåÀ´½øÐÐÈÕÖ¾ÅäÖã¨ÀýÈ磬 `logback-spring.xml` ¶ø²»ÊÇ `logback.xml` £©¡£ Èç¹ûÄãʹÓñê×¼ÅäÖÃλÖã¬Spring²»ÄÜÍêÈ«¿ØÖÆÈÕÖ¾³õʼ»¯¡£ |
+| --- | --- |
+
+
+
+
+
+| | µ±´Ó "¿ÉÖ´ÐеÄjar "ÖÐÔËÐÐʱ£¬Java Util LoggingÓÐһЩÒÑÖªµÄÀà¼ÓÔØÎÊÌ⣬»áµ¼ÖÂÎÊÌâ¡£ Èç¹û¿ÉÄܵϰ£¬ÎÒÃǽ¨ÒéÄãÔÚ´Ó "¿ÉÖ´ÐеÄjar" ÖÐÔËÐÐʱ±ÜÃâʹÓÃËü¡£ |
+| --- | --- |
+
+
+
+
+
+ΪÁ˰ïÖú¶¨ÖÆ£¬ÆäËûһЩÊôÐÔ´ÓSpringµÄ `Environment` ×ªÒÆµ½System properties£¬ÈçϱíËùʾ¡£
+
+
+
+| Spring Environment | System Property | ±¸×¢ |
+| --- | --- | --- |
+| `logging.exception-conversion-word` | `LOG_EXCEPTION_CONVERSION_WORD` | ¼Ç¼Ò쳣ʱʹÓõÄת»»´Ê¡£ |
+| `logging.file.name` | `LOG_FILE` | Èç¹û¶¨ÒåÁË£¬Ëü½«ÓÃÓÚĬÈϵÄÈÕÖ¾ÅäÖÃÖС£ |
+| `logging.file.path` | `LOG_PATH` | Èç¹û¶¨ÒåÁË£¬Ëü½«ÓÃÓÚĬÈϵÄÈÕÖ¾ÅäÖÃÖС£ |
+| `logging.pattern.console` | `CONSOLE_LOG_PATTERN` | ÔÚ¿ØÖÆÌ¨£¨stdout£©Ê¹ÓõÄÈÕÖ¾Êä³öģʽ¡£ |
+| `logging.pattern.dateformat` | `LOG_DATEFORMAT_PATTERN` | date ¸ñʽ»¯. |
+| `logging.charset.console` | `CONSOLE_LOG_CHARSET` | ¿ØÖÆÌ¨Êä³öÈÕÖ¾µÄ×Ö·û±àÂë¡£ |
+| `logging.threshold.console` | `CONSOLE_LOG_THRESHOLD` | ÓÃÓÚ¿ØÖÆÌ¨ÈÕÖ¾¼Ç¼µÄÈÕÖ¾¼¶±ð¡£ |
+| `logging.pattern.file` | `FILE_LOG_PATTERN` | ÒªÔÚÎļþÖÐʹÓõÄÈÕ־ģʽ£¨Èç¹û `LOG_FILE` ±»ÆôÓã©¡£ |
+| `logging.charset.file` | `FILE_LOG_CHARSET` | ÎļþÈÕÖ¾µÄ×Ö·û±àÂ루Èç¹û `LOG_FILE` ±»ÆôÓã©¡£ |
+| `logging.threshold.file` | `FILE_LOG_THRESHOLD` | ÓÃÓÚÎļþÈÕÖ¾¼Ç¼µÄÈÕÖ¾¼¶±ð¡£ |
+| `logging.pattern.level` | `LOG_LEVEL_PATTERN` | äÖȾÈÕÖ¾¼¶±ðʱʹÓõĸñʽ£¨Ä¬ÈÏΪ `%5p` £©¡£ |
+| `PID` | `PID` | µ±Ç°µÄ½ø³ÌID |
+
+
+
+Èç¹ûÄãʹÓÃLogback£¬ÒÔÏÂÊôÐÔÒ²»á±»×ªÒÆ¡£
+
+
+
+| Spring Environment | System Property | ±¸×¢ |
+| --- | --- | --- |
+| `logging.logback.rollingpolicy.file-name-pattern` | `LOGBACK_ROLLINGPOLICY_FILE_NAME_PATTERN` | ¹ö¶¯ÈÕÖ¾ÎļþÃûµÄģʽ£¨Ä¬ÈÏΪ `${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz` £©¡£ |
+| `logging.logback.rollingpolicy.clean-history-on-start` | `LOGBACK_ROLLINGPOLICY_CLEAN_HISTORY_ON_START` | ÊÇ·ñÔÚÆô¶¯Ê±ÇåÀí¹éµµÈÕÖ¾Îļþ¡£ |
+| `logging.logback.rollingpolicy.max-file-size` | `LOGBACK_ROLLINGPOLICY_MAX_FILE_SIZE` | ×î´óÈÕÖ¾Îļþ´óС¡£ |
+| `logging.logback.rollingpolicy.total-size-cap` | `LOGBACK_ROLLINGPOLICY_TOTAL_SIZE_CAP` | Òª±£ÁôµÄÈÕÖ¾±¸·ÝµÄ×Ü´óС¡£ |
+| `logging.logback.rollingpolicy.max-history` | `LOGBACK_ROLLINGPOLICY_MAX_HISTORY` | Òª±£ÁôµÄ×î´ó¹éµµÈÕÖ¾ÎļþÊýÁ¿¡£ |
+
+
+
+ËùÓÐÖ§³ÖµÄÈÕ־ϵͳÔÚ½âÎöÆäÅäÖÃÎļþʱ¶¼¿ÉÒÔ´Ó System properties ÖлñÈ¡ÊôÐÔ¡£ Àý×Ó¼û `spring-boot.jar` ÖеÄĬÈÏÅäÖá£
+
+
+
+
+
+* [Logback](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/logback/defaults.xml)
+
+* [Log4j 2](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/log4j2/log4j2.xml)
+
+* [Java Util logging](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot/src/main/resources/org/springframework/boot/logging/java/logging-file.properties)
+
+
+
+
+
+| | Èç¹ûÄãÏëÔÚÈÕÖ¾ÊôÐÔÖÐʹÓÃռλ·û£¬ÄãÓ¦¸ÃʹÓÃ[Spring BootµÄÓï·¨](https://springdoc.cn/spring-boot/features.html#features.external-config.files.property-placeholders)¶ø²»Êǵײã¿ò¼ÜµÄÓï·¨¡£ ÖµµÃ×¢ÒâµÄÊÇ£¬Èç¹ûÄãʹÓÃLogback£¬ÄãÓ¦¸ÃʹÓà `:` ×÷ΪÊôÐÔÃûºÍÆäĬÈÏÖµÖ®¼äµÄ·Ö¸ô·û£¬¶ø²»ÊÇʹÓà `:-` ¡£ |
+| --- | --- |
+
+
+
+
+
+| | Äã¿ÉÒÔͨ¹ýÖ»¸²¸Ç `LOG_LEVEL_PATTERN` £¨»òʹÓÃLogbackµÄ `logging.pattern.level` £©À´ÏòÈÕÖ¾ÐÐÌí¼ÓMDCºÍÆäËûÁÙʱÄÚÈÝ¡£ ÀýÈ磬Èç¹ûÄãʹÓà `logging.pattern.level=user:%X{user} %5p` £¬ÄÇôĬÈϵÄÈÕÖ¾¸ñʽ°üº¬Ò»¸ö "user" µÄMDCÌõÄ¿£¬Èç¹ûËü´æÔڵϰ£¬ÈçÏÂÀýËùʾ¡£ 2019-08-30 12:30:04.031 user:someone INFO 22174 --- [ nio-8080-exec-0] demo.ControllerHandling authenticated request |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.logging.logback-extensions)4.9\. Logback À©Õ¹
+
+
+
+Spring Boot°üÀ¨Ò»Ð©¶ÔLogbackµÄÀ©Õ¹£¬¿ÉÒÔ°ïÖú½øÐи߼¶ÅäÖᣠÄã¿ÉÒÔÔÚÄãµÄ `logback-spring.xml` ÅäÖÃÎļþÖÐʹÓÃÕâЩÀ©Õ¹¡£
+
+
+
+
+
+| | ÒòΪ±ê×¼µÄ `logback.xml` ÅäÖÃÎļþ±»¹ýÔç¼ÓÔØ£¬Äã²»ÄÜÔÚÆäÖÐʹÓÃÀ©Õ¹¡£ ÄãÐèҪʹÓà `logback-spring.xml` »òÕß¶¨ÒåÒ»¸ö `logging.config` ÊôÐÔ¡£ |
+| --- | --- |
+
+
+
+
+
+| | À©Õ¹³ÌÐò²»ÄÜÓë [LogbackµÄÅäÖÃɨÃè](https://logback.qos.ch/manual/configuration.html#autoScan) Ò»ÆðʹÓᣠÈç¹ûÄãÊÔͼÕâÑù×ö£¬¶ÔÅäÖÃÎļþ½øÐÐÐ޸ĻᵼÖÂÀàËÆÓÚÒÔϵĴíÎ󱻼ǼÏÂÀ´¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+ ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProperty], current ElementPath is [[configuration][springProperty]]
+ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:71 - no applicable action for [springProfile], current ElementPath is [[configuration][springProfile]]
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.logging.logback-extensions.profile-specific)4.9.1\. ÌØ¶¨µÄÅäÖÃÎļþ
+
+
+
+`` ±êÇ©ÈÃÄã¿ÉÒÔ¸ù¾Ý»î¶¯µÄSpringÅäÖÃÎļþÑ¡ÔñÐԵذüÀ¨»òÅųýÅäÖõIJ¿·Ö£¬ Ö§³ÖÔÚ `` ÔªËØµÄÈκεط½¶¨ÒåËü¡£ ʹÓà `name` ÊôÐÔÀ´Ö¸¶¨½ÓÊÜÅäÖõÄÅäÖÃÎļþ¡£ `` ±êÇ©¿ÉÒÔ°üº¬Ò»¸öÅäÖÃÎļþÃû³Æ£¨ÀýÈç `staging` £©»òÒ»¸öÅäÖÃÎļþ±í´ïʽ¡£ ÅäÖÃÎļþ±í´ïʽÔÊÐí±í´ï¸ü¸´ÔÓµÄÅäÖÃÎļþÂß¼£¬ÀýÈç `production & (eu-central | eu-west)` ¡£ ²é¿´ [Spring ¿ò¼Ü²Î¿¼Ö¸ÄÏ](https://docs.spring.io/spring-framework/docs/6.0.5/reference/html/core.html#beans-definition-profiles-java) ÒÔÁ˽â¸ü¶àϸ½Ú¡£ ÏÂÃæµÄÁбíÏÔʾÁËÈý¸öÑù±¾ÅäÖÃÎļþ¡£
+
+
+
+
+
+
+
+```
+
+
+
+
+
+
+
+
+
+
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.logging.logback-extensions.environment-properties)4.9.2\. £¨»·¾³ÊôÐÔ£©Environment Properties
+
+
+
+`` ±êÇ©¿ÉÒÔ·ÃÎÊ Spring `Environment` ÖеÄÊôÐÔ£¬ÒÔ±ãÔÚLogbackÖÐʹÓᣠÈç¹ûÄãÏëÔÚLogbackÅäÖÃÖзÃÎÊ `application.properties` ÎļþÖеÄÖµ£¬ÕâÑù×ö»áºÜÓÐÓᣠ¸Ã±êÇ©µÄ¹¤×÷·½Ê½ÓëLogbackµÄ±ê×¼ `` ±êÇ©ÀàËÆ¡£ È»¶ø£¬Äã²»ÊÇÖ±½ÓÖ¸¶¨Ò»¸ö `value` £¬¶øÊÇÖ¸¶¨ÊôÐ﵀ `source` £¨À´×Ô `Environment` £©¡£ Èç¹ûÄãÐèÒªÔÚ `local` ·¶Î§ÒÔÍâµÄµØ·½´æ´¢¸ÃÊôÐÔ£¬Äã¿ÉÒÔʹÓà `scope` ÊôÐÔ¡£ Èç¹ûÄãÐèÒªÒ»¸öºó±¸Öµ£¨Ä¬ÈÏÖµ£©£¨ÍòÒ»¸ÃÊôÐÔûÓÐÔÚ `Environment` ÖÐÉèÖã©£¬Äã¿ÉÒÔʹÓà `defaultValue` ÊôÐÔ¡£ ÏÂÃæµÄÀý×ÓÏÔʾÁËÈçºÎ¹«¿ªÊôÐÔÒÔ±ãÔÚLogbackÖÐʹÓá£
+
+
+
+
+
+
+
+```
+
+
+ ${fluentHost}
+ ...
+
+```
+
+
+
+
+
+
+
+| | `source` ±ØÐëÒÔkebab·ç¸ñÖ¸¶¨£¨Èç `my.property-name` £©¡£ È»¶ø£¬ÊôÐÔ¿ÉÒÔͨ¹ýʹÓÿíËɵĹæÔòÌí¼Óµ½ `Environment` ÖС£ |
+| --- | --- |
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.logging.log4j2-extensions)4.10\. Log4j2 À©Õ¹
+
+
+
+Spring Boot°üÀ¨Ò»Ð©¶ÔLog4j2µÄÀ©Õ¹£¬¿ÉÒÔ°ïÖú½øÐи߼¶ÅäÖá£Äã¿ÉÒÔÔÚÈκΠ`log4j2-spring.xml` ÅäÖÃÎļþÖÐʹÓÃÕâЩÀ©Õ¹¡£
+
+
+
+
+
+| | ÒòΪ±ê×¼µÄ `log4j2.xml` ÅäÖÃÎļþ±»¹ýÔç¼ÓÔØ£¬Äã²»ÄÜÔÚÆäÖÐʹÓÃÀ©Õ¹¡£ÄãÐèҪʹÓà `log4j2-spring.xml` »òÕß¶¨ÒåÒ»¸ö ``logging.config`` ÊôÐÔ¡£ |
+| --- | --- |
+
+
+
+
+
+| | ÕâЩÀ©Õ¹È¡´úÁËLog4JÌṩµÄ [Spring BootÖ§³Ö](https://logging.apache.org/log4j/2.x/log4j-spring-boot/index.html)¡£ ÄãÓ¦¸ÃÈ·±£ÔÚÄãµÄ¹¹½¨Öв»°üÀ¨ `org.apache.logging.log4j:log4j-spring-boot` Ä£¿é¡£ |
+| --- | --- |
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.logging.log4j2-extensions.profile-specific)4.10.1\. ÌØ¶¨ÅäÖÃÎļþÅäÖÃ
+
+
+
+`` ±êÇ©ÈÃÄã¿ÉÒÔ¸ù¾Ý»î¶¯µÄSpringÅäÖÃÎļþÑ¡ÔñÐԵذüÀ¨»òÅųýÅäÖõIJ¿·Ö¡£ÅäÖÃÎļþ²¿·Ö±»Ö§³ÖÔÚ `` ÔªËØµÄÈκεط½¡£Ê¹Óà `name` ÊôÐÔÀ´Ö¸¶¨ÄĸöÅäÖÃÎļþ½ÓÊÜÅäÖᣠ`` ±êÇ©¿ÉÒÔ°üº¬Ò»¸öÅäÖÃÎļþÃû³Æ£¨ÀýÈç `staging`£©»òÒ»¸öÅäÖÃÎļþ±í´ïʽ¡£ ÅäÖÃÎļþ±í´ïʽÔÊÐí±í´ï¸ü¸´ÔÓµÄÅäÖÃÎļþÂß¼£¬ÀýÈç `production & (eu-central | eu-west)`¡£²é¿´ [Spring¿ò¼Ü²Î¿¼Ö¸ÄÏ](https://docs.spring.io/spring-framework/docs/6.0.5/reference/html/core.html#beans-definition-profiles-java) ÒÔÁ˽â¸ü¶àϸ½Ú¡£ ÏÂÃæµÄÁбíÏÔʾÁËÈý¸öÑù±¾ÅäÖÃÎļþ¡£
+
+
+
+
+
+
+
+```
+
+
+
+
+
+
+
+
+
+
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.logging.log4j2-extensions.environment-properties-lookup)4.10.2\. »·¾³£¨Environment£©ÊôÐÔ²éÕÒ
+
+
+
+Èç¹ûÄãÏëÔÚLog4j2ÅäÖÃÖÐÒýÓÃSpring `Environment` ÖеÄÊôÐÔ£¬Äã¿ÉÒÔʹÓà `spring:` ǰ׺ [²éÕÒ](https://logging.apache.org/log4j/2.x/manual/lookups.html)¡£Èç¹ûÄãÏëÔÚLog4j2ÅäÖÃÖзÃÎÊ `application.properties` ÎļþÖеÄÖµ£¬ÕâÑù×ö»áºÜÓÐÓá£
+
+
+
+
+
+ÏÂÃæµÄÀý×ÓÏÔʾÁËÈçºÎÉèÖÃÒ»¸öÃûΪ `applicationName` µÄLog4j2ÊôÐÔ£¬Ëü´ÓSpring `Environment` ÖжÁÈ¡ `spring.application.name`¡£
+
+
+
+
+
+
+
+```
+
+ ${spring:spring.application.name}
+
+```
+
+
+
+
+
+
+
+| | ²éѯkeyÓ¦ÒÔkebabf·ç¸ñÖ¸¶¨£¨Èç `my.property-name`£©¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.logging.log4j2-extensions.environment-property-source)4.10.3\. Log4j2 ϵͳÊôÐÔ£¨System Properties£©
+
+
+
+Log4j2Ö§³ÖһЩ [System Properties](https://logging.apache.org/log4j/2.x/manual/configuration.html#SystemProperties)£¬¿ÉÒÔÓÃÀ´ÅäÖø÷ÖÖÏîÄ¿¡£ÀýÈ磬`log4j2.skipJansi` ϵͳÊôÐÔ¿ÉÒÔÓÃÀ´ÅäÖà `ConsoleAppender` ÊÇ·ñ»áÔÚWindowsÉϳ¢ÊÔʹÓà [Jansi](https://github.com/fusesource/jansi) Êä³öÁ÷¡£
+
+
+
+
+
+Log4j2 ³õʼ»¯ºó¼ÓÔØµÄËùÓÐϵͳÊôÐÔ¶¼¿ÉÒÔ´ÓSpring `Environment` ÖлñµÃ¡£ÀýÈ磬Äã¿ÉÒÔÔÚ `application.properties` ÎļþÖÐÌí¼Ó `log4j2.skipJansi=false`£¬Èà `ConsoleAppender` ÔÚWindowsÉÏʹÓÃJansi¡£
+
+
+
+
+
+| | Ö»Óе±ÏµÍ³ÊôÐÔ£¨system properties£©ºÍ²Ù×÷ϵͳ»·¾³±äÁ¿²»°üº¬ÕýÔÚ¼ÓÔØµÄֵʱ£¬²Å»á¿¼ÂÇSpring `Environment`¡£ |
+| --- | --- |
+
+
+
+
+
+| | ÔÚÔçÆÚLog4j2³õʼ»¯ÆÚ¼ä¼ÓÔØµÄϵͳÊôÐÔ²»ÄÜÒýÓÃSpring `Environment`¡£ÀýÈ磬Log4j2ÓÃÓÚÔÊÐíÑ¡ÔñĬÈÏLog4j2ʵÏÖµÄÊôÐÔÊÇÔÚ Spring Environment ¿ÉÓÃ֮ǰʹÓõġ£ |
+| --- | --- |
+
+
+
+
+
+
+
diff --git "a/docs/spring/SpringBoot/SpringBoot\345\272\224\347\224\250\344\271\237\345\217\257\344\273\245\351\203\250\347\275\262\345\210\260\345\244\226\351\203\250Tomcat.md" "b/docs/spring/SpringBoot/SpringBoot\345\272\224\347\224\250\344\271\237\345\217\257\344\273\245\351\203\250\347\275\262\345\210\260\345\244\226\351\203\250Tomcat.md"
new file mode 100644
index 0000000..e22fa00
--- /dev/null
+++ "b/docs/spring/SpringBoot/SpringBoot\345\272\224\347\224\250\344\271\237\345\217\257\344\273\245\351\203\250\347\275\262\345\210\260\345\244\226\351\203\250Tomcat.md"
@@ -0,0 +1,302 @@
+
+
+
+
+# Spring Boot Tomcat²¿Êð
+
+ÒÔÏÂÄÚÈݽöÊÇÕ¾³¤»òÍøÓѸöÈËѧϰ±Ê¼Ç¡¢×ܽáºÍÑо¿Êղء£²»±£Ö¤ÕýÈ·ÐÔ£¬ÒòʹÓöø´øÀ´µÄ·çÏÕÓë±¾Õ¾Î޹أ¡
+
+
+
+
+
+
+
+
+
+ͨ¹ýʹÓÃSpring BootÓ¦ÓóÌÐò£¬¿ÉÒÔ´´½¨Ò»¸öwarÎļþÒÔ²¿Êðµ½Web·þÎñÆ÷ÖС£ÔÚ±¾ÕÂÖУ¬½«Ñ§Ï°ÈçºÎ´´½¨WARÎļþ²¢ÔÚTomcat Web·þÎñÆ÷Öв¿ÊðSpring BootÓ¦ÓóÌÐò¡£
+
+## Spring Boot Servlet³õʼ»¯³ÌÐò
+
+´«Í³µÄ²¿Êð·½Ê½ÊÇʹSpring BootÓ¦ÓóÌÐò`[@SpringBootApplication](https://github.com/SpringBootApplication "@SpringBootApplication")`ÀàÀ©Õ¹`SpringBootServletInitializer`Àà¡£ `SpringBootServletInitializer`ÀàÎļþÔÊÐíÔÚʹÓÃServletÈÝÆ÷Æô¶¯Ê±ÅäÖÃÓ¦ÓóÌÐò¡£
+
+ÏÂÃæ¸ø³öÁËÓÃÓÚJARÎļþ²¿ÊðµÄSpring BootÓ¦ÓóÌÐòÀàÎļþµÄ´úÂë -
+
+```
+package com.yiibai.demo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DemoApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(DemoApplication.class, args);
+ }
+}
+
+```
+
+ÐèÒªÀ©Õ¹Àà`SpringBootServletInitializer`ÒÔÖ§³ÖWARÎļþ²¿Êð¡£ Spring BootÓ¦ÓóÌÐòÀàÎļþµÄ´úÂëÈçÏ -
+
+```
+package com.yiibai.demo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.support.SpringBootServletInitializer;
+
+@SpringBootApplication
+public class DemoApplication extends SpringBootServletInitializer {
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(DemoApplication.class);
+ }
+ public static void main(String[] args) {
+ SpringApplication.run(DemoApplication.class, args);
+ }
+}
+
+```
+
+## ÉèÖÃMainÀà
+
+ÔÚSpring BootÖУ¬ÐèÒªÔÚ¹¹½¨ÎļþÖÐÖ¸¶¨Æô¶¯µÄÖ÷Àà¡£
+¶ÔÓÚMaven£¬ÔÚ`pom.xml`ÊôÐÔÖÐÌí¼Ó`start`À࣬ÈçÏÂËùʾ -
+
+```
+com.yiibai.demo.DemoApplication
+
+```
+
+¶ÔÓÚGradle£¬ÔÚ`build.gradle`ÖÐÌí¼ÓÖ÷ÀàÃû£¬ÈçÏÂËùʾ -
+
+```
+mainClassName="com.yiibai.demo.DemoApplication"
+
+```
+
+## ½«´ò°üJAR¸üÐÂΪWAR
+
+ʹÓÃÒÔÏ´úÂ뽫°ü×°JAR¸üÐÂΪWAR¡£
+
+¶ÔÓÚMaven£¬ÔÚ_pom.xml_ Öн«°ü×°Ìí¼ÓΪWAR£¬ÈçÏÂËùʾ -
+
+```
+war
+
+```
+
+¶ÔÓÚGradle£¬ÔÚ_build.gradle_ ÖÐÌí¼ÓÓ¦ÓóÌÐò²å¼þºÍwar²å¼þ£¬ÈçÏÂËùʾ -
+
+```
+apply plugin: 'war'
+apply plugin: 'application'
+
+```
+
+¶ÔÓÚGradlNow£¬±àдһ¸ö¼òµ¥µÄRest¶ËµãÀ´·µ»Ø×Ö·û´®:`"Hello World from Tomcat"`¡£ Òª±àдRest¶Ëµã£¬ÐèÒª½«Spring Boot Web starterÒÀÀµÏîÌí¼Óµ½¹¹½¨ÎļþÖС£
+
+¶ÔÓÚMaven£¬Ê¹ÓÃÈçÏÂËùʾµÄ´úÂëÔÚ_pom.xml_ ÖÐÌí¼ÓSpring BootÆô¶¯³ÌÐòÒÀÀµÏî -
+
+```
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+```
+
+¶ÔÓÚGradle£¬Ê¹ÓÃÈçÏÂËùʾµÄ´úÂëÔÚ_build.gradle_ ÖÐÌí¼ÓSpring Boot starterÒÀÀµÏî -
+
+```
+dependencies {
+ compile('org.springframework.boot:spring-boot-starter-web')
+}
+
+```
+
+ÏÖÔÚ£¬Ê¹ÓÃÈçÏÂËùʾµÄ´úÂëÔÚSpring Boot ApplicationÀàÎļþÖбàдһ¸ö¼òµ¥µÄRest¶Ëµã -
+
+```
+package com.yiibai.demo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.support.SpringBootServletInitializer;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@SpringBootApplication
+@RestController
+public class DemoApplication extends SpringBootServletInitializer {
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(DemoApplication.class);
+ }
+ public static void main(String[] args) {
+ SpringApplication.run(DemoApplication.class, args);
+ }
+
+ @RequestMapping(value = "/")
+ public String hello() {
+ return "Hello World from Tomcat";
+ }
+}
+
+```
+
+## ´ò°üÓ¦ÓóÌÐò
+
+ÏÖÔÚ£¬Ê¹ÓÃMavenºÍGradleÃüÁî´´½¨Ò»¸öWARÎļþÒÔ²¿Êðµ½Tomcat·þÎñÆ÷ÖУ¬ÒÔ´ò°üÓ¦ÓóÌÐò£¬ÈçÏÂËùʾ¡£
+
+¶ÔÓÚMaven£¬Ê¹ÓÃÃüÁî`mvn package`´ò°üÓ¦ÓóÌÐò¡£ È»ºó´´½¨WARÎļþ£¬¿ÉÒÔÔÚÄ¿±êĿ¼ÖÐÕÒµ½Ëü£¬ÈçÏÂÃæ¸ø³öµÄÆÁÄ»½ØÍ¼Ëùʾ -
+
+
+
+¶ÔÓÚGradle£¬Ê¹ÓÃÃüÁî`gradle clean build`´ò°üÓ¦ÓóÌÐò¡£ È»ºó£¬½«´´½¨WARÎļþ£¬¿ÉÒÔÔÚ`build/libs`Ŀ¼ÏÂÕÒµ½Ëü¡£¹Û²ì´Ë´¦¸ø³öµÄÆÁÄ»½ØÍ¼ÒÔ±ã¸üºÃµØÀí½â -
+
+
+
+## ²¿Êðµ½Tomcat
+
+ÏÖÔÚ£¬ÔËÐÐTomcat·þÎñÆ÷£¬²¢ÔÚwebappsĿ¼Ï²¿ÊðWARÎļþ¡£¹Û²ì´Ë´¦ÏÔʾµÄÆÁÄ»½ØÍ¼ÒÔ±ã¸üºÃµØÀí½â -
+
+
+
+³É¹¦²¿Êðºó£¬µã»÷ÍøÒ³ä¯ÀÀÆ÷ÖеÄURL => `http://localhost:8080/demo-0.0.1-SNAPSHOT/`£¬¹Û²ìÊä³ö½á¹ûÈçÏÂͼËùʾ -
+
+
+
+ÍêÕû´úÂëÈçÏ£º
+
+Îļþ£º_pom.xml_ -
+
+```
+
+
+4.0.0
+
+ com.yiibai
+ demo
+ 0.0.1-SNAPSHOT
+ war
+ demo
+ Demo project for Spring Boot
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.5.8.RELEASE
+
+
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ com.yiibai.demo.DemoApplication
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+```
+
+Îļþ£º_build.gradle_
+
+```
+buildscript {
+ ext {
+ springBootVersion = '1.5.8.RELEASE'
+ }
+ repositories {
+ mavenCentral()
+ }
+dependencies {
+ classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
+ }
+}
+
+apply plugin: 'java'
+apply plugin: 'eclipse'
+apply plugin: 'org.springframework.boot'
+apply plugin: 'war'
+apply plugin: 'application'
+
+group = 'com.yiibai'
+version = '0.0.1-SNAPSHOT'
+sourceCompatibility = 1.8
+mainClassName = "com.yiibai.demo.DemoApplication"
+
+repositories {
+ mavenCentral()
+}
+dependencies {
+ compile('org.springframework.boot:spring-boot-starter-web')
+ testCompile('org.springframework.boot:spring-boot-starter-test')
+}
+
+```
+
+Spring BootÓ¦ÓóÌÐòÀàÎļþµÄ´úÂëÈçÏ -
+
+```
+package com.yiibai.demo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.support.SpringBootServletInitializer;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@SpringBootApplication
+@RestController
+public class DemoApplication extends SpringBootServletInitializer {
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ return application.sources(DemoApplication.class);
+ }
+ public static void main(String[] args) {
+ SpringApplication.run(DemoApplication.class, args);
+ }
+
+ @RequestMapping(value = "/")
+ public String hello() {
+ return "Hello World from Tomcat";
+ }
+}
+```
+
+
+
+
+
+//¸ü¶àÇëÔĶÁ£ºhttps://www.yiibai.com/spring-boot/spring_boot_tomcat_deployment.html
+
diff --git "a/docs/spring/SpringBoot/SpringBoot\347\224\237\344\272\247\347\216\257\345\242\203\345\267\245\345\205\267Actuator.md" "b/docs/spring/SpringBoot/SpringBoot\347\224\237\344\272\247\347\216\257\345\242\203\345\267\245\345\205\267Actuator.md"
new file mode 100644
index 0000000..e0eeb3e
--- /dev/null
+++ "b/docs/spring/SpringBoot/SpringBoot\347\224\237\344\272\247\347\216\257\345\242\203\345\267\245\345\205\267Actuator.md"
@@ -0,0 +1,5832 @@
+
+
+# Éú²ú¾ÍÐ÷¹¦ÄÜ
+
+[Back to index](https://springdoc.cn/spring-boot/index.html)
+
+* [1\. ÆôÓÃÉú²ú¾ÍÐ÷µÄ¹¦ÄÜ](https://springdoc.cn/spring-boot/actuator.html#actuator.enabling)
+* [2\. ¶Ëµã£¨Endpoint£©](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints)
+* [3\. ͨ¹ýHTTP½øÐÐ¼à¿ØºÍ¹ÜÀí](https://springdoc.cn/spring-boot/actuator.html#actuator.monitoring)
+* [4\. ͨ¹ýJMX½øÐÐ¼à¿ØºÍ¹ÜÀí](https://springdoc.cn/spring-boot/actuator.html#actuator.jmx)
+* [5\. ¿É¹Û²âÐÔ£¨Observability£©](https://springdoc.cn/spring-boot/actuator.html#actuator.observability)
+* [6\. ÈÕÖ¾¼Ç¼Æ÷£¨Logger£©](https://springdoc.cn/spring-boot/actuator.html#actuator.loggers)
+* [7\. Ö¸±ê£¨Metrics£©](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics)
+* [8\. ×·×Ù£¨Tracing£©](https://springdoc.cn/spring-boot/actuator.html#actuator.micrometer-tracing)
+* [9\. Éó¼Æ](https://springdoc.cn/spring-boot/actuator.html#actuator.auditing)
+* [10\. ¼Ç¼ HTTP Exchange](https://springdoc.cn/spring-boot/actuator.html#actuator.http-exchanges)
+* [11\. ½ø³Ì¼à¿Ø](https://springdoc.cn/spring-boot/actuator.html#actuator.process-monitoring)
+* [12\. Cloud Foundry µÄÖ§³Ö](https://springdoc.cn/spring-boot/actuator.html#actuator.cloud-foundry)
+* [13\. ½ÓÏÂÀ´¶Áʲô](https://springdoc.cn/spring-boot/actuator.html#actuator.whats-next)
+
+
+
+
+
+
+
+
+
+
+
+
+
+| | ±¾Õ¾([springdoc.cn](https://springdoc.cn/))ÖеÄÄÚÈÝÀ´Ô´ÓÚ [spring.io](https://spring.io/) £¬Ôʼ°æÈ¨¹éÊôÓÚ [spring.io](https://spring.io/)¡£ÓÉ [springboot.io - Spring BootÖÐÎÄÉçÇø](https://springboot.io/) ½øÐзÒ룬ÕûÀí¡£¿É¹©¸öÈËѧϰ¡¢Ñо¿£¬Î´¾Ðí¿É£¬²»µÃ½øÐÐÈκÎ×ªÔØ¡¢ÉÌÓûòÓëÖ®Ïà¹ØµÄÐÐΪ¡£ É̱êÉùÃ÷£ºSpring ÊÇ Pivotal Software, Inc. ÔÚÃÀ¹úÒÔ¼°ÆäËû¹ú¼ÒµÄÉ̱ꡣ |
+| --- | --- |
+
+
+
+
+
+Spring Boot°üÀ¨Ò»Ð©¶îÍâµÄ¹¦ÄÜ£¬ÒÔ°ïÖúÄãÔÚ½«Ó¦ÓóÌÐò·¢²¼µ½Éú²úʱ¼à¿ØºÍ¹ÜÀíÄãµÄÓ¦ÓóÌÐò¡£ Äã¿ÉÒÔÑ¡Ôñͨ¹ýʹÓÃHTTP¶Ëµã»òʹÓÃJMXÀ´¹ÜÀíºÍ¼à¿ØÄãµÄÓ¦ÓóÌÐò¡£ É󼯡¢½¡¿µºÍÖ¸±êÊÕ¼¯Ò²¿ÉÒÔ×Ô¶¯Ó¦ÓÃÓÚÄãµÄÓ¦ÓóÌÐò¡£
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.enabling)1\. ÆôÓÃÉú²ú¾ÍÐ÷µÄ¹¦ÄÜ
+
+
+
+
+
+[`spring-boot-actuator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator) Ä£¿éÌṩÁËËùÓÐSpring BootµÄÉú²ú¾ÍÐ÷¹¦ÄÜ¡£ ÆôÓÃÕâЩ¹¦ÄܵÄÍÆ¼ö·½·¨ÊÇÌí¼Ó¶Ô `spring-boot-starter-actuator` ¡°Starter¡± µÄÒÀÀµ¡£
+
+
+
+
+
+
+
+ActuatorµÄ¶¨Òå
+
+
+
+actuator£¨Ö´ÐÐÆ÷£© ÊÇÒ»¸öÖÆÔìÊõÓָµÄÊÇÓÃÓÚÒÆ¶¯»ò¿ØÖÆÄ³ÎïµÄ»úеװÖá£actuator ¿ÉÒÔ´ÓÒ»¸öСµÄ±ä»¯ÖвúÉú´óÁ¿µÄÔ˶¯¡£
+
+
+
+
+
+
+
+
+
+ÒªÔÚ»ùÓÚMavenµÄÏîÄ¿ÖÐÌí¼Óactuator£¬ÇëÌí¼ÓÒÔÏ ¡°Starter¡± ÒÀÀµ¡£
+
+
+
+
+
+
+
+```
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+```
+
+
+
+
+
+
+
+¶ÔÓÚGradle£¬Ê¹ÓÃÒÔÏÂÉùÃ÷¡£
+
+
+
+
+
+
+
+```
+dependencies {
+ implementation 'org.springframework.boot:spring-boot-starter-actuator'
+}
+```
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints)2\. ¶Ëµã£¨Endpoint£©
+
+
+
+
+
+Actuator ¶Ëµã£¨endpoint£©ÈÃÄã¿ÉÒÔ¼à¿Ø²¢ÓëÄãµÄÓ¦ÓóÌÐò»¥¶¯¡£ Spring Boot°üÀ¨Ò»Ð©ÄÚÖõĶ˵㣬²¢ÔÊÐíÄãÌí¼Ó×Ô¼ºµÄ¶Ëµã¡£ ÀýÈ磬`health` ¶ËµãÌṩ»ù±¾µÄÓ¦ÓóÌÐò½¡¿µÐÅÏ¢¡£
+
+
+
+
+
+Äã¿ÉÒÔ[ÆôÓûò½ûÓÃ](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.enabling)ÿ¸öµ¥¶ÀµÄ¶Ëµã£¬²¢[ͨ¹ýHTTP»òJMX¹«¿ªËüÃÇ£¨Ê¹ËüÃÇ¿ÉÒÔÔ¶³Ì·ÃÎÊ£©](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.exposing)¡£µ±Ò»¸ö¶Ëµã±»ÆôÓúͱ©Â¶Ê±£¬Ëü±»ÈÏΪÊÇ¿ÉÓõġ£ÄÚÖõĶ˵ãÖ»ÓÐÔÚËüÃÇ¿ÉÓÃʱ²Å»á±»×Ô¶¯ÅäÖᣴó¶àÊýÓ¦ÓóÌÐòÑ¡Ôñͨ¹ýHTTP±©Â¶£¬ÆäÖж˵ãµÄIDºÍ `/actuator` µÄǰ׺±»Ó³Éäµ½Ò»¸öURL¡£ÀýÈ磬ĬÈÏÇé¿öÏ£¬`health` ¶Ëµã±»Ó³Éäµ½ `/actuator/health`¡£
+
+
+
+
+
+| | ÒªÁ˽â¸ü¶à¹ØÓÚactuatorµÄ¶ËµãÒÔ¼°ËüÃǵÄÇëÇóºÍÏìÓ¦¸ñʽ£¬Çë¿´µ¥¶ÀµÄAPIÎĵµ£¨ [HTML](https://docs.spring.io/spring-boot/docs/3.1.0-SNAPSHOT/actuator-api/htmlsingle) »ò [PDF](https://docs.spring.io/spring-boot/docs/3.1.0-SNAPSHOT/actuator-api/pdf/spring-boot-actuator-web-api.pdf)£©¡£ |
+| --- | --- |
+
+
+
+
+
+ÒÔÏÂÊǼ¼ÊõÎ޹صÄÖÕ¶Ë¡£
+
+
+
+
+| ID | ˵Ã÷ |
+| --- | --- |
+| `auditevents` | ¹«¿ªµ±Ç°Ó¦ÓóÌÐòµÄÉó¼ÆÊ¼þÐÅÏ¢¡£ ÐèÒªÒ»¸ö `AuditEventRepository` bean¡£ |
+| `beans` | ÏÔʾÄãµÄÓ¦ÓóÌÐòÖÐËùÓÐSpring BeanµÄÍêÕûÁÐ±í¡£ |
+| `caches` | ÏÔʾ¿ÉÓõĻº´æ¡£ |
+| `conditions` | ÏÔʾ¶ÔÅäÖúÍ×Ô¶¯ÅäÖÃÀà½øÐÐÆÀ¹ÀµÄÌõ¼þ£¬ÒÔ¼°ËüÃÇ·ûºÏ»ò²»·ûºÏµÄÔÒò¡£ |
+| `configprops` | ÏÔʾËùÓÐ `@ConfigurationProperties` µÄÕûÀíÁÐ±í¡£ |
+| `env` | ±©Â¶SpringµÄ `ConfigurableEnvironment` ÖеÄÊôÐÔ¡£ |
+| `flyway` | ÏÔʾÈκÎÒѾӦÓõÄFlywayÊý¾Ý¿âÇ¨ÒÆ¡£ ÐèÒªÒ»¸ö»ò¶à¸ö `Flyway` bean¡£ |
+| `health` | ÏÔʾӦÓóÌÐòµÄ½¡¿µÐÅÏ¢¡£ |
+| `httpexchanges` | ÏÔʾ HTTP exchange ÐÅÏ¢£¨Ä¬ÈÏÇé¿öÏ£¬×îºó 100 ¸ö HTTP request/response exchange£©¡£ ÐèÒªÒ»¸ö `HttpExchangeRepository` bean¡£ |
+| `info` | ÏÔʾÈÎÒâµÄÓ¦ÓóÌÐòÐÅÏ¢¡£ |
+| `integrationgraph` | ÏÔʾSpring¼¯³Éͼ¡£ ÐèÒªÒÀÀµ `spring-integration-core`¡£ |
+| `loggers` | ÏÔʾºÍÐÞ¸ÄÓ¦ÓóÌÐòÖÐloggerµÄÅäÖᣠ|
+| `liquibase` | ÏÔʾÈκÎÒѾӦÓõÄLiquibaseÊý¾Ý¿âÇ¨ÒÆ¡£ ÐèÒªÒ»¸ö»ò¶à¸ö `Liquibase` Bean¡£ |
+| `metrics` | ÏÔʾµ±Ç°Ó¦ÓóÌÐòµÄ ¡°metrics¡± ÐÅÏ¢¡£ |
+| `mappings` | ÏÔʾËùÓÐ `@RequestMapping` ·¾¶µÄÕûÀíÁÐ±í¡£ |
+| `quartz` | ÏÔʾÓйØQuartz Scheduler JobµÄÐÅÏ¢¡£ |
+| `scheduledtasks` | ÏÔʾÄãµÄÓ¦ÓóÌÐòÖеļƻ®ÈÎÎñ¡£ |
+| `sessions` | ÔÊÐí´ÓSpring SessionÖ§³ÖµÄ»á»°´æ´¢ÖмìË÷ºÍɾ³ýÓû§»á»°¡£ ÐèÒªÒ»¸öʹÓÃSpring SessionµÄ»ùÓÚServletµÄWebÓ¦ÓóÌÐò¡£ |
+| `shutdown` | ÈÃÓ¦ÓóÌÐòÓÅÑŵعرա£Ö»ÔÚʹÓÃjar´ò°üʱÓÐЧ¡£Ä¬ÈÏÇé¿öÏÂÊǽûÓõġ£ |
+| `startup` | ÏÔʾÓÉ `ApplicationStartup` ÊÕ¼¯µÄ[Æô¶¯²½ÖèÊý¾Ý](https://springdoc.cn/spring-boot/features.html#features.spring-application.startup-tracking)¡£ÒªÇó `SpringApplication` ±»ÅäÖÃΪ `BufferingApplicationStartup`¡£ |
+| `threaddump` | Performs a thread dump. |
+
+
+
+Èç¹ûÄãµÄÓ¦ÓóÌÐòÊÇÒ»¸öWebÓ¦ÓóÌÐò£¨Spring MVC¡¢Spring WebFlux»òJersey£©£¬Äã¿ÉÒÔʹÓÃÒÔ϶îÍâµÄ¶Ëµã¡£
+
+
+
+
+| ID | ˵Ã÷ |
+| --- | --- |
+| `heapdump` | ·µ»ØÒ»¸ö¶ÑdumpÎļþ¡£ ÔÚHotSpot JVMÉÏ£¬·µ»ØÒ»¸ö `HPROF` ¸ñʽµÄÎļþ¡£ ÔÚOpenJ9 JVMÉÏ£¬·µ»ØÒ»¸ö `PHD` ¸ñʽµÄÎļþ¡£ |
+| `logfile` | ·µ»ØÈÕÖ¾ÎļþµÄÄÚÈÝ£¨Èç¹û `logging.file.name` »ò `logging.file.path` ÊôÐÔÒѱ»ÉèÖã©¡£ Ö§³ÖʹÓÃHTTP `Range` Í·À´¼ìË÷ÈÕÖ¾ÎļþµÄ²¿·ÖÄÚÈÝ¡£ |
+| `prometheus` | ÒԿɱ» Prometheus ·þÎñÆ÷ץȡµÄ¸ñʽչʾ¶ÈÁ¿£¨metric£©¡£ ÒÀÀµÓÚ `micrometer-registry-prometheus`¡£ |
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.enabling)2.1\. ÆôÓö˵ã
+
+
+
+ĬÈÏÇé¿öÏ£¬³ý `shutdown` ÍâµÄËùÓж˵㶼±»ÆôÓᣠҪÅäÖÃÒ»¸ö¶ËµãµÄÆôÓã¬ÇëʹÓÃÆä `management.endpoint..enabled` ÊôÐÔ¡£ ÏÂÃæµÄÀý×ÓÆôÓÃÁË `shutdown` ¶Ëµã¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoint.shutdown.enabled=true
+
+```
+
+
+
+
+
+
+
+Èç¹ûÄãÏ£Íû¶ËµãÆôÓÃÊÇ¡°Ñ¡ÔñÆôÓá±¶ø²»ÊÇ¡°Ñ¡Ôñ½ûÓá±£¬Ç뽫 `management.endpoints.enabled-by-default` ÊôÐÔÉèÖÃΪ `false`£¬²¢Ê¹Óõ¥¸ö¶ËµãµÄ `enabled` ÊôÐÔÀ´Ñ¡ÔñÖØÐÂÆôÓᣠÏÂÃæµÄÀý×ÓÆôÓÃÁË `info` ¶Ëµã£¬²¢½ûÓÃÁËËùÓÐÆäËû¶Ëµã¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoints.enabled-by-default=false
+management.endpoint.info.enabled=true
+
+```
+
+
+
+
+
+
+
+| | ±»½ûÓõĶ˵ã»á´ÓÓ¦ÓóÌÐòÉÏÏÂÎÄÖÐÍêȫɾ³ý¡£Èç¹ûÄãÏëÖ»¸Ä±ä±©Â¶¶ËµãµÄ¼¼Êõ£¬ÇëʹÓà [`include` ºÍ `exclude` ÊôÐÔ](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.exposing)À´´úÌæ¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.exposing)2.2\. ±©Â¶¶Ëµã
+
+
+
+ĬÈÏÇé¿öÏ£¬Ö»ÓÐhealth¶ËµãÊÇͨ¹ýHTTPºÍJMX±©Â¶µÄ¡£ ÓÉÓڶ˵ã¿ÉÄܰüº¬Ãô¸ÐÐÅÏ¢£¬ÄãÓ¦¸Ã×Ðϸ¿¼ÂǺÎʱ±©Â¶ËüÃÇ¡£
+
+
+
+
+
+Òª¸Ä±äÄÄЩ¶Ëµã±»±©Â¶£¬ÇëʹÓÃÒÔÏÂÌØ¶¨¼¼ÊõµÄ `include` ºÍ `exclude` ÊôÐÔ¡£
+
+
+
+
+| ÊôÐÔ | ĬÈÏ |
+| --- | --- |
+| `management.endpoints.jmx.exposure.exclude` | |
+| `management.endpoints.jmx.exposure.include` | `health` |
+| `management.endpoints.web.exposure.exclude` | |
+| `management.endpoints.web.exposure.include` | `health` |
+
+
+
+`include` ÊôÐÔÁгöÁ˱»±©Â¶µÄ¶ËµãµÄID¡£ `exclude` ÊôÐÔÁгöÁ˲»Ó¦¸Ã±»¹«¿ªµÄ¶ËµãµÄID¡£ `exclude` ÊôÐÔÓÅÏÈÓÚ `include` ÊôÐÔ¡£ Äã¿ÉÒÔÓÃÒ»¸ö¶ËµãIDÁбíÀ´ÅäÖà `include` ºÍ `exclude` ÊôÐÔ¡£
+
+
+
+
+
+ÀýÈ磬Ҫͨ¹ýJMXÖ»¹«¿ª `health` ºÍ `info` ¶Ëµã£¬ÇëʹÓÃÒÔÏÂÊôÐÔ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoints.jmx.exposure.include=health,info
+
+```
+
+
+
+
+
+
+
+`*` ¿ÉÒÔÓÃÀ´Ñ¡ÔñËùÓж˵㡣 ÀýÈ磬Ҫͨ¹ýHTTP¹«¿ªËùÓеĶ«Î÷£¬³ýÁË `env` ºÍ `beans` ¶Ëµã£¬Ê¹ÓÃÒÔÏÂÊôÐÔ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoints.web.exposure.include=*
+management.endpoints.web.exposure.exclude=env,beans
+
+```
+
+
+
+
+
+
+
+| | `*` ÔÚYAMLÖоßÓÐÌØÊ⺬Ò壬ËùÒÔÈç¹ûÄãÏë°üÀ¨£¨»òÅųý£©ËùÓеĶ˵㣬һ¶¨Òª¼ÓÒýºÅ¡£ |
+| --- | --- |
+
+
+
+
+
+| | Èç¹ûÄãµÄÓ¦ÓóÌÐòÊǹ«¿ª±©Â¶µÄ£¬ÎÒÃÇÇ¿ÁÒ½¨ÒéÄãÒ²[±£»¤ÄãµÄ¶Ëµã](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.security)¡£ |
+| --- | --- |
+
+
+
+
+
+| | Èç¹ûÄãÏëÔڶ˵㱩¶ʱʵʩ×Ô¼ºµÄ²ßÂÔ£¬Äã¿ÉÒÔ×¢²áÒ»¸ö `EndpointFilter` bean¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.security)2.3\. °²È«£¨Security£©
+
+
+
+ΪÁ˰²È«Æð¼û£¬Ä¬ÈÏÇé¿öÏÂÖ»ÓÐ `/health` ¶Ëµãͨ¹ýHTTP¹«¿ª¡£ Äã¿ÉÒÔʹÓà `management.endpoints.web.exposure.include` ÊôÐÔÀ´ÅäÖñ»±©Â¶µÄ¶Ëµã¡£
+
+
+
+
+
+| | ÔÚÉèÖà `management.endpoints.web.exposure.include` ֮ǰ£¬ÇëÈ·±£±©Â¶µÄÖ´ÐÐÆ÷²»°üº¬Ãô¸ÐÐÅÏ¢£¬½«ÆäÖÃÓÚ·À»ðǽ֮ºó£¬»òÓÉSpring SecurityÖ®ÀàµÄ¶«Î÷À´±£Ö¤°²È«¡£ |
+| --- | --- |
+
+
+
+
+
+Èç¹ûSpring SecurityÔÚclasspathÉÏ£¬²¢ÇÒûÓÐÆäËû `SecurityFilterChain` bean£¬ÄÇô³ýÁË `/health` Ö®ÍâµÄËùÓÐÖ´ÐÐÆ÷£¨actuator£©¶¼ÓÉSpring Boot×Ô¶¯ÅäÖÃÀ´±£Ö¤°²È«¡£ Èç¹ûÄ㶨ÒåÁËÒ»¸ö×Ô¶¨ÒåµÄ `SecurityFilterChain` bean£¬Spring Boot×Ô¶¯ÅäÖþͻáÍËËõ£¬ÈÃÄãÍêÈ«¿ØÖÆÖ´ÐÐÆ÷µÄ·ÃÎʹæÔò¡£
+
+
+
+
+
+Èç¹ûÄãÏëΪHTTP¶ËµãÅäÖÃ×Ô¶¨Ò尲ȫ£¨ÀýÈ磬ֻÔÊÐí¾ßÓÐijÖÖ½ÇÉ«µÄÓû§·ÃÎÊ£©£¬Spring BootÌṩÁËһЩ·½±ãµÄ `RequestMatcher` ¶ÔÏó£¬Äã¿ÉÒÔÓëSpring Security½áºÏʹÓá£
+
+
+
+
+
+Ò»¸öµäÐ͵ÄSpring SecurityÅäÖÿÉÄÜ¿´ÆðÀ´ÏñÏÂÃæµÄÀý×Ó¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Configuration(proxyBeanMethods = false)
+public class MySecurityConfiguration {
+
+ @Bean
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+ http.securityMatcher(EndpointRequest.toAnyEndpoint());
+ http.authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("ENDPOINT_ADMIN"));
+ http.httpBasic(withDefaults());
+ return http.build();
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+Ç°ÃæµÄÀý×ÓʹÓà `EndpointRequest.toAnyEndpoint()` À´Æ¥ÅäÒ»¸öÇëÇóµ½Èκζ˵㣬ȻºóÈ·±£ËùÓеĶ˵㶼ÓÐ `ENDPOINT_ADMIN` µÄ½ÇÉ«¡£ `EndpointRequest` ÉÏ»¹ÓÐÆäËû¼¸¸öÆ¥ÅäÆ÷·½·¨¡£ ÏêÇé¼ûAPIÎĵµ£¨ [HTML](https://docs.spring.io/spring-boot/docs/3.1.0-SNAPSHOT/actuator-api/htmlsingle) »ò [PDF](https://docs.spring.io/spring-boot/docs/3.1.0-SNAPSHOT/actuator-api/pdf/spring-boot-actuator-web-api.pdf)£©¡£
+
+
+
+
+
+Èç¹ûÄãÔÚ·À»ðǽºóÃæ²¿ÊðÓ¦ÓóÌÐò£¬Äã¿ÉÄÜÏ£ÍûÄãµÄËùÓÐÖ´ÐÐÆ÷¶Ëµã¶¼Äܱ»·ÃÎÊ£¬¶ø²»ÐèÒªÈÏÖ¤¡£ Äã¿ÉÒÔͨ¹ý¸Ä±ä `management.endpoints.web.exposure.include` ÊôÐÔÀ´×öµ½ÕâÒ»µã£¬ÈçÏÂËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoints.web.exposure.include=*
+
+```
+
+
+
+
+
+
+
+´ËÍ⣬Èç¹û´æÔÚSpring Security£¬ÄãÐèÒªÌí¼Ó×Ô¶¨Ò尲ȫÅäÖã¬ÔÊÐíδ¾ÈÏÖ¤µÄ·ÃÎʶ˵㣬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Configuration(proxyBeanMethods = false)
+public class MySecurityConfiguration {
+
+ @Bean
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+ http.securityMatcher(EndpointRequest.toAnyEndpoint());
+ http.authorizeHttpRequests((requests) -> requests.anyRequest().permitAll());
+ return http.build();
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+| | ÔÚÇ°ÃæµÄÁ½¸öÀý×ÓÖУ¬ÅäÖÃÖ»ÊÊÓÃÓÚactuator¶Ëµã¡£ ÓÉÓÚSpring BootµÄ°²È«ÅäÖÃÔÚÓÐÈκΠ`SecurityFilterChain` beanµÄÇé¿ö϶¼»áÍêÈ«Í˳ö£¬ËùÒÔÄãÐèÒªÅäÖÃÒ»¸ö¶îÍâµÄ `SecurityFilterChain` bean£¬Æä¹æÔòÊÊÓÃÓÚÓ¦ÓóÌÐòµÄÆäËû²¿·Ö¡£ |
+| --- | --- |
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.security.csrf)2.3.1\. ¿çÍøÕ¾ÇëÇóαÔì±£»¤£¨CSRF£©
+
+
+
+ÓÉÓÚSpring BootÒÀÀµSpring SecurityµÄĬÈÏÖµ£¬CSRF±£»¤ÔÚĬÈÏÇé¿öϱ»´ò¿ª¡£ ÕâÒâζ×ÅÔÚʹÓÃĬÈϰ²È«ÅäÖÃʱ£¬ÐèÒª `POST`£¨shutdownºÍloggers¶Ëµã£©¡¢`PUT` »ò `DELETE` µÄactuator¶Ëµã»á³öÏÖ403£¨½ûÖ¹£©µÄ´íÎó¡£
+
+
+
+
+
+| | ÎÒÃǽ¨ÒéÖ»ÓÐÔÚÄã´´½¨µÄ·þÎñ±»·Çä¯ÀÀÆ÷¿Í»§¶ËʹÓÃʱ²ÅÍêÈ«½ûÓÃCSRF±£»¤¡£ |
+| --- | --- |
+
+
+
+
+
+Äã¿ÉÒÔÔÚ [Spring°²È«²Î¿¼Ö¸ÄÏ](https://docs.spring.io/spring-security/reference/6.1.0-M1/features/exploits/csrf.html) ÖÐÕÒµ½¹ØÓÚCSRF±£»¤µÄÆäËûÐÅÏ¢¡£
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.caching)2.4\. ÅäÖö˵ã
+
+
+
+¶Ëµã»á×Ô¶¯»º´æ²»ÐèÒªÈκβÎÊýµÄ¶ÁÈ¡²Ù×÷µÄÏìÓ¦¡£ ÒªÅäÖö˵㻺´æÏìÓ¦µÄʱ¼ä£¬ÇëʹÓÃÆä `cache.time-to-live` ÊôÐÔ¡£ ÏÂÃæµÄÀý×Ó½« `beans` ¶ËµãµÄ»º´æÉú´æÊ±¼äÉèÖÃΪ10Ãë¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoint.beans.cache.time-to-live=10s
+
+```
+
+
+
+
+
+
+
+| | `management.endpoint.` ǰ׺ΨһµØ±êʶÁËÕýÔÚÅäÖõĶ˵㡣 |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.hypermedia)2.5\. ÓÃÓÚ Actuator Web ¶ËµãµÄ³¬Ã½Ì壨Hypermedia£©
+
+
+
+Ò»¸ö ¡°discovery page¡± ±»Ìí¼Óµ½ËùÓж˵ãµÄÁ´½ÓÖС£ ĬÈÏÇé¿öÏ£¬¡°discovery page¡± ÔÚ `/actuator` ÉÏÊÇ¿ÉÓõġ£
+
+
+
+
+
+Òª½ûÓà ¡°discovery page¡±£¬ÇëÔÚÄãµÄÓ¦ÓóÌÐòÊôÐÔÖÐÌí¼ÓÒÔÏÂÊôÐÔ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoints.web.discovery.enabled=false
+
+```
+
+
+
+
+
+
+
+µ±ÅäÖÃÁËÒ»¸ö×Ô¶¨ÒåµÄ¹ÜÀíÉÏÏÂÎÄ·¾¶Ê±£¬¡°discovery page¡± »á×Ô¶¯´Ó `/actuator` ÒÆµ½¹ÜÀíÉÏÏÂÎĵĸù²¿¡£ ÀýÈ磬Èç¹û¹ÜÀíÉÏÏÂÎÄ·¾¶ÊÇ `/management`£¬discovery page¿ÉÒÔ´Ó `/management` »ñµÃ¡£ µ±¹ÜÀíÉÏÏÂÎÄ·¾¶±»ÉèÖÃΪ `/` ʱ£¬·¢ÏÖÒ³±»½ûÓã¬ÒÔ·ÀÖ¹ÓëÆäËûmapping·¢Éú³åÍ»µÄ¿ÉÄÜÐÔ¡£
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.cors)2.6\. CORSµÄÖ§³Ö
+
+
+
+[¿çÔ´×ÊÔ´¹²Ïí](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing)£¨CORS£©ÊÇ [W3CµÄÒ»¸ö¹æ·¶](https://www.w3.org/TR/cors/)£¬¿ÉÒÔÈÃÄãÒÔÁé»îµÄ·½Ê½Ö¸¶¨ÄÄÖÖ¿çÓòÇëÇó±»ÊÚȨ¡£Èç¹ûÄãʹÓÃSpring MVC»òSpring WebFlux£¬Äã¿ÉÒÔÅäÖÃActuatorµÄWeb¶ËµãÀ´Ö§³ÖÕâÖÖÇé¿ö¡£
+
+
+
+
+
+CORSÖ§³ÖÔÚĬÈÏÇé¿öÏÂÊǽûÓõģ¬Ö»ÓÐÔÚÄãÉèÖÃÁË `management.endpoints.web.cors.allowed-origins` ÊôÐÔºó²Å»áÆôÓᣠÏÂÃæµÄÅäÖÃÔÊÐí´Ó `example.com` ÓòÃûÖе÷Óà `GET` ºÍ `POST`¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoints.web.cors.allowed-origins=https://example.com
+management.endpoints.web.cors.allowed-methods=GET,POST
+
+```
+
+
+
+
+
+
+
+| | ²Î¼û [`CorsEndpointProperties`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/CorsEndpointProperties.java) ÒÔ»ñµÃÍêÕûµÄÑ¡ÏîÁÐ±í¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom)2.7\. ʵÏÖ×Ô¶¨Òå¶Ëµã
+
+
+
+Èç¹ûÄãÌí¼ÓÁËÒ»¸ö´øÓÐ `@Endpoint` ×¢½âµÄ `@Bean`£¬ÈκδøÓÐ `@ReadOperation`¡¢`@WriteOperation` »ò `@DeleteOperation` ×¢Ê͵ķ½·¨¶¼»á×Ô¶¯Í¨¹ýJMX¹«¿ª£¬ÔÚWebÓ¦ÓóÌÐòÖÐÒ²»áͨ¹ýHTTP¹«¿ª¡£ ͨ¹ýʹÓÃJersey¡¢Spring MVC»òSpring WebFlux£¬¶Ëµã¿ÉÒÔͨ¹ýHTTP±©Â¶¡£ Èç¹ûJerseyºÍSpring MVC¶¼¿ÉÓã¬ÔòʹÓÃSpring MVC¡£
+
+
+
+
+
+ÏÂÃæµÄÀý×Ó±©Â¶ÁËÒ»¸ö¶Á²Ù×÷£¬Ëü·µ»ØÒ»¸ö×Ô¶¨Òå¶ÔÏó¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ReadOperation
+public CustomData getData() {
+ return new CustomData("test", 5);
+}
+
+```
+
+
+
+
+
+
+
+ÄãÒ²¿ÉÒÔͨ¹ýʹÓà `@JmxEndpoint` »ò `@WebEndpoint` À´±àÐ´ÌØ¶¨¼¼ÊõµÄ¶Ëµã¡£ ÕâЩ¶Ëµã±»ÏÞÖÆÔÚËüÃǸ÷×Եļ¼ÊõÉÏ¡£ ÀýÈ磬`@WebEndpoint` ֻͨ¹ýHTTP±©Â¶£¬¶ø²»ÊÇͨ¹ýJMX¡£
+
+
+
+
+
+Äã¿ÉÒÔͨ¹ýʹÓà `@EndpointWebExtension` ºÍ `@EndpointJmxExtension` À´±àÐ´ÌØ¶¨µÄ¼¼ÊõÀ©Õ¹¡£ ÕâЩע½âÈÃÄãÌá¹©ÌØ¶¨¼¼ÊõµÄ²Ù×÷£¬ÒÔÔöÇ¿ÏÖÓеĶ˵㡣
+
+
+
+
+
+×îºó£¬Èç¹ûÄãÐèÒª·ÃÎÊWeb¿ò¼ÜµÄÌØ¶¨¹¦ÄÜ£¬Äã¿ÉÒÔʵÏÖservlet»òSpringµÄ `@Controller` ºÍ `@RestController` ¶Ëµã£¬´ú¼ÛÊÇËüÃDz»ÄÜͨ¹ýJMX»òʹÓò»Í¬µÄWeb¿ò¼Üʱ¿ÉÓá£
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.input)2.7.1\. ½ÓÊÕÊäÈë
+
+
+
+¶ËµãÉϵIJÙ×÷ͨ¹ýÆä²ÎÊý½ÓÊÕÊäÈë¡£ µ±Í¨¹ýweb¹«¿ªÊ±£¬ÕâЩ²ÎÊýµÄÖµÀ´×ÔURLµÄ²éѯ²ÎÊýºÍJSONÇëÇóÌå¡£ µ±Í¨¹ýJMX¹«¿ªÊ±£¬²ÎÊý±»Ó³Éäµ½MBean²Ù×÷µÄ²ÎÊýÖС£ ĬÈÏÇé¿öÏ£¬²ÎÊýÊDZØÐèµÄ¡£ ËüÃÇ¿ÉÒÔͨ¹ýʹÓà `@javax.annotation.Nullable` »ò `@org.springframework.lang.Nullable` ½øÐÐ×¢½â¶ø³ÉΪ¿ÉÑ¡Ïî¡£
+
+
+
+
+
+Äã¿ÉÒÔ½«JSONÇëÇóÌåÖеÄÿ¸ö¸ùÊôÐÔÓ³Éäµ½¶ËµãµÄÒ»¸ö²ÎÊý¡£ ¿¼ÂÇÒ»ÏÂÏÂÃæµÄJSONÇëÇóÌå¡£
+
+
+
+
+
+
+
+```
+{
+ "name": "test",
+ "counter": 42
+}
+```
+
+
+
+
+
+
+
+Äã¿ÉÒÔÓÃËüÀ´µ÷ÓÃÒ»¸öд²Ù×÷£¬¸Ã²Ù×÷ÐèÒª `String name` ºÍ `int counter` ²ÎÊý£¬ÈçÏÂÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@WriteOperation
+public void updateData(String name, int counter) {
+ // injects "test" and 42
+}
+
+```
+
+
+
+
+
+
+
+| | ÒòΪ¶ËµãÊǼ¼Êõ²»¿ÉÖªµÄ£¬ÔÚ·½·¨Ç©ÃûÖÐÖ»ÄÜÖ¸¶¨¼òµ¥µÄÀàÐÍ¡£ ÌØ±ðÊÇ£¬²»Ö§³ÖÓà `CustomData` ÀàÐÍÉùÃ÷Ò»¸ö¶¨ÒåÁË `name` ºÍ `counter` ÊôÐԵĵ¥Ò»²ÎÊý¡£ |
+| --- | --- |
+
+
+
+
+
+| | ΪÁËÈÃÊäÈëÓ³Éäµ½²Ù×÷·½·¨µÄ²ÎÊý£¬ÊµÏֶ˵ãµÄJava´úÂëÓ¦¸ÃÓà `-parameters` ±àÒ룬¶øÊµÏֶ˵ãµÄKotlin´úÂëÓ¦¸ÃÓà `-java-parameters` ±àÒë¡£ Èç¹ûÄãʹÓÃSpring BootµÄGradle²å¼þ»òʹÓÃMavenºÍ `spring-boot-starter-parent`£¬Õ⽫×Ô¶¯·¢Éú¡£ |
+| --- | --- |
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.input.conversion)ÊäÈëÀàÐÍת»»
+
+
+
+Èç¹ûÓбØÒª£¬´«µÝ¸ø¶Ëµã²Ù×÷·½·¨µÄ²ÎÊý»á×Ô¶¯×ª»»ÎªËùÐèÀàÐÍ¡£ ÔÚµ÷ÓòÙ×÷·½·¨Ö®Ç°£¬Í¨¹ýJMX»òHTTPÊÕµ½µÄÊäÈ뱻ת»»ÎªËùÐèµÄÀàÐÍ£¬·½·¨ÊÇʹÓà `ApplicationConversionService` µÄʵÀýÒÔ¼°ÈκΠ`Converter` »ò `GenericConverter` Bean£¬²¢ÒÔ `@EndpointConverter` ÏÞ¶¨¡£
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.web)2.7.2\. ×Ô¶¨ÒåWEB¶Ëµã
+
+
+
+¶Ô `@Endpoint`¡¢`@WebEndpoint` »ò `@EndpointWebExtension` ²Ù×÷»á×Ô¶¯Ê¹ÓÃJersey¡¢Spring MVC»òSpring WebFluxͨ¹ýHTTP¹«¿ª¡£ Èç¹ûJerseyºÍSpring MVC¶¼¿ÉÓã¬ÔòʹÓÃSpring MVC¡£
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.web.request-predicates)WEB¶ËµãÇëÇóν´Ê£¨Predicates£©
+
+
+
+Ò»¸öÇëÇóν´Ê»áΪweb±©Â¶µÄ¶ËµãÉϵÄÿ¸ö²Ù×÷£¨operation£©×Ô¶¯Éú³É¡£
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.web.path-predicates)Path
+
+
+
+pathν´ÊÓɶ˵ãµÄIDºÍÍøÂ籩¶µÄ¶ËµãµÄ»ù±¾Â·¾¶¾ö¶¨¡£ ĬÈϵĻù±¾Â·¾¶ÊÇ `/actuator`¡£ ÀýÈ磬һ¸öIDΪ `sessions` µÄ¶ËµãÔÚν´ÊÖÐʹÓà `/actuator/sessions` ×÷ΪÆä·¾¶¡£
+
+
+
+
+
+Äã¿ÉÒÔͨ¹ýÓà `@Selector` ×¢½â²Ù×÷·½·¨µÄÒ»¸ö»ò¶à¸ö²ÎÊýÀ´½øÒ»²½¶¨ÖÆÂ·¾¶¡£ ÕâÑùµÄ²ÎÊý»á×÷Ϊһ¸ö·¾¶±äÁ¿Ìí¼Óµ½Â·¾¶Î½´ÊÖС£ ÔÚµ÷Óö˵ã²Ù×÷ʱ£¬¸Ã±äÁ¿µÄÖµ»á±»´«Èë²Ù×÷·½·¨¡£ Èç¹ûÄãÏë²¶»ñËùÓÐÊ£ÓàµÄ·¾¶ÔªËØ£¬Äã¿ÉÒÔÔÚ×îºóÒ»¸ö²ÎÊýÉÏÌí¼Ó `@Selector(Match=ALL_REMAINING)`£¬²¢Ê¹Æä³ÉΪһ¸öÓë `String[]` ת»»¼æÈݵÄÀàÐÍ¡£
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.web.method-predicates)HTTP method£¨·½·¨£©
+
+
+
+HTTP methodν´ÊÊÇÓɲÙ×÷ÀàÐ;ö¶¨µÄ£¬ÈçϱíËùʾ¡£
+
+
+
+
+| Operation | HTTP method |
+| --- | --- |
+| `@ReadOperation` | `GET` |
+| `@WriteOperation` | `POST` |
+| `@DeleteOperation` | `DELETE` |
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.web.consumes-predicates)Consumes
+
+
+
+¶ÔÓÚʹÓÃrequest bodyµÄ `@WriteOperation`£¨HTTP `POST`£©£¬Î½´ÊµÄ `consumes` ×Ó¾äÊÇ `application/vnd.spring-boot.actuator.v2+json, application/json`¡£ ¶ÔÓÚËùÓÐÆäËû²Ù×÷£¬`consumes` ×Ó¾äÊǿյġ£
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.web.produces-predicates)Produces
+
+
+
+ν´ÊµÄ `produces` ×Ó¾ä¿ÉÒÔÓÉ `@DeleteOperation`¡¢`@ReadOperation` ºÍ `@WriteOperation` ×¢Ê굀 `produces` ÊôÐÔ¾ö¶¨¡£ ¸ÃÊôÐÔÊÇ¿ÉÑ¡µÄ¡£ Èç¹û²»Ê¹ÓÃËü£¬`produces` ×Ó¾ä»á×Ô¶¯È·¶¨¡£
+
+
+
+
+
+Èç¹û²Ù×÷·½·¨·µ»Ø `void` »ò `Void`£¬Ôò `produces` ×Ó¾äΪ¿Õ¡£ Èç¹û²Ù×÷·½·¨·µ»Ø `org.springframework.core.io.Resource`£¬`produces` ×Ó¾äÊÇ `application/octet-stream`¡£ ¶ÔÓÚËùÓÐÆäËû²Ù×÷£¬`produces` ×Ó¾äÊÇ `application/vnd.spring-boot.actuator.v2+json, application/json`¡£
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.web.response-status)WEB¶ËµãÏìӦ״̬
+
+
+
+¶Ëµã²Ù×÷µÄĬÈÏÏìӦ״̬ȡ¾öÓÚ²Ù×÷ÀàÐÍ£¨¶Á¡¢Ð´»òɾ³ý£©ºÍ²Ù×÷·µ»ØµÄÄÚÈÝ£¨Èç¹ûÓеϰ£©¡£
+
+
+
+
+
+Èç¹û `@ReadOperation` ·µ»ØÒ»¸öÖµ£¬ÏìӦ״̬½«ÊÇ200(Ok)¡£ Èç¹ûËüûÓзµ»ØÒ»¸öÖµ£¬ÏìӦ״̬½«ÊÇ404(Not Found)¡£
+
+
+
+
+
+Èç¹û `@WriteOperation` »ò `@DeleteOperation` ·µ»ØÒ»¸öÖµ£¬ÏìӦ״̬½«ÊÇ200£¨OK£©¡£ Èç¹ûËüûÓзµ»ØÒ»¸öÖµ£¬ÏìӦ״̬½«ÊÇ204£¨No Content£©¡£
+
+
+
+
+
+Èç¹ûÒ»¸ö²Ù×÷ÔÚµ÷ÓÃʱûÓÐËùÐèµÄ²ÎÊý£¬»òÕß²ÎÊý²»Äܱ»×ª»»ÎªËùÐèµÄÀàÐÍ£¬²Ù×÷·½·¨¾Í²»»á±»µ÷Óã¬ÏìӦ״̬½«ÊÇ400£¨Bad Request£©¡£
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.web.range-requests)WEB¶Ëµã Range ÇëÇó
+
+
+
+Äã¿ÉÒÔʹÓÃHTTP rangeÇëÇóÀ´ÇëÇóÒ»¸öHTTP×ÊÔ´µÄÒ»²¿·Ö¡£ µ±Ê¹ÓÃSpring MVC»òSpring Web Fluxʱ£¬·µ»Ø `org.springframework.core.io.Resource` µÄ²Ù×÷×Ô¶¯Ö§³Ö·¶Î§ÇëÇó¡£
+
+
+
+
+
+| | ʹÓÃJerseyʱ²»Ö§³Ö Range ÇëÇó¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.web.security)Web¶ËµãµÄ°²È«
+
+
+
+ÔÚweb¶Ëµã»òwebÌØ¶¨¶ËµãÀ©Õ¹ÉϵIJÙ×÷¿ÉÒÔ½ÓÊÕµ±Ç°µÄ `java.security.Principal` »ò `org.springframework.boot.actuate.endpoint.SecurityContext` ×÷Ϊ·½·¨²ÎÊý¡£ ǰÕßͨ³£Óë `@Nullable` Ò»ÆðʹÓã¬ÎªÒÑÈÏÖ¤ºÍδÈÏÖ¤µÄÓû§Ìṩ²»Í¬µÄÐÐΪ¡£ ºóÕßͨ³£ÓÃÓÚͨ¹ýʹÓÃÆä `isUserInRole(String)` ·½·¨À´Ö´ÐÐÊÚȨ¼ì²é¡£
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.servlet)2.7.3\. Servlet ¶Ëµã
+
+
+
+Ò»¸öServlet¿ÉÒÔ×÷Ϊһ¸ö¶Ëµã±©Â¶³öÀ´£¬·½·¨ÊÇʵÏÖÒ»¸öÓà `@ServletEndpoint` ×¢½âµÄÀ࣬ͬʱʵÏÖ `Supplier`¡£ Servlet¶ËµãÌṩÁËÓëservletÈÝÆ÷µÄ¸üÉî²ã´ÎµÄÕûºÏ£¬µ«È´ÎþÉüÁË¿ÉÒÆÖ²ÐÔ¡£ ËüÃǵÄÄ¿µÄÊÇÓÃÀ´½«ÏÖÓеÄServlet×÷Ϊһ¸ö¶ËµãÀ´¹«¿ª¡£ ¶ÔÓÚеĶ˵㣬Ӧ¾¡¿ÉÄÜÑ¡Ôñ `@Endpoint` ºÍ `@WebEndpoint` ×¢½â¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.controller)2.7.4\. Controller ¶Ëµã
+
+
+
+Äã¿ÉÒÔʹÓà `@ControllerEndpoint` ºÍ `@RestControllerEndpoint` À´ÊµÏÖÒ»¸ö½öÓÉSpring MVC»òSpring WebFlux¹«¿ªµÄ¶Ëµã¡£ ·½·¨Í¨¹ýʹÓÃSpring MVCºÍSpring WebFluxµÄ±ê×¼×¢½â½øÐÐÓ³É䣬Èç `@RequestMapping` ºÍ `@GetMapping`£¬¶ËµãµÄID±»ÓÃ×÷·¾¶µÄǰ׺¡£ ¿ØÖÆÆ÷¶ËµãÌṩÁËÓëSpringµÄWeb¿ò¼Ü¸üÉîÈëµÄ¼¯³É£¬µ«È´ÎþÉüÁË¿ÉÒÆÖ²ÐÔ¡£ Ó¦¾¡¿ÉÄÜÑ¡Ôñ `@Endpoint` ºÍ `@WebEndpoint` ×¢½â¡£
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.health)2.8\. ½¡¿µÐÅÏ¢
+
+
+
+Äã¿ÉÒÔʹÓý¡¿µÐÅÏ¢À´¼ì²éÄãÔËÐеÄÓ¦ÓóÌÐòµÄ״̬¡£ Ëü¾³£±»¼à¿ØÈí¼þÓÃÀ´ÔÚÉú²úϵͳ·¢Éú¹ÊÕÏʱÌáÐѱðÈË¡£ `health` ¶Ëµã±©Â¶µÄÐÅϢȡ¾öÓÚ `management.endpoint.health.show-details` ºÍ `management.endpoint.health.show-components` ÊôÐÔ£¬ËüÃÇ¿ÉÒÔÅäÖÃΪÒÔÏÂÖµÖ®Ò»¡£
+
+
+
+
+| Öµ | ˵Ã÷ |
+| --- | --- |
+| `never` | ϸ½Ú´Ó²»ÏÔʾ¡£ |
+| `when-authorized` | ϸ½ÚÖ»ÏÔʾ¸øÊÚȨÓû§¡£ ÊÚȨµÄ½ÇÉ«¿ÉÒÔͨ¹ýʹÓà `management.endpoint.health.roles` ½øÐÐÅäÖᣠ|
+| `always` | ÏêÇéÏÔʾ¸øËùÓÐÓû§¡£ |
+
+
+
+ĬÈÏÖµÊÇ `never`¡£ µ±Óû§´¦Óڶ˵ãµÄÒ»¸ö»ò¶à¸ö½ÇÉ«ÖÐʱ£¬ËûÃDZ»ÈÏΪÊDZ»ÊÚȨµÄ¡£ Èç¹û¶ËµãûÓÐÅäÖýÇÉ«£¨Ä¬ÈÏÖµ£©£¬ËùÓÐÈÏÖ¤µÄÓû§¶¼±»ÈÏΪÊÇÊÚȨµÄ¡£ Äã¿ÉÒÔͨ¹ýʹÓà `management.endpoint.health.roles` ÊôÐÔÀ´ÅäÖýÇÉ«¡£
+
+
+
+
+
+| | Èç¹ûÄãÒѾ±£»¤ÁËÄãµÄÓ¦ÓóÌÐò²¢Ï£ÍûʹÓà `always`£¬ÄãµÄ°²È«ÅäÖã¨security configuration£©±ØÐëÔÊÐíÈÏÖ¤ºÍ·ÇÈÏÖ¤Óû§·ÃÎÊhealth¶Ëµã¡£ |
+| --- | --- |
+
+
+
+
+
+½¡¿µÐÅÏ¢ÊÇ´Ó [`HealthContributorRegistry`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthContributorRegistry.java) µÄÄÚÈÝÖÐÊÕ¼¯µÄ£¨Ä¬ÈÏÇé¿öÏ£¬ËùÓÐ [`HealthContributor`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthContributor.java) ʵÀý¶¼¶¨ÒåÔÚÄãµÄ `ApplicationContext` ÖУ©¡£ Spring Boot°üÀ¨Ò»Ð©×Ô¶¯ÅäÖÃµÄ `HealthContributor`£¬ÄãÒ²¿ÉÒÔ±àд×Ô¼ºµÄ¡£
+
+
+
+
+
+Ò»¸ö `HealthContributor` ¿ÉÒÔÊÇÒ»¸ö `HealthIndicator` »òÒ»¸ö `CompositeHealthContributor`¡£ Ò»¸ö `HealthIndicator` Ìṩʵ¼ÊµÄ½¡¿µÐÅÏ¢£¬°üÀ¨ `Status`¡£ Ò»¸ö `CompositeHealthContributor` ÌṩÆäËû `HealthContributors` µÄ×éºÏ¡£ ×ÛºÏÆðÀ´£¬contributorÐγÉÒ»¸öÊ÷×´½á¹¹À´±íʾÕû¸öϵͳµÄ½¡¿µ×´¿ö¡£
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬×îÖÕµÄϵͳ½¡¿µ×´¿öÊÇÓÉÒ»¸ö `StatusAggregator` µÃ³öµÄ£¬Ëü¸ù¾ÝÒ»¸öÓÐÐòµÄ״̬Áбí¶Ôÿ¸ö `HealthIndicator` µÄ״̬½øÐÐÅÅÐò¡£ ÅÅÐòÁбíÖеĵÚÒ»¸ö״̬±»ÓÃ×÷ÕûÌ彡¿µ×´Ì¬¡£ Èç¹ûûÓÐ `HealthIndicator` ·µ»ØµÄ״̬ÊÇ `StatusAggregator` ËùÖªµÀµÄ£¬¾Í»áʹÓà `UNKNOWN` ״̬¡£
+
+
+
+
+
+| | Äã¿ÉÒÔʹÓà `HealthContributorRegistry` À´ÔÚÔËÐÐʱע²áºÍÈ¡Ïû×¢²á½¡¿µÖ¸±ê¡£ |
+| --- | --- |
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.health.auto-configured-health-indicators)2.8.1\. ×Ô¶¯ÅäÖõÄHealthIndicators
+
+
+
+ÔÚÊʵ±µÄʱºò£¬Spring Boot»á×Ô¶¯ÅäÖÃϱíÖÐÁгöµÄ `HealthIndicators`¡£ ÄãÒ²¿ÉÒÔͨ¹ýÅäÖà `management.health.key.enabled` À´ÆôÓûòÍ£ÓÃËùѡָ±ê¡£ ºÍϱíÖÐÁгöµÄ `key`¡£
+
+
+
+
+| Key | Name | ˵Ã÷ |
+| --- | --- | --- |
+| `cassandra` | [`CassandraDriverHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverHealthIndicator.java) | ¼ì²éCassandraÊý¾Ý¿âÊÇ·ñÒѾÆô¶¯¡£ |
+| `couchbase` | [`CouchbaseHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/couchbase/CouchbaseHealthIndicator.java) | ¼ì²éCouchbase¼¯ÈºÊÇ·ñÒѾÆô¶¯¡£ |
+| `db` | [`DataSourceHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/jdbc/DataSourceHealthIndicator.java) | ¼ì²éÊÇ·ñ¿ÉÒÔ»ñµÃÓë`DataSource`µÄÁ¬½Ó¡£ |
+| `diskspace` | [`DiskSpaceHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/system/DiskSpaceHealthIndicator.java) | ¼ì²é´ÅÅ̿ռäÊÇ·ñ²»×ã¡£ |
+| `elasticsearch` | [`ElasticsearchRestHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/elasticsearch/ElasticsearchRestHealthIndicator.java) | ¼ì²éElasticsearch¼¯ÈºÊÇ·ñÒѾÆô¶¯¡£ |
+| `hazelcast` | [`HazelcastHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/hazelcast/HazelcastHealthIndicator.java) | ¼ì²éHazelcast·þÎñÆ÷ÊÇ·ñÒѾÆô¶¯¡£ |
+| `influxdb` | [`InfluxDbHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/influx/InfluxDbHealthIndicator.java) | ¼ì²éInfluxDB·þÎñÆ÷ÊÇ·ñÒѾÆô¶¯¡£ |
+| `jms` | [`JmsHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/jms/JmsHealthIndicator.java) | ¼ì²éÒ»¸öJMS´úÀíÊÇ·ñÒѾÆô¶¯¡£ |
+| `ldap` | [`LdapHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/ldap/LdapHealthIndicator.java) | ¼ì²éÒ»¸öLDAP·þÎñÆ÷ÊÇ·ñÕý³£¡£ |
+| `mail` | [`MailHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/mail/MailHealthIndicator.java) | ¼ì²éÒ»¸öÓʼþ·þÎñÆ÷ÊÇ·ñÕý³£¡£ |
+| `mongo` | [`MongoHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/mongo/MongoHealthIndicator.java) | ¼ì²éMongoÊý¾Ý¿âÊÇ·ñÒѾÆô¶¯¡£ |
+| `neo4j` | [`Neo4jHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jHealthIndicator.java) | ¼ì²éNeo4jÊý¾Ý¿âÊÇ·ñÒѾÆô¶¯¡£ |
+| `ping` | [`PingHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/PingHealthIndicator.java) | ×ÜÊÇÏìÓ¦ `UP` ¡£ |
+| `rabbit` | [`RabbitHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/amqp/RabbitHealthIndicator.java) | ¼ì²éÒ»¸öRabbit·þÎñÆ÷ÊÇ·ñÒѾÆô¶¯¡£ |
+| `redis` | [`RedisHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/redis/RedisHealthIndicator.java) | ¼ì²éRedis·þÎñÆ÷ÊÇ·ñÒѾÆô¶¯¡£ |
+
+
+
+| | Äã¿ÉÒÔͨ¹ýÉèÖà `management.health.defaults.enabled` ÊôÐÔÀ´½ûÓÃËüÃÇ¡£ |
+| --- | --- |
+
+
+
+
+
+¶îÍâµÄ `HealthIndicators` ÊÇ¿ÉÓõ쬵«ÔÚĬÈÏÇé¿öϲ»ÆôÓá£
+
+
+
+
+| Key | Name | ˵Ã÷ |
+| --- | --- | --- |
+| `livenessstate` | [`LivenessStateHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/availability/LivenessStateHealthIndicator.java) | ÏÔʾ ¡°Liveness¡± Ó¦ÓóÌÐòµÄ¿ÉÓÃÐÔ״̬¡£ |
+| `readinessstate` | [`ReadinessStateHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/availability/ReadinessStateHealthIndicator.java) | ±©Â¶ ¡°Readiness¡± Ó¦ÓóÌÐòµÄ¿ÉÓÃÐÔ״̬¡£ |
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.health.writing-custom-health-indicators)2.8.2\. ±àд×Ô¶¨ÒåHealthIndicators
+
+
+
+ΪÁËÌṩ×Ô¶¨ÒåµÄ½¡¿µÐÅÏ¢£¬Äã¿ÉÒÔ×¢²áʵÏÖ [`HealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicator.java) ½Ó¿ÚµÄSpring Bean¡£ ÄãÐèÒªÌṩһ¸ö `health()` ·½·¨µÄʵÏÖ£¬²¢·µ»ØÒ»¸ö `Health` ÏìÓ¦¡£ `Health` ÏìÓ¦Ó¦¸Ã°üÀ¨Ò»¸östatus£¬²¢¿ÉÒÔÑ¡Ôñ°üÀ¨ÒªÏÔʾµÄÆäËûϸ½Ú¡£ ÏÂÃæµÄ´úÂëÏÔʾÁËÒ»¸ö `HealthIndicator` µÄʵÏÖÑù±¾¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Component
+public class MyHealthIndicator implements HealthIndicator {
+
+ @Override
+ public Health health() {
+ int errorCode = check();
+ if (errorCode != 0) {
+ return Health.down().withDetail("Error Code", errorCode).build();
+ }
+ return Health.up().build();
+ }
+
+ private int check() {
+ // perform some specific health check
+ return ...
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+| | Ò»¸ö¸ø¶¨µÄ `HealthIndicator` µÄ±êʶ·û£¨ID£©ÊÇûÓÐ `HealthIndicator` ºó׺µÄBeanµÄÃû×Ö£¬Èç¹ûËü´æÔڵϰ¡£ ÔÚÇ°ÃæµÄÀý×ÓÖУ¬½¡¿µÐÅÏ¢¿ÉÒÔÔÚÒ»¸öÃûΪ `my` µÄÌõÄ¿ÖÐÕÒµ½¡£ |
+| --- | --- |
+
+
+
+
+
+| | ½¡¿µÖ¸±êͨ³£ÊÇͨ¹ýHTTPµ÷Óõģ¬ÐèÒªÔÚÈκÎÁ¬½Ó³¬Ê±Ö®Ç°×ö³öÏìÓ¦¡£ Èç¹ûÈκν¡¿µÖ¸±êµÄÏìӦʱ¼ä³¬¹ý10Ã룬Spring Boot½«¼Ç¼һÌõ¾¯¸æÐÅÏ¢¡£ Èç¹ûÄãÏëÅäÖÃÕâ¸öãÐÖµ£¬Äã¿ÉÒÔʹÓà `management.endpoint.health.logging.slow-indicator-threshold` ÊôÐÔ¡£ |
+| --- | --- |
+
+
+
+
+
+³ýÁËSpring BootÔ¤¶¨ÒåµÄ [`Status`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/Status.java) ÀàÐÍÍ⣬`Health` ¿ÉÒÔ·µ»Ø´ú±íÐÂϵͳ״̬µÄ×Ô¶¨Òå `Status`¡£ ÔÚÕâÖÖÇé¿öÏ£¬Ä㻹ÐèÒªÌṩ `StatusAggregator` ½Ó¿ÚµÄ×Ô¶¨ÒåʵÏÖ£¬»òÕßÄã±ØÐëͨ¹ýʹÓà `management.endpoint.health.status.order` ÅäÖÃÊôÐÔÀ´ÅäÖÃĬÈÏʵÏÖ¡£
+
+
+
+
+
+ÀýÈ磬¼ÙÉèÔÚÄãµÄÒ»¸ö `HealthIndicator` ʵÏÖÖÐʹÓÃÁËÒ»¸ö´úÂëΪ `FATAL` µÄР`Status`¡£ ΪÁËÅäÖÃÑÏÖØÐÔ˳Ðò£¬ÔÚÄãµÄÓ¦ÓóÌÐòÊôÐÔÖÐÌí¼ÓÒÔÏÂÊôÐÔ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoint.health.status.order=fatal,down,out-of-service,unknown,up
+
+```
+
+
+
+
+
+
+
+ÏìÓ¦ÖеÄHTTP״̬´úÂë·´Ó³ÁËÕûÌ彡¿µ×´Ì¬¡£ ĬÈÏÇé¿öÏ£¬`OUT_OF_SERVICE` ºÍ `DOWN` Ó³Éäµ½503¡£ ÈκÎδӳÉäµÄ½¡¿µ×´Ì¬£¬°üÀ¨ `UP`£¬¶¼Ó³ÉäΪ200¡£ Èç¹ûÄãͨ¹ýHTTP·ÃÎʽ¡¿µ¶Ëµã£¬Äã¿ÉÄÜ»¹Ïë×¢²á×Ô¶¨Òå״̬ӳÉä¡£ ÅäÖÃ×Ô¶¨ÒåÓ³Éä»á½ûÓà `DOWN` ºÍ `OUT_OF_SERVICE` µÄĬÈÏÓ³Éä¡£ Èç¹ûÄãÏë±£ÁôĬÈÏÓ³É䣬Äã±ØÐëÃ÷È·µØÅäÖÃËüÃÇ£¬ÒÔ¼°ÈκÎ×Ô¶¨ÒåÓ³Éä¡£ ÀýÈ磬ÏÂÃæµÄÊôÐÔ½« `FATAL` Ó³ÉäΪ503£¨·þÎñ²»¿ÉÓã©£¬²¢±£ÁôÁË `DOWN` ºÍ `OUT_OF_SERVICE` µÄĬÈÏÓ³Éä¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoint.health.status.http-mapping.down=503
+management.endpoint.health.status.http-mapping.fatal=503
+management.endpoint.health.status.http-mapping.out-of-service=503
+
+```
+
+
+
+
+
+
+
+| | Èç¹ûÄãÐèÒª¸ü¶àµÄ¿ØÖÆ£¬Äã¿ÉÒÔ¶¨ÒåÄã×Ô¼ºµÄ `HttpCodeStatusMapper` bean¡£ |
+| --- | --- |
+
+
+
+
+
+ϱíÏÔʾÁËÄÚÖÃ״̬µÄĬÈÏ״̬ӳÉä¡£
+
+
+
+
+| Status | Mapping |
+| --- | --- |
+| `DOWN` | `SERVICE_UNAVAILABLE` (`503`) |
+| `OUT_OF_SERVICE` | `SERVICE_UNAVAILABLE` (`503`) |
+| `UP` | ĬÈÏÇé¿öÏÂûÓÐÓ³É䣬ËùÒÔHTTP״̬Ϊ `200`¡£ |
+| `UNKNOWN` | ĬÈÏÇé¿öÏÂûÓÐÓ³É䣬ËùÒÔHTTP״̬Ϊ `200`¡£ |
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.health.reactive-health-indicators)2.8.3\. ÏìӦʽ½¡¿µÖ¸±ê
+
+
+
+¶ÔÓÚÏìӦʽӦÓóÌÐò£¬ÀýÈçÄÇЩʹÓÃSpring WebFluxµÄÓ¦ÓóÌÐò£¬`ReactiveHealthContributor` ÌṩÁËÒ»¸ö·Ç×èÈûµÄÆõÔ¼À´»ñȡӦÓóÌÐòµÄ½¡¿µ×´¿ö¡£ Ó봫ͳµÄ `HealthContributor` ÀàËÆ£¬½¡¿µÐÅÏ¢´Ó [`ReactiveHealthContributorRegistry`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthContributorRegistry.java) µÄÄÚÈÝÖÐÊÕ¼¯£¨Ä¬ÈÏÇé¿öÏ£¬ËùÓÐ [`HealthContributor`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthContributor.java) ºÍ [`ReactiveHealthContributor`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthContributor.java) µÄʵÀý¶¨ÒåÔÚÄãµÄ `ApplicationContext` À¡£
+
+
+
+
+
+²»¶ÔÏìӦʽAPI½øÐмì²éµÄ³£¹æ `HealthContributors` ÔÚµ¯ÐÔµ÷¶ÈÆ÷ÉÏÖ´ÐС£
+
+
+
+
+
+| | ÔÚÒ»¸öÏìӦʽӦÓóÌÐòÖУ¬ÄãÓ¦¸ÃʹÓà `ReactiveHealthContributorRegistry` À´ÔÚÔËÐÐʱע²áºÍÈ¡Ïû×¢²á½¡¿µÖ¸±ê¡£ Èç¹ûÄãÐèҪע²áÒ»¸öÆÕͨµÄ `HealthContributor`£¬ÄãÓ¦¸ÃÓà `ReactiveHealthContributor#adapt` À´°ü×°Ëü¡£ |
+| --- | --- |
+
+
+
+
+
+ΪÁË´ÓÏìӦʽAPIÖÐÌṩ×Ô¶¨ÒåµÄ½¡¿µÐÅÏ¢£¬Äã¿ÉÒÔ×¢²áʵÏÖ [`ReactiveHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/ReactiveHealthIndicator.java) ½Ó¿ÚµÄSpring Bean¡£ ÏÂÃæµÄ´úÂëÏÔʾÁËÒ»¸ö `ReactiveHealthIndicator` µÄʾÀýʵÏÖ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Component
+public class MyReactiveHealthIndicator implements ReactiveHealthIndicator {
+
+ @Override
+ public Mono health() {
+ return doHealthCheck().onErrorResume((exception) ->
+ Mono.just(new Health.Builder().down(exception).build()));
+ }
+
+ private Mono doHealthCheck() {
+ // perform some specific health check
+ return ...
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+| | ΪÁË×Ô¶¯´¦Àí´íÎ󣬿ÉÒÔ¿¼ÂÇ´Ó `AbstractReactiveHealthIndicator` ÖÐÀ©Õ¹¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.health.auto-configured-reactive-health-indicators)2.8.4\. ×Ô¶¯ÅäÖÃµÄ ReactiveHealthIndicators
+
+
+
+ÔÚÊʵ±µÄʱºò£¬Spring Boot»á×Ô¶¯ÅäÖÃÒÔÏ嵀 `ReactiveHealthIndicators`¡£
+
+
+
+
+| Key | Name | ˵Ã÷ |
+| --- | --- | --- |
+| `cassandra` | [`CassandraDriverReactiveHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/cassandra/CassandraDriverReactiveHealthIndicator.java) | ¼ì²éCassandraÊý¾Ý¿âÊÇ·ñÒѾÆô¶¯¡£ |
+| `couchbase` | [`CouchbaseReactiveHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/couchbase/CouchbaseReactiveHealthIndicator.java) | ¼ì²éCouchbase¼¯ÈºÊÇ·ñÒѾÆô¶¯¡£ |
+| `elasticsearch` | [`ElasticsearchReactiveHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/elasticsearch/ElasticsearchReactiveHealthIndicator.java) | ¼ì²éElasticsearch¼¯ÈºÊÇ·ñÒѾÆô¶¯¡£ |
+| `mongo` | [`MongoReactiveHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/mongo/MongoReactiveHealthIndicator.java) | ¼ì²éMongoÊý¾Ý¿âÊÇ·ñÒѾÆô¶¯¡£ |
+| `neo4j` | [`Neo4jReactiveHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/neo4j/Neo4jReactiveHealthIndicator.java) | ¼ì²éNeo4jÊý¾Ý¿âÊÇ·ñÒѾÆô¶¯¡£ |
+| `redis` | [`RedisReactiveHealthIndicator`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/data/redis/RedisReactiveHealthIndicator.java) | ¼ì²éRedis·þÎñÆ÷ÊÇ·ñÒѾÆô¶¯¡£ |
+
+
+
+| | Èç¹ûÓбØÒª£¬ÏìӦʽָ±ê»áÈ¡´ú³£¹æÖ¸±ê¡£ ÁíÍ⣬ÈκÎûÓб»Ã÷È·´¦ÀíµÄ `HealthIndicator` ¶¼»á±»×Ô¶¯°ü×°ÆðÀ´¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.health.groups)2.8.5\. Health·Ö×飨Health Groups£©
+
+
+
+ÓÐʱ£¬½«½¡¿µÖ¸±ê×éÖ¯³É¿ÉÒÔÓÃÓÚ²»Í¬Ä¿µÄµÄ×éÊǺÜÓÐÓõġ£
+
+
+
+
+
+Òª´´½¨Ò»¸ö½¡¿µÖ¸±ê×飬Äã¿ÉÒÔʹÓà `management.endpoint.health.group.` ÊôÐÔ£¬²¢Ö¸¶¨Ò»¸ö½¡¿µÖ¸±êIDÁбíÀ´ `include` »ò `exclude`¡£ ÀýÈ磬Ҫ´´½¨Ò»¸öÖ»°üÀ¨Êý¾Ý¿âÖ¸±êµÄ×飬Äã¿ÉÒÔ¶¨ÒåÈçÏ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoint.health.group.custom.include=db
+
+```
+
+
+
+
+
+
+
+È»ºóÄã¿ÉÒÔͨ¹ýµã»÷ `[localhost:8080/actuator/health/custom](http://localhost:8080/actuator/health/custom)` À´¼ì²é½á¹û¡£
+
+
+
+
+
+ͬÑù£¬Òª´´½¨Ò»¸ö×飬½«Êý¾Ý¿âÖ¸±êÅųýÔÚ¸Ã×éÖ®Í⣬²¢°üÀ¨ËùÓÐÆäËûÖ¸±ê£¬Äã¿ÉÒÔ¶¨ÒåÈçÏ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoint.health.group.custom.exclude=db
+
+```
+
+
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬×é¼Ì³ÐÁËÓëϵͳ½¡¿µÏàͬµÄ `StatusAggregator` ºÍ `HttpCodeStatusMapper` ÉèÖᣠȻ¶ø£¬ÄãÒ²¿ÉÒÔÔÚÿ¸ö×éµÄ»ù´¡É϶¨ÒåÕâЩ¡£ Èç¹ûÐèÒª£¬ÄãÒ²¿ÉÒÔ¸²¸Ç `show-details` ºÍ `roles` ÊôÐÔ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoint.health.group.custom.show-details=when-authorized
+management.endpoint.health.group.custom.roles=admin
+management.endpoint.health.group.custom.status.order=fatal,up
+management.endpoint.health.group.custom.status.http-mapping.fatal=500
+management.endpoint.health.group.custom.status.http-mapping.out-of-service=500
+
+```
+
+
+
+
+
+
+
+| | Èç¹ûÄãÐèҪע²á×Ô¶¨ÒåµÄ `StatusAggregator` »ò `HttpCodeStatusMapper` BeanÒÔÓÃÓÚ×飬Äã¿ÉÒÔʹÓà `@Qualifier("groupname")`¡£ |
+| --- | --- |
+
+
+
+
+
+Ò»¸ö½¡¿µ×éÒ²¿ÉÒÔ°üÀ¨/ÅųýÒ»¸ö `CompositeHealthContributor`¡£ ÄúÒ²¿ÉÒÔÖ»°üÀ¨/ÅųýÒ»¸ö `CompositeHealthContributor` µÄij¸ö×é¼þ¡£ Õâ¿ÉÒÔʹÓÃ×é¼þµÄÍêÈ«Ãû³ÆÀ´Íê³É£¬ÈçÏÂËùʾ¡£
+
+
+
+
+
+
+
+```
+management.endpoint.health.group.custom.include="test/primary"
+management.endpoint.health.group.custom.exclude="test/primary/b"
+```
+
+
+
+
+
+
+
+ÔÚÉÏÃæµÄÀý×ÓÖУ¬`custom` ×齫°üÀ¨Ãû³ÆÎª `primary` µÄ `HealthContributor`£¬ËüÊǸ´ºÏ `test` µÄÒ»¸ö×é³É²¿·Ö¡£ ÔÚÕâÀ`primary` ±¾Éí¾ÍÊÇÒ»¸ö¸´ºÏÌ壬Ãû×ÖΪ `b` µÄ `HealthContributor` ½«±»ÅųýÔÚ `custom` ×éÖ®Íâ¡£
+
+
+
+
+
+½¡¿µ×é¿ÉÒÔÔÚÖ÷¶Ë¿Ú»ò¹ÜÀí¶Ë¿ÚµÄ¶îÍâ·¾¶ÉÏÌṩ¡£ ÕâÔÚKubernetesµÈÔÆ»·¾³ÖкÜÓÐÓã¬ÔÚÕâЩ»·¾³ÖУ¬³öÓÚ°²È«¿¼ÂÇ£¬ÎªÖ´ÐÐÆ÷¶ËµãʹÓÃÒ»¸öµ¥¶ÀµÄ¹ÜÀí¶Ë¿ÚÊǺܳ£¼ûµÄ¡£ ÓÐÒ»¸öµ¥¶ÀµÄ¶Ë¿Ú¿ÉÄܵ¼Ö²»¿É¿¿µÄ½¡¿µ¼ì²é£¬ÒòΪ¼´Ê¹½¡¿µ¼ì²é³É¹¦£¬Ö÷Ó¦ÓóÌÐòÒ²¿ÉÄÜÎÞ·¨Õý³£¹¤×÷¡£ ½¡¿µ×é¿ÉÒÔÓÃÒ»¸ö¶îÍâµÄ·¾¶½øÐÐÅäÖã¬ÈçÏÂËùʾ¡£
+
+
+
+
+
+
+
+```
+management.endpoint.health.group.live.additional-path="server:/healthz"
+```
+
+
+
+
+
+
+
+Õ⽫ʹ `live` ½¡¿µ×éÔÚÖ÷·þÎñÆ÷¶Ë¿Ú `/healthz` ÉÏ¿ÉÓᣠǰ׺ÊÇÇ¿ÖÆÐԵ쬱ØÐëÊÇ `server:`£¨´ú±íÖ÷·þÎñÆ÷¶Ë¿Ú£©»ò `management:`£¨´ú±í¹ÜÀí¶Ë¿Ú£¬Èç¹ûÒÑÅäÖã©¡£ ·¾¶±ØÐëÊÇÒ»¸öµ¥Ò»µÄ·¾¶¶Î¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.health.datasource)2.8.6\. Êý¾ÝÔ´½¡¿µ
+
+
+
+`DataSource` ½¡¿µÖ¸±êÏÔʾ±ê×¼Êý¾ÝÔ´ºÍ·ÓÉÊý¾ÝÔ´BeanµÄ½¡¿µ×´¿ö¡£ ·ÓÉÊý¾ÝÔ´µÄ½¡¿µ×´¿ö°üÀ¨Æäÿ¸öÄ¿±êÊý¾ÝÔ´µÄ½¡¿µ×´¿ö¡£ ÔÚ½¡¿µ¶ËµãµÄÏìÓ¦ÖУ¬Â·ÓÉÊý¾ÝÔ´µÄÿ¸öÄ¿±ê¶¼ÊÇͨ¹ýʹÓÃÆä·ÓɼüÀ´ÃüÃûµÄ¡£ Èç¹ûÄ㲻ϣÍûÔÚÖ¸±êµÄÊä³öÖаüÀ¨Â·ÓÉÊý¾ÝÔ´£¬Ç뽫 `management.health.db.ignore-routing-data-sources` ÉèÖÃΪ `true`¡£
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.kubernetes-probes)2.9\. Kubernetes ̽Õë
+
+
+
+²¿ÊðÔÚKubernetesÉϵÄÓ¦ÓóÌÐò¿ÉÒÔͨ¹ý [ÈÝÆ÷̽Õë](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes) ÌṩÓÐ¹ØÆäÄÚ²¿×´Ì¬µÄÐÅÏ¢¡£¸ù¾Ý [ÄãµÄKubernetesÅäÖÃ](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/)£¬kubelet»áµ÷ÓÃÕâЩ̽Õë²¢¶Ô½á¹û×ö³ö·´Ó¦¡£
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬Spring Boot»á¹ÜÀíÄãµÄ[Ó¦ÓÿÉÓÃÐÔ״̬](https://springdoc.cn/spring-boot/features.html#features.spring-application.application-availability)¡£ Èç¹û²¿ÊðÔÚKubernetes»·¾³ÖУ¬actuator´Ó `ApplicationAvailability` ½Ó¿ÚÖÐÊÕ¼¯ ¡°Liveness¡± ºÍ ¡°Readiness¡± ÐÅÏ¢£¬²¢ÔÚרÓÃ[½¡¿µÖ¸±ê](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.health.auto-configured-health-indicators)ÖÐʹÓÃÕâЩÐÅÏ¢¡£`LivenessStateHealthIndicator` ºÍ `ReadinessStateHealthIndicator`¡£ ÕâЩָ±êÏÔʾÔÚÈ«¾Ö½¡¿µ¶Ëµã£¨`"/actuator/health"`£©¡£ ËüÃÇÒ²¿ÉÒÔͨ¹ýʹÓÃ[½¡¿µ×é](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.health.groups)×÷Ϊµ¥¶ÀµÄHTTP̽Õ룺`"/actuator/health/liveness"` ºÍ `"/actuator/health/readiness"`¡£
+
+
+
+
+
+È»ºó£¬Äã¿ÉÒÔÓÃÒÔ϶˵ãÐÅÏ¢ÅäÖÃÄãµÄKubernetes»ù´¡ÉèÊ©¡£
+
+
+
+
+
+
+
+```
+livenessProbe:
+ httpGet:
+ path: "/actuator/health/liveness"
+ port:
+ failureThreshold: ...
+ periodSeconds: ...
+
+readinessProbe:
+ httpGet:
+ path: "/actuator/health/readiness"
+ port:
+ failureThreshold: ...
+ periodSeconds: ...
+```
+
+
+
+
+
+
+
+| | `` Ó¦¸Ã±»ÉèÖÃΪִÐÐÆ÷¶Ëµã¿ÉÓõĶ˿ڡ£ Ëü¿ÉÒÔÊÇÖ÷Web·þÎñÆ÷µÄ¶Ë¿Ú£¬Ò²¿ÉÒÔÊÇÒ»¸öµ¥¶ÀµÄ¹ÜÀí¶Ë¿Ú£¬Èç¹û `"management.server.port"` ÊôÐÔÒѾ±»ÉèÖᣠ|
+| --- | --- |
+
+
+
+
+
+Ö»Óе±Ó¦ÓóÌÐò[ÔÚKubernetes»·¾³ÖÐÔËÐÐʱ](https://springdoc.cn/spring-boot/deployment.html#deployment.cloud.kubernetes)£¬ÕâЩ½¡¿µ×é²Å»á×Ô¶¯ÆôÓᣠÄã¿ÉÒÔͨ¹ýʹÓà `management.endpoint.health.probes.enabled` ÅäÖÃÊôÐÔÔÚÈκλ·¾³ÖÐÆôÓÃËüÃÇ¡£
+
+
+
+
+
+| | Èç¹ûÒ»¸öÓ¦ÓóÌÐòµÄÆô¶¯Ê±¼ä³¬¹ýÁËÅäÖõÄÓÐЧÆÚ£¬Kubernetes »áÌáµ½ `"startupProbe"` ×÷Ϊһ¸ö¿ÉÄܵĽâ¾ö·½°¸¡£Ò»°ãÀ´Ëµ£¬ÕâÀï²»Ò»¶¨ÐèÒª `"startupProbe"`£¬ÒòΪ `"readinessProbe"` »áÔÚËùÓÐÆô¶¯ÈÎÎñÍê³É֮ǰʧЧ¡£ÕâÒâζ×ÅÄãµÄÓ¦ÓóÌÐòÔÚ×¼±¸ºÃ֮ǰ²»»áÊÕµ½Á÷Á¿¡£È»¶ø£¬Èç¹ûÄãµÄÓ¦ÓóÌÐòÐèÒªºÜ³¤Ê±¼ä²ÅÄÜÆô¶¯£¬¿ÉÒÔ¿¼ÂÇʹÓà `"startupProbe"` À´È·±£Kubernetes²»»áÔÚÄãµÄÓ¦ÓóÌÐòÆô¶¯¹ý³ÌÖÐɱËÀËü¡£Çë²ÎÔÄÃèÊö[̽ÕëÔÚÓ¦ÓóÌÐòÉúÃüÖÜÆÚÖеÄÐÐΪ](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.kubernetes-probes.lifecycle)µÄ²¿·Ö¡£ |
+| --- | --- |
+
+
+
+
+
+Èç¹ûÄãµÄActuator¶Ëµã±»²¿ÊðÔÚÒ»¸öµ¥¶ÀµÄ¹ÜÀíÉÏÏÂÎÄÖУ¬ÄÇôÕâЩ¶Ëµã¾Í²»»áÏñÖ÷³ÌÐòÄÇÑùʹÓÃÏàͬµÄÍøÂç»ù´¡ÉèÊ©£¨¶Ë¿Ú¡¢Á¬½Ó³Ø¡¢¿ò¼Ü×é¼þ£©¡£ ÔÚÕâÖÖÇé¿öÏ£¬¼´Ê¹Ö÷³ÌÐò²»ÄÜÕý³£¹¤×÷£¨ÀýÈ磬Ëü²»ÄܽÓÊÜеÄÁ¬½Ó£©£¬Ì½²â¼ì²éÒ²¿ÉÄܳɹ¦¡£ ÓÉÓÚÕâ¸öÔÒò£¬ÔÚÖ÷·þÎñÆ÷¶Ë¿ÚÉÏÉèÖà `liveness` ºÍ `readiness` ½¡¿µ×éÊǸöºÃÖ÷Òâ¡£ Õâ¿ÉÒÔͨ¹ýÉèÖÃÒÔÏÂÊôÐÔÀ´ÊµÏÖ¡£
+
+
+
+
+
+
+
+```
+management.endpoint.health.probes.add-additional-paths=true
+```
+
+
+
+
+
+
+
+Õ⽫ʹ `liveness` ÔÚ `/livez` ¿ÉÓã¬`readiness` ÔÚ `readyz` µÄÖ÷·þÎñÆ÷¶Ë¿Ú¿ÉÓá£
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.kubernetes-probes.external-state)2.9.1\. ÓÃKubernetes̽Õë¼ì²éÍⲿ״̬
+
+
+
+Ö´ÐÐÆ÷½« ¡°liveness¡± ºÍ ¡°readiness¡± ̽ÕëÅäÖÃΪ½¡¿µ×é¡£ÕâÒâζ×ÅËùÓеÄ[½¡¿µ×éµÄ¹¦ÄÜ](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.health.groups)¶ÔËüÃǶ¼ÊÇ¿ÉÓõġ£ÀýÈ磬Äã¿ÉÒÔÅäÖöîÍâµÄ½¡¿µÖ¸±ê¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoint.health.group.readiness.include=readinessState,customCheck
+
+```
+
+
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬Spring Boot²»»áÏòÕâЩ×éÌí¼ÓÆäËû½¡¿µÖ¸±ê¡£
+
+
+
+
+
+¡°liveness¡± ̽Õë²»Ó¦¸ÃÒÀÀµÓÚÍⲿϵͳµÄ½¡¿µ¼ì²é¡£Èç¹û[Ó¦ÓóÌÐòµÄÓÐЧÐÔ״̬](https://springdoc.cn/spring-boot/features.html#features.spring-application.application-availability.liveness)±»ÆÆ»µ£¬Kubernetes»á³¢ÊÔͨ¹ýÖØÐÂÆô¶¯Ó¦ÓóÌÐòʵÀýÀ´½â¾öÕâ¸öÎÊÌâ¡£ÕâÒâζ×Å£¬Èç¹ûÒ»¸öÍⲿϵͳ£¨ÈçÊý¾Ý¿â¡¢Web API»òÍⲿ»º´æ£©³öÏÖ¹ÊÕÏ£¬Kubernetes¿ÉÄÜ»áÖØÐÂÆô¶¯ËùÓÐÓ¦ÓóÌÐòʵÀý£¬²¢²úÉú¼¶Áª¹ÊÕÏ¡£
+
+
+
+
+
+ÖÁÓÚ ¡°readiness¡± ̽²â£¬¼ì²éÍⲿϵͳµÄÑ¡Ôñ±ØÐëÓÉÓ¦ÓóÌÐò¿ª·¢ÈËÔ±½÷É÷×÷³ö¡£³öÓÚÕâ¸öÔÒò£¬Spring BootÔÚ×¼±¸×´Ì¬Ì½²âÖв»°üÀ¨ÈκζîÍâµÄ½¡¿µ¼ì²é¡£Èç¹û[Ó¦ÓóÌÐòʵÀýµÄreadiness stateÊÇunready](https://springdoc.cn/spring-boot/features.html#features.spring-application.application-availability.readiness)£¬Kubernetes¾Í²»»á½«Á÷Á¿Â·Óɵ½¸ÃʵÀý¡£Ò»Ð©Íⲿϵͳ¿ÉÄܲ»±»Ó¦ÓÃʵÀýËù¹²Ïí£¬ÔÚÕâÖÖÇé¿öÏ£¬ËüÃÇ¿ÉÒÔ±»°üÀ¨ÔÚ×¼±¸×´Ì¬Ì½²âÖС£ÆäËûÍⲿϵͳ¿ÉÄܲ»ÊÇÓ¦ÓóÌÐòµÄ¹Ø¼ü£¨Ó¦ÓóÌÐò¿ÉÄÜÓжÏ·Æ÷ºÍ»ØÍË£©£¬ÔÚÕâÖÖÇé¿öÏ£¬ËüÃǾø¶Ô²»Ó¦¸Ã±»°üÀ¨ÔÚÄÚ¡£²»ÐÒµÄÊÇ£¬Ò»¸ö±»ËùÓÐÓ¦ÓÃʵÀý¹²ÏíµÄÍⲿϵͳºÜ³£¼û£¬Äã±ØÐë×ö³öÅжϡ£°ÑËü°üÀ¨ÔÚ×¼±¸¾ÍÐ÷̽ÕëÖУ¬²¢ÆÚÍûµ±Íⲿ·þÎñ·¢Éú¹ÊÕÏʱ£¬Ó¦ÓóÌÐò»á±»Í£Ö¹·þÎñ£¬»òÕß²»°üÀ¨Ëü£¬²¢´¦Àí¶ÑÕ»Öиü¸ß²ã´ÎµÄ¹ÊÕÏ£¬Ò²Ðíͨ¹ýÔÚµ÷ÓÃÕßÖÐʹÓöÏ·Æ÷¡£
+
+
+
+
+
+| | Èç¹ûÒ»¸öÓ¦ÓóÌÐòµÄËùÓÐʵÀý¶¼Ã»ÓÐ×¼±¸ºÃ£¬`type=ClusterIP` »ò `NodePort` µÄKubernetes·þÎñ²»½ÓÊÜÈκδ«ÈëÁ¬½Ó¡£Ã»ÓÐHTTP´íÎóÏìÓ¦£¨503µÈ£©£¬ÒòΪûÓÐÁ¬½Ó¡£`type=LoadBalancer` µÄ·þÎñ¿ÉÄܽÓÊÜÒ²¿ÉÄܲ»½ÓÊÜÁ¬½Ó£¬ÕâÈ¡¾öÓÚÌṩÕß¡£Ò»¸öÓÐÃ÷È· [ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) µÄ·þÎñÒ²»áÒÔÒ»ÖÖÈ¡¾öÓÚʵÏֵķ½Ê½½øÐÐÏìÓ¦¡ª?Èë¿Ú·þÎñ±¾Éí±ØÐë¾ö¶¨ÈçºÎ´¦ÀíÀ´×ÔÏÂÓ뵀 ¡°connection refused¡±¡£ÔÚ¸ºÔؾùºâÆ÷ºÍÈë¿ÚµÄÇé¿öÏ£¬HTTP 503ÊǺÜÓпÉÄܵġ£ |
+| --- | --- |
+
+
+
+
+
+ÁíÍ⣬Èç¹ûÒ»¸öÓ¦ÓóÌÐòʹÓà Kubernetes [autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)£¬Ëü¿ÉÄÜ»á¶ÔÓ¦ÓóÌÐò±»´Ó¸ºÔØÆ½ºâÆ÷ÖÐÈ¡³ö×ö³ö²»Í¬µÄ·´Ó¦£¬ÕâÈ¡¾öÓÚÆäautoscalerµÄÅäÖá£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.kubernetes-probes.lifecycle)2.9.2\. Ó¦ÓóÌÐòÉúÃüÖÜÆÚºÍ̽Õë״̬
+
+
+
+Kubernetes ProbesÖ§³ÖµÄÒ»¸öÖØÒª·½ÃæÊÇËüÓëÓ¦ÓóÌÐòÉúÃüÖÜÆÚµÄÒ»ÖÂÐÔ¡£ `AvailabilityState`£¨¼´Ó¦ÓóÌÐòµÄÄÚ´æÄÚ²¿×´Ì¬£©ºÍʵ¼ÊµÄ̽Õ루±©Â¶¸Ã״̬£©Ö®¼ä´æÔÚ×ÅÏÔÖøµÄÇø±ð¡£ ºÍʵ¼ÊµÄ̽Õ루±©Â¶Á˸Ã״̬£©Ö®¼äÓкܴóµÄÇø±ð¡£ ¸ù¾ÝÓ¦ÓóÌÐòÉúÃüÖÜÆÚµÄ²»Í¬½×¶Î£¬Ì½Õë¿ÉÄÜÎÞ·¨Ê¹Óá£
+
+
+
+
+
+Spring BootÔÚ[Æô¶¯ºÍ¹Ø±ÕÆÚ¼ä·¢²¼application event](https://springdoc.cn/spring-boot/features.html#features.spring-application.application-events-and-listeners)£¬Ì½Õë¿ÉÒÔ¼àÌýÕâЩʼþ²¢±©Â¶³ö `AvailabilityState` ÐÅÏ¢¡£
+
+
+
+
+
+ϱíÏÔʾÁ˲»Í¬½×¶ÎµÄ `AvailabilityState` ºÍHTTP connectorµÄ״̬¡£
+
+
+
+
+
+µ±Ò»¸öSpring BootÓ¦ÓóÌÐòÆô¶¯Ê±¡£
+
+
+
+
+| Æô¶¯½×¶Î | LivenessState | ReadinessState | HTTP server | ±¸×¢ |
+| --- | --- | --- | --- | --- |
+| Starting | `BROKEN` | `REFUSING_TRAFFIC` | δÆô¶¯ | Kubernetes¼ì²é "liveness" ̽Õ룬Èç¹ûʱ¼ä¹ý³¤£¬¾ÍÖØÐÂÆô¶¯Ó¦ÓóÌÐò¡£ |
+| Started | `CORRECT` | `REFUSING_TRAFFIC` | ¾Ü¾øÇëÇó | Ó¦ÓóÌÐòÉÏÏÂÎı»Ë¢Ð¡£Ó¦ÓóÌÐòÖ´ÐÐÆô¶¯ÈÎÎñ£¬»¹Ã»ÓÐÊÕµ½Á÷Á¿¡£ |
+| Ready | `CORRECT` | `ACCEPTING_TRAFFIC` | ½ÓÊÜÇëÇó | Æô¶¯ÈÎÎñÒѾÍê³É¡£¸ÃÓ¦ÓóÌÐòÕýÔÚ½ÓÊÕÁ÷Á¿¡£ |
+
+
+
+µ±Ò»¸öSpring BootÓ¦ÓóÌÐò¹Ø±Õʱ¡£
+
+
+
+
+| Í£»ú½×¶Î | Liveness State | Readiness State | HTTP server | ±¸×¢ |
+| --- | --- | --- | --- | --- |
+| Running | `CORRECT` | `ACCEPTING_TRAFFIC` | ½ÓÊÜÇëÇó | ÒÑÒªÇ󹨱ա£ |
+| Graceful shutdown | `CORRECT` | `REFUSING_TRAFFIC` | еÄÇëÇ󱻾ܾø | Èç¹ûÆôÓ㬠[ÓÅÑŹػú»á´¦Àí¡°´¦ÀíÖС±µÄÇëÇó](https://springdoc.cn/spring-boot/web.html#web.graceful-shutdown)¡£ |
+| Shutdown complete | N/A | N/A | ·þÎñÆ÷±»¹Ø±Õ | Ó¦ÓóÌÐòÉÏÏÂÎı»¹Ø±Õ£¬Ó¦ÓóÌÐò±»¹Ø±Õ¡£ |
+
+
+
+| | ¹ØÓÚKubernetes²¿ÊðµÄ¸ü¶àÐÅÏ¢£¬Çë²Î¼û[KubernetesÈÝÆ÷ÉúÃüÖÜÆÚ](https://springdoc.cn/spring-boot/deployment.html#deployment.cloud.kubernetes.container-lifecycle)²¿·Ö¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.info)2.10\. Ó¦ÓÃÐÅÏ¢
+
+
+
+Ó¦ÓóÌÐòÐÅÏ¢¹«¿ªÁË´ÓÄãµÄ `ApplicationContext` Öж¨ÒåµÄËùÓÐ [`InfoContributor`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoContributor.java) BeanÊÕ¼¯µÄ¸÷ÖÖÐÅÏ¢¡£ Spring Boot°üÀ¨Ò»Ð©×Ô¶¯ÅäÖÃµÄ `InfoContributor` Bean£¬ÄãÒ²¿ÉÒÔ±àд×Ô¼ºµÄ¡£
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.info.auto-configured-info-contributors)2.10.1\. ×Ô¶¯ÅäÖÃµÄ InfoContributor
+
+
+
+ÔÚÊʵ±µÄʱºò£¬Spring»á×Ô¶¯ÅäÖÃÒÔÏ `InfoContributor` Bean¡£
+
+
+
+
+| ID | Name | ˵Ã÷ | ǰÌáÌõ¼þ |
+| --- | --- | --- | --- |
+| `build` | [`BuildInfoContributor`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/BuildInfoContributor.java) | ±©Â¶Á˹¹½¨ÐÅÏ¢¡£ | Ò»¸ö `META-INF/build-info.properties` ×ÊÔ´¡£ |
+| `env` | [`EnvironmentInfoContributor`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/EnvironmentInfoContributor.java) | ±©Â¶ `Environment` ÖÐÃû³ÆÒÔ `info.` ¿ªÍ·µÄÈκÎÊôÐÔ¡£ | None. |
+| `git` | [`GitInfoContributor`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/GitInfoContributor.java) | ±©Â¶ÁËgitÐÅÏ¢¡£ | Ò»¸ö `git.properties` ×ÊÔ´¡£ |
+| `java` | [`JavaInfoContributor`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/JavaInfoContributor.java) | ±©Â¶JavaÔËÐÐʱ£¨Runtime£©ÐÅÏ¢¡£ | None. |
+| `os` | [`OsInfoContributor`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/OsInfoContributor.java) | ±©Â¶²Ù×÷ϵͳÐÅÏ¢¡£ | None. |
+
+
+
+¸öÈ˹±Ï×Õߣ¨contributor£©ÊÇ·ñ±»ÆôÓÃÊÇÓÉÆä `management.info..enabled` ÊôÐÔ¿ØÖÆ¡£ ²»Í¬µÄcontributor¶ÔÕâ¸öÊôÐÔÓв»Í¬µÄĬÈÏÖµ£¬ÕâÈ¡¾öÓÚËûÃǵÄÏȾöÌõ¼þºÍËûÃÇËù±©Â¶µÄÐÅÏ¢µÄÐÔÖÊ¡£
+
+
+
+
+
+ÓÉÓÚûÓÐÏȾöÌõ¼þ±íÃ÷ËüÃÇÓ¦¸Ã±»ÆôÓã¬`env`¡¢`java` ºÍ `os` contributor ĬÈÏÊǽûÓõġ£ ¿ÉÒÔͨ¹ýÉèÖà `management.info..enabled` ÊôÐÔΪ `true` À´ÆôÓÃËüÃÇ¡£
+
+
+
+
+
+`build` ºÍ `git` ÐÅÏ¢contributorĬÈÏÊÇÆôÓõġ£ ¿ÉÒÔͨ¹ý½«Æä `management.info..enabled` ÊôÐÔÉèÖÃΪ `false` À´½ûÓᣠÁíÍ⣬Ҫ½ûÓÃÿһ¸öĬÈÏÆôÓõÄcontributor£¬Ç뽫 `management.info.defaults.enabled` ÊôÐÔÉèΪ `false`¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.info.custom-application-information)2.10.2\. ×Ô¶¨ÒåÓ¦ÓÃÐÅÏ¢£¨Application Information£©
+
+
+
+µ± `env` contributor ±»ÆôÓÃʱ£¬Äã¿ÉÒÔͨ¹ýÉèÖà `info.*` SpringÊôÐÔÀ´¶¨ÖÆ `info` ¶ËµãËù±©Â¶µÄÊý¾Ý¡£ `info` keyϵÄËùÓÐ `Environment` ÊôÐÔ¶¼»á×Ô¶¯±©Â¶¡£ ÀýÈ磬Äã¿ÉÒÔÔÚÄãµÄ `application.properties` ÎļþÖÐÌí¼ÓÒÔÏÂÉèÖá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+info.app.encoding=UTF-8
+info.app.java.source=17
+info.app.java.target=17
+
+```
+
+
+
+
+
+
+
+| | ÓëÆäÓ²±àÂëÕâЩֵ£¬Ä㻹¿ÉÒÔ [ÔÚ¹¹½¨Ê±À©Õ¹ÐÅÏ¢ÊôÐÔ](https://springdoc.cn/spring-boot/howto.html#howto.properties-and-configuration.expand-properties)¡£¼ÙÉèÄãʹÓÃMaven£¬Äã¿ÉÒÔ½«Ç°ÃæµÄÀý×Ó¸ÄдÈçÏ¡£PropertiesYaml```info.app.encoding=@project.build.sourceEncoding@info.app.java.source=@java.version@info.app.java.target=@java.version@``` |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.info.git-commit-information)2.10.3\. Git Commit ÐÅÏ¢
+
+
+
+`info` ¶ËµãµÄÁíÒ»¸öÓÐÓõŦÄÜÊÇËüÄܹ»·¢²¼¹ØÓÚÄãµÄ `git` Ô´´úÂë¿âÔÚÏîÄ¿½¨Á¢Ê±µÄ״̬µÄÐÅÏ¢¡£ Èç¹ûÓÐÒ»¸ö `GitProperties` bean£¬Äã¿ÉÒÔʹÓà `info` ¶ËµãÀ´¹«²¼ÕâЩÊôÐÔ¡£
+
+
+
+
+
+| | Èç¹ûclasspathµÄ¸ù²¿ÓÐ `git.properties` Îļþ£¬`GitProperties` Bean¾Í»á±»×Ô¶¯ÅäÖ᣸ü¶àϸ½Ú¼û "[ÈçºÎÉú³ÉgitÐÅÏ¢](https://springdoc.cn/spring-boot/howto.html#howto.build.generate-git-info)"¡£ |
+| --- | --- |
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬¶Ëµã»á±©Â¶ `git.branch`¡¢`git.commit.id` ºÍ `git.commit.time` ÊôÐÔ£¨Èç¹û´æÔÚ£©¡£ Èç¹ûÄã²»ÏëÈÃÕâЩÊôÐÔ³öÏÖÔڶ˵ãÏìÓ¦ÖУ¬ÐèÒª´Ó `git.properties` ÎļþÖÐÅųýËüÃÇ¡£ Èç¹ûÄãÏëÏÔʾÍêÕûµÄgitÐÅÏ¢£¨¼´ `git.properties` µÄÈ«²¿ÄÚÈÝ£©£¬Ê¹Óà `management.info.git.mode` ÊôÐÔ£¬ÈçÏÂËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.info.git.mode=full
+
+```
+
+
+
+
+
+
+
+Òª´Ó `info` ¶ËµãÍêÈ«½ûÓÃgitÌá½»ÐÅÏ¢£¬Çë `management.info.git.enabled` ÊôÐÔÉèΪ `false`£¬ÈçÏÂËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.info.git.enabled=false
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.info.build-information)2.10.4\. ¹¹½¨ÐÅÏ¢
+
+
+
+Èç¹û `BuildProperties` BeanÊÇ¿ÉÓõģ¬`info` ¶ËµãÒ²¿ÉÒÔ·¢²¼¹ØÓÚÄãµÄ¹¹½¨ÐÅÏ¢¡£Èç¹ûclasspathÖÐµÄ `META-INF/build-info.properties` Îļþ¿ÉÓ㬾ͻᷢÉúÕâÖÖÇé¿ö¡£
+
+
+
+
+
+| | MavenºÍGradle²å¼þ¶¼¿ÉÒÔÉú³É¸ÃÎļþ¡£Ïê¼û "[ÈçºÎÉú³É¹¹½¨ÐÅÏ¢](https://springdoc.cn/spring-boot/howto.html#howto.build.generate-info)"¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.info.java-information)2.10.5\. JavaÐÅÏ¢
+
+
+
+`info` ¶Ëµã·¢²¼Á˹ØÓÚÄãµÄJavaÔËÐл·¾³µÄÐÅÏ¢£¬¸ü¶àϸ½Ú¼û [`JavaInfo`](https://docs.spring.io/spring-boot/docs/3.1.0-SNAPSHOT/api/org/springframework/boot/info/JavaInfo.html)¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.info.os-information)2.10.6\. ²Ù×÷ϵͳ£¨OS£©ÐÅÏ¢
+
+
+
+`info` ¶Ëµã·¢²¼¹ØÓÚÄãµÄ²Ù×÷ϵͳµÄÐÅÏ¢£¬¸ü¶àϸ½Ú¼û [`OsInfo`](https://docs.spring.io/spring-boot/docs/3.1.0-SNAPSHOT/api/org/springframework/boot/info/OsInfo.html)`¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.info.writing-custom-info-contributors)2.10.7\. ±àд×Ô¶¨Òå InfoContributor
+
+
+
+ΪÁËÌṩ×Ô¶¨ÒåµÄÓ¦ÓóÌÐòÐÅÏ¢£¬Äã¿ÉÒÔ×¢²áʵÏÖ [`InfoContributor`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/InfoContributor.java) ½Ó¿ÚµÄSpring Bean¡£
+
+
+
+
+
+ÏÂÃæµÄÀý×Ó¹±Ï×ÁËÒ»¸öÖ»ÓÐÒ»¸öÖµµÄ `example` ÌõÄ¿¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Component
+public class MyInfoContributor implements InfoContributor {
+
+ @Override
+ public void contribute(Info.Builder builder) {
+ builder.withDetail("example", Collections.singletonMap("key", "value"));
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+Èç¹ûÄãÇëÇó `info` ¶Ëµã£¬ÄãÓ¦¸Ã¿´µ½Ò»¸ö°üº¬ÒÔ϶îÍâÌõÄ¿µÄÏìÓ¦¡£
+
+
+
+
+
+
+
+```
+{
+ "example": {
+ "key" : "value"
+ }
+}
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.monitoring)3\. ͨ¹ýHTTP½øÐÐ¼à¿ØºÍ¹ÜÀí
+
+
+
+
+
+Èç¹ûÄãÕýÔÚ¿ª·¢Ò»¸öWebÓ¦ÓóÌÐò£¬Spring Boot Actuator»á×Ô¶¯ÅäÖÃËùÓÐÆôÓõĶ˵㣬ʹÆäͨ¹ýHTTP¹«¿ª¡£ ĬÈϵĹßÀýÊÇʹÓö˵ãµÄ `id` ºÍ `/actuator` µÄǰ׺×÷ΪURL·¾¶¡£ ÀýÈ磬`health` ÒÔ `/actuator/health` µÄÐÎʽ¹«¿ª¡£
+
+
+
+
+
+| | Actuator Ö§³Ö Spring MVC¡¢Spring WebFluxºÍJersey¡£ Èç¹ûJerseyºÍSpring MVC¶¼¿ÉÓã¬Ôò»áʹÓÃSpring MVC¡£ |
+| --- | --- |
+
+
+
+
+
+| | ΪÁË»ñµÃAPIÎĵµ£¨ [HTML](https://docs.spring.io/spring-boot/docs/3.1.0-SNAPSHOT/actuator-api/htmlsingle) »ò [PDF](https://docs.spring.io/spring-boot/docs/3.1.0-SNAPSHOT/actuator-api/pdf/spring-boot-actuator-web-api.pdf) £©ÖмÇÔØµÄÕýÈ·µÄJSONÏìÓ¦£¬JacksonÊÇÒ»¸ö±ØÒªµÄÒÀÀµ¡£ |
+| --- | --- |
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.monitoring.customizing-management-server-context-path)3.1\. ¶¨ÖƹÜÀí¶Ëµã·¾¶
+
+
+
+ÓÐʱ£¬Îª¹ÜÀí¶Ëµã¶¨ÖÆÇ°×ºÊǺÜÓÐÓõġ£ ÀýÈ磬ÄãµÄÓ¦ÓóÌÐò¿ÉÄÜÒѾ½« `/actuator` ÓÃÓÚÆäËûÄ¿µÄ¡£ Äã¿ÉÒÔʹÓà `management.endpoints.web.base-path` ÊôÐÔÀ´¸Ä±ä¹ÜÀí¶ËµãµÄǰ׺£¬ÈçÏÂÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoints.web.base-path=/manage
+
+```
+
+
+
+
+
+
+
+Ç°ÃæµÄ `application.properties` Àý×Ó½«¶Ëµã´Ó `/actuator/{id}` ¸ÄΪ `/manage/{id}` £¨ÀýÈ磬`/manage/info`£©¡£
+
+
+
+
+
+| | ³ý·Ç¹ÜÀí¶Ë¿Ú±»ÅäÖÃΪ[ʹÓò»Í¬µÄHTTP¶Ë¿Ú](https://springdoc.cn/spring-boot/actuator.html#actuator.monitoring.customizing-management-server-port)À´±©Â¶¶Ëµã£¬·ñÔò `management.endpoints.web.base-path` ÊÇÏà¶ÔÓÚ `server.servlet.context-path` £¨ÓÃÓÚServlet WebÓ¦Óã©»ò `spring.webflux.base-path` £¨ÓÃÓÚreactive WebÓ¦Óã©¡£Èç¹ûÅäÖÃÁË `management.server.port`£¬ `management.endpoints.web.base-path` ÊÇÏà¶ÔÓÚ `management.server.base-path` µÄ¡£ |
+| --- | --- |
+
+
+
+
+
+Èç¹ûÄãÏë°Ñ¶ËµãÓ³Éäµ½²»Í¬µÄ·¾¶£¬Äã¿ÉÒÔʹÓà `management.endpoints.web.path-mapping` ÊôÐÔ¡£
+
+
+
+
+
+ÏÂÃæµÄÀý×Ó½« `/actuator/health` ÖØÐÂÓ³ÉäΪ `/healthcheck`¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoints.web.base-path=/
+management.endpoints.web.path-mapping.health=healthcheck
+
+```
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.monitoring.customizing-management-server-port)3.2\. ¶¨ÖƹÜÀí·þÎñÆ÷¶Ë¿Ú
+
+
+
+¶ÔÓÚ»ùÓÚÔÆµÄ²¿ÊðÀ´Ëµ£¬Í¨¹ýʹÓÃĬÈϵÄHTTP¶Ë¿ÚÀ´±©Â¶¹ÜÀí¶ËµãÊÇÒ»¸öÃ÷ÖǵÄÑ¡Ôñ¡£ È»¶ø£¬Èç¹ûÄãµÄÓ¦ÓóÌÐòÔÚÄã×Ô¼ºµÄÊý¾ÝÖÐÐÄÄÚÔËÐУ¬Äã¿ÉÄܸüϲ»¶Ê¹Óò»Í¬µÄHTTP¶Ë¿ÚÀ´±©Â¶¶Ëµã¡£
+
+
+
+
+
+Äã¿ÉÒÔÉèÖà `management.server.port` ÊôÐÔÀ´¸Ä±äHTTP¶Ë¿Ú£¬ÈçÏÂÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.server.port=8081
+
+```
+
+
+
+
+
+
+
+| | ÔÚ Cloud Foundry ÉÏ£¬Ä¬ÈÏÇé¿öÏ£¬Ó¦ÓóÌÐò½öÔÚ¶Ë¿Ú 8080 ÉϽÓÊÕ HTTP ºÍ TCP ·ÓɵÄÇëÇó¡£ Èç¹ûÄúÏëÔÚ Cloud Foundry ÉÏʹÓÃ×Ô¶¨Òå¹ÜÀí¶Ë¿Ú£¬ÄúÐèÒªÃ÷È·ÉèÖÃÓ¦ÓóÌÐòµÄ·ÓÉÒÔ½«Á÷Á¿×ª·¢µ½×Ô¶¨Òå¶Ë¿Ú¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.monitoring.management-specific-ssl)3.3\. ÅäÖÃÕë¶ÔManagement£¨¹ÜÀí£©²ãµÄSSL
+
+
+
+µ±ÅäÖÃΪʹÓÃ×Ô¶¨Òå¶Ë¿Úʱ£¬ÄãÒ²¿ÉÒÔͨ¹ýʹÓø÷ÖÖ `management.server.ssl.*` ÊôÐÔÀ´ÅäÖùÜÀí·þÎñÆ÷µÄSSL¡£ ÀýÈ磬ÕâÑù×ö¿ÉÒÔÈùÜÀí·þÎñÆ÷ͨ¹ýHTTPÌṩ·þÎñ£¬¶øÖ÷Ó¦ÓóÌÐòʹÓÃHTTPS£¬ÈçÒÔÏÂÊôÐÔÉèÖÃËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+server.port=8443
+server.ssl.enabled=true
+server.ssl.key-store=classpath:store.jks
+server.ssl.key-password=secret
+management.server.port=8080
+management.server.ssl.enabled=false
+
+```
+
+
+
+
+
+
+
+»òÕߣ¬Ö÷·þÎñÆ÷ºÍ¹ÜÀí·þÎñÆ÷¶¼¿ÉÒÔʹÓÃSSL£¬µ«Ê¹Óò»Í¬µÄÃÜÔ¿´æ´¢£¬ÈçÏÂËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+server.port=8443
+server.ssl.enabled=true
+server.ssl.key-store=classpath:main.jks
+server.ssl.key-password=secret
+management.server.port=8080
+management.server.ssl.enabled=true
+management.server.ssl.key-store=classpath:management.jks
+management.server.ssl.key-password=secret
+
+```
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.monitoring.customizing-management-server-address)3.4\. ¶¨ÖÆManagement£¨¹ÜÀí£©·þÎñÆ÷µØÖ·
+
+
+
+Äã¿ÉÒÔͨ¹ýÉèÖà `management.server.address` ÐÔÀ´¶¨ÖƹÜÀí¶ËµãµÄ¿ÉÓõØÖ·¡£ Èç¹ûÄãÏëÖ»ÔÚÄÚ²¿»òÃæÏòÔËάµÄÍøÂçÉϼàÌý£¬»òÕßÖ»¼àÌýÀ´×Ô `localhost` µÄÁ¬½Ó£¬ÕâÑù×ö»áºÜÓÐÓá£
+
+
+
+
+
+| | Ö»Óе±¶Ë¿ÚÓëÖ÷·þÎñÆ÷¶Ë¿Ú²»Í¬Ê±£¬Äã²ÅÄÜÔÚ²»Í¬µÄµØÖ·ÉϽøÐмàÌý¡£ |
+| --- | --- |
+
+
+
+
+
+ÏÂÃæµÄÀý×Ó `application.properties` ²»ÔÊÐíÔ¶³Ì¹ÜÀíÁ¬½Ó¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.server.port=8081
+management.server.address=127.0.0.1
+
+```
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.monitoring.disabling-http-endpoints)3.5\. ½ûÓÃHTTP¶Ëµã
+
+
+
+Èç¹ûÄã²»Ïëͨ¹ýHTTP±©Â¶¶Ëµã£¬Äã¿ÉÒ԰ѹÜÀí¶Ë¿ÚÉèÖÃΪ `-1`£¬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.server.port=-1
+
+```
+
+
+
+
+
+
+
+ÄãÒ²¿ÉÒÔͨ¹ýʹÓà `management.endpoints.web.exposure.exclude` ÊôÐÔÀ´ÊµÏÖ£¬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoints.web.exposure.exclude=*
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.jmx)4\. ͨ¹ýJMX½øÐÐ¼à¿ØºÍ¹ÜÀí
+
+
+
+
+
+Java¹ÜÀíÀ©Õ¹£¨JMX£©ÌṩÁËÒ»¸ö±ê×¼µÄ»úÖÆÀ´¼à¿ØºÍ¹ÜÀíÓ¦ÓóÌÐò¡£ ĬÈÏÇé¿öÏ£¬¸Ã¹¦ÄÜδ±»ÆôÓᣠÄã¿ÉÒÔͨ¹ýÉèÖà `spring.jmx.enabled` ÅäÖÃÊôÐÔΪ `true` À´´ò¿ªËü¡£ Spring Boot½«×îºÏÊ浀 `MBeanServer` ×÷ΪIDΪ `mbeanServer` µÄBean¹«¿ª¡£ ÄãµÄÈκδøÓÐSpring JMX×¢½âµÄBean£¨`@ManagedResource`¡¢`@ManagedAttribute` »ò `@ManagedOperation`£©¶¼»á±©Â¶¸øËü¡£
+
+
+
+
+
+Èç¹ûÄãµÄƽ̨ÌṩÁËÒ»¸ö±ê×¼µÄ `MBeanServer` £¬Spring Boot»áʹÓÃËü£¬²¢ÔÚ±ØÒªÊ±Ä¬ÈÏΪVM `MBeanServer`¡£ Èç¹ûËùÓÐÕâЩ¶¼Ê§°ÜÁË£¬¾Í»á´´½¨Ò»¸öÐ嵀 `MBeanServer`¡£
+
+
+
+
+
+¸ü¶àϸ½Ú¼û [`JmxAutoConfiguration`](https://github.com/spring-projects/spring-boot/tree/main/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jmx/JmxAutoConfiguration.java) Àà¡£
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬Spring BootÒ²½«¹ÜÀí¶Ëµã×÷ΪJMX MBeansÔÚ `org.springframework.boot` ÓòϹ«¿ª¡£ ÒªÍêÈ«¿ØÖÆJMXÓòÖеĶ˵ã×¢²á£¬¿ÉÒÔ¿¼ÂÇ×¢²áÄã×Ô¼ºµÄ `EndpointObjectNameFactory` ʵÏÖ¡£
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.jmx.custom-mbean-names)4.1\. ×Ô¶¨ÒåMBeanÃû³Æ
+
+
+
+MBeanµÄÃû×Öͨ³£Óɶ˵ãµÄ `id` Éú³É¡£ ÀýÈ磬 `health` ¶Ëµã±»±©Â¶Îª `org.springframework.boot:type=Endpoint,name=Health`¡£
+
+
+
+
+
+Èç¹ûÄãµÄÓ¦ÓóÌÐò°üº¬Ò»¸öÒÔÉϵÄSpring `ApplicationContext`£¬Äã¿ÉÄܻᷢÏÖÃû×Ö·¢Éú³åÍ»¡£ ΪÁ˽â¾öÕâ¸öÎÊÌ⣬Äã¿ÉÒÔ½« `spring.jmx.unique-names` ÊôÐÔÉèÖÃΪ `true`£¬ÕâÑùMBeanµÄÃû×Ö¾Í×ÜÊÇΨһµÄ¡£
+
+
+
+
+
+Ä㻹¿ÉÒÔ×Ô¶¨Ò屩¶¶ËµãµÄJMXÓò¡£ ÏÂÃæµÄÉèÖÃÏÔʾÁËÔÚ `application.properties` ÖÐÕâÑù×öµÄÒ»¸öÀý×Ó¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+spring.jmx.unique-names=true
+management.endpoints.jmx.domain=com.example.myapp
+
+```
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.jmx.disable-jmx-endpoints)4.2\. ½ûÓÃJMX¶Ëµã
+
+
+
+Èç¹ûÄã²»Ïëͨ¹ýJMX±©Â¶¶Ëµã£¬Äã¿ÉÒÔ°Ñ `management.endpoints.jmx.exposure.exclude` ÊôÐÔÉèÖÃΪ `*`£¬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.endpoints.jmx.exposure.exclude=*
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.observability)5\. ¿É¹Û²âÐÔ£¨Observability£©
+
+
+
+
+
+¿É¹Û²ìÐÔÊÇÖ¸´ÓÍⲿ¹Û²ìÒ»¸öÔËÐÐÖеÄϵͳµÄÄÚ²¿×´Ì¬µÄÄÜÁ¦¡£ËüÓÉÈý¸öÖ§Öù×é³É£ºÈÕÖ¾¡¢¶ÈÁ¿ºÍ¸ú×Ù¡£
+
+
+
+
+
+¶ÔÓÚ¶ÈÁ¿ºÍ¸ú×Ù£¬Spring BootʹÓà [Micrometer Observation](https://micrometer.io/docs/observation)¡£Òª´´½¨Äã×Ô¼ºµÄ¹Û²ì£¨Õ⽫µ¼Ö¶ÈÁ¿ºÍ¸ú×Ù£©£¬Äã¿ÉÒÔ×¢ÈëÒ»¸ö `ObservationRegistry`¡£
+
+
+
+
+
+
+
+```
+@Component
+public class MyCustomObservation {
+
+ private final ObservationRegistry observationRegistry;
+
+ public MyCustomObservation(ObservationRegistry observationRegistry) {
+ this.observationRegistry = observationRegistry;
+ }
+
+ public void doSomething() {
+ Observation.createNotStarted("doSomething", this.observationRegistry)
+ .lowCardinalityKeyValue("locale", "en-US")
+ .highCardinalityKeyValue("userId", "42")
+ .observe(() -> {
+ // Execute business logic here
+ });
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+| | µÍ¿¨¶ÈµÄ±êÇ©½«±»Ìí¼Óµ½Ö¸±êºÍ×·×ÙÖУ¬¶ø¸ß¿¨¶ÈµÄ±êÇ©½«Ö»±»Ìí¼Óµ½×·×ÙÖС£ |
+| --- | --- |
+
+
+
+
+
+`ObservationPredicate`¡¢`GlobalObservationConvention` ºÍ `ObservationHandler` ÀàÐ굀 Bean ½«±»×Ô¶¯×¢²áµ½ `ObservationRegistry` ÉÏ¡£Äã¿ÉÒÔÁíÍâ×¢²áÈÎÒâÊýÁ¿µÄ `ObservationRegistryCustomizer` BeanÀ´½øÒ»²½ÅäÖÃ×¢²á±í¡£
+
+
+
+
+
+¸ü¶àϸ½ÚÇë¼û [Micrometer Observation Îĵµ](https://micrometer.io/docs/observation)¡£
+
+
+
+
+
+| | JDBCºÍR2DBCµÄ¿É¹Û²ìÐÔ£¨Observability£©¿ÉÒÔʹÓõ¥¶ÀµÄÏîÄ¿½øÐÐÅäÖ᣶ÔÓÚ JDBC£¬ [Datasource Micrometer ÏîÄ¿](https://github.com/jdbc-observations/datasource-micrometer) ÌṩÁËÒ»¸ö Spring Boot Starter£¬ÔÚµ÷ÓÃJDBC²Ù×÷ʱ×Ô¶¯´´½¨¹Û²ì¡£ÔÚ [²Î¿¼Îĵµ](https://jdbc-observations.github.io/datasource-micrometer/docs/current/docs/html/)ÖÐÔĶÁ¸ü¶à¹ØÓÚËüµÄÐÅÏ¢¡£¶ÔÓÚR2DBC£¬ [R2DBC¹Û²ìµÄSpring Boot×Ô¶¯ÅäÖÃ](https://github.com/spring-projects-experimental/r2dbc-micrometer-spring-boot) ¿ÉÒÔΪR2DBC²éѯµ÷Óô´½¨¹Û²ì¡£ |
+| --- | --- |
+
+
+
+
+
+½ÓÏÂÀ´µÄÕ½ڽ«Ìṩ¹ØÓÚÈÕÖ¾¡¢Ö¸±êºÍ×·×ٵĸü¶àϸ½Ú¡£
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.loggers)6\. ÈÕÖ¾¼Ç¼Æ÷£¨Logger£©
+
+
+
+
+
+Spring Boot Actuator°üÀ¨ÔÚÔËÐÐʱ²é¿´ºÍÅäÖÃÓ¦ÓóÌÐòµÄÈÕÖ¾¼¶±ðµÄ¹¦ÄÜ¡£ Äã¿ÉÒԲ鿴Õû¸öÁбí»òµ¥¸öÈÕÖ¾¼Ç¼Æ÷µÄÅäÖã¬ËüÓÉÃ÷È·ÅäÖõÄÈÕÖ¾¼¶±ðÒÔ¼°ÈÕÖ¾¿ò¼Ü¸³ÓèËüµÄÓÐЧÈÕÖ¾¼¶±ð×é³É¡£ ÕâЩ¼¶±ð¿ÉÒÔÊÇÒÔÏÂÖ®Ò»¡£
+
+
+
+
+
+* `TRACE`
+
+* `DEBUG`
+
+* `INFO`
+
+* `WARN`
+
+* `ERROR`
+
+* `FATAL`
+
+* `OFF`
+
+* `null`
+
+
+
+
+
+`null` ±íʾûÓÐÃ÷È·µÄÅäÖá£
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.loggers.configure)6.1\. ÅäÖÃÒ»¸ö Logger
+
+
+
+ÒªÅäÖÃÒ»¸ö¸ø¶¨µÄ¼Ç¼Æ÷£¬`POST` Ò»¸ö²¿·ÖʵÌåµ½×ÊÔ´µÄURI£¬ÈçÏÂÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+
+
+```
+{
+ "configuredLevel": "DEBUG"
+}
+```
+
+
+
+
+
+
+
+| | Òª ¡°reset¡± £¨ÖØÖ㩼ǼÆ÷µÄÌØ¶¨¼¶±ð£¨²¢Ê¹ÓÃĬÈÏÅäÖã©£¬Äã¿ÉÒÔ´«µÝÒ»¸ö `null` µÄÖµ×÷Ϊ `configuredLevel`¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics)7\. Ö¸±ê£¨Metrics£©
+
+
+
+
+
+Spring Boot ActuatorΪ [Micrometer](https://micrometer.io/) ÌṩÁËÒÀÀµ¹ÜÀíºÍ×Ô¶¯ÅäÖã¬MicrometerÊÇÒ»¸öÖ§³Ö [ÖÚ¶à¼à¿ØÏµÍ³](https://micrometer.io/docs) µÄÓ¦ÓóÌÐòÖ¸±ê½Ó¿Ú£¬°üÀ¨¡£
+
+
+
+
+
+* [AppOptics](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.appoptics)
+
+* [Atlas](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.atlas)
+
+* [Datadog](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.datadog)
+
+* [Dynatrace](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.dynatrace)
+
+* [Elastic](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.elastic)
+
+* [Ganglia](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.ganglia)
+
+* [Graphite](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.graphite)
+
+* [Humio](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.humio)
+
+* [Influx](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.influx)
+
+* [JMX](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.jmx)
+
+* [KairosDB](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.kairos)
+
+* [New Relic](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.newrelic)
+
+* [OpenTelemetry](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.otlp)
+
+* [Prometheus](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.prometheus)
+
+* [SignalFx](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.signalfx)
+
+* [Simple (in-memory)](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.simple)
+
+* [Stackdriver](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.stackdriver)
+
+* [StatsD](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.statsd)
+
+* [Wavefront](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.wavefront)
+
+
+
+
+
+| | ÒªÁ˽â¸ü¶à¹ØÓÚMicrometerµÄ¹¦ÄÜ£¬Çë²Î¼ûÆä [²Î¿¼Îĵµ](https://micrometer.io/docs)£¬ÌرðÊÇ [¸ÅÄ·Ö](https://micrometer.io/docs/concepts)¡£ |
+| --- | --- |
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.getting-started)7.1\. ÈëÃÅ
+
+
+
+Spring Boot»á×Ô¶¯ÅäÖÃÒ»¸ö¸´ºÏµÄ `MeterRegistry`£¬²¢ÎªËüÔÚclasspathÉÏ·¢ÏÖµÄÿ¸öÖ§³ÖµÄʵÏÖÌí¼ÓÒ»¸ö×¢²á±í¡£ ÔÚÄãµÄÔËÐÐʱclasspathÖÐÓÐ¶Ô `micrometer-registry-{system}` µÄÒÀÀµ¾Í×ãÒÔÈÃSpring BootÅäÖÃ×¢²á±íÁË¡£
+
+
+
+
+
+´ó¶àÊý×¢²á±íÓй²Í¬µÄÌØµã¡£ ÀýÈ磬¼´Ê¹ Micrometer ×¢²á±íµÄʵÏÖÔÚclasspathÉÏ£¬ÄãÒ²¿ÉÒÔ½ûÓÃÒ»¸öÌØ¶¨µÄ×¢²á±í¡£ ÏÂÃæµÄÀý×Ó½ûÓÃÁËDatadog¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.datadog.metrics.export.enabled=false
+
+```
+
+
+
+
+
+
+
+ÄãÒ²¿ÉÒÔ½ûÓÃËùÓеÄ×¢²á±í£¬³ý·Ç×¢²á±íÌØ¶¨ÊôÐÔÁíÓÐ˵Ã÷£¬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.defaults.metrics.export.enabled=false
+
+```
+
+
+
+
+
+
+
+Spring Boot»¹½«ÈκÎ×Ô¶¯ÅäÖõÄ×¢²á±íÌí¼Óµ½ `Metrics` ÀàÉϵÄÈ«¾Ö¾²Ì¬¸´ºÏ×¢²á±í£¬³ý·ÇÄãÃ÷È·¸æËßËü²»ÒªÕâÑù×ö¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.metrics.use-global-registry=false
+
+```
+
+
+
+
+
+
+
+Äã¿ÉÒÔ×¢²áÈÎÒâÊýÁ¿µÄ `MeterRegistryCustomizer` BeanÀ´½øÒ»²½ÅäÖÃ×¢²á±í£¬±ÈÈçÔÚÈÎºÎ±í±»×¢²á֮ǰӦÓÃÆÕͨ±êÇ©¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Configuration(proxyBeanMethods = false)
+public class MyMeterRegistryConfiguration {
+
+ @Bean
+ public MeterRegistryCustomizer metricsCommonTags() {
+ return (registry) -> registry.config().commonTags("region", "us-east-1");
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+Äã¿ÉÒÔͨ¹ý¸ü¾ßÌåµÄ·ºÐͽ«¶¨ÖÆÓ¦ÓÃÓÚÌØ¶¨µÄ×¢²á±íʵÏÖ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Configuration(proxyBeanMethods = false)
+public class MyMeterRegistryConfiguration {
+
+ @Bean
+ public MeterRegistryCustomizer graphiteMetricsNamingConvention() {
+ return (registry) -> registry.config().namingConvention(this::name);
+ }
+
+ private String name(String name, Meter.Type type, String baseUnit) {
+ return ...
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+Spring Boot»¹ [ÅäÖÃÁËÄÚÖà instrumentation](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported)£¬Äã¿ÉÒÔͨ¹ýÅäÖûòרÓÃ×¢½â±ê¼ÇÀ´¿ØÖÆ¡£
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export)7.2\. Ö§³ÖµÄ¼à¿ØÏµÍ³
+
+
+
+±¾½Ú¼òÒª½éÉÜÿ¸öÖ§³ÖµÄ¼à¿ØÏµÍ³¡£
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.appoptics)7.2.1\. AppOptics
+
+
+
+ĬÈÏÇé¿öÏ£¬AppOptics×¢²áÖÐÐĻᶨÆÚ½«Ö¸±êÍÆË͵½ `[api.appoptics.com/v1/measurements](https://api.appoptics.com/v1/measurements)`¡£Òª½«Ö¸±êµ¼³öµ½ SaaS [AppOptics](https://micrometer.io/docs/registry/appOptics)£¬±ØÐëÌṩÄãµÄAPIÁîÅÆ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.appoptics.metrics.export.api-token=YOUR_TOKEN
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.atlas)7.2.2\. Atlas
+
+
+
+ĬÈÏÇé¿öÏ£¬Ö¸±ê»á±»µ¼³öµ½ÔËÐÐÔÚÄã±¾µØ»úÆ÷É쵀 [Atlas](https://micrometer.io/docs/registry/atlas)¡£Äã¿ÉÒÔÌṩ [Atlas server](https://github.com/Netflix/atlas) µÄλÖá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.atlas.metrics.export.uri=https://atlas.example.com:7101/api/v1/publish
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.datadog)7.2.3\. Datadog
+
+
+
+Ò»¸öDatadog×¢²áÖÐÐĻᶨÆÚ½«Ö¸±êÍÆË͵½ [datadoghq](https://www.datadoghq.com/)¡£ Òªµ¼³öÖ¸±êµ½ [Datadog](https://micrometer.io/docs/registry/datadog)£¬Äã±ØÐëÌṩÄãµÄAPIÃÜÔ¿¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.datadog.metrics.export.api-key=YOUR_KEY
+
+```
+
+
+
+
+
+
+
+Èç¹ûÄãÁíÍâÌṩһ¸öÓ¦ÓÃÃÜÔ¿£¨¿ÉÑ¡£©£¬ÄÇôԪÊý¾Ý£¬ÈçÒDZíÃèÊö¡¢ÀàÐͺͻù±¾µ¥Î»Ò²½«±»µ¼³ö¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.datadog.metrics.export.api-key=YOUR_API_KEY
+management.datadog.metrics.export.application-key=YOUR_APPLICATION_KEY
+
+```
+
+
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬Ö¸±ê±»·¢Ë͵½DatadogÃÀ¹ú [site](https://docs.datadoghq.com/getting_started/site) £¨`[api.datadoghq.com](https://api.datadoghq.com/)`£©¡£ Èç¹ûÄãµÄDatadogÏîÄ¿ÍйÜÔÚÆäËûÍøÕ¾ÉÏ£¬»òÕßÄãÐèҪͨ¹ý´úÀí·¢ËÍÖ¸±ê£¬ÇëÏàÓ¦ÅäÖÃURI¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.datadog.metrics.export.uri=https://api.datadoghq.eu
+
+```
+
+
+
+
+
+
+
+Ä㻹¿ÉÒԸıäÏòDatadog·¢ËÍÖ¸±êµÄʱ¼ä¼ä¸ô¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.datadog.metrics.export.step=30s
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.dynatrace)7.2.4\. Dynatrace
+
+
+
+DynatraceÌṩÁËÁ½¸öÖ¸±êÉãÈ¡API£¬¶¼ÊÇΪ [Micrometer](https://micrometer.io/docs/registry/dynatrace) ʵÏֵġ£Äã¿ÉÒÔÔÚ [ÕâÀï](https://www.dynatrace.com/support/help/how-to-use-dynatrace/metrics/metric-ingestion/ingestion-methods/micrometer) ÕÒµ½Dynatrace¹ØÓÚMicrometerÖ¸±êÉãÈëµÄÎĵµ¡£`v1` ÃüÃû¿Õ¼äÖеÄÅäÖÃÊôÐÔÖ»ÊÊÓÃÓÚµ¼³öµ½ [Timeseries v1 API](https://www.dynatrace.com/support/help/dynatrace-api/environment-api/metric-v1/) ʱ¡£`v2` ÃüÃû¿Õ¼äÖеÄÅäÖÃÊôÐÔÖ»ÊÊÓÃÓÚµ¼³öµ½ [Metrics v2 API](https://www.dynatrace.com/support/help/dynatrace-api/environment-api/metric-v2/post-ingest-metrics/) ʱ¡£Çë×¢Ò⣬¸Ã¼¯³Éÿ´ÎÖ»Äܵ¼³öµ½APIµÄ `v1` »ò `v2` °æ±¾£¬`v2` °æ±¾ÊÇÊ×Ñ¡¡£Èç¹û `device-id`£¨v1°æÐèÒª£¬µ«ÔÚv2°æÖв»Ê¹Óã©ÔÚ `v1` °æÃüÃû¿Õ¼äÖб»ÉèÖã¬ÄÇômetric½«±»µ¼³öµ½ `v1` °æ¶Ëµã¡£·ñÔò£¬¾Í¼Ù¶¨ÊÇ `v2` °æ±¾¡£
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.dynatrace.v2-api)v2 API
+
+
+
+Äã¿ÉÒÔͨ¹ýÁ½ÖÖ·½Ê½Ê¹ÓÃv2 API¡£
+
+
+
+
+
+###### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.dynatrace.v2-api.auto-config)×Ô¶¯ÅäÖÃ
+
+
+
+Dynatrace×Ô¶¯ÅäÖÃÊÊÓÃÓÚÓÉOneAgent»òDynatrace Operator for Kubernetes¼à¿ØµÄÖ÷»ú¡£
+
+
+
+
+
+**±¾µØOneAgent£º**Èç¹ûÖ÷»úÉÏÔËÐÐOneAgent£¬Ö¸±ê»á×Ô¶¯Êä³öµ½ [local OneAgent ingest endpoint](https://www.dynatrace.com/support/help/how-to-use-dynatrace/metrics/metric-ingestion/ingestion-methods/local-api/) ¡£ ÉãÈ¡¶Ëµã½«Ö¸±êת·¢µ½Dynatraceºó¶Ë¡£
+
+
+
+
+
+**Dynatrace Kubernetes Operator£º**ÔÚ°²×°ÁËDynatrace OperatorµÄKubernetesÖÐÔËÐÐʱ£¬×¢²á±í½«×Ô¶¯´Ó²Ù×÷Ô±ÄÇÀï»ñÈ¡ÄãµÄ¶ËµãURIºÍAPIÁîÅÆ¡£
+
+
+
+
+
+ÕâÊÇĬÈÏÐÐΪ£¬³ýÁËÒÀÀµ `io.micrometer:micrometer-registry-dynatrace` Ö®Í⣬²»ÐèÒªÌØ±ðµÄÉèÖá£
+
+
+
+
+
+
+
+###### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.dynatrace.v2-api.manual-config)ÊÖ¶¯ÅäÖÃ
+
+
+
+Èç¹ûûÓÐ×Ô¶¯ÅäÖã¬ÔòÐèÒª [Metrics v2 API](https://www.dynatrace.com/support/help/dynatrace-api/environment-api/metric-v2/post-ingest-metrics/) µÄ¶ËµãºÍÒ»¸ö API ÁîÅÆ¡£APIÁîÅÆ±ØÐëÓÐ ¡°Ingest metrics¡± £¨`metrics.ingest`£©µÄȨÏÞÉèÖá£ÎÒÃǽ¨Ò齫ÁîÅÆµÄ·¶Î§ÏÞÖÆÔÚÕâÒ»¸öȨÏÞÉÏ¡£Äã±ØÐëÈ·±£¶ËµãURI°üº¬Â·¾¶£¨ÀýÈ磬`/api/v2/metrics/ingest`£©¡£
+
+
+
+
+
+Metrics API v2ÉãÈ¡¶ËµãµÄURL¸ù¾ÝÄãµÄ²¿ÊðÑ¡Ïî¶ø²»Í¬¡£
+
+
+
+
+
+* SaaS: `https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest`
+
+* Managed deployments: `https://{your-domain}/e/{your-environment-id}/api/v2/metrics/ingest`
+
+
+
+
+
+ÏÂÃæµÄÀý×ÓÊÇÓà `example` environment id ÅäÖöÈÁ¿Öµµ¼³ö¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.dynatrace.metrics.export.uri=https://example.live.dynatrace.com/api/v2/metrics/ingest
+management.dynatrace.metrics.export.api-token=YOUR_TOKEN
+
+```
+
+
+
+
+
+
+
+ÔÚʹÓÃDynatrace v2 APIʱ£¬¿ÉÒÔʹÓÃÒÔÏ¿ÉÑ¡¹¦ÄÜ£¨¸ü¶àϸ½Ú¿ÉÔÚ [DynatraceÎĵµ](https://www.dynatrace.com/support/help/how-to-use-dynatrace/metrics/metric-ingestion/ingestion-methods/micrometer#dt-configuration-properties) ÖÐÕÒµ½£©¡£
+
+
+
+
+
+* Metric key µÄǰ׺¡£ÉèÖÃÒ»¸öǰ׺£¬¸Ãǰ׺½«±»Ìí¼Óµ½ËùÓе¼³öµÄmetric keyÖС£
+
+* ÓÃDynatraceÔªÊý¾ÝÀ´³äʵ¡£Èç¹ûOneAgent»òDynatrace²Ù×÷Ô±ÕýÔÚÔËÐУ¬ÓöîÍâµÄÔªÊý¾Ý£¨ÀýÈ磬¹ØÓÚÖ÷»ú¡¢½ø³Ì»òPod£©À´·á¸»Ö¸±ê¡£
+
+* ĬÈÏά¶È¡£Ö¸¶¨Ìí¼Óµ½ËùÓе¼³ö¶ÈÁ¿µÄ¼üÖµ¶Ô¡£ Èç¹ûÓÃMicrometerÖ¸¶¨Á˾ßÓÐÏàͬ¼üµÄ±êÇ©£¬ËüÃǽ«¸²¸ÇĬÈÏdimension¡£
+
+* ʹÓÃDynatrace Summary instrument¡£ÔÚijЩÇé¿öÏ£¬Micrometer Dynatrace×¢²á±í´´½¨µÄÖ¸±ê±»¾Ü¾ø¡£ ÔÚMicrometer 1.9.xÖУ¬Í¨¹ýÒýÈëDynatraceÌØ¶¨µÄÕªÒª¹¤¾ßÀ´½â¾öÕâ¸öÎÊÌâ¡£ °ÑÕâ¸ö¿ª¹ØÉèÖÃΪ `false` »áÆÈʹMicrometer»Øµ½1.9.x֮ǰµÄĬÈÏÐÐΪ¡£ Ö»ÓÐÔÚ´ÓMicrometer 1.8.xÇ¨ÒÆµ½1.9.xʱÓöµ½ÎÊÌâʱ²Å¿ÉÒÔʹÓá£
+
+
+
+
+
+¿ÉÒÔ²»Ö¸¶¨URIºÍAPIÁîÅÆ£¬ÈçÒÔÏÂÀý×ÓËùʾ¡£ ÔÚÕâÖÖÇé¿öÏ£¬»áʹÓÃ×Ô¶¯ÅäÖõĶ˵㡣
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.dynatrace.metrics.export.v2.metric-key-prefix=your.key.prefix
+management.dynatrace.metrics.export.v2.enrich-with-dynatrace-metadata=true
+management.dynatrace.metrics.export.v2.default-dimensions.key1=value1
+management.dynatrace.metrics.export.v2.default-dimensions.key2=value2
+management.dynatrace.metrics.export.v2.use-dynatrace-summary-instruments=true
+
+```
+
+
+
+
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.dynatrace.v1-api)v1 API (Legacy)
+
+
+
+Dynatrace v1 APIÖ¸±ê×¢²á±íͨ¹ýʹÓà [Timeseries v1 API](https://www.dynatrace.com/support/help/dynatrace-api/environment-api/metric-v1/) ¶¨ÆÚ½«Ö¸±êÍÆË͵½ÅäÖõÄURI¡£ ΪÁËÏòºó¼æÈÝÏÖÓеÄÉèÖ㬵± `device-id` ±»ÉèÖÃʱ£¨v1ÐèÒª£¬µ«ÔÚv2Öв»Ê¹Óã©£¬Ö¸±ê±»µ¼³öµ½Timeseries v1¶Ëµã¡£ ÒªÏò [Dynatrace](https://micrometer.io/docs/registry/dynatrace) µ¼³öÖ¸±ê£¬±ØÐëÌṩÄãµÄAPIÁîÅÆ¡¢É豸IDºÍURI¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.dynatrace.metrics.export.uri=https://{your-environment-id}.live.dynatrace.com
+management.dynatrace.metrics.export.api-token=YOUR_TOKEN
+management.dynatrace.metrics.export.v1.device-id=YOUR_DEVICE_ID
+
+```
+
+
+
+
+
+
+
+¶ÔÓÚv1°æAPI£¬Äã±ØÐëÖ¸¶¨»ù±¾»·¾³URI£¬¶ø²»Ö¸¶¨Â·¾¶£¬ÒòΪv1°æµÄ¶Ëµã·¾¶»á×Ô¶¯Ìí¼Ó¡£
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.dynatrace.version-independent-settings)Óë°æ±¾Î޹صÄÉèÖÃ
+
+
+
+³ýÁËAPI¶ËµãºÍÁîÅÆÍ⣬Ä㻹¿ÉÒԸıäÏòDynatrace·¢ËÍÖ¸±êµÄ¼ä¸ôʱ¼ä¡£ ĬÈϵĵ¼³öʱ¼ä¼ä¸ôÊÇ `60s`¡£ ÏÂÃæµÄÀý×Ó½«µ¼³öʱ¼ä¼ä¸ôÉèÖÃΪ30Ãë¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.dynatrace.metrics.export.step=30s
+
+```
+
+
+
+
+
+
+
+Äã¿ÉÒÔÔÚ [MicrometerÎĵµ](https://micrometer.io/docs/registry/dynatrace) ºÍ [DynatraceÎĵµ](https://www.dynatrace.com/support/help/how-to-use-dynatrace/metrics/metric-ingestion/ingestion-methods/micrometer) ÖÐÕÒµ½¹ØÓÚÈçºÎΪMicrometerÉèÖÃDynatrace exporter£¨µ¼³öÆ÷£©µÄ¸ü¶àÐÅÏ¢¡£
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.elastic)7.2.5\. Elastic
+
+
+
+ĬÈÏÇé¿öÏ£¬Ö¸±ê±»µ¼³öµ½ÔËÐÐÔÚÄã±¾µØ»úÆ÷É쵀 [Elastic](https://micrometer.io/docs/registry/elastic) ¡£ Äã¿ÉÒÔͨ¹ýʹÓÃÒÔÏÂÊôÐÔÌṩҪʹÓõÄElastic·þÎñÆ÷µÄλÖá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.elastic.metrics.export.host=https://elastic.example.com:8086
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.ganglia)7.2.6\. Ganglia
+
+
+
+ĬÈÏÇé¿öÏ£¬Ö¸±ê±»µ¼³öµ½ÔËÐÐÔÚÄã±¾µØ»úÆ÷É쵀 [Ganglia](https://micrometer.io/docs/registry/ganglia) ¡£Äã¿ÉÒÔÌṩ [Ganglia server](http://ganglia.sourceforge.net/) µÄÖ÷»úºÍ¶Ë¿Ú£¬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.ganglia.metrics.export.host=ganglia.example.com
+management.ganglia.metrics.export.port=9649
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.graphite)7.2.7\. Graphite
+
+
+
+ĬÈÏÇé¿öÏ£¬Ö¸±ê»á±»µ¼³öµ½ÔËÐÐÔÚÄã±¾µØ»úÆ÷É쵀 [Graphite](https://micrometer.io/docs/registry/graphite) ¡£Äã¿ÉÒÔÌṩ [Graphite server](https://graphiteapp.org/) µÄÖ÷»úºÍ¶Ë¿Ú£¬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.graphite.metrics.export.host=graphite.example.com
+management.graphite.metrics.export.port=9004
+
+```
+
+
+
+
+
+
+
+MicrometerÌṩÁËÒ»¸öĬÈ쵀 `HierarchicalNameMapper`£¬¹ÜÀídimensional meter IDÈçºÎhttps://micrometer.io/docs/registry/graphite#_hierarchical_name_mapping[Ó³Éäµ½ flat hierarchical name]¡£
+
+
+
+
+
+| | Òª¿ØÖÆÕâÖÖÐÐΪ£¬Ç붨ÒåÄãµÄ `GraphiteMeterRegistry` ²¢ÌṩÄã×Ô¼ºµÄ `HierarchicalNameMapper`¡£ ³ý·ÇÄã×Ô¼º¶¨Ò壬·ñÔò»áÌṩһ¸ö×Ô¶¯ÅäÖÃµÄ `GraphiteConfig` ºÍ `Clock` Bean¡£JavaKotlin```@Configuration(proxyBeanMethods = false)public class MyGraphiteConfiguration { @Bean public GraphiteMeterRegistry graphiteMeterRegistry(GraphiteConfig config, Clock clock) { return new GraphiteMeterRegistry(config, clock, this::toHierarchicalName); } private String toHierarchicalName(Meter.Id id, NamingConvention convention) { return ... }}``` |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.humio)7.2.8\. Humio
+
+
+
+ĬÈÏÇé¿öÏ£¬Humio×¢²áÖÐÐĻᶨÆÚ½«Ö¸±êÍÆË͵½ [cloud.humio.com](https://cloud.humio.com/) ¡£ Òª½«Ö¸±êµ¼³öµ½SaaS [Humio](https://micrometer.io/docs/registry/humio)£¬Äã±ØÐëÌṩÄãµÄAPIÁîÅÆ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.humio.metrics.export.api-token=YOUR_TOKEN
+
+```
+
+
+
+
+
+
+
+Ä㻹Ӧ¸ÃÅäÖÃÒ»¸ö»ò¶à¸ö±êÇ©£¬ÒÔÈ·¶¨ÍÆËÍÖ¸±êµÄÊý¾ÝÔ´¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.humio.metrics.export.tags.alpha=a
+management.humio.metrics.export.tags.bravo=b
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.influx)7.2.9\. Influx
+
+
+
+ĬÈÏÇé¿öÏ£¬Ö¸±ê»á±»µ¼³öµ½ÔËÐÐÔÚ±¾µØ»úÆ÷É쵀 [Influx](https://micrometer.io/docs/registry/influx) v1ʵÀý£¬²¢²ÉÓÃĬÈÏÅäÖá£Òªµ¼³öÖ¸±êµ½InfluxDB v2£¬ÇëÅäÖà `org`¡¢`bucket` ºÍÓÃÓÚдÈëÖ¸±êµÄauthentication `token`¡£Äã¿ÉÒÔͨ¹ýÒÔÏ·½Ê½ÌṩҪʹÓÃµÄ [Influx server](https://www.influxdata.com/) µÄλÖá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.influx.metrics.export.uri=https://influx.example.com:8086
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.jmx)7.2.10\. JMX
+
+
+
+MicrometerÌṩÁË¶Ô [JMX](https://micrometer.io/docs/registry/jmx) µÄ·Ö²ãÓ³É䣬Ö÷ÒªÊÇ×÷ΪһÖÖÁ®¼ÛºÍ¿ÉÒÆÖ²µÄ·½Ê½À´²é¿´±¾µØµÄ¶ÈÁ¿¡£ ĬÈÏÇé¿öÏ£¬Ö¸±ê±»µ¼³öµ½ `metrics` JMXÓò¡£ Äã¿ÉÒÔͨ¹ýÒÔÏ·½Ê½ÌṩҪʹÓõÄÓò¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.jmx.metrics.export.domain=com.example.app.metrics
+
+```
+
+
+
+
+
+
+
+MicrometerÌṩÁËÒ»¸öĬÈ쵀 `HierarchicalNameMapper`£¬¹ÜÀídimensional meter ID ÈçºÎ [Ó³Éäµ½ flat hierarchical name](https://micrometer.io/docs/registry/jmx#_hierarchical_name_mapping)¡£
+
+
+
+
+
+| | Òª¿ØÖÆÕâÖÖÐÐΪ£¬Ç붨ÒåÄãµÄ `JmxMeterRegistry` ²¢ÌṩÄã×Ô¼ºµÄ `HierarchicalNameMapper`¡£ ³ý·ÇÄã×Ô¼º¶¨Ò壬·ñÔò»áÌṩһ¸ö×Ô¶¯ÅäÖÃµÄ `JmxConfig` ºÍ `Clock` Bean¡£JavaKotlin```@Configuration(proxyBeanMethods = false)public class MyJmxConfiguration { @Bean public JmxMeterRegistry jmxMeterRegistry(JmxConfig config, Clock clock) { return new JmxMeterRegistry(config, clock, this::toHierarchicalName); } private String toHierarchicalName(Meter.Id id, NamingConvention convention) { return ... }}``` |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.kairos)7.2.11\. KairosDB
+
+
+
+ĬÈÏÇé¿öÏ£¬Ö¸±ê±»µ¼³öµ½ÔËÐÐÔÚÄã±¾µØ»úÆ÷É쵀 [KairosDB](https://micrometer.io/docs/registry/kairos) ¡£Äã¿ÉÒÔͨ¹ýÒÔÏ·½Ê½ÌṩҪʹÓÃµÄ [KairosDB server](https://kairosdb.github.io/) µÄλÖá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.kairos.metrics.export.uri=https://kairosdb.example.com:8080/api/v1/datapoints
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.newrelic)7.2.12\. New Relic
+
+
+
+New Relic×¢²áÖÐÐĻᶨÆÚ½«Ö¸±êÍÆË͵½ [New Relic](https://micrometer.io/docs/registry/new-relic)¡£Òªµ¼³öÖ¸±êµ½ [New Relic](https://newrelic.com/)£¬Äã±ØÐëÌṩÄãµÄAPIÃÜÔ¿ºÍÕË»§ID¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.newrelic.metrics.export.api-key=YOUR_KEY
+management.newrelic.metrics.export.account-id=YOUR_ACCOUNT_ID
+
+```
+
+
+
+
+
+
+
+Ä㻹¿ÉÒԸıäÏòNew Relic·¢ËÍÖ¸±êµÄʱ¼ä¼ä¸ô¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.newrelic.metrics.export.step=30s
+
+```
+
+
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬Ö¸±êÊÇͨ¹ýRESTµ÷Ó÷¢²¼µÄ£¬µ«Èç¹ûÄãÔÚclasspathÉÏÓÐJava Agent API£¬ÄãÒ²¿ÉÒÔʹÓÃËü¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.newrelic.metrics.export.client-provider-type=insights-agent
+
+```
+
+
+
+
+
+
+
+×îºó£¬Äã¿ÉÒÔͨ¹ý¶¨ÒåÄã×Ô¼ºµÄ `NewRelicClientProvider` ¶¹À´ÍêÈ«¿ØÖÆ¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.otlp)7.2.13\. OpenTelemetry
+
+
+
+ĬÈÏÇé¿öÏ£¬Ö¸±ê±»µ¼³öµ½ÔËÐÐÔÚÄã±¾µØ»úÆ÷É쵀 [OpenTelemetry](https://micrometer.io/docs/registry/otlp) ¡£Äã¿ÉÒÔͨ¹ýÒÔÏ·½Ê½ÌṩҪʹÓÃµÄ [OpenTelemtry metric endpoint](https://opentelemetry.io/) µÄλÖá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.otlp.metrics.export.url=https://otlp.example.com:4318/v1/metrics
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.prometheus)7.2.14\. Prometheus
+
+
+
+[Prometheus](https://micrometer.io/docs/registry/prometheus) Ï£Íûscrape»òÂÖѯµ¥¸öÓ¦ÓóÌÐòʵÀýµÄÖ¸±ê¡£Spring BootÔÚ `/actuator/prometheus` ÌṩÁËÒ»¸öactuator¶Ëµã£¬ÒÔ±ãÒÔÊʵ±µÄ¸ñʽ³ÊÏÖ [Prometheus scrape](https://prometheus.io/)¡£
+
+
+
+
+
+| | ĬÈÏÇé¿öÏ£¬¸Ã¶ËµãÊDz»¿ÉÓõ쬱ØÐë±»±©Â¶¡£¸ü¶àϸ½ÚÇë²Î¼û[±©Â¶¶Ëµã](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.exposing)¡£ |
+| --- | --- |
+
+
+
+
+
+ÏÂÃæµÄÀý×Ó `scrape_config` Ìí¼Óµ½ `prometheus.yml`¡£
+
+
+
+
+
+
+
+```
+scrape_configs:
+ - job_name: "spring"
+ metrics_path: "/actuator/prometheus"
+ static_configs:
+ - targets: ["HOST:PORT"]
+```
+
+
+
+
+
+
+
+Ò²Ö§³Ö [Prometheus Exemplars](https://prometheus.io/docs/prometheus/latest/feature_flags/#exemplars-storage)¡£ÒªÆôÓÃÕâ¸ö¹¦ÄÜ£¬Ó¦¸ÃÓÐÒ»¸ö `SpanContextSupplier` Bean¡£Èç¹ûÄãʹÓà [Micrometer Tracing](https://micrometer.io/docs/tracing)£¬Õ⽫ΪÄã×Ô¶¯ÅäÖ㬵«Èç¹ûÄãÏ룬Äã×ÜÊÇ¿ÉÒÔ´´½¨×Ô¼ºµÄ¡£Çë²é¿´ [Prometheus Îĵµ](https://prometheus.io/docs/prometheus/latest/feature_flags/#exemplars-storage) £¬ÒòΪÕâ¸ö¹¦ÄÜÐèÒªÔÚPrometheusÕâ±ßÃ÷È·ÆôÓ㬶øÇÒÖ»Ö§³ÖʹÓà [OpenMetrics](https://github.com/OpenObservability/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md#exemplars) ¸ñʽ¡£
+
+
+
+
+
+¶ÔÓÚ¶ÌÔݵĻòÅú´¦ÀíµÄ×÷Òµ£¬¿ÉÄÜ´æÔÚµÄʱ¼ä²»¹»³¤£¬ÎÞ·¨±»¹ÎÈ¡£¬Äã¿ÉÒÔʹÓà [Prometheus Pushgateway](https://github.com/prometheus/pushgateway) Ö§³Ö£¬½«Ö¸±ê±©Â¶¸øPrometheus¡£ÒªÆôÓÃPrometheus PushgatewayÖ§³Ö£¬ÇëÔÚÄãµÄÏîÄ¿ÖÐÌí¼ÓÒÔÏÂÒÀÀµ¡£
+
+
+
+
+
+
+
+```
+
+ io.prometheus
+ simpleclient_pushgateway
+
+```
+
+
+
+
+
+
+
+µ±Prometheus PushgatewayµÄÒÀÀµ³öÏÖÔÚclasspathÉÏ£¬²¢ÇÒ `management.prometheus.metrics.export.pushgateway.enabled` ÊôÐÔ±»ÉèÖÃΪ `true` ʱ£¬Ò»¸ö `PrometheusPushGatewayManager` bean¾Í±»×Ô¶¯ÅäÖÃÁË¡£ Ëü¸ºÔð¹ÜÀíÏòPrometheus PushgatewayÍÆËÍÖ¸±êµÄ¹¤×÷¡£
+
+
+
+
+
+Äã¿ÉÒÔͨ¹ýʹÓà `management.prometheus.metrics.export.pushgateway` ϵÄÊôÐÔÀ´µ÷Õû `PrometheusPushGatewayManager`¡£ ¶ÔÓڸ߼¶ÅäÖã¬ÄãÒ²¿ÉÒÔÌṩÄã×Ô¼ºµÄ `PrometheusPushGatewayManager` bean¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.signalfx)7.2.15\. SignalFx
+
+
+
+SignalFx×¢²áÖÐÐĻᶨÆÚ½«Ö¸±êÍÆË͵½ [SignalFx](https://micrometer.io/docs/registry/signalFx)¡£Òªµ¼³öÖ¸±êµ½ [SignalFx](https://www.signalfx.com/)£¬Äã±ØÐëÌṩÄãµÄaccess token¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.signalfx.metrics.export.access-token=YOUR_ACCESS_TOKEN
+
+```
+
+
+
+
+
+
+
+ÄãÒ²¿ÉÒԸıäÏòSignalFx·¢ËÍÖ¸±êµÄʱ¼ä¼ä¸ô¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.signalfx.metrics.export.step=30s
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.simple)7.2.16\. Simple
+
+
+
+MicrometerÌṩÁËÒ»¸ö¼òµ¥µÄ¡¢ÄÚ´æÖеĺó¶Ë£¬Èç¹ûûÓÐÅäÖÃÆäËû×¢²á±í£¬¸Ãºó¶Ë»á×Ô¶¯×÷Ϊ±¸Óá£Õâ¿ÉÒÔÈÃÄã¿´µ½ÔÚ [metrics endpoint](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.endpoint) ÖÐÊÕ¼¯ÁËÄÄЩ¶ÈÁ¿¡£
+
+
+
+
+
+Ò»µ©ÄãʹÓÃÈÎºÎÆäËû¿ÉÓõĺó¶Ë£¬ÄÚ´æÖеĺó¶Ë¾Í»á×Ô¶¯¹Ø±Õ¡£ÄãÒ²¿ÉÒÔÃ÷È·µØ½ûÓÃËü¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.simple.metrics.export.enabled=false
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.stackdriver)7.2.17\. Stackdriver
+
+
+
+Stackdriver×¢²áÖÐÐĻᶨÆÚÏò [Stackdriver](https://cloud.google.com/stackdriver/) ÍÆËÍÖ¸±ê¡£Òªµ¼³öÖ¸±êµ½SaaS [Stackdriver](https://micrometer.io/docs/registry/stackdriver)£¬Äã±ØÐëÌṩÄãµÄGoogle Cloud project ID¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.stackdriver.metrics.export.project-id=my-project
+
+```
+
+
+
+
+
+
+
+Ä㻹¿ÉÒԸıäÏòStackdriver·¢ËÍÖ¸±êµÄʱ¼ä¼ä¸ô¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.stackdriver.metrics.export.step=30s
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.statsd)7.2.18\. StatsD
+
+
+
+StatsD×¢²á±í¼±Çеؽ«Ö¸±êͨ¹ýUDPÍÆË͸øStatsD agent¡£Ä¬ÈÏÇé¿öÏ£¬Ö¸±ê±»µ¼³öµ½ÔËÐÐÔÚÄã±¾µØ»úÆ÷É쵀 [StatsD](https://micrometer.io/docs/registry/statsD) agent¡£Äã¿ÉÒÔͨ¹ýÒÔÏ·½Ê½ÌṩStatsD´úÀíµÄÖ÷»ú¡¢¶Ë¿ÚºÍÐÒ飬ÒÔ±ãʹÓá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.statsd.metrics.export.host=statsd.example.com
+management.statsd.metrics.export.port=9125
+management.statsd.metrics.export.protocol=udp
+
+```
+
+
+
+
+
+
+
+Ä㻹¿ÉÒԸıäҪʹÓõÄStatsDÏß·ÐÒ飨ĬÈÏΪDatadog£©¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.statsd.metrics.export.flavor=etsy
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.export.wavefront)7.2.19\. Wavefront
+
+
+
+Wavefront×¢²á±í¶¨ÆÚ½«Ö¸±êÍÆË͵½ [Wavefront](https://micrometer.io/docs/registry/wavefront)¡£Èç¹ûÄãÖ±½Ó½«Ö¸±êµ¼³öµ½ [Wavefront](https://www.wavefront.com/)£¬Äã±ØÐëÌṩÄãµÄAPI token¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.wavefront.api-token=YOUR_API_TOKEN
+
+```
+
+
+
+
+
+
+
+ÁíÍ⣬Äú¿ÉÒÔÔÚÄúµÄ»·¾³ÖÐʹÓÃWavefront sidecar»òÄÚ²¿´úÀíÀ´×ª·¢Ö¸±êÊý¾Ýµ½Wavefront APIÖ÷»ú¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.wavefront.uri=proxy://localhost:2878
+
+```
+
+
+
+
+
+
+
+Èç¹ûÄú½«Ö¸±ê·¢²¼µ½Wavefront´úÀí£¨Èç [WavefrontÎĵµ](https://docs.wavefront.com/proxies_installing.html) ÖÐËùÊö£©£¬Ö÷»ú±ØÐëÊÇ `proxy://HOST:PORT` ¸ñʽ¡£
+
+
+
+
+
+ÄãÒ²¿ÉÒԸıäÏòWavefront·¢ËÍÖ¸±êµÄʱ¼ä¼ä¸ô¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.wavefront.metrics.export.step=30s
+
+```
+
+
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported)7.3\. Ö§³ÖµÄÖ¸±ê £¨Metric£©ºÍ¶ÈÁ¿£¨Meter£©
+
+
+
+Spring BootΪ¸÷ÖÖ¸÷ÑùµÄ¼¼ÊõÌṩÁË×Ô¶¯¼ÆÁ¿Æ÷×¢²á¡£ ÔÚ´ó¶àÊýÇé¿öÏ£¬Ä¬ÈÏÖµÌṩÁ˺ÏÀíµÄÖ¸±ê£¬¿ÉÒÔ·¢²¼µ½ÈκÎÖ§³ÖµÄ¼à¿ØÏµÍ³ÖС£
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.jvm)7.3.1\. JVMÖ¸±ê
+
+
+
+×Ô¶¯ÅäÖÃͨ¹ýʹÓúËÐÄ Micrometer ÀàÆôÓÃJVM¶ÈÁ¿¡£ JVMÖ¸±êÔÚ `jvm.` meter name Ï·¢²¼¡£
+
+
+
+
+
+ÌṩÒÔÏÂJVMÖ¸±ê¡£
+
+
+
+
+
+* ¸÷ÖÖÄÚ´æºÍ»º³å³ØÏ¸½Ú
+
+* ÓëÀ¬»øÊÕ¼¯ÓйصÄͳ¼ÆÊý¾Ý
+
+* Ïß³ÌÀûÓÃÂÊ
+
+* ¼ÓÔØºÍÐ¶ÔØµÄÀàµÄÊýÁ¿
+
+* JVMµÄ°æ±¾ÐÅÏ¢
+
+* JIT ±àÒëʱ¼ä
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.system)7.3.2\. ϵͳָ±ê
+
+
+
+×Ô¶¯ÅäÖÃͨ¹ýʹÓúËÐÄMicrometerÀàÀ´ÊµÏÖϵͳ¶ÈÁ¿¡£ ϵͳָ±êÔÚ `system.`¡¢`process.` ºÍ `disk.` meter ÃûÏ·¢²¼¡£
+
+
+
+
+
+ÌṩÒÔÏÂϵͳָ±ê¡£
+
+
+
+
+
+* CPUÖ¸±ê
+
+* ÎļþÃèÊö·ûÖ¸±ê
+
+* Õý³£ÔËÐÐʱ¼äÖ¸±ê£¨°üÀ¨Ó¦ÓóÌÐòÒѾÔËÐеÄʱ¼äºÍ¾ø¶ÔÆô¶¯Ê±¼äµÄ¹Ì¶¨²âÁ¿£©¡£
+
+* ¿ÉÓõĴÅÅ̿ռä
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.application-startup)7.3.3\. Ó¦ÓóÌÐòÆô¶¯Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖñ©Â¶ÁËÓ¦ÓóÌÐòµÄÆô¶¯Ê±¼äÖ¸±ê¡£
+
+
+
+
+
+* `application.started.time`: Æô¶¯Ó¦ÓóÌÐòµÄʱ¼ä¡£
+
+* `application.ready.time`£ºÓ¦ÓóÌÐò×¼±¸ºÃΪÇëÇóÌṩ·þÎñËùÐèµÄʱ¼ä¡£
+
+
+
+
+
+Ö¸±êÊÇÓÉÓ¦ÓÃÀàµÄÍêÈ«Ãû³ÆÀ´±ê¼ÇµÄ¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.logger)7.3.4\. ÈÕÖ¾¼Ç¼Æ÷Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖÃÆôÓÃÁËLogbackºÍLog4J2µÄʼþ¶ÈÁ¿¡£ ϸ½ÚÔÚ `log4j2.events.` »ò `logback.events.` meterÃûϹ«²¼¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.tasks)7.3.5\. ÈÎÎñÖ´Ðк͵÷¶ÈÖ¸±ê
+
+
+
+×Ô¶¯ÅäÖÃʹËùÓпÉÓÃµÄ `ThreadPoolTaskExecutor` ºÍ `ThreadPoolTaskScheduler` Bean¶¼Äܱ»²âÁ¿£¬Ö»Òªµ×²ãµÄ `ThreadPoolExecutor` ¿ÉÓᣠָ±êÓÉexecutorµÄÃû³ÆÀ´±ê¼Ç£¬executorµÄÃû³ÆÀ´×ÔÓÚBeanµÄÃû³Æ¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.spring-mvc)7.3.6\. Spring MVC Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖÃÄܹ»¶Ô Spring MVC ControllerºÍ±à³Ìʽhandler´¦ÀíµÄËùÓÐÇëÇó½øÐжÈÁ¿¡£ ĬÈÏÇé¿öÏ£¬Ö¸±êÊÇÒÔ `http.server.requests` ΪÃû³ÆÉú³ÉµÄ¡£ Äã¿ÉÒÔͨ¹ýÉèÖà `management.observations.http.server.requests.name` ÊôÐÔÀ´¶¨ÖƸÃÃû³Æ¡£
+
+
+
+
+
+¹ØÓÚ²úÉúµÄ¹Û²ì½á¹û£¨observation£©µÄ¸ü¶àÐÅÏ¢£¬Çë²Î¼û [Spring Framework ²Î¿¼Îĵµ](https://docs.spring.io/spring-framework/docs/6.0.5/reference/html/integration.html#integration.observability.http-server.servlet)¡£
+
+
+
+
+
+ÒªÌí¼Óµ½Ä¬ÈϱêÇ©ÖУ¬ÇëÌṩһ¸ö¼Ì³ÐÁË `org.springframework.http.server.observation` °üÖÐµÄ `DefaultServerRequestObservationConvention` µÄ `@Bean`¡£ÒªÌ滻ĬÈϱêÇ©£¬ÇëÌṩһ¸öʵÏÖ `ServerRequestObservationConvention` µÄ `@Bean`¡£
+
+
+
+
+
+| | ÔÚijЩÇé¿öÏ£¬Web¿ØÖÆÆ÷Öд¦ÀíµÄÒì³£²»»á±»¼Ç¼ΪÇëÇó¶ÈÁ¿±êÇ©¡£Ó¦ÓóÌÐò¿ÉÒÔÑ¡Ôñ¼ÓÈ벢ͨ¹ý½«[handled exception ÉèÖÃΪ request attribute](https://springdoc.cn/spring-boot/web.html#web.servlet.spring-mvc.error-handling)À´¼Ç¼Òì³£¡£ |
+| --- | --- |
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬ËùÓÐÇëÇó¶¼±»´¦Àí¡£ Òª×Ô¶¨Òå¹ýÂËÆ÷£¬ÇëÌṩһ¸öʵÏÖ `FilterRegistrationBean` µÄ `@Bean`¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.spring-webflux)7.3.7\. Spring WebFlux Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖÃÄܹ»¶ÔSpring WebFlux controllerºÍ±à³ÌʽhandlerµÄËùÓÐÇëÇó½øÐжÈÁ¿¡£ ĬÈÏÇé¿öÏ£¬Ö¸±êÊÇÒÔ `http.server.requests` ΪÃûÉú³ÉµÄ¡£ Äã¿ÉÒÔͨ¹ýÉèÖà `management.observations.http.server.requests.name` ÊôÐÔÀ´¶¨ÖƸÃÃû³Æ¡£
+
+
+
+
+
+¹ØÓÚ²úÉúµÄ¹Û²ì½á¹û£¨observation£©µÄ¸ü¶àÐÅÏ¢£¬Çë²Î¼û [Spring Framework ²Î¿¼Îĵµ](https://docs.spring.io/spring-framework/docs/6.0.5/reference/html/integration.html#integration.observability.http-server.reactive)¡£
+
+
+
+
+
+ÒªÌí¼Óµ½Ä¬ÈϱêÇ©ÖУ¬ÇëÌṩ¼Ì³ÐÁË `org.springframework.http.server.reactive.observation` °üÖÐµÄ `DefaultServerRequestObservationConvention` µÄ `@Bean`¡£ÒªÌ滻ĬÈϱêÇ©£¬ÇëÌṩһ¸öʵÏÖ `ServerRequestObservationConvention` µÄ `@Bean`¡£
+
+
+
+
+
+| | ÔÚijЩÇé¿öÏ£¬¿ØÖÆÆ÷ºÍ´¦Àíº¯ÊýÖд¦ÀíµÄÒì³£²»»á±»¼Ç¼ΪÇëÇó¶ÈÁ¿±êÇ©¡£Ó¦ÓóÌÐò¿ÉÒÔÑ¡Ôñ¼ÓÈ벢ͨ¹ý[½«handled exceptionÉèÖÃΪrequest attribute](https://springdoc.cn/spring-boot/web.html#web.reactive.webflux.error-handling)À´¼Ç¼Òì³£¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.jersey)7.3.8\. Jersey Server Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖÃʹJersey JAX-RSʵÏÖËù´¦ÀíµÄËùÓÐÇëÇó¶¼Äܱ»²âÁ¿¡£ ĬÈÏÇé¿öÏ£¬Ö¸±êÊÇÒÔ `http.server.requests` ΪÃû³ÆÉú³ÉµÄ¡£ Äã¿ÉÒÔͨ¹ýÉèÖà `management.observations.http.server.requests.name` ÊôÐÔÀ´¶¨ÖÆÃû³Æ¡£
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬Jersey·þÎñÆ÷Ö¸±ê±»±ê¼ÇΪÒÔÏÂÐÅÏ¢¡£
+
+
+
+
+| Tag | ˵Ã÷ |
+| --- | --- |
+| `exception` | ´¦ÀíÇëÇóʱÅ׳öµÄÈκÎÒì³£µÄ¼òµ¥ÀàÃû¡£ |
+| `method` | ÇëÇóµÄ·½·¨£¨ÀýÈ磬`GET` »ò `POST`£©¡£ |
+| `outcome` | ÇëÇóµÄ½á¹û£¬»ùÓÚÏìÓ¦µÄ״̬´úÂë¡£ 1xxÊÇ `INFORMATIONAL`£¬2xxÊÇ `SUCCESS`£¬3xxÊÇ `REDIRECTION`£¬4xxÊÇ `CLIENT_ERROR`£¬5xxÊÇ `SERVER_ERROR`¡£ |
+| `status` | ÏìÓ¦µÄHTTP״̬´úÂ루ÀýÈ磬`200` »ò `500`£©¡£ |
+| `uri` | Èç¹û¿ÉÄܵϰ£¬ÔÚ½øÐбäÁ¿Ì滻֮ǰ£¬ÇëÇóµÄURIÄ£°å£¨ÀýÈ磺`/api/person/{id}`£©¡£ |
+
+
+
+Òª¶¨ÖƱêÇ©£¬ÇëÌṩһ¸öʵÏÖ `JerseyTagsProvider` µÄ `@Bean`¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.http-clients)7.3.9\. HTTP Client Ö¸±ê
+
+
+
+Spring Boot Actuator¸ºÔð¹ÜÀí `RestTemplate` ºÍ `WebClient` µÄ¹¤¾ß¡£Îª´Ë£¬Äã±ØÐë×¢Èë×Ô¶¯ÅäÖõĹ¹½¨Æ÷²¢Ê¹ÓÃËüÀ´´´½¨ÊµÀý¡£
+
+
+
+
+
+* `RestTemplateBuilder` ÓÃÓÚ `RestTemplate`
+
+* `WebClient.Builder` ÓÃÓÚ `WebClient`
+
+
+
+
+
+ÄãÒ²¿ÉÒÔÊÖ¶¯Ó¦ÓøºÔðÕâ¸ö¹¤¾ßµÄcustomizer£¬¼´ `ObservationRestTemplateCustomizer` ºÍ `ObservationWebClientCustomizer`¡£
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬Ö¸±êÊÇÒÔ `http.client.requests` Õâ¸öÃû×ÖÉú³ÉµÄ¡£
+
+
+
+
+
+Äã¿ÉÒÔͨ¹ýÉèÖà `management.observations.http.client.requests.name` ÊôÐÔÀ´¶¨ÖÆÕâ¸öÃû×Ö¡£
+
+
+
+
+
+¹ØÓÚ²úÉúµÄ¹Û²ì½á¹û£¨observation£©µÄ¸ü¶àÐÅÏ¢£¬Çë²Î¼û [Spring Framework ²Î¿¼Îĵµ](https://docs.spring.io/spring-framework/docs/6.0.5/reference/html/integration.html#integration.observability.http-client)¡£
+
+
+
+
+
+ÒªÔÚʹÓà `RestTemplate` ʱ¶¨ÖƱêÇ©£¬ÇëÌṩһ¸öʵÏÖÁË `org.springframework.http.client.observation` °üÖÐ `ClientRequestObservationConvention` µÄ `@Bean`¡£ÒªÔÚʹÓà `WebClient` ʱ×Ô¶¨Òå±êÇ©£¬ÇëÌṩһ¸öʵÏÖÁË `org.springframework.web.reactive.function.client` °üÖÐ `ClientRequestObservationConvention` µÄ `@Bean`¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.tomcat)7.3.10\. Tomcat Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖýöÔÚ `MBeanRegistry` ±»ÆôÓÃʱ²Å»áÆôÓÃTomcatµÄÒÇÆ÷¡£ ĬÈÏÇé¿öÏ£¬`MBeanRegistry` ÊǽûÓõ쬵«Äã¿ÉÒÔͨ¹ýÉèÖà `server.tomcat.mbeanregistry.enabled` Ϊ `true` À´ÆôÓÃËü¡£
+
+
+
+
+
+TomcatµÄÖ¸±êÔÚ `tomcat.` meter ÃûÏ·¢²¼¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.cache)7.3.11\. Cache Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖÿÉÒÔÔÚÆô¶¯Ê±¶ÔËùÓпÉÓÃµÄ `Cache` ʵÀý½øÐмì²â£¬ÆäÖ¸±êÒÔ `cache` Ϊǰ׺¡£
+
+
+
+
+
+»º´æÒDZíÊDZê×¼»¯µÄ»ù±¾Ö¸±ê¼¯¡£
+
+
+
+
+
+Ò²¿ÉÒÔʹÓöîÍâµÄ¡¢Õë¶Ô»º´æµÄÖ¸±ê¡£
+
+
+
+
+
+Ö§³ÖÒÔÏ»º´æ¿â¡£
+
+
+
+
+
+* Cache2k
+
+* Caffeine
+
+* Hazelcast
+
+* ÈκμæÈݵÄJCache£¨JSR-107£©ÊµÏÖ
+
+* Redis
+
+
+
+
+
+Ö¸±êÓÉ»º´æµÄÃû³ÆºÍ `CacheManager` µÄÃû³ÆÀ´±ê¼Ç£¬`CacheManager` µÄÃû³ÆÊÇÓÉBeanÃû³ÆÅÉÉúµÄ¡£
+
+
+
+
+
+| | Ö»ÓÐÔÚÆô¶¯Ê±ÅäÖõĻº´æ±»°ó¶¨µ½×¢²á±í¡£ ¶ÔÓÚûÓÐÔÚ»º´æÅäÖÃÖж¨ÒåµÄ»º´æ£¬ÀýÈçÔÚÆô¶¯½×¶ÎºóÁÙʱ´´½¨µÄ»º´æ»òÒÔ±à³Ì·½Ê½´´½¨µÄ»º´æ£¬ÐèÒªÃ÷È·×¢²á¡£ Ò»¸ö `CacheMetricsRegistrar` Bean¿ÉÒÔʹÕâ¸ö¹ý³Ì¸üÈÝÒס£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.spring-graphql)7.3.12\. Spring GraphQL Ö¸±ê
+
+
+
+²Î¼û [Spring GraphQL ²Î¿¼Îĵµ](https://docs.spring.io/spring-graphql/docs/1.1.2/reference/html/)¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.jdbc)7.3.13\. DataSource Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖÃʹËùÓпÉÓÃµÄ `DataSource` ¶ÔÏóµÄÒÇÆ÷»¯£¬Ö¸±êǰ׺Ϊ `jdbc.connections`¡£ Êý¾ÝÔ´¼ì²âµÄ½á¹ûÊDZíʾ³ØÖе±Ç°»î¶¯µÄ¡¢¿ÕÏеġ¢×î´óÔÊÐíµÄºÍ×îСÔÊÐíµÄÁ¬½ÓÊýµÄÒÇ±í¡£
+
+
+
+
+
+ºâÁ¿±ê×¼Ò²ÓÉ»ùÓÚbeanÃû³Æ¼ÆËãµÄ `DataSource` µÄÃû³ÆÀ´±ê¼Ç¡£
+
+
+
+
+
+| | ĬÈÏÇé¿öÏ£¬Spring BootΪËùÓÐÖ§³ÖµÄÊý¾ÝÔ´ÌṩԪÊý¾Ý¡£ Èç¹ûÄãϲ»¶µÄÊý¾ÝÔ´²»±»Ö§³Ö£¬Äã¿ÉÒÔÌí¼Ó¶îÍâµÄ `DataSourcePoolMetadataProvider` Bean¡£ Çë²ÎÔÄ `DataSourcePoolMetadataProvidersConfiguration` ÒÔÁ˽âʵÀý¡£ |
+| --- | --- |
+
+
+
+
+
+´ËÍ⣬HikariÌØ¶¨µÄÖ¸±êÒÔ `hikaricp` ǰ׺±©Â¶¡£ ÿ¸öÖ¸±ê¶¼±»poolµÄÃû×ÖËù±ê¼Ç£¨Äã¿ÉÒÔÓà `spring.datasource.name` À´¿ØÖÆ£©¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.hibernate)7.3.14\. Hibernate Ö¸±ê
+
+
+
+Èç¹û `org.hibernate.orm:hibernate-micrometer` ÔÚclasspathÉÏ£¬ËùÓÐÆôÓÃÁËͳ¼Æ¹¦ÄܵÄHibernate `EntityManagerFactory` ʵÀý¶¼»á±»Ò»¸öÃûΪ `hibernate` µÄÖ¸±êËù¼ì²â¡£
+
+
+
+
+
+ºâÁ¿±ê×¼Ò²ÓÉ `EntityManagerFactory` µÄÃû³ÆÀ´±ê¼Ç£¬¸ÃÃû³ÆÊÇÓÉBeanÃû³ÆÅÉÉúµÄ¡£
+
+
+
+
+
+ÒªÆôÓÃͳ¼Æ£¬±ê×¼JPAÊôÐÔ `hibernate.generate_statistics` ±ØÐëÉèÖÃΪ `true`¡£ Äã¿ÉÒÔÔÚ×Ô¶¯ÅäÖÃµÄ `EntityManagerFactory` ÉÏÆôÓá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+spring.jpa.properties[hibernate.generate_statistics]=true
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.spring-data-repository)7.3.15\. Spring Data Repository Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖÃÄܹ»¶ÔËùÓÐSpring Data `Repository` ·½·¨µÄµ÷ÓýøÐжÈÁ¿¡£ ĬÈÏÇé¿öÏ£¬Ö¸±êÒÔ `spring.data.repository.invocations` ΪÃûÉú³É¡£ Äã¿ÉÒÔͨ¹ýÉèÖà `management.metrics.data.repository.metric-name` ÊôÐÔÀ´×Ô¶¨ÒåÃû³Æ¡£
+
+
+
+
+
+`io.micrometer.core.annotation` °üÖÐµÄ `@Timed` ×¢½âÖ§³Ö `Repository` ½Ó¿ÚºÍ·½·¨¡£Èç¹ûÄã²»Ïë¼Ç¼ËùÓÐ `Repository` µ÷ÓõĶÈÁ¿£¨metric£©£¬Äã¿ÉÒÔ½« `management.metrics.data.repository.autotime.enabled` ÉèÖÃΪ `false`£¬¶ø×¨ÃÅʹÓà `@Timed` ×¢½â¡£
+
+
+
+
+
+| | Ò»¸ö´øÓÐ `longTask = true` µÄ `@Timed` ×¢½â¿ÉÒÔΪ¸Ã·½·¨ÆôÓÃÒ»¸ö³¤ÈÎÎñ¼ÆÊ±Æ÷¡£³¤ÈÎÎñ¶¨Ê±Æ÷ÐèÒªÒ»¸öµ¥¶ÀµÄ metric name£¬²¢ÇÒ¿ÉÒÔÓë¶ÌÈÎÎñ¶¨Ê±Æ÷£¨task timer£©µþ¼Ó¡£ |
+| --- | --- |
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬repositoryµ÷ÓÃÏà¹ØµÄ¶ÈÁ¿±ê×¼±»±ê¼ÇΪÒÔÏÂÐÅÏ¢¡£
+
+
+
+
+| Tag | ˵Ã÷ |
+| --- | --- |
+| `repository` | Ô´ `Repository` µÄ¼òµ¥ÀàÃû¡£ |
+| `method` | ±»µ÷ÓÃµÄ `Repository` ·½·¨µÄÃû³Æ¡£ |
+| `state` | ½á¹û״̬£¨`SUCCESS`, `ERROR`, `CANCELED`, `RUNNING`£©¡£ |
+| `exception` | µ÷ÓÃÖÐÅ׳öµÄÈκÎÒì³£µÄ¼òµ¥ÀàÃû¡£ |
+
+
+
+ÒªÌæ»»Ä¬ÈϱêÇ©£¬ÐèÒªÌṩһ¸öʵÏÖÁË `RepositoryTagsProvider` µÄ `@Bean`¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.rabbitmq)7.3.16\. RabbitMQ Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖÃʹËùÓпÉÓÃµÄ RabbitMQ Á¬½Ó¹¤³§µÄÒÇÆ÷»¯£¬ÆäÖ¸±êÃûΪ `rabbitmq`¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.spring-integration)7.3.17\. Spring Integration Ö¸±ê
+
+
+
+Ö»ÒªÓÐ `MeterRegistry` bean£¬Spring Integration¾Í»á×Ô¶¯Ìṩ [Micrometer support](https://docs.spring.io/spring-integration/docs/6.1.0-M1/reference/html/system-management.html#micrometer-integration)¡£ ¶ÈÁ¿±ê×¼ÔÚ `spring.integration.` meter Ãû³ÆÏ·¢²¼¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.kafka)7.3.18\. Kafka Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖÃΪ×Ô¶¯ÅäÖõÄÏû·ÑÕß¹¤³§ºÍÉú²úÕß¹¤³§·Ö±ð×¢²áÁËÒ»¸ö `MicrometerConsumerListener` ºÍ `MicrometerProducerListener`¡£ Ëü»¹Îª `StreamsBuilderFactoryBean` ×¢²áÁËÒ»¸ö `KafkaStreamsMicrometerListener`¡£ ¸ü¶àϸ½Ú£¬Çë²ÎÔÄSpring KafkaÎĵµÖÐµÄ [Micrometer Native Metrics](https://docs.spring.io/spring-kafka/docs/3.0.3/reference/html/#micrometer-native) ²¿·Ö¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.mongodb)7.3.19\. MongoDB Ö¸±ê
+
+
+
+±¾½Ú¼òÒª½éÉÜMongoDBµÄ¿ÉÓöÈÁ¿¡£
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.mongodb.command)MongoDBÃüÁîÖ¸±ê
+
+
+
+×Ô¶¯ÅäÖý« `MongoMetricsCommandListener` Óë×Ô¶¯ÅäÖÃµÄ `MongoClient` ×¢²á¡£
+
+
+
+
+
+Ò»¸öÃûΪ `mongodb.driver.commands` µÄtimerÖ¸±ê±»´´½¨£¬ÓÃÓÚÏòµ×²ãMongoDB driver·¢³öµÄÿÌõÃüÁî¡£ ĬÈÏÇé¿öÏ£¬Ã¿¸öÖ¸±ê¶¼±»±ê¼ÇΪÒÔÏÂÐÅÏ¢¡£
+
+
+
+
+| Tag | ˵Ã÷ |
+| --- | --- |
+| `command` | ·¢³öµÄÃüÁîµÄÃû³Æ¡£ |
+| `cluster.id` | ·¢Ë͸ÃÃüÁîµÄ¼¯ÈºµÄ±êʶ·û¡£ |
+| `server.address` | ·¢ËÍÃüÁîµÄ·þÎñÆ÷µÄµØÖ·¡£ |
+| `status` | ÃüÁîµÄ½á¹û£¨`SUCCESS` »ò `FAILED£©¡£ |
+
+
+
+ΪÁËÌæ»»Ä¬ÈϵĶÈÁ¿ºâ±êÇ©£¬¶¨ÒåÒ»¸ö `MongoCommandTagsProvider` bean£¬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Configuration(proxyBeanMethods = false)
+public class MyCommandTagsProviderConfiguration {
+
+ @Bean
+ public MongoCommandTagsProvider customCommandTagsProvider() {
+ return new CustomCommandTagsProvider();
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+Òª½ûÓÃ×Ô¶¯ÅäÖõÄÃüÁî¶ÈÁ¿£¬ÇëÉèÖÃÒÔÏÂÊôÐÔ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.metrics.mongo.command.enabled=false
+
+```
+
+
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.mongodb.connection-pool)MongoDB Á¬½Ó³ØÖ¸±ê
+
+
+
+×Ô¶¯ÅäÖý« `MongoMetricsConnectionPoolListener` Óë×Ô¶¯ÅäÖÃµÄ `MongoClient` ×¢²á¡£
+
+
+
+
+
+ÒÔÏÂÊÇΪÁ¬½Ó³Ø´´½¨µÄ²âÁ¿Ö¸±ê¡£
+
+
+
+
+
+* `mongodb.driver.pool.size` ±¨¸æÁ¬½Ó³ØµÄµ±Ç°´óС£¬°üÀ¨¿ÕÏкÍÕýÔÚʹÓõijÉÔ±¡£
+
+* `mongodb.driver.pool.checkedout` ±¨¸æµ±Ç°Ê¹ÓÃÖеÄÁ¬½ÓÊý¡£
+
+* `mongodb.driver.pool.waitqueuesize` ±¨¸æ³ØÖÐÁ¬½ÓµÄµÈ´ý¶ÓÁеĵ±Ç°´óС¡£
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬Ã¿¸öÖ¸±ê¶¼±»±ê¼ÇΪÒÔÏÂÐÅÏ¢¡£
+
+
+
+
+| Tag | ˵Ã÷ |
+| --- | --- |
+| `cluster.id` | Á¬½Ó³ØËù¶ÔÓ¦µÄ¼¯ÈºµÄ±êʶ·û¡£ |
+| `server.address` | Á¬½Ó³ØËù¶ÔÓ¦µÄ·þÎñÆ÷µÄµØÖ·¡£ |
+
+
+
+Ҫȡ´úĬÈϵĶÈÁ¿ºâ±êÇ©£¬Ç붨ÒåÒ»¸ö `MongoConnectionPoolTagsProvider` bean¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Configuration(proxyBeanMethods = false)
+public class MyConnectionPoolTagsProviderConfiguration {
+
+ @Bean
+ public MongoConnectionPoolTagsProvider customConnectionPoolTagsProvider() {
+ return new CustomConnectionPoolTagsProvider();
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+Òª½ûÓÃ×Ô¶¯ÅäÖõÄÁ¬½Ó³Ø¶ÈÁ¿£¬ÇëÉèÖÃÒÔÏÂÊôÐÔ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.metrics.mongo.connectionpool.enabled=false
+
+```
+
+
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.jetty)7.3.20\. Jetty Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖÃͨ¹ýʹÓÃMicrometerµÄ `JettyServerThreadPoolMetrics` ΪJettyµÄ `ThreadPool` °ó¶¨Ö¸±ê¡£ JettyµÄ `Connector` ʵÀýµÄÖ¸±êͨ¹ýʹÓÃMicrometerµÄ `JettyConnectionMetrics` À´°ó¶¨£¬µ± `server.ssl.enabled` ±»ÉèÖÃΪ `true` ʱ£¬MicrometerµÄ `JettySslHandshakeMetrics`¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.timed-annotation)7.3.21\. @Timed ×¢½âµÄÖ§³Ö
+
+
+
+ÒªÔÚSpring Boot²»Ö±½ÓÖ§³ÖµÄµØ·½Ê¹Óà `@Timed`£¬Çë²Î¿¼ [Micrometer Îĵµ](https://micrometer.io/docs/concepts#_the_timed_annotation)¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.redis)7.3.22\. Redis Ö¸±ê
+
+
+
+×Ô¶¯ÅäÖÃΪ×Ô¶¯ÅäÖÃµÄ `LettuceConnectionFactory` ×¢²áÁËÒ»¸ö `MicrometerCommandLatencyRecorder`¡£ ¸ü¶àϸ½Ú£¬Çë²ÎÔÄLettuceÎĵµµÄ [Micrometer Metrics²¿·Ö](https://lettuce.io/core/6.2.3.RELEASE/reference/index.html#command.latency.metrics.micrometer)¡£
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.registering-custom)7.4\. ×¢²á×Ô¶¨ÒåÖ¸±ê
+
+
+
+Ҫע²á×Ô¶¨Òå¶ÈÁ¿£¬Ç뽫 `MeterRegistry` ×¢ÈëÄãµÄ×é¼þÖС£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Component
+public class MyBean {
+
+ private final Dictionary dictionary;
+
+ public MyBean(MeterRegistry registry) {
+ this.dictionary = Dictionary.load();
+ registry.gauge("dictionary.size", Tags.empty(), this.dictionary.getWords().size());
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+Èç¹ûÄãµÄ¶ÈÁ¿±ê×¼ÒÀÀµÓÚÆäËûBean£¬ÎÒÃǽ¨ÒéÄãʹÓà `MeterBinder` À´×¢²áËüÃÇ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+public class MyMeterBinderConfiguration {
+
+ @Bean
+ public MeterBinder queueSize(Queue queue) {
+ return (registry) -> Gauge.builder("queueSize", queue::size).register(registry);
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+ʹÓà `MeterBinder` ¿ÉÒÔÈ·±£½¨Á¢ÕýÈ·µÄÒÀÀµ¹ØÏµ£¬²¢ÇÒÔÚ¼ìË÷¶ÈÁ¿ÖµµÄʱºò£¬BeanÊÇ¿ÉÓõġ£ Èç¹ûÄã·¢ÏÖÄãÔÚ×é¼þ»òÓ¦ÓóÌÐòÖÐÖØ¸´²âÁ¿Ò»Ì×Ö¸±ê£¬ÄÇô `MeterBinder` µÄʵÏÖÒ²»áºÜÓÐÓá£
+
+
+
+
+
+| | ĬÈÏÇé¿öÏ£¬ËùÓÐ `MeterBinder` BeanµÄÖ¸±ê¶¼»á×Ô¶¯°ó¶¨µ½Spring¹ÜÀíµÄ `MeterRegistry`¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.customizing)7.5\. ¶¨ÖƸö±ðÖ¸±ê
+
+
+
+Èç¹ûÄãÐèÒª¶ÔÌØ¶¨µÄ `Meter` ʵÀý½øÐÐ×Ô¶¨Ò壬Äã¿ÉÒÔʹÓà `io.micrometer.core.instrument.config.MeterFilter` ½Ó¿Ú¡£
+
+
+
+
+
+ÀýÈ磬Èç¹ûÄãÏë°ÑËùÓÐÒÔ `com.example` ¿ªÍ·µÄÒDZíIDµÄ `mytag.region` ±êÇ©ÖØÃüÃûΪ `mytag.area`£¬Äã¿ÉÒÔ×öÒÔϹ¤×÷¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Configuration(proxyBeanMethods = false)
+public class MyMetricsFilterConfiguration {
+
+ @Bean
+ public MeterFilter renameRegionTagMeterFilter() {
+ return MeterFilter.renameTag("com.example", "mytag.region", "mytag.area");
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+| | ĬÈÏÇé¿öÏ£¬ËùÓÐµÄ `MeterFilter` Bean¶¼×Ô¶¯°ó¶¨µ½Spring¹ÜÀíµÄ `MeterRegistry`¡£ ÇëÈ·±£Ê¹ÓÃSpring¹ÜÀíµÄ `MeterRegistry` À´×¢²áÄãµÄÖ¸±ê£¬¶ø²»ÊÇʹÓà `Metrics` µÄÈκξ²Ì¬·½·¨¡£ ÕâЩ·½·¨Ê¹ÓõÄÊDz»±»Spring¹ÜÀíµÄÈ«¾Ö×¢²á±í¡£ |
+| --- | --- |
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.customizing.common-tags)7.5.1\. ³£¼û±êÇ©£¨Tag£©
+
+
+
+ͨÓñêǩһ°ãÓÃÓÚ¶ÔÔËÐл·¾³½øÐÐά¶ÈÏÂ×꣬ÈçÖ÷»ú¡¢ÊµÀý¡¢ÇøÓò¡¢¶ÑÕ»µÈ¡£ ¹²ÓñêÇ©ÊÊÓÃÓÚËùÓÐÒÇ±í£¬¿ÉÒÔ½øÐÐÅäÖã¬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.metrics.tags.region=us-east-1
+management.metrics.tags.stack=prod
+
+```
+
+
+
+
+
+
+
+Ç°ÃæµÄÀý×ÓΪËùÓÐֵΪ `us-east-1` ºÍ `prod` µÄÒDZíÌí¼ÓÁË `region` ºÍ `stack` ±êÇ©¡£
+
+
+
+
+
+| | Èç¹ûÄãʹÓÃGraphite£¬ÆÕͨ±êÇ©µÄ˳ÐòÊǺÜÖØÒªµÄ¡£ ÓÉÓÚʹÓÃÕâÖÖ·½·¨²»Äܱ£Ö¤³£¼û±êÇ©µÄ˳Ðò£¬½¨ÒéGraphiteÓû§¶¨ÒåÒ»¸ö×Ô¶¨ÒåµÄ `MeterFilter` À´´úÌæ¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.customizing.per-meter-properties)7.5.2\. Per-meter Properties
+
+
+
+³ýÁË `MeterFilter` Bean£¬Ä㻹¿ÉÒÔʹÓÃÊôÐÔÔÚÿ¸ö±íµÄ»ù´¡ÉÏÓ¦ÓÃÒ»×éÓÐÏÞµÄ×Ô¶¨Ò幦ÄÜ¡£ ʹÓÃSpring BootµÄ `PropertiesMeterFilter`£¬Ã¿¸ö±íµÄ¶¨ÖƱ»Ó¦ÓÃÓÚÒÔ¸ø¶¨Ãû³Æ¿ªÍ·µÄÈκαíµÄID¡£ ÏÂÃæµÄÀý×Ó¹ýÂ˵ôÈκÎIDÒÔ `example.remote` ¿ªÍ·µÄÒÇ±í¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.metrics.enable.example.remote=false
+
+```
+
+
+
+
+
+
+
+ÏÂÃæµÄÊôÐÔÔÊÐíper-meterµÄ¶¨ÖÆ¡£
+
+
+
+Table 1\. Per-meter customizations
+| Property | ˵Ã÷ |
+| --- | --- |
+| `management.metrics.enable` | ÊÇ·ñ½ÓÊܾßÓÐÌØ¶¨IDµÄMeter¡£ ²»½ÓÊܵÄMeter½«´Ó `MeterRegistry` ÖйýÂ˵ô¡£ |
+| `management.metrics.distribution.percentiles-histogram` | ÊÇ·ñ·¢²¼ÊʺϼÆËã¿É¾Û¼¯£¨¿çά¶È£©µÄ°Ù·ÖλÊý½üËÆÖµµÄÖ±·½Í¼¡£ |
+| `management.metrics.distribution.minimum-expected-value`, `management.metrics.distribution.maximum-expected-value` | ͨ¹ýÇ¯ÖÆÔ¤ÆÚÖµµÄ·¶Î§£¬·¢²¼¸üÉÙµÄÖ±·½Í¼Í°¡£ |
+| `management.metrics.distribution.percentiles` | ·¢²¼ÔÚÄãµÄÓ¦ÓóÌÐòÖмÆËãµÄ°Ù·Öλֵ |
+| `management.metrics.distribution.expiry`, `management.metrics.distribution.buffer-length` | ͨ¹ýÔÚ»·Ðλº³åÇøÖлýÀÛ×î½üµÄÑù±¾£¬¸øËüÃǸü´óµÄÈ¨ÖØ£¬»·Ðλº³åÇøÔÚ¿ÉÅäÖõĹýÆÚºóÐýת£¬»º³åÇø³¤¶ÈΪ ¿ÉÅäÖõĻº³åÇø³¤¶È¡£ |
+| `management.metrics.distribution.slo` | ·¢²¼Ò»¸öÀÛ»ýÖ±·½Í¼£¬ÆäÖеÄͰÓÉÄãµÄ·þÎñˮƽĿ±ê¶¨Òå¡£ |
+
+
+
+¹ØÓÚ `percentiles-histogram` £¨°Ù·ÖÊý-Ö±·½Í¼£©¡¢`percentiles`£¨°Ù·ÖÊý£©ºÍ `slo` ±³ºóµÄ¸ÅÄîµÄ¸ü¶àϸ½Ú£¬Çë²Î¼ûMicrometerÎĵµÖÐµÄ [¡°Histograms and percentiles¡± £¨Ö±·½Í¼ºÍ°Ù·ÖÊý£©²¿·Ö](https://micrometer.io/docs/concepts#_histograms_and_percentiles)¡£
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.endpoint)7.6\. Ö¸±ê¶Ëµã
+
+
+
+Spring BootÌṩÁËÒ»¸ö `metrics` ¶Ëµã£¬Äã¿ÉÒÔÕï¶ÏÐÔµØÊ¹ÓÃËüÀ´¼ì²éÓ¦ÓóÌÐòÊÕ¼¯µÄÖ¸±ê¡£¸Ã¶ËµãĬÈÏÇé¿öÏÂÊDz»¿ÉÓõ쬱ØÐ빫¿ª¡£¸ü¶àϸ½ÚÇë²Î¼û [±©Â¶¶Ëµã](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.exposing)¡£
+
+
+
+
+
+µ¼º½µ½ `/actuator/metrics` »áÏÔʾһ¸ö¿ÉÓõÄÒDZíÃû³ÆÁÐ±í¡£ Äã¿ÉÒÔͨ¹ýÌṩÃû³Æ×÷ΪѡÔñÆ÷À´ÉîÈë²é¿´Ä³¸öÌØ¶¨ÒDZíµÄÐÅÏ¢£¬ÀýÈ磬`/actuator/metrics/jvm.memory.max`¡£
+
+
+
+
+
+| | ÄãÔÚÕâÀïʹÓõÄÃû×ÖÓ¦¸ÃÓë´úÂëÖÐʹÓõÄÃû×ÖÒ»Ö£¬¶ø²»ÊÇÔÚËü±»ÔËÍùµÄ¼à¿ØÏµÍ³Öо¹ýÃüÃû¹ßÀý¹æ·¶»¯ºóµÄÃû×Ö¡£ »»¾ä»°Ëµ£¬Èç¹û `jvm.memory.max` ÔÚPrometheusÖÐÏÔʾΪ `jvm_memory_max`£¬ÒòΪËüµÄÉßÐÎÃüÃû¹ßÀý£¬ÄãÈÔȻӦ¸ÃʹÓà `jvm.memory.max` ×÷ΪѡÔñÆ÷£¬ÔÚ `metrics` ¶ËµãÖмì²éÒÇ±í¡£ |
+| --- | --- |
+
+
+
+
+
+ÄãÒ²¿ÉÒÔÔÚURLµÄĩβÌí¼ÓÈÎÒâÊýÁ¿µÄ `tag=KEY:VALUE` ²éѯ²ÎÊý£¬ÒÔ¶ÔÒÇ±í½øÐÐά¶ÈÏÂ×ê?¡ª?ÀýÈ磬`/actuator/metrics/jvm.memory.max?tag=area:nonheap`¡£
+
+
+
+
+
+| | ±¨¸æµÄ²âÁ¿ÖµÊÇËùÓÐÓëÒDZíÃû³ÆÏàÆ¥ÅäµÄÒDZíºÍÈκÎÒÑÓ¦ÓõıêÇ©µÄͳ¼ÆÁ¿µÄ _×ܺÍ_¡£ ÔÚÇ°ÃæµÄÀý×ÓÖУ¬·µ»ØµÄ `Value` ͳ¼ÆÊÇ¶ÑµÄ ¡°Code Cache¡±¡¢¡°Compressed Class Space¡± ºÍ ¡°Metaspace¡± ÇøÓòµÄ×î´óÄÚ´æ¡°×ã¼£¡±Ö®ºÍ¡£ Èç¹ûÄãÏëÖ»¿´µ½ ¡°Metaspace¡± µÄ×î´ó³ß´ç£¬Äã¿ÉÒÔÌí¼ÓÒ»¸ö¶îÍâµÄ `tag=id:Metaspace` --¼´ `/actuator/metrics/jvm.memory.max?tag=area:nonheap&tag=id:Metaspace`¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.micrometer-observation)7.7\. ÕûºÏ Micrometer Observation
+
+
+
+Ò»¸ö `DefaultMeterObservationHandler` ±»×Ô¶¯×¢²áÔÚ `ObservationRegistry` ÉÏ£¬ËüΪÿ¸öÍê³ÉµÄ¹Û²ì£¨completed observation£©´´½¨¶ÈÁ¿£¨metric£©¡£
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.micrometer-tracing)8\. ×·×Ù£¨Tracing£©
+
+
+
+
+
+Spring Boot Actuator Ϊ Micrometer Tracing ÌṩÁËÒÀÀµÐÔ¹ÜÀíºÍ×Ô¶¯ÅäÖ㬠[Micrometer Tracing](https://micrometer.io/docs/tracing) ÊÇÁ÷ÐеÄ×·×ÙÆ÷£¨tracer£©¿âµÄÒ»¸ö½Ó¿Ú£¨facade£©¡£
+
+
+
+
+
+| | ÒªÁ˽â¸ü¶à¹ØÓÚ Micrometer Tracing ¹¦ÄܵÄÐÅÏ¢£¬Çë²ÎÔÄÆä [²Î¿¼Îĵµ](https://micrometer.io/docs/tracing)¡£ |
+| --- | --- |
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.micrometer-tracing.tracers)8.1\. Ö§³ÖµÄ×·×ÙÆ÷
+
+
+
+Spring BootΪÒÔÏÂ×·×ÙÆ÷ÌṩÁË×Ô¶¯ÅäÖá£
+
+
+
+
+
+* ʹÓà [Zipkin](https://zipkin.io/) »ò [Wavefront](https://docs.wavefront.com/) µÄ [OpenTelemetry](https://opentelemetry.io/)
+
+* ʹÓà [Zipkin](https://zipkin.io/) »ò [Wavefront](https://docs.wavefront.com/) µÄ [OpenZipkin Brave](https://github.com/openzipkin/brave)
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.micrometer-tracing.getting-started)8.2\. ÈëÃÅ
+
+
+
+ÎÒÃÇÐèÒªÒ»¸ö¿ÉÒÔÓÃÀ´¿ªÊ¼×·×ÙµÄʾÀýÓ¦ÓóÌÐò¡£¾ÍÎÒÃǵÄÄ¿µÄ¶øÑÔ£¬¡°[getting-started.html](https://springdoc.cn/spring-boot/getting-started.html#getting-started.first-application)¡± ²¿·ÖËùÉæ¼°µÄ¼òµ¥µÄ ¡°Hello World!¡± web³ÌÐò¾Í×ã¹»ÁË¡£ÎÒÃǽ«Ê¹Óà `OpenTelemetry` ×·×ÙÆ÷ºÍ `Zipkin` ×÷Ϊ׷×Ùºó¶Ë¡£
+
+
+
+
+
+»Ø¹Ëһϣ¬ÎÒÃǵÄÖ÷ÒªÓ¦ÓôúÂë¿´ÆðÀ´ÊÇÕâÑùµÄ¡£
+
+
+
+
+
+
+
+```
+@RestController
+@SpringBootApplication
+public class MyApplication {
+
+ private static final Log logger = LogFactory.getLog(MyApplication.class);
+
+ @RequestMapping("/")
+ String home() {
+ logger.info("home() has been called");
+ return "Hello World!";
+ }
+
+ public static void main(String[] args) {
+ SpringApplication.run(MyApplication.class, args);
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+| | ÔÚ `home()` ·½·¨ÖУ¬ÓÐÒ»¸ö¸½¼ÓµÄloggerÓï¾ä£¬ÕâÔÚºóÃæ»áºÜÖØÒª¡£ |
+| --- | --- |
+
+
+
+
+
+ÏÖÔÚ£¬ÎÒÃDZØÐëÌí¼ÓÒÔÏÂÒÀÀµÏî¡£
+
+
+
+
+
+* `org.springframework.boot:spring-boot-starter-actuator`
+
+* `io.micrometer:micrometer-tracing-bridge-otel` - ÕâÊÇÁ¬½Ó Micrometer Observation API ºÍ OpenTelemetry µÄ±ØÒªÌõ¼þ¡£
+
+* `io.opentelemetry:opentelemetry-exporter-zipkin` - ÕâÊÇÏòZipkin±¨¸æ [traces](https://micrometer.io/docs/tracing#_glossary) ËùÐèÒªµÄ¡£
+
+
+
+
+
+Ìí¼ÓÈçÏ嵀 application properties:
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.tracing.sampling.probability=1.0
+
+```
+
+
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬Spring BootÖ»¶Ô10%µÄÇëÇó½øÐвÉÑù£¬ÒÔ·ÀÖ¹×·×Ùºó¶Ë²»¿°Öظº¡£´ËÊôÐÔ½«ÆäÇл»Îª100%£¬ÕâÑùÿ¸öÇëÇ󶼻ᱻ·¢Ë͵½¸ú×Ùºó¶Ë¡£
+
+
+
+
+
+ΪÁËÊÕ¼¯ºÍ¿ÉÊÓ»¯¸ú×Ù£¬ÎÒÃÇÐèÒªÒ»¸öÔËÐиú×ٵĺó¶Ë¡£ÎÒÃÇÔÚÕâÀïʹÓÃZipkin×÷ΪÎÒÃǵĸú×Ùºó¶Ë¡£ [Zipkin¿ìËÙÈëÃÅÖ¸ÄÏ](https://zipkin.io/pages/quickstart) ÌṩÁËÈçºÎÔÚ±¾µØÆô¶¯ZipkinµÄ˵Ã÷¡£
+
+
+
+
+
+ZipkinÔËÐкó£¬Äã¿ÉÒÔÆô¶¯ÄãµÄÓ¦ÓóÌÐò¡£
+
+
+
+
+
+Èç¹ûÄã´ò¿ªwebä¯ÀÀÆ÷·ÃÎÊ `[localhost:8080](http://localhost:8080/)`£¬ÄãÓ¦¸Ã¿´µ½ÒÔÏÂÊä³ö¡£
+
+
+
+
+
+
+
+ Hello World!
+
+
+
+
+
+
+
+ÔÚÄ»ºó£¬ÒѾΪHTTPÇëÇó´´½¨ÁËÒ»¸ö observation£¬Ëü·´¹ýÀ´±»ÇŽӵ½ `OpenTelemetry`£¬ºóÕßÏòZipkin±¨¸æÒ»¸öеĸú×Ù£¨trace£©¡£
+
+
+
+
+
+ÏÖÔÚ£¬ÔÚ `[localhost:9411](http://localhost:9411/)` ´ò¿ªZipkinÓû§½çÃæ£¬µã»÷ "Run Query" °´Å¥£¬ÁгöËùÓÐÊÕ¼¯µ½µÄ¸ú×ÙÐÅÏ¢¡£ÄãÓ¦¸Ã¿´µ½Ò»¸ö×·×Ù¡£µã»÷ "Show" °´Å¥£¬²é¿´¸Ã×·×ÙµÄϸ½Ú¡£
+
+
+
+
+
+| | Äã¿ÉÒÔͨ¹ý½« `logging.pattern.level` ÊôÐÔÉèÖÃΪ `%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]`£¬ÔÚÈÕÖ¾Öаüº¬µ±Ç°µÄ¸ú×Ù£¨trace£©ºÍ span id¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.micrometer-tracing.tracer-implementations)8.3\. ¸ú×ÙÆ÷£¨Tracer£©µÄʵÏÖ
+
+
+
+ÓÉÓÚMicrometer TracerÖ§³Ö¶àÖÖʾ×ÙÆ÷µÄʵÏÖ£¬Òò´ËSpring Boot¿ÉÄÜÓжàÖÖÒÀÀµ×éºÏ¡£
+
+
+
+
+
+ËùÓÐ×·×ÙÆ÷µÄʵÏÖ¶¼ÐèÒª `org.springframework.boot:spring-boot-starter-actuator` ÒÀÀµ¡£
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.micrometer-tracing.tracer-implementations.otel-zipkin)8.3.1\. ʹÓà Zipkin µÄ OpenTelemetry
+
+
+
+* `io.micrometer:micrometer-tracing-bridge-otel` - ÕâÊÇÁ¬½Ó Micrometer Observation API ºÍ OpenTelemetry µÄ±ØÒªÌõ¼þ¡£
+
+* `io.opentelemetry:opentelemetry-exporter-zipkin` - ÕâÊÇÏòZipkin±¨¸ætraceËùÐèÒªµÄ¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.micrometer-tracing.tracer-implementations.otel-wavefront)8.3.2\. ʹÓà Wavefront µÄ OpenTelemetry
+
+
+
+* `io.micrometer:micrometer-tracing-bridge-otel` - ÕâÊÇÁ¬½Ó Micrometer Observation API ºÍ OpenTelemetry µÄ±ØÒªÌõ¼þ¡£
+
+* `io.micrometer:micrometer-tracing-reporter-wavefront` - ÕâÊÇÏòWavefront±¨¸ætraceËùÐèÒªµÄ¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.micrometer-tracing.tracer-implementations.brave-zipkin)8.3.3\. ʹÓà Zipkin µÄ OpenZipkin Brave
+
+
+
+* `io.micrometer:micrometer-tracing-bridge-brave` - ÕâÊÇÁ¬½Ó Micrometer Observation API ºÍ Brave µÄ±ØÒªÌõ¼þ¡£
+
+* `io.zipkin.reporter2:zipkin-reporter-brave` - ÕâÊÇÏòZipkin±¨¸æ trace ËùÐèÒªµÄ¡£
+
+
+
+
+
+| | Èç¹ûÄãµÄÏîĿûÓÐʹÓÃSpring MVC»òSpring WebFlux£¬Ò²ÐèҪʹÓà `io.zipkin.reporter2:zipkin-sender-urlconnection` ÒÀÀµÏî¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.micrometer-tracing.tracer-implementations.brave-wavefront)8.3.4\. ʹÓÃWavefrontµÄOpenZipkin Brave
+
+
+
+* `io.micrometer:micrometer-tracing-bridge-brave` - ÕâÊÇÁ¬½Ó²âMicrometer Observation APIºÍBraveµÄ±ØÒªÌõ¼þ¡£
+
+* `io.micrometer:micrometer-tracing-reporter-wavefront` - ÕâÊÇÏòWavefront±¨¸ætraceËùÐèÒªµÄ¡£
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.micrometer-tracing.creating-spans)8.4\. ´´½¨×Ô¶¨Òå¿ç¶È£¨span£©
+
+
+
+Äã¿ÉÒÔͨ¹ýÆô¶¯Ò»¸ö observation À´´´½¨Äã×Ô¼ºµÄspan¡£Îª´Ë£¬½« `ObservationRegistry` ×¢Èëµ½ÄãµÄ×é¼þÖС£
+
+
+
+
+
+
+
+```
+@Component
+class CustomObservation {
+
+ private final ObservationRegistry observationRegistry;
+
+ CustomObservation(ObservationRegistry observationRegistry) {
+ this.observationRegistry = observationRegistry;
+ }
+
+ void someOperation() {
+ Observation observation = Observation.createNotStarted("some-operation", this.observationRegistry);
+ observation.lowCardinalityKeyValue("some-tag", "some-value");
+ observation.observe(() -> {
+ // Business logic ...
+ });
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+Õ⽫´´½¨Ò»¸öÃûΪ "some-operation" µÄ observation£¬±êǩΪ£¬±êǩΪ "some-tag=some-value"¡£
+
+
+
+
+
+| | Èç¹ûÄãÏëÔÚ²»´´½¨metricµÄÇé¿öÏ´´½¨Ò»¸öspan£¬ÄãÐèҪʹÓà Micrometer µÄ [µÍ¼¶Tracer API](https://micrometer.io/docs/tracing#_using_micrometer_tracing_directly)¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.auditing)9\. Éó¼Æ
+
+
+
+
+
+Ò»µ©Spring Security·¢»Ó×÷Óã¬Spring Boot Actuator¾ÍÓÐÒ»¸öÁé»îµÄÉó¼Æ¿ò¼Ü£¬¿ÉÒÔ·¢²¼Ê¼þ£¨Ä¬ÈÏΪ ¡°authentication success¡±, ¡°failure¡± ºÍ ¡°access denied¡± µÄÒì³££©¡£ ÕâÒ»¹¦ÄܶÔÓÚ±¨¸æºÍʵʩ»ùÓÚÈÏ֤ʧ°ÜµÄËø¶¨²ßÂԷdz£ÓÐÓá£
+
+
+
+
+
+Äã¿ÉÒÔͨ¹ýÔÚÓ¦ÓóÌÐòµÄÅäÖÃÖÐÌṩһ¸ö `AuditEventRepository` ÀàÐ͵ÄbeanÀ´ÆôÓÃÉ󼯡£ ΪÁË·½±ã£¬Spring BootÌṩÁËÒ»¸ö `InMemoryAuditEventRepository`¡£ `InMemoryAuditEventRepository` µÄ¹¦ÄÜÓÐÏÞ£¬ÎÒÃǽ¨ÒéÖ»ÔÚ¿ª·¢»·¾³ÖÐʹÓÃËü¡£ ¶ÔÓÚÉú²ú»·¾³£¬Ç뿼ÂÇ´´½¨Äã×Ô¼ºµÄÌæ´ú `AuditEventRepository` ʵÏÖ¡£
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.auditing.custom)9.1\. ¶¨ÖÆÉó¼Æ
+
+
+
+ΪÁ˶¨ÖÆ·¢²¼µÄ°²È«Ê¼þ£¬Äã¿ÉÒÔÌṩÄã×Ô¼ºµÄ `AbstractAuthenticationAuditListener` ºÍ `AbstractAuthorizationAuditListener` µÄʵÏÖ¡£
+
+
+
+
+
+ÄãÒ²¿ÉÒÔΪÄã×Ô¼ºµÄÒµÎñʼþʹÓÃÉ󼯷þÎñ¡£ Òª×öµ½ÕâÒ»µã£¬ÒªÃ´½« `AuditEventRepository` bean×¢ÈëÄã×Ô¼ºµÄ×é¼þ²¢Ö±½ÓʹÓÃËü£¬ÒªÃ´ÓÃSpringµÄ `ApplicationEventPublisher` ·¢²¼ `AuditApplicationEvent`£¨Í¨¹ýʵÏÖ `ApplicationEventPublisherAware`£©¡£
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.http-exchanges)10\. ¼Ç¼ HTTP Exchange
+
+
+
+
+
+Äã¿ÉÒÔͨ¹ýÔÚÓ¦ÓóÌÐòµÄÅäÖÃÖÐÌṩһ¸ö `HttpExchangeRepository` ÀàÐ굀 bean À´ÆôÓà HTTP exchange µÄ¼Ç¼¡£ÎªÁË·½±ãÆð¼û£¬Spring Boot ÌṩÁË `InMemoryHttpExchangeRepository`£¬Ä¬ÈÏÇé¿öÏ£¬Ëü´æ´¢ÁË×îºó100¸ö request/response exchange¡£Óë×·×Ù½â¾ö·½°¸£¨tracing solutions£©Ïà±È£¬`InMemoryHttpExchangeRepository` ÊÇÓÐÏ޵ģ¬ÎÒÃǽ¨ÒéÖ»ÔÚ¿ª·¢»·¾³ÖÐʹÓÃËü¡£¶ÔÓÚÉú²ú»·¾³£¬ÎÒÃǽ¨ÒéʹÓÃÒ»¸öÉú²ú¾ÍÐ÷µÄ¸ú×Ù»ò¹Û²ì½â¾ö·½°¸£¬Èç `Zipkin` »ò `OpenTelemetry`¡£ÁíÍ⣬ÄãÒ²¿ÉÒÔ´´½¨Äã×Ô¼ºµÄ `HttpExchangeRepository`¡£
+
+
+
+
+
+Äã¿ÉÒÔʹÓà `httpexchanges` ¶ËµãÀ´»ñÈ¡´æ´¢ÔÚ `HttpExchangeRepository` ÖÐµÄ request/response exchange µÄÐÅÏ¢¡£
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.http-exchanges.custom)10.1\. ×Ô¶¨Òå HTTP Exchange ¼Ç¼
+
+
+
+Òª×Ô¶¨Òå°üÀ¨ÔÚÿ¸ö¼Ç¼µÄ exchange ÏîÄ¿£¬ÇëʹÓà `management.httpexchanges.recording.include` ÅäÖÃÊôÐÔ¡£
+
+
+
+
+
+ÒªÍêÈ«½ûÖ¹ÖØÐ±àÂ룬Ç뽫 `management.httpexchanges.recording.enabled` ÉèÖÃΪ `false`¡£
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.process-monitoring)11\. ½ø³Ì¼à¿Ø
+
+
+
+
+
+ÔÚ `spring-boot` Ä£¿éÖУ¬Äã¿ÉÒÔÕÒµ½Á½¸ö´´½¨ÎļþµÄÀ࣬ÕâЩÎļþÔÚ½ø³Ì¼à¿ØÖÐͨ³£ºÜÓÐÓá£
+
+
+
+
+
+* `ApplicationPidFileWriter` ´´½¨Ò»¸ö°üº¬Ó¦ÓóÌÐòPIDµÄÎļþ£¨Ä¬ÈÏÇé¿öÏ£¬ÔÚÓ¦ÓóÌÐòĿ¼Ï£¬ÎļþÃûΪ `application.pid`£©¡£
+
+* `WebServerPortFileWriter` ´´½¨Ò»¸ö£¨»ò¶à¸ö£©Îļþ£¬°üº¬ÔËÐÐÖеÄWeb·þÎñÆ÷µÄ¶Ë¿Ú£¨Ä¬ÈÏÇé¿öÏ£¬ÔÚÓ¦ÓóÌÐòĿ¼Ï£¬ÎļþÃûΪ `application.port`£©¡£
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬ÕâЩдÊÖûÓб»¼¤»î£¬µ«Äã¿ÉÒÔÆôÓÃËüÃÇ¡£
+
+
+
+
+
+* [ͨ¹ýÀ©Õ¹ÅäÖÃ](https://springdoc.cn/spring-boot/actuator.html#actuator.process-monitoring.configuration)
+
+* [ÒÔ±à³Ì·½Ê½ÊµÏÖ½ø³Ì¼à¿Ø](https://springdoc.cn/spring-boot/actuator.html#actuator.process-monitoring.programmatically)
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.process-monitoring.configuration)11.1\. À©Õ¹ÅäÖÃ
+
+
+
+ÔÚ `META-INF/spring.factories` ÎļþÖУ¬Äã¿ÉÒÔ¼¤»îдÈëPIDÎļþµÄlistener£¨Ò»¸ö»òÕß¶à¸ö£©¡£
+
+
+
+
+
+
+
+ org.springframework.context.ApplicationListener=\
+org.springframework.boot.context.ApplicationPidFileWriter,\
+org.springframework.boot.web.context.WebServerPortFileWriter
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.process-monitoring.programmatically)11.2\. ÒÔ±à³Ì·½Ê½ÊµÏÖ½ø³Ì¼à¿Ø
+
+
+
+ÄãÒ²¿ÉÒÔͨ¹ýµ÷Óà `SpringApplication.addListeners(¡?)` ·½·¨²¢´«µÝÊʵ±µÄ `Writer` ¶ÔÏóÀ´¼¤»îÒ»¸ö¼àÌýÆ÷¡£ Õâ¸ö·½·¨»¹¿ÉÒÔÈÃÄãÔÚ `Writer` ¹¹Ô캯ÊýÖÐ×Ô¶¨ÒåÎļþÃûºÍ·¾¶¡£
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.cloud-foundry)12\. Cloud Foundry µÄÖ§³Ö
+
+
+
+
+
+Spring Boot µÄactuatorÄ£¿é°üÀ¨¶îÍâµÄÖ§³Ö£¬µ±Äú²¿Êðµ½¼æÈÝµÄ Cloud Foundry ʵÀýʱ£¬¸ÃÖ§³Ö½«±»¼¤»î¡£ `/cloudfoundryapplication` ·¾¶ÎªËùÓÐ `@Endpoint` BeanÌṩÁËÁíÒ»Ìõ°²È«Â·Ïß¡£
+
+
+
+
+
+À©Õ¹Ö§³Öʹ Cloud Foundry ¹ÜÀí UI£¨ÀýÈçÄú¿ÉÒÔÓÃÀ´²é¿´ÒѲ¿ÊðµÄÓ¦ÓóÌÐòµÄ Web Ó¦ÓóÌÐò£©µÃµ½ Spring Boot Ö´ÐÐÆ÷ÐÅÏ¢µÄÔöÇ¿¡£ ÀýÈ磬ӦÓóÌÐò×´Ì¬Ò³Ãæ¿ÉÒÔ°üÀ¨ÍêÕûµÄ½¡¿µÐÅÏ¢£¬¶ø²»ÊǵäÐ굀 ¡°running¡± »ò ¡°stopped¡± ״̬¡£
+
+
+
+
+
+| | ÆÕͨÓû§ÎÞ·¨Ö±½Ó·ÃÎÊ `/cloudfoundryapplication` ·¾¶¡£ ҪʹÓøö˵㣬Äú±ØÐëÔÚÇëÇóÖд«µÝÒ»¸öÓÐЧµÄ UAA ÁîÅÆ¡£ |
+| --- | --- |
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.cloud-foundry.disable)12.1\. ½ûÓÃÀ©Õ¹µÄ Cloud Foundry Actuator Ö§³Ö
+
+
+
+Èç¹ûÄúÏëÍêÈ«½ûÓà `/cloudfoundryapplication` ¶Ëµã£¬Äú¿ÉÒÔÔÚÄúµÄ `application.properties` ÎļþÖÐÌí¼ÓÒÔÏÂÉèÖá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.cloudfoundry.enabled=false
+
+```
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.cloud-foundry.ssl)12.2\. Cloud Foundry×ÔÇ©ÃûÖ¤Êé
+
+
+
+ĬÈÏÇé¿öÏ£¬`/cloudfoundryapplication` ¶ËµãµÄ°²È«ÑéÖ¤»á¶Ô¸÷ÖÖ Cloud Foundry ·þÎñ½øÐÐ SSL µ÷ÓᣠÈç¹ûÄúµÄ Cloud Foundry UAA »ò Cloud Controller ·þÎñʹÓÃ×ÔÇ©ÃûÖ¤Ê飬ÄúÐèÒªÉèÖÃÒÔÏÂÊôÐÔ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.cloudfoundry.skip-ssl-validation=true
+
+```
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/actuator.html#actuator.cloud-foundry.custom-context-path)12.3\. ×Ô¶¨Òå Context Path
+
+
+
+Èç¹û·þÎñÆ÷µÄ context-path ±»ÅäÖÃΪ `/` ÒÔÍâµÄÈκÎÄÚÈÝ£¬Ôò Cloud Foundry ¶ËµãÔÚÓ¦ÓóÌÐòµÄ¸ù²¿²»¿ÉÓᣠÀýÈ磬Èç¹û `server.servlet.context-path=/app`£¬Ôò Cloud Foundry ¶ËµãÔÚ `/app/cloudfoundryapplication/*` ´¦¿ÉÓá£
+
+
+
+
+
+Èç¹ûÄúÏ£Íû Cloud Foundry ¶ËµãʼÖÕÔÚ `/cloudfoundryapplication/*` ´¦¿ÉÓã¬ÎÞÂÛ·þÎñÆ÷µÄÉÏÏÂÎÄ·¾¶ÈçºÎ£¬ÄúÐèÒªÔÚÄúµÄÓ¦ÓóÌÐòÖÐÃ÷È·ÅäÖᣠ¸ÃÅäÖÃÒòʹÓÃµÄ Web ·þÎñÆ÷²»Í¬¶ø²»Í¬¡£ ¶ÔÓÚ Tomcat£¬Äú¿ÉÒÔÌí¼ÓÒÔÏÂÅäÖá£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Configuration(proxyBeanMethods = false)
+public class MyCloudFoundryConfiguration {
+
+ @Bean
+ public TomcatServletWebServerFactory servletWebServerFactory() {
+ return new TomcatServletWebServerFactory() {
+
+ @Override
+ protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
+ super.prepareContext(host, initializers);
+ StandardContext child = new StandardContext();
+ child.addLifecycleListener(new Tomcat.FixContextListener());
+ child.setPath("/cloudfoundryapplication");
+ ServletContainerInitializer initializer = getServletContextInitializer(getContextPath());
+ child.addServletContainerInitializer(initializer, Collections.emptySet());
+ child.setCrossContext(true);
+ host.addChild(child);
+ }
+
+ };
+ }
+
+ private ServletContainerInitializer getServletContextInitializer(String contextPath) {
+ return (classes, context) -> {
+ Servlet servlet = new GenericServlet() {
+
+ @Override
+ public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
+ ServletContext context = req.getServletContext().getContext(contextPath);
+ context.getRequestDispatcher("/cloudfoundryapplication").forward(req, res);
+ }
+
+ };
+ context.addServlet("cloudfoundry", servlet).addMapping("/*");
+ };
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/actuator.html#actuator.whats-next)13\. ½ÓÏÂÀ´¶Áʲô
+
+
+
+
+
+Äã¿ÉÄÜÏë¶ÁһϠ[Graphite](https://graphiteapp.org/) µÈͼÐι¤¾ß¡£
+
+
+
+
+
+·ñÔò£¬Äã¿ÉÒÔ¼ÌÐøÔĶÁ [¡°²¿ÊðÑ¡Ï](https://springdoc.cn/spring-boot/deployment.html#deployment) £¬»òÕßÌøµ½Ç°ÃæÈ¥Á˽âÓйØSpring Boot [¹¹½¨¹¤¾ß²å](https://springdoc.cn/spring-boot/build-tool-plugins.html#build-tool-plugins)¼þµÄһЩÉîÈëÐÅÏ¢¡£
+
+
+
+
+
+
+
diff --git "a/docs/spring/SpringBoot/SpringBoot\347\232\204Starter\346\234\272\345\210\266.md" "b/docs/spring/SpringBoot/SpringBoot\347\232\204Starter\346\234\272\345\210\266.md"
new file mode 100644
index 0000000..0318193
--- /dev/null
+++ "b/docs/spring/SpringBoot/SpringBoot\347\232\204Starter\346\234\272\345\210\266.md"
@@ -0,0 +1,262 @@
+starterÊÇSpringBootÖеÄÒ»¸öз¢Ã÷£¬ËüÓÐЧµÄ½µµÍÁËÏîÄ¿¿ª·¢¹ý³ÌµÄ¸´Ôӳ̶ȣ¬¶ÔÓÚ¼ò»¯¿ª·¢²Ù×÷ÓÐ×ŷdz£ºÃµÄЧ¹û¡£±¾ÎÄ×ªÔØÁËһƬÎÄÕ£¬Ïêϸ½éÉÜÁËspring boot staterÊÇʲô£¿ËüµÄ×÷ÓÃÊÇʲô£¿
+
+Spring Boot StarterÊÇÔÚSpringBoot×é¼þÖб»Ìá³öÀ´µÄÒ»ÖÖ¸ÅÄstackoverflowÉÏÃæÒѾÓÐÈ˸ÅÀ¨ÁËÕâ¸östarterÊÇʲô¶«Î÷£¬Ïë¿´ÍêÕûµÄ»Ø´ð´Á[ÕâÀï](https://stackoverflow.com/a/28273660)£¨https://stackoverflow.com/questions/28273543/what-are-spring-boot-starter-jars/28273660#28273660£©
+
+
+
+´ó¸ÅÒâ˼¾ÍÊÇ˵starterÊÇÒ»ÖÖ¶ÔÒÀÀµµÄsynthesize£¨ºÏ³É£©£¬ÕâÊÇʲôÒâË¼ÄØ£¿ÎÒ¿ÉÒÔ¾Ù¸öÀý×ÓÀ´ËµÃ÷¡£
+
+### ¡¡ ? ´«Í³µÄ×ö·¨
+
+ÔÚûÓÐstarter֮ǰ£¬¼ÙÈçÎÒÏëÒªÔÚSpringÖÐʹÓÃjpa£¬ÄÇÎÒ¿ÉÄÜÐèÒª×öÒÔϲÙ×÷£º
+
+1. ÔÚMavenÖÐÒýÈëʹÓõÄÊý¾Ý¿âµÄÒÀÀµ£¨¼´JDBCµÄjar£©
+2. ÒýÈëjpaµÄÒÀÀµ
+3. ÔÚxxx.xmlÖÐÅäÖÃһЩÊôÐÔÐÅÏ¢
+4. ·´¸´µÄµ÷ÊÔÖ±µ½¿ÉÒÔÕý³£ÔËÐÐ
+
+ÐèҪעÒâµÄÊÇ£¬ÕâÀï²Ù×÷ÔÚÎÒÃÇ**_ÿ´Îн¨Ò»¸öÐèÒªÓõ½jpaµÄÏîÄ¿µÄʱºò¶¼ÐèÒªÖØ¸´µÄ×öÒ»´Î_**¡£Ò²ÐíÄãÔÚµÚÒ»´Î×Ô¼º½¨Á¢ÏîÄ¿µÄʱºòÊÇÔÚGoogleÉÏ×Ô¼ºËÑË÷ÁËÒ»·¬£¬»¨Á˰ëÌìʱ¼ä½â¾öµôÁ˸÷ÖÖÆæ¹ÖµÄÎÊÌâÖ®ºó£¬jpaÖÕÓÚÄÜÕý³£ÔËÐÐÁË¡£ÓÐЩÓоÑéµÄÈË»áÔÚOneNoteÉÏÃæ°ÑÕâ´Î½¨Á¢ÏîÄ¿µÄ¹ý³Ì¸ø¼Ç¼ÏÂÀ´£¬°üÀ¨²Ù×÷µÄ²½ÖèÒÔ¼°ÐèÒªÓõ½µÄÅäÖÃÎļþµÄÄÚÈÝ£¬ÔÚÏÂÒ»´ÎÔÙ´´½¨jpaÏîÄ¿µÄʱºò£¬¾Í²»ÐèÒªÔÙ´ÎÈ¥GoogleÁË£¬Ö»ÐèÒªÕÕ×űʼÇÀ´£¬Ö®ºóÔÙ°ÑËùÓеÄÅäÖÃÎļþcopy&paste¾Í¿ÉÒÔÁË¡£
+
+ÏñÉÏÃæÕâÑùµÄ²Ù×÷Ò²²»Ëã²»ÐУ¬ÊÂʵÉÏÎÒÃÇÔÚûÓÐstarter֮ǰ¶¼ÊÇÕâô¸ÉµÄ£¬µ«ÊÇÕâÑù×öÓм¸¸öÎÊÌ⣺
+
+1. Èç¹û¹ý³Ì±È½Ï·±Ëö£¬ÕâÑùÒ»²½²½²Ù×÷»áÔö¼Ó³ö´íµÄ¿ÉÄÜÐÔ
+2. ²»Í£µØcopy&paste²»·ûºÏ[Don¡¯t repeat yourself](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)¾«Éñ
+3. ÔÚµÚÒ»´ÎÅäÖõÄʱºò£¨ÓÈÆäÈç¹û¿ª·¢Õ߱ȽÏС°×£©£¬ÐèÒª»¨·Ñµô´óÁ¿µÄʱ¼ä
+
+### ¡¡¡¡Ê¹ÓÃSpring Boot StarterÌáÉýЧÂÊ
+
+starterµÄÖ÷ҪĿµÄ¾ÍÊÇΪÁ˽â¾öÉÏÃæµÄÕâЩÎÊÌâ¡£
+
+starterµÄÀíÄstarter»á°ÑËùÓÐÓõ½µÄÒÀÀµ¶¼¸ø°üº¬½øÀ´£¬±ÜÃâÁË¿ª·¢Õß×Ô¼ºÈ¥ÒýÈëÒÀÀµËù´øÀ´µÄÂé·³¡£ÐèҪעÒâµÄÊDz»Í¬µÄstarterÊÇΪÁ˽â¾ö²»Í¬µÄÒÀÀµ£¬ËùÒÔËüÃÇÄÚ²¿µÄʵÏÖ¿ÉÄÜ»áÓкܴóµÄ²îÒ죬ÀýÈçjpaµÄstarterºÍRedisµÄstarter¿ÉÄÜʵÏ־Ͳ»Ò»Ñù£¬ÕâÊÇÒòΪstarterµÄ±¾ÖÊÔÚÓÚsynthesize£¬ÕâÊÇÒ»²ãÔÚÂß¼²ãÃæµÄ³éÏó£¬Ò²ÐíÕâÖÖÀíÄîÓеãÀàËÆÓÚDocker£¬ÒòΪËüÃǶ¼ÊÇÔÚ×öÒ»¸ö¡°°ü×°¡±µÄ²Ù×÷£¬Èç¹ûÄãÖªµÀDockerÊÇΪÁ˽â¾öʲôÎÊÌâµÄ£¬Ò²ÐíÄã¿ÉÒÔÓÃDockerºÍstarter×öÒ»¸öÀà±È¡£
+
+starterµÄʵÏÖ£ºËäÈ»²»Í¬µÄstarterʵÏÖÆðÀ´¸÷ÓвîÒ죬µ«ÊÇËûÃÇ»ù±¾É϶¼»áʹÓõ½Á½¸öÏàͬµÄÄÚÈÝ£ºConfigurationPropertiesºÍAutoConfiguration¡£ÒòΪSpring Boot¼áÐÅ¡°Ô¼¶¨´óÓÚÅäÖá±ÕâÒ»ÀíÄËùÒÔÎÒÃÇʹÓÃConfigurationPropertiesÀ´±£´æÎÒÃǵÄÅäÖ㬲¢ÇÒÕâЩÅäÖö¼¿ÉÒÔÓÐÒ»¸öĬÈÏÖµ£¬¼´ÔÚÎÒÃÇûÓÐÖ÷¶¯¸²Ð´ÔʼÅäÖõÄÇé¿öÏ£¬Ä¬ÈÏÖµ¾Í»áÉúЧ£¬ÕâÔںܶàÇé¿öÏÂÊǷdz£ÓÐÓõġ£³ý´ËÖ®Í⣬starterµÄConfigurationProperties»¹Ê¹µÃËùÓеÄÅäÖÃÊôÐÔ±»¾Û¼¯µ½Ò»¸öÎļþÖУ¨Ò»°ãÔÚresourcesĿ¼ÏµÄapplication.properties£©£¬ÕâÑùÎÒÃǾ͸æ±ðÁËSpringÏîÄ¿ÖÐXMLµØÓü¡£
+
+starterµÄÕûÌåÂß¼£º
+
+
+
+ÉÏÃæµÄstarterÒÀÀµµÄjarºÍÎÒÃÇ×Ô¼ºÊÖ¶¯ÅäÖõÄʱºòÒÀÀµµÄjar²¢Ã»ÓÐʲô²»Í¬£¬ËùÒÔÎÒÃÇ¿ÉÒÔÈÏΪstarterÆäʵÊǰÑÕâһЩ·±ËöµÄÅäÖòÙ×÷½»¸øÁË×Ô¼º£¬¶ø°Ñ¼òµ¥½»¸øÁËÓû§¡£³ýÁ˰ïÖúÓû§È¥³ýÁË·±ËöµÄ¹¹½¨²Ù×÷£¬ÔÚ¡°Ô¼¶¨´óÓÚÅäÖá±µÄÀíÄîÏ£¬ConfigurationProperties»¹°ïÖúÓû§¼õÉÙÁËÎÞνµÄÅäÖòÙ×÷¡£²¢ÇÒÒòΪ?`application.properties`?ÎļþµÄ´æÔÚ£¬¼´Ê¹ÐèÒª×Ô¶¨ÒåÅäÖã¬ËùÓеÄÅäÖÃÒ²Ö»ÐèÒªÔÚÒ»¸öÎļþÖнøÐУ¬Ê¹ÓÃÆðÀ´·Ç³£·½±ã¡£
+
+Á˽âÁËstarterÆäʵ¾ÍÊǰïÖúÓû§¼ò»¯ÁËÅäÖõIJÙ×÷Ö®ºó£¬ÒªÀí½âstarterºÍ±»ÅäÖÃÁËstarterµÄ×é¼þÖ®¼ä²¢²»ÊǾºÕù¹ØÏµ£¬¶øÊǸ¨Öú¹ØÏµ£¬¼´ÎÒÃÇ¿ÉÒÔ¸øÒ»¸ö×é¼þ´´½¨Ò»¸östarterÀ´ÈÃ×îÖÕÓû§ÔÚʹÓÃÕâ¸ö×é¼þµÄʱºò¸ü¼ÓµÄ¼òµ¥·½±ã¡£»ùÓÚÕâÖÖÀíÄÎÒÃÇ¿ÉÒÔ¸øÈÎÒâÒ»¸öÏÖÓеÄ×é¼þ´´½¨Ò»¸östarterÀ´ÈñðÈËÔÚʹÓÃÕâ¸ö×é¼þµÄʱºò¸ü¼ÓµÄ¼òµ¥·½±ã£¬ÊÂʵÉÏSpring BootÍŶÓÒѾ°ïÖúÏÖÓд󲿷ֵÄÁ÷ÐеÄ×é¼þ´´½¨ºÃÁËËüÃǵÄstarter£¬Äã¿ÉÒÔÔÚ[ÕâÀï](https://github.com/spring-projects/spring-boot/tree/v1.5.7.RELEASE/spring-boot-starters)²é¿´ÕâЩstarterµÄÁÐ±í¡£
+
+ÓÃÁËspringboot ÄÇô¾ÃÁ˾ÓÈ»¶¼»¹Ã»×Ô¶¨Òå¹ýstarter£¬ÏëÏë¶¼¾õµÃÐßÀ¢£¬ËùÒÔ½ñÌìÀ´ÍæÒ»Ï¡£
+
+
+
+# SpringBoot starter
+
+SpringBootÖеÄstarterÊÇÒ»Öַdz£ÖØÒªµÄ»úÖÆ£¬Äܹ»ÅׯúÒÔǰ·±ÔÓµÄÅäÖ㬽«Æäͳһ¼¯³É½østarter£¬Ó¦ÓÃÕßÖ»ÐèÒªÔÚmavenÖÐÒýÈëstarterÒÀÀµ£¬SpringBoot¾ÍÄÜ×Ô¶¯É¨Ãèµ½Òª¼ÓÔØµÄÐÅÏ¢²¢Æô¶¯ÏàÓ¦µÄĬÈÏÅäÖá£starterÈÃÎÒÃǰÚÍÑÁ˸÷ÖÖÒÀÀµ¿âµÄ´¦Àí£¬ÐèÒªÅäÖø÷ÖÖÐÅÏ¢µÄÀ§ÈÅ¡£SpringBoot»á×Ô¶¯Í¨¹ýclasspath·¾¶ÏµÄÀà·¢ÏÖÐèÒªµÄBean£¬²¢×¢²á½øIOCÈÝÆ÷¡£SpringBootÌṩÁËÕë¶ÔÈÕ³£ÆóÒµÓ¦ÓÃÑз¢¸÷ÖÖ³¡¾°µÄspring-boot-starterÒÀÀµÄ£¿é¡£ËùÓÐÕâЩÒÀÀµÄ£¿é¶¼×ñÑ×ÅÔ¼¶¨³ÉË×µÄĬÈÏÅäÖ㬲¢ÔÊÐíÎÒÃǵ÷ÕûÕâЩÅäÖ㬼´×ñÑ¡°Ô¼¶¨´óÓÚÅäÖá±µÄÀíÄî¡£
+
+# ×Ô¶¨Òåstarter
+
+ÈÕ³£¹¤×÷ÖÐÓÐʱÓÐһЩ¶ÀÁ¢ÓÚÒµÎñÖ®ÍâµÄ¹¦ÄÜ»òÄ£¿é£¬¿ÉÄÜÕâ¸öÏîÄ¿ÔÚÓã¬ÁíÒ»¸öÏîĿҲҪÓã¬Èç¹ûÿ´Î¶¼ÖØÐ¼¯³ÉµÄ»°¾Í»áºÜÂé·³£¬ÕâʱÎÒÃÇÖ»Òª°ÑÕâЩ¹¦ÄÜ»òÄ£¿é·â×°³ÉÒ»¸ö¸östarterµÄ»°£¬ÔÚʹÓõÄʱºòÒýÈë½øÈ¥¾ÍºÜ·½±ãÁË¡£
+
+## ×Ô¶¨Òåstarter²½Öè
+
+Æäʵ×Ô¶¨ÒåstarterºÜ¼òµ¥£¬´óÖÂÐèÒªÒÔÏÂ5²½£º
+
+1. н¨Á½¸öÄ£¿é£¬ÃüÃû¹æ·¶£º springboot×Ô´øµÄstarterÃüÃû¹æ·¶Îªspring-boot-starter-xxx£¬ ×Ô¶¨ÒåµÄstarterÃüÃû¹æ·¶Îªxxx-spring-boot-starter
+
+¡ñ xxx-spring-boot-autoconfigure£º×Ô¶¯ÅäÖúËÐÄ´úÂë
+¡ñ xxx-spring-boot-starter£º¹ÜÀíÒÀÀµ
+Èç¹û²»ÐèÒª½«×Ô¶¯ÅäÖôúÂëºÍÒÀÀµÏî¹ÜÀí·ÖÀ뿪À´£¬Ôò¿ÉÒÔ½«ËüÃÇ×éºÏµ½Ò»¸öÄ£¿éÖС£Ö»²»¹ýspringboot¹Ù·½½¨Ò齫Á½¸öÄ£¿é·Ö¿ª¡£
+2\. ÒýÈëspring-boot-autoconfigureÒÀÀµ
+3\. ´´½¨×Ô¶¨ÒåµÄXXXProperties Àà: Õâ¸öÀàµÄÊôÐÔ¸ù¾ÝÐèÒªÊÇÒª³öÏÖÔÚÅäÖÃÎļþÖеġ£
+4\. ´´½¨×Ô¶¨ÒåµÄXXXAutoConfigurationÀࣺÕâ¸öÀàÒªÅäÖÃ×Ô¶¯ÅäÖÃʱµÄһЩÂß¼£¬Í¬Ê±Ò²ÒªÈÃXXXProperties ÀàÉúЧ¡£
+5\. ´´½¨×Ô¶¨ÒåµÄspring.factoriesÎļþ£ºÔÚresources/META-INF´´½¨Ò»¸öspring.factoriesÎļþºÍspring-configuration-metadata.json£¬spring-configuration-metadata.jsonÎļþÊÇÓÃÓÚÔÚÌîдÅäÖÃÎļþʱµÄÖÇÄÜÌáʾ£¬¿ÉÒª¿É²»Òª£¬ÓеϰÌáʾÆðÀ´¸üÓѺá£spring.factoriesÓÃÓÚµ¼Èë×Ô¶¯ÅäÖÃÀ࣬±ØÐëÒªÓÐ
+
+## ʵÏÖ
+
+ÎÒÕâÀïΪÁË·½±ã¾ÍÖ»´´½¨Ò»¸öÄ£¿éÁË£¬
+
+1. ´´½¨Ò»¸öÄ£¿é£¬ÃüÃûΪspring-boot-starter-my-starter£¬¶ÔÓ¦pomÎļþ
+
+```
+ com.example
+ spring-boot-starter-my-starter
+ 1.0
+ my-starter
+¸´ÖÆ´úÂë
+```
+
+1. ÒýÈëspring-boot-autoconfigureÒÀÀµ ÎÒÕâÀïʹÓõÄspring-boot-autoconfigure°æ±¾ÊÇ2.6.2
+
+```
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+ 2.6.2
+
+
+¸´ÖÆ´úÂë
+```
+
+1. ´´½¨×Ô¶¨ÒåµÄXXXProperties Àà
+
+```
+@ConfigurationProperties(prefix = "com.arron")
+public class MyStarterProperties {
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+ÔÙ´´½¨Ò»¸öMyStarterConfigÓÃÓÚ¶ÁÈ¡MyStarterProperties ÀïµÄÊôÐÔ
+
+```
+public class MyStarterConfig {
+
+ private MyStarterProperties myStarterProperties;
+
+ private String name;
+
+ public MyStarterConfig(MyStarterProperties myStarterProperties) {
+ this.myStarterProperties = myStarterProperties;
+ }
+
+ public String getName() {
+ return myStarterProperties.getName();
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+1. ´´½¨×Ô¶¨ÒåµÄXXXAutoConfigurationÀà
+
+```
+@Configuration
+// EnableConfigurationProperties valueÊý×éÖеÄÅäÖÃÀàÆð×÷ÓÃ
+@EnableConfigurationProperties(value = {MyStarterProperties.class})
+public class MyStarterAutoConfiguration {
+
+ @Autowired
+ private MyStarterProperties myStarterProperties;
+
+ @Bean
+ @ConditionalOnMissingBean(MyStarterConfig.class)
+ public MyStarterConfig myStarterConfig(){
+ return new MyStarterConfig(myStarterProperties);
+ }
+
+}
+¸´ÖÆ´úÂë
+```
+
+1. ÔÚresources/META-INF´´½¨Ò»¸öspring.factoriesÎļþ
+
+spring.factories
+
+```
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.myStarter.MyStarterAutoConfiguration
+¸´ÖÆ´úÂë
+```
+
+spring-configuration-metadata.json
+
+```
+{
+ "group": [
+ {
+ "name": "com.arron",
+ "type": "com.example.myStarter.MyStarterProperties",
+ "sourceType": "com.example.myStarter.MyStarterProperties"
+ }
+ ],
+ "properties": [
+ {
+ "name": "com.arron.name",
+ "type": "java.lang.String",
+ "description": "my start name",
+ "sourceType": "com.example.myStarter.MyStarterProperties",
+ "defaultValue": "MyStarterProperties name"
+ }
+ ]
+}
+¸´ÖÆ´úÂë
+```
+
+## ´ò°ü²âÊÔ
+
+ÕÒµ½Èçͼmaven£¬µã»÷install£¬°²×°µ½±¾µØ 
+
+È»ºóн¨Ò»¸öÏîÄ¿µ¼°ü½øÐвâÊÔ£¬´´½¨ÏîÄ¿¹ý³Ì¾Í²»½éÉÜÁË¡£
+
+1. ÒýÈëÒÀÀµ
+
+```
+
+ com.example
+ spring-boot-starter-my-starter
+ 1.0
+
+¸´ÖÆ´úÂë
+```
+
+1. ÅäÖÃÎļþÌí¼ÓÊôÐÔ£º
+
+```
+com:
+ arron:
+ name: myname
+¸´ÖÆ´úÂë
+```
+
+1. µ¥Ôª²âÊÔ£º
+
+```
+@RunWith(SpringRunner.class)
+@SpringBootTest
+class RabbitmqApplicationTests {
+ @Autowired
+ private MyStarterConfig myStarterConfig;
+
+ @Test
+ public void testMyStarter(){
+ String name = myStarterConfig.getName();
+ System.out.println(name);
+ }
+}
+¸´ÖÆ´úÂë
+```
+
+¿ØÖÆÌ¨Êä³ö£º
+
+```
+myname
+¸´ÖÆ´úÂë
+```
+
+ÖÁ´Ë£¬Ò»¸ö¼òµ¥×Ô¶¨ÒåµÄspringboot starter¾ÍÍê³ÉÁË¡£
+
+# ×¢½â½âÊÍ
+
+ÏÂÃæÕâЩע½âÔÚ×Ô¶¨ÒåstarterÊÇ¿ÉÄÜ»áÓõ½¡£
+
+* @Conditional£º°´ÕÕÒ»¶¨µÄÌõ¼þ½øÐÐÅжϣ¬Âú×ãÌõ¼þ¸øÈÝÆ÷×¢²ábean
+* @ConditionalOnMissingBean£º¸ø¶¨µÄÔÚbean²»´æÔÚʱ,ÔòʵÀý»¯µ±Ç°Bean
+* @ConditionalOnProperty£ºÅäÖÃÎļþÖÐÂú×㶨ÒåµÄÊôÐÔÔò´´½¨bean£¬·ñÔò²»´´½¨
+* @ConditionalOnBean£º¸ø¶¨µÄÔÚbean´æÔÚʱ,ÔòʵÀý»¯µ±Ç°Bean
+* @ConditionalOnClass£º µ±¸ø¶¨µÄÀàÃûÔÚÀà·¾¶ÉÏ´æÔÚ£¬ÔòʵÀý»¯µ±Ç°Bean
+* @ConditionalOnMissingClass £ºµ±¸ø¶¨µÄÀàÃûÔÚÀà·¾¶Éϲ»´æÔÚ£¬ÔòʵÀý»¯µ±Ç°Bean
+
+
+
+×÷ÕߣºË÷ÂëÀí
+Á´½Ó£ºhttps://juejin.cn/post/7127468724046528525
+À´Ô´£ºÏ¡ÍÁ¾ò½ð
+Öø×÷Ȩ¹é×÷ÕßËùÓС£ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£
+
diff --git "a/docs/spring/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md" "b/docs/spring/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md"
index 36a2500..247e419 100644
--- "a/docs/spring/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md"
+++ "b/docs/spring/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md"
@@ -20,55 +20,20 @@
µã»÷¡°Éú³É¡±°´Å¥£¬ÏÂÔØ zip Îļþ£¬²¢½«Æä½âѹµ½Äú¼ÆËã»úÉϵÄÒ»¸öÎļþ¼ÐÖС£
-
+
[start.spring.io](http://start.spring.io/)´´½¨µÄÏîÄ¿°üº¬[Spring Boot](https://spring.io/projects/spring-boot)£¬Ò»¸öÈÃSpring×¼±¸ºÃÔÚÄúµÄÓ¦ÓóÌÐòÄÚ²¿¹¤×÷£¬µ«²»ÐèҪ̫¶à´úÂë»òÅäÖᣠSpring Boot ÊÇÆô¶¯ Spring ÏîÄ¿µÄ×î¿ìºÍ×îÁ÷Ðеķ½Ê½¡£
ÕâÀïÎÒÃÇÑ¡ÔñʹÓÃmaven×÷Ϊ°ü¹ÜÀí¹¤¾ß£¬ÏÂÔØÏÂÀ´µÄÏîÄ¿Àï»á°üº¬pomÎļþ£¬pomÎļþÀï°üº¬ÁËÄãµÄÌí¼ÓµÄÒÀÀµ¡£
-````
-
-
- 4.0.0
-
- org.springframework.boot
- spring-boot-starter-parent
- 3.0.5
-
-
- com.example
- demo
- 0.0.1-SNAPSHOT
- demo
- Demo project for Spring Boot
-
- 17
-
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
-
-
-````
+````
+
+ 4.0.0 org.springframework.boot spring-boot-starter-parent 3.0.5 com.example demo 0.0.1-SNAPSHOT demo Demo project for Spring Boot 17 org.springframework.boot spring-boot-starter-web
+ org.springframework.boot spring-boot-starter-test test
+ org.springframework.boot spring-boot-maven-plugin
+
+````
## µÚ¶þ²½£ºÌí¼ÓÄãµÄ´úÂë
@@ -76,27 +41,20 @@
ÔÚÄúµÄ IDE Öдò¿ªÏîÄ¿²¢ÔÚ `src/main/java/com/example/demo` Îļþ¼ÐÖÐÕÒµ½ `DemoApplication.java` Îļþ¡£
ÏÖÔÚͨ¹ýÌí¼ÓÏÂÃæ´úÂëÖÐÏÔʾµÄ¶îÍâ·½·¨ºÍ×¢ÊÍÀ´¸ü¸ÄÎļþµÄÄÚÈÝ¡£Äú¿ÉÒÔ¸´ÖƲ¢Õ³Ìù´úÂë»òÖ±½Ó¼üÈë´úÂë¡£
-```
-package com.example.demo;
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-@SpringBootApplication
-@RestController
-public class DemoApplication {
- public static void main(String[] args) {
- SpringApplication.run(DemoApplication.class, args);
- }
- @GetMapping("/hello")
- public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
- return String.format("Hello %s!", name);
- }
-}
-
-```
+```
+package com.example.demo;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@SpringBootApplication
+@RestController
+public class DemoApplication {
+ public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @GetMapping("/hello") public String hello(@RequestParam(value = "name", defaultValue = "World") String name) { return String.format("Hello %s!", name); }}
+
+```
ÕâÊÇÔÚ Spring Boot Öд´½¨Ò»¸ö¼òµ¥µÄ¡°Hello World¡± Web ·þÎñËùÐèµÄËùÓдúÂë¡£
@@ -104,8 +62,7 @@ public class DemoApplication {
ÕâÒâζ×ÅÈç¹ûÄúÔÚÇëÇóÖн«ÄúµÄÃû×ÖÉèÖÃΪ¡°Amy¡±£¬ÔòÏìÓ¦½«ÊÇ¡°Hello Amy¡±¡£
-`@RestController` ×¢Ê͸æËß Spring£¬´Ë´úÂëÃèÊöÁËÒ»¸ö¶Ëµã£¬¸Ã¶ËµãÓ¦ÔÚ Web ÉÏ¿ÉÓá£
-
+`@RestController` ×¢Ê͸æËß Spring£¬´Ë´úÂëÃèÊöÁËÒ»¸ö¶Ëµã£¬¸Ã¶ËµãÓ¦ÔÚ Web ÉÏ¿ÉÓá£
@GetMapping(¡°/hello¡±) ¸æËß Spring ʹÓÃÎÒÃÇµÄ hello() ·½·¨À´ÏìÓ¦·¢Ë͵½ http://localhost:8080/hello µØÖ·µÄÇëÇó¡£
×îºó£¬@RequestParam ¸æËß Spring ÔÚÇëÇóÖÐÆÚÍûÒ»¸öÃû³ÆÖµ£¬µ«Èç¹û²»´æÔÚ£¬Ëü½«Ä¬ÈÏʹÓõ¥´Ê¡°World¡±¡£
@@ -118,34 +75,33 @@ public class DemoApplication {
**MacOS/Linux:**
-```
-COPY./gradlew bootRun
-
-```
+```
+COPY./gradlew bootRun
+
+```
**Windows:**
-```
-COPY.\gradlew.bat bootRun
-
-```
+```
+COPY.\gradlew.bat bootRun
+
+```
-ÄúÓ¦¸Ã»á¿´µ½Ò»Ð©Óë´Ë·Ç³£ÏàËÆµÄÊä³ö£º
-
+ÄúÓ¦¸Ã»á¿´µ½Ò»Ð©Óë´Ë·Ç³£ÏàËÆµÄÊä³ö£º
+
-ÕâÀïµÄ×îºó¼¸ÐиæËßÎÒÃÇ£¬SpringÓ¦ÓÃÒѾ¿ªÊ¼ÔËÐÐÁË¡£
-Spring Boot µÄǶÈëʽ Apache Tomcat ·þÎñÆ÷³äµ±ÍøÂç·þÎñÆ÷£¬²¢ÕýÔÚ¼àÌý¡°localhost¡±¶Ë¿Ú¡°8080¡±ÉϵÄÇëÇó¡£
+ÕâÀïµÄ×îºó¼¸ÐиæËßÎÒÃÇ£¬SpringÓ¦ÓÃÒѾ¿ªÊ¼ÔËÐÐÁË¡£ Spring Boot µÄǶÈëʽ Apache Tomcat ·þÎñÆ÷³äµ±ÍøÂç·þÎñÆ÷£¬²¢ÕýÔÚ¼àÌý¡°localhost¡±¶Ë¿Ú¡°8080¡±ÉϵÄÇëÇó¡£
´ò¿ªä¯ÀÀÆ÷£¬ÔÚ¶¥²¿µÄµØÖ·À¸ÖÐÊäÈë`http://localhost:8080/hello`¡£
-ÄãÓ¦¸ÃµÃµ½ÕâÑùÒ»¸öÓѺõĻØÓ¦£º
-
+ÄãÓ¦¸ÃµÃµ½ÕâÑùÒ»¸öÓѺõĻØÓ¦£º
+
# ×ܽá
-¾ÍÊÇÈç´Ë¼òµ¥£¬µÚÒ»¸öSpringBootÓ¦ÓþÍÕâô¹¹½¨Íê³ÉÁË£¬Äã²»ÐèÒª¶îÍâµÄÅäÖÃÎļþ£¬¶îÍâµÄÒÀÀµ£¬ÉõÖÁÊǶîÍâµÄ·þÎñÆ÷¡£
+¾ÍÊÇÈç´Ë¼òµ¥£¬µÚÒ»¸öSpringBootÓ¦ÓþÍÕâô¹¹½¨Íê³ÉÁË£¬Äã²»ÐèÒª¶îÍâµÄÅäÖÃÎļþ£¬¶îÍâµÄÒÀÀµ£¬ÉõÖÁÊǶîÍâµÄ·þÎñÆ÷¡£
Ö»ÐèÒªÒ»¸öÆô¶¯À࣬¾Í¿ÉÒÔʵÏÖÒ»¸ö×î»ù±¾µÄSpringBootµÄÓ¦Óá£
-ÕâÒ²ÊÇΪʲôspringboot¿ÉÒÔÓÃÀ´¿ìËÙ¹¹½¨Ò»¸ö΢·þÎñ£¬ÒòΪËüʵÔÚÊÇÌ«·½±ãÁË¡£
+ÕâÒ²ÊÇΪʲôspringboot¿ÉÒÔÓÃÀ´¿ìËÙ¹¹½¨Ò»¸ö΢·þÎñ£¬ÒòΪËüʵÔÚÊÇÌ«·½±ãÁË¡£
µ±È»£¬Êµ¼Ê¿ª·¢ÖÐÎÒÃÇÐèÒªÓõ½¸ü¶àspringbootµÄ¹¦ÄܺÍÌØÐÔ£¬ÎÒÃǽ«»áÔÚ½ÓÏÂÀ´µÄÕ½ÚÖÐÖð½¥Õ¹¿ª½éÉÜ¡£
# ²Î¿¼ÎÄÕÂ
diff --git "a/docs/spring/SpringBoot/SpringBoot\347\232\204\351\205\215\347\275\256\346\226\207\344\273\266\347\256\241\347\220\206.md" "b/docs/spring/SpringBoot/SpringBoot\347\232\204\351\205\215\347\275\256\346\226\207\344\273\266\347\256\241\347\220\206.md"
new file mode 100644
index 0000000..46c6771
--- /dev/null
+++ "b/docs/spring/SpringBoot/SpringBoot\347\232\204\351\205\215\347\275\256\346\226\207\344\273\266\347\256\241\347\220\206.md"
@@ -0,0 +1,2989 @@
+## 1.SpringBootÅäÖùÜÀíµÄ±³¾°Óë»ù´¡
+
+ΪʵÏÖ¿ìËٴºÍ¿ª·¢£¬ÏîÄ¿ÒÔSpringboot¿ò¼Ü´î½¨£¬springboot´î½¨µÄÏîÄ¿¿ÉÒÔ½«ÏîĿֱ½Ó´ò³Éjar°ü²¢ÔËÐУ¬ÎÞÐè×Ô¼º°²×°ÅäÖÃTomcat»òÕ߯äËû·þÎñÆ÷£¬ÊÇÒ»ÖÖ·½±ã¿ì½ÝµÄ²¿Êð·½Ê½¡£
+
+¼ÙÉèÏîÄ¿ÒÔ×î³£¹æµÄ·½Ê½´ò°ü³ÉÒ»¸öÕûÌåµÄjar°ü²¿Ê𣬼´ÅäÖÃÎļþºÍµÚÈý·½ÒÀÀµ°ü¶¼°üº¬ÔÚjar°üÀ¾Í»áÓÐÈçÏÂÁ½¸öÎÊÌâ
+
+ÎÊÌâÒ»£ºÏîÄ¿ÔËÐйý³ÌÖУ¬Òª¸Ä¶¯ÅäÖÃÎļþµÄ»°ÐèÒªÖØÐ´ò°ü²¢²¿Êð¡£
+
+ÎÊÌâ¶þ£º¶à¸öµÚÈý·½ÒÀÀµ°ü¶¼Ïà½üµÄÏîĿҪ²¿ÊðÔÚͬһ̨·þÎñÆ÷ʱ£¬¸÷×ÔµÄjar°ü¶¼°üº¬ÁËÏàͬµÄµÚÈý·½ÒÀÀµ°ü£¨¼ÙÉèÏîÄ¿jar°üÓÐ100M£¬µÚÈý·½ÒÀÀµ°ü¿ÉÄܾÍÕ¼ÓÃÁË99M£©£¬ÕâÑùµÚÈý·½ÒÀÀµ°üÈßÓàÔì³ÉÁË·þÎñÆ÷×ÊÔ´µÄÀË·ÑÒÔ¼°½µµÍÁËÏîÄ¿²¿ÊðµÄЧÂÊ¡£
+
+Èç¹û½«¸÷ÏîÄ¿µÄÅäÖÃÎļþ¡¢µÚÈý·½ÒÀÀµ°ü¶¼ÌáÈ¡µ½jar°üÍâͳһ¹ÜÀí£¬ÕâÑù¼´ÌáÉýÁËÏîÄ¿´ò°üЧÂÊÓÖ½ÚÔ¼ÁË·þÎñÆ÷µÄ´ÅÅÌÏûºÄ£¬Í¬Ê±ÏîÄ¿µÄÔËάҲÊǷdz£·½±ãµÄ£¬¸Ä¶¯ÁËÅäÖÃÎļþÖØÆôÏ·þÎñ¾Í¿ÉÒÔÁË£¬ÎÞÐèÖØÐ¹¹½¨²¿Êð¡£
+
+ÏÂÃæÊǾßÌåµÄʵÏÖ·½°¸
+
+### 1.1 **ÅäÖÃÎļþͳһ¹ÜÀí**
+
+```
+ - springbootºËÐÄÅäÖÃÎļþ
+ - Springboot¶ÁÈ¡ºËÐÄÅäÖÃÎļþ£¨application.properties£©µÄÓÅÏȼ¶Îª
+ - Jar°üͬ¼¶Ä¿Â¼µÄconfigĿ¼
+ - Jar°üͬ¼¶Ä¿Â¼
+ - classPath(¼´resourcesĿ¼)µÄconfigĿ¼
+ - classpathĿ¼
+
+```
+
+ÉÏÃæÊÇspringbootĬÈÏÈ¥ÄÃ×Ô¼ºµÄºËÐÄÅäÖÃÎļþµÄÓÅÏȼ¶£¬»¹ÓÐÒ»ÖÖ×î¸ßÓÅÏȼ¶µÄ·½Ê½ÊÇÏîÄ¿Æô¶¯Ê±Í¨¹ýÃüÁîµÄ·½Ê½Ö¸¶¨ÏîÄ¿¼ÓÔØºËÐÄÅäÖÃÎļþ£¬ÃüÁîÈçÏÂ
+java ¨Cjar -Dspring.config.location=xxx/xxx/xxxx.properties xxxx.jar
+
+Èç¹ûSpring BootÔÚÓÅÏȼ¶¸ü¸ßµÄλÖÃÕÒµ½ÁËÅäÖã¬ÄÇôËü»áÎÞÊÓÓÅÏȼ¶¸üµÍµÄÅäÖÃ
+
+### 1.2 **ÆäËû×ÊÔ´ÅäÖÃÎļþ**
+
+ÉÏÃæÃèÊöµÄSpringbootºËÐÄÎļþÒѾÄܹ»ÌáÈ¡³öjar°üÍâ½øÐйÜÀíÁË£¬µ«ÊÇ»¹ÓÐÆäËûһЩҵÎñÉϵÄÅäÖÃÎļþ£¬ÈçÊý¾ÝÔ´ÅäÖÃÎļþ£¬¹«¹²×ÊÔ´¶¨ÒåÅäÖÃÎļþ£¨³£Á¿£¬FTPÐÅÏ¢µÈ£©£¬quartz¶¨Ê±Æ÷£¬ÈÕÖ¾µÈÅäÖÃÎļþÎÒÃÇÈçºÎÈ¥ÌáÈ¡³öÀ´²¢È·±£ÄÜÔÚ´úÂëÖÐÒýÓõ½ÄØ
+
+ÎÒÃÇÖªµÀSpringbootÏîÄ¿¿ÉÒÔͨ¹ý×¢½â·½Ê½À´»ñÈ¡Ïà¹ØÅäÖÃÎļþ£¬ËùÒÔÎÒÃÇÒ²ÊÇͨ¹ý×¢½â·½Ê½ÈÃÏîÄ¿Äܹ»ÒýÓõ½jar°üÍⲿµÄÅäÖÃÎļþµÄ£¬ÈçÏÂͼ£º
+
+
+@PropertySourceÀïÃæµÄvalueÓÐÁ½¸öÖµ£¬µÚÒ»¸öÊÇclasspathÏÂconfigĿ¼ÏµÄÊý¾ÝÔ´ÅäÖÃÎļþ£¬µÚ¶þ¸öÔòÊǸù¾Ýspring.profiles.path¶¯Ì¬»ñÈ¡µÄĿ¼£¬spring.profiles.pathÊÇÎÒÃÇÔÚºËÐÄÎļþ×Ô¶¨ÒåµÄÒ»¸öÅäÖÃÏËüµÄÖµÊÇÎÒÃÇÅäÖÃÎļþͳһ¹ÜÀíµÄÎļþ¼Ð·¾¶£¬ºóÃæµÄignoreResourceNotFound=trueÔòÊÇÉ趨¼ÙÈç¸ù¾ÝÇ°ÃæÒ»¸ö·¾¶Ã»ÓÐÕÒµ½Ïà¹ØÅäÖÃÎļþ£¬Ôò¸ù¾ÝµÚ¶þ¸ö·¾¶È¥ÕÒ¡£
+
+ÎÒÃÇ»¹¿ÉÒÔÖ±½Ó¸ù¾Ý·¾¶£¬ÓÃFileSystemResourceÀàÈ¥¼ÓÔØÒ»¸öÅäÖÃÎļþʵÀý³öÀ´£¬ÈçÏÂͼ
+
+
+ÔÀíÀàËÆ£¬¸ù¾ÝÔÚºËÐÄÎļþ×Ô¶¨ÒåµÄͳһÅäÖÃĿ¼µÄ·¾¶À´¼ÓÔØÅäÖÃÎļþ
+
+ÁíÍâlogbackÈÕÖ¾ÅäÖÃÎļþ¼ÓÔØ·½Ê½ÈçÏ£º
+
+
+×ÛÉÏËùÊö£¬ÎÒÃÇÊáÀíÒ»ÏÂʵÏÖ·½°¸µÄ˼·
+
+```
+ - ÔÚspringbootºËÐÄÎļþÀﶨÒåÒ»¸öspring.profiles.pathÅäÖÃÏËüµÄÖµÖ¸ÏòÎÒÃÇËùÓÐÅäÖÃÎļþͳһ·ÅÖõÄĿ¼£¬°üº¬ºËÐÄÎļþ×ÔÉíÒ²ÊÇ·ÅÖÃÔÚÀïÃæµÄ
+
+ - ´úÂë»òÕßÅäÖÃÎļþÀï¼ÓÔØÅäÖÃÎļþµÄµØ·½Ò²Ó¦¸Ã»ñÈ¡spring.profiles.pathÅäÖÃÏîÀ´¶¯Ì¬¼ÓÔØ¸Ã·¾¶ÏµÄÅäÖÃÎļþ
+
+ - Pom.xmlÎļþÐ޸Ĵò°üÏà¹ØÄ£¿é£¬½«ÅäÖÃÎļþÅųý£¬ÕâÑùÎÒÃÇ´ò³öµÄjar°üÊDz»º¬ÅäÖÃÎļþµÄ£¬´ò°üÅäÖÃÇë²Î¿¼Îĵµ½Úµã3
+
+ - Æô¶¯jar°üʱ£¬Í¨¹ýÃüÁîÖ¸¶¨¼ÓÔØµÄºËÐÄÎļþΪspring.profiles.pathϵĺËÐÄÎļþ
+
+```
+**µÚÈý·½ÒÀÀµ°üͳһ¹ÜÀí**
+
+ͨ³£µÚÈý·½jar°ü¿ÉÒÔ´ò½øjar°üÀҲ¿ÉÒÔ·ÅÔÚÏîÄ¿jar°üͬ¼¶Ä¿Â¼ÏµÄlibĿ¼£¬ÎÒÃÇ¿ÉÒÔ¸ù¾ÝÐÞ¸Äpom.xml´ò°üÅäÖÃÀ´ÊµÏÖ£¬Çë²Î¿¼Îĵµ½Úµã3´ò°üÅäÖÃ
+
+**´ò°üÅäÖÃ**
+
+```
+
+
+
+ src/main/java
+
+ **/*.properties
+ **/*.xml
+
+ true
+
+
+ src/main/resources
+
+
+ **/*.properties
+ **/*.xml
+ **/*.yml
+
+ false
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+ true
+ true
+
+ C:/Program Files/Java/jdk1.8.0_161/bin/javac.exe
+
+
+
+
+ maven-jar-plugin
+
+
+
+ true
+ lib/
+ false
+ com.xrq.demo.Application
+
+
+ ./
+
+
+
+ *.properties
+ *.yml
+ *.xml
+ config/**
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy
+ package
+
+ copy-dependencies
+
+
+
+ ${project.build.directory}/lib
+
+
+
+
+
+
+
+
+```
+
+¸ÄºÃpom.xmlµÄbuildÄ£¿éºó£¬¾Í¿ÉÒÔͨ¹ýmvn package »òÕßmvn install´ò³öÎÒÃǵÄjar°üÁË
+
+1. **ÏîÄ¿¹ÜÀíshell½Å±¾±àд**
+ ×Ô¶¨Òåshell½Å±¾£¬ÊµÏÖÏîÄ¿µÄÆô¶¯£¬Í£Ö¹£¬×´Ì¬£¬ÖØÆô²Ù×÷£º
+
+```
+#!/bin/bash
+#ÕâÀï¿ÉÌæ»»ÎªÄã×Ô¼ºµÄÖ´ÐгÌÐò,ÆäËû´úÂëÎÞÐè¸ü¸Ä
+APP_NAME=demo1-0.0.1-SNAPSHOT.jar
+JVM="-server -Xms512m -Xmx512m -XX:PermSize=64M -XX:MaxNewSize=128m -XX:MaxPermSize=128m -Djava.awt.headless=true -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled"
+APPFILE_PATH="-Dspring.config.location=/usr/local/demo/config/application-demo1.properties"
+#ʹÓÃ˵Ã÷,ÓÃÀ´ÌáʾÊäÈë²ÎÊý
+usage() {
+echo "Usage: sh Ö´Ðнű¾.sh [start|stop|restart|status]"
+exit 1
+}
+#¼ì²é³ÌÐòÊÇ·ñÔÚÔËÐÐ
+is_exist(){
+pid=`ps -ef|grep $APP_NAME|grep -v grep|awk '{print $2}' `
+#Èç¹û²»´æÔÚ·µ»Ø1,´æÔÚ·µ»Ø0
+if [ -z "${pid}" ]; then
+return 1
+else
+return 0
+fi
+}
+#Æô¶¯·½·¨
+start(){
+is_exist
+if [ $? -eq "0" ]; then
+echo "${APP_NAME} is already running. pid=${pid} ."
+else
+nohup java $JVM -jar $APPFILE_PATH $APP_NAME > /dev/null 2>&1
+fi
+}
+#Í£Ö¹·½·¨
+stop(){
+is_exist
+if [ $? -eq "0" ]; then
+kill -9 $pid
+else
+echo "${APP_NAME} is not running"
+fi
+}
+#Êä³öÔËÐÐ״̬
+status(){
+is_exist
+if [ $? -eq "0" ]; then
+echo "${APP_NAME} is running. Pid is ${pid}"
+else
+echo "${APP_NAME} is NOT running."
+fi
+}
+#ÖØÆô
+restart(){
+stop
+start
+}
+#¸ù¾ÝÊäÈë²ÎÊý,Ñ¡ÔñÖ´ÐжÔÓ¦·½·¨,²»ÊäÈëÔòÖ´ÐÐʹÓÃ˵Ã÷
+case "$1" in
+"start")
+start
+;;
+"stop")
+stop
+;;
+"status")
+status
+;;
+"restart")
+restart
+;;
+*)
+usage
+;;
+esac
+
+```
+
+**²¿Êð**
+
+linux·þÎñÆ÷ÉÏн¨¸öÎļþ¼Ð£¬½«ÎÒÃÇ´òºÃµÄÏîÄ¿jar°ü¶¼¶ª½øÈ¥£¬ÔÚjar°üµÄͬ¼¶Ä¿Â¼Ð½¨configºÍlibÎļþ¼Ð£¬·Ö±ð½«ÅäÖÃÎļþºÍµÚÈý·½ÒÀÀµ°ü¶ª½øÈ¥£¬Æä½á¹¹ÈçÏÂͼ£¬*.shΪ×Ô¼ºÐ´µÄÏîÄ¿Æô¶¯shell½Å±¾
+
+
+
+´ò¿ªconfigÄÚµÄspringbootºËÐÄÎļþ£¨Èçapplication-demo1.propertiesÎļþ£©£¬
+
+spring.profiles.pathÅäÖÃÏî¸Ä³Éµ±Ç°ÅäÖÃÎļþËùÔÚµÄĿ¼£¬¼ÙÉèΪ/usr/local/demo/config
+
+´ò¿ª*.sh½Å±¾£¬ÐÞ¸ÄAPPFILE_PATHµÄÖµ£¬ÈçÏÂ
+
+APPFILE_PATH="-Dspring.config.location=/usr/local/demo/config/application-demo1.properties"
+
+**ÏîÄ¿¹ÜÀí**
+
+½øÈëjar°üËùÔÚĿ¼ִÐÐÏÂÃæÃüÁî
+
+sh [demo1.sh](http://demo1.sh/) start Æô¶¯ÏîÄ¿
+
+sh [demo1.sh](http://demo1.sh/) stop Í£Ö¹ÏîÄ¿
+
+sh [demo1.sh](http://demo1.sh/) restartÖØÆôÏîÄ¿
+
+sh [demo1.sh](http://demo1.sh/) statusÏîĿ״̬
+
+## 2\. Íⲿ»¯µÄÅäÖÃ
+
+
+
+
+
+Spring Boot¿ÉÒÔÈÃÄ㽫ÅäÖÃÍⲿ»¯£¬ÕâÑùÄã¾Í¿ÉÒÔÔÚ²»Í¬µÄ»·¾³ÖÐʹÓÃÏàͬµÄÓ¦ÓóÌÐò´úÂë¡£ Äã¿ÉÒÔʹÓø÷ÖÖÍⲿÅäÖÃÔ´£¬°üÀ¨Java properties Îļþ¡¢YAMLÎļþ¡¢»·¾³±äÁ¿ºÍÃüÁîÐвÎÊý¡£
+
+
+
+
+
+ÊôÐÔÖµ¿ÉÒÔͨ¹ýʹÓà `@Value` ×¢½âÖ±½Ó×¢ÈëÄãµÄBean£¬Ò²¿ÉÒÔͨ¹ýSpring µÄ `Environment` ·ÃÎÊ£¬»òÕßͨ¹ý `@ConfigurationProperties` [°ó¶¨µ½¶ÔÏó](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties)¡£
+
+
+
+
+
+Spring Boot ʹÓÃÒ»¸ö·Ç³£ÌرðµÄ `PropertySource` ˳Ðò£¬Ö¼ÔÚÔÊÐíºÏÀíµØÖØÐ´Öµ¡£ ºóÃæµÄ property source ¿ÉÒÔ¸²¸ÇÇ°ÃæÊôÐÔÔ´Öж¨ÒåµÄÖµ¡£ °´ÒÔÏÂ˳Ðò¿¼ÂÇ¡£
+
+
+
+
+
+1. ĬÈÏÊôÐÔ£¨Í¨¹ý `SpringApplication.setDefaultProperties` Ö¸¶¨£©¡£
+
+2. @Configuration ÀàÉ쵀 [`@PropertySource`](https://docs.spring.io/spring-framework/docs/6.0.5/javadoc-api/org/springframework/context/annotation/PropertySource.html) ×¢½â¡£Çë×¢Ò⣬ÕâÑùµÄÊôÐÔÔ´Ö±µ½application context±»Ë¢ÐÂʱ²Å»á±»Ìí¼Óµ½»·¾³ÖС£Õâ¶ÔÓÚÅäÖÃijЩÊôÐÔÀ´ËµÒѾ̫ÍíÁË£¬±ÈÈç `logging.*` ºÍ `spring.main.*` £¬ËüÃÇÔÚˢпªÊ¼Ç°¾ÍÒѾ±»¶ÁÈ¡ÁË¡£
+
+3. ÅäÖÃÊý¾Ý£¨Èç `application.properties` Îļþ£©¡£
+
+4. `RandomValuePropertySource`£¬ËüÖ»ÓÐ `random.*` ÊôÐÔ¡£
+
+5. ²Ù×÷ϵͳ»·¾³±äÁ¿
+
+6. Java System properties (`System.getProperties()`).
+
+7. `java:comp/env` ÖÐµÄ JNDI ÊôÐÔ¡£
+
+8. `ServletContext` init parameters.
+
+9. `ServletConfig` init parameters.
+
+10. À´×Ô `SPRING_APPLICATION_JSON` µÄÊôÐÔ£¨Ç¶Èë»·¾³±äÁ¿»òϵͳÊôÐÔÖеÄÄÚÁªJSON£©¡£
+
+11. ÃüÁîÐвÎÊý
+
+12. ÄãÔÚ²âÊÔÖÐµÄ `properties` ÊôÐÔ¡£ÔÚ [`@SpringBootTest`](https://docs.spring.io/spring-boot/docs/3.1.0-SNAPSHOT/api/org/springframework/boot/test/context/SpringBootTest.html) ºÍ²âÊÔ×¢½âÖпÉÓã¬[ÓÃÓÚ²âÊÔÄãµÄÓ¦ÓóÌÐòµÄÒ»¸öÌØ¶¨Æ¬¶Ï](https://springdoc.cn/spring-boot/features.html#features.testing.spring-boot-applications.autoconfigured-tests)¡£
+
+13. Äã²âÊÔÖеÄhttps://docs.spring.io/spring-framework/docs/6.0.5/javadoc-api/org/springframework/test/context/TestPropertySource.html[`@TestPropertySource`] ×¢½â.
+
+14. µ±devtools´¦Óڻ״̬ʱ£¬`$HOME/.config/spring-boot` Ŀ¼ÏµÄ[DevtoolsÈ«¾ÖÉèÖÃÊôÐÔ](https://springdoc.cn/spring-boot/using.html#using.devtools.globalsettings)¡£
+
+
+
+
+
+ÅäÖÃÊý¾ÝÎļþ°´ÒÔÏÂ˳Ðò¿¼ÂÇ¡£
+
+
+
+
+
+1. ÔÚÄãµÄjarÖдò°üµÄ[Application properties](https://springdoc.cn/spring-boot/features.html#features.external-config.files)£¨application.properties ºÍ YAML£©¡£
+
+2. ÔÚÄãµÄjarÖдò°üµÄ [ÌØ¶¨µÄ Profile application properties](https://springdoc.cn/spring-boot/features.html#features.external-config.files.profile-specific)£¨`application-{profile}.properties` ºÍ YAML£©¡£
+
+3. ÔÚÄã´ò°üµÄjarÖ®ÍâµÄ[Application properties](https://springdoc.cn/spring-boot/features.html#features.external-config.files)ÐÔ£¨application.propertiesºÍYAML£©¡£
+
+4. ÔÚÄã´ò°üµÄjarÖ®ÍâµÄ[ÌØ¶¨µÄ Profile application properties](https://springdoc.cn/spring-boot/features.html#features.external-config.files.profile-specific)£¨ `application-{profile}.properties` ºÍYAML£©¡£
+
+
+
+
+
+| | ½¨ÒéÄãÔÚÕû¸öÓ¦ÓóÌÐòÖмá³ÖʹÓÃÒ»ÖÖ¸ñʽ¡£ Èç¹ûÄãÔÚͬһ¸öµØ·½ÓÐ `.properties` ºÍ `.yml` ¸ñʽµÄÅäÖÃÎļþ£¬`.properties` ÓÅÏÈ¡£ |
+| --- | --- |
+
+
+
+
+
+ΪÁËÌṩһ¸ö¾ßÌåµÄÀý×Ó£¬¼ÙÉèÄ㿪·¢ÁËÒ»¸ö `@Component`£¬Ê¹ÓÃÁËÒ»¸ö `name` ÊôÐÔ£¬ÈçÏÂÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Component
+public class MyBean {
+
+ @Value("${name}")
+ private String name;
+
+ // ...
+
+}
+
+```
+
+
+
+
+
+
+
+ÔÚÄãµÄÓ¦ÓóÌÐòµÄclasspath£¨ÀýÈ磬ÔÚÄãµÄjarÖУ©£¬Äã¿ÉÒÔÓÐÒ»¸ö `application.properties` Îļþ£¬Îª `name` Ìṩһ¸öºÏÀíµÄĬÈÏÊôÐÔÖµ¡£µ±ÔÚÒ»¸öÐµĻ·¾³ÖÐÔËÐÐʱ£¬¿ÉÒÔÔÚÄãµÄjarÖ®ÍâÌṩһ¸ö `application.properties` ÎļþÀ´¸²¸Ç `name` ¡£¶ÔÓÚÒ»´ÎÐԵIJâÊÔ£¬Äã¿ÉÒÔÓÃÒ»¸öÌØ¶¨µÄÃüÁîÐвÎÊýÀ´Æô¶¯£¨ÀýÈ磬`java -jar app.jar --name="Spring"`£©¡£
+
+
+
+
+
+| | `env` ºÍ `configprops` ¶ËµãÔÚÈ·¶¨Ò»¸öÊôÐÔΪʲôÓÐÒ»¸öÌØ¶¨µÄֵʱ·Ç³£ÓÐÓá£Äã¿ÉÒÔʹÓÃÕâÁ½¸ö¶ËµãÀ´Õï¶ÏÒâÍâµÄÊôÐÔÖµ¡£Ïê¼û "[Éú²ú¾ÍÐ÷¹¦ÄÜ](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints)" ²¿·Ö¡£ |
+| --- | --- |
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.external-config.command-line-args)2.1\. ·ÃÎÊÃüÁîÐÐÊôÐÔ
+
+
+
+ĬÈÏÇé¿öÏ£¬`SpringApplication` »á½«ÈκÎÃüÁîÐÐÑ¡Ïî²ÎÊý£¨¼´ÒÔ `--` ¿ªÍ·µÄ²ÎÊý£¬Èç `--server.port=9000` £©×ª»»Îª `property` ²¢½«ÆäÌí¼Óµ½Spring `Environment` ÖС£ ÈçǰËùÊö£¬ÃüÁîÐÐÊôÐÔ×ÜÊÇÓÅÏÈÓÚ»ùÓÚÎļþµÄÊôÐÔÔ´¡£
+
+
+
+
+
+Èç¹ûÄ㲻ϣÍûÃüÁîÐÐÊôÐÔ±»Ìí¼Óµ½ `Environment` ÖУ¬Äã¿ÉÒÔͨ¹ý `SpringApplication.setAddCommandLineProperties(false)` ½ûÓÃËüÃÇ¡£
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.external-config.application-json)2.2\. JSON Application Properties
+
+
+
+»·¾³±äÁ¿ºÍϵͳÊôÐÔÍùÍùÓÐÏÞÖÆ£¬ÕâÒâζ×ÅÓÐЩÊôÐÔÃû³Æ²»ÄÜʹÓᣠΪÁ˰ïÖú½â¾öÕâ¸öÎÊÌ⣬Spring BootÔÊÐíÄ㽫һ¸öÊôÐÔ¿é±àÂëΪһ¸öµ¥Ò»µÄJSON½á¹¹¡£
+
+
+
+
+
+µ±ÄãµÄÓ¦ÓóÌÐòÆô¶¯Ê±£¬ÈκΠ`spring.application.json` »ò `SPRING_APPLICATION_JSON` ÊôÐÔ½«±»½âÎö²¢Ìí¼Óµ½ `Environment` ÖС£
+
+
+
+
+
+ÀýÈ磬`SPRING_APPLICATION_JSON` ÊôÐÔ¿ÉÒÔÔÚ UN*X shell µÄÃüÁîÐÐÖÐ×÷Ϊ»·¾³±äÁ¿Ìṩ¡£
+
+
+
+
+
+
+
+```
+$ SPRING_APPLICATION_JSON='{"my":{"name":"test"}}' java -jar myapp.jar
+```
+
+
+
+
+
+
+
+ÔÚÇ°ÃæµÄÀý×ÓÖУ¬ÄãÔÚSpringµÄ `Environment` ÖÐ×îÖյõ½ÁË `my.name=test`¡£
+
+
+
+
+
+ͬÑùµÄJSONÒ²¿ÉÒÔ×÷Ϊһ¸öϵͳÊôÐÔÌṩ¡£
+
+
+
+
+
+
+
+```
+$ java -Dspring.application.json='{"my":{"name":"test"}}' -jar myapp.jar
+```
+
+
+
+
+
+
+
+»òÕßÄã¿ÉÒÔͨ¹ýʹÓÃÒ»¸öÃüÁîÐвÎÊýÀ´ÌṩJSON¡£
+
+
+
+
+
+
+
+```
+$ java -jar myapp.jar --spring.application.json='{"my":{"name":"test"}}'
+```
+
+
+
+
+
+
+
+Èç¹ûÄãÒª²¿Êðµ½Ò»¸ö¾µäµÄÓ¦Ó÷þÎñÆ÷ÖУ¬ÄãÒ²¿ÉÒÔʹÓÃÒ»¸öÃûΪ `java:comp/env/spring.application.json` µÄJNDI±äÁ¿¡£
+
+
+
+
+
+| | ¾¡¹ÜJSONÖÐµÄ `null` Öµ½«±»Ìí¼Óµ½Éú³ÉµÄÊôÐÔÔ´ÖУ¬µ« `PropertySourcesPropertyResolver` ½« `null` ÊôÐÔÊÓΪȱʧֵ¡£ ÕâÒâζ×ÅJSON²»ÄÜÓà `null` Öµ¸²¸ÇÀ´×Եͽ×ÊôÐÔÔ´µÄÊôÐÔ¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.external-config.files)2.3\. ÍⲿµÄ Application Properties
+
+
+
+µ±ÄãµÄÓ¦ÓóÌÐòÆô¶¯Ê±£¬Spring Boot»á×Ô¶¯´ÓÒÔÏÂλÖÃÕÒµ½²¢¼ÓÔØ `application.properties` ºÍ `application.yaml` Îļþ¡£
+
+
+
+
+
+1. classpath
+
+
+
+ 1. classpath ¸ù·¾¶
+
+ 2. classpath Ï嵀 `/config` °ü
+
+
+
+2. µ±Ç°Ä¿Â¼
+
+
+
+ 1. µ±Ç°Ä¿Â¼ÏÂ
+
+ 2. µ±Ç°Ä¿Â¼Ï嵀 `config/` ×ÓĿ¼
+
+ 3. `config/` ×ÓĿ¼µÄÖ±½Ó×ÓĿ¼
+
+
+
+
+
+
+
+ÁÐ±í°´ÓÅÏȼ¶ÅÅÐò£¨½ÏµÍÏîÄ¿µÄÖµ¸²¸Ç½ÏÔçÏîÄ¿µÄÖµ£©¡£ ¼ÓÔØµÄÎļþ±»×÷Ϊ `PropertySources` Ìí¼Óµ½SpringµÄ `Environment` ÖС£
+
+
+
+
+
+Èç¹ûÄ㲻ϲ»¶ `application` ×÷ΪÅäÖÃÎļþÃû³Æ£¬Äã¿ÉÒÔͨ¹ýÖ¸¶¨ `spring.config.name` »·¾³ÊôÐÔÇл»µ½ÁíÒ»¸öÎļþÃû³Æ¡£ ÀýÈ磬ΪÁËѰÕÒ `myproject.properties` ºÍ `myproject.yaml` Îļþ£¬Äã¿ÉÒÔ°´ÒÔÏ·½Ê½ÔËÐÐÄãµÄÓ¦ÓóÌÐò¡£
+
+
+
+
+
+
+
+```
+$ java -jar myproject.jar --spring.config.name=myproject
+```
+
+
+
+
+
+
+
+ÄãÒ²¿ÉÒÔͨ¹ýʹÓà `spring.config.location` »·¾³ÊôÐÔÀ´ÒýÓÃÒ»¸öÃ÷È·µÄλÖᣠ¸ÃÊôÐÔ½ÓÊÜÒ»¸ö¶ººÅ·Ö¸ôµÄÁÐ±í£¬ÆäÖаüº¬Ò»¸ö»ò¶à¸öÒª¼ì²éµÄλÖá£
+
+
+
+
+
+ÏÂÃæµÄÀý×ÓÏÔʾÁËÈçºÎÖ¸¶¨Á½¸ö²»Í¬µÄÎļþ¡£
+
+
+
+
+
+
+
+```
+$ java -jar myproject.jar --spring.config.location=\
+ optional:classpath:/default.properties,\
+ optional:classpath:/override.properties
+```
+
+
+
+
+
+
+
+| | Èç¹û [ÅäÖÃÎļþÊÇ¿ÉÑ¡µÄ](https://springdoc.cn/spring-boot/features.html#features.external-config.files.optional-prefix)£¬²¢ÇÒ¿ÉÒÔÊDz»´æÔڵģ¬ÄÇôÇëʹÓà `optional:` ǰ׺¡£ |
+| --- | --- |
+
+
+
+
+
+| | `spring.config.name`, `spring.config.location`, ºÍ `spring.config.extra-location` ºÜÔç¾ÍÓÃÀ´È·¶¨ÄÄЩÎļþ±ØÐë±»¼ÓÔØ¡£ ËüÃDZØÐë±»¶¨ÒåΪ»·¾³ÊôÐÔ£¨Í¨³£ÊDzÙ×÷ϵͳ»·¾³±äÁ¿£¬ÏµÍ³ÊôÐÔ£¬»òÃüÁîÐвÎÊý£©¡£ |
+| --- | --- |
+
+
+
+
+
+Èç¹û `spring.config.location` °üº¬Ä¿Â¼£¨¶ø²»ÊÇÎļþ£©£¬ËüÃÇÓ¦¸ÃÒÔ `/` ½áβ¡£ ÔÚÔËÐÐʱ£¬ËüÃǽ«±»¸½¼ÓÉÏÓÉ `spring.config.name` Éú³ÉµÄÃû³Æ£¬È»ºó±»¼ÓÔØ¡£ ÔÚ `spring.config.location` ÖÐÖ¸¶¨µÄÎļþ±»Ö±½Óµ¼Èë¡£
+
+
+
+
+
+| | Ŀ¼ºÍÎļþλÖÃÖµÒ²±»À©Õ¹£¬ÒÔ¼ì²é[ÌØ¶¨µÄÅäÖÃÎļþ](https://springdoc.cn/spring-boot/features.html#features.external-config.files.profile-specific)¡£ÀýÈ磬Èç¹ûÄãµÄ `spring.config.location` ÊÇ `classpath:myconfig.properties`£¬ÄãÒ²»á·¢ÏÖÊʵ±µÄ `classpath:myconfig-.properties` Îļþ±»¼ÓÔØ¡£ |
+| --- | --- |
+
+
+
+
+
+ÔÚ´ó¶àÊýÇé¿öÏ£¬ÄãÌí¼ÓµÄÿ¸ö `spring.config.location` ÏÒýÓÃÒ»¸öÎļþ»òĿ¼¡£ λÖÃÊǰ´ÕÕËüÃDZ»¶¨ÒåµÄ˳ÐòÀ´´¦ÀíµÄ£¬ºóÃæµÄλÖÿÉÒÔ¸²¸ÇÇ°ÃæµÄλÖõÄÖµ¡£
+
+
+
+
+
+Èç¹ûÄãÓÐÒ»¸ö¸´ÔÓµÄλÖÃÉèÖ㬶øÇÒÄãʹÓÃÌØ¶¨µÄÅäÖÃÎļþ£¬Äã¿ÉÄÜÐèÒªÌṩ½øÒ»²½µÄÌáʾ£¬ÒÔ±ãSpring BootÖªµÀËüÃÇÓ¦¸ÃÈçºÎ·Ö×é¡£Ò»¸öλÖÃ×éÊÇÒ»¸öλÖõļ¯ºÏ£¬ÕâЩλÖö¼±»ÈÏΪÊÇÔÚͬһ¼¶±ð¡£ÀýÈ磬Äã¿ÉÄÜÏë°ÑËùÓÐclasspathλÖ÷Ö×飬ȻºóÊÇËùÓÐÍⲿλÖá£Ò»¸öλÖÃ×éÄÚµÄÏîĿӦ¸ÃÓà `;` ·Ö¸ô¡£¸ü¶àϸ½Ú¼û ¡°[Ö¸¶¨ profile](https://springdoc.cn/spring-boot/features.html#features.external-config.files.profile-specific)¡± ²¿·ÖµÄÀý×Ó¡£
+
+
+
+
+
+ͨ¹ýʹÓà `spring.config.location` ÅäÖõÄλÖÃÈ¡´úĬÈÏλÖᣠÀýÈ磬Èç¹û `spring.config.location` ±»ÅäÖÃΪ `optional:classpath:/custom-config/,optional:file:./custom-config/` £¬¿¼ÂǵÄÍêÕûλÖü¯ÈçÏ¡£
+
+
+
+
+
+1. `optional:classpath:custom-config/`
+
+2. `optional:file:./custom-config/`
+
+
+
+
+
+Èç¹ûÄãϲ»¶Ìí¼Ó¶îÍâµÄλÖ㬶ø²»ÊÇÌæ»»ËüÃÇ£¬Äã¿ÉÒÔʹÓà `spring.config.extra-location` ¡£ ´Ó¸½¼ÓλÖüÓÔØµÄÊôÐÔ¿ÉÒÔ¸²¸ÇĬÈÏλÖõÄÊôÐÔ¡£ ÀýÈ磬Èç¹û `spring.config.extra-location` ±»ÅäÖÃΪ `optional:classpath:/custom-config/,optional:file:./custom-config/` £¬¿¼ÂǵÄÍêÕûλÖü¯ÈçÏ¡£
+
+
+
+
+
+1. `optional:classpath:/;optional:classpath:/config/`
+
+2. `optional:file:./;optional:file:./config/;optional:file:./config/*/`
+
+3. `optional:classpath:custom-config/`
+
+4. `optional:file:./custom-config/`
+
+
+
+
+
+ÕâÖÖËÑË÷ÅÅÐòÈÃÄãÔÚÒ»¸öÅäÖÃÎļþÖÐÖ¸¶¨Ä¬ÈÏÖµ£¬È»ºóÔÚÁíÒ»¸öÎļþÖÐÑ¡ÔñÐԵظ²¸ÇÕâЩֵ¡£ Äã¿ÉÒÔÔÚÆäÖÐÒ»¸öĬÈÏλÖÃµÄ `application.properties` £¨»òÄãÓà `spring.config.name` Ñ¡ÔñµÄÆäËûbasename£©ÖÐΪÄãµÄÓ¦ÓóÌÐòÌṩĬÈÏÖµ¡£ È»ºó£¬ÕâЩĬÈÏÖµ¿ÉÒÔÔÚÔËÐÐʱ±»Î»ÓÚÆäÖÐÒ»¸ö×Ô¶¨ÒåλÖõIJ»Í¬Îļþ¸²¸Ç¡£
+
+
+
+
+
+| | Èç¹ûÄãʹÓû·¾³±äÁ¿¶ø²»ÊÇϵͳÊôÐÔ£¬´ó¶àÊý²Ù×÷ϵͳ²»ÔÊÐíʹÓþäµã·Ö¸ôµÄ¼üÃû£¬µ«Äã¿ÉÒÔʹÓÃÏ»®Ïß´úÌæ£¨ÀýÈ磬 `SPRING_CONFIG_NAME` ¶ø²»ÊÇ `spring.config.name` £©¡£ ²Î¼û[´Ó»·¾³±äÁ¿°ó¶¨](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables) Á˽âÏêÇé¡£ |
+| --- | --- |
+
+
+
+
+
+| | Èç¹ûÄãµÄÓ¦ÓóÌÐòÔÚservletÈÝÆ÷»òÓ¦Ó÷þÎñÆ÷ÖÐÔËÐУ¬ÄÇôJNDIÊôÐÔ£¨ÔÚ `java:comp/env` ÖУ©»òservletÉÏÏÂÎijõʼ»¯²ÎÊý¿ÉÒÔ´úÌæ»·¾³±äÁ¿»òϵͳÊôÐÔ£¬»òÕßÓëÖ®Ò»Ñù¡£ |
+| --- | --- |
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.files.optional-prefix)2.3.1\. ¿ÉÑ¡µÄλÖÃ(Optional Locations)
+
+
+
+ĬÈÏÇé¿öÏ£¬µ±Ö¸¶¨µÄÅäÖÃÊý¾ÝλÖò»´æÔÚʱ£¬Spring Boot½«Å׳öÒ»¸ö `ConfigDataLocationNotFoundException` £¬ÄãµÄÓ¦ÓóÌÐò½«ÎÞ·¨Æô¶¯¡£
+
+
+
+
+
+Èç¹ûÄãÏëÖ¸¶¨Ò»¸öλÖ㬵«Äã²»½éÒâËü²¢²»×ÜÊÇ´æÔÚ£¬Äã¿ÉÒÔʹÓà `optional:` ǰ׺¡£Äã¿ÉÒÔÔÚ `spring.config.locationºÍspring.config.extra-location` ÊôÐÔÖÐʹÓÃÕâ¸öǰ׺£¬Ò²¿ÉÒÔÔÚ [`spring.config.import`](https://springdoc.cn/spring-boot/features.html#features.external-config.files.importing) ÉùÃ÷ÖÐʹÓá£
+
+
+
+
+
+ÀýÈ磬`spring.config.import` ֵΪ `optional:file:./myconfig.properties` ÔÊÐíÄãµÄÓ¦ÓóÌÐòÆô¶¯£¬¼´Ê¹ `myconfig.properties` Îļþ¶ªÊ§¡£
+
+
+
+
+
+Èç¹ûÄãÏëºöÂÔËùÓÐµÄ `ConfigDataLocationNotFoundExceptions` ²¢Ê¼ÖÕ¼ÌÐøÆô¶¯ÄãµÄÓ¦ÓóÌÐò£¬Äã¿ÉÒÔʹÓà `spring.config.on-not-found` ÊôÐÔ¡£ ʹÓà `SpringApplication.setDefaultProperties(..)` »òʹÓÃϵͳ/»·¾³±äÁ¿½«ÆäÖµÉèÖÃΪ `ignore`¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.files.wildcard-locations)2.3.2\. ͨÅä·ûµØÖ·
+
+
+
+Èç¹ûÒ»¸öÅäÖÃÎļþµÄλÖÃÔÚ×îºóÒ»¸ö·¾¶¶ÎÖаüº¬ `*` ×Ö·û£¬Ëü¾Í±»ÈÏΪÊÇÒ»¸öͨÅä·ûλÖᣠͨÅä·ûÔÚ¼ÓÔØÅäÖÃʱ±»À©Õ¹£¬Òò´Ë£¬Ö±½ÓµÄ×ÓĿ¼Ҳ±»¼ì²é¡£ ͨÅä·ûλÖÃÔÚKubernetesÕâÖÖÓжà¸öÅäÖÃÊôÐÔµÄÀ´Ô´µÄ»·¾³ÖÐÌØ±ðÓÐÓá£
+
+
+
+
+
+ÀýÈ磬Èç¹ûÄãÓÐһЩRedisÅäÖúÍһЩMySQLÅäÖã¬Äã¿ÉÄÜÏë°ÑÕâÁ½²¿·ÖÅäÖ÷ֿª£¬Í¬Ê±ÒªÇóÕâÁ½²¿·Ö¶¼´æÔÚÓÚÒ»¸ö `application.properties` ÎļþÖС£
+
+
+
+
+
+Õâ¿ÉÄܻᵼÖÂÁ½¸ö¶ÀÁ¢µÄ `application.properties` Îļþ¹ÒÔØÔÚ²»Í¬µÄλÖã¬Èç `/config/redis/application.properties` ºÍ `/config/mysql/application.properties` ¡£ ÔÚÕâÖÖÇé¿öÏ£¬ÓÐÒ»¸öͨÅä·ûλÖà `config/*/` £¬½«µ¼ÖÂÁ½¸öÎļþ±»´¦Àí¡£
+
+
+
+
+
+ĬÈÏÇé¿öÏ£¬Spring Boot½« `config/*/` ÁÐÈëĬÈÏËÑË÷λÖᣠÕâÒâζ×ÅÄãµÄjarÖ®ÍâµÄ `/config` Ŀ¼µÄËùÓÐ×ÓĿ¼¶¼»á±»ËÑË÷µ½¡£
+
+
+
+
+
+Äã¿ÉÒÔÔÚ `spring.config.location` ºÍ `spring.config.extra-location` ÊôÐÔÖÐʹÓÃͨÅä·ûλÖá£
+
+
+
+
+
+| | ͨÅä·ûλÖñØÐëÖ»°üº¬Ò»¸ö `*` ²¢ÒÔ `*/` ½á⣬ÓÃÓÚËÑË÷ÊôÓÚĿ¼µÄλÖ㬻ò `*/` ÓÃÓÚËÑË÷ÊôÓÚÎļþµÄλÖᣠ´øÓÐͨÅä·ûµÄλÖý«¸ù¾ÝÎļþÃûµÄ¾ø¶Ô·¾¶°´×Öĸ˳ÐòÅÅÐò¡£ |
+| --- | --- |
+
+
+
+
+
+| | ͨÅä·ûλÖÃÖ»¶ÔÍⲿĿ¼Æð×÷ÓᣠÄã²»ÄÜÔÚ `classpath:` λÖÃÖÐʹÓÃͨÅä·û¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.files.profile-specific)2.3.3\. ÌØ¶¨Îļþ£¨Profile Specific Files£©
+
+
+
+³ýÁË `application` ÊôÐÔÎļþ£¬Spring Boot»¹½«³¢ÊÔʹÓà `application-{profile}` µÄÃüÃû¹ßÀý¼ÓÔØprofileÌØ¶¨µÄÎļþ¡£ ÀýÈ磬Èç¹ûÄãµÄÓ¦ÓóÌÐò¼¤»îÁËÃûΪ `prod` µÄÅäÖÃÎļþ£¨`spring.profiles.active=prod`£©²¢Ê¹ÓÃYAMLÎļþ£¬ÄÇô `application.yml` ºÍ `application-prod.yml` ¶¼½«±»¿¼ÂÇ¡£
+
+
+
+
+
+ÌØ¶¨Îļþ(`profiles`)µÄÊôÐÔÓë±ê×¼µÄ `application.properties` µÄλÖÃÏàͬ£¬Ìض¨Îļþ×ÜÊÇÓÅÏÈÓÚ·ÇÌØ¶¨Îļþ¡£ Èç¹ûÖ¸¶¨Á˼¸¸öÅäÖÃÎļþ£¬Ôò²ÉÓÃ×îºóʤ³öµÄ²ßÂÔ¡£ ÀýÈ磬Èç¹ûÅäÖÃÎļþ `prod,live` ÊÇÓÉ `spring.profiles.active` ÊôÐÔÖ¸¶¨µÄ£¬`application-prod.properties` ÖеÄÖµ¿ÉÒÔ±» `application-live.properties` ÖеÄÖµËù¸²¸Ç¡£
+
+
+
+
+
+| | ×îºóʤ³öµÄ²ßÂÔÊÊÓÃÓÚ[location group](https://springdoc.cn/spring-boot/features.html#features.external-config.files.location-groups)¼¶±ð¡£ `spring.config.location` µÄ `classpath:/cfg/,classpath:/ext/` ½«²»»áÓÐÓë `classpath:/cfg/;classpath:/ext/` ÏàͬµÄ¸²¸Ç¹æÔò¡£ÀýÈ磬ÄÃÎÒÃÇÉÏÃæµÄ `prod,live` Àý×ÓÀ´Ëµ£¬ÎÒÃÇ¿ÉÄÜÓÐÒÔÏÂÎļþ¡£ /cfg application-live.properties/ext application-live.properties application-prod.properties µ±ÎÒÃÇÓÐÒ»¸ö `spring.config.location` Ϊ `classpath:/cfg/,classpath:/ext/` ʱ£¬ÎÒÃÇ»áÔÚËùÓÐ `/ext` Îļþ֮ǰ´¦ÀíËùÓÐ `/cfg` Îļþ¡£1. `/cfg/application-live.properties` 2. `/ext/application-prod.properties` 3. `/ext/application-live.properties` µ±ÎÒÃÇÓà `classpath:/cfg/;classpath:/ext/` ´úÌæÊ±£¨Óà `;` ·Ö¸ô·û£©£¬ÎÒÃÇÔÚͬһ¼¶±ð´¦Àí `/cfg` ºÍ `/ext` ¡£1. `/ext/application-prod.properties` 2. `/cfg/application-live.properties` 3. `/ext/application-live.properties` |
+| --- | --- |
+
+
+
+
+
+`Environment` ÓÐÒ»×éĬÈϵÄÅäÖÃÎļþ£¨Ä¬ÈÏΪ `[default]` £©£¬Èç¹ûûÓÐÉèÖûµÄÅäÖÃÎļþ£¬¾Í»áʹÓÃÕâЩÅäÖÃÎļþ¡£ »»¾ä»°Ëµ£¬Èç¹ûûÓÐÃ÷È·¼¤»îµÄÅäÖÃÎļþ£¬ÄÇô¾Í»á¿¼ÂÇÀ´×Ô `application-default` µÄÊôÐÔ¡£
+
+
+
+
+
+| | ÊôÐÔÎļþÖ»±»¼ÓÔØÒ»´Î¡£ Èç¹ûÄãÒѾֱ½Ó[µ¼ÈëÁË](https://springdoc.cn/spring-boot/features.html#features.external-config.files.importing)Ò»¸öÅäÖÃÎļþµÄÌØ¶¨ÊôÐÔÎļþ£¬ÄÇôËü½«²»»á±»µÚ¶þ´Îµ¼Èë¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.files.importing)2.3.4\. µ¼Èë¶îÍâµÄÊý¾Ý
+
+
+
+application properties ÖпÉÒÔʹÓà `spring.config.import` ÊôÐÔ´ÓÆäËûµØ·½µ¼Èë¸ü¶àµÄÅäÖÃÊý¾Ý¡£ µ¼ÈëÔÚ±»·¢ÏÖʱ±»´¦Àí£¬²¢±»ÊÓΪ½ô½Ó×ÅÉùÃ÷µ¼ÈëµÄÎļþÏÂÃæ²åÈëµÄ¶îÍâÎļþ¡£
+
+
+
+
+
+ÀýÈ磬Äã¿ÉÄÜÔÚÄãµÄ classpath `application.properties` ÎļþÖÐÓÐÒÔÏÂÄÚÈÝ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+spring.application.name=myapp
+spring.config.import=optional:file:./dev.properties
+
+```
+
+
+
+
+
+
+
+Õ⽫´¥·¢µ¼È뵱ǰĿ¼Ï嵀 `dev.properties` Îļþ£¨Èç¹û´æÔÚÕâÑùµÄÎļþ£©¡£ µ¼ÈëµÄ `dev.properties` ÖеÄÖµ½«ÓÅÏÈÓÚ´¥·¢µ¼ÈëµÄÎļþ¡£ ÔÚÉÏÃæµÄÀý×ÓÖУ¬`dev.properties` ¿ÉÒÔ½« `spring.application.name` ÖØÐ¶¨ÒåΪһ¸ö²»Í¬µÄÖµ¡£
+
+
+
+
+
+Ò»¸öµ¼ÈëÖ»»á±»µ¼ÈëÒ»´Î£¬ÎÞÂÛËü±»ÉùÃ÷¶àÉٴΡ£ Ò»¸öµ¼ÈëÔÚproperties/yamlÎļþÄڵĵ¥¸öÎļþÖб»¶¨ÒåµÄ˳Ðò²¢²»ÖØÒª¡£ ÀýÈ磬ÏÂÃæµÄÁ½¸öÀý×Ó²úÉúÏàͬµÄ½á¹û¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+spring.config.import=my.properties
+my.property=value
+
+```
+
+
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+my.property=value
+spring.config.import=my.properties
+
+```
+
+
+
+
+
+
+
+ÔÚÉÏÊöÁ½¸öÀý×ÓÖУ¬`my.properties` ÎļþµÄÖµ½«ÓÅÏÈÓÚ´¥·¢Æäµ¼ÈëµÄÎļþ¡£
+
+
+
+
+
+ÔÚÒ»¸öµ¥Ò»µÄ `spring.config.import` ÊôÐÔÏ¿ÉÒÔÖ¸¶¨¶à¸öλÖᣠλÖý«°´ÕÕËüÃDZ»¶¨ÒåµÄ˳Ðò±»´¦Àí£¬ºóÀ´µÄµ¼È뽫±»ÓÅÏÈ´¦Àí¡£
+
+
+
+
+
+| | ÔÚÊʵ±µÄʱºò£¬[ÌØ¶¨ÅäÖÃÎļþµÄ±äÌå](https://springdoc.cn/spring-boot/features.html#features.external-config.files.profile-specific)Ò²±»¿¼Âǵ¼Èë¡£ ÉÏÃæµÄÀý×Ó½«µ¼Èë `my.properties` ÒÔ¼°ÈκΠ`my-.properties` ±äÌå¡£ |
+| --- | --- |
+
+
+
+
+
+| | Spring Boot ÌṩÁ˿ɲå°ÎµÄAPI£¨²å¼þ£©£¬ÔÊÐíÖ§³Ö¸÷ÖÖ²»Í¬µÄλÖõØÖ·¡£ ĬÈÏÇé¿öÏ£¬Äã¿ÉÒÔµ¼ÈëJava Properties¡¢YAMLºÍ ¡°[ÅäÖÃÊ÷](https://springdoc.cn/spring-boot/features.html#features.external-config.files.configtree)¡± ¡£µÚÈý·½jar¿ÉÒÔÌṩ¶ÔÆäËû¼¼ÊõµÄÖ§³Ö£¨²»ÒªÇó±ØÐëÊDZ¾µØÎļþ£©¡£ ÀýÈ磬Äã¿ÉÒÔÏëÏóÅäÖÃÊý¾ÝÀ´×ÔÍⲿ´æ´¢£¬ÈçConsul¡¢Apache ZooKeeper»òNetflix Archaius£¨°üÀ¨Nacos£©¡£Èç¹ûÄãÏëÖ§³ÖÄã×Ô¼ºµÄλÖã¨ÊµÏÖ×Ô¼º¶¨ÒåµÄÅäÖüÓÔØ£©£¬Çë²ÎÔÄ `org.springframework.boot.context.config` °üÖÐµÄ `ConfigDataLocationResolver` ºÍ `ConfigDataLoader` Àà¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.files.importing-extensionless)2.3.5\. µ¼ÈëÎÞÀ©Õ¹ÃûµÄÎļþ
+
+
+
+ÓÐÐ©ÔÆÆ½Ì¨²»ÄÜΪ¾í×°Îļþ£¨volume mounted files£©Ìí¼ÓÎļþÀ©Õ¹Ãû¡£ Òªµ¼ÈëÕâЩÎÞÀ©Õ¹ÃûµÄÎļþ£¬ÄãÐèÒª¸øSpring BootÒ»¸öÌáʾ£¬ÒÔ±ãËüÖªµÀÈçºÎ¼ÓÔØËüÃÇ¡£ Äã¿ÉÒÔͨ¹ý°ÑÀ©Õ¹ÃûÌáʾ·ÅÔÚ·½À¨ºÅÀïÀ´×öµ½ÕâÒ»µã¡£
+
+
+
+
+
+ÀýÈ磬¼ÙÉèÄãÓÐÒ»¸ö `/etc/config/myconfig` Îļþ£¬ÄãÏ£ÍûÒÔyamlÐÎʽµ¼Èë¡£ Äã¿ÉÒÔÓÃÏÂÃæµÄ·½·¨´ÓÄãµÄ `application.properties` Öе¼ÈëËü¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+spring.config.import=file:/etc/config/myconfig[.yaml]
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.files.configtree)2.3.6\. ʹÓÃÅäÖÃÊ÷£¨Configuration Trees£©
+
+
+
+µ±ÔÚÔÆÆ½Ì¨£¨ÈçKubernetes£©ÉÏÔËÐÐÓ¦ÓóÌÐòʱ£¬Äã¾³£ÐèÒª¶Áȡƽ̨ÌṩµÄÅäÖÃÖµ¡£ ½«»·¾³±äÁ¿ÓÃÓÚ´ËÀàÄ¿µÄ²¢²»ÉÙ¼û£¬µ«Õâ¿ÉÄÜÓÐȱµã£¬ÌرðÊÇÈç¹û¸ÃÖµÊÇ secret µÄ¡£
+
+
+
+
+
+×÷Ϊ»·¾³±äÁ¿µÄÌæ´ú·½°¸£¬Ðí¶àÔÆÆ½Ì¨ÏÖÔÚÔÊÐíÄ㽫ÅäÖÃÓ³Éäµ½¹ÒÔØµÄÊý¾Ý¾í¡£ ÀýÈ磬Kubernetes ¿ÉÒÔ¾í¹ÒÔØ [`ConfigMaps`](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#populate-a-volume-with-data-stored-in-a-configmap) ºÍ [`Secrets`](https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-files-from-a-pod)¡£
+
+
+
+
+
+¿ÉÒÔʹÓÃÁ½ÖÖ³£¼ûµÄ volume ¹ÒÔØÄ£Ê½£º
+
+
+
+
+
+1. Ò»¸öÎļþ°üº¬Ò»Ì×ÍêÕûµÄÊôÐÔ£¨Í¨³£Ð´³ÉYAML£©¡£
+
+2. ¶à¸öÎļþ±»Ð´ÈëÒ»¸öĿ¼Ê÷ÖУ¬ÎļþÃû³ÉΪ ¡®key¡¯£¬ÄÚÈݳÉΪ ¡®value¡¯¡£
+
+
+
+
+
+¶ÔÓÚµÚÒ»ÖÖÇé¿ö£¬Äã¿ÉÒÔʹÓà `spring.config.import` Ö±½Óµ¼ÈëYAML»òÊôÐÔÎļþ£¬[ÈçÉÏËùÊö](https://springdoc.cn/spring-boot/features.html#features.external-config.files.importing)¡£ ¶ÔÓÚµÚ¶þÖÖÇé¿ö£¬ÄãÐèҪʹÓà `configtree:` ǰ׺£¬ÒÔ±ãSpring BootÖªµÀËüÐèÒª½«ËùÓÐÎļþ×÷ΪÊôÐÔ¹«¿ª¡£
+
+
+
+
+
+¾Ù¸öÀý×Ó£¬ÈÃÎÒÃÇÏëÏóһϣ¬KubernetesÒѾ¹ÒÔØÁËÒÔÏÂvolume¡£
+
+
+
+
+
+
+
+ etc/
+ config/
+ myapp/
+ username
+ password
+
+
+
+
+
+
+
+`username` ÎļþµÄÄÚÈݽ«ÊÇÒ»¸öÅäÖÃÖµ£¬¶ø `password` µÄÄÚÈݽ«ÊÇÒ»¸ö secret¡£
+
+
+
+
+
+Òªµ¼ÈëÕâЩÊôÐÔ£¬Äã¿ÉÒÔÔÚÄãµÄ `application.properties` »ò `application.yaml` ÎļþÖÐÌí¼ÓÒÔÏÂÄÚÈÝ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+spring.config.import=optional:configtree:/etc/config/
+
+```
+
+
+
+
+
+
+
+È»ºóÄã¿ÉÒÔ´Ó `Environment` ÖÐÒÔ³£¹æ·½Ê½·ÃÎÊ»ò×¢Èë `myapp.username` ºÍ `myapp.password` ÊôÐÔ¡£
+
+
+
+
+
+| | ÅäÖÃÊ÷ϵÄÎļþ¼Ð¹¹³ÉÁËÊôÐÔÃû³Æ¡£ ÔÚÉÏÃæµÄÀý×ÓÖУ¬ÎªÁË·ÃÎÊÊôÐÔΪ `username` ºÍ `password`£¬Äã¿ÉÒÔ½« `spring.config.import` ÉèÖÃΪ `optional:configtree:/etc/config/myapp` ¡£ |
+| --- | --- |
+
+
+
+
+
+| | ´øÓеã·ûºÅµÄÎļþÃûÒ²»á±»ÕýÈ·Ó³Éä¡£ ÀýÈ磬ÔÚÉÏÃæµÄÀý×ÓÖУ¬`/etc/config` ÖÐÃûΪ `myapp.username` µÄÎļþÔÚ `Environment` ÖеÄÊôÐÔÃû½«»áÊÇ `myapp.username` ¡£ |
+| --- | --- |
+
+
+
+
+
+| | ÅäÖÃÊ÷µÄÖµ¿ÉÒÔ±»°ó¶¨µ½×Ö·û´® `String` ºÍ `byte[]` ÀàÐÍ£¬ÕâÈ¡¾öÓÚÔ¤ÆÚµÄÄÚÈÝ¡£ |
+| --- | --- |
+
+
+
+
+
+Èç¹ûÄãÓжà¸öÅäÖÃÊ÷Òª´Óͬһ¸ö¸¸Îļþ¼Ðµ¼È룬Äã¿ÉÒÔʹÓÃͨÅä·û¿ì½Ý·½Ê½¡£ ÈκÎÒÔ `/*/` ½áβµÄ `configtree:` λÖý«µ¼ÈëËùÓÐÖ±½ÓµÄ×ÓÎļþ¼Ð×÷ΪÅäÖÃÊ÷¡£
+
+
+
+
+
+ÀýÈ磬¸ø¶¨ÒÔÏÂvolume£º
+
+
+
+
+
+
+
+ etc/
+ config/
+ dbconfig/
+ db/
+ username
+ password
+ mqconfig/
+ mq/
+ username
+ password
+
+
+
+
+
+
+
+Äã¿ÉÒÔʹÓà `configtree:/etc/config/*/` ×÷Ϊµ¼ÈëλÖá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+spring.config.import=optional:configtree:/etc/config/*/
+
+```
+
+
+
+
+
+
+
+Õ⽫Ìí¼Ó `db.username`¡¢`db.password`¡¢`mq.username` ºÍ `mq.password` ÊôÐÔ¡£
+
+
+
+
+
+| | ʹÓÃͨÅä·û¼ÓÔØµÄĿ¼Êǰ´×Öĸ˳ÐòÅÅÁеġ£ Èç¹ûÄãÐèÒªÒ»¸ö²»Í¬µÄ˳Ðò£¬ÄÇôÄãÓ¦¸Ã°Ñÿ¸öλÖÃ×÷Ϊһ¸öµ¥¶ÀµÄµ¼ÈëÁгö¡£ |
+| --- | --- |
+
+
+
+
+
+ÅäÖÃÊ÷Ò²¿ÉÓÃÓÚDocker secret¡£ µ±Docker swarm·þÎñ±»ÊÚÓè¶ÔsecretµÄ·ÃÎÊȨʱ£¬¸Ãsecret»á±»×°Ôص½ÈÝÆ÷ÖС£ ÀýÈ磬Èç¹ûÒ»¸öÃûΪ `db.password` µÄsecret¡£±»¹ÒÔØÔÚ `/run/secrets/` µÄλÖã¬Äã¿ÉÒÔÓÃÒÔÏ·½·¨Èà `db.password` ¶ÔSpring»·¾³¿ÉÓá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+spring.config.import=optional:configtree:/run/secrets/
+
+```
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.files.property-placeholders)2.3.7\. ÊôÐÔռλ·û
+
+
+
+`application.properties` ºÍ `application.yml` ÖеÄÖµÔÚʹÓÃʱͨ¹ýÏÖÓÐµÄ `Environment` ¹ýÂË£¬ËùÒÔÄã¿ÉÒԲο¼ÒÔǰ¶¨ÒåµÄÖµ£¨ÀýÈ磬À´×ÔϵͳÊôÐÔ»ò»·¾³±äÁ¿£©¡£ ±ê×¼µÄ `${name}` ÊôÐÔռλ·ûÓï·¨¿ÉÒÔÓÃÔÚÒ»¸öÖµµÄÈκεط½¡£ ÊôÐÔռλ·ûÒ²¿ÉÒÔÖ¸¶¨Ò»¸öĬÈÏÖµ£¬Ê¹Óà `:` À´·Ö¸ôĬÈÏÖµºÍÊôÐÔÃû³Æ£¬ÀýÈç `${name:default}` ¡£
+
+
+
+
+
+ÏÂÃæµÄÀý×ÓÏÔʾÁË´øÄ¬ÈÏÖµºÍ²»´øÄ¬ÈÏÖµµÄռλ·ûµÄʹÓÃÇé¿ö¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+app.name=MyApp
+app.description=${app.name} is a Spring Boot application written by ${username:Unknown}
+
+```
+
+
+
+
+
+
+
+¼ÙÉè `username` ÊôÐÔûÓÐÔÚÆäËûµØ·½ÉèÖã¬`app.description` µÄÖµ½«ÊÇ `MyApp is a Spring Boot application written by Unknown`¡£
+
+
+
+
+
+| | ÄãÓ¦¸ÃʼÖÕʹÓÃռλ·ûÖеÄÊôÐÔÃû³ÆµÄ¹æ·¶ÐÎʽ£¨½öʹÓÃСд×ÖĸµÄkebab-case£©À´ÒýÓÃËüÃÇ¡£ Õ⽫ÔÊÐíSpring BootʹÓÃÓë[¿íËɰó¶¨](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.relaxed-binding) `@ConfigurationProperties` ʱÏàͬµÄÂß¼¡£ÀýÈ磬`${demo.item-price}` ½«´Ó `application.properties` ÎļþÖлñÈ¡ `demo.item-price` ºÍ `demo.itemPrice` ÐÎʽµÄÊôÐÔ£¬ÒÔ¼°´Óϵͳ»·¾³ÖлñÈ¡ `DEMO_ITEMPRICE` ¡£ Èç¹ûÄãÓà `${demo.itemPrice}` µÄ»°£¬ `demo.item-price` ºÍ `DEMO_ITEMPRICE` ¾Í²»»á±»¿¼ÂÇ¡£ |
+| --- | --- |
+
+
+
+
+
+| | ÄãÒ²¿ÉÒÔʹÓÃÕâÖÖ¼¼ÊõÀ´´´½¨ÏÖÓÐSpring BootÊôÐ﵀ ¡°short¡± ±äÌå¡£ ÏêÇéÇë²Î¼û_[howto.html](https://springdoc.cn/spring-boot/howto.html#howto.properties-and-configuration.short-command-line-arguments)_µÄ·½·¨¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.files.multi-document)2.3.8\. ʹÓöàÎĵµÎļþ£¨Working with Multi-Document Files£©
+
+
+
+Spring BootÔÊÐíÄ㽫һ¸öÎïÀíÎļþ·Ö³É¶à¸öÂß¼Îļþ£¬Ã¿¸öÎļþ¶¼ÊǶÀÁ¢Ìí¼ÓµÄ¡£ ÎļþÊǰ´Ë³Ðò´¦ÀíµÄ£¬´ÓÉϵ½Ï¡£ ºóÃæµÄÎļþ¿ÉÒÔ¸²¸ÇÇ°ÃæÎļþÖж¨ÒåµÄÊôÐÔ¡£
+
+
+
+
+
+¶ÔÓÚ `application.yml` Îļþ£¬Ê¹Óñê×¼µÄYAML¶àÎĵµÓï·¨¡£ Èý¸öÁ¬ÐøµÄÁ¬×Ö·û£¨`---`£©´ú±íÒ»¸öÎļþµÄ½áÊø£¬ºÍÏÂÒ»¸öÎļþµÄ¿ªÊ¼¡£
+
+
+
+
+
+ÀýÈ磬ÏÂÃæµÄÎļþÓÐÁ½¸öÂß¼Îĵµ¡£
+
+
+
+
+
+
+
+```
+spring:
+ application:
+ name: "MyApp"
+---
+spring:
+ application:
+ name: "MyCloudApp"
+ config:
+ activate:
+ on-cloud-platform: "kubernetes"
+```
+
+
+
+
+
+
+
+¶ÔÓÚ `application.properties` Îļþ£¬Ò»¸öÌØÊâµÄ `#---` »ò `!---` ×¢Êͱ»ÓÃÀ´±ê¼ÇÎļþµÄ·Ö¸î¡£
+
+
+
+
+
+
+
+```
+spring.application.name=MyApp
+#---
+spring.application.name=MyCloudApp
+spring.config.activate.on-cloud-platform=kubernetes
+```
+
+
+
+
+
+
+
+| | properties ÎļþµÄ·Ö¸ô·û²»ÄÜÓÐÈκÎǰµ¼¿Õ°×£¬²¢ÇÒ±ØÐëÕýºÃÓÐÈý¸öÁ¬×Ö·û¡£ ·Ö¸ô·ûµÄǰºóÁ½Ðв»ÄÜÊÇÏàͬµÄ×¢ÊÍǰ׺¡£ |
+| --- | --- |
+
+
+
+
+
+| | ¶àÎĵµÊôÐÔÎļþͨ³£Ó뼤»îÊôÐÔÒ»ÆðʹÓã¬Èç `spring.config.activated.on-profile`¡£ Ïê¼û[ÏÂÒ»½Ú](https://springdoc.cn/spring-boot/features.html#features.external-config.files.activation-properties)¡£ |
+| --- | --- |
+
+
+
+
+
+| | ¶àÎĵµÊôÐÔÎļþ²»ÄÜͨ¹ýʹÓà `@PropertySource` »ò `@TestPropertySource` ×¢½â¼ÓÔØ¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.files.activation-properties)2.3.9\. ¼¤»îÊôÐÔ£¨Activation Properties£©
+
+
+
+ÓÐʱ£¬Ö»ÔÚÂú×ãijЩÌõ¼þʱ¼¤»îÒ»×éÌØ¶¨µÄÊôÐÔÊǺÜÓÐÓõġ£ ÀýÈ磬Äã¿ÉÄÜÓÐһЩÊôÐÔÖ»ÓÐÔÚÌØ¶¨µÄÅäÖÃÎļþ±»¼¤»îʱ²ÅÏà¹Ø¡£
+
+
+
+
+
+Äã¿ÉÒÔʹÓà `spring.config.activation.*` ÓÐÌõ¼þµØ¼¤»îÒ»¸öÊôÐÔÎļþ¡£
+
+
+
+
+
+¼¤»îÊôÐÔÓÐÈçÏ¡£
+
+
+
+Table 2\. activation properties
+| ÊôÐÔ | ˵Ã÷ |
+| --- | --- |
+| `on-profile` | Ò»¸ö±ØÐëÓë֮ƥÅäµÄÅäÖÃÎļþ±í´ïʽ£¬ÒÔʹÎļþ´¦Óڻ״̬£¨¼¤»îÖ¸¶¨µÄÅäÖÃÎļþʱÓÐЧ£©¡£ |
+| `on-cloud-platform` | ±ØÐë¼ì²âµ½µÄ `CloudPlatform`£¬ÒÔʹÎļþ´¦Óڻ״̬¡££¨ÔÆÆ½Ì¨×´Ì¬ÏÂÓÐЧ£© |
+
+
+
+ÀýÈ磬ÏÂÃæÖ¸¶¨µÚ¶þ¸öÎļþÖ»ÓÐÔÚKubernetesÉÏÔËÐÐʱ²ÅÓÐЧ£¬²¢ÇÒÖ»ÓÐÔÚ ¡°prod¡± »ò ¡°staging¡± ÅäÖÃÎļþ´¦Óڻ״̬ʱ²ÅÓÐЧ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+myprop=always-set
+#---
+spring.config.activate.on-cloud-platform=kubernetes
+spring.config.activate.on-profile=prod | staging
+myotherprop=sometimes-set
+
+```
+
+
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.external-config.encrypting)2.4\. ¼ÓÃÜÅäÖÃÊôÐÔ£¨Encrypting Properties£©
+
+
+
+Spring BootûÓÐΪ¼ÓÃÜÊôÐÔÖµÌṩÈκÎÄÚÖÃÖ§³Ö£¬µ«ËüÌṩÁËHookm£¬¿ÉÒÔÓÃÀ´ÐÞ¸ÄSpring `Environment` Öаüº¬µÄÖµ¡£ `EnvironmentPostProcessor` ½Ó¿ÚÔÊÐíÄãÔÚÓ¦ÓóÌÐòÆô¶¯Ç°²Ù×÷ `Environment`¡£ ²Î¼û[howto.html](https://springdoc.cn/spring-boot/howto.html#howto.application.customize-the-environment-or-application-context)ÒÔÁ˽âÏêÇé¡£
+
+
+
+
+
+Èç¹ûÄãÐèÒªÒ»ÖÖ°²È«µÄ·½Ê½À´´æ´¢Æ¾Ö¤ºÍÃÜÂ룬 [Spring Cloud Vault](https://cloud.spring.io/spring-cloud-vault/) ÏîÄ¿ÌṩÁ˶ÔÔÚ [HashiCorp Vault](https://www.vaultproject.io/)Öд洢Íⲿ»¯ÅäÖõÄÖ§³Ö¡£
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.external-config.yaml)2.5\. ʹÓà YAML
+
+
+
+[YAML](https://yaml.org/) ÊÇJSONµÄ³¬¼¯£¬Òò´ËÊÇÖ¸¶¨·Ö²ãÅäÖÃÊý¾ÝµÄ·½±ã¸ñʽ¡£ Ö»ÒªÄãµÄclasspathÉÏÓÐ [SnakeYAML](https://github.com/snakeyaml/snakeyaml) ¿â£¬`SpringApplication` Àà¾Í»á×Ô¶¯Ö§³ÖYAML×÷ΪpropertiesµÄÌæ´úÆ·¡£
+
+
+
+
+
+| | Èç¹ûÄãʹÓà ¡°Starter¡±£¬SnakeYAML½«ÓÉ `spring-boot-starter` ×Ô¶¯Ìṩ¡£ |
+| --- | --- |
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.yaml.mapping-to-properties)2.5.1\. ½«YAMLÓ³Éäµ½Properties
+
+
+
+YAML ÎĵµÐèÒª´ÓÆä·Ö²ã¸ñʽת»»Îª¿ÉÓë Spring `Environment` Ò»ÆðʹÓÃµÄ±âÆ½½á¹¹¡£ ÀýÈ磬¿¼ÂÇÏÂÃæÕâ¸öYAMLÎĵµ¡£
+
+
+
+
+
+
+
+```
+environments:
+ dev:
+ url: "https://dev.example.com"
+ name: "Developer Setup"
+ prod:
+ url: "https://another.example.com"
+ name: "My Cool App"
+```
+
+
+
+
+
+
+
+ΪÁË´Ó `Environment` ÖзÃÎÊÕâЩÊôÐÔ£¬ËüÃǽ«±»±âƽ»¯£¬ÈçÏÂËùʾ¡£
+
+
+
+
+
+
+
+```
+environments.dev.url=https://dev.example.com
+environments.dev.name=Developer Setup
+environments.prod.url=https://another.example.com
+environments.prod.name=My Cool App
+```
+
+
+
+
+
+
+
+ͬÑùµØ£¬YAMLÖеÄÁбíÒ²ÐèÒª½øÐÐ±âÆ½»¯´¦Àí¡£ ËüÃDZ»±íʾΪ´øÓÐ `[index]` Ë÷ÒýµÄkey¡£ ÀýÈ磬¿¼ÂÇÏÂÃæµÄYAML¡£
+
+
+
+
+
+
+
+```
+my:
+ servers:
+ - "dev.example.com"
+ - "another.example.com"
+```
+
+
+
+
+
+
+
+Ç°ÃæµÄÀý×Ó½«±»×ª»¯ÎªÈçÏÂÊôÐÔ¡£
+
+
+
+
+
+
+
+```
+my.servers[0]=dev.example.com
+my.servers[1]=another.example.com
+```
+
+
+
+
+
+
+
+| | ʹÓà `[index]` ·ûºÅµÄÊôÐÔ¿ÉÒÔʹÓÃSpring BootµÄ `Binder` Àà°ó¶¨µ½Java `List` »ò `Set` ¶ÔÏó¡£ ¸ü¶àϸ½Ú¼ûÏÂÃæµÄ ¡°[ÀàÐͰ²È«µÄÅäÖÃÊôÐÔ](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties)¡± ²¿·Ö¡£ |
+| --- | --- |
+
+
+
+
+
+| | YAMLÎļþ²»ÄÜͨ¹ýʹÓà `@PropertySource` »ò `@TestPropertySource` ×¢½âÀ´¼ÓÔØ¡£ ËùÒÔ£¬ÔÚÄãÐèÒªÒÔÕâÖÖ·½Ê½¼ÓÔØÖµµÄÇé¿öÏ£¬ÄãÐèҪʹÓÃÒ»¸ö properties Îļþ¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.yaml.directly-loading)2.5.2\. Ö±½Ó¼ÓÔØYAML
+
+
+
+Spring FrameworkÌṩÁËÁ½¸ö·½±ãµÄÀ࣬¿ÉÒÔÓÃÀ´¼ÓÔØYAMLÎĵµ¡£ `YamlPropertiesFactoryBean` ½«YAML×÷Ϊ `Properties` ¼ÓÔØ£¬`YamlMapFactoryBean` ½«YAML×÷Ϊ `Map` ¼ÓÔØ¡£
+
+
+
+
+
+Èç¹ûÄãÏë°ÑYAML¼ÓÔØÎªSpringµÄ `PropertySource` £¬ÄãÒ²¿ÉÒÔʹÓà `YamlPropertySourceLoader` Àà¡£
+
+
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.external-config.random-values)2.6\. ÅäÖÃËæ»úÖµ
+
+
+
+The `RandomValuePropertySource` is useful for injecting random values (for example, into secrets or test cases). It can produce integers, longs, uuids, or strings, as shown in the following example:
+
+
+
+
+
+`RandomValuePropertySource` ¶ÔÓÚ×¢ÈëËæ»úÖµºÜÓÐÓã¨ÀýÈ磬עÈëÃÜÂë»ò²âÊÔ°¸Àý£©¡£ Ëü¿ÉÒÔ²úÉúInteger¡¢Long¡¢UUID£¬»òString£¬ÈçÏÂÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+my.secret=${random.value}
+my.number=${random.int}
+my.bignumber=${random.long}
+my.uuid=${random.uuid}
+my.number-less-than-ten=${random.int(10)}
+my.number-in-range=${random.int[1024,65536]}
+
+```
+
+
+
+
+
+
+
+`random.int*` µÄÓï·¨ÊÇ `OPEN value (,max) CLOSE`£¬ÆäÖÐ `OPEN,CLOSE` ÊÇÈκÎ×Ö·û£¬ `value,max` ÊÇÕûÊý¡£ Èç¹ûÌṩÁË `max`£¬ÄÇô `value` ÊÇ×îСֵ£¬ `max` ÊÇ×î´óÖµ£¨¶ÀÕ¼£©¡£
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.external-config.system-environment)2.7\. ÅäÖÃϵͳ»·¾³ÊôÐÔ
+
+
+
+Spring BootÖ§³ÖΪ»·¾³ÊôÐÔÉèÖÃÒ»¸öǰ׺¡£ Èç¹ûϵͳ»·¾³±»¶à¸ö¾ßÓв»Í¬ÅäÖÃÒªÇóµÄSpring BootÓ¦ÓóÌÐò¹²Ïí£¬Õâ¾ÍºÜÓÐÓᣠϵͳ»·¾³ÊôÐÔµÄǰ׺¿ÉÒÔÖ±½ÓÔÚ `SpringApplication` ÉÏÉèÖá£
+
+
+
+
+
+ÀýÈ磬Èç¹ûÄ㽫ǰ׺ÉèÖÃΪ `input` £¬ÖîÈç `remote.timeout` ÕâÑùµÄÊôÐÔÔÚϵͳ»·¾³ÖÐÒ²½«±»½âÎöΪ `input.remote.timeout`¡£
+
+
+
+
+
+
+
+### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties)2.8\. ÀàÐͰ²È«µÄÅäÖÃÊôÐÔ
+
+
+
+ʹÓà `@Value("${property}")` ×¢½âÀ´×¢ÈëÅäÖÃÊôÐÔÓÐʱ»áºÜÂé·³£¬ÌرðÊǵ±ÄãÒª´¦Àí¶à¸öÊôÐÔ»òÄãµÄÊý¾ÝÊÇ·Ö²ãµÄ¡£ Spring BootÌṩÁËÒ»ÖÖ´¦ÀíÊôÐÔµÄÌæ´ú·½·¨£¬ÈÃÇ¿ÀàÐ͵ÄBean¹ÜÀíºÍÑéÖ¤ÄãµÄÓ¦ÓóÌÐòµÄÅäÖá£
+
+
+
+
+
+| | ÁíÇë²Î¼û[`@Value` ºÍÀàÐͰ²È«ÅäÖÃÊôÐÔÖ®¼äµÄÇø±ð](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.vs-value-annotation)¡£ |
+| --- | --- |
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.java-bean-binding)2.8.1\. JavaBean ÊôÐÔ°ó¶¨
+
+
+
+ÈçÏÂÃæµÄÀý×ÓËùʾ£¬¿ÉÒÔ°ó¶¨Ò»¸öÉùÃ÷Á˱ê×¼JavaBeanÊôÐÔµÄbean¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties("my.service")
+public class MyProperties {
+
+ private boolean enabled;
+
+ private InetAddress remoteAddress;
+
+ private final Security security = new Security();
+
+ // getters / setters...
+
+ public static class Security {
+
+ private String username;
+
+ private String password;
+
+ private List roles = new ArrayList<>(Collections.singleton("USER"));
+
+ // getters / setters...
+
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+Ç°ÃæµÄPOJO¶¨ÒåÁËÒÔÏÂÊôÐÔ¡£
+
+
+
+
+
+* `my.service.enabled`£¬Ä¬ÈÏֵΪ`false`¡£
+
+* `my.service.remote-address`£¬ÆäÀàÐÍ¿ÉÓÉ`String`Ç¿ÖÆÌṩ¡£
+
+* `my.service.security.username`£¬ÓÐÒ»¸öǶÌ×µÄ `security` ¶ÔÏ󣬯äÃû³ÆÓɸÃÊôÐÔµÄÃû³Æ¾ö¶¨¡£ ÌØ±ðÊÇ£¬ÄÇÀïÍêȫûÓÐʹÓÃÀàÐÍ£¬¿ÉÒÔÊÇ `SecurityProperties`¡£
+
+* `my.service.security.password`.
+
+* `my.service.security.role`£¬ÓÐÒ»¸ö `String` µÄ¼¯ºÏ£¬Ä¬ÈÏΪ `USER`¡£
+
+
+
+
+
+| | Ó³Éäµ½Spring BootÖпÉÓÃµÄ `@ConfigurationProperties` ÀàµÄÊôÐÔ£¬Í¨¹ýpropertiesÎļþ¡¢YAMLÎļþ¡¢»·¾³±äÁ¿ºÍÆäËû»úÖÆ½øÐÐÅäÖã¬ÕâЩÊôÐÔÊǹ«¹²API£¬µ«Àà±¾ÉíµÄ getters/setters ²¢²»Òâζ×Å¿ÉÒÔÖ±½ÓʹÓã¨Ò»¾ä»°£¬SpringÒ²ÊÇͨ¹ýgetter/setterÕâЩpublic·½·¨½øÐÐÉèÖÃÖµµÄ£¬Äã±ðÓã©¡£ |
+| --- | --- |
+
+
+
+
+
+| | ÕâÑùµÄÉè¼ÆÒÀÀµÓÚÒ»¸öĬÈϵÄÎ޲ι¹Ô캯Êý£¬getterºÍsetterͨ³£ÊDZØÐëµÄ£¬ÒòΪ°ó¶¨ÊÇͨ¹ý±ê×¼µÄJava Beans property descriptor£¨JavaÄÚÊ¡£©ÊµÏֵ쬾ÍÏñÔÚSpring MVCÖÐÒ»Ñù¡£ ÔÚÒÔÏÂÇé¿öÏ£¬¿ÉÒÔÊ¡ÂÔsetter¡£* Map, Ö»ÒªËüÃDZ»³õʼ»¯£¬¾ÍÐèÒªÒ»¸ögetter£¬µ«²»Ò»¶¨ÐèÒªÒ»¸ösetter£¬ÒòΪËüÃÇ¿ÉÒÔ±»°ó¶¨Æ÷Í»±ä¡£ * CollectionºÍarray ¿ÉÒÔͨ¹ýË÷Òý£¨Í¨³£ÓÃYAML£©»òʹÓõ¥¸ö¶ººÅ·Ö¸ôµÄÖµ£¨ÊôÐÔ£©À´·ÃÎÊ¡£ ÔÚºóÒ»ÖÖÇé¿öÏ£¬Ò»¸ösetterÊDZØÐëµÄ¡£ ÎÒÃǽ¨Òé×ÜÊÇΪÕâÀàÀàÐÍÌí¼ÓÒ»¸ösetter¡£ Èç¹ûÄã³õʼ»¯Ò»¸ö¼¯ºÏ£¬È·±£Ëü²»ÊDz»¿É±äµÄ£¨ÈçÇ°ÃæµÄÀý×Ó£©¡£ * Èç¹ûǶÌ×µÄPOJOÊôÐÔ±»³õʼ»¯£¨¾ÍÏñÇ°ÃæÀý×ÓÖÐµÄ `Security` ×ֶΣ©£¬¾Í²»ÐèÒªsetter¡£ Èç¹ûÄãÏëÈÃ°ó¶¨Æ÷ͨ¹ýʹÓÃËüµÄĬÈϹ¹Ô캯ÊýÀ´¼´Ê±´´½¨ÊµÀý£¬ÄãÐèÒªÒ»¸ösetter¡£ ÓÐЩÈËʹÓÃProject LombokÀ´×Ô¶¯Ìí¼ÓgetterºÍsetter¡£ ÇëÈ·±£Lombok²»»áΪÕâÑùµÄÀàÐÍÉú³ÉÈκÎÌØ¶¨µÄ¹¹Ô캯Êý£¬ÒòΪËü±»ÈÝÆ÷×Ô¶¯ÓÃÀ´ÊµÀý»¯¶ÔÏó¡£×îºó£¬Ö»¿¼ÂDZê×¼µÄJava BeanÊôÐÔ£¬²»Ö§³Ö¶Ô¾²Ì¬ÊôÐԵİ󶨡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.constructor-binding)2.8.2\. ¹¹Ô캯Êý°ó¶¨
+
+
+
+ÉÏÒ»½ÚµÄÀý×Ó¿ÉÒÔÓò»¿É±äµÄ·½Ê½ÖØÐ´£¬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties("my.service")
+public class MyProperties {
+
+ // fields...
+
+ public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
+ this.enabled = enabled;
+ this.remoteAddress = remoteAddress;
+ this.security = security;
+ }
+
+ // getters...
+
+ public static class Security {
+
+ // fields...
+
+ public Security(String username, String password, @DefaultValue("USER") List roles) {
+ this.username = username;
+ this.password = password;
+ this.roles = roles;
+ }
+
+ // getters...
+
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+ÔÚÕâÖÖÉèÖÃÖУ¬Î¨Ò»µÄ¡°´ø²ÎÊý¹¹Ô캯Êý¡±µÄ´æÔÚÒâζ×ÅÓ¦¸ÃʹÓøù¹Ô캯Êý½øÐа󶨡£ ÕâÒâζ×Ű󶍯÷»áÕÒµ½Ò»¸ö´øÓÐÄãÏ£Íû°ó¶¨µÄ²ÎÊýµÄ¹¹Ô캯Êý¡£ Èç¹ûÄãµÄÀàÓжà¸ö¹¹Ô캯Êý£¬¿ÉÒÔʹÓà `@ConstructorBinding` ×¢½âÀ´Ö¸¶¨Ê¹ÓÃÄĸö¹¹Ô캯Êý½øÐй¹Ô캯Êý°ó¶¨¡£ Èç¹ûҪΪһ¸öÖ»ÓÐÒ»¸ö¡°´ø²ÎÊý¹¹Ô캯Êý¡±µÄÀàÑ¡Ôñ²»°ó¶¨¹¹Ô캯Êý£¬¸Ã¹¹Ô캯Êý±ØÐëÓà `@Autowired` À´×¢½â¡£ ¹¹Ô캯Êý°ó¶¨¿ÉÒÔÓë `Record` Ò»ÆðʹÓᣠ³ý·ÇÄãµÄ¼Ç¼Óжà¸ö¹¹Ô캯Êý£¬·ñÔòûÓбØÒªÊ¹Óà `@ConstructorBinding`¡£
+
+
+
+
+
+¹¹Ô캯Êý°ó¶¨ÀàµÄǶÌ׳ÉÔ±£¨ÈçÉÏÃæÀý×ÓÖÐµÄ `Security`£©Ò²½«Í¨¹ýÆä¹¹Ô캯Êý±»°ó¶¨¡£
+
+
+
+
+
+ĬÈÏÖµ¿ÉÒÔÔÚ¹¹Ô캯Êý²ÎÊýºÍRecord×é¼þÉÏʹÓà `@DefaultValue` À´Ö¸¶¨¡£ ת»»·þÎñ½«±»Ó¦ÓÃÓÚ½«×¢½âµÄ `String` ÖµÇ¿ÖÆ×ª»»ÎªÈ±Ê§ÊôÐÔµÄÄ¿±êÀàÐÍ¡£
+
+
+
+
+
+²Î¿¼Ç°ÃæµÄÀý×Ó£¬Èç¹ûûÓÐÊôÐ԰󶨵½ `Security` £¬ `MyProperties` ʵÀý½«°üº¬Ò»¸ö `security` ÀàÐ굀 `null` Öµ¡£ ΪÁËʹËü°üº¬Ò»¸ö·Ç null µÄ `Security` ʵÀý£¬¼´Ê¹Ã»ÓÐÊôÐÔÓëÖ®°ó¶¨£¨µ±Ê¹ÓÃKotlinʱ£¬Õ⽫ҪÇó `Security` µÄ `username` ºÍ `password` ²ÎÊý±»ÉùÃ÷Ϊ nullable£¬ÒòΪËüÃÇûÓÐĬÈÏÖµ£©£¬Ê¹ÓÃÒ»¸ö¿ÕµÄ `@DefaultValue` ×¢½â¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+public MyProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
+ this.enabled = enabled;
+ this.remoteAddress = remoteAddress;
+ this.security = security;
+}
+
+```
+
+
+
+
+
+
+
+| | ҪʹÓù¹Ô캯Êý°ó¶¨£¬¸ÃÀà±ØÐëʹÓà `@EnableConfigurationProperties` »òÅäÖÃÊôÐÔɨÃèÀ´ÆôÓᣠÄã²»ÄܶÔͨ¹ý³£¹æSpring»úÖÆ´´½¨µÄBeanʹÓù¹Ô캯Êý°ó¶¨£¨ÀýÈç `@Component` Bean£¬Í¨¹ýʹÓà `@Bean` ·½·¨´´½¨µÄBean»òͨ¹ýʹÓà `@Import` ¼ÓÔØµÄBean£©¡£ |
+| --- | --- |
+
+
+
+
+
+| | ÒªÔÚÔÉú¾µÏñÖÐʹÓù¹Ô캯Êý°ó¶¨£¬±ØÐëÓà `-parameters` ²ÎÊý±àÒë¸ÃÀà¡£Èç¹ûÄãʹÓà Spring Boot µÄ Gradle ²å¼þ»òʹÓà Maven ºÍ `spring-boot-starter-parent`£¬Õ⽫×Ô¶¯ÅäÖᣠ|
+| --- | --- |
+
+
+
+
+
+| | ²»½¨Ò齫 `java.util.Optional` Óë `@ConfigurationProperties` Ò»ÆðʹÓã¬ÒòΪËüÖ÷ÒªÊÇ×÷Ϊһ¸ö·µ»ØÀàÐÍʹÓᣠÒò´Ë£¬Ëü²¢²»ÊʺÏÅäÖÃÊôÐÔ×¢Èë¡£ ΪÁËÓëÆäËûÀàÐ͵ÄÊôÐÔ±£³ÖÒ»Ö£¬Èç¹ûÄãȷʵÉùÃ÷ÁËÒ»¸ö `Optional` ÊôÐÔ£¬µ«ËüûÓÐÖµ£¬`null` ¶ø²»ÊÇÒ»¸ö¿ÕµÄ `Optional` ½«±»°ó¶¨¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.enabling-annotated-types)2.8.3\. ÆôÓÃ @ConfigurationProperties Àà
+
+
+
+Spring BootÌṩÁË°ó¶¨ `@ConfigurationProperties` ÀàÐͲ¢½«Æä×¢²áΪBeanµÄ»ù´¡ÉèÊ©¡£ Äã¿ÉÒÔÔÚÖð¸öÀàµÄ»ù´¡ÉÏÆôÓÃÅäÖÃÊôÐÔ£¬»òÕ߯ôÓÃÅäÖÃÊôÐÔɨÃ裬Æä¹¤×÷·½Ê½Óë×é¼þɨÃèÀàËÆ¡£
+
+
+
+
+
+ÓÐʱ£¬Óà `@ConfigurationProperties` ×¢½âµÄÀà¿ÉÄܲ»ÊʺÏɨÃ裬ÀýÈ磬Èç¹ûÄãÕýÔÚ¿ª·¢Äã×Ô¼ºµÄ×Ô¶¯ÅäÖûòÕßÄãÏëÓÐÌõ¼þµØÆôÓÃËüÃÇ¡£ ÔÚÕâЩÇé¿öÏ£¬Ê¹Óà `@EnableConfigurationProperties` ×¢½âÖ¸¶¨Òª´¦ÀíµÄÀàÐÍÁÐ±í£¬ Ëü¿ÉÒÔ×¢½âÔÚÈκΠ`@Configuration` ÀàÉÏ£¬ÈçÏÂÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Configuration(proxyBeanMethods = false)
+@EnableConfigurationProperties(SomeProperties.class)
+public class MyConfiguration {
+
+}
+
+```
+
+
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties("some.properties")
+public class SomeProperties {
+
+}
+
+```
+
+
+
+
+
+
+
+ҪʹÓÃÅäÖÃÊôÐÔɨÃ裬ÇëÏòÄãµÄapplicationÌí¼Ó `@ConfigurationPropertiesScan` ×¢½â¡£ ͨ³££¬Ëü±»Ìí¼Óµ½Óà `@SpringBootApplication` ×¢½âµÄmainÀàÖУ¬µ«ËüÒ²¿ÉÒÔ±»Ìí¼Óµ½ÈκΠ`@Configuration` ÀàÉÏ¡£ ĬÈÏÇé¿öÏ£¬É¨Ãè»á´Ó×¢½âËùÔڵİü¿ªÊ¼£¬ÄãÈç¹ûÏë×Ô¶¨ÒåɨÃèÆäËû°ü£¬¿ÉÒԲο¼ÈçÏ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@SpringBootApplication
+@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
+public class MyApplication {
+
+}
+
+```
+
+
+
+
+
+
+
+| | µ± `@ConfigurationProperties` BeanʹÓÃÅäÖÃÊôÐÔɨÃè»òͨ¹ý `@EnableConfigurationProperties` ×¢²áʱ£¬¸ÃBeanÓÐÒ»¸ö³£¹æÃû³Æ£º`-`£¬ÆäÖÐ `` ÊÇ `@ConfigurationProperties` ×¢½âÖÐÖ¸¶¨µÄ»·¾³¼üǰ׺£¬ `` ÊÇBeanµÄÍêÈ«ÏÞ¶¨Ãû³Æ¡£ Èç¹û×¢½âûÓÐÌṩÈκÎǰ׺£¬ÔòֻʹÓÃBeanµÄÍêÈ«ÏÞ¶¨Ãû³Æ¡£¼ÙÉèËüÔÚ `com.example.app` °üÖУ¬ÉÏÃæµÄ `SomeProperties` Àý× bean Ãû³ÆÊÇ `some.properties-com.example.app.SomeProperties`¡£ |
+| --- | --- |
+
+
+
+
+
+ÎÒÃǽ¨Òé `@ConfigurationProperties` Ö»´¦Àí environment£¬ÌرðÊDz»´ÓÉÏÏÂÎÄ×¢ÈëÆäËûBean¡£ ¶ÔÓڱ߽ǰ¸Àý£¨ÌØÊâÇé¿ö£©£¬¿ÉÒÔʹÓà setter ×¢Èë»ò¿ò¼ÜÌṩµÄÈκΠ`*Aware` ½Ó¿Ú£¨Èç `EnvironmentAware` £¬Èç¹ûÄãÐèÒª·ÃÎÊ `Environment`£©¡£ Èç¹ûÄãÈÔÈ»ÏëʹÓù¹ÔìÆ÷×¢ÈëÆäËûBean£¬ÅäÖÃÊôÐÔBean±ØÐëÓà `@Component` À´×¢½â£¬²¢Ê¹ÓûùÓÚJavaBeanµÄÊôÐ԰󶨡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.using-annotated-types)2.8.4\. ʹÓà @ConfigurationProperties Àà
+
+
+
+ÕâÖÖÅäÖ÷½Ê½Óë `SpringApplication` ÍⲿYAMLÅäÖÃÅäºÏµÃÌØ±ðºÃ£¬ÈçÒÔÏÂÀý×ÓËùʾ¡£
+
+
+
+
+
+
+
+```
+my:
+ service:
+ remote-address: 192.168.1.1
+ security:
+ username: "admin"
+ roles:
+ - "USER"
+ - "ADMIN"
+```
+
+
+
+
+
+
+
+ҪʹÓà `@ConfigurationProperties` Bean£¬Äã¿ÉÒÔÓÃÓëÆäËûBeanÏàͬµÄ·½Ê½×¢ÈëËüÃÇ£¬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Service
+public class MyService {
+
+ private final MyProperties properties;
+
+ public MyService(MyProperties properties) {
+ this.properties = properties;
+ }
+
+ public void openConnection() {
+ Server server = new Server(this.properties.getRemoteAddress());
+ server.start();
+ // ...
+ }
+
+ // ...
+
+}
+
+```
+
+
+
+
+
+
+
+| | ʹÓà `@ConfigurationProperties` »¹¿ÉÒÔÈÃÄãÉú³ÉÔªÊý¾ÝÎļþ£¬ÕâЩÎļþ¿ÉÒÔ±»IDEÓÃÀ´ÅäÖÃÊôÐԵġ°×Ô¶¯²¹È«¡±¹¦ÄÜ¡£ ÏêÇé¼û[¸½Â¼](https://springdoc.cn/spring-boot/configuration-metadata.html#appendix.configuration-metadata)¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.third-party-configuration)2.8.5\. µÚÈý·½ÅäÖÃ
+
+
+
+³ýÁËʹÓà `@ConfigurationProperties` À´×¢½âÒ»¸öÀàÖ®Í⣬Ä㻹¿ÉÒÔÔÚ¹«¹²µÄ `@Bean` ·½·¨ÉÏʹÓÃËü¡£ µ±ÄãÏë°ÑÊôÐ԰󶨵½Äã¿ØÖÆÖ®ÍâµÄµÚÈý·½×é¼þʱ£¬ÕâÑù×öÌØ±ðÓÐÓá£
+
+
+
+
+
+Òª´Ó `Environment` ÊôÐÔÖÐÅäÖÃÒ»¸öBean£¬ÇëÔÚÆäBean×¢²áÖÐÌí¼Ó `@ConfigurationProperties` £¬ÈçÏÂÀýËùʾ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@Configuration(proxyBeanMethods = false)
+public class ThirdPartyConfiguration {
+
+ @Bean
+ @ConfigurationProperties(prefix = "another")
+ public AnotherComponent anotherComponent() {
+ return new AnotherComponent();
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+ÈκÎÓà `another` ǰ׺¶¨ÒåµÄJavaBeanÊôÐÔ¶¼»á±»Ó³Éäµ½ `AnotherComponent` BeanÉÏ£¬Æä·½Ê½ÀàËÆÓÚÇ°ÃæµÄ `SomeProperties` Àý×Ó¡£
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.relaxed-binding)2.8.6\. ¿íËɵİó¶¨
+
+
+
+Spring BootÔÚ½« `Environment` ÊôÐ԰󶨵½ `@ConfigurationProperties` beanʱʹÓÃÁËһЩ¿íËɵĹæÔò£¬Òò´Ë `Environment` ÊôÐÔÃû³ÆºÍbeanÊôÐÔÃû³ÆÖ®¼ä²»ÐèÒªÍêȫƥÅä¡£ ÕâºÜÓÐÓ㬳£¼ûµÄÀý×Ó°üÀ¨ÆÆÕۺŷָôµÄÊôÐÔÃû³Æ£¨ÀýÈ磬 `context-path` °ó¶¨µ½ `contextPath` £©£¬ºÍ´óдµÄÊôÐÔÃû³Æ£¨ÀýÈ磬`PORT` °ó¶¨µ½ `port` £©¡£
+
+
+
+
+
+ÑÝʾһ¸öÀý×Ó£¬¿¼ÂÇÒÔÏ `@ConfigurationProperties` Àà¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties(prefix = "my.main-project.person")
+public class MyPersonProperties {
+
+ private String firstName;
+
+ public String getFirstName() {
+ return this.firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+¶ÔÒÔÉϵĴúÂëÀ´Ëµ£¬ÒÔϵÄÊôÐÔÃû³Æ¶¼¿ÉÒÔʹÓá£
+
+
+
+Table 3\. relaxed binding
+| Property | Note |
+| --- | --- |
+| `my.main-project.person.first-name` | Kebab ·ç¸ñ£¨¶ÌºáÏ߸ô¿ª£©£¬½¨ÒéÔÚ `.properties` ºÍ `.yml` ÎļþÖÐʹÓᣠ|
+| `my.main-project.person.firstName` | ±ê×¼µÄÍÕ·åÓï·¨¡£ |
+| `my.main-project.person.first_name` | Ï»®Ïߣ¬ÕâÊÇÒ»ÖÖÓÃÓÚ `.properties` ºÍ `.yml` ÎļþµÄÌæ´ú¸ñʽ¡£ |
+| `MY_MAINPROJECT_PERSON_FIRSTNAME` | ´óд¸ñʽ£¬ÔÚʹÓÃϵͳ»·¾³±äÁ¿Ê±½¨ÒéʹÓôóд¸ñʽ¡£ |
+
+
+
+| | ×¢½âµÄ `prefix` Öµ _±ØÐë_ ÊÇkebab·ç¸ñ£¨Ð¡Ð´²¢ÒÔ `-` ·Ö¸ô£¬Èç `my.main-project.person` £©¡£ |
+| --- | --- |
+
+
+
+Table 4\. ÿÖÖÊôÐÔÔ´µÄ¿íËɰ󶨹æÔò
+| ÊôÐÔÔ´ | ¼òµ¥µÄ | Áбí |
+| --- | --- | --- |
+| Properties Îļþ | ÍÕ·å, kebab , Ï»®Ïß | ʹÓà `[ ]` »ò¶ººÅ·Ö¸ôÖµµÄ±ê×¼ÁбíÓï·¨ |
+| YAML Îļþ | ÍÕ·å, kebab , Ï»®Ïß | ±ê×¼YAMLÁбíÓï·¨»ò¶ººÅ·Ö¸ôµÄÖµ |
+| »·¾³±äÁ¿ | ´óд£¬Ï»®ÏßΪ·Ö¸ô·û(¼û [´Ó»·¾³±äÁ¿°ó¶¨](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables)). | Numeric values surrounded by underscores (see [´Ó»·¾³±äÁ¿°ó¶¨](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables)) |
+| ϵͳÊôÐÔ£¨System properties£© | ÍÕ·å, kebab , Ï»®Ïß | ʹÓà `[ ]` »ò¶ººÅ·Ö¸ôÖµµÄ±ê×¼ÁбíÓï·¨ |
+
+
+
+| | ÎÒÃǽ¨Ò飬ÔÚ¿ÉÄܵÄÇé¿öÏ£¬ÊôÐÔÓ¦ÒÔСдµÄkebab¸ñʽ´æ´¢£¬ÀýÈç `my.person.first-name=Rod` ¡£ |
+| --- | --- |
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.relaxed-binding.maps)°ó¶¨Map
+
+
+
+µ±°ó¶¨µ½ `Map` ÊôÐÔʱ£¬Äã¿ÉÄÜÐèҪʹÓÃÒ»¸öÌØÊâµÄÀ¨ºÅ·ûºÅ£¬ÒԱ㱣ÁôÔʼµÄ `key` Öµ¡£ Èç¹ûkeyûÓб» `[ ]` °ü¹ü£¬ÈκηÇ×ÖĸÊý×Ö¡¢`-` »ò `.` µÄ×Ö·û½«±»É¾³ý¡£
+
+
+
+
+
+ÀýÈ磬¿¼Âǽ«ÒÔÏÂÊôÐ԰󶨵½Ò»¸ö `Map`¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+my.map.[/key1]=value1
+my.map.[/key2]=value2
+my.map./key3=value3
+```
+
+
+
+
+
+
+
+| | ¶ÔÓÚYAMLÎļþ£¬À¨ºÅÐèÒªÓÃÒýºÅ°ü¹ü£¬ÒÔʹkey±»ÕýÈ·½âÎö¡£ |
+| --- | --- |
+
+
+
+
+
+ÉÏÃæµÄÊôÐÔ½«°ó¶¨µ½Ò»¸ö `Map` £¬`/key1`£¬`/key2` ºÍ `key3` ×÷ΪmapµÄkey¡£ бÏßÒѾ´Ó `key3` ÖÐɾ³ý£¬ÒòΪËüûÓб»·½À¨ºÅ°ü¹ü¡£
+
+
+
+
+
+µ±°ó¶¨µ½±êÁ¿ÖµÊ±£¬´øÓÐ `.` µÄ¼ü²»ÐèÒªÓà `[]` °ü¹ü¡£ ±êÁ¿Öµ°üÀ¨Ã¶¾ÙºÍËùÓÐ `java.lang` °üÖеÄÀàÐÍ£¬³ýÁË `Object` ¡£ ½« `a.b=c` °ó¶¨µ½ `Map` ½«±£Áô¼üÖÐµÄ `.` £¬²¢·µ»ØÒ»¸ö´øÓÐ `{"a.b"="c"}` EntryµÄMap¡£ ¶ÔÓÚÈÎºÎÆäËûÀàÐÍ£¬Èç¹ûÄãµÄ `key` °üº¬ `.` £¬ÄãÐèҪʹÓÃÀ¨ºÅ·ûºÅ¡£ ÀýÈ磬½« `a.b=c` °ó¶¨µ½ `Map` ½«·µ»ØÒ»¸ö´øÓÐ `{"a"={"b"="c"}` entryµÄMap£¬¶ø `[a.b]=c` ½«·µ»ØÒ»¸ö´øÓÐ `{"a.b"="c"}` entry µÄMap¡£
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.relaxed-binding.environment-variables)´Ó»·¾³±äÁ¿°ó¶¨
+
+
+
+ÀýÈ磬Linux shell±äÁ¿Ö»Äܰüº¬×Öĸ£¨`a` µ½ `z` »ò `A` µ½ `Z` £©¡¢Êý×Ö£¨ `0` µ½ `9` £©»òÏ»®Ïß×Ö·û£¨ `_` £©¡£ °´ÕÕ¹ßÀý£¬Unix shell±äÁ¿µÄÃû³ÆÒ²½«²ÉÓôóд×Öĸ¡£
+
+
+
+
+
+Spring Boot¿íËɵİ󶨹æÔò±»Éè¼ÆÎª¾¡¿ÉÄܵØÓëÕâЩÃüÃûÏÞÖÆ¼æÈÝ¡£
+
+
+
+
+
+Òª½«¹æ·¶ÐÎʽµÄÊôÐÔÃû³Æ×ª»»Îª»·¾³±äÁ¿Ãû³Æ£¬Äã¿ÉÒÔ×ñÑÕâЩ¹æÔò¡£
+
+
+
+
+
+* ÓÃÏ»®Ïߣ¨`_`£©Ìæ»»µã£¨`.`£©¡£
+
+* ɾ³ýÈÎºÎÆÆÕۺţ¨`-`£©¡£
+
+* ת»»Îª´óд×Öĸ¡£
+
+
+
+
+
+ÀýÈ磬ÅäÖÃÊôÐÔ `spring.main.log-startup-info` ½«ÊÇÒ»¸öÃûΪ `SPRING_MAIN_LOGSTARTUPINFO` µÄ»·¾³±äÁ¿¡£
+
+
+
+
+
+»·¾³±äÁ¿Ò²¿ÉÒÔÔڰ󶨵½¶ÔÏóÁÐ±í£¨List£©Ê±Ê¹ÓᣠҪ°ó¶¨µ½Ò»¸ö `List`£¬ÔÚ±äÁ¿Ãû³ÆÖУ¬ÔªËرàºÅ£¨Ë÷Òý£©Ó¦¸ÃÓÃÏ»®Ïß°ü¹ü¡£
+
+
+
+
+
+ÀýÈ磬ÅäÖÃÊôÐÔ `my.service[0].other` ½«Ê¹ÓÃÒ»¸öÃûΪ `MY_SERVICE_0_OTHER` µÄ»·¾³±äÁ¿¡£
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.merging-complex-types)2.8.7\. ºÏ²¢¸´ÔÓµÄÀàÐÍ
+
+
+
+µ±List±»ÅäÖÃÔÚ¶à¸öµØ·½Ê±£¬¸²¸ÇµÄ×÷ÓÃÊÇÌæ»»Õû¸ölist¡£
+
+
+
+
+
+ÀýÈ磬¼ÙÉèÒ»¸ö `MyPojo` ¶ÔÏóµÄ `name` ºÍ `description` ÊôÐÔĬÈÏΪ `null`¡£ ÏÂÃæµÄÀý×Ó´Ó `MyProperties` Öб©Â¶ÁËÒ»¸ö `MyPojo` ¶ÔÏóµÄÁÐ±í¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties("my")
+public class MyProperties {
+
+ private final List list = new ArrayList<>();
+
+ public List getList() {
+ return this.list;
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+¿¼ÂÇÒÔÏÂÅäÖá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+my.list[0].name=my name
+my.list[0].description=my description
+#---
+spring.config.activate.on-profile=dev
+my.list[0].name=my another name
+
+```
+
+
+
+
+
+
+
+Èç¹û `dev` ÅäÖÃÎļþδ±»¼¤»î£¬`MyProperties.list` °üº¬Ò»¸ö `MyPojo` ÌõÄ¿£¬Èç֮ǰ¶¨ÒåµÄÄÇÑù¡£ È»¶ø£¬Èç¹û `dev` ÅäÖÃÎļþ±»¼¤»î£¬`list` ÈÔȻֻ°üº¬Ò»¸öÌõÄ¿£¨name Ϊ `my another name`£¬descriptionΪ `null`£©¡£ ÕâÖÖÅäÖò»»áÔÚÁбíÖÐÌí¼ÓµÚ¶þ¸ö `MyPojo` ʵÀý£¬Ò²²»»áºÏ²¢ÏîÄ¿¡£
+
+
+
+
+
+µ±Ò»¸ö `List` ÔÚ¶à¸öÅäÖÃÎļþÖб»Ö¸¶¨Ê±£¬½«Ê¹ÓþßÓÐ×î¸ßÓÅÏȼ¶µÄÄǸö£¨²¢ÇÒÖ»ÓÐÄǸö£©¡£ ¿¼ÂÇÏÂÃæµÄÀý×Ó¡£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+my.list[0].name=my name
+my.list[0].description=my description
+my.list[1].name=another name
+my.list[1].description=another description
+#---
+spring.config.activate.on-profile=dev
+my.list[0].name=my another name
+
+```
+
+
+
+
+
+
+
+ÔÚÇ°ÃæµÄÀý×ÓÖУ¬Èç¹û `dev` ÅäÖÃÎļþÊǼ¤»îµÄ£¬`MyProperties.list` °üº¬ _Ò»¸ö_ `MyPojo` ÌõÄ¿£¨name ÊÇ `my another name`£¬descriptionÊÇ `null`£©¡£ ¶ÔÓÚYAML£¬¶ººÅ·Ö¸ôµÄÁбíºÍYAMLÁÐ±í¶¼¿ÉÒÔÓÃÀ´ÍêÈ«¸²¸ÇÁбíµÄÄÚÈÝ¡£
+
+
+
+
+
+¶ÔÓÚ `Map` ÊôÐÔ£¬Äã¿ÉÒÔÓôӶà¸öÀ´Ô´»ñÈ¡µÄÊôÐÔÖµ½øÐа󶨡£ È»¶ø£¬¶ÔÓÚ¶à¸öÀ´Ô´ÖеÄͬһÊôÐÔ£¬Ê¹ÓþßÓÐ×î¸ßÓÅÏȼ¶µÄÄǸö¡£ ÏÂÃæµÄÀý×Ó´Ó `MyProperties` ±©Â¶ÁËÒ»¸ö `Map`¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties("my")
+public class MyProperties {
+
+ private final Map map = new LinkedHashMap<>();
+
+ public Map getMap() {
+ return this.map;
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+¿¼ÂÇÒÔÏÂÅäÖá£
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+my.map.key1.name=my name 1
+my.map.key1.description=my description 1
+#---
+spring.config.activate.on-profile=dev
+my.map.key1.name=dev name 1
+my.map.key2.name=dev name 2
+my.map.key2.description=dev description 2
+
+```
+
+
+
+
+
+
+
+Èç¹û `dev` ÅäÖÃÎļþûÓм¤»î£¬`MyProperties.map` °üº¬Ò»¸ökeyΪ `key1` µÄÌõÄ¿£¨nameΪ `my name 1` £¬descriptionΪ `my description 1` £©¡£ È»¶ø£¬Èç¹û `dev` ÅäÖÃÎļþ±»¼¤»î£¬`map` °üº¬Á½¸öÌõÄ¿£¬keyΪ `key1` £¨nameΪ `dev name 1`£¬descriptionΪ `my description 1` £©ºÍ `key2`£¨nameΪ `dev name 2`£¬descriptionΪ `dev description 2`£©¡£
+
+
+
+
+
+| | Ç°ÃæµÄºÏ²¢¹æÔòÊÊÓÃÓÚËùÓÐÊôÐÔÔ´µÄÊôÐÔ£¬¶ø²»½ö½öÊÇÎļþ¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.conversion)2.8.8\. ÊôÐÔ£¨Properties£©×ª»»
+
+
+
+µ±Spring BootÓë `@ConfigurationProperties` Bean°ó¶¨Ê±£¬ËüÊÔͼ½«Íⲿapplication propertiesÇ¿ÖÆ¸ÄΪÕýÈ·µÄÀàÐÍ¡£ Èç¹ûÄãÐèÒª×Ô¶¨ÒåÀàÐÍת»»£¬Äã¿ÉÒÔÌṩһ¸ö `ConversionService` bean£¨BeanµÄÃû³ÆÎª `conversionService` £©»ò×Ô¶¨ÒåÊôÐÔ±à¼Æ÷£¨Í¨¹ý `CustomEditorConfigurer` bean£©»ò×Ô¶¨Òå `Converters` Bean£¨Ê¹Óà `@ConfigurationPropertiesBinding` ×¢½â£©¡£
+
+
+
+
+
+| | ÓÉÓÚÕâ¸öBeanÊÇÔÚÓ¦ÓóÌÐòÉúÃüÖÜÆÚµÄÔçÆÚ±»ÇëÇóµÄ£¬ÇëÈ·±£ÏÞÖÆÄãµÄ `ConversionService` ËùʹÓõÄÒÀÀµ¹ØÏµ¡£ ͨ³£Çé¿öÏ£¬ÄãËùÐèÒªµÄÈκÎÒÀÀµ¹ØÏµÔÚ´´½¨Ê±¿ÉÄÜûÓÐÍêÈ«³õʼ»¯¡£ Èç¹ûÄãµÄ×Ô¶¨Òå `ConversionService` ²»ÐèÒªÅäÖÃkeys coercion£¬Äã¿ÉÄÜÏëÖØÃüÃûËü£¬²¢ÇÒÖ»ÒÀÀµÓà `@ConfigurationPropertiesBinding` ÏÞ¶¨µÄ×Ô¶¨Òåת»»Æ÷¡£ |
+| --- | --- |
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.conversion.durations)ת»»Îª Duration
+
+
+
+Spring Boot¶Ô±í´ï³ÖÐøÊ±¼äÓÐרÃŵÄÖ§³Ö¡£ Èç¹ûÄ㹫¿ªÁËÒ»¸ö `java.time.Duration` ÊôÐÔ£¬application propertiesÖеÄÒÔϸñʽ¾Í¿ÉÓá£
+
+
+
+
+
+* ÆÕͨµÄ `long` £¨Ê¹ÓúÁÃë×÷ΪĬÈϵ¥Î»£¬³ý·ÇÖ¸¶¨ÁË `@DurationUnit` £©¡£
+
+* ±ê×¼µÄISO-8601¸ñʽ [ÓÉ `java.time.Duration` ʹÓÃ](https://docs.oracle.com/javase/17/docs/api/java/time/Duration.html#parse-java.lang.CharSequence-)¡£
+
+* Ò»¸ö¸üÒ×¶ÁµÄ¸ñʽ£¬ÆäÖÐÖµºÍµ¥Î»ÊÇñîºÏµÄ£¨`10s` ±íʾ10Ã룩¡£
+
+
+
+
+
+Ç뿼ÂÇÒÔÏÂÀý×Ó¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties("my")
+public class MyProperties {
+
+ @DurationUnit(ChronoUnit.SECONDS)
+ private Duration sessionTimeout = Duration.ofSeconds(30);
+
+ private Duration readTimeout = Duration.ofMillis(1000);
+
+ // getters / setters...
+
+}
+
+```
+
+
+
+
+
+
+
+ÒªÖ¸¶¨Ò»¸ö30ÃëµÄ»á»°³¬Ê±£¬ `30` ¡¢ `PT30S` ºÍ `30s` ¶¼Êǵȼ۵ġ£ ¶ÁÈ¡³¬Ê±Îª500ms£¬¿ÉÒÔÓÃÒÔÏÂÈκÎÒ»ÖÖÐÎʽָ¶¨¡£ `500`, `PT0.5S` ºÍ `500ms`.
+
+
+
+
+
+ÄãÒ²¿ÉÒÔʹÓÃÈçÏÂÖ§³ÖµÄʱ¼äµ¥Î»¡£
+
+
+
+
+
+* `ns` ÄÉÃë
+
+* `us` ΢Ãë
+
+* `ms` ºÁÃë
+
+* `s` Ãë
+
+* `m` ·Ö
+
+* `h` Сʱ
+
+* `d` Ìì
+
+
+
+
+
+ĬÈϵ¥Î»ÊǺÁÃ룬¿ÉÒÔʹÓà `@DurationUnit` À´ÖØÐ´£¬ÈçÉÏÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+Èç¹ûÄãϲ»¶Ê¹Óù¹Ô캯Êý°ó¶¨£¬Í¬ÑùµÄÊôÐÔ¿ÉÒÔ±»±©Â¶³öÀ´£¬ÈçÏÂÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties("my")
+public class MyProperties {
+
+ // fields...
+
+ public MyProperties(@DurationUnit(ChronoUnit.SECONDS) @DefaultValue("30s") Duration sessionTimeout,
+ @DefaultValue("1000ms") Duration readTimeout) {
+ this.sessionTimeout = sessionTimeout;
+ this.readTimeout = readTimeout;
+ }
+
+ // getters...
+
+}
+
+```
+
+
+
+
+
+
+
+| | Èç¹ûÄãÒªÉý¼¶Ò»¸ö `Long` µÄÊôÐÔ£¬Èç¹ûËü²»ÊǺÁÃ룬ÇëÈ·±£¶¨Ò嵥λ£¨Ê¹Óà `@DurationUnit` £©¡£ ÕâÑù×öÌṩÁËÒ»¸ö͸Ã÷µÄÉý¼¶Â·¾¶£¬Í¬Ê±Ö§³Ö¸ü·á¸»µÄ¸ñʽ |
+| --- | --- |
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.conversion.periods)ת»»ÎªÆÚ¼ä£¨Period£©
+
+
+
+³ýÁËduration£¬Spring Boot»¹¿ÉÒÔʹÓà `java.time.Period` ÀàÐÍ¡£ ÒÔϸñʽ¿ÉÒÔÔÚapplication propertiesÖÐʹÓá£
+
+
+
+
+
+* Ò»¸ö³£¹æµÄ `int` ±íʾ·¨£¨Ê¹ÓÃÌì×÷ΪĬÈϵ¥Î»£¬³ý·ÇÖ¸¶¨ÁË `@PeriodUnit` £©¡£
+
+* ±ê×¼µÄISO-8601¸ñʽ [ÓÉ `java.time.Period` ʹÓÃ](https://docs.oracle.com/javase/17/docs/api/java/time/Period.html#parse-java.lang.CharSequence-)¡£
+
+* Ò»¸ö¸ü¼òµ¥µÄ¸ñʽ£¬ÆäÖÐÖµºÍµ¥Î»¶ÔÊÇñîºÏµÄ£¨ `1y3d` ±íʾ1Äê3Ì죩¡£
+
+
+
+
+
+Ö§³ÖÏÂÁмòµ¥µÄµ¥Î»¸ñʽ¡£
+
+
+
+
+
+* `y` Äê
+
+* `m` ÔÂ
+
+* `w` ÖÜ
+
+* `d` ÈÕ
+
+
+
+
+
+| | `java.time.Period` ÀàÐÍʵ¼ÊÉÏ´Óδ´æ´¢¹ýÖÜÊý£¬ËüÊÇÒ»¸ö¿ì½Ý·½Ê½£¬Òâζ×Å ¡°7Ì족¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.conversion.data-sizes)ת»»ÎªÊý¾Ý´óС£¨Data Sizes£©
+
+
+
+Spring FrameworkÓÐÒ»¸ö `DataSize` ÖµÀàÐÍ£¬ÒÔ×Ö½ÚΪµ¥Î»±í´ï´óС¡£ Èç¹ûÄ㹫¿ªÁËÒ»¸ö `DataSize` ÊôÐÔ£¬application propertiesÖеÄÒÔϸñʽ¾Í¿ÉÓá£
+
+
+
+
+
+* Ò»¸ö³£¹æµÄ `long` ±íʾ£¨Ê¹ÓÃ×Ö½Ú×÷ΪĬÈϵ¥Î»£¬³ý·ÇÖ¸¶¨ÁË `@DataSizeUnit`£©¡£
+
+* Ò»¸ö¸üÒ×¶ÁµÄ¸ñʽ£¬ÆäÖÐÖµºÍµ¥Î»ÊÇñîºÏµÄ£¨`10MB` Òâζ×Å10Õ××Ö½Ú£©¡£
+
+
+
+
+
+¿¼ÂÇÒÔÏÂÀý×Ó¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties("my")
+public class MyProperties {
+
+ @DataSizeUnit(DataUnit.MEGABYTES)
+ private DataSize bufferSize = DataSize.ofMegabytes(2);
+
+ private DataSize sizeThreshold = DataSize.ofBytes(512);
+
+ // getters/setters...
+
+}
+
+```
+
+
+
+
+
+
+
+ÒªÖ¸¶¨Ò»¸ö10Õ××Ö½Ú£¨Mb£©µÄ»º³åÇø´óС£¬ `10` ºÍ `10MB` Êǵȼ۵ġ£ 256×ֽڵĴóСãÐÖµ¿ÉÒÔÖ¸¶¨Îª `256` »ò `256B`¡£
+
+
+
+
+
+ÄãÒ²¿ÉÒÔʹÓÃÈçÏÂÕâЩ֧³ÖµÄµ¥Î»¡£
+
+
+
+
+
+* `B` ×Ö½Ú
+
+* `KB` KB
+
+* `MB` MB
+
+* `GB` GB
+
+* `TB` TB
+
+
+
+
+
+ĬÈϵ¥Î»ÊÇ×Ö½Ú£¬¿ÉÒÔʹÓà `@DataSizeUnit` À´ÖØÐ´£¬ÈçÉÏÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+Èç¹ûÄãϲ»¶Ê¹Óù¹Ô캯Êý°ó¶¨£¬Í¬ÑùµÄÊôÐÔ¿ÉÒÔ±»±©Â¶³öÀ´£¬ÈçÏÂÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties("my")
+public class MyProperties {
+
+ // fields...
+
+ public MyProperties(@DataSizeUnit(DataUnit.MEGABYTES) @DefaultValue("2MB") DataSize bufferSize,
+ @DefaultValue("512B") DataSize sizeThreshold) {
+ this.bufferSize = bufferSize;
+ this.sizeThreshold = sizeThreshold;
+ }
+
+ // getters...
+
+}
+
+```
+
+
+
+
+
+
+
+| | Èç¹ûÄãÕýÔÚÉý¼¶Ò»¸ö `Long` ÊôÐÔ£¬È·±£¶¨Ò嵥λ£¨Ê¹Óà `@DataSizeUnit`£©£¬Èç¹ûËü²»ÊÇ×Ö½Ú¡£ ÕâÑù×öÌṩÁËÒ»¸ö͸Ã÷µÄÉý¼¶Â·¾¶£¬Í¬Ê±Ö§³Ö¸ü·á¸»µÄ¸ñʽ¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.validation)2.8.9\. @ConfigurationProperties УÑé
+
+
+
+ֻҪʹÓÃSpringµÄ `@Validated` ×¢½â£¬Spring Boot¾Í»á³¢ÊÔÑéÖ¤ `@ConfigurationProperties` Àà¡£ Äã¿ÉÒÔÖ±½ÓÔÚÄãµÄÅäÖÃÀàÉÏʹÓÃJSR-303µÄ `jakarta.validation` Ô¼Êø×¢½â¡£ Òª×öµ½ÕâÒ»µã£¬ÇëÈ·±£ÄãµÄclasspathÉÏÓÐÒ»¸ö¼æÈݵÄJSR-303ʵÏÖ£¬È»ºó½«Ô¼Êø×¢½âÌí¼Óµ½ÄãµÄ×Ö¶ÎÖУ¬ÈçÏÂÃæµÄÀý×ÓËùʾ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties("my.service")
+@Validated
+public class MyProperties {
+
+ @NotNull
+ private InetAddress remoteAddress;
+
+ // getters/setters...
+
+}
+
+```
+
+
+
+
+
+
+
+| | ÄãÒ²¿ÉÒÔͨ¹ýÔÚ configuration properties µÄ `@Bean` ·½·¨ÉÏ×¢½â `@Validated` À´´¥·¢ÑéÖ¤¡£ |
+| --- | --- |
+
+
+
+
+
+ΪÁËÈ·±£×ÜÊÇΪǶÌ×µÄÊôÐÔ´¥·¢ÑéÖ¤£¬¼´Ê¹Ã»ÓÐÕÒµ½ÊôÐÔ£¬Ïà¹ØµÄ×ֶαØÐëÓà `@Valid` À´×¢ÊÍ¡£ ÏÂÃæµÄÀý×Ó½¨Á¢ÔÚÇ°ÃæµÄ `MyProperties` µÄ»ù´¡ÉÏ¡£
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ConfigurationProperties("my.service")
+@Validated
+public class MyProperties {
+
+ @NotNull
+ private InetAddress remoteAddress;
+
+ @Valid
+ private final Security security = new Security();
+
+ // getters/setters...
+
+ public static class Security {
+
+ @NotEmpty
+ private String username;
+
+ // getters/setters...
+
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+ÄãÒ²¿ÉÒÔͨ¹ý´´½¨Ò»¸öÃûΪ `configurationPropertiesValidator` µÄbean¶¨ÒåÀ´Ìí¼ÓÒ»¸ö×Ô¶¨ÒåµÄSpring `Validator`¡£ `@Bean` ·½·¨Ó¦¸Ã±»ÉùÃ÷Ϊ `static`¡£ ÅäÖÃÊôÐÔÑéÖ¤Æ÷ÊÇÔÚÓ¦ÓóÌÐòÉúÃüÖÜÆÚµÄÔçÆÚ´´½¨µÄ£¬½« `@Bean` ·½·¨ÉùÃ÷Ϊ¾²Ì¬£¬¿ÉÒÔÈÃBeanµÄ´´½¨²»ÐèҪʵÀý»¯ `@Configuration` Àà¡£ ÕâÑù×ö¿ÉÒÔ±ÜÃâ¹ýÔçʵÀý»¯¿ÉÄÜÒýÆðµÄÈκÎÎÊÌâ¡£
+
+
+
+
+
+| | `spring-boot-actuator` Ä£¿é°üÀ¨Ò»¸ö±©Â¶ËùÓÐ `@ConfigurationProperties` Bean µÄ¶Ëµã¡£ Äã¿ÉÒÔͨ¹ýä¯ÀÀÆ÷·ÃÎÊ `/actuator/configprops` »òʹÓÃÏàÓ¦µÄJMX¶Ëµã¡£ ÏêÇé¼û"[Éú²ú¾ÍÐ÷](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints)"²¿·Ö¡£ |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.vs-value-annotation)2.8.10\. @ConfigurationProperties vs. @Value
+
+
+
+`@Value` ×¢½âÊÇÒ»¸öºËÐĵÄÈÝÆ÷¹¦ÄÜ£¬Ëü²»ÌṩÓëÀàÐͰ²È«µÄÅäÖÃÊôÐÔÏàͬµÄ¹¦ÄÜ¡£ ϱí×ܽáÁË `@ConfigurationProperties` ºÍ `@Value` ËùÖ§³ÖµÄ¹¦ÄÜ¡£
+
+
+
+
+| ¹¦ÄÜ | `@ConfigurationProperties` | `@Value` |
+| --- | --- | --- |
+| [¿íËɰó¶¨](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.relaxed-binding) | Yes | ÓÐÏÞÖÆ (¼û [ÏÂÎÄ×¢ÊÍ](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.vs-value-annotation.note)) |
+| [Ö§³Ö Meta-data](https://springdoc.cn/spring-boot/configuration-metadata.html#appendix.configuration-metadata) | Yes | No |
+| `SpEL` ±í´ïʽ | No | Yes |
+
+
+
+| | Èç¹ûÄãȷʵÏëʹÓà `@Value`£¬ÎÒÃǽ¨ÒéÄãʹÓÃÊôÐÔÃû³ÆµÄ¹æ·¶ÐÎʽ£¨½öʹÓÃСд×ÖĸµÄkebab-case£©À´ÒýÓÃÊôÐÔÃû³Æ¡£ Õ⽫ÔÊÐíSpring BootʹÓÃÓë [¿íËɰó¶¨](https://springdoc.cn/spring-boot/features.html#features.external-config.typesafe-configuration-properties.relaxed-binding) `@ConfigurationProperties` ʱÏàͬµÄÂß¼¡£ÀýÈ磬`@Value("${demo.item-price}")` ½«´Ó `application.properties` ÎļþÖлñÈ¡ `demo.item-price` ºÍ `demo.itemPrice` ÐÎʽ£¬ÒÔ¼°´Óϵͳ»·¾³ÖлñÈ¡ `DEMO_ITEMPRICE`¡£ Èç¹ûÄãÓà `@Value("${demo.itemPrice}")` ´úÌæ£¬`demo.item-price` ºÍ `DEMO_ITEMPRICE` ½«²»»á±»¿¼ÂÇ¡£ |
+| --- | --- |
+
+
+
+
+
+Èç¹ûÄãΪÄã×Ô¼ºµÄ×é¼þ¶¨ÒåÁËÒ»×éÅäÖüü£¬ÎÒÃǽ¨ÒéÄ㽫ËüÃÇ·Ö×éÔÚÒ»¸öÓà `@ConfigurationProperties` ×¢½âµÄPOJOÖС£ ÕâÑù×ö½«ÎªÄãÌṩ½á¹¹»¯µÄ¡¢ÀàÐͰ²È«µÄ¶ÔÏó£¬Äã¿ÉÒÔ½«Æä×¢Èëµ½Äã×Ô¼ºµÄbeanÖС£
+
+
+
+
+
+À´×ÔÓ¦ÓÃ[application property](https://springdoc.cn/spring-boot/features.html#features.external-config.files) ÎļþµÄ `SpEL` ±í´ïʽÔÚ½âÎöÕâЩÎļþºÍÌî³äenvironmentʱ²»»á±»´¦Àí¡£ È»¶ø£¬¿ÉÒÔÔÚ `@Value` ÖÐдһ¸ö `SpEL` ±í´ïʽ¡£ Èç¹ûÀ´×ÔÓ¦ÓóÌÐòÊôÐÔÎļþµÄÊôÐÔÖµÊÇÒ»¸ö `SpEL` ±í´ïʽ£¬Ëü½«ÔÚ±» `@Value` Ïû·Ñʱ±»½âÎö¡£
+
+
+
+
+
+
+
+
+
+
+
+
+
+## [](https://springdoc.cn/spring-boot/features.html#features.profiles)
+
diff --git "a/docs/spring/SpringBoot/SpringBoot\350\207\252\345\270\246\347\232\204\347\203\255\351\203\250\347\275\262\345\267\245\345\205\267.md" "b/docs/spring/SpringBoot/SpringBoot\350\207\252\345\270\246\347\232\204\347\203\255\351\203\250\347\275\262\345\267\245\345\205\267.md"
new file mode 100644
index 0000000..477370a
--- /dev/null
+++ "b/docs/spring/SpringBoot/SpringBoot\350\207\252\345\270\246\347\232\204\347\203\255\351\203\250\347\275\262\345\267\245\345\205\267.md"
@@ -0,0 +1,345 @@
+# SpringBootÈëÃÅ - ÅäÖÃÈȲ¿Êðdevtools¹¤¾ß
+
+> ÔÚSpringBoot¿ª·¢µ÷ÊÔÖУ¬Èç¹ûÎÒÿÐдúÂëµÄÐ޸ͼÐèÒªÖØÆôÆô¶¯ÔÙµ÷ÊÔ£¬¿ÉÄܱȽϷÑʱ¼ä£»SpringBootÍŶÓÕë¶Ô´ËÎÊÌâÌṩÁËspring-boot-devtools£¨¼ò³Ædevtools£©²å¼þ£¬ËüÊÔͼÌáÉý¿ª·¢µ÷ÊÔµÄЧÂÊ¡£@pdai
+
+* [SpringBootÈëÃÅ - ÅäÖÃÈȲ¿Êðdevtools¹¤¾ß](#springboot%E5%85%A5%E9%97%A8---%E9%85%8D%E7%BD%AE%E7%83%AD%E9%83%A8%E7%BD%B2devtools%E5%B7%A5%E5%85%B7)
+ * [×¼±¸ÖªÊ¶µã](#%E5%87%86%E5%A4%87%E7%9F%A5%E8%AF%86%E7%82%B9)
+ * [ʲôÊÇÈȲ¿ÊðºÍÈȼÓÔØ£¿](#%E4%BB%80%E4%B9%88%E6%98%AF%E7%83%AD%E9%83%A8%E7%BD%B2%E5%92%8C%E7%83%AD%E5%8A%A0%E8%BD%BD)
+ * [ʲôÊÇLiveLoad£¿](#%E4%BB%80%E4%B9%88%E6%98%AFliveload)
+ * [ÅäÖÃdevtoolsʵÏÖÈȲ¿Êð](#%E9%85%8D%E7%BD%AEdevtools%E5%AE%9E%E7%8E%B0%E7%83%AD%E9%83%A8%E7%BD%B2)
+ * [POMÅäÖÃ](#pom%E9%85%8D%E7%BD%AE)
+ * [IDEAÅäÖÃ](#idea%E9%85%8D%E7%BD%AE)
+ * [application.ymlÅäÖÃ](#applicationyml%E9%85%8D%E7%BD%AE)
+ * [ʹÓÃLiveLoad](#%E4%BD%BF%E7%94%A8liveload)
+ * [½øÒ»²½Àí½â](#%E8%BF%9B%E4%B8%80%E6%AD%A5%E7%90%86%E8%A7%A3)
+ * [devtoolµÄÔÀí£¿ÎªºÎ»á×Ô¶¯ÖØÆô£¿](#devtool%E7%9A%84%E5%8E%9F%E7%90%86%E4%B8%BA%E4%BD%95%E4%BC%9A%E8%87%AA%E5%8A%A8%E9%87%8D%E5%90%AF)
+ * [devtoolÊÇ·ñ»á±»´ò°ü½øJar£¿](#devtool%E6%98%AF%E5%90%A6%E4%BC%9A%E8%A2%AB%E6%89%93%E5%8C%85%E8%BF%9Bjar)
+ * [devtoolΪºÎ»áĬÈϽûÓûº´æÑ¡Ï](#devtool%E4%B8%BA%E4%BD%95%E4%BC%9A%E9%BB%98%E8%AE%A4%E7%A6%81%E7%94%A8%E7%BC%93%E5%AD%98%E9%80%89%E9%A1%B9)
+ * [devtoolÊÇ·ñ¿ÉÒÔ¸øËùÓÐSpringbootÓ¦ÓÃ×öÈ«¾ÖµÄÅäÖã¿](#devtool%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E7%BB%99%E6%89%80%E6%9C%89springboot%E5%BA%94%E7%94%A8%E5%81%9A%E5%85%A8%E5%B1%80%E7%9A%84%E9%85%8D%E7%BD%AE)
+ * [Èç¹ûÎÒ²»ÓÃdevtool£¬»¹ÓÐʲôѡÔñ£¿](#%E5%A6%82%E6%9E%9C%E6%88%91%E4%B8%8D%E7%94%A8devtool%E8%BF%98%E6%9C%89%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9)
+ * [ʾÀýÔ´Âë](#%E7%A4%BA%E4%BE%8B%E6%BA%90%E7%A0%81)
+ * [²Î¿¼ÎÄÕÂ](#%E5%8F%82%E8%80%83%E6%96%87%E7%AB%A0)
+
+## [#](#×¼±¸ÖªÊ¶µã) ×¼±¸ÖªÊ¶µã
+
+### [#](#ʲôÊÇÈȲ¿ÊðºÍÈȼÓÔØ) ʲôÊÇÈȲ¿ÊðºÍÈȼÓÔØ£¿
+
+> ÈȲ¿ÊðºÍÈȼÓÔØÊÇÔÚÓ¦ÓÃÕýÔÚÔËÐеÄʱºò£¬×Ô¶¯¸üУ¨ÖØÐ¼ÓÔØ»òÕßÌæ»»classµÈ£©Ó¦ÓõÄÒ»ÖÖÄÜÁ¦¡££¨PS£ºspring-boot-devtoolsÌṩµÄ·½°¸Ò²ÊÇÒªÖØÆôµÄ£¬Ö»ÊÇÎÞÐèÊÖ¶¯ÖØÆôÄÜʵÏÖ×Ô¶¯¼ÓÔØ¶øÒÑ¡££©
+
+ÑϸñÒâÒåÉÏ£¬ÎÒÃÇÐè񻂿·ÖÏÂÈȲ¿ÊðºÍÈȼÓÔØ, ¶ÔÓÚJavaÏîÄ¿¶øÑÔ£º
+
+* **ÈȲ¿Êð**
+
+ * ÔÚ·þÎñÆ÷ÔËÐÐÊ±ÖØÐ²¿ÊðÏîÄ¿
+ * ËüÊÇÖ±½ÓÖØÐ¼ÓÔØÕû¸öÓ¦Óã¬ÕâÖÖ·½Ê½»áÊÍ·ÅÄڴ棬±ÈÈȼÓÔØ¸ü¼Ó¸É¾»³¹µ×£¬µ«Í¬Ê±Ò²¸ü·Ñʱ¼ä¡£
+* **ÈȼÓÔØ**
+
+ * ÔÚÔÚÔËÐÐÊ±ÖØÐ¼ÓÔØclass£¬´Ó¶øÉý¼¶Ó¦Óá£
+ * ÈȼÓÔØµÄʵÏÖÔÀíÖ÷ÒªÒÀÀµ[javaµÄÀà¼ÓÔØ»úÖÆ](/md/java/jvm/java-jvm-classload.html)£¬ÔÚʵÏÖ·½Ê½¿ÉÒÔ¸ÅÀ¨ÎªÔÚÈÝÆ÷Æô¶¯µÄʱºòÆðÒ»Ìõºǫ́Ị̈߳¬¶¨Ê±µÄ¼ì²âÀàÎļþµÄʱ¼ä´Á±ä»¯£¬Èç¹ûÀàµÄʱ¼ä´Á±äµôÁË£¬Ôò½«ÀàÖØÐÂÔØÈë¡£
+ * ¶Ô±È·´Éä»úÖÆ£¬·´ÉäÊÇÔÚÔËÐÐʱ»ñÈ¡ÀàÐÅÏ¢£¬Í¨¹ý¶¯Ì¬µÄµ÷ÓÃÀ´¸Ä±ä³ÌÐòÐÐΪ£» ÈȼÓÔØÔòÊÇÔÚÔËÐÐʱͨ¹ýÖØÐ¼ÓÔØ¸Ä±äÀàÐÅÏ¢£¬Ö±½Ó¸Ä±ä³ÌÐòÐÐΪ¡£
+
+### [#](#ʲôÊÇliveload) ʲôÊÇLiveLoad£¿
+
+LiveLoadÊÇÌṩä¯ÀÀÆ÷¿Í»§¶Ë×Ô¶¯¼ÓÔØ¸üÐµĹ¤¾ß£¬·ÖΪLiveLoad·þÎñÆ÷ºÍLiveloadä¯ÀÀÆ÷²å¼þÁ½²¿·Ö£» devtoolsÖÐÒѾ¼¯³ÉÁËLiveLoad·þÎñÆ÷£¬ËùÒÔÈç¹ûÎÒÃÇ¿ª·¢µÄÊÇwebÓ¦Ó㬲¢ÇÒÆÚÍûä¯ÀÀÆ÷×Ô¶¯Ë¢Ð£¬ Õâʱºò¿ÉÒÔ¿¼ÂÇLiveLoad.
+
+
+
+ͬһʱ¼äÖ»ÄÜÔËÐÐÒ»¸öLiveReload·þÎñÆ÷¡£ ¿ªÊ¼Ó¦ÓóÌÐò֮ǰ£¬ÇëÈ·±£Ã»ÓÐÆäËûLiveReload·þÎñÆ÷ÕýÔÚÔËÐС£Èç¹û´ÓIDEÆô¶¯¶à¸öÓ¦ÓóÌÐò£¬ÔòÖ»ÓеÚÒ»¸öÓ¦ÓóÌÐò½«Ö§³ÖLiveReload¡£
+
+## [#](#ÅäÖÃdevtoolsʵÏÖÈȲ¿Êð) ÅäÖÃdevtoolsʵÏÖÈȲ¿Êð
+
+> ÎÒÃÇͨ¹ýÈçÏÂÅäÖÃÀ´ÊµÏÖ×Ô¶¯ÖØÆô·½Ê½µÄÈȲ¿Êð¡£
+
+### [#](#pomÅäÖÃ) POMÅäÖÃ
+
+Ìí¼Óspring-boot-devtoolsµÄÒÀÀµ
+
+
+
+```
+
+
+ org.springframework.boot
+ spring-boot-devtools
+ true
+
+
+
+```
+
+
+
+### [#](#ideaÅäÖÃ) IDEAÅäÖÃ
+
+> Èç¹ûÄãʹÓÃIDEA¿ª·¢¹¤¾ß£¬Í¨³£ÓÐÈçÏÂÁ½ÖÖ·½Ê½£º
+
+* ·½Ê½Ò»£º **ÎÞÈκÎÅäÖÃʱ£¬ÊÖ¶¯´¥·¢ÖØÆô¸üУ¨Ctrl+F9£©**
+
+
+£¨Ò²¿ÉÒÔÓÃ`mvn compile`±àÒë´¥·¢ÖØÆô¸üУ©
+
+* ·½Ê½¶þ£º **IDEAÐ迪ÆôÔËÐÐʱ±àÒ룬×Ô¶¯ÖØÆô¸üÐÂ**
+
+**ÉèÖÃ1**£º
+
+File->Setting->Build,Execution,Deployment->Compile
+
+¹´Ñ¡£ºMake project automatically
+
+
+
+**ÉèÖÃ2**£º
+
+¿ì½Ý¼ü£ºctrl+alt+shift+/
+
+Ñ¡Ôñ£ºRegistry
+
+¹´Ñ¡£ºcompiler.automake.allow.when.app.running
+
+а汾µÄIDEA¿ÉÒÔÔÚFile->setting->Advanced SetttingsÀïÃæµÄµÚÒ»¸öÉèÖãº
+
+
+### [#](#application-ymlÅäÖÃ) application.ymlÅäÖÃ
+
+
+
+```
+spring:
+ devtools:
+ restart:
+ enabled: true #ÉèÖÿªÆôÈȲ¿Êð
+ additional-paths: src/main/java #ÖØÆôĿ¼
+ exclude: WEB-INF/**
+ thymeleaf:
+ cache: false #ʹÓÃThymeleafÄ£°åÒýÇæ£¬¹Ø±Õ»º´æ
+
+```
+
+
+
+### [#](#ʹÓÃliveload) ʹÓÃLiveLoad
+
+spring-boot-devtoolsÄ£¿é°üº¬**ǶÈëʽLiveReload·þÎñÆ÷**£¬¿ÉÒÔÔÚ×ÊÔ´¸ü¸ÄʱÓÃÓÚ´¥·¢ä¯ÀÀÆ÷ˢС£ LiveReloadä¯ÀÀÆ÷À©Õ¹³ÌÐòÖ§³ÖChrome£¬FirefoxºÍSafari£¬Äã¿ÉÒÔ´Ólivereload.comÃâ·ÑÏÂÔØ¡£
+
+
+»òÕß´Óä¯ÀÀÆ÷²å¼þÖÐÐÄÏÂÔØ£¬±ÈÈçfirefox:
+
+
+
+°²×°ÍêÖ®ºó£¬¿ÉÒÔͨ¹ýÈçÏÂͼ±ê¹ÜÀí
+
+
+
+Èç¹ûÄã²»ÏëÔÚÓ¦ÓóÌÐòÔËÐÐʱÆô¶¯LiveReload·þÎñÆ÷£¬Ôò¿ÉÒÔ½«spring.devtools.livereload.enabledÊôÐÔÉèÖÃΪfalse ¡£
+
+ͬһʱ¼äÖ»ÄÜÔËÐÐÒ»¸öLiveReload·þÎñÆ÷¡£ ¿ªÊ¼Ó¦ÓóÌÐò֮ǰ£¬ÇëÈ·±£Ã»ÓÐÆäËûLiveReload·þÎñÆ÷ÕýÔÚÔËÐС£Èç¹û´ÓIDEÆô¶¯¶à¸öÓ¦ÓóÌÐò£¬ÔòÖ»ÓеÚÒ»¸öÓ¦ÓóÌÐò½«Ö§³ÖLiveReload¡£
+
+## [#](#½øÒ»²½Àí½â) ½øÒ»²½Àí½â
+
+> ËäȻһЩ¿ª·¢Õß»áʹÓÃdevtool¹¤¾ß£¬µ«ÊǺÜÉÙÓÐÄܹ»ÉîÈëÀí½âµÄ£»ÈÃÎÒÃÇÀí½âÈçϼ¸¸öÎÊÌ⣬°ïÖúÄã½øÒ»²½Àí½â¡£@pdai
+
+### [#](#devtoolµÄÔÀí-ΪºÎ»á×Ô¶¯ÖØÆô) devtoolµÄÔÀí£¿ÎªºÎ»á×Ô¶¯ÖØÆô£¿
+
+> ΪʲôͬÑùÊÇÖØÆôÓ¦Óã¬ÎªÊ²Ã´²»ÊÖ¶¯ÖØÆô£¬¶øÊǽ¨ÒéʹÓÃspring-boot-devtools½øÐÐÈȲ¿ÊðÖØÆô£¿
+
+spring-boot-devtoolsʹÓÃÁËÁ½¸öÀà¼ÓÔØÆ÷ClassLoader£¬Ò»¸öClassLoader¼ÓÔØ²»»á·¢Éú¸ü¸ÄµÄÀࣨµÚÈý·½jar°ü£©£¬ÁíÒ»¸öClassLoader£¨restart ClassLoader£©¼ÓÔØ»á¸ü¸ÄµÄÀࣨ×Ô¶¨ÒåµÄÀࣩ¡£
+
+ºǫ́Æô¶¯Ò»¸ö**Îļþ¼àÌýỊ̈߳¨File Watcher£©**£¬**¼à²âµÄĿ¼ÖеÄÎļþ·¢Éú±ä¶¯Ê±£¬ ÔÀ´µÄrestart ClassLoader±»¶ªÆú£¬½«»áÖØÐ¼ÓÔØÐµÄrestart ClassLoader**¡£
+
+ÒòΪÎļþ±ä¶¯ºó£¬µÚÈý·½jar°ü²»ÔÙÖØÐ¼ÓÔØ£¬Ö»¼ÓÔØ×Ô¶¨ÒåµÄÀ࣬¼ÓÔØµÄÀà±È½ÏÉÙ£¬ËùÒÔÖØÆô±È½Ï¿ì¡£
+
+ÕâÒ²ÊÇΪʲô£¬Í¬ÑùÊÇÖØÆôÓ¦Óã¬ÎªÊ²Ã´²»ÊÖ¶¯ÖØÆô£¬½¨ÒéʹÓÃspring-boot-devtools½øÐÐÈȲ¿ÊðÖØÆô¡£
+
+ÔÚ×Ô¶¯ÖØÆôÖÐÓм¸µãÐèҪעÒâ:
+
+* **×Ô¶¯ÖØÆô»á¼Ç¼ÈÕÖ¾µÄ**
+
+£¨¼Ç¼ÔÚʲôÇé¿öÏÂÖØÆôµÄÈÕÖ¾£©
+
+¿ÉÒÔͨ¹ýÈçϹرÕ
+
+
+
+```
+spring:
+ devtools:
+ restart:
+ log-condition-evaluation-delta: false
+
+```
+
+
+
+* **ÅųýһЩ²»ÐèÒª×Ô¶¯ÖØÆôµÄ×ÊÔ´**
+
+ijЩ×ÊÔ´ÔÚ¸ü¸Äʱ²»Ò»¶¨ÐèÒª´¥·¢ÖØÐÂÆô¶¯¡£Ä¬ÈÏÇé¿öÏ£¬¸Ä±ä×ÊÔ´/META-INF/maven£¬/META-INF/resources£¬/resources£¬/static£¬/public£¬»ò/templates²»´¥·¢ÖØÐÂÆô¶¯£¬µ«È·»á´¥·¢ÏÖ³¡ÖØ×°¡£Èç¹ûÒª×Ô¶¨ÒåÕâЩÅųýÏ¿ÉÒÔʹÓøÃspring.devtools.restart.excludeÊôÐÔ¡£ÀýÈ磬Ҫ½öÅųý/static£¬/publicÄ㽫ÉèÖÃÒÔÏÂÊôÐÔ£º
+
+
+
+```
+spring:
+ devtools:
+ restart:
+ exclude: "static/**,public/**"
+
+```
+
+
+
+Èç¹ûÒª±£ÁôÕâЩĬÈÏÖµ²¢Ìí¼ÓÆäËûÅųýÏÇë¸ÄÓøÃspring.devtools.restart.additional-excludeÊôÐÔ¡£
+
+* **×Ô¶¨ÒåÖØÆôÀà¼ÓÔØÆ÷**
+
+ÖØÆô¹¦ÄÜÊÇͨ¹ýʹÓÃÁ½¸öÀà¼ÓÔØÆ÷À´ÊµÏֵġ£¶ÔÓÚ´ó¶àÊýÓ¦ÓóÌÐò£¬ÕâÖÖ·½·¨Ð§¹ûºÜºÃ¡£µ«ÊÇ£¬ËüÓÐʱ»áµ¼ÖÂÀà¼ÓÔØÎÊÌâ¡£
+
+ĬÈÏÇé¿öÏ£¬IDE ÖеÄÈκδò¿ªÏîÄ¿¶¼Ê¹Óá°ÖØÆô¡±Àà¼ÓÔØÆ÷¼ÓÔØ£¬Èκγ£¹æ.jarÎļþ¶¼Ê¹Óá°»ù±¾¡±Àà¼ÓÔØÆ÷¼ÓÔØ¡£Èç¹ûÄã´¦ÀíÒ»¸ö¶àÄ£¿éÏîÄ¿£¬²¢ÇÒ²»ÊÇÿ¸öÄ£¿é¶¼µ¼Èëµ½ÄãµÄ IDE ÖУ¬Äã¿ÉÄÜÐèÒª×Ô¶¨ÒåһЩ¶«Î÷¡£Îª´Ë£¬Äã¿ÉÒÔ´´½¨Ò»¸öMETA-INF/spring-devtools.propertiesÎļþ¡£
+
+¸Ãspring-devtools.propertiesÎļþ¿ÉÒÔ°üº¬ÒÔrestart.excludeºÍΪǰ׺µÄÊôÐÔrestart.include¡£¸ÃincludeÔªËØÊÇÓ¦¸Ã±»À¸ßµ½¡°ÖØÆô¡±µÄÀà¼ÓÔØÆ÷µÄÏîÄ¿£¬ÒÔ¼°excludeÒªËØÊÇÓ¦¸ÃÏòÏÂÍÆÈë¡°Base¡±Àà¼ÓÔØÆ÷µÄÏîÄ¿¡£¸ÃÊôÐÔµÄÖµÊÇÓ¦ÓÃÓÚÀà·¾¶µÄÕýÔò±í´ïʽģʽ£¬ÈçÒÔÏÂʾÀýËùʾ£º
+
+
+
+```
+restart:
+ exclude:
+ companycommonlibs: "/mycorp-common-[\\w\\d-\\.]+\\.jar"
+ include:
+ projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar"
+
+```
+
+
+
+¸ü¶àÏà¹ØµÄÐÅÏ¢¿ÉÒÔÔÚ[ÕâÀïÔÚд°¿Ú´ò¿ª](https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.devtools)²é¿´¡£
+
+### [#](#devtoolÊÇ·ñ»á±»´ò°ü½øjar) devtoolÊÇ·ñ»á±»´ò°ü½øJar£¿
+
+> devtoolÔÔòÉÏÀ´ËµÓ¦¸ÃÊÇÖ»ÔÚ¿ª·¢µ÷ÊÔµÄʱºòʹÓ㬶øÔÚÉú²ú»·¾³ÔËÐÐjar°üʱÊDz»ÐèÒªµÄ£¬ËùÒÔSpring´ò°ü»á²»»á°ÑËü´ò½øJARÂð£¿
+
+* **ĬÈÏÇé¿öÏ£¬²»»á±»´ò°ü½øJAR**
+
+ÔËÐдò°üµÄÓ¦ÓóÌÐòʱ£¬¿ª·¢ÈËÔ±¹¤¾ß**»á×Ô¶¯½ûÓÃ**¡£Èç¹ûÄãͨ¹ý java -jar»òÕ߯äËûÌØÊâµÄÀà¼ÓÔØÆ÷½øÐÐÆô¶¯Ê±£¬¶¼»á±»ÈÏΪÊÇ¡°Éú²ú»·¾³µÄÓ¦Óᱡ£
+
+* **Èç¹ûÎÒÃÇÆÚÍûÔ¶³Ìµ÷ÊÔÓ¦ÓÃ**
+
+£¨_Éú²ú»·¾³ÎðÓã¬Ö»ÓÐÔÚÊÜÐÅÈεÄÍøÂçÉÏÔËÐлòʹÓà SSL ½øÐб£»¤Ê±£¬²ÅÓ¦ÆôÓÃËü_£©
+
+ÔÚÕâÖÖÇé¿öÏ£¬devtoolÒ²¾ß±¸Ô¶³Ìµ÷ÊÔµÄÄÜÁ¦£ºÔ¶³Ì¿Í»§¶ËÓ¦ÓóÌÐòÖ¼ÔÚ´ÓÄãµÄ IDE ÖÐÔËÐС£ÄãÐèÒªorg.springframework.boot.devtools.RemoteSpringApplicationʹÓÃÓëÄãÁ¬½ÓµÄÔ¶³ÌÏîÄ¿ÏàͬµÄÀà·¾¶ÔËÐС£Ó¦ÓóÌÐòµÄΨһ±ØÐè²ÎÊýÊÇËüÁ¬½Óµ½µÄÔ¶³Ì URL¡£
+
+ÀýÈ磬Èç¹ûʹÓà Eclipse »ò Spring Tools£¬²¢ÇÒÄãÓÐÒ»¸ömy-appÒѲ¿Êðµ½ Cloud Foundry µÄÃûΪµÄÏîÄ¿£¬Ö´ÐÐÒÔϲÙ×÷£º
+
+1. Ñ¡ÔñRun Configurations¡?´ÓRun²Ëµ¥¡£
+2. ´´½¨Ò»¸öеÄJava Application¡°Æô¶¯ÅäÖᱡ£
+3. ä¯ÀÀmy-appÏîÄ¿¡£
+4. ʹÓÃorg.springframework.boot.devtools.RemoteSpringApplication×÷ΪÖ÷Àà¡£
+5. Ìí¼Óhttps://myapp.cfapps.ioµ½Program arguments£¨»òÈκÎÄãµÄÔ¶³Ì URL£©¡£
+
+ÕýÔÚÔËÐеÄÔ¶³Ì¿Í»§¶Ë¿ÉÄÜÀàËÆÓÚÒÔÏÂÁÐ±í£º
+
+
+
+```
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ ___ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | | _ \___ _ __ ___| |_ ___ \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| []::::::[] / -_) ' \/ _ \ _/ -_) ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | |_|_\___|_|_|_\___/\__\___|/ / / /
+ =========|_|==============|___/===================================/_/_/_/
+ :: Spring Boot Remote :: 2.5.4
+
+2015-06-10 18:25:06.632 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication : Starting RemoteSpringApplication on pwmbp with PID 14938 (/Users/pwebb/projects/spring-boot/code/spring-boot-project/spring-boot-devtools/target/classes started by pwebb in /Users/pwebb/projects/spring-boot/code)
+2015-06-10 18:25:06.671 INFO 14938 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2a17b7b6: startup date [Wed Jun 10 18:25:06 PDT 2015]; root of context hierarchy
+2015-06-10 18:25:07.043 WARN 14938 --- [ main] o.s.b.d.r.c.RemoteClientConfiguration : The connection to http://localhost:8080 is insecure. You should use a URL starting with 'https://'.
+2015-06-10 18:25:07.074 INFO 14938 --- [ main] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
+2015-06-10 18:25:07.130 INFO 14938 --- [ main] o.s.b.devtools.RemoteSpringApplication : Started RemoteSpringApplication in 0.74 seconds (JVM running for 1.105)
+
+```
+
+
+
+### [#](#devtoolΪºÎ»áĬÈϽûÓûº´æÑ¡Ïî) devtoolΪºÎ»áĬÈϽûÓûº´æÑ¡Ï
+
+> Spring Boot Ö§³ÖµÄһЩ¿â**ʹÓûº´æÀ´Ìá¸ßÐÔÄÜ**¡£ÀýÈ磬ģ°åÒýÇæ»º´æÒѱàÒëµÄÄ£°åÒÔ±ÜÃâÖØ¸´½âÎöÄ£°åÎļþ¡£´ËÍ⣬Spring MVC ¿ÉÒÔÔÚÌṩ¾²Ì¬×ÊԴʱÏòÏìÓ¦Ìí¼Ó HTTP »º´æ±êÍ·¡£
+
+ËäÈ»»º´æ**ÔÚÉú²úÖзdz£ÓÐÒæ£¬µ«ÔÚ¿ª·¢¹ý³ÌÖпÉÄÜ»áÊÊµÃÆä·´**£¬Ê¹ÄãÎÞ·¨¿´µ½¸Õ¸ÕÔÚÓ¦ÓóÌÐòÖÐËù×öµÄ¸ü¸Ä¡£³öÓÚÕâ¸öÔÒò£¬ spring-boot-devtools ĬÈϽûÓûº´æÑ¡Ïî¡£
+
+±ÈÈçThymeleaf ÌṩÁËspring.thymeleaf.cacheÀ´ÉèÖÃÄ£°åÒýÇæµÄ»º´æ£¬Ê¹ÓÃspring-boot-devtoolsÄ£¿éʱÊDz»ÐèÒªÊÖ¶¯ÉèÖÃÕâЩÊôÐԵģ¬ÒòΪspring-boot-devtools»á×Ô¶¯½øÐÐÉèÖá£
+
+ÄÇô»á×Ô¶¯ÉèÖÃÄÄЩÅäÖÃÄØ£¿Äã¿ÉÒÔÔÚDevToolsPropertyDefaultsPostProcessorÀàÕÒµ½¶ÔÓ¦µÄĬÈÏÅäÖá£
+
+
+
+```
+public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostProcessor {
+
+ static {
+ Map properties = new HashMap<>();
+ properties.put("spring.thymeleaf.cache", "false");
+ properties.put("spring.freemarker.cache", "false");
+ properties.put("spring.groovy.template.cache", "false");
+ properties.put("spring.mustache.cache", "false");
+ properties.put("server.servlet.session.persistent", "true");
+ properties.put("spring.h2.console.enabled", "true");
+ properties.put("spring.web.resources.cache.period", "0");
+ properties.put("spring.web.resources.chain.cache", "false");
+ properties.put("spring.template.provider.cache", "false");
+ properties.put("spring.mvc.log-resolved-exception", "true");
+ properties.put("server.error.include-binding-errors", "ALWAYS");
+ properties.put("server.error.include-message", "ALWAYS");
+ properties.put("server.error.include-stacktrace", "ALWAYS");
+ properties.put("server.servlet.jsp.init-parameters.development", "true");
+ properties.put("spring.reactor.debug", "true");
+ PROPERTIES = Collections.unmodifiableMap(properties);
+ }
+
+```
+
+
+
+µ±È»Èç¹ûÄã²»Ïë±»Ó¦ÓÃÊôÐÔ±»spring-boot-devtoolsĬÈÏÉèÖ㬠¿ÉÒÔͨ¹ýspring.devtools.add-propertiesµ½falseÄãapplication.ymlÖС£
+
+### [#](#devtoolÊÇ·ñ¿ÉÒÔ¸øËùÓÐspringbootÓ¦ÓÃ×öÈ«¾ÖµÄÅäÖÃ) devtoolÊÇ·ñ¿ÉÒÔ¸øËùÓÐSpringbootÓ¦ÓÃ×öÈ«¾ÖµÄÅäÖã¿
+
+> ¿ÉÒÔͨ¹ý½«spring-boot-devtools.ymlÎļþÌí¼Óµ½$HOME/.config/spring-bootĿ¼À´**ÅäÖÃÈ«¾Ö devtools ÉèÖÃ**¡£
+
+Ìí¼Óµ½ÕâЩÎļþµÄÈκÎÊôÐÔ¶¼ÊÊÓÃÓÚÄã»úÆ÷ÉÏʹÓà devtools µÄËùÓÐSpring Boot Ó¦ÓóÌÐò¡£ÀýÈ磬Ҫ½«ÖØÐÂÆô¶¯ÅäÖÃΪʼÖÕʹÓô¥·¢Æ÷Îļþ£¬ÄãÐèÒª½«ÒÔÏÂÊôÐÔÌí¼Óµ½ÄãµÄspring-boot-devtoolsÎļþÖУº
+
+
+
+```
+spring:
+ devtools:
+ restart:
+ trigger-file: ".reloadtrigger"
+
+```
+
+
+
+### [#](#Èç¹ûÎÒ²»ÓÃdevtool-»¹ÓÐʲôѡÔñ) Èç¹ûÎÒ²»ÓÃdevtool£¬»¹ÓÐʲôѡÔñ£¿
+
+> Èç¹ûÎÒ²»ÓÃdevtool£¬»¹ÓÐʲôѡÔñ£¿
+
+**ÔÚʵ¼ÊµÄ¿ª·¢¹ý³ÌÖУ¬ÎÒÒ²²»»áȥʹÓÃdevtool¹¤¾ß**, ÒòΪ£º
+
+* devtool±¾Éí»ùÓÚÖØÆô·½Ê½£¬ÕâÖÖÈÔÈ»²»ÊÇÕæÕýµÄÈÈÌæ»»·½°¸£¬JRebel²ÅÊÇ£¨ËüÊÇÊշѵģ©
+* ¿ª·¢µ÷ÊÔ×îÖØÒªµÄ»¹ÊÇÒ»ÖÖȨºâ
+ * ×Ô¶¯ÖØÆôµÄ¿ªÏúÈç¹ûºÍÊÖ¶¯ÖØÆôûÓÐʲô̫´ó²î±ð£¬ÄÇô»¹²»ÈçÊÖ¶¯ÖØÆô£¨°´ÐèÖØÆô£©
+ * ¶àÊýÇé¿öÏ£¬Èç¹ûÊÇ**·½·¨ÄÚ²¿µÄÐ޸ĻòÕß¾²Ì¬×ÊÔ´µÄÐÞ¸Ä**£¬ÔÚIDEAÖÐÊÇ¿ÉÒÔͨ¹ýRebuild£¨Ctrl + Shift + F9£©½øÐÐÈȸüµÄ
+
+
+
+* ´ËÍ⻹ÓÐÒ»¸ö¹¤¾ßspring loaded£¬ ¿ÉʵÏÖÐÞ¸ÄÀàÎļþµÄÈȲ¿Ê𣬾ßÌå¿É¿´Æä[githubµØÖ·ÔÚд°¿Ú´ò¿ª](https://github.com/spring-projects/spring-loaded)ÉϵÄ˵Ã÷¡£
+
+## [#](#ʾÀýÔ´Âë) ʾÀýÔ´Âë
+
+https://github.com/realpdai/tech-pdai-spring-demos
+
+## [#](#²Î¿¼ÎÄÕÂ) ²Î¿¼ÎÄÕÂ
+
+https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.devtools
+
+https://liayun.blog.csdn.net/article/details/116541775
+
+* * *
+
+Öø×÷Ȩ¹é@pdaiËùÓÐ ÔÎÄÁ´½Ó£ºhttps://pdai.tech/md/spring/springboot/springboot-x-hello-devtool.html
\ No newline at end of file
diff --git "a/docs/spring/SpringBoot/SpringBoot\351\233\206\346\210\220Swagger\345\256\236\347\216\260API\346\226\207\346\241\243\350\207\252\345\212\250\347\224\237\346\210\220.md" "b/docs/spring/SpringBoot/SpringBoot\351\233\206\346\210\220Swagger\345\256\236\347\216\260API\346\226\207\346\241\243\350\207\252\345\212\250\347\224\237\346\210\220.md"
new file mode 100644
index 0000000..e225d74
--- /dev/null
+++ "b/docs/spring/SpringBoot/SpringBoot\351\233\206\346\210\220Swagger\345\256\236\347\216\260API\346\226\207\346\241\243\350\207\252\345\212\250\347\224\237\346\210\220.md"
@@ -0,0 +1,625 @@
+
+
+Ŀ¼
+
+* [SwaggerµÄ½éÉÜ](https://www.cnblogs.com/progor/p/13297904.html#swagger%E7%9A%84%E4%BB%8B%E7%BB%8D)
+ * [ÓŵãÓëȱµã](https://www.cnblogs.com/progor/p/13297904.html#%E4%BC%98%E7%82%B9%E4%B8%8E%E7%BC%BA%E7%82%B9)
+* [Ìí¼Óswagger](https://www.cnblogs.com/progor/p/13297904.html#%E6%B7%BB%E5%8A%A0swagger)
+ * [1.Ìí¼ÓÒÀÀµ°ü£º](https://www.cnblogs.com/progor/p/13297904.html#1%E6%B7%BB%E5%8A%A0%E4%BE%9D%E8%B5%96%E5%8C%85)
+ * [2.ÅäÖÃSwagger:](https://www.cnblogs.com/progor/p/13297904.html#2%E9%85%8D%E7%BD%AEswagger)
+ * [3.²âÊÔ](https://www.cnblogs.com/progor/p/13297904.html#3%E6%B5%8B%E8%AF%95)
+* [³¡¾°£º](https://www.cnblogs.com/progor/p/13297904.html#%E5%9C%BA%E6%99%AF)
+ * [¶¨Òå½Ó¿Ú×é](https://www.cnblogs.com/progor/p/13297904.html#%E5%AE%9A%E4%B9%89%E6%8E%A5%E5%8F%A3%E7%BB%84)
+ * [¶¨Òå½Ó¿Ú](https://www.cnblogs.com/progor/p/13297904.html#%E5%AE%9A%E4%B9%89%E6%8E%A5%E5%8F%A3)
+ * [¶¨Òå½Ó¿ÚÇëÇó²ÎÊý](https://www.cnblogs.com/progor/p/13297904.html#%E5%AE%9A%E4%B9%89%E6%8E%A5%E5%8F%A3%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0)
+ * [³¡¾°Ò»£ºÇëÇó²ÎÊýÊÇʵÌåÀà¡£](https://www.cnblogs.com/progor/p/13297904.html#%E5%9C%BA%E6%99%AF%E4%B8%80%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0%E6%98%AF%E5%AE%9E%E4%BD%93%E7%B1%BB)
+ * [³¡¾°¶þ£ºÇëÇó²ÎÊýÊÇ·ÇʵÌåÀà¡£](https://www.cnblogs.com/progor/p/13297904.html#%E5%9C%BA%E6%99%AF%E4%BA%8C%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0%E6%98%AF%E9%9D%9E%E5%AE%9E%E4%BD%93%E7%B1%BB)
+ * [¶¨Òå½Ó¿ÚÏìÓ¦](https://www.cnblogs.com/progor/p/13297904.html#%E5%AE%9A%E4%B9%89%E6%8E%A5%E5%8F%A3%E5%93%8D%E5%BA%94)
+ * [ÏìÓ¦ÊÇʵÌåÀࣺ](https://www.cnblogs.com/progor/p/13297904.html#%E5%93%8D%E5%BA%94%E6%98%AF%E5%AE%9E%E4%BD%93%E7%B1%BB)
+ * [ÏìÓ¦ÊÇ·ÇʵÌåÀࣺ](https://www.cnblogs.com/progor/p/13297904.html#%E5%93%8D%E5%BA%94%E6%98%AF%E9%9D%9E%E5%AE%9E%E4%BD%93%E7%B1%BB)
+* [Swagger UIÔöÇ¿](https://www.cnblogs.com/progor/p/13297904.html#swagger-ui%E5%A2%9E%E5%BC%BA)
+ * [UI¶Ô±È£º](https://www.cnblogs.com/progor/p/13297904.html#ui%E5%AF%B9%E6%AF%94)
+ * [ʹÓÃ](https://www.cnblogs.com/progor/p/13297904.html#%E4%BD%BF%E7%94%A8)
+ * [Óŵã](https://www.cnblogs.com/progor/p/13297904.html#%E4%BC%98%E7%82%B9)
+* [ÕûºÏSpring Security×¢Òâ](https://www.cnblogs.com/progor/p/13297904.html#%E6%95%B4%E5%90%88spring-security%E6%B3%A8%E6%84%8F)
+* [¶ÔÓÚtokenµÄ´¦Àí](https://www.cnblogs.com/progor/p/13297904.html#%E5%AF%B9%E4%BA%8Etoken%E7%9A%84%E5%A4%84%E7%90%86)
+* [SwaggerµÄ°²È«¹ÜÀí](https://www.cnblogs.com/progor/p/13297904.html#swagger%E7%9A%84%E5%AE%89%E5%85%A8%E7%AE%A1%E7%90%86)
+
+
+
+* * *
+
+# SwaggerµÄ½éÉÜ
+
+?Äã¿ÉÄܳ¢ÊÔ¹ýдÍêÒ»¸ö½Ó¿Úºó£¬×Ô¼ºÈ¥´´½¨½Ó¿ÚÎĵµ£¬»òÕßÐ޸ĽӿںóÐ޸ĽӿÚÎĵµ¡£¶àÁËÖ®ºó£¬Äã¿Ï¶¨»á·¢ÉúÒ»¸ö²Ù×÷£¬ÄǾÍÊÇÍü¼ÇÁËÐÞ¸ÄÎĵµ»òÕß´´½¨Îĵµ£¨³ý·ÇÄãÃǹ«Ë¾°Ñ½Ó¿ÚÎĵµºÍд½Ó¿ÚÒªÇóµÃºÜ½ôÃÜ?Íü¼ÇдÎĵµ¾Í¿Û¹¤×Ê£¿£¬·ñÔòÁ½¸ö·ÖÀëµÄ¹¤×÷×ÜÊÇÓпÉÄÜÒÅ©µÄ£©¡£¶øswagger¾ÍÊÇÒ»¸öÔÚÄãд½Ó¿ÚµÄʱºò×Ô¶¯°ïÄãÉú³É½Ó¿ÚÎĵµµÄ¶«Î÷£¬Ö»ÒªÄã×ñÑËüµÄ¹æ·¶²¢Ð´Ò»Ð©½Ó¿ÚµÄ˵Ã÷×¢½â¼´¿É¡£
+
+## ÓŵãÓëȱµã
+
+?Óŵ㣺
+
+* ×Ô¶¯Éú³ÉÎĵµ£¬Ö»ÐèÒªÔÚ½Ó¿ÚÖÐʹÓÃ×¢½â½øÐбê×¢£¬¾ÍÄÜÉú³É¶ÔÓ¦µÄ½Ó¿ÚÎĵµ¡£
+* ×Ô¶¯¸üÐÂÎĵµ£¬ÓÉÓÚÊǶ¯Ì¬Éú³ÉµÄ£¬ËùÒÔÈç¹ûÄãÐÞ¸ÄÁ˽ӿڣ¬ÎĵµÒ²»á×Ô¶¯¶ÔÓ¦Ð޸ģ¨Èç¹ûÄãÒ²¸üÐÂÁË×¢½âµÄ»°£©¡£ÕâÑù¾Í²»»á·¢ËÍÎÒÐÞ¸ÄÁ˽ӿڣ¬È´Íü¼Ç¸üнӿÚÎĵµµÄÇé¿ö¡£
+* Ö§³ÖÔÚÏßµ÷ÊÔ£¬swaggerÌṩÁËÔÚÏßµ÷ÓýӿڵŦÄÜ¡£
+
+?ȱµã£º
+
+* ²»ÄÜ´´½¨²âÊÔÓÃÀý£¬ËùÒÔËûÔÝʱ²»ÄܰïÄã´¦ÀíÍêËùÓеÄÊÂÇé¡£ËûÖ»ÄÜÌṩһ¸ö¼òµ¥µÄÔÚÏßµ÷ÊÔ£¬Èç¹ûÄãÏë´æ´¢ÄãµÄ²âÊÔÓÃÀý£¬¿ÉÒÔʹÓÃPostman»òÕßYAPIÕâÑùÖ§³Ö´´½¨²âÊÔÓû§µÄ¹¦ÄÜ¡£
+* Òª×ñÑһЩ¹æ·¶£¬Ëü²»ÊÇÈÎÒâ¹æ·¶µÄ¡£±ÈÈç˵£¬Äã¿ÉÄܻ᷵»ØÒ»¸öjsonÊý¾Ý£¬¶øÕâ¸öÊý¾Ý¿ÉÄÜÊÇÒ»¸öMap¸ñʽµÄ£¬ÄÇôÎÒÃÇ´Ëʱ²»Äܱê×¢Õâ¸öMap¸ñʽµÄ·µ»ØÊý¾ÝµÄÿ¸ö×ֶεÄ˵Ã÷£¬¶øÈç¹ûËüÊÇÒ»¸öʵÌåÀàµÄ»°£¬ÎÒÃÇ¿ÉÒÔͨ¹ý±ê×¢ÀàµÄÊôÐÔÀ´¸ø·µ»Ø×ֶμÓ˵Ã÷¡£Ò²±ÈÈç˵£¬¶ÔÓÚswagger£¬²»ÍƼöÔÚʹÓÃGET·½Ê½Ìá½»Êý¾ÝµÄʱºò»¹Ê¹ÓÃBody£¬½öÍÆ¼öʹÓÃquery²ÎÊý¡¢header²ÎÊý»òÕß·¾¶²ÎÊý£¬µ±È»ÁËÕâ¸öÏÞÖÆÖ»ÊÊÓÃÓÚÔÚÏßµ÷ÊÔ¡£
+* ûÓнӿÚÎĵµ¸üйÜÀí£¬ËäȻһ¸ö½Ó¿Ú¸üÐÂÖ®ºó£¬¿ÉÄܲ»»á¹ØÐľɰæµÄ½Ó¿ÚÐÅÏ¢£¬µ«Äã¡°¿ÉÄÜ¡±Ïë¿´¿´¾É°æµÄ½Ó¿ÚÐÅÏ¢£¬ÀýÈçÓÐЩ»Ò¶È¸üз¢²¼µÄʱºò¿ÉÄÜ»¹»á¹ØÐľɰæµÄ½Ó¿Ú¡£ÄÇô´ËʱֻÄÜÓɺó¶ËÈ¥¿´¿´ÓÐûÓÐ×¢ÊÍÁôÏÂÁË£¬ËùÒÔ¿ÉÒÔ¿¼ÂǽӿÚÎĵµ´ó¸üеÄʱºò×¢Ê;ɰæµÄ£¬È»ºóдÏÂаæµÄ¡£¡¾µ±È»Õâ¸öÎÊÌâ¿ÉÒÔͨ¹ýµ¼³ö½Ó¿ÚÎĵµÀ´¶Ô±È¡£¡¿
+* ËäÈ»ÏÖÔÚJavaµÄʵÌåÀàÖÐÓв»ÉÙÄ£ÐÍ£¬po,dto,voµÈ£¬Ä£Ð͵ÄÇø·ÖÊÇΪÁËÆÁ±ÎһЩ¶àÓà²ÎÊý£¬±ÈÈçÒ»¸öÓû§µÇ¼µÄʱºòÖ»ÐèÒªusername,password£¬µ«²éȨÏÞµÄʱºòÐèÒªÁ¬½ÓÉÏȨÏÞ±íµÄÐÅÏ¢£¬¶øÈç¹ûÉÏÊöÁ½¸ö²Ù×÷¶¼ÊÇʹÓÃÁËUserÕâ¸öʵÌåµÄ»°£¬ÔÚÎĵµÖоͻá×Ô¶¯Éú³ÉÁ˶àÓàµÄÐÅÏ¢£¬Õâ¾ÍÒªÇóÁËÄã»ùÓÚÄ£ÐÍÀ´´´½¨¶à¸öʵÌåÀ࣬±ÈÈçµÇ¼µÄʱºòÒ»¸öLoginForm£¬ÐèÒªÓû§-ȨÏÞµÈÐÅÏ¢µÄʱºò²ÅʹÓÃUserÀà¡££¨µ±È»ÁË£¬Õâ¸öÎÊÌâµÈÄã»áswaggerÖ®ºóÄã¾Í´ó¸Å¾Í»áÔõô¹æ±ÜÕâ¸öÎÊÌâÁË¡££©
+
+?ÉÏÃæµÄȱµãºÃÏñдµÄÓеã¶à£¬Äã¿ÉÄÜ»á¾õµÃswaggerÕâ¸ö¿ÓÓеã´ó¡£µ«ÆäʵÖ÷ÒªÊǹ淶ÎÊÌ⣬¶ø¹æ·¶ÎÊÌâÓÐʱºòÓÖ»áÌá¸ßÄãµÄ´úÂë¹æ·¶ÐÔ£¬Õâ¸ö¾Í¼ûÈʼûÖÇÁË£¬ÄãÒÔǰ¿ÉÄÜʲô½Ó¿ÚµÄ²ÎÊý¶¼Ê¹ÓÃÒ»¸öÀ࣬¶øÏÖÔÚswaggerÒªÇóÄã·Ö¿ªºó£¬Ä³ÖÖ²ã´ÎÉÏÌá¸ßÁËÄãµÄ´úÂë¹æ·¶ÐÔ¡£
+
+?×¢£ºÒÔÏ´úÂëʾÀý»ùÓÚSpring Boot¡£ÍêÕû´úÂë¿ÉÒԲο¼£º[swagger-demo](https://github.com/alprogor/swagger-demo)
+
+* * *
+
+# Ìí¼Óswagger
+
+?ÕâÀïÏȽ²Ìí¼Óswagger£¬Ò²¾ÍÊÇÏÈÕûºÏ½øÀ´£¬ÖÁÓÚÔõôʹÓã¬ÏÂÃæµÄ¡°³¡¾°¡±ÖÐÔÙ½²½â¡£
+
+## 1.Ìí¼ÓÒÀÀµ°ü£º
+
+?×¢Ò⣬ÕâÀïµÄǰÌáÊÇÒѾµ¼ÈëÁËspring bootµÄweb°ü¡£
+
+¸´ÖÆ´úÂë
+
+```
+
+ io.springfox
+ springfox-swagger2
+ 2.9.2
+
+
+ io.springfox
+ springfox-swagger-ui
+ 2.9.2
+
+
+```
+
+## 2.ÅäÖÃSwagger:
+
+ҪʹÓÃswagger£¬ÎÒÃDZØÐë¶Ôswagger½øÐÐÅäÖã¬ÎÒÃÇÐèÒª´´½¨Ò»¸öswaggerµÄÅäÖÃÀ࣬±ÈÈç¿ÉÒÔÃüÃûΪSwaggerConfig.java
+
+¸´ÖÆ´úÂë
+
+```
+package com.example.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration // ±êÃ÷ÊÇÅäÖÃÀà
+@EnableSwagger2 //¿ªÆôswagger¹¦ÄÜ
+public class SwaggerConfig {
+ @Bean
+ public Docket createRestApi() {
+ return new Docket(DocumentationType.SWAGGER_2) // DocumentationType.SWAGGER_2 ¹Ì¶¨µÄ£¬´ú±íswagger2
+// .groupName("·Ö²¼Ê½ÈÎÎñϵͳ") // Èç¹ûÅäÖöà¸öÎĵµµÄʱºò£¬ÄÇôÐèÒªÅäÖÃgroupNameÀ´·Ö×é±êʶ
+ .apiInfo(apiInfo()) // ÓÃÓÚÉú³ÉAPIÐÅÏ¢
+ .select() // select()º¯Êý·µ»ØÒ»¸öApiSelectorBuilderʵÀý,ÓÃÀ´¿ØÖƽӿڱ»swagger×ö³ÉÎĵµ
+ .apis(RequestHandlerSelectors.basePackage("com.example.controller")) // ÓÃÓÚÖ¸¶¨É¨ÃèÄĸö°üϵĽӿÚ
+ .paths(PathSelectors.any())// Ñ¡ÔñËùÓеÄAPI,Èç¹ûÄãÏëֻΪ²¿·ÖAPIÉú³ÉÎĵµ£¬¿ÉÒÔÅäÖÃÕâÀï
+ .build();
+ }
+
+ /**
+ * ÓÃÓÚ¶¨ÒåAPIÖ÷½çÃæµÄÐÅÏ¢£¬±ÈÈç¿ÉÒÔÉùÃ÷ËùÓеÄAPIµÄ×ܱêÌâ¡¢ÃèÊö¡¢°æ±¾
+ * @return
+ */
+ private ApiInfo apiInfo() {
+ return new ApiInfoBuilder()
+ .title("XXÏîÄ¿API") // ¿ÉÒÔÓÃÀ´×Ô¶¨ÒåAPIµÄÖ÷±êÌâ
+ .description("XXÏîÄ¿SwaggerAPI¹ÜÀí") // ¿ÉÒÔÓÃÀ´ÃèÊöÕûÌåµÄAPI
+ .termsOfServiceUrl("") // ÓÃÓÚ¶¨Òå·þÎñµÄÓòÃû
+ .version("1.0") // ¿ÉÒÔÓÃÀ´¶¨Òå°æ±¾¡£
+ .build(); //
+ }
+}
+
+```
+
+## 3.²âÊÔ
+
+ÔËÐÐÎÒÃǵÄSpring BootÏîÄ¿£¬£¨ÎÒĬÈÏÊÇ8080¶Ë¿Ú£¬Èç¹ûÄã²»Ò»Ñù£¬Çë×¢ÒâÐ޸ĺóÐøµÄurl£©£¬·ÃÎÊ`http://localhost:8080/swagger-ui.html`
+È»ºóÄã¾Í¿ÉÒÔ¿´µ½Ò»¸öÈçϵĽçÃæ£¬ÓÉÓÚÎÒÃÇÔÝʱûÓÐÅäÖýӿÚÊý¾Ý£¬ËùÒÔÏÂÃæÏÔʾ`No operations defined in spec!`
+
+
+
+?ÏÂÃæÎÒÃǽ«½éÉÜÈçºÎ¶¨Òå½Ó¿Ú£¬ÒÔ¼°ÔÚswagger UI½çÃæÖеÄÄÚÈÝ¡£
+
+* * *
+
+# ³¡¾°£º
+
+## ¶¨Òå½Ó¿Ú×é
+
+½Ó¿ÚÓÐʱºòÓ¦¸ÃÊÇ·Ö×éµÄ£¬¶øÇҴ󲿷ֶ¼ÊÇÔÚÒ»¸öcontrollerÖе쬱ÈÈçÓû§¹ÜÀíÏà¹ØµÄ½Ó¿ÚÓ¦¸Ã¶¼ÔÚUserControllerÖУ¬ÄÇô²»Í¬µÄÒµÎñµÄʱºò£¬Ó¦¸Ã¶¨Òå/»®·Ö²»Í¬µÄ½Ó¿Ú×é¡£½Ó¿Ú×é¿ÉÒÔʹÓÃ`@Api`À´»®·Ö¡£
+±ÈÈ磺
+
+¸´ÖÆ´úÂë
+
+```
+@Api(tags = "½ÇÉ«¹ÜÀí") // tags£ºÄã¿ÉÒÔµ±×÷ÊÇÕâ¸ö×éµÄÃû×Ö¡£
+@RestController
+public class RoleController {
+}
+
+```
+
+ºÍ
+
+¸´ÖÆ´úÂë
+
+```
+@Api(tags = "Óû§¹ÜÀí") // tags£ºÄã¿ÉÒÔµ±×÷ÊÇÕâ¸ö×éµÄÃû×Ö¡£
+@RestController
+public class UserController {
+}
+
+```
+
+?ÄãÒ²¿ÉÒÔÀí½â³É»ùÓÚtagsÀ´·Ö×飬¾ÍºÃÏñһЩÎÄÕÂÀïÃæµÄ±êǩһÑù£¬Ê¹ÓñêÇ©À´·ÖÀà¡£
+?Èç¹ûÕâ¸öControllerÏ£¨½Ó¿Ú×飩ÏÂÃæÃ»Óнӿڣ¬ÄÇôÔÚswagger uiÖÐÊDz»»áÏÔʾµÄ£¬Èç¹ûÓеϰ¾Í»áÕâÑùÏÔʾ£º
+
+
+## ¶¨Òå½Ó¿Ú
+
+ʹÓÃÁË`@Api`À´±ê×¢Ò»¸öControllerÖ®ºó£¬Èç¹ûÏÂÃæÓнӿڣ¬ÄÇô¾Í»áĬÈÏÉú³ÉÎĵµ£¬µ«Ã»ÓÐÎÒÃÇ×Ô¶¨ÒåµÄ˵Ã÷£º
+
+¸´ÖÆ´úÂë
+
+```
+@Api(tags = "Óû§¹ÜÀí")
+@RestController
+public class UserController {
+ // ×¢Ò⣬¶ÔÓÚswagger£¬²»ÒªÊ¹ÓÃ@RequestMapping£¬
+ // ÒòΪ@RequestMappingÖ§³ÖÈÎÒâÇëÇó·½Ê½£¬swagger»áΪÕâ¸ö½Ó¿ÚÉú³É7ÖÖÇëÇó·½Ê½µÄ½Ó¿ÚÎĵµ
+ @GetMapping("/info")
+ public String info(String id){
+ return "aaa";
+ }
+}
+
+```
+
+
+
+
+
+ÎÒÃÇ¿ÉÒÔʹÓÃ`@ApiOperation`À´ÃèÊö½Ó¿Ú£¬±ÈÈ磺
+
+¸´ÖÆ´úÂë
+
+```
+ @ApiOperation(value = "Óû§²âÊÔ",notes = "Óû§²âÊÔnotes")
+ @GetMapping("/test")
+ public String test(String id){
+ return "test";
+ }
+
+```
+
+
+³£ÓÃÅäÖÃÏ
+
+* value£º¿ÉÒÔµ±×÷Êǽӿڵļò³Æ
+* notes£º½Ó¿ÚµÄÃèÊö
+* tags£º¿ÉÒÔ¶îÍⶨÒå½Ó¿Ú×飬±ÈÈçÕâ¸ö½Ó¿ÚÍâ²ãÒѾÓÐ`@Api(tags = "Óû§¹ÜÀí")`£¬½«½Ó¿Ú»®·Öµ½ÁË¡°Óû§¹ÜÀí¡±ÖУ¬µ«Äã¿ÉÒÔ¶îÍâµÄʹÓÃtags£¬ÀýÈç`tags = "½ÇÉ«¹ÜÀí"`ÈýÇÉ«¹ÜÀíÖÐÒ²ÓÐÕâ¸ö½Ó¿ÚÎĵµ¡£
+
+## ¶¨Òå½Ó¿ÚÇëÇó²ÎÊý
+
+ÉÏÃæÊ¹ÓÃÁË`@ApiOperation`À´ÁËÃèÊö½Ó¿Ú£¬µ«Æäʵ»¹È±ÉÙ½Ó¿ÚÇëÇó²ÎÊýµÄ˵Ã÷£¬ÏÂÃæÎÒÃÇ·Ö³¡¾°À´½²¡£
+?×¢Òâһϣ¬**¶ÔÓÚGET·½Ê½£¬swagger²»ÍƼöʹÓÃbody·½Ê½À´´«µÝÊý¾Ý**£¬Ò²¾ÍÊDz»Ï£ÍûÔÚGET·½Ê½Ê±Ê¹ÓÃjson¡¢form-dataµÈ·½Ê½À´´«µÝ£¬Õâʱºò×îºÃʹÓ÷¾¶²ÎÊý»òÕßurl²ÎÊý¡£(?ËäÈ»POSTMANµÈÊÇÖ§³ÖµÄ)£¬ËùÒÔÈç¹û½Ó¿Ú´«µÝµÄÊý¾ÝÊÇjson»òÕßform-data·½Ê½µÄ£¬»¹ÊÇʹÓÃPOST·½Ê½ºÃ¡£
+
+### ³¡¾°Ò»£ºÇëÇó²ÎÊýÊÇʵÌåÀà¡£
+
+´ËʱÎÒÃÇÐèҪʹÓÃ`@ApiModel`À´±êעʵÌåÀ࣬ȻºóÔÚ½Ó¿ÚÖж¨ÒåÈë²ÎΪʵÌåÀ༴¿É£º
+
+* @ApiModel£ºÓÃÀ´±êÀà
+ * ³£ÓÃÅäÖÃÏ
+ * value£ºÊµÌåÀà¼ò³Æ
+ * description£ºÊµÌåÀà˵Ã÷
+* @ApiModelProperty£ºÓÃÀ´ÃèÊöÀàµÄ×ֶεÄÒâÒå¡£
+ * ³£ÓÃÅäÖÃÏ
+ * value£º×Ö¶Î˵Ã÷
+ * example£ºÉèÖÃÇëÇóʾÀý£¨Example Value£©µÄĬÈÏÖµ£¬Èç¹û²»ÅäÖ㬵±×Ö¶ÎΪstringµÄʱºò£¬´ËʱÇëÇóʾÀýÖÐĬÈÏֵΪ"".
+ * name£ºÓÃеÄ×Ö¶ÎÃûÀ´Ìæ´ú¾ÉµÄ×Ö¶ÎÃû¡£
+ * allowableValues£ºÏÞÖÆÖµµÃ·¶Î§£¬ÀýÈç`{1,2,3}`´ú±íÖ»ÄÜÈ¡ÕâÈý¸öÖµ£»`[1,5]`´ú±íÈ¡1µ½5µÄÖµ£»`(1,5)`´ú±í1µ½5µÄÖµ£¬²»°üÀ¨1ºÍ5£»»¹¿ÉÒÔʹÓÃinfinity»ò-infinityÀ´ÎÞÏÞÖµ£¬±ÈÈç`[1, infinity]`´ú±í×îСֵΪ1£¬×î´óÖµÎÞÇî´ó¡£
+ * required£º±ê¼Ç×Ö¶ÎÊÇ·ñ±ØÌĬÈÏÊÇfalse,
+ * hidden£ºÓÃÀ´Òþ²Ø×ֶΣ¬Ä¬ÈÏÊÇfalse£¬Èç¹ûÒªÒþ²ØÐèҪʹÓÃtrue£¬ÒòΪ×Ö¶ÎĬÈ϶¼»áÏÔʾ£¬¾ÍËãûÓÐ`@ApiModelProperty`¡£
+
+¸´ÖÆ´úÂë
+
+```
+// ÏÈʹÓÃ@ApiModelÀ´±ê×¢Àà
+@ApiModel(value="Óû§µÇ¼±íµ¥¶ÔÏó",description="Óû§µÇ¼±íµ¥¶ÔÏó")
+public class LoginForm {
+ // ʹÓÃApiModelPropertyÀ´±ê×¢×Ö¶ÎÊôÐÔ¡£
+ @ApiModelProperty(value = "Óû§Ãû",required = true,example = "root")
+ private String username;
+ @ApiModelProperty(value = "ÃÜÂë",required = true,example = "123456")
+ private String password;
+
+ // ´Ë´¦Ê¡ÂÔÈë²Î¸³ÖµÊ±ÐèÒªµÄgetter,setter,swaggerÒ²ÐèÒªÕâ¸ö
+}
+
+```
+
+¶¨Òå³ÉÈë²Î£º
+
+¸´ÖÆ´úÂë
+
+```
+ @ApiOperation(value = "µÇ¼½Ó¿Ú",notes = "µÇ¼½Ó¿ÚµÄ˵Ã÷")
+ @PostMapping("/login")
+ public LoginForm login(@RequestBody LoginForm loginForm){
+ return loginForm;
+ }
+
+```
+
+Ч¹û£º
+
+
+
+### ³¡¾°¶þ£ºÇëÇó²ÎÊýÊÇ·ÇʵÌåÀà¡£
+
+£¨**ÔÙ˵һ´Î£º¶ÔÓÚGET·½Ê½£¬swagger²»ÍƼöʹÓÃbody·½Ê½À´´«µÝÊý¾Ý£¬ËùÒÔËäÈ»Spring MVC¿ÉÒÔ×Ô¶¯·â×°²ÎÊý£¬µ«¶ÔÓÚGETÇëÇó»¹ÊDz»ÒªÊ¹ÓÃform-data£¬jsonµÈ·½Ê½´«µÝ²ÎÊý£¬³ý·ÇÄãʹÓÃPostmanÀ´²âÊÔ½Ó¿Ú£¬swaggerÔÚÏß²âÊÔÊDz»Ö§³ÖÕâ¸ö²Ù×÷µÄ**£©
+¶ÔÓÚ·ÇʵÌåÀà²ÎÊý£¬¿ÉÒÔʹÓÃ`@ApiImplicitParams`ºÍ`@ApiImplicitParam`À´ÉùÃ÷ÇëÇó²ÎÊý¡£
+`@ApiImplicitParams`ÓÃÔÚ·½·¨Í·ÉÏ£¬`@ApiImplicitParam`¶¨ÒåÔÚ`@ApiImplicitParams`ÀïÃæ£¬Ò»¸ö`@ApiImplicitParam`¶ÔÓ¦Ò»¸ö²ÎÊý¡£
+`@ApiImplicitParam`³£ÓÃÅäÖÃÏ
+
+* name£ºÓÃÀ´¶¨Òå²ÎÊýµÄÃû×Ö£¬Ò²¾ÍÊÇ×ֶεÄÃû×Ö,¿ÉÒÔÓë½Ó¿ÚµÄÈë²ÎÃû¶ÔÓ¦¡£**Èç¹û²»¶ÔÓ¦£¬Ò²»áÉú³É£¬ËùÒÔ¿ÉÒÔÓÃÀ´¶¨Òå¶îÍâ²ÎÊý£¡**
+* value£ºÓÃÀ´ÃèÊö²ÎÊý
+* required£ºÓÃÀ´±ê×¢²ÎÊýÊÇ·ñ±ØÌî
+* paramTypeÓÐpath,query,body,form,headerµÈ·½Ê½£¬µ«¶ÔÓÚ¶ÔÓÚ·ÇʵÌåÀà²ÎÊýµÄʱºò£¬³£ÓõÄÖ»ÓÐpath,query,header£»bodyºÍformÊDz»³£Óõġ£body²»ÊÊÓÃÓÚ¶à¸öÁãÉ¢²ÎÊýµÄÇé¿ö£¬Ö»ÊÊÓÃÓÚjson¶ÔÏóµÈÇé¿ö¡£¡¾Èç¹ûÄãµÄ½Ó¿ÚÊÇ`form-data`,`x-www-form-urlencoded`µÄʱºò¿ÉÄܲ»ÄÜʹÓÃswaggerÒ³ÃæAPIµ÷ÊÔ£¬µ«¿ÉÒÔÔÚºóÃæ½²µ½»ùÓÚBootstrapUIµÄswaggerÔöÇ¿Öе÷ÊÔ£¬»ùÓÚBootstrapUIµÄswaggerÖ§³ÖÖ¸¶¨`form-data`»ò`x-www-form-urlencoded`¡¿
+
+ʾÀýÒ»£ºÉùÃ÷Èë²ÎÊÇURL²ÎÊý
+
+¸´ÖÆ´úÂë
+
+```
+ // ʹÓÃURL query²ÎÊý
+ @ApiOperation(value = "µÇ¼½Ó¿Ú2",notes = "µÇ¼½Ó¿ÚµÄ˵Ã÷2")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "username",//²ÎÊýÃû×Ö
+ value = "Óû§Ãû",//²ÎÊýµÄÃèÊö
+ required = true,//ÊÇ·ñ±ØÐë´«Èë
+ //paramType¶¨Òå²ÎÊý´«µÝÀàÐÍ£ºÓÐpath,query,body,form,header
+ paramType = "query"
+ )
+ ,
+ @ApiImplicitParam(name = "password",//²ÎÊýÃû×Ö
+ value = "ÃÜÂë",//²ÎÊýµÄÃèÊö
+ required = true,//ÊÇ·ñ±ØÐë´«Èë
+ paramType = "query"
+ )
+ })
+ @PostMapping(value = "/login2")
+ public LoginForm login2(String username,String password){
+ System.out.println(username+":"+password);
+ LoginForm loginForm = new LoginForm();
+ loginForm.setUsername(username);
+ loginForm.setPassword(password);
+ return loginForm;
+ }
+
+```
+
+ʾÀý¶þ£ºÉùÃ÷Èë²ÎÊÇURL·¾¶²ÎÊý
+
+¸´ÖÆ´úÂë
+
+```
+ // ʹÓ÷¾¶²ÎÊý
+ @PostMapping("/login3/{id1}/{id2}")
+ @ApiOperation(value = "µÇ¼½Ó¿Ú3",notes = "µÇ¼½Ó¿ÚµÄ˵Ã÷3")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "id1",//²ÎÊýÃû×Ö
+ value = "Óû§Ãû",//²ÎÊýµÄÃèÊö
+ required = true,//ÊÇ·ñ±ØÐë´«Èë
+ //paramType¶¨Òå²ÎÊý´«µÝÀàÐÍ£ºÓÐpath,query,body,form,header
+ paramType = "path"
+ )
+ ,
+ @ApiImplicitParam(name = "id2",//²ÎÊýÃû×Ö
+ value = "ÃÜÂë",//²ÎÊýµÄÃèÊö
+ required = true,//ÊÇ·ñ±ØÐë´«Èë
+ paramType = "path"
+ )
+ })
+ public String login3(@PathVariable Integer id1,@PathVariable Integer id2){
+ return id1+":"+id2;
+ }
+
+```
+
+ʾÀýÈý£ºÉùÃ÷Èë²ÎÊÇheader²ÎÊý
+
+¸´ÖÆ´úÂë
+
+```
+ // ÓÃheader´«µÝ²ÎÊý
+ @PostMapping("/login4")
+ @ApiOperation(value = "µÇ¼½Ó¿Ú4",notes = "µÇ¼½Ó¿ÚµÄ˵Ã÷4")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "username",//²ÎÊýÃû×Ö
+ value = "Óû§Ãû",//²ÎÊýµÄÃèÊö
+ required = true,//ÊÇ·ñ±ØÐë´«Èë
+ //paramType¶¨Òå²ÎÊý´«µÝÀàÐÍ£ºÓÐpath,query,body,form,header
+ paramType = "header"
+ )
+ ,
+ @ApiImplicitParam(name = "password",//²ÎÊýÃû×Ö
+ value = "ÃÜÂë",//²ÎÊýµÄÃèÊö
+ required = true,//ÊÇ·ñ±ØÐë´«Èë
+ paramType = "header"
+ )
+ })
+ public String login4( @RequestHeader String username,
+ @RequestHeader String password){
+ return username+":"+password;
+ }
+
+```
+
+ʾÀýËÄ£ºÉùÃ÷ÎļþÉÏ´«²ÎÊý
+
+¸´ÖÆ´úÂë
+
+```
+ // ÓÐÎļþÉÏ´«Ê±ÒªÓÃ@ApiParam£¬Ó÷¨»ù±¾Óë@ApiImplicitParamÒ»Ñù£¬²»¹ý@ApiParamÓÃÔÚ²ÎÊýÉÏ
+ // »òÕßÄãÒ²¿ÉÒÔ²»×¢½â£¬swagger»á×Ô¶¯Éú³É˵Ã÷
+ @ApiOperation(value = "ÉÏ´«Îļþ",notes = "ÉÏ´«Îļþ")
+ @PostMapping(value = "/upload")
+ public String upload(@ApiParam(value = "ͼƬÎļþ", required = true)MultipartFile uploadFile){
+ String originalFilename = uploadFile.getOriginalFilename();
+
+ return originalFilename;
+ }
+
+ // ¶à¸öÎļþÉÏ´«Ê±£¬**swaggerÖ»ÄܲâÊÔµ¥ÎļþÉÏ´«**
+ @ApiOperation(value = "ÉÏ´«¶à¸öÎļþ",notes = "ÉÏ´«¶à¸öÎļþ")
+ @PostMapping(value = "/upload2",consumes = "multipart/*", headers = "content-type=multipart/form-data")
+ public String upload2(@ApiParam(value = "ͼƬÎļþ", required = true,allowMultiple = true)MultipartFile[] uploadFile){
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < uploadFile.length; i++) {
+ System.out.println(uploadFile[i].getOriginalFilename());
+ sb.append(uploadFile[i].getOriginalFilename());
+ sb.append(",");
+ }
+ return sb.toString();
+ }
+
+ // ¼ÈÓÐÎļþ£¬ÓÖÓвÎÊý
+ @ApiOperation(value = "¼ÈÓÐÎļþ£¬ÓÖÓвÎÊý",notes = "¼ÈÓÐÎļþ£¬ÓÖÓвÎÊý")
+ @PostMapping(value = "/upload3")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "name",
+ value = "ͼƬÐÂÃû×Ö",
+ required = true
+ )
+ })
+ public String upload3(@ApiParam(value = "ͼƬÎļþ", required = true)MultipartFile uploadFile,
+ String name){
+ String originalFilename = uploadFile.getOriginalFilename();
+
+ return originalFilename+":"+name;
+ }
+
+```
+
+## ¶¨Òå½Ó¿ÚÏìÓ¦
+
+¶¨Òå½Ó¿ÚÏìÓ¦£¬ÊÇ·½±ã²é¿´½Ó¿ÚÎĵµµÄÈËÄܹ»ÖªµÀ½Ó¿Ú·µ»ØµÄÊý¾ÝµÄÒâÒå¡£
+
+### ÏìÓ¦ÊÇʵÌåÀࣺ
+
+Ç°ÃæÔÚ¶¨Òå½Ó¿ÚÇëÇó²ÎÊýµÄʱºòÓÐÌᵽʹÓÃ`@ApiModel`À´±ê×¢À࣬Èç¹û½Ó¿Ú·µ»ØÁËÕâ¸öÀ࣬ÄÇôÕâ¸öÀàÉϵÄ˵Ã÷Ò²»á×÷ΪÏìÓ¦µÄ˵Ã÷£º
+
+¸´ÖÆ´úÂë
+
+```
+ // ·µ»Ø±»@ApiModel±ê×¢µÄÀà¶ÔÏó
+ @ApiOperation(value = "ʵÌåÀàÏìÓ¦",notes = "·µ»ØÊý¾ÝΪʵÌåÀàµÄ½Ó¿Ú")
+ @PostMapping("/role1")
+ public LoginForm role1(@RequestBody LoginForm loginForm){
+ return loginForm;
+ }
+
+```
+
+
+
+### ÏìÓ¦ÊÇ·ÇʵÌåÀࣺ
+
+swaggerÎÞ·¨¶Ô·ÇʵÌåÀàµÄÏìÓ¦½øÐÐÏêϸ˵Ã÷£¬Ö»Äܱê×¢ÏìÓ¦ÂëµÈÐÅÏ¢¡£ÊÇͨ¹ý`@ApiResponses`ºÍ`@ApiResponse`À´ÊµÏֵġ£
+`@ApiResponses`ºÍ`@ApiResponse`¿ÉÒÔÓë`@ApiModel`Ò»ÆðʹÓá£
+
+¸´ÖÆ´úÂë
+
+```
+ // ÆäËûÀàÐ͵Ä,´Ëʱ²»ÄÜÔö¼Ó×Ö¶Î×¢ÊÍ£¬ËùÒÔÆäʵswaggerÍÆ¼öʹÓÃʵÌåÀà
+ @ApiOperation(value = "·ÇʵÌåÀà",notes = "·ÇʵÌåÀà")
+ @ApiResponses({
+ @ApiResponse(code=200,message = "µ÷Óóɹ¦"),
+ @ApiResponse(code=401,message = "ÎÞȨÏÞ" )
+ }
+ )
+ @PostMapping("/role2")
+ public String role2(){
+ return " {\n" +
+ " name:\"¹ã¶«\",\n" +
+ " citys:{\n" +
+ " city:[\"¹ãÖÝ\",\"ÉîÛÚ\",\"Ö麣\"]\n" +
+ " }\n" +
+ " }";
+ }
+
+```
+
+
+
+* * *
+
+# Swagger UIÔöÇ¿
+
+Äã¿ÉÄÜ»á¾õµÃÏÖÔÚÕâ¸öUI²»ÊǺܺÿ´£¬ÏÖÔÚÓÐһЩµÚÈý·½ÌṩÁËһЩSwagger UIÔöÇ¿£¬±È½ÏÁ÷ÐеÄÊÇ`swagger-bootstrap-ui`£¬ÎÒÃÇÕâÀïÒÔ`swagger-bootstrap-ui`ΪÀý¡£
+
+## UI¶Ô±È£º
+
+
+
+
+
+## ʹÓÃ
+
+1.Ìí¼ÓÒÀÀµ°ü£º
+
+¸´ÖÆ´úÂë
+
+```
+
+
+ io.springfox
+ springfox-swagger2
+ 2.9.2
+
+
+ io.springfox
+ springfox-swagger-ui
+ 2.9.2
+
+
+
+ com.github.xiaoymin
+ swagger-bootstrap-ui
+ 1.8.7
+
+
+```
+
+2.ÔÚswaggerÅäÖÃÀàÖÐÔö¼Ó×¢½â`@EnableSwaggerBootstrapUI`:
+
+¸´ÖÆ´úÂë
+
+```
+@Configuration // ±êÃ÷ÊÇÅäÖÃÀà
+@EnableSwagger2 //¿ªÆôswagger¹¦ÄÜ
+@EnableSwaggerBootstrapUI // ¿ªÆôSwaggerBootstrapUI
+public class SwaggerConfig {
+ // Ê¡ÂÔÅäÖÃÄÚÈÝ
+}
+
+```
+
+3.·ÃÎÊAPI£º`http://localhost:8080/doc.html`£¬¼´¿ÉÔ¤ÀÀµ½»ùÓÚbootstarpµÄSwagger UI½çÃæ¡£
+
+## Óŵã
+
+1.?½çÃæºÃ¿´ÁËÒ»µã
+
+2.ÉÏÃæËµ¹ýÁË£¬»ùÓÚBootstrapUIµÄswaggerÖ§³ÖÖ¸¶¨`form-data`»ò`x-www-form-urlencoded`£º
+
+
+3.Ö§³Ö¸´ÖƵ¥¸öAPIÎĵµºÍµ¼³öÈ«²¿APIÎĵµ£º
+
+
+
+
+* * *
+
+# ÕûºÏSpring Security×¢Òâ
+
+ÔÚSpring BootÕûºÏSpring SecurityºÍSwaggerµÄʱºò£¬ÐèÒªÅäÖÃÀ¹½ØµÄ·¾¶ºÍ·ÅÐеÄ·¾¶£¬×¢ÒâÊÇ·ÅÐÐÒÔϼ¸¸ö·¾¶¡£
+
+¸´ÖÆ´úÂë
+
+```
+.antMatchers("/swagger**/**").permitAll()
+.antMatchers("/webjars/**").permitAll()
+.antMatchers("/v2/**").permitAll()
+.antMatchers("/doc.html").permitAll() // Èç¹ûÄãÓÃÁËbootstarpµÄSwagger UI½çÃæ£¬¼ÓÒ»¸öÕâ¸ö¡£
+
+```
+
+* * *
+
+# ¶ÔÓÚtokenµÄ´¦Àí
+
+ÔÚswaggerÖÐÖ»Ö§³ÖÁ˼òµ¥µÄµ÷ÊÔ£¬µ«¶ÔÓÚһЩ½Ó¿Ú£¬ÎÒÃDzâÊÔµÄʱºò¿ÉÄÜÐèÒª°ÑtokenÐÅϢдµ½headerÖУ¬Ä¿Ç°ºÃÏñû¿´µ½¿ÉÒÔ×Ô¶¨Òå¼ÓÇëÇóÍ·µÄµØ·½£¿
+?·½·¨Ò»£º
+¡¡¡¡Èç¹ûÄãʹÓÃÁËSwagger BootstrapUI£¬ÄÇôÄã¿ÉÒÔÔÚ¡°Îĵµ¹ÜÀí¡±ÖÐÔö¼ÓÈ«¾Ö²ÎÊý£¬Õâ°üÀ¨ÁËÌí¼Óheader²ÎÊý¡£
+
+?·½·¨¶þ£ºÔÚswaggerÅäÖÃÀàÖÐÔö¼ÓÈ«¾Ö²ÎÊýÅäÖãº
+
+¸´ÖÆ´úÂë
+
+```
+ //Èç¹ûÓжîÍâµÄÈ«¾Ö²ÎÊý£¬±ÈÈç˵ÇëÇóÍ·²ÎÊý£¬¿ÉÒÔÕâÑùÌí¼Ó
+ ParameterBuilder parameterBuilder = new ParameterBuilder();
+ List parameters = new ArrayList();
+ parameterBuilder.name("authorization").description("ÁîÅÆ")
+ .modelRef(new ModelRef("string")).parameterType("header").required(false).build();
+ parameters.add(parameterBuilder.build());
+ return new Docket(DocumentationType.SWAGGER_2) // DocumentationType.SWAGGER_2 ¹Ì¶¨µÄ£¬´ú±íswagger2
+ .apiInfo(apiInfo()) // ÓÃÓÚÉú³ÉAPIÐÅÏ¢
+ .select() // select()º¯Êý·µ»ØÒ»¸öApiSelectorBuilderʵÀý,ÓÃÀ´¿ØÖƽӿڱ»swagger×ö³ÉÎĵµ
+ .apis(RequestHandlerSelectors.basePackage("com.example.controller")) // ÓÃÓÚÖ¸¶¨É¨ÃèÄĸö°üϵĽӿÚ
+ .paths(PathSelectors.any())// Ñ¡ÔñËùÓеÄAPI,Èç¹ûÄãÏëֻΪ²¿·ÖAPIÉú³ÉÎĵµ£¬¿ÉÒÔÅäÖÃÕâÀï
+ .build().globalOperationParameters(parameters);
+
+```
+
+?·½·¨Èý£ºÊ¹ÓÃ`@ApiImplicitParams`À´¶îÍâ±ê×¢Ò»¸öÇëÇóÍ·²ÎÊý£¬ÀýÈ磺
+
+¸´ÖÆ´úÂë
+
+```
+ // Èç¹ûÐèÒª¶îÍâµÄ²ÎÊý£¬·Ç±¾·½·¨Óõ½£¬µ«¹ýÂËÆ÷ÒªÓÃ,ÀàËÆÓÚȨÏÞtoken
+ @PostMapping("/login6")
+ @ApiOperation(value = "´øtokenµÄ½Ó¿Ú",notes = "´øtokenµÄ½Ó¿Ú")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = "authorization",//²ÎÊýÃû×Ö
+ value = "ÊÚȨtoken",//²ÎÊýµÄÃèÊö
+ required = true,//ÊÇ·ñ±ØÐë´«Èë
+ paramType = "header"
+ )
+ ,
+ @ApiImplicitParam(name = "username",//²ÎÊýÃû×Ö
+ value = "Óû§Ãû",//²ÎÊýµÄÃèÊö
+ required = true,//ÊÇ·ñ±ØÐë´«Èë
+ paramType = "query"
+ )
+ })
+ public String login6(String username){
+ return username;
+ }
+
+```
+
+* * *
+
+# SwaggerµÄ°²È«¹ÜÀí
+
+1.Èç¹ûÄãÕûºÏÁËȨÏÞ¹ÜÀí£¬¿ÉÒÔ¸øswagger¼ÓÉÏȨÏÞ¹ÜÀí£¬ÒªÇó·ÃÎÊswaggerÒ³ÃæÊäÈëÓû§ÃûºÍÃÜÂ룬ÕâЩÊÇspring securityºÍshiroµÄÊÂÁË£¬ÕâÀï²»½²¡£
+
+2.Èç¹ûÄã½ö½öÊDz»ÏëÔÚÕýʽ»·¾³ÖпÉÒÔ·ÃÎÊ£¬¿ÉÒÔÔÚÕýʽ»·¾³ÖйرÕSwagger×Ô¶¯ÅäÖã¬Õâ¾Í²»»áÓÐswaggerÒ³ÃæÁË¡£Ê¹ÓÃ`@Profile({"dev","test"})`×¢½âÀ´ÏÞÖÆÖ»ÔÚdev»òÕßtestÏÂÆôÓÃSwagger×Ô¶¯ÅäÖá£
+È»ºóÔÚSpring BootÅäÖÃÎļþÖÐÐ޸ĵ±Ç°profile`spring.profiles.active=release`£¬ÖØÆôÖ®ºó£¬´ËʱÎÞ·¨·ÃÎÊ`http://localhost:8080/swagger-ui.html`
+
+* * *
+
+
+
+×÷Õߣº[progor](https://www.cnblogs.com/progor/)
+±¾ÎÄΪ×÷ÕßÔ´´£¬×ªÔØÇë×¢Ã÷³ö´¦
+
diff --git "a/docs/spring/SpringBoot/\345\237\272\344\272\216SpringBoot\344\270\255\347\232\204\345\274\200\346\272\220\347\233\221\346\216\247\345\267\245\345\205\267SpringBootAdmin.md" "b/docs/spring/SpringBoot/\345\237\272\344\272\216SpringBoot\344\270\255\347\232\204\345\274\200\346\272\220\347\233\221\346\216\247\345\267\245\345\205\267SpringBootAdmin.md"
new file mode 100644
index 0000000..fc25a2c
--- /dev/null
+++ "b/docs/spring/SpringBoot/\345\237\272\344\272\216SpringBoot\344\270\255\347\232\204\345\274\200\346\272\220\347\233\221\346\216\247\345\267\245\345\205\267SpringBootAdmin.md"
@@ -0,0 +1,294 @@
+Spring Boot Admin(SBA)ÊÇÒ»¸ö¿ªÔ´µÄÉçÇøÏîÄ¿£¬ÓÃÓÚ¹ÜÀíºÍ¼à¿Ø Spring Boot Ó¦ÓóÌÐò¡£Ó¦ÓóÌÐò¿ÉÒÔͨ¹ý http µÄ·½Ê½£¬»ò Spring Cloud ·þÎñ·¢ÏÖ»ú֯ע²áµ½ SBA ÖУ¬È»ºó¾Í¿ÉÒÔʵÏÖ¶Ô Spring Boot ÏîÄ¿µÄ¿ÉÊÓ»¯¹ÜÀíºÍ²é¿´ÁË¡£
+
+Spring Boot Admin ¿ÉÒÔ¼à¿Ø Spring Boot µ¥»ú»ò¼¯ÈºÏîÄ¿£¬ËüÌṩÏêϸµÄ½¡¿µ (Health)ÐÅÏ¢¡¢ÄÚ´æÐÅÏ¢¡¢JVM ϵͳºÍ»·¾³ÊôÐÔ¡¢À¬»ø»ØÊÕÐÅÏ¢¡¢ÈÕÖ¾ÉèÖúͲ鿴¡¢¶¨Ê±ÈÎÎñ²é¿´¡¢Spring Boot »º´æ²é¿´ºÍ¹ÜÀíµÈ¹¦ÄÜ¡£½ÓÏÂÀ´ÎÒÃÇÒ»ÆðÀ´´î½¨ºÍʹÓðɡ£
+
+Ëü×îÖÕµÄչʾЧ¹ûÈçÏ£º
+
+[](https://s5.51cto.com/oss/202201/14/5d142e8c6b544f7b981b3eff8099b3d8.png)
+
+## 1.´î½¨SBA¼à¿Ø¶Ë
+
+ÎÒÃÇÐèÒª´´½¨Ò»¸ö Spring Boot Admin ÏîÄ¿£¬ÓÃÀ´¼à¿ØºÍ¹ÜÀíÎÒÃÇµÄ Spring Boot ÏîÄ¿£¬´î½¨µÄ·½Ê½ºÍ´´½¨ÆÕͨµÄ Spring Boot ÏîÄ¿ÀàËÆ£¬¾ßÌå²½ÖèÈçÏ¡£Ê¹Óà Idea ´´½¨Ò»¸ö Spring Boot ÏîÄ¿£º
+
+[](https://s5.51cto.com/oss/202201/14/d97c492785db6ff2ded49175184ceda9.png)
+
+[](https://s3.51cto.com/oss/202201/14/8bb1f0389b95e174b56ac01ba313ec7b.png)
+
+ÕâÀïÐèҪעÒ⣬ÐèÒªÌí¼Ó Spring Boot Admin(Server)·þÎñ¶Ë¿ò¼ÜµÄÖ§³Ö£¬ÈçÏÂͼËùʾ£º
+
+[](https://s4.51cto.com/oss/202201/14/122e9f0726fde8ac0c8936c79ef12f5f.png)
+
+Ò²¾ÍÊÇ´´½¨µÄ Spring Boot ÏîÄ¿ÐèÒªÌí¼ÓÒÔÏÂÁ½¸öÖØÒªµÄ¿ò¼ÜÖ§³Ö£º
+
+
+
+¸´ÖÆ
+
+```
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ de.codecentric
+ spring-boot-admin-starter-server
+
+
+```
+
+
+
+
+
+
+
+### 1.1 ¿ªÆôSBA·þÎñ
+
+´´½¨ÍêÏîĿ֮ºó£¬ÐèÒªÔÚÆô¶¯ÀàÉÏ¿ªÆô SBA ·þÎñ£º
+
+
+
+¸´ÖÆ
+
+```
+import de.codecentric.boot.admin.server.config.EnableAdminServer;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@EnableAdminServer // Ìí¼Ó´ËÐдúÂë
+@SpringBootApplication
+public class SbaserverApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(SbaserverApplication.class, args);
+ }
+}
+
+```
+
+
+
+
+
+### 1.2 ÅäÖÃSBA¶Ë¿ÚºÅ
+
+ÔÚ application.properties ÖÐÅäÖÃÒ»¸öÏîÄ¿µÄ¶Ë¿ÚºÅ¾Í¿ÉÒÔÖ±½ÓÆô¶¯ÁË£¬ÎÒÅäÖõĶ˿ںÅÊÇ 9001£º
+
+
+
+¸´ÖÆ
+
+```
+server.port=9001
+
+```
+
+
+
+
+
+PS£ºÅäÖö˿ںŵÄÖ÷ҪĿµÄÊÇΪÁ˲»ºÍÆäËû Spring Boot ÏîÄ¿³åÍ»£¬Èç¹û SBA Êǵ¥¶À²¿Êð´Ë²½Öè¿ÉÒÔºöÂÔ¡£
+
+Æô¶¯ÏîĿ֮ºó£¬¾Í¿ÉÒÔ¿´µ½ SBA µÄÖ÷Ò³ÁË£¬ÈçÏÂͼËùʾ£º
+
+[](https://s5.51cto.com/oss/202201/14/20418ce88230b20b234f9e9c15e07f47.png)
+
+´Ëʱ SBA Öл¹Ã»ÓÐÌí¼ÓÈκÎÐèÒª¼à¿ØµÄÏîÄ¿£¬½ÓÏÂÀ´ÎÒÃÇÔÙ´´½¨Ò»¸ö Spring Boot ÏîÄ¿£¬¼ÓÈëµ½ SBA ÖÐÀ´½øÐÐ¼à¿ØºÍ¹ÜÀí°É¡£
+
+## 2.´´½¨Ò»¸öÆÕͨSpringBootÏîÄ¿
+
+Ê×ÏÈ£¬ÎÒÃÇÐèÒª´´½¨Ò»¸öÆÕͨµÄ Spring Boot ÏîÄ¿£¬¾ßÌåµÄ´´½¨²½ÖèÕâÀï¾Í²»ÑÝʾÁË¡£µ±´´½¨ºÃ Spring Boot ÏîĿ֮ºó£¬ÐèÒªÔÚÕâ¸ö Spring Boot ÏîÄ¿ÖÐÐèÒªÌí¼Ó SBA ¿Í»§¶Ë¿ò¼ÜµÄÖ§³Ö£¬Ò²¾ÍÊÇÔÚ pom.xml ÖÐÅäÖÃÈçÏÂÄÚÈÝ£º
+
+
+
+
+
+¸´ÖÆ
+
+```
+
+ de.codecentric
+ spring-boot-admin-starter-client
+
+
+```
+
+
+
+
+
+È»ºóÔÚ application.properties ÎļþÖÐÅäÖà SBA ·þÎñÆ÷¶ËµØÖ·£¬Ò²¾ÍÊÇÔÛÃǵÚÒ»²½´´½¨ SBA ÏîÄ¿µÄµØÖ·£¬ÅäÖÃÄÚÈÝÈçÏ£º
+
+
+
+¸´ÖÆ
+
+```
+# µ±Ç°ÏîÄ¿¶Ë¿ÚºÅ
+server.port=8080
+# Spring Boot Admin ¼à¿Ø·þÎñÆ÷¶ËµØÖ·
+spring.boot.admin.client.url=http://localhost:9001
+
+```
+
+
+
+
+
+ÆäÖС°spring.boot.admin.client.url¡±Îª SBA ¼à¿ØµØÖ·¡£
+
+## 3.SpringBootAdmin¼à¿Ø×ÜÀÀ
+
+ÅäÖÃÍêÒÔÉÏÐÅÏ¢Ö®ºó£¬´Ëʱ²é¿´ Spring Boot Admin Ò³ÃæÖоÍÓб»¼à¿ØµÄ Spring Boot ÏîÄ¿ÁË£¬ÈçÏÂͼËùʾ£º
+
+[](https://s5.51cto.com/oss/202201/14/c010770a5cdfe5fad0ad1e8f0c3b07dc.png)
+
+Ò²¿ÉÒÔµã»÷¡°Ó¦ÓÃǽ¡±²é¿´ Spring Boot Admin ÖÐËùÓб»¼à¿ØµÄ Spring Boot ÏîÄ¿£¬ÈçÏÂͼËùʾ£º
+
+[](https://s4.51cto.com/oss/202201/14/d88e33f87e116000f9717e8c19c43cc4.png)
+
+µã»÷Ó¦ÓýøÈëÏêÇéÒ³Ãæ£¬ÈçÏÂͼËùʾ£º
+
+[](https://s2.51cto.com/oss/202201/14/4c3609840ea5cb45779eafbc2b260324.png)
+
+[](https://s4.51cto.com/oss/202201/14/2912ed434d97f8dd49c27ce73252d34c.png)
+
+ʼþÈÕÖ¾Öаüº¬ Spring Boot ¸÷ÖÖ״̬µÄչʾ(UP ΪÕý³£¡¢OFFLINE ΪÒì³£)ºÍ·¢ÉúµÄʱ¼ä£¬ÈçÏÂͼËùʾ£º
+
+[](https://s5.51cto.com/oss/202201/14/5792a62fbcafe6978bfe3bd26cf1e3ab.png)
+
+## 4.SpringBootÒì³£¼à¿Ø
+
+µ±ÎÒÃÇÊÖ¶¯°Ñ±»¼à¿ØµÄ Spring Boot ÏîĿֹ֮ͣºó£¬ÔÚ Spring Boot Admin ÖоͿÉÒԲ鿴µ½Ò»¸öÓ¦ÓÃÒѾ±»Í£µôÁË£¬ÈçÏÂͼËùʾ£º
+
+[](https://s5.51cto.com/oss/202201/14/47569a3fe09e62b2364c26bdbd7da4bc.png)
+
+ÎÒÃÇÒ²¿ÉÒÔͨ¹ýʼþÈÕÖ¾²é¿´ Spring Boot å´»úµÄ¾ßÌåʱ¼ä£¬ÈçÏÂͼËùʾ£º
+
+[](https://s2.51cto.com/oss/202201/14/b63f631561fa646f85ccf3e1e4321939.png)
+
+## 5.ÅäÖò鿴¸ü¶à¼à¿ØÏî
+
+ͨ¹ýÉÏÃæµÄÄÚÈÝÎÒÃÇ¿ÉÒÔ¿´³ö£¬¼à¿ØµÄ Spring Boot Ñ¡ÏÊDZȽÏÉٵģ¬Ôõô²ÅÄܲ鿴¸ü¶àµÄ¼à¿ØÏîÄØ?Òª½â¾öÕâ¸öÎÊÌ⣬ÎÒÃÇÐèÒªÔÚ±»¼à¿ØµÄ Spring Boot ÏîÄ¿ÖÐÌí¼Ó spring-boot-starter-actuator ¿ò¼ÜµÄÖ§³Ö£¬²¢¿ªÆô²é¿´ËùÓÐ¼à¿ØÏîµÄÅäÖòÅÐУ¬×îÖÕչʾЧ¹ûÈçÏ£º
+
+[](https://s4.51cto.com/oss/202201/14/03938ac0bded4487b6720fc4657f9e99.png)
+
+½ÓÏÂÀ´ÎÒÃÇÀ´ÅäÖÃÒ»ÏÂÕâЩ¼à¿ØÏî¡£
+
+### 5.1 Ìí¼Óactuator¿ò¼ÜÖ§³Ö
+
+ÔÚ±»¼à¿ØµÄ Spring Boot ÏîÄ¿ÖÐÌí¼Ó actuator ¿ò¼ÜÖ§³Ö£¬Ò²¾ÍÊÇÔÚ pom.xml ÖÐÌí¼ÓÒÔÏÂÅäÖãº
+
+
+
+
+
+¸´ÖÆ
+
+```
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+```
+
+
+
+
+
+ÊÖ¶¯µã»÷ Maven µ¼ÈëÒÀÀµ°ü(Èç¹û¿ªÆôÁË×Ô¶¯µ¼È룬´Ë²½Öè¿ÉºöÂÔ)¡£
+
+### 5.2 ÅäÖÿª·ÅËùÓÐ¼à¿ØÏî
+
+ÔÚ±»¼à¿ØµÄ Spring Boot ÏîÄ¿ÖÐÌí¼ÓÒÔÏÂÅäÖãº
+
+
+
+¸´ÖÆ
+
+```
+# ¿ªÆô¼à¿ØËùÓÐÏî
+management.endpoints.web.exposure.include=*
+
+```
+
+
+
+
+
+ÒÔÉϵÄÅäÖÃÊÇ¿ª·Å¼à¿ØËùÓÐÑ¡ÏÅäÖÃÍêÖ®ºó£¬ÖØÆô´Ë Spring Boot ÏîÄ¿£¬È»ºóÔÙˢРSpring Boot Admin ¸ü¶àµÄ¼à¿ØÏî¾Íչʾ³öÀ´ÁË£¬ÈçÏÂͼËùʾ£º
+
+[](https://s6.51cto.com/oss/202201/14/2cc24e05bc6185ba1869872db5a864a5.png)
+
+### 5.3 ¼à¿ØÏîĿԤÀÀ
+
+½« Spring Boot µÄËùÓÐ¼à¿ØÏî¶¼¿ªÆôÖ®ºó£¬Í¨¹ý SBA ¾Í¿ÉÒԲ鿴ÒÔÏÂÄÚÈÝÁË£º
+
+* Æô¶¯Ê±¼ä¡¢ÀÛ¼ÆÔËÐÐʱ¼ä;
+* ½ø³ÌºÍÏß³ÌÊýÁ¿ºÍÕ¼ÓÃµÄ CPU ×ÊÔ´;
+* À¬»ø»ØÊÕÏêÇéÐÅÏ¢£¬»ØÊÕ´ÎÊýºÍ»¨·Ñʱ¼ä;
+* JVM Ïß³Ìת´¢¡¢ÄÚ´æ×ª´¢ÏêÇéºÍ¶ÔÓ¦µÄÎļþÏÂÔØ;
+* ¿ÉÒԲ鿴ºÍÅäÖà Spring Boot ÏîÄ¿ÖеÄÈÕÖ¾¼¶±ð;
+* ²é¿´ Spring Boot ÏîÄ¿ÐÔÄÜ¼à¿Ø;
+* ²é¿´ Spring Boot ÔËÐл·¾³ÐÅÏ¢;
+* ²é¿´ Spring Boot ËùÓÐÀàÐÅÏ¢;
+* ²é¿´ Spring Boot ÖеĶ¨Ê±ÈÎÎñ;
+* ²é¿´ºÍ¹ÜÀí Spring Boot ÏîÄ¿ÖеÄËùÓлº´æ¡£
+
+ÒÔÏÂÊǼ¸¸öÖØÒªÒ³ÃæµÄ½ØÍ¼£¬ÎÒÃÇÒ»ÆðÀ´¿´¡£
+
+### 5.3.1 ²é¿´ÔËÐл·¾³
+
+[](https://s5.51cto.com/oss/202201/14/a9db77b1b0e378450086edd1ab438df5.png)
+
+[](https://s2.51cto.com/oss/202201/14/17604f4f5eb388a2a6c08f55e1e050ac.png)
+
+### 5.3.2 ²é¿´¶¨Ê±ÈÎÎñ
+
+[](https://s5.51cto.com/oss/202201/14/113d94b9bd488e239967915aededc89c.png)
+
+### 5.3.3 ÏîÄ¿ÈÕÖ¾¼¶±ðÅäÖÃ
+
+[](https://s3.51cto.com/oss/202201/14/8da60846eecbdbd9472ae6dbf17d951f.png)
+
+ÎÒÃÇ¿ÉÒÔͨ¹ý Spring Boot Admin À´¶¯Ì¬µÄÅäÖÃÏîÄ¿ÖеÄÈÕÖ¾¼¶±ð¡£
+
+### 5.3.4 JVMÏ̺߳ÍÄÚ´æ²é¿´
+
+[](https://s2.51cto.com/oss/202201/14/d3f98228a8b19675475c863457821034.png)
+
+### 5.3.5 ²é¿´SpringBootËùÓлº´æ
+
+[](https://s5.51cto.com/oss/202201/14/ae811102080c26b11135be50cd889710.png)
+
+µ±È»ÎÒÃÇ»¹¿ÉÒÔ¶ÔÕâЩ»º´æ½øÐÐɾ³ý²Ù×÷¡£
+
+## 6.²é¿´ÏîĿʵʱÈÕÖ¾
+
+ÏëÒª²é¿´¼à¿ØÏîÄ¿ÖеÄÈÕÖ¾ÐÅÏ¢£¬ÓÐÒ»¸öǰÌáÌõ¼þ£¬Ç°ÌáÌõ¼þÊÇÄã±»¼à¿ØµÄ Spring Boot ÏîÄ¿£¬±ØÐëÅäÖÃÁËÈÕÖ¾µÄ±£´æÂ·¾¶»òÕßÈÕÖ¾±£´æÎļþÃû£¬Ö»ÓÐÅäÖÃÕâÁ½ÏîÖеÄÈÎÒâÒ»ÏÄãµÄ Spring Boot ÏîÄ¿²Å»á½«ÈÕÖ¾±£´æµ½´ÅÅÌÉÏ£¬ÕâÑù²ÅÄÜͨ¹ý SBA ²é¿´µ½£¬ÎÒÅäÖõÄÊÇÈÕ־·¾¶£¬ÔÚ Spring Boot µÄ application.properties ÅäÖÃÎļþÖÐÌí¼ÓÒÔÏÂÅäÖãº
+
+
+
+¸´ÖÆ
+
+```
+# ÉèÖÃÈÕÖ¾±£´æÂ·¾¶
+logging.file.path=C:\\work\\log
+
+```
+
+
+
+
+
+ÉèÖÃÍê³ÉÖ®ºó£¬ÖØÆôÄãµÄ Spring Boot ÏîÄ¿£¬È»ºóˢРSBA Ò³Ãæ£¬×îÖÕչʾЧ¹ûÈçÏ£º
+
+[](https://s6.51cto.com/oss/202201/14/3f03c6402cc8a2532ed45ab43be156ac.png)
+
+´ËʱÎÒÃǾͿÉÒԲ鿴ʵʱµÄÈÕÖ¾ÐÅÏ¢ÁË£¬µ±È»ÄãÒ²¿ÉÒÔËæÊ±ÏÂÔØÈÕÖ¾£¬Èç¹ûÐèÒªµÄ»°¡£
+
+## ×ܽá
+
+Spring Boot Admin(SBA)ÊÇÒ»¸öÉçÇø¿ªÔ´ÏîÄ¿£¬ÓÃÓÚ¹ÜÀíºÍ¼àÊÓ Spring Boot Ó¦ÓóÌÐò£¬ËüÌṩÏêϸµÄ½¡¿µ (Health)ÐÅÏ¢¡¢ÄÚ´æÐÅÏ¢¡¢JVM ϵͳºÍ»·¾³ÊôÐÔ¡¢À¬»ø»ØÊÕÐÅÏ¢¡¢ÈÕÖ¾ÉèÖúͲ鿴¡¢¶¨Ê±ÈÎÎñ²é¿´¡¢Spring Boot »º´æ²é¿´ºÍ¹ÜÀíµÈ¹¦ÄÜ¡£
+
+ÎÒÃÇÐèÒª´´½¨Ò»¸ö SBA ·þÎñÆ÷¶ËÓÃÀ´¼à¿ØÒ»¸ö»ò¶à¸ö Spring Boot ÏîÄ¿£¬±»¼à¿ØµÄ Spring Boot ÏîĿҪÌí¼Ó SBA Client ¿ò¼ÜµÄÖ§³Ö£¬ÇÒÌí¼Ó actuator ¿ò¼ÜºÍÏàÓ¦µÄÅäÖ㬾ͿÉÒÔʵÏÖ¶Ô Spring Boot ÏîÄ¿µÄÍêÃÀ¼à¿ØÁË¡£
\ No newline at end of file
diff --git "a/docs/spring/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md" "b/docs/spring/SpringBoot/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md"
similarity index 100%
rename from "docs/spring/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md"
rename to "docs/spring/SpringBoot/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md"
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\233\275\351\231\205\345\214\226\345\212\237\350\203\275.md" "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\233\275\351\231\205\345\214\226\345\212\237\350\203\275.md"
new file mode 100644
index 0000000..374388b
--- /dev/null
+++ "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\233\275\351\231\205\345\214\226\345\212\237\350\203\275.md"
@@ -0,0 +1,179 @@
+#### ¹ú¼Ê»¯
+
+* * *
+
+ÔÚ¿ª·¢Ó¦ÓóÌÐòµÄʱºò£¬¾³£»áÓöµ½Ö§³Ö¶àÓïÑÔµÄÐèÇó£¬ÕâÖÖÖ§³Ö¶àÓïÑԵŦÄܳÆÖ®Îª¹ú¼Ê»¯£¬Ó¢ÎÄÊÇinternationalization£¬ËõдΪi18n£¨ÒòΪÊ××ÖĸiºÍÄ©×ÖĸnÖмäÓÐ18¸ö×Öĸ£©¡£
+
+»¹ÓÐÕë¶ÔÌØ¶¨µØÇøµÄ±¾µØ»¯¹¦ÄÜ£¬Ó¢ÎÄÊÇlocalization£¬ËõдΪL10n£¬±¾µØ»¯ÊÇÖ¸¸ù¾ÝµØÇøµ÷ÕûÀàËÆÐÕÃû¡¢ÈÕÆÚµÄÏÔʾµÈ¡£
+
+Ò²ÓаÑÉÏÃæÁ½ÕߺϳÆÎªÈ«Çò»¯£¬Ó¢ÎÄÊÇglobalization£¬ËõдΪg11n¡£
+
+ÔÚJavaÖУ¬Ö§³Ö¶àÓïÑԺͱ¾µØ»¯ÊÇͨ¹ý`MessageFormat`ÅäºÏ`Locale`ʵÏֵģº
+
+
+¶ÔÓÚWebÓ¦ÓóÌÐò£¬ÒªÊµÏÖ¹ú¼Ê»¯¹¦ÄÜ£¬Ö÷ÒªÊÇäÖȾViewµÄʱºò£¬Òª°Ñ¸÷ÖÖÓïÑÔµÄ×ÊÔ´ÎļþÌá³öÀ´£¬ÕâÑù£¬²»Í¬µÄÓû§·ÃÎÊͬһ¸öÒ³ÃæÊ±£¬ÏÔʾµÄÓïÑÔ¾ÍÊDz»Í¬µÄ¡£
+
+ÎÒÃÇÀ´¿´¿´ÔÚSpring MVCÓ¦ÓóÌÐòÖÐÈçºÎʵÏÖ¹ú¼Ê»¯¡£
+
+### »ñÈ¡Locale
+
+ʵÏÖ¹ú¼Ê»¯µÄµÚÒ»²½ÊÇ»ñÈ¡µ½Óû§µÄ`Locale`¡£ÔÚWebÓ¦ÓóÌÐòÖУ¬HTTP¹æ·¶¹æ¶¨ÁËä¯ÀÀÆ÷»áÔÚÇëÇóÖÐЯ´ø`Accept-Language`Í·£¬ÓÃÀ´Ö¸Ê¾Óû§ä¯ÀÀÆ÷É趨µÄÓïÑÔ˳Ðò£¬È磺
+
+```
+Accept-Language: zh-CN,zh;q=0.8,en;q=0.2
+
+```
+
+ÉÏÊöHTTPÇëÇóÍ·±íʾÓÅÏÈÑ¡Ôñ¼òÌåÖÐÎÄ£¬Æä´ÎÑ¡ÔñÖÐÎÄ£¬×îºóÑ¡ÔñÓ¢ÎÄ¡£`q`±íÊ¾È¨ÖØ£¬½âÎöºóÎÒÃǿɻñµÃÒ»¸ö¸ù¾ÝÓÅÏȼ¶ÅÅÐòµÄÓïÑÔÁÐ±í£¬°ÑËüת»»ÎªJavaµÄ`Locale`£¬¼´»ñµÃÁËÓû§µÄ`Locale`¡£´ó¶àÊý¿ò¼Üͨ³£Ö»·µ»ØÈ¨ÖØ×î¸ßµÄ`Locale`¡£
+
+Spring MVCͨ¹ý`LocaleResolver`À´×Ô¶¯´Ó`HttpServletRequest`ÖлñÈ¡`Locale`¡£ÓжàÖÖ`LocaleResolver`µÄʵÏÖÀ࣬ÆäÖÐ×î³£ÓõÄÊÇ`CookieLocaleResolver`£º
+
+```
+@Primary
+@Bean
+LocaleResolver createLocaleResolver() {
+ var clr = new CookieLocaleResolver(); clr.setDefaultLocale(Locale.ENGLISH); clr.setDefaultTimeZone(TimeZone.getDefault()); return clr;}
+
+```
+
+`CookieLocaleResolver`´Ó`HttpServletRequest`ÖлñÈ¡`Locale`ʱ£¬Ê×Ïȸù¾ÝÒ»¸öÌØ¶¨µÄCookieÅжÏÊÇ·ñÖ¸¶¨ÁË`Locale`£¬Èç¹ûûÓУ¬¾Í´ÓHTTPÍ·»ñÈ¡£¬Èç¹û»¹Ã»ÓУ¬¾Í·µ»ØÄ¬ÈϵÄ`Locale`¡£
+
+µ±Óû§µÚÒ»´Î·ÃÎÊÍøÕ¾Ê±£¬`CookieLocaleResolver`Ö»ÄÜ´ÓHTTPÍ·»ñÈ¡`Locale`£¬¼´Ê¹ÓÃä¯ÀÀÆ÷µÄĬÈÏÓïÑÔ¡£Í¨³£ÍøÕ¾Ò²ÔÊÐíÓû§×Ô¼ºÑ¡ÔñÓïÑÔ£¬´Ëʱ£¬`CookieLocaleResolver`¾Í»á°ÑÓû§Ñ¡ÔñµÄÓïÑÔ´æ·Åµ½CookieÖУ¬ÏÂÒ»´Î·ÃÎÊʱ£¬¾Í»á·µ»ØÓû§ÉÏ´ÎÑ¡ÔñµÄÓïÑÔ¶ø²»ÊÇä¯ÀÀÆ÷ĬÈÏÓïÑÔ¡£
+
+### ÌáÈ¡×ÊÔ´Îļþ
+
+µÚ¶þ²½ÊǰÑдËÀÔÚÄ£°åÖеÄ×Ö·û´®ÒÔ×ÊÔ´ÎļþµÄ·½Ê½´æ´¢ÔÚÍⲿ¡£¶ÔÓÚ¶àÓïÑÔ£¬Ö÷ÎļþÃûÈç¹ûÃüÃûΪ`messages`£¬ÄÇô×ÊÔ´Îļþ±ØÐë°´ÈçÏ·½Ê½ÃüÃû²¢·ÅÈëclasspathÖУº
+
+* ĬÈÏÓïÑÔ£¬ÎļþÃû±ØÐëΪ`messages.properties`£»
+* ¼òÌåÖÐÎÄ£¬LocaleÊÇ`zh_CN`£¬ÎļþÃû±ØÐëΪ`messages_zh_CN.properties`£»
+* ÈÕÎÄ£¬LocaleÊÇ`ja_JP`£¬ÎļþÃû±ØÐëΪ`messages_ja_JP.properties`£»
+* ÆäËü¸ü¶àÓïÑÔ¡¡
+
+ÿ¸ö×ÊÔ´Îļþ¶¼ÓÐÏàͬµÄkey£¬ÀýÈ磬ĬÈÏÓïÑÔÊÇÓ¢ÎÄ£¬Îļþ`messages.properties`ÄÚÈÝÈçÏ£º
+
+```
+language.select=Language
+home=Home
+signin=Sign In
+copyright=Copyright?{0,number,#}
+
+```
+
+Îļþ`messages_zh_CN.properties`ÄÚÈÝÈçÏ£º
+
+```
+language.select=ÓïÑÔ
+home=Ê×Ò³
+signin=怬
+copyright=°æÈ¨ËùÓÐ?{0,number,#}
+
+```
+
+### ´´½¨MessageSource
+
+µÚÈý²½ÊÇ´´½¨Ò»¸öSpringÌṩµÄ`MessageSource`ʵÀý£¬Ëü×Ô¶¯¶ÁÈ¡ËùÓеÄ`.properties`Îļþ£¬²¢Ìṩһ¸öͳһ½Ó¿ÚÀ´ÊµÏÖ¡°·Ò롱£º
+
+```
+// code, arguments, locale:
+String text = messageSource.getMessage("signin", null, locale);
+
+```
+
+ÆäÖУ¬`signin`ÊÇÎÒÃÇÔÚ`.properties`ÎļþÖж¨ÒåµÄkey£¬µÚ¶þ¸ö²ÎÊýÊÇ`Object[]`Êý×é×÷Ϊ¸ñʽ»¯Ê±´«ÈëµÄ²ÎÊý£¬×îºóÒ»¸ö²ÎÊý¾ÍÊÇ»ñÈ¡µÄÓû§`Locale`ʵÀý¡£
+
+´´½¨`MessageSource`ÈçÏ£º
+
+```
+@Bean("i18n")
+MessageSource createMessageSource() {
+ var messageSource = new ResourceBundleMessageSource(); // Ö¸¶¨ÎļþÊÇUTF-8±àÂë:
+ messageSource.setDefaultEncoding("UTF-8"); // Ö¸¶¨Ö÷ÎļþÃû:
+ messageSource.setBasename("messages"); return messageSource;}
+
+```
+
+×¢Òâµ½`ResourceBundleMessageSource`»á×Ô¶¯¸ù¾ÝÖ÷ÎļþÃû×Ô¶¯°ÑËùÓÐÏà¹ØÓïÑÔµÄ×ÊÔ´Îļþ¶¼¶Á½øÀ´¡£
+
+ÔÙ×¢Òâµ½SpringÈÝÆ÷»á´´½¨²»Ö»Ò»¸ö`MessageSource`ʵÀý£¬ÎÒÃÇ×Ô¼º´´½¨µÄÕâ¸ö`MessageSource`ÊÇרßøÒ³Ãæ¹ú¼Ê»¯Ê¹Óõģ¬Òò´ËÃüÃûΪ`i18n`£¬²»»áÓëÆäËü`MessageSource`ʵÀý³åÍ»¡£
+
+### ʵÏÖ¶àÓïÑÔ
+
+ÒªÔÚViewÖÐʹÓÃ`MessageSource`¼ÓÉÏ`Locale`Êä³ö¶àÓïÑÔ£¬ÎÒÃÇͨ¹ý±àдһ¸ö`MvcInterceptor`£¬°ÑÏà¹Ø×ÊÔ´×¢Èëµ½`ModelAndView`ÖУº
+
+```
+@Component
+public class MvcInterceptor implements HandlerInterceptor {
+ @Autowired LocaleResolver localeResolver;
+ // ×¢Òâ×¢ÈëµÄMessageSourceÃû³ÆÊÇi18n:
+ @Autowired @Qualifier("i18n") MessageSource messageSource;
+ public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { if (modelAndView != null) { // ½âÎöÓû§µÄLocale:
+ Locale locale = localeResolver.resolveLocale(request); // ·ÅÈëModel:
+ modelAndView.addObject("__messageSource__", messageSource); modelAndView.addObject("__locale__", locale); } }}
+
+```
+
+²»ÒªÍüÁËÔÚ`WebMvcConfigurer`ÖÐ×¢²á`MvcInterceptor`¡£ÏÖÔÚ£¬¾Í¿ÉÒÔÔÚViewÖе÷ÓÃ`MessageSource.getMessage()`·½·¨À´ÊµÏÖ¶àÓïÑÔ£º
+
+```
+{{ __messageSource__.getMessage('signin', null, __locale__) }}
+
+```
+
+ÉÏÊöÕâÖÖд·¨ËäÈ»¿ÉÐУ¬µ«¸ñʽ̫¸´ÔÓÁË¡£Ê¹ÓÃViewʱ£¬Òª¸ù¾Ýÿ¸öÌØ¶¨µÄViewÒýÇæ¶¨Öƹú¼Ê»¯º¯Êý¡£ÔÚPebbleÖУ¬ÎÒÃÇ¿ÉÒÔ·â×°Ò»¸ö¹ú¼Ê»¯º¯Êý£¬Ãû³Æ¾ÍÊÇÏ»®Ïß`_`£¬¸ÄÔìһϴ´½¨`ViewResolver`µÄ´úÂ룺
+
+```
+@Bean
+ViewResolver createViewResolver(@Autowired ServletContext servletContext, @Autowired @Qualifier("i18n") MessageSource messageSource) {
+ var engine = new PebbleEngine.Builder() .autoEscaping(true) .cacheActive(false) .loader(new Servlet5Loader(servletContext)) // Ìí¼ÓÀ©Õ¹:
+ .extension(createExtension(messageSource)) .build(); var viewResolver = new PebbleViewResolver(); viewResolver.setPrefix("/WEB-INF/templates/"); viewResolver.setSuffix(""); viewResolver.setPebbleEngine(engine); return viewResolver;}
+
+private Extension createExtension(MessageSource messageSource) {
+ return new AbstractExtension() { @Override public Map getFunctions() { return Map.of("_", new Function() { public Object execute(Map args, PebbleTemplate self, EvaluationContext context, int lineNumber) { String key = (String) args.get("0"); List arguments = this.extractArguments(args); Locale locale = (Locale) context.getVariable("__locale__"); return messageSource.getMessage(key, arguments.toArray(), "???" + key + "???", locale); } private List extractArguments(Map args) { int i = 1; List arguments = new ArrayList<>(); while (args.containsKey(String.valueOf(i))) { Object param = args.get(String.valueOf(i)); arguments.add(param); i++; } return arguments; } public List getArgumentNames() { return null; } }); } };}
+
+```
+
+ÕâÑù£¬ÎÒÃÇ¿ÉÒ԰ѶàÓïÑÔÒ³Ãæ¸ÄдΪ£º
+
+```
+{{ _('signin') }}
+
+```
+
+Èç¹ûÊÇ´ø²ÎÊýµÄ¶àÓïÑÔ£¬ÐèÒª°Ñ²ÎÊý´«½øÈ¥£º
+
+```
+{{ _('copyright', 2020) }}
+
+```
+
+ʹÓÃÆäËüViewÒýÇæÊ±£¬Ò²Ó¦µ±¸ù¾ÝÒýÇæ½Ó¿ÚʵÏÖ¸ü·½±ãµÄÓï·¨¡£
+
+### Çл»Locale
+
+×îºó£¬ÎÒÃÇÐèÒªÔÊÐíÓû§ÊÖ¶¯Çл»`Locale`£¬±àдһ¸ö`LocaleController`À´ÊµÏָù¦ÄÜ£º
+
+```
+@Controller
+public class LocaleController {
+ final Logger logger = LoggerFactory.getLogger(getClass());
+ @Autowired LocaleResolver localeResolver;
+ @GetMapping("/locale/{lo}") public String setLocale(@PathVariable("lo") String lo, HttpServletRequest request, HttpServletResponse response) { // ¸ù¾Ý´«ÈëµÄlo´´½¨LocaleʵÀý:
+ Locale locale = null; int pos = lo.indexOf('_'); if (pos > 0) { String lang = lo.substring(0, pos); String country = lo.substring(pos + 1); locale = new Locale(lang, country); } else { locale = new Locale(lo); } // É趨´ËLocale:
+ localeResolver.setLocale(request, response, locale); logger.info("locale is set to {}.", locale); // Ë¢ÐÂÒ³Ãæ:
+ String referer = request.getHeader("Referer"); return "redirect:" + (referer == null ? "/" : referer); }}
+
+```
+
+ÔÚÒ³ÃæÉè¼ÆÖУ¬Í¨³£ÔÚÓÒÉϽǸøÓû§Ìṩһ¸öÓïÑÔÑ¡ÔñÁÐ±í£¬À´¿´¿´Ð§¹û£º
+
+
+
+Çл»µ½ÖÐÎÄ£º
+
+
+
+### С½á
+
+¶àÓïÑÔÖ§³ÖÐèÒª´ÓHTTPÇëÇóÖнâÎöÓû§µÄLocale£¬È»ºóÕë¶Ô²»Í¬LocaleÏÔʾ²»Í¬µÄÓïÑÔ£»
+
+Spring MVCÓ¦ÓóÌÐòͨ¹ý`MessageSource`ºÍ`LocaleResolver`£¬ÅäºÏViewʵÏÖ¹ú¼Ê»¯¡£
\ No newline at end of file
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\270\270\347\224\250\345\212\237\350\203\275.md" "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\270\270\347\224\250\345\212\237\350\203\275.md"
new file mode 100644
index 0000000..6b1c4bb
--- /dev/null
+++ "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\270\270\347\224\250\345\212\237\350\203\275.md"
@@ -0,0 +1,594 @@
+
+
+
+
+# Spring MVC ʹÓÃ@Controller×¢½â¶¨ÒåÒ»¸ö¿ØÖÆÆ÷
+
+
+
+2018-07-26 14:02 ¸üÐÂ
+
+
+
+
+
+
+
+
+
+> [Original] The `@Controller` annotation indicates that a particular class serves the role of a controller. Spring does not require you to extend any controller base class or reference the Servlet API. However, you can still reference Servlet-specific features if you need to.
+
+`@Controller`×¢½â±íÃ÷ÁËÒ»¸öÀàÊÇ×÷Ϊ¿ØÖÆÆ÷µÄ½ÇÉ«¶ø´æÔڵġ£Spring²»ÒªÇóÄãÈ¥¼Ì³ÐÈκοØÖÆÆ÷»ùÀ࣬Ҳ²»ÒªÇóÄãȥʵÏÖServletµÄÄÇÌ×API¡£µ±È»£¬Èç¹ûÄãÐèÒªµÄ»°Ò²¿ÉÒÔȥʹÓÃÈκÎÓëServletÏà¹ØµÄÌØÐÔºÍÉèÊ©¡£
+
+> [Original] The `@Controller` annotation acts as a stereotype for the annotated class, indicating its role. The dispatcher scans such annotated classes for mapped methods and detects `@RequestMapping` annotations (see the next section).
+
+`@Controller`×¢½â¿ÉÒÔÈÏΪÊDZ»±ê×¢ÀàµÄÔÐÍ£¨stereotype£©£¬±íÃ÷ÁËÕâ¸öÀàËù³Ðµ£µÄ½ÇÉ«¡£·ÖÅÉÆ÷£¨`DispatcherServlet`£©»áɨÃèËùÓÐ×¢½âÁË`@Controller`µÄÀ࣬¼ì²âÆäÖÐͨ¹ý`@RequestMapping`×¢½âÅäÖõķ½·¨£¨Ïê¼ûÏÂһС½Ú£©¡£
+
+> [Original] You can define annotated controller beans explicitly, using a standard Spring bean definition in the dispatcher¡¯s context. However, the `@Controller` stereotype also allows for autodetection, aligned with Spring general support for detecting component classes in the classpath and auto-registering bean definitions for them.
+
+µ±È»£¬ÄãÒ²¿ÉÒÔ²»Ê¹ÓÃ`@Controller`×¢½â¶øÏÔʽµØÈ¥¶¨Òå±»×¢½âµÄbean£¬Õâµãͨ¹ý±ê×¼µÄSpring beanµÄ¶¨Ò巽ʽ£¬ÔÚdispatherµÄÉÏÏÂÎÄÊôÐÔÏÂÅäÖü´¿É×öµ½¡£µ«ÊÇ`@Controller`ÔÐÍÊÇ¿ÉÒÔ±»¿ò¼Ü×Ô¶¯¼ì²âµÄ£¬SpringÖ§³Öclasspath·¾¶ÏÂ×é¼þÀàµÄ×Ô¶¯¼ì²â£¬ÒÔ¼°¶ÔÒѶ¨ÒåbeanµÄ×Ô¶¯×¢²á¡£
+
+> [Original] To enable autodetection of such annotated controllers, you add component scanning to your configuration. Use the spring-context schema as shown in the following XML snippet:
+
+ÄãÐèÒªÔÚÅäÖÃÖмÓÈë×é¼þɨÃèµÄÅäÖôúÂëÀ´¿ªÆô¿ò¼Ü¶Ô×¢½â¿ØÖÆÆ÷µÄ×Ô¶¯¼ì²â¡£ÇëʹÓÃÏÂÃæXML´úÂëËùʾµÄspring-context schema£º
+
+```
+
+
+
+
+
+
+
+
+```
+
+
+
+
+
+
+
+
+
+# Spring MVC ʹÓÃ@RequestMapping×¢½âÓ³ÉäÇëÇó·¾¶
+
+
+
+2018-07-26 15:29 ¸üÐÂ
+
+
+
+
+
+
+
+Äã¿ÉÒÔʹÓÃ`@RequestMapping`×¢½âÀ´½«ÇëÇóURL£¬Èç`/appointments`µÈ£¬Ó³Éäµ½Õû¸öÀàÉÏ»òij¸öÌØ¶¨µÄ´¦ÀíÆ÷·½·¨ÉÏ¡£Ò»°ãÀ´Ëµ£¬À༶±ðµÄ×¢½â¸ºÔð½«Ò»¸öÌØ¶¨£¨»ò·ûºÏijÖÖģʽ£©µÄÇëÇó·¾¶Ó³Éäµ½Ò»¸ö¿ØÖÆÆ÷ÉÏ£¬Í¬Ê±Í¨¹ý·½·¨¼¶±ðµÄ×¢½âÀ´Ï¸»¯Ó³É䣬¼´¸ù¾ÝÌØ¶¨µÄHTTPÇëÇó·½·¨£¨¡°GET¡±¡°POST¡±·½·¨µÈ£©¡¢HTTPÇëÇóÖÐÊÇ·ñЯ´øÌض¨²ÎÊýµÈÌõ¼þ£¬½«ÇëÇóÓ³É䵽ƥÅäµÄ·½·¨ÉÏ¡£
+
+
+
+ÏÂÃæÕâ¶Î´úÂëʾÀýÀ´×ÔPetcare£¬ËüչʾÁËÔÚSpring MVCÖÐÈçºÎÔÚ¿ØÖÆÆ÷ÉÏʹÓÃ`@RequestMapping`×¢½â£º
+
+```
+@Controller
+@RequestMapping("/appointments")
+public class AppointmentsController {
+
+ private final AppointmentBook appointmentBook;
+
+ @Autowired
+ public AppointmentsController(AppointmentBook appointmentBook) {
+ this.appointmentBook = appointmentBook;
+ }
+
+ @RequestMapping(method = RequestMethod.GET)
+ public Map get() {
+ return appointmentBook.getAppointmentsForToday();
+ }
+
+ @RequestMapping(path = "/{day}", method = RequestMethod.GET)
+ public Map getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
+ return appointmentBook.getAppointmentsForDay(day);
+ }
+
+ @RequestMapping(path = "/new", method = RequestMethod.GET)
+ public AppointmentForm getNewForm() {
+ return new AppointmentForm();
+ }
+
+ @RequestMapping(method = RequestMethod.POST)
+ public String add(@Valid AppointmentForm appointment, BindingResult result) {
+ if (result.hasErrors()) {
+ return "appointments/new";
+ }
+ appointmentBook.addAppointment(appointment);
+ return "redirect:/appointments";
+ }
+}
+
+```
+
+ÔÚÉÏÃæµÄʾÀýÖУ¬Ðí¶àµØ·½¶¼Ê¹Óõ½ÁË`@RequestMapping`×¢½â¡£µÚÒ»´ÎʹÓõãÊÇ×÷ÓÃÓÚÀ༶±ðµÄ£¬ËüָʾÁËËùÓÐ`/appointments`¿ªÍ·µÄ·¾¶¶¼»á±»Ó³Éäµ½¿ØÖÆÆ÷Ï¡£`get()`·½·¨ÉϵÄ`@RequestMapping`×¢½â¶ÔÇëÇó·¾¶½øÐÐÁ˽øÒ»²½Ï¸»¯£ºËü½ö½ÓÊÜGET·½·¨µÄÇëÇó¡£ÕâÑù£¬Ò»¸öÇëÇ󷾶Ϊ`/appointments`¡¢HTTP·½·¨ÎªGETµÄÇëÇ󣬽«»á×îÖÕ½øÈëµ½Õâ¸ö·½·¨±»´¦Àí¡£`add()`·½·¨Ò²×öÁËÀàËÆµÄϸ»¯£¬¶ø`getNewForm()`·½·¨Ôòͬʱע½âÁËÄܹ»½ÓÊܵÄÇëÇóµÄHTTP·½·¨ºÍ·¾¶¡£ÕâÖÖÇé¿öÏ£¬Ò»¸ö·¾¶Îª`appointments/new`¡¢HTTP·½·¨ÎªGETµÄÇëÇ󽫻ᱻÕâ¸ö·½·¨Ëù´¦Àí¡£
+
+`getForDay()`·½·¨ÔòչʾÁËʹÓÃ`@RequestMapping`×¢½âµÄÁíÒ»¸ö¼¼ÇÉ£ºURIÄ£°å¡££¨¹ØÓÚURIÄ£°å£¬Çë¼ûÏÂС½Ú£©
+
+À༶±ðµÄ`@RequestMapping`×¢½â²¢²»ÊDZØÐëµÄ¡£²»ÅäÖõϰÔòËùÓеÄ·¾¶¶¼ÊǾø¶Ô·¾¶£¬¶ø·ÇÏà¶Ô·¾¶¡£ÒÔϵĴúÂëʾÀýÀ´×ÔPetClinic£¬ËüչʾÁËÒ»¸ö¾ßÓжà¸ö´¦ÀíÆ÷·½·¨µÄ¿ØÖÆÆ÷£º
+
+```
+@Controller
+public class ClinicController {
+
+ private final Clinic clinic;
+
+ @Autowired
+ public ClinicController(Clinic clinic) {
+ this.clinic = clinic;
+ }
+
+ @RequestMapping("/")
+ public void welcomeHandler() {
+ }
+
+ @RequestMapping("/vets")
+ public ModelMap vetsHandler() {
+ return new ModelMap(this.clinic.getVets());
+ }
+}
+
+```
+
+ÒÔÉÏ´úÂëûÓÐÖ¸¶¨ÇëÇó±ØÐëÊÇGET·½·¨»¹ÊÇPUT/POST»òÆäËû·½·¨£¬`@RequestMapping`×¢½âĬÈÏ»áÓ³ÉäËùÓеÄHTTPÇëÇó·½·¨¡£Èç¹û½öÏë½ÓÊÕijÖÖÇëÇó·½·¨£¬ÇëÔÚ×¢½âÖÐÖ¸¶¨Ö®`@RequestMapping(method=GET)`ÒÔËõС·¶Î§¡£
+
+## @ControllerºÍÃæÏòÇÐÃæ£¨AOP£©´úÀí
+
+ÓÐʱ£¬ÎÒÃÇÏ£ÍûÔÚÔËÐÐʱʹÓÃAOP´úÀíÀ´×°ÊοØÖÆÆ÷£¬±ÈÈçµ±ÄãÖ±½ÓÔÚ¿ØÖÆÆ÷ÉÏʹÓÃ`@Transactional`×¢½âʱ¡£ÕâÖÖÇé¿öÏ£¬ÎÒÃÇÍÆ¼öʹÓÃÀ༶±ð£¨ÔÚ¿ØÖÆÆ÷ÉÏʹÓ㩵ĴúÀí·½Ê½¡£ÕâÒ»°ãÊÇ´úÀí¿ØÖÆÆ÷µÄĬÈÏ×ö·¨¡£Èç¹û¿ØÖÆÆ÷±ØÐëʵÏÖһЩ½Ó¿Ú£¬¶ø¸Ã½Ó¿ÚÓÖ²»Ö§³ÖSpring ContextµÄ»Øµ÷£¨±ÈÈç`InitializingBean`, `*Aware`µÈ½Ó¿Ú£©£¬ÄÇÒªÅäÖÃÀ༶±ðµÄ´úÀí¾Í±ØÐëÊÖ¶¯ÅäÖÃÁË¡£±ÈÈ磬ÔÀ´µÄÅäÖÃÎļþ` `ÐèÒªÏÔʽÅäÖÃΪ` `¡£
+
+## Spring MVC 3.1ÖÐÐÂÔöÖ§³Ö@RequestMappingµÄһЩÀà
+
+> They are recommended for use and even required to take advantage of new features in Spring MVC 3.1 and going forward.
+
+Spring 3.1ÖÐÐÂÔöÁËÒ»×éÀàÓÃÒÔÔöÇ¿`@RequestMapping`£¬·Ö±ðÊÇ`RequestMappingHandlerMapping`ºÍ`RequestMappingHandlerAdapter`¡£ÎÒÃÇÍÆ¼öÄãÓÃÒ»Óá£Óв¿·ÖSpring MVC 3.1Ö®ºóÐÂÔöµÄÌØÐÔ£¬ÕâÁ½¸ö×¢½âÉõÖÁÊDZØÐëµÄ¡£ÔÚMVCÃüÃû¿Õ¼äºÍMVC Java±à³ÌÅäÖ÷½Ê½Ï£¬Õâ×éÀ༰ÆäÐÂÌØÐÔĬÈÏÊÇ¿ªÆôµÄ¡£µ«ÈôÄãʹÓÃÆäËûÅäÖ÷½Ê½£¬Ôò¸ÃÌØÐÔ±ØÐëÊÖ¶¯ÅäÖòÅÄÜʹÓᣱ¾Ð¡½Ú½«¼òÒª½éÉÜһϣ¬ÐÂÀàÏà±È֮ǰµÄÒ»Ð©ÖØÒª±ä»¯¡£
+
+ÔÚSpring 3.1֮ǰ£¬¿ò¼Ü»áÔÚÁ½¸ö²»Í¬µÄ½×¶Î·Ö±ð¼ì²éÀ༶±ðºÍ·½·¨¼¶±ðµÄÇëÇóÓ³É䡪¡ªÊ×ÏÈ£¬`DefaultAnnotationHanlderMapping`»áÏÈÔÚÀ༶±ðÉÏÑ¡ÖÐÒ»¸ö¿ØÖÆÆ÷£¬È»ºóÔÙͨ¹ý`AnnotationMethodHandlerAdapter`¶¨Î»µ½¾ßÌåÒªµ÷Óõķ½·¨¡£
+
+> [Original] With the new support classes in Spring 3.1, the `RequestMappingHandlerMapping` is the only place where a decision is made about which method should process the request. Think of controller methods as a collection of unique endpoints with mappings for each method derived from type and method-level `@RequestMapping` information.
+
+ÏÖÔÚÓÐÁËSpring 3.1ºóÒýÈëµÄÕâ×éÐÂÀ࣬`RequestMappingHandlerMapping`³ÉΪÁËÕâÁ½¸ö¾ö²ßʵ¼Ê·¢ÉúµÄΨһһ¸öµØ·½¡£Äã¿ÉÒÔ°Ñ¿ØÖÆÆ÷ÖеÄһϵÁд¦Àí·½·¨µ±³ÉÊÇһϵÁжÀÁ¢µÄ·þÎñ½Úµã£¬Ã¿¸ö´ÓÀ༶±ðºÍ·½·¨¼¶±ðµÄ`@RequestMapping`×¢½âÖлñÈ¡µ½×ã¹»ÇëÇó1·¾¶Ó³ÉäÐÅÏ¢¡£
+
+> [Original] This enables some new possibilities. For once a `HandlerInterceptor` or a `HandlerExceptionResolver` can now expect the Object-based handler to be a `HandlerMethod`, which allows them to examine the exact method, its parameters and associated annotations. The processing for a URL no longer needs to be split across different controllers.
+
+ÕâÖÖеĴ¦Àí·½Ê½´øÀ´ÁËеĿÉÄÜÐÔ¡£Ö®Ç°µÄ`HandlerInterceptor`»ò`HandlerExceptionResolver`ÏÖÔÚ¿ÉÒÔÈ·¶¨Äõ½µÄÕâ¸ö´¦ÀíÆ÷¿Ï¶¨ÊÇÒ»¸ö`HandlerMethod`ÀàÐÍ£¬Òò´ËËüÄܹ»¾«È·µØÁ˽âÕâ¸ö·½·¨µÄËùÓÐÐÅÏ¢£¬°üÀ¨ËüµÄ²ÎÊý¡¢Ó¦ÓÃÓÚÆäÉϵÄ×¢½âµÈ¡£ÕâÑù£¬ÄÚ²¿¶ÔÓÚÒ»¸öURLµÄ´¦ÀíÁ÷³ÌÔÙÒ²²»ÐèÒª·Ö¸ôµ½²»Í¬µÄ¿ØÖÆÆ÷ÀïÃæÈ¥Ö´ÐÐÁË¡£
+
+> [Original] There are also several things no longer possible: [Original] _Select a controller first with a `SimpleUrlHandlerMapping` or `BeanNameUrlHandlerMapping` and then narrow the method based on `@RequestMapping` annotations. [Original] _Rely on method names as a fall-back mechanism to disambiguate between two `@RequestMapping` methods that don¡¯t have an explicit path mapping URL path but otherwise match equally, e.g. by HTTP method. In the new support classes `@RequestMapping` methods have to be mapped uniquely. [Original] * Have a single default method (without an explicit path mapping) with which requests are processed if no other controller method matches more concretely. In the new support classes if a matching method is not found a 404 error is raised.
+
+ͬʱ£¬Ò²ÓÐÆäËûµÄһЩ±ä»¯£¬±ÈÈçÓÐЩÊÂÇé¾Íû·¨ÕâÃ´Íæ¶ùÁË£º
+
+* ÏÈͨ¹ý`SimpleUrlHandlerMapping`»ò`BeanNameUrlHandlerMapping`À´Äõ½¸ºÔð´¦ÀíÇëÇóµÄ¿ØÖÆÆ÷£¬È»ºóͨ¹ý`@RequestMapping`×¢½âÅäÖõÄÐÅÏ¢À´¶¨Î»µ½¾ßÌåµÄ´¦Àí·½·¨£»
+* ÒÀ¿¿·½·¨Ãû³ÆÀ´×÷ΪѡÔñ´¦Àí·½·¨µÄ±ê×¼¡£±ÈÈç˵£¬Á½¸ö×¢½âÁË`@RequestMapping`µÄ·½·¨³ýÁË·½·¨Ãû³ÆÓµÓÐÍêÈ«ÏàͬµÄURLÓ³ÉäºÍHTTPÇëÇó·½·¨¡£ÔÚа汾Ï£¬`@RequestMapping`×¢½âµÄ·½·¨±ØÐë¾ßÓÐΨһµÄÇëÇóÓ³É䣻
+* ¶¨ÒåÒ»¸öĬÈÏ·½·¨£¨¼´Ã»ÓÐÉùÃ÷·¾¶Ó³É䣩£¬ÔÚÇëÇó·¾¶ÎÞ·¨±»Ó³Éäµ½¿ØÖÆÆ÷ϸü¾«È·µÄ·½·¨ÉÏȥʱ£¬Îª¸ÃÇëÇóÌṩĬÈÏ´¦Àí¡£ÔÚа汾ÖУ¬Èç¹ûÎÞ·¨ÎªÒ»¸öÇëÇóÕÒµ½ºÏÊʵĴ¦Àí·½·¨£¬ÄÇôһ¸ö404´íÎ󽫱»Å׳ö£»
+
+> [Original] The above features are still supported with the existing support classes. However to take advantage of new Spring MVC 3.1 features you¡¯ll need to use the new support classes.
+
+Èç¹ûʹÓÃÔÀ´µÄÀ࣬ÒÔÉϵŦÄÜ»¹ÊÇ¿ÉÒÔ×öµ½¡£µ«ÊÇ£¬Èç¹ûÒªÏíÊÜSpring MVC 3.1°æ±¾´øÀ´µÄ·½±ãÌØÐÔ£¬Äã¾ÍÐèҪȥʹÓÃеÄÀà¡£
+
+> [Original] ## URI Template Patterns
+
+## URIÄ£°å
+
+> [Original] URI templates can be used for convenient access to selected parts of a URL in a `@RequestMapping` method.
+
+URIÄ£°å¿ÉÒÔΪ¿ìËÙ·ÃÎÊ`@RequestMapping`ÖÐÖ¸¶¨µÄURLµÄÒ»¸öÌØ¶¨µÄ²¿·ÖÌṩºÜ´óµÄ±ãÀû¡£
+
+> [Original] A URI Template is a URI-like string, containing one or more variable names. When you substitute values for these variables, the template becomes a URI. The proposed RFC for URI Templates defines how a URI is parameterized. For example, the URI Template `http://www.example.com/users/{userId}` contains the variable userId. Assigning the value fred to the variable yields `http://www.example.com/users/fred`.
+
+URIÄ£°åÊÇÒ»¸öÀàËÆÓÚURIµÄ×Ö·û´®£¬Ö»²»¹ýÆäÖаüº¬ÁËÒ»¸ö»ò¶à¸öµÄ±äÁ¿Ãû¡£µ±ÄãʹÓÃʵ¼ÊµÄֵȥÌî³äÕâЩ±äÁ¿ÃûµÄʱºò£¬Ä£°å¾ÍÍË»¯³ÉÁËÒ»¸öURI¡£ÔÚURIÄ£°åµÄRFCÌáÒéÖж¨ÒåÁËÒ»¸öURIÊÇÈçºÎ½øÐвÎÊý»¯µÄ¡£±ÈÈç˵£¬Ò»¸öÕâ¸öURIÄ£°å`http://www.example.com/users/{userId}`¾Í°üº¬ÁËÒ»¸ö±äÁ¿Ãû_userId_¡£½«Öµ_fred_¸³¸øÕâ¸ö±äÁ¿Ãûºó£¬Ëü¾Í±ä³ÉÁËÒ»¸öURI£º`http://www.example.com/users/fred`¡£
+
+> [Original] In Spring MVC you can use the `@PathVariable` annotation on a method argument to bind it to the value of a URI template variable:
+
+ÔÚSpring MVCÖÐÄã¿ÉÒÔÔÚ·½·¨²ÎÊýÉÏʹÓÃ`@PathVariable`×¢½â£¬½«ÆäÓëURIÄ£°åÖеIJÎÊý°ó¶¨ÆðÀ´£º
+
+```
+@RequestMapping(path="/owners/{ownerId}", method=RequestMethod.GET)
+public String findOwner(@PathVariable String ownerId, Model model) {
+ Owner owner = ownerService.findOwner(ownerId);
+ model.addAttribute("owner", owner);
+ return "displayOwner";
+}
+
+```
+
+> [Original] The URI Template "`/owners/{ownerId}`" specifies the variable name `ownerId`. When the controller handles this request, the value of `ownerId` is set to the value found in the appropriate part of the URI. For example, when a request comes in for `/owners/fred`, the value of `ownerId` is `fred`.
+
+URIÄ£°å"`/owners/{ownerId}`"Ö¸¶¨ÁËÒ»¸ö±äÁ¿£¬ÃûΪ`ownerId`¡£µ±¿ØÖÆÆ÷´¦ÀíÕâ¸öÇëÇóµÄʱºò£¬`ownerId`µÄÖµ¾Í»á±»URIÄ£°åÖжÔÓ¦²¿·ÖµÄÖµËùÌî³ä¡£±ÈÈç˵£¬Èç¹ûÇëÇóµÄURIÊÇ`/owners/fred`£¬´Ëʱ±äÁ¿`ownerId`µÄÖµ¾ÍÊÇ`fred`. `
+
+> ΪÁË´¦Àí`@PathVariables`×¢½â£¬Spring MVC±ØÐëͨ¹ý±äÁ¿ÃûÀ´ÕÒµ½URIÄ£°åÖÐÏà¶ÔÓ¦µÄ±äÁ¿¡£Äã¿ÉÒÔÔÚ×¢½âÖÐÖ±½ÓÉùÃ÷£º
+>
+> ```
+> @RequestMapping(path="/owners/{ownerId}}", method=RequestMethod.GET)
+> public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {
+> // ¾ßÌåµÄ·½·¨´úÂë¡
+> }
+>
+> ```
+>
+> »òÕߣ¬Èç¹ûURIÄ£°åÖеıäÁ¿ÃûÓë·½·¨µÄ²ÎÊýÃûÊÇÏàͬµÄ£¬ÔòÄã¿ÉÒÔ²»±ØÔÙÖ¸¶¨Ò»´Î¡£Ö»ÒªÄãÔÚ±àÒëµÄʱºòÁôÏÂdebugÐÅÏ¢£¬Spring MVC¾Í¿ÉÒÔ×Ô¶¯Æ¥ÅäURLÄ£°åÖÐÓë·½·¨²ÎÊýÃûÏàͬµÄ±äÁ¿Ãû¡£
+>
+> ```
+> @RequestMapping(path="/owners/{ownerId}", method=RequestMethod.GET)
+> public String findOwner(@PathVariable String ownerId, Model model) {
+> // ¾ßÌåµÄ·½·¨´úÂë¡
+> }
+>
+> ```
+>
+> [Original] A method can have any number of `@PathVariable` annotations:
+
+Ò»¸ö·½·¨¿ÉÒÔÓµÓÐÈÎÒâÊýÁ¿µÄ`@PathVariable`×¢½â£º
+
+```
+@RequestMapping(path="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET)
+public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
+ Owner owner = ownerService.findOwner(ownerId);
+ Pet pet = owner.getPet(petId);
+ model.addAttribute("pet", pet);
+ return "displayPet";
+}
+
+```
+
+> [Original] When a `@PathVariable` annotation is used on a `Map` argument, the map is populated with all URI template variables.
+
+µ±`@PathVariable`×¢½â±»Ó¦ÓÃÓÚ`Map`ÀàÐ͵IJÎÊýÉÏʱ£¬¿ò¼Ü»áʹÓÃËùÓÐURIÄ£°å±äÁ¿À´Ìî³äÕâ¸ömap¡£
+
+> [Original] A URI template can be assembled from type and path level _@RequestMapping_ annotations. As a result the `findPet()` method can be invoked with a URL such as `/owners/42/pets/21`.
+
+URIÄ£°å¿ÉÒÔ´ÓÀ༶±ðºÍ·½·¨¼¶±ðµÄ _@RequestMapping_ ×¢½â»ñÈ¡Êý¾Ý¡£Òò´Ë£¬ÏñÕâÑùµÄ`findPet()`·½·¨¿ÉÒÔ±»ÀàËÆÓÚ`/owners/42/pets/21`ÕâÑùµÄURL·Óɲ¢µ÷Óõ½£º
+
+```
+_@Controller_
+@RequestMapping("/owners/{ownerId}")
+public class RelativePathUriTemplateController {
+
+ @RequestMapping("/pets/{petId}")
+ public void findPet(_@PathVariable_ String ownerId, _@PathVariable_ String petId, Model model) {
+ // ·½·¨ÊµÏÖÌåÕâÀïºöÂÔ
+ }
+
+}
+
+```
+
+> [Original] A `@PathVariable` argument can be of _any simple type_ such as int, long, Date, etc. Spring automatically converts to the appropriate type or throws a `TypeMismatchException` if it fails to do so. You can also register support for parsing additional data types. See [the section called "Method Parameters And Type Conversion"](https://linesh.gitbooks.io/spring-mvc-documentation-linesh-translation/content/publish/21-3/mvc.html#mvc-ann-typeconversion) and [the section called "Customizing WebDataBinder initialization"](https://linesh.gitbooks.io/spring-mvc-documentation-linesh-translation/content/publish/21-3/mvc.html#mvc-ann-webdatabinder).
+
+`@PathVariable`¿ÉÒÔ±»Ó¦ÓÃÓÚËùÓÐ _¼òµ¥ÀàÐÍ_ µÄ²ÎÊýÉÏ£¬±ÈÈçint¡¢long¡¢DateµÈÀàÐÍ¡£Spring»á×Ô¶¯µØ°ïÄã°Ñ²ÎÊýת»¯³ÉºÏÊʵÄÀàÐÍ£¬Èç¹ûת»»Ê§°Ü£¬¾ÍÅ׳öÒ»¸ö`TypeMismatchException`¡£Èç¹ûÄãÐèÒª´¦ÀíÆäËûÊý¾ÝÀàÐ͵Äת»»£¬Ò²¿ÉÒÔ×¢²á×Ô¼ºµÄÀà¡£ÈôÐèÒª¸üÏêϸµÄÐÅÏ¢¿ÉÒԲο¼[¡°·½·¨²ÎÊýÓëÀàÐÍת»»¡±Ò»½Ú](http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-typeconversion)ºÍ[¡°¶¨ÖÆWebDataBinder³õʼ»¯¹ý³Ì¡±Ò»½Ú](http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-webdatabinder)
+
+## ´øÕýÔò±í´ïʽµÄURIÄ£°å
+
+> [Original] Sometimes you need more precision in defining URI template variables. Consider the URL `"/spring-web/spring-web-3.0.5.jar"`. How do you break it down into multiple parts?
+
+ÓÐʱºòÄã¿ÉÄÜÐèÒª¸ü׼ȷµØÃèÊöÒ»¸öURIÄ£°åµÄ±äÁ¿£¬±ÈÈç˵Õâ¸öURL£º`"/spring-web/spring-web-3.0.5.jar`¡£ÄãÒªÔõô°ÑËü·Ö½â³É¼¸¸öÓÐÒâÒåµÄ²¿·ÖÄØ£¿
+
+> [Original] The `@RequestMapping` annotation supports the use of regular expressions in URI template variables. The syntax is `{varName:regex}` where the first part defines the variable name and the second - the regular expression.For example:
+
+`@RequestMapping`×¢½âÖ§³ÖÄãÔÚURIÄ£°å±äÁ¿ÖÐʹÓÃÕýÔò±í´ïʽ¡£Óï·¨ÊÇ`{varName:regex}`£¬ÆäÖеÚÒ»²¿·Ö¶¨ÒåÁ˱äÁ¿Ãû£¬µÚ¶þ²¿·Ö¾ÍÊÇÄãËùÒªÓ¦ÓõÄÕýÔò±í´ïʽ¡£±ÈÈçÏÂÃæµÄ´úÂëÑùÀý£º
+
+```
+@RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]+}")
+ public void handle(@PathVariable String version, @PathVariable String extension) {
+ // ´úÂ벿·ÖÊ¡ÂÔ...
+ }
+}
+
+```
+
+## Path Patterns£¨²»ºÃ·£¬ÈÝÒ×µôÔÏ棩
+
+> [Original] In addition to URI templates, the `@RequestMapping` annotation also supports Ant-style path patterns (for example, `/myPath/*.do`). A combination of URI template variables and Ant-style globs is also supported (e.g. `/owners/*/pets/{petId}`).
+
+³ýÁËURIÄ£°åÍ⣬`@RequestMapping`×¢½â»¹Ö§³ÖAnt·ç¸ñµÄ·¾¶Ä£Ê½£¨Èç`/myPath/*.do`µÈ£©¡£²»½öÈç´Ë£¬»¹¿ÉÒÔ°ÑURIÄ£°å±äÁ¿ºÍAnt·ç¸ñµÄglob×éºÏÆðÀ´Ê¹Ó㨱ÈÈç`/owners/*/pets/{petId}`ÕâÑùµÄÓ÷¨µÈ£©¡£
+
+## ·¾¶ÑùʽµÄÆ¥Åä(Path Pattern Comparison)
+
+> [Original] When a URL matches multiple patterns, a sort is used to find the most specific match.
+
+µ±Ò»¸öURLͬʱƥÅä¶à¸öÄ£°å£¨pattern£©Ê±£¬ÎÒÃǽ«ÐèÒªÒ»¸öËã·¨À´¾ö¶¨ÆäÖÐ×îÆ¥ÅäµÄÒ»¸ö¡£
+
+> [Original] A pattern with a lower count of URI variables and wild cards is considered more specific. For example `/hotels/{hotel}/*` has 1 URI variable and 1 wild card and is considered more specific than `/hotels/{hotel}/**` which as 1 URI variable and 2 wild cards.
+
+URIÄ£°å±äÁ¿µÄÊýÄ¿ºÍͨÅä·ûÊýÁ¿µÄ×ܺÍ×îÉÙµÄÄǸö·¾¶Ä£°å¸ü׼ȷ¡£¾Ù¸öÀý×Ó£¬`/hotels/{hotel}/*`Õâ¸ö·¾¶ÓµÓÐÒ»¸öURI±äÁ¿ºÍÒ»¸öͨÅä·û£¬¶ø`/hotels/{hotel}/**`Õâ¸ö·¾¶ÔòÓµÓÐÒ»¸öURI±äÁ¿ºÍÁ½¸öͨÅä·û£¬Òò´Ë£¬ÎÒÃÇÈÏΪǰÕßÊǸü׼ȷµÄ·¾¶Ä£°å¡£
+
+> [Original] If two patterns have the same count, the one that is longer is considered more specific. For example `/foo/bar*` is longer and considered more specific than `/foo/*`.
+
+Èç¹ûÁ½¸öÄ£°åµÄURIÄ£°åÊýÁ¿ºÍͨÅä·ûÊýÁ¿×ܺÍÒ»Ö£¬Ôò·¾¶¸ü³¤µÄÄǸöÄ£°å¸ü׼ȷ¡£¾Ù¸öÀý×Ó£¬`/foo/bar*`¾Í±»ÈÏΪ±È`/foo/*`¸ü׼ȷ£¬ÒòΪǰÕߵķ¾¶¸ü³¤¡£
+
+> [Original] When two patterns have the same count and length, the pattern with fewer wild cards is considered more specific. For example `/hotels/{hotel}` is more specific than `/hotels/*`.
+
+Èç¹ûÁ½¸öÄ£°åµÄÊýÁ¿ºÍ³¤¶È¾ùÒ»Ö£¬ÔòÄǸö¾ßÓиüÉÙͨÅä·ûµÄÄ£°åÊǸü¼Ó׼ȷµÄ¡£±ÈÈ磬`/hotels/{hotel}`¾Í±È`/hotels/*`¸ü¾«È·¡£
+
+> [Original] There are also some additional special rules:
+
+³ý´ËÖ®Í⣬»¹ÓÐһЩÆäËûµÄ¹æÔò£º
+
+> [Original] _The **default mapping pattern** `/*_`is less specific than any other pattern. For example`/api/{a}/{b}/{c}` is more specific.
+>
+> [Original] _A **prefix pattern** such as `/public/*_`is less specific than any other pattern that doesn't contain double wildcards. For example`/public/path3/{a}/{b}/{c}` is more specific.
+
+* **ĬÈϵÄͨÅäģʽ**`/**`±ÈÆäËûËùÓеÄģʽ¶¼¸ü¡°²»×¼È·¡±¡£±È·½Ëµ£¬`/api/{a}/{b}/{c}`¾Í±ÈĬÈϵÄͨÅäģʽ`/**`Òª¸ü׼ȷ
+* **ǰ׺ͨÅä**£¨±ÈÈç`/public/**`)±»ÈÏΪ±ÈÆäËûÈκβ»°üÀ¨Ë«Í¨Åä·ûµÄģʽ¸ü²»×¼È·¡£±ÈÈç˵£¬`/public/path3/{a}/{b}/{c}`¾Í±È`/public/**`¸ü׼ȷ
+
+> [Original] For the full details see `AntPatternComparator` in `AntPathMatcher`. Note that the PathMatcher can be customized (see [Section 21.16.11, "Path Matching"](https://linesh.gitbooks.io/spring-mvc-documentation-linesh-translation/content/publish/21-3/mvc.html#mvc-config-path-matching) in the section on configuring Spring MVC).
+
+¸ü¶àµÄϸ½ÚÇë²Î¿¼ÕâÁ½¸öÀࣺ`AntPatternComparator`ºÍ`AntPathMatcher`¡£ÖµµÃÒ»ÌáµÄÊÇ£¬PathMatcherÀàÊÇ¿ÉÒÔÅäÖõ썼û¡°ÅäÖÃSpring MVC¡±Ò»½ÚÖеÄ[·¾¶µÄÆ¥Åä](https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/spring_mvc_documentation_linesh_translation-cgvo27t2.html)Ò»½Ú)¡£
+
+## ´øÕ¼Î»·ûµÄ·¾¶Ä£Ê½£¨path patterns£©
+
+> [Original] Patterns in `@RequestMapping` annotations support ${¡} placeholders against local properties and/or system properties and environment variables. This may be useful in cases where the path a controller is mapped to may need to be customized through configuration. For more information on placeholders, see the javadocs of the `PropertyPlaceholderConfigurer` class.
+
+`@RequestMapping`×¢½âÖ§³ÖÔÚ·¾¶ÖÐʹÓÃռλ·û£¬ÒÔÈ¡µÃһЩ±¾µØÅäÖá¢ÏµÍ³ÅäÖᢻ·¾³±äÁ¿µÈ¡£Õâ¸öÌØÐÔÓÐʱºÜÓÐÓ㬱ÈÈç˵¿ØÖÆÆ÷µÄÓ³Éä·¾¶ÐèҪͨ¹ýÅäÖÃÀ´¶¨ÖƵij¡¾°¡£Èç¹ûÏëÁ˽â¸ü¶à¹ØÓÚռλ·ûµÄÐÅÏ¢£¬¿ÉÒԲο¼`PropertyPlaceholderConfigurer`Õâ¸öÀàµÄÎĵµ¡£
+
+## Suffix Pattern Matching
+
+## ºó׺ģʽƥÅä
+
+> [Original] By default Spring MVC performs `".*"` suffix pattern matching so that a controller mapped to `/person` is also implicitly mapped to `/person.*`. This makes it easy to request different representations of a resource through the URL path (e.g. `/person.pdf`, `/person.xml`).
+
+Spring MVCĬÈϲÉÓÃ`".*"`µÄºó׺ģʽƥÅäÀ´½øÐз¾¶Æ¥Å䣬Òò´Ë£¬Ò»¸öÓ³Éäµ½`/person`·¾¶µÄ¿ØÖÆÆ÷Ò²»áÒþʽµØ±»Ó³Éäµ½`/person.*`¡£ÕâʹµÃͨ¹ýURLÀ´ÇëÇóͬһ×ÊÔ´ÎļþµÄ²»Í¬¸ñʽ±äµÃ¸ü¼òµ¥£¨±ÈÈç`/person.pdf`£¬`/person.xml`£©¡£
+
+> [Original] Suffix pattern matching can be turned off or restricted to a set of path extensions explicitly registered for content negotiation purposes. This is generally recommended to minimize ambiguity with common request mappings such as `/person/{id}` where a dot might not represent a file extension, e.g. `/person/joe@email.com` vs `/person/joe@email.com.json)`. Furthermore as explained in the note below suffix pattern matching as well as content negotiation may be used in some circumstances to attempt malicious attacks and there are good reasons to restrict them meaningfully.
+
+Äã¿ÉÒԹرÕĬÈϵĺó׺ģʽƥÅ䣬»òÕßÏÔʽµØ½«Â·¾¶ºó׺ÏÞ¶¨µ½Ò»Ð©Ìض¨¸ñʽÉÏfor content negotiation purpose¡£ÎÒÃÇÍÆ¼öÕâÑù×ö£¬ÕâÑù¿ÉÒÔ¼õÉÙÓ³ÉäÇëÇóʱ¿ÉÒÔ´øÀ´µÄһЩ¶þÒåÐÔ£¬±ÈÈçÇëÇóÒÔÏ·¾¶`/person/{id}`ʱ£¬Â·¾¶ÖеĵãºÅºóÃæ´øµÄ¿ÉÄܲ»ÊÇÃèÊöÄÚÈݸñʽ£¬±ÈÈç`/person/joe@email.com` vs `/person/joe@email.com.json`¡£¶øÇÒÕýÈçÏÂÃæÂíÉÏÒªÌáµ½µÄ£¬ºó׺ģʽͨÅäÒÔ¼°ÄÚÈÝÐÉÌÓÐʱ¿ÉÄܻᱻºÚ¿ÍÓÃÀ´½øÐй¥»÷£¬Òò´Ë£¬¶Ôºó׺ͨÅä½øÐÐÓÐÒâÒåµÄÏÞ¶¨ÊÇÓкô¦µÄ¡£
+
+> [Original] See [Section 21.16.11, "Path Matching"](https://linesh.gitbooks.io/spring-mvc-documentation-linesh-translation/content/publish/21-3/mvc.html#mvc-config-path-matching) for suffix pattern matching configuration and also [Section 21.16.6, "Content Negotiation"](https://linesh.gitbooks.io/spring-mvc-documentation-linesh-translation/content/publish/21-3/mvc.html#mvc-config-content-negotiation) for content negotiation configuration.
+
+¹ØÓÚºó׺ģʽƥÅäµÄÅäÖÃÎÊÌ⣬¿ÉÒԲο¼[Spring MVC·¾¶Æ¥ÅäÅäÖÃ](https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/spring_mvc_documentation_linesh_translation-cgvo27t2.html)£»¹ØÓÚÄÚÈÝÐÉ̵ÄÅäÖÃÎÊÌ⣬¿ÉÒԲο¼[Spring MVC ÄÚÈÝÐÉÌ"](https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/spring_mvc_documentation_linesh_translation-h8br27sx.html)µÄÄÚÈÝ¡£
+
+## ºó׺ģʽƥÅäÓëRFD
+
+> [Original] Reflected file download (RFD) attack was first described in a [paper by Trustwave](https://www.trustwave.com/Resources/SpiderLabs-Blog/Reflected-File-Download---A-New-Web-Attack-Vector/) in 2014\. The attack is similar to XSS in that it relies on input (e.g. query parameter, URI variable) being reflected in the response. However instead of inserting JavaScript into HTML, an RFD attack relies on the browser switching to perform a download and treating the response as an executable script if double-clicked based on the file extension (e.g. .bat, .cmd).
+
+RFD(Reflected file download)¹¥»÷×îÏÈÊÇ2014ÄêÔÚ[TrustwaveµÄһƪÂÛÎÄ](https://www.trustwave.com/Resources/SpiderLabs-Blog/Reflected-File-Download---A-New-Web-Attack-Vector/)Öб»Ìá³öµÄ¡£ËüÓëXSS¹¥»÷ÓÐЩÏàËÆ£¬ÒòΪÕâÖÖ¹¥»÷·½Ê½Ò²ÒÀÀµÓÚÄ³Ð©ÌØÕ÷£¬¼´ÐèÒªÄãµÄÊäÈ루±ÈÈç²éѯ²ÎÊý£¬URI±äÁ¿µÈ£©µÈÒ²ÔÚÊä³ö£¨response£©ÖÐÒÔijÖÖÐÎʽ³öÏÖ¡£²»Í¬µÄÊÇ£¬RFD¹¥»÷²¢²»ÊÇͨ¹ýÔÚHTMLÖÐдÈëJavaScript´úÂë½øÐУ¬¶øÊÇÒÀÀµÓÚä¯ÀÀÆ÷À´Ìø×ªµ½ÏÂÔØÒ³Ãæ£¬²¢°ÑÌØ¶¨¸ñʽ£¨±ÈÈç.bat£¬.cmdµÈ£©µÄresponseµ±³ÉÊÇ¿ÉÖ´Ðнű¾£¬Ë«»÷Ëü¾Í»áÖ´ÐС£
+
+> [Original] In Spring MVC `@ResponseBody` and `ResponseEntity` methods are at risk because they can render different content types which clients can request including via URL path extensions. Note however that neither disabling suffix pattern matching nor disabling the use of path extensions for content negotiation purposes alone are effective at preventing RFD attacks.
+
+Spring MVCµÄ`@ResponseBody`ºÍ`ResponseEntity`·½·¨ÊÇÓзçÏյģ¬ÒòΪËüÃÇ»á¸ù¾Ý¿Í»§µÄÇëÇ󡪡ª°üÀ¨URLµÄ·¾¶ºó׺£¬À´äÖȾ²»Í¬µÄÄÚÈÝÀàÐÍ¡£Òò´Ë£¬½ûÓúó׺ģʽƥÅä»òÕß½ûÓýöΪÄÚÈÝÐÉÌ¿ªÆôµÄ·¾¶Îļþºó׺ÃûЯ´ø£¬¶¼ÊÇ·À·¶RFD¹¥»÷µÄÓÐЧ·½Ê½¡£
+
+> [Original] For comprehensive protection against RFD, prior to rendering the response body Spring MVC adds a `Content-Disposition:inline;filename=f.txt` header to suggest a fixed and safe download file filename. This is done only if the URL path contains a file extension that is neither whitelisted nor explicitly registered for content negotiation purposes. However it may potentially have side effects when URLs are typed directly into a browser.
+
+ÈôÒª¿ªÆô¶ÔRFD¸ü¸ß¼¶µÄ±£»¤Ä£Ê½£¬¿ÉÒÔÔÚSpring MVCäÖȾ¿ªÊ¼ÇëÇóÕýÎÄ֮ǰ£¬ÔÚÇëÇóÍ·ÖÐÔö¼ÓÒ»ÐÐÅäÖÃ`Content-Disposition:inline;filename=f.txt`£¬Ö¸¶¨¹Ì¶¨µÄÏÂÔØÎļþµÄÎļþÃû¡£Õâ½öÔÚURL·¾¶Öаüº¬ÁËÒ»¸öÎļþ·ûºÏÒÔÏÂÌØÕ÷µÄÍØÕ¹ÃûʱÊÊÓ㺸ÃÀ©Õ¹Ãû¼È²»ÔÚÐÅÈÎÁÐ±í£¨°×Ãûµ¥£©ÖУ¬Ò²Ã»Óб»ÏÔʽµØ±»×¢²áÓÚÄÚÈÝÐÉÌʱʹÓᣲ¢ÇÒÕâÖÖ×ö·¨»¹¿ÉÒÔÓÐһЩ¸±×÷Ó㬱ÈÈ磬µ±URLÊÇͨ¹ýä¯ÀÀÆ÷ÊÖ¶¯ÊäÈëµÄʱºò¡£
+
+> [Original] Many common path extensions are whitelisted by default. Furthermore REST API calls are typically not meant to be used as URLs directly in browsers. Nevertheless applications that use custom `HttpMessageConverter` implementations can explicitly register file extensions for content negotiation and the Content-Disposition header will not be added for such extensions. See [Section 21.16.6, "Content Negotiation"](https://linesh.gitbooks.io/spring-mvc-documentation-linesh-translation/content/publish/21-3/mvc.html#mvc-config-content-negotiation).
+
+ºÜ¶à³£ÓõÄ·¾¶Îļþºó׺ĬÈÏÊDZ»ÐÅÈεġ£ÁíÍ⣬RESTµÄAPIÒ»°ãÊDz»Ó¦¸ÃÖ±½ÓÓÃ×öURLµÄ¡£²»¹ý£¬Äã¿ÉÒÔ×Ô¼º¶¨ÖÆ`HttpMessageConverter`µÄʵÏÖ£¬È»ºóÏÔʽµØ×¢²áÓÃÓÚÄÚÈÝÐÉ̵ÄÎļþÀàÐÍ£¬ÕâÖÖÇéÐÎÏÂContent-DispositionÍ·½«²»»á±»¼ÓÈëµ½ÇëÇóÍ·ÖС£Ïê¼û[Spring MVC ÄÚÈÝÐÉÌ](https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/spring_mvc_documentation_linesh_translation-h8br27sx.html)¡£
+
+> [Original] This was originally introduced as part of work for [CVE-2015-5211](http://pivotal.io/security/cve-2015-5211). Below are additional recommendations from the report:
+>
+> * Encode rather than escape JSON responses. This is also an OWASP XSS recommendation. For an example of how to do that with Spring see [spring-jackson-owasp](https://github.com/rwinch/spring-jackson-owasp).
+> * Configure suffix pattern matching to be turned off or restricted to explicitly registered suffixes only.
+> * Configure content negotiation with the properties "useJaf" and "ignoreUnknownPathExtensions" set to false which would result in a 406 response for URLs with unknown extensions. Note however that this may not be an option if URLs are naturally expected to have a dot towards the end.
+> * Add `X-Content-Type-Options: nosniff` header to responses. Spring Security 4 does this by default.
+
+¸Ð¾õÕâ½ÚµÄ·ÒëÖÊÁ¿»¹ÓÐÏÞ£¬ÐèÒª¼ÌÐøÁ˽âXSS¹¥»÷ºÍRFD¹¥»÷µÄϸ½ÚÔÙ·¡£
+
+## ¾ØÕó±äÁ¿
+
+> [Original] The URI specification [RFC 3986](http://tools.ietf.org/html/rfc3986#section-3.3) defines the possibility of including name-value pairs within path segments. There is no specific term used in the spec. The general "URI path parameters" could be applied although the more unique ["Matrix URIs"](http://www.w3.org/DesignIssues/MatrixURIs.html), originating from an old post by Tim Berners-Lee, is also frequently used and fairly well known. Within Spring MVC these are referred to as matrix variables.
+
+ÔÀ´µÄURI¹æ·¶[RFC 3986](http://tools.ietf.org/html/rfc3986#section-3.3)ÖÐÔÊÐíÔÚ·¾¶¶ÎÂäÖÐЯ´ø¼üÖµ¶Ô£¬µ«¹æ·¶Ã»ÓÐÃ÷È·¸øÕâÑùµÄ¼üÖµ¶Ô¶¨ÒåÊõÓï¡£ÓÐÈ˽С°URI·¾¶²ÎÊý¡±£¬Ò²ÓнÐ[¡°¾ØÕóURI¡±](http://www.w3.org/DesignIssues/MatrixURIs.html)µÄ¡£ºóÕßÊÇTim Berners-LeeÊ×ÏÈÔÚÆä²©¿ÍÖÐÌáµ½µÄÊõÓ±»Ê¹ÓõÃÒª¸ü¼ÓƵ·±Ò»Ð©£¬ÖªÃû¶ÈÒ²¸ü¸ßЩ¡£¶øÔÚSpring MVCÖУ¬ÎÒÃdzÆÕâÑùµÄ¼üÖµ¶ÔΪ¾ØÕó±äÁ¿¡£
+
+> [Original] Matrix variables can appear in any path segment, each matrix variable separated with a ";" (semicolon). For example: `"/cars;color=red;year=2012"`. Multiple values may be either "," (comma) separated `"color=red,green,blue"` or the variable name may be repeated `"color=red;color=green;color=blue"`.
+
+¾ØÕó±äÁ¿¿ÉÒÔÔÚÈκη¾¶¶ÎÂäÖгöÏÖ£¬Ã¿¶Ô¾ØÕó±äÁ¿Ö®¼äʹÓÃÒ»¸ö·ÖºÅ¡°;¡±¸ô¿ª¡£±ÈÈçÕâÑùµÄURI£º`"/cars;color=red;year=2012"`¡£¶à¸öÖµ¿ÉÒÔÓöººÅ¸ô¿ª`"color=red,green,blue"`£¬»òÕßÖØ¸´±äÁ¿Ãû¶à´Î`"color=red;color=green;color=blue"`¡£
+
+> [Original] If a URL is expected to contain matrix variables, the request mapping pattern must represent them with a URI template. This ensures the request can be matched correctly regardless of whether matrix variables are present or not and in what order they are provided.
+
+Èç¹ûÒ»¸öURLÓпÉÄÜÐèÒª°üº¬¾ØÕó±äÁ¿£¬ÄÇôÔÚÇëÇó·¾¶µÄÓ³ÉäÅäÖÃÉϾÍÐèҪʹÓÃURIÄ£°åÀ´ÌåÏÖÕâÒ»µã¡£ÕâÑù²ÅÄÜÈ·±£ÇëÇó¿ÉÒÔ±»ÕýÈ·µØÓ³É䣬¶ø²»¹Ü¾ØÕó±äÁ¿ÔÚURIÖÐÊÇ·ñ³öÏÖ¡¢³öÏֵĴÎÐòÊÇÔõÑùµÈ¡£
+
+> [Original] Below is an example of extracting the matrix variable "q":
+
+ÏÂÃæÊÇÒ»¸öÀý×Ó£¬Õ¹Ê¾ÁËÎÒÃÇÈçºÎ´Ó¾ØÕó±äÁ¿ÖлñÈ¡µ½±äÁ¿¡°q¡±µÄÖµ£º
+
+```
+// GET /pets/42;q=11;r=22
+
+@RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET)
+public void findPet(@PathVariable String petId, @MatrixVariable int q) {
+
+ // petId == 42
+ // q == 11
+
+}
+
+```
+
+> [Original] Since all path segments may contain matrix variables, in some cases you need to be more specific to identify where the variable is expected to be:
+
+ÓÉÓÚÈÎÒâ·¾¶¶ÎÂäÖж¼¿ÉÒÔº¬ÓоØÕó±äÁ¿£¬ÔÚijЩ³¡¾°Ï£¬ÄãÐèÒªÓøü¾«È·µÄÐÅÏ¢À´Ö¸¶¨Ò»¸ö¾ØÕó±äÁ¿µÄλÖãº
+
+```
+// GET /owners/42;q=11/pets/21;q=22
+
+@RequestMapping(path = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)
+public void findPet(
+ @MatrixVariable(name="q", pathVar="ownerId") int q1,
+ @MatrixVariable(name="q", pathVar="petId") int q2) {
+
+ // q1 == 11
+ // q2 == 22
+
+}
+
+```
+
+> [Original] A matrix variable may be defined as optional and a default value specified:
+
+ÄãÒ²¿ÉÒÔÉùÃ÷Ò»¸ö¾ØÕó±äÁ¿²»ÊDZØÐë³öÏֵ쬲¢¸øËü¸³Ò»¸öĬÈÏÖµ£º
+
+```
+// GET /pets/42
+
+@RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET)
+public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {
+
+ // q == 1
+
+}
+
+```
+
+> [Original] All matrix variables may be obtained in a Map:
+
+Ò²¿ÉÒÔͨ¹ýÒ»¸öMapÀ´´æ´¢ËùÓеľØÕó±äÁ¿£º
+
+```
+// GET /owners/42;q=11;r=12/pets/21;q=22;s=23
+
+@RequestMapping(path = "/owners/{ownerId}/pets/{petId}", method = RequestMethod.GET)
+public void findPet(
+ @MatrixVariable Map matrixVars,
+ @MatrixVariable(pathVar="petId") Map petMatrixVars) {
+
+ // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
+ // petMatrixVars: ["q" : 11, "s" : 23]
+
+}
+
+```
+
+> [Original] Note that to enable the use of matrix variables, you must set the `removeSemicolonContent`property of `RequestMappingHandlerMapping` to `false`. By default it is set to `true`.
+
+Èç¹ûÒªÔÊÐí¾ØÕó±äÁ¿µÄʹÓã¬Äã±ØÐë°Ñ`RequestMappingHandlerMapping`ÀàµÄ`removeSemicolonContent`ÊôÐÔÉèÖÃΪ`false`¡£¸ÃֵĬÈÏÊÇ`true`µÄ¡£
+
+> [Original] The MVC Java config and the MVC namespace both provide options for enabling the use of matrix variables.
+>
+> MVCµÄJava±à³ÌÅäÖúÍÃüÃû¿Õ¼äÅäÖö¼ÌṩÁËÆôÓþØÕó±äÁ¿µÄ·½Ê½¡£
+>
+> [Original] If you are using Java config, The [Advanced Customizations with MVC Java Config](https://linesh.gitbooks.io/spring-mvc-documentation-linesh-translation/content/publish/21-3/mvc.html#mvc-config-advanced-java) section describes how the `RequestMappingHandlerMapping` can be customized.
+>
+> Èç¹ûÄãÊÇʹÓÃJava±à³ÌµÄ·½Ê½£¬[¡°MVC Java¸ß¼¶¶¨ÖÆ»¯ÅäÖá±Ò»½Ú](http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/mvc.html#mvc-config-advanced-java)ÃèÊöÁËÈçºÎ¶Ô`RequestMappingHandlerMapping`½øÐж¨ÖÆ¡£
+>
+> [Original] In the MVC namespace, the `` element has an `enable-matrix-variables` attribute that should be set to `true`. By default it is set to `false`.
+>
+> ¶øÊ¹ÓÃMVCµÄÃüÃû¿Õ¼äÅäÖÃʱ£¬Äã¿ÉÒÔ°Ñ``ÔªËØÏµÄ`enable-matrix-variables`ÊôÐÔÉèÖÃΪ`true`¡£¸ÃֵĬÈÏÇé¿öÏÂÊÇÅäÖÃΪ`false`µÄ¡£
+
+```
+
+
+
+
+
+
+
+```
+
+## ¿ÉÏû·ÑµÄýÌåÀàÐÍ
+
+> [Original] You can narrow the primary mapping by specifying a list of consumable media types. The request will be matched only if the _Content-Type_ request header matches the specified media type. For example:
+
+Äã¿ÉÒÔÖ¸¶¨Ò»×é¿ÉÏû·ÑµÄýÌåÀàÐÍ£¬ËõСӳÉäµÄ·¶Î§¡£ÕâÑùÖ»Óе±ÇëÇóÍ·ÖÐ _Content-Type_ µÄÖµÓëÖ¸¶¨¿ÉÏû·ÑµÄýÌåÀàÐÍÖÐÓÐÏàͬµÄʱºò£¬ÇëÇó²Å»á±»Æ¥Åä¡£±ÈÈçÏÂÃæÕâ¸öÀý×Ó£º
+
+```
+@Controller
+@RequestMapping(path = "/pets", method = RequestMethod.POST, consumes="application/json")
+public void addPet(@RequestBody Pet pet, Model model) {
+ // ·½·¨ÊµÏÖÊ¡ÂÔ
+}
+
+```
+
+> [Original] Consumable media type expressions can also be negated as in _!text/plain_ to match to all requests other than those with _Content-Type_ of _text/plain_. Also consider using constants provided in `MediaType` such as `APPLICATION_JSON_VALUE` and `APPLICATION_JSON_UTF8_VALUE`.
+
+Ö¸¶¨¿ÉÏû·ÑýÌåÀàÐ͵ıí´ïʽÖл¹¿ÉÒÔʹÓ÷ñ¶¨£¬±ÈÈ磬¿ÉÒÔʹÓà _!text/plain_ À´Æ¥ÅäËùÓÐÇëÇóÍ· _Content-Type_ Öв»º¬ _text/plain_ µÄÇëÇó¡£Í¬Ê±£¬ÔÚ`MediaType`ÀàÖл¹¶¨ÒåÁËһЩ³£Á¿£¬±ÈÈç`APPLICATION_JSON_VALUE`¡¢`APPLICATION_JSON_UTF8_VALUE`µÈ£¬ÍƼö¸ü¶àµØÊ¹ÓÃËüÃÇ¡£
+
+> [Original] The _consumes_ condition is supported on the type and on the method level. Unlike most other conditions, when used at the type level, method-level consumable types override rather than extend type-level consumable types.
+>
+> _consumes_ ÊôÐÔÌṩµÄÊÇ·½·¨¼¶µÄÀàÐÍÖ§³Ö¡£ÓëÆäËûÊôÐÔ²»Í¬£¬µ±ÔÚÀàÐͼ¶Ê¹ÓÃʱ£¬·½·¨¼¶µÄÏû·ÑÀàÐͽ«¸²¸ÇÀàÐͼ¶µÄÅäÖ㬶ø·Ç¼Ì³Ð¹ØÏµ¡£
+
+## ¿ÉÉú²úµÄýÌåÀàÐÍ
+
+> [Original] You can narrow the primary mapping by specifying a list of producible media types. The request will be matched only if the _Accept_ request header matches one of these values. Furthermore, use of the _produces_ condition ensures the actual content type used to generate the response respects the media types specified in the _produces_ condition. For example:
+
+Äã¿ÉÒÔÖ¸¶¨Ò»×é¿ÉÉú²úµÄýÌåÀàÐÍ£¬ËõСӳÉäµÄ·¶Î§¡£ÕâÑùÖ»Óе±ÇëÇóÍ·ÖÐ _Accept_ µÄÖµÓëÖ¸¶¨¿ÉÉú²úµÄýÌåÀàÐÍÖÐÓÐÏàͬµÄʱºò£¬ÇëÇó²Å»á±»Æ¥Åä¡£¶øÇÒ£¬Ê¹Óà _produces_ Ìõ¼þ¿ÉÒÔÈ·±£ÓÃÓÚÉú³ÉÏìÓ¦£¨response£©µÄÄÚÈÝÓëÖ¸¶¨µÄ¿ÉÉú²úµÄýÌåÀàÐÍÊÇÏàͬµÄ¡£¾Ù¸öÀý×Ó£º
+
+```
+@Controller
+@RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+@ResponseBody
+public Pet getPet(@PathVariable String petId, Model model) {
+ // ·½·¨ÊµÏÖÊ¡ÂÔ
+}
+
+```
+
+> [Original] Be aware that the media type specified in the _produces_ condition can also optionally specify a character set. For example, in the code snippet above we specify the same media type than the default one configured in `MappingJackson2HttpMessageConverter`, including the `UTF-8`charset.
+>
+> ҪעÒâµÄÊÇ£¬Í¨¹ý _condition_ Ìõ¼þÖ¸¶¨µÄýÌåÀàÐÍÒ²¿ÉÒÔÖ¸¶¨×Ö·û¼¯¡£±ÈÈçÔÚÉÏÃæµÄС¶Î´úÂëÖУ¬ÎÒÃÇ»¹ÊǸ²Ð´ÁË`MappingJackson2HttpMessageConverter`ÀàÖÐĬÈÏÅäÖõÄýÌåÀàÐÍ£¬Í¬Ê±£¬»¹Ö¸¶¨ÁËʹÓÃ`UTF-8`µÄ×Ö·û¼¯¡£
+>
+> [Original] Just like with _consumes_, producible media type expressions can be negated as in _!text/plain_ to match to all requests other than those with an _Accept_ header value of _text/plain_. Also consider using constants provided in `MediaType` such as `APPLICATION_JSON_VALUE` and `APPLICATION_JSON_UTF8_VALUE`.
+
+Óë _consumes_ Ìõ¼þÀàËÆ£¬¿ÉÉú²úµÄýÌåÀàÐͱí´ïʽҲ¿ÉÒÔʹÓ÷ñ¶¨¡£±ÈÈ磬¿ÉÒÔʹÓà _!text/plain_ À´Æ¥ÅäËùÓÐÇëÇóÍ· _Accept_ Öв»º¬ _text/plain_ µÄÇëÇó¡£Í¬Ê±£¬ÔÚ`MediaType`ÀàÖл¹¶¨ÒåÁËһЩ³£Á¿£¬±ÈÈç`APPLICATION_JSON_VALUE`¡¢`APPLICATION_JSON_UTF8_VALUE`µÈ£¬ÍƼö¸ü¶àµØÊ¹ÓÃËüÃÇ¡£
+
+> [Original] The _produces_ condition is supported on the type and on the method level. Unlike most other conditions, when used at the type level, method-level producible types override rather than extend type-level producible types.
+>
+> _produces_ ÊôÐÔÌṩµÄÊÇ·½·¨¼¶µÄÀàÐÍÖ§³Ö¡£ÓëÆäËûÊôÐÔ²»Í¬£¬µ±ÔÚÀàÐͼ¶Ê¹ÓÃʱ£¬·½·¨¼¶µÄÏû·ÑÀàÐͽ«¸²¸ÇÀàÐͼ¶µÄÅäÖ㬶ø·Ç¼Ì³Ð¹ØÏµ¡£
+
+## ÇëÇó²ÎÊýÓëÇëÇóÍ·µÄÖµ
+
+> [Original] You can narrow request matching through request parameter conditions such as `"myParam"`, `"!myParam"`, or `"myParam=myValue"`. The first two test for request parameter presence/absence and the third for a specific parameter value. Here is an example with a request parameter value condition:
+
+Äã¿ÉÒÔɸѡÇëÇó²ÎÊýµÄÌõ¼þÀ´ËõСÇëÇóÆ¥Å䷶Χ£¬±ÈÈç`"myParam"`¡¢`"!myParam"`¼°`"myParam=myValue"`µÈ¡£Ç°Á½¸öÌõ¼þÓÃÓÚɸѡ´æÔÚ/²»´æÔÚijЩÇëÇó²ÎÊýµÄÇëÇ󣬵ÚÈý¸öÌõ¼þɸѡ¾ßÓÐÌØ¶¨²ÎÊýÖµµÄÇëÇó¡£ÏÂÃæÓиöÀý×Ó£¬Õ¹Ê¾ÁËÈçºÎʹÓÃÇëÇó²ÎÊýÖµµÄɸѡÌõ¼þ£º
+
+```
+@Controller
+@RequestMapping("/owners/{ownerId}")
+public class RelativePathUriTemplateController {
+
+ @RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET, params="myParam=myValue")
+ public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
+ // ʵ¼ÊʵÏÖÊ¡ÂÔ
+ }
+
+}
+
+```
+
+> [Original] The same can be done to test for request header presence/absence or to match based on a specific request header value:
+
+ͬÑù£¬Äã¿ÉÒÔÓÃÏàͬµÄÌõ¼þÀ´É¸Ñ¡ÇëÇóÍ·µÄ³öÏÖÓë·ñ£¬»òÕßɸѡ³öÒ»¸ö¾ßÓÐÌØ¶¨ÖµµÄÇëÇóÍ·£º
+
+```
+@Controller
+@RequestMapping("/owners/{ownerId}")
+public class RelativePathUriTemplateController {
+
+ @RequestMapping(path = "/pets", method = RequestMethod.GET, headers="myHeader=myValue")
+ public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
+ // ·½·¨ÌåʵÏÖÊ¡ÂÔ
+ }
+
+}
+
+```
+
+> [Original] Although you can match to _Content-Type_ and _Accept_ header values using media type wild cards (for example _"content-type=text/*"_ will match to _"text/plain"_ and _"text/html"_), it is recommended to use the _consumes_ and _produces_ conditions respectively instead. They are intended specifically for that purpose.
+>
+> ¾¡¹Ü£¬Äã¿ÉÒÔʹÓÃýÌåÀàÐ͵ÄͨÅä·û£¨±ÈÈç _"content-type=text/*"_£©À´Æ¥ÅäÇëÇóÍ· _Content-Type_ºÍ _Accept_µÄÖµ£¬µ«ÎÒÃǸüÍÆ¼ö¶ÀÁ¢Ê¹Óà _consumes_ºÍ _produces_Ìõ¼þÀ´É¸Ñ¡¸÷×ÔµÄÇëÇó¡£ÒòΪËüÃǾÍÊÇרÃÅÎªÇø·ÖÕâÁ½ÖÖ²»Í¬µÄ³¡¾°¶øÉúµÄ¡£
+
+
+
+
+
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\274\202\345\270\270\345\244\204\347\220\206\345\231\250.md" "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\274\202\345\270\270\345\244\204\347\220\206\345\231\250.md"
new file mode 100644
index 0000000..604e246
--- /dev/null
+++ "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\274\202\345\270\270\345\244\204\347\220\206\345\231\250.md"
@@ -0,0 +1,235 @@
+
+
+
+
+# Spring MVC ´¦ÀíÆ÷Òì³£½âÎöÆ÷
+
+
+
+2018-07-26 14:32 ¸üÐÂ
+
+
+
+
+
+
+
+SpringµÄ´¦ÀíÆ÷Òì³£½âÎöÆ÷`HandlerExceptionResolver`½Ó¿ÚµÄʵÏÖ¸ºÔð´¦Àí¸÷Àà¿ØÖÆÆ÷Ö´Ðйý³ÌÖгöÏÖµÄÒì³£¡£Ä³Ö̶ֳÈÉϽ²£¬`HandlerExceptionResolver`ÓëÄãÔÚwebÓ¦ÓÃÃèÊö·û`web.xml`ÎļþÖÐÄܶ¨ÒåµÄÒì³£Ó³É䣨exception mapping£©ºÜÏàÏñ£¬²»¹ýËü±ÈºóÕßÌṩÁ˸üÁé»îµÄ·½Ê½¡£±ÈÈçËüÄÜÌṩÒì³£±»Å׳öʱÕýÔÚÖ´ÐеÄÊÇÄĸö´¦ÀíÆ÷ÕâÑùµÄÐÅÏ¢¡£²¢ÇÒ£¬Ò»¸ö¸üÁé»î£¨programmatic£©µÄÒì³£´¦Àí·½Ê½¿ÉÒÔΪÄãÌṩ¸ü¶àÑ¡Ôñ£¬Ê¹ÄãÔÚÇëÇó±»Ö±½ÓתÏòµ½ÁíÒ»¸öURL֮ǰ£¨ÓëÄãʹÓÃServlet¹æ·¶µÄÒì³£Ó³ÉäÊÇÒ»ÑùµÄ£©Óиü¶àµÄ·½Ê½À´´¦ÀíÒì³£¡£
+
+
+
+ʵÏÖ`HandlerExceptionResolver`½Ó¿Ú²¢·ÇʵÏÖÒì³£´¦ÀíµÄΨһ·½Ê½£¬ËüÖ»ÊÇÌṩÁË`resolveException(Exception, Hanlder)`·½·¨µÄÒ»¸öʵÏÖ¶øÒÑ£¬·½·¨»á·µ»ØÒ»¸ö`ModelAndView`¡£³ý´ËÖ®Í⣬Ä㻹¿ÉÒÔ¿ò¼ÜÌṩµÄ`SimpleMappingExceptionResolver`»òÔÚÒì³£´¦Àí·½·¨ÉÏ×¢½â`@ExceptionHandler`¡£`SimpleMappingExceptionResolver`ÔÊÐíÄã»ñÈ¡¿ÉÄÜÅ׳öµÄÒì³£ÀàµÄÃû×Ö£¬²¢°ÑËüÓ³Éäµ½Ò»¸öÊÓͼÃûÉÏÈ¥¡£ÕâÓëServlet APIÌṩµÄÒì³£Ó³ÉäÌØÐÔÊǹ¦Äܵȼ۵쬵«ÄãÒ²¿ÉÒÔ»ùÓÚ´ËʵÏÖÁ£¶È¸ü¾«Ï¸µÄÒì³£Ó³Éä¡£¶ø`@ExceptionHandler`×¢½âµÄ·½·¨Ôò»áÔÚÒì³£Å׳öʱ±»µ÷ÓÃÒÔ´¦Àí¸ÃÒì³£¡£ÕâÑùµÄ·½·¨¿ÉÒÔ¶¨ÒåÔÚ`@Controller`×¢½âµÄ¿ØÖÆÆ÷ÀàÀҲ¿ÉÒÔ¶¨ÒåÔÚ`@ControllerAdvice`ÀàÖУ¬ºóÕß¿ÉÒÔʹ¸ÃÒì³£´¦Àí·½·¨±»Ó¦Óõ½¸ü¶àµÄ`@Controller`¿ØÖÆÆ÷ÖС£ÏÂһС½Ú½«Ìṩ¸üΪÏêϸµÄÐÅÏ¢¡£
+
+
+
+
+
+
+
+
+
+# Spring MVC ʹÓÃ@ExceptionHandler×¢½â
+
+
+
+2018-07-26 14:33 ¸üÐÂ
+
+
+
+
+
+
+
+
+
+`HandlerExceptionResolver`½Ó¿ÚÒÔ¼°`SimpleMappingExceptionResolver`½âÎöÆ÷ÀàµÄʵÏÖʹµÃÄãÄÜÉùÃ÷ʽµØ½«Òì³£Ó³Éäµ½ÌØ¶¨µÄÊÓͼÉÏ£¬»¹¿ÉÒÔÔÚÒì³£±»×ª·¢£¨forward£©µ½¶ÔÓ¦µÄÊÓͼǰʹÓÃJava´úÂë×öЩÅжϺÍÂß¼¡£²»¹ýÔÚһЩ³¡¾°£¬ÌرðÊÇÒÀ¿¿`@ResponseBody`·µ»ØÏìÓ¦¶ø·ÇÒÀÀµÊÓͼ½âÎö»úÖÆµÄ³¡¾°Ï£¬Ö±½ÓÉèÖÃÏìÓ¦µÄ״̬Âë²¢½«¿Í»§¶ËÐèÒªµÄ´íÎóÐÅÏ¢Ö±½Óд»ØÏìÓ¦ÌåÖУ¬¿ÉÄÜÊǸü·½±ãµÄ·½·¨¡£
+
+ÄãÒ²¿ÉÒÔʹÓÃ`@ExceptionHandler`·½·¨À´×öµ½Õâµã¡£Èç¹û`@ExceptionHandler`·½·¨ÊÇÔÚ¿ØÖÆÆ÷ÄÚ²¿¶¨ÒåµÄ£¬ÄÇôËü»á½ÓÊÕ²¢´¦ÀíÓÉ¿ØÖÆÆ÷£¨»òÆäÈκÎ×ÓÀࣩÖеÄ`@RequestMapping`·½·¨Å׳öµÄÒì³£¡£Èç¹ûÄ㽫`@ExceptionHandler`·½·¨¶¨ÒåÔÚ`@ControllerAdvice`ÀàÖУ¬ÄÇôËü»á´¦ÀíÏà¹Ø¿ØÖÆÆ÷ÖÐÅ׳öµÄÒì³£¡£ÏÂÃæµÄ´úÂë¾ÍչʾÁËÒ»¸ö¶¨ÒåÔÚ¿ØÖÆÆ÷ÄÚ²¿µÄ`@ExceptionHandler`·½·¨£º
+
+```
+@Controller
+public class SimpleController {
+
+ // @RequestMapping methods omitted ...
+
+ @ExceptionHandler(IOException.class)
+ public ResponseEntity handleIOException(IOException ex) {
+ // prepare responseEntity
+ return responseEntity;
+ }
+
+}
+
+```
+
+´ËÍ⣬`@ExceptionHandler`×¢½â»¹¿ÉÒÔ½ÓÊÜÒ»¸öÒì³£ÀàÐ͵ÄÊý×é×÷Ϊ²ÎÊýÖµ¡£ÈôÅ׳öÁËÒÑÔÚÁбíÖÐÉùÃ÷µÄÒì³££¬ÄÇôÏàÓ¦µÄ`@ExceptionHandler`·½·¨½«»á±»µ÷Óá£Èç¹ûûÓиø×¢½âÈκβÎÊýÖµ£¬ÄÇôĬÈÏ´¦ÀíµÄÒì³£ÀàÐͽ«ÊÇ·½·¨²ÎÊýËùÉùÃ÷µÄÄÇЩÒì³£¡£
+
+Óë±ê×¼µÄ¿ØÖÆÆ÷`@RequestMapping`×¢½â´¦Àí·½·¨Ò»Ñù£¬`@ExceptionHandler`·½·¨µÄ·½·¨²ÎÊýºÍ·µ»ØÖµÒ²¿ÉÒÔºÜÁé»î¡£±ÈÈ磬ÔÚServlet»·¾³Ï·½·¨¿ÉÒÔ½ÓÊÕ`HttpServletRequest`²ÎÊý£¬¶øPortlet»·¾³Ï·½·¨¿ÉÒÔ½ÓÊÕ`PortletRequest`²ÎÊý¡£·µ»ØÖµ¿ÉÒÔÊÇ`String`ÀàÐÍ¡ª¡ªÕâÖÖÇé¿öÏ»ᱻ½âÎöΪÊÓͼÃû¡ª¡ª¿ÉÒÔÊÇ`ModelAndView`ÀàÐ͵ĶÔÏó£¬Ò²¿ÉÒÔÊÇ`ResponseEntity`¡£»òÕßÄ㻹¿ÉÒÔÔÚ·½·¨ÉÏÌí¼Ó`@ResponseBody`×¢½âÒÔʹÓÃÏûϢת»»Æ÷»áת»»ÐÅÏ¢ÎªÌØ¶¨ÀàÐ͵ÄÊý¾Ý£¬È»ºó°ÑËüÃÇд»Øµ½ÏìÓ¦Á÷ÖС£
+
+
+
+
+
+
+
+
+
+# Spring MVC ´¦ÀíÒ»°ãµÄÒì³£
+
+
+
+2018-07-26 14:34 ¸üÐÂ
+
+
+
+
+
+
+
+´¦ÀíÇëÇóµÄ¹ý³ÌÖУ¬Spring MVC¿ÉÄÜ»áÅ׳öһЩµÄÒì³£¡£`SimpleMappingExceptionResolver`¿ÉÒÔ¸ù¾ÝÐèÒªºÜ·½±ãµØ½«ÈκÎÒì³£Ó³Éäµ½Ò»¸öĬÈϵĴíÎóÊÓͼ¡£µ«£¬Èç¹û¿Í»§¶ËÊÇͨ¹ý×Ô¶¯¼ì²âÏìÓ¦µÄ·½Ê½À´·Ö·¢´¦ÀíÒì³£µÄ£¬ÄÇôºó¶Ë¾ÍÐèҪΪÏìÓ¦ÉèÖöÔÓ¦µÄ״̬Âë¡£¸ù¾ÝÅ׳öÒì³£µÄÀàÐͲ»Í¬£¬¿ÉÄÜÐèÒªÉèÖò»Í¬µÄ״̬ÂëÀ´±êʶÊǿͻ§¶Ë´íÎó£¨4xx£©»¹ÊÇ·þÎñÆ÷¶Ë´íÎó£¨5xx£©¡£
+
+
+
+ĬÈÏ´¦ÀíÆ÷Òì³£½âÎöÆ÷`DefaultHandlerExceptionResolver`»á½«Spring MVCÅ׳öµÄÒ쳣ת»»³É¶ÔÓ¦µÄ´íÎó״̬Âë¡£¸Ã½âÎöÆ÷ÔÚMVCÃüÃû¿Õ¼äÅäÖûòMVC JavaÅäÖõķ½Ê½ÏÂĬÈÏÒѾ±»×¢²áÁË£¬ÁíÍ⣬ͨ¹ý`DispatcherServlet`×¢²áÒ²ÊÇ¿ÉÐе썼´²»Ê¹ÓÃMVCÃüÃû¿Õ¼ä»òJava±à³Ì·½Ê½½øÐÐÅäÖõÄʱºò£©¡£Ï±íÁгöÁ˸ýâÎöÆ÷ÄÜ´¦ÀíµÄһЩÒì³££¬¼°ËûÃǶÔÓ¦µÄ״̬Âë¡£
+
+| Òì³£ | HTTP״̬Âë |
+| --- | --- |
+| `BindException` | 400 (ÎÞЧÇëÇó) |
+| `ConversionNotSupportedException` | 500 (·þÎñÆ÷ÄÚ²¿´íÎó) |
+| `HttpMediaTypeNotAcceptableException` | 406 (²»½ÓÊÜ) |
+| `HttpMediaTypeNotSupportedException` | 415 (²»Ö§³ÖµÄýÌåÀàÐÍ) |
+| `HttpMessageNotReadableException` | 400 (ÎÞЧÇëÇó) |
+| `HttpMessageNotWritableException` | 500 (·þÎñÆ÷ÄÚ²¿´íÎó) |
+| `HttpRequestMethodNotSupportedException` | 405 (²»Ö§³ÖµÄ·½·¨) |
+| `MethodArgumentNotValidException` | 400 (ÎÞЧÇëÇó) |
+| `MissingServletRequestParameterException` | 400 (ÎÞЧÇëÇó) |
+| `MissingServletRequestPartException` | 400 (ÎÞЧÇëÇó) |
+| `NoHandlerFoundException` | 404 (ÇëÇóδÕÒµ½) |
+| `NoSuchRequestHandlingMethodException` | 404 (ÇëÇóδÕÒµ½) |
+| `TypeMismatchException` | 400 (ÎÞЧÇëÇó) |
+| `MissingPathVariableException` | 500 (·þÎñÆ÷ÄÚ²¿´íÎó) |
+| `NoHandlerFoundException` | 404 (ÇëÇóδÕÒµ½) |
+
+ÒÔÏ´ý·Òë¡£
+
+The `DefaultHandlerExceptionResolver` works transparently by setting the status of the response. However, it stops short of writing any error content to the body of the response while your application may need to add developer- friendly content to every error response for example when providing a REST API. You can prepare a `ModelAndView` and render error content through view resolution?--?i.e. by configuring a `ContentNegotiatingViewResolver`, `MappingJackson2JsonView`, and so on. However, you may prefer to use`@ExceptionHandler` methods instead.
+
+If you prefer to write error content via `@ExceptionHandler` methods you can extend `ResponseEntityExceptionHandler` instead. This is a convenient base for `@ControllerAdvice` classes providing an `@ExceptionHandler` method to handle standard Spring MVC exceptions and return `ResponseEntity`. That allows you to customize the response and write error content with message converters. See the `ResponseEntityExceptionHandler` javadocs for more details.
+
+
+
+
+
+
+
+
+
+# Spring MVC ʹÓÃ@ResponseStatus×¢½âÒµÎñÒì³£
+
+
+
+2020-07-31 10:52 ¸üÐÂ
+
+
+
+
+
+
+
+ÒµÎñÒì³£¿ÉÒÔʹÓÃ`@ResponseStatus`À´×¢½â¡£µ±Òì³£±»Å׳öʱ£¬`ResponseStatusExceptionResolver`»áÉèÖÃÏàÓ¦µÄÏìӦ״̬Âë¡£`DispatcherServlet`»áĬÈÏ×¢²áÒ»¸ö`ResponseStatusExceptionResolver` ÒÔ¹©Ê¹Óá£
+
+ResponseStatus×¢½âµÄʹÓ÷dz£¼òµ¥£¬ÎÒÃÇ´´½¨Ò»¸öÒì³£À࣬¼ÓÉÏ×¢½â
+
+```
+package com.zj.exception;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@ResponseStatus(value=HttpStatus.FORBIDDEN,reason="Óû§²»Æ¥Åä")
+public class UserNotMatchException extends RuntimeException{
+}
+```
+
+> ResponseStatus×¢½âÊÇÐÞÊÎÀàµÄ
+> ËüÓÐÁ½¸öÊôÐÔ£¬valueÊôÐÔÊÇhttp״̬Â룬±ÈÈç404£¬500µÈ¡£reasonÊÇ´íÎóÐÅÏ¢
+
+дһ¸öÄ¿±ê·½·¨Å׳ö¸ÃÒì³£
+
+```
+@RequestMapping("/testResponseStatus")
+public String testResponseStatus(int i){
+ if(i==0)
+ throw new UserNotMatchException();
+ return "hello";
+}
+```
+
+> ʹÓÃÁËResponseStatus×¢½âÖ®ºó£¬Óû§¿´µ½µÄÒì³£½çÃæÕýÊÇÎÒÃÇ×Ô¼º¶¨ÒåµÄÒì³££¬¶ø²»ÔÙÊÇÒ»´ó¶ÑÓû§¿´²»¶®µÄ´úÂë¡£
+
+
+
+
+
+
+
+# Spring MVC ¶ÔServletĬÈÏÈÝÆ÷´íÎóÒ³ÃæµÄ¶¨ÖÆ»¯
+
+
+
+2018-07-26 14:36 ¸üÐÂ
+
+
+
+
+
+
+
+µ±ÏìÓ¦µÄ״̬Âë±»ÉèÖÃΪ´íÎó״̬Â룬²¢ÇÒÏìÓ¦ÌåÖÐûÓÐÄÚÈÝʱ£¬ServletÈÝÆ÷ͨ³£»áäÖȾһ¸öHTML´íÎóÒ³¡£ÈôÐèÒª¶¨ÖÆÈÝÆ÷ĬÈÏÌṩµÄ´íÎóÒ³£¬Äã¿ÉÒÔÔÚ`web.xml`Öж¨ÒåÒ»¸ö´íÎóÒ³Ãæ``ÔªËØ¡£ÔÚServlet 3¹æ·¶³öÀ´Ö®Ç°£¬¸Ã´íÎóÒ³ÔªËØ±ØÐë±»ÏÔʽָ¶¨Ó³Éäµ½Ò»¸ö¾ßÌåµÄ´íÎóÂë»òÒ»¸öÒì³£ÀàÐÍ¡£´ÓServlet 3¿ªÊ¼£¬´íÎóÒ³²»ÔÙÐèÒªÓ³Éäµ½ÆäËûÐÅÏ¢ÁË£¬ÕâÒâζ×Å£¬ÄãÖ¸¶¨µÄλÖþÍÊǶÔServletÈÝÆ÷ĬÈÏ´íÎóÒ³µÄ×Ô¶¨ÖÆÁË¡£
+
+
+
+```
+
+ /error
+
+
+```
+
+ÕâÀï´íÎóÒ³µÄλÖÃËùÔÚ¿ÉÒÔÊÇÒ»¸öJSPÒ³Ãæ£¬»òÕ߯äËûµÄһЩURL£¬Ö»ÒªËüÖ¸¶¨ÈÝÆ÷ÀïÈÎÒâÒ»¸ö`@Controller`¿ØÖÆÆ÷ϵĴ¦ÀíÆ÷·½·¨£º
+
+д»Ø`HttpServletResponse`µÄ´íÎóÐÅÏ¢ºÍ´íÎó״̬Âë¿ÉÒÔÔÚ¿ØÖÆÆ÷ÖÐͨ¹ýÇëÇóÊôÐÔÀ´»ñÈ¡£º
+
+```
+@Controller
+public class ErrorController {
+
+ @RequestMapping(path = "/error", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+ @ResponseBody
+ public Map handle(HttpServletRequest request) {
+
+ Map map = new HashMap();
+ map.put("status", request.getAttribute("javax.servlet.error.status_code"));
+ map.put("reason", request.getAttribute("javax.servlet.error.message"));
+
+ return map;
+ }
+
+}
+
+```
+
+»òÕßÔÚJSPÖÐÕâôʹÓÃ:
+
+```
+<%@ page contentType="application/json" pageEncoding="UTF-8"%>
+{
+ status:<%=request.getAttribute("javax.servlet.error.status_code") %>,
+ reason:<%=request.getAttribute("javax.servlet.error.message") %>
+}
+```
+
+
+
+
+
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\346\213\246\346\210\252\345\231\250.md" "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\346\213\246\346\210\252\345\231\250.md"
new file mode 100644
index 0000000..ba66314
--- /dev/null
+++ "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\346\213\246\346\210\252\345\231\250.md"
@@ -0,0 +1,88 @@
+
+
+
+
+# Spring MVC ʹÓÃHandlerInterceptorÀ¹½ØÇëÇó
+
+
+
+2018-07-26 14:07 ¸üÐÂ
+
+
+
+
+
+
+
+SpringµÄ´¦ÀíÆ÷Ó³Éä»úÖÆ°üº¬ÁË´¦ÀíÆ÷À¹½ØÆ÷¡£À¹½ØÆ÷ÔÚÄãÐèÒªÎªÌØ¶¨ÀàÐ͵ÄÇëÇóÓ¦ÓÃһЩ¹¦ÄÜʱ¿ÉÄܺÜÓÐÓ㬱ÈÈ磬¼ì²éÓû§Éí·ÝµÈ¡£
+
+
+
+´¦ÀíÆ÷Ó³Éä´¦Àí¹ý³ÌÅäÖõÄÀ¹½ØÆ÷£¬±ØÐëʵÏÖ `org.springframework.web.servlet`°üÏ嵀 `HandlerInterceptor`½Ó¿Ú¡£Õâ¸ö½Ó¿Ú¶¨ÒåÁËÈý¸ö·½·¨£º `preHandle(..)`£¬ËüÔÚ´¦ÀíÆ÷ʵ¼ÊÖ´ÐÐ _֮ǰ_ »á±»Ö´ÐУ» `postHandle(..)`£¬ËüÔÚ´¦ÀíÆ÷Ö´ÐÐ _Íê±Ï_ ÒÔºó±»Ö´ÐУ» `afterCompletion(..)`£¬ËüÔÚ _Õû¸öÇëÇó´¦ÀíÍê³É_ Ö®ºó±»Ö´ÐС£ÕâÈý¸ö·½·¨Îª¸÷ÖÖÀàÐ͵Äǰ´¦ÀíºÍºó´¦ÀíÐèÇóÌṩÁË×ã¹»µÄÁé»îÐÔ¡£
+
+`preHandle(..)`·½·¨·µ»ØÒ»¸öbooleanÖµ¡£Äã¿ÉÒÔͨ¹ýÕâ¸ö·½·¨À´¾ö¶¨ÊÇ·ñ¼ÌÐøÖ´Ðд¦ÀíÁ´ÖеIJ¿¼þ¡£µ±·½·¨·µ»Ø `true`ʱ£¬´¦ÀíÆ÷Á´»á¼ÌÐøÖ´ÐУ»Èô·½·¨·µ»Ø `false`£¬ `DispatcherServlet`¼´ÈÏΪÀ¹½ØÆ÷×ÔÉíÒѾÍê³ÉÁ˶ÔÇëÇóµÄ´¦Àí£¨±ÈÈç˵£¬ÒѾäÖȾÁËÒ»¸öºÏÊʵÄÊÓͼ£©£¬ÄÇôÆäÓàµÄÀ¹½ØÆ÷ÒÔ¼°Ö´ÐÐÁ´ÖÐµÄÆäËû´¦ÀíÆ÷¾Í²»»áÔÙ±»Ö´ÐÐÁË¡£
+
+À¹½ØÆ÷¿ÉÒÔͨ¹ý`interceptors`ÊôÐÔÀ´ÅäÖ㬸ÃÑ¡ÏîÔÚËùÓм̳ÐÁË`AbstractHandlerMapping`µÄ´¦ÀíÆ÷Ó³ÉäÀà`HandlerMapping`¶¼ÌṩÁËÅäÖõĽӿڡ£ÈçÏÂÃæ´úÂëÑùÀýËùʾ£º
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```
+package samples;
+
+public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
+
+ private int openingTime;
+ private int closingTime;
+
+ public void setOpeningTime(int openingTime) {
+ this.openingTime = openingTime;
+ }
+
+ public void setClosingTime(int closingTime) {
+ this.closingTime = closingTime;
+ }
+
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
+ Object handler) throws Exception {
+ Calendar cal = Calendar.getInstance();
+ int hour = cal.get(HOUR_OF_DAY);
+ if (openingTime <= hour && hour < closingTime) {
+ return true;
+ }
+ response.sendRedirect("http://host.com/outsideOfficeHours.html");
+ return false;
+ }
+}
+
+```
+
+ÔÚÉÏÃæµÄÀý×ÓÖУ¬ËùÓб»´Ë´¦ÀíÆ÷´¦ÀíµÄÇëÇ󶼻ᱻ`TimeBasedAccessInterceptor`À¹½ØÆ÷À¹½Ø¡£Èç¹ûµ±Ç°Ê±¼äÔÚ¹¤×÷ʱ¼äÒÔÍ⣬ÄÇôÓû§¾Í»á±»Öض¨Ïòµ½Ò»¸öHTMLÎļþÌáʾÓû§£¬±ÈÈçÏÔʾ¡°ÄãÖ»ÓÐÔÚ¹¤×÷ʱ¼ä²Å¿ÉÒÔ·ÃÎʱ¾ÍøÕ¾¡±Ö®ÀàµÄÐÅÏ¢¡£
+
+> ʹÓÃ`RequestMappingHandlerMapping`ʱ£¬Êµ¼ÊµÄ´¦ÀíÆ÷ÊÇÒ»¸ö´¦ÀíÆ÷·½·¨`HandlerMethod`µÄʵÀý£¬Ëü±êʶÁËÒ»¸ö½«±»ÓÃÓÚ´¦Àí¸ÃÇëÇóµÄ¿ØÖÆÆ÷·½·¨¡£
+
+ÈçÄãËù¼û£¬SpringµÄÀ¹½ØÆ÷ÊÊÅäÆ÷`HandlerInterceptorAdapter`Èü̳Ð`HandlerInterceptor`½Ó¿Ú±äµÃ¸ü¼òµ¥ÁË¡£
+
+> ÉÏÃæµÄÀý×ÓÖУ¬ËùÓпØÖÆÆ÷·½·¨´¦ÀíµÄÇëÇ󶼻ᱻÅäÖõÄÀ¹½ØÆ÷ÏÈÀ¹½Øµ½¡£Èç¹ûÄãÏë½øÒ»²½ËõСÀ¹½ØµÄURL·¶Î§£¬Äã¿ÉÒÔͨ¹ýMVCÃüÃû¿Õ¼ä»òMVC Java±à³ÌµÄ·½Ê½À´ÅäÖ㬻òÕߣ¬ÉùÃ÷Ò»¸ö`MappedInterceptor`ÀàÐ͵ÄbeanʵÀýÀ´´¦Àí¡£¾ßÌåÇë¼û [21.16.1 ÆôÓÃMVC Java±à³ÌÅäÖûòMVCÃüÃû¿Õ¼äÅäÖÃ](https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/spring_mvc_documentation_linesh_translation-ouxg27ss.html)һС½Ú¡£
+
+ÐèҪעÒâµÄÊÇ£¬`HandlerInterceptor`µÄºóÀ¹½Ø`postHandle`·½·¨²»Ò»¶¨×ÜÊÇÊÊÓÃÓÚ×¢½âÁË`@ResponseBody`»ò`ResponseEntity`µÄ·½·¨¡£ÕâЩ³¡¾°ÖУ¬`HttpMessageConverter`»áÔÚÀ¹½ØÆ÷µÄ`postHandle`·½·¨±»µ÷֮ǰ¾Í°ÑÐÅϢд»ØÏìÓ¦ÖС£ÕâÑùÀ¹½ØÆ÷¾ÍÎÞ·¨ÔٸıäÏìÓ¦ÁË£¬±ÈÈçÒªÔö¼ÓÒ»¸öÏìӦͷ֮ÀàµÄ¡£Èç¹ûÓÐÕâÖÖÐèÇó£¬ÇëÈÃÄãµÄÓ¦ÓÃʵÏÖ`ResponseBodyAdvice`½Ó¿Ú£¬²¢½«Æä¶¨ÒåΪһ¸ö`@ControllerAdvice`bean»òÖ±½ÓÔÚ`RequestMappingHandlerMapping`ÖÐÅäÖá£
+
+
+
+
+
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\231\250.md" "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\231\250.md"
new file mode 100644
index 0000000..6537078
--- /dev/null
+++ "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\231\250.md"
@@ -0,0 +1,181 @@
+
+
+
+
+# Spring MVC ʹÓÃViewResolver½Ó¿Ú½âÎöÊÓͼ
+
+
+
+2018-07-26 15:39 ¸üÐÂ
+
+
+
+
+
+
+
+ÕýÈçÔÚ[Spring MVC ¿ØÖÆÆ÷µÄʵÏÖ](https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/spring_mvc_documentation_linesh_translation-7z6u27rb.html)Ò»½ÚÖÐËùÌÖÂ۵ģ¬Spring MVCÖÐËùÓпØÖÆÆ÷µÄ´¦ÀíÆ÷·½·¨¶¼±ØÐë·µ»ØÒ»¸öÂß¼ÊÓͼµÄÃû×Ö£¬ÎÞÂÛÊÇÏÔʽ·µ»Ø£¨±ÈÈç·µ»ØÒ»¸ö`String`¡¢`View`»òÕß`ModelAndView`£©»¹ÊÇÒþʽ·µ»Ø£¨±ÈÈç»ùÓÚÔ¼¶¨µÄ·µ»Ø£©¡£SpringÖеÄÊÓͼÓÉÒ»¸öÊÓͼÃû±êʶ£¬²¢ÓÉÊÓͼ½âÎöÆ÷À´äÖȾ¡£SpringÓзdz£¶àÄÚÖõÄÊÓͼ½âÎöÆ÷¡£Ï±íÁгöÁ˴󲿷֣¬±íºóÒ²¸ø³öÁËһЩÀý×Ó¡£
+
+
+
+**±í21.3 ÊÓͼ½âÎöÆ÷**
+
+| ÊÓͼ½âÎöÆ÷ | ÃèÊö |
+| --- | --- |
+| `AbstractCachingViewResolver` | Ò»¸ö³éÏóµÄÊÓͼ½âÎöÆ÷À࣬ÌṩÁË»º´æÊÓͼµÄ¹¦ÄÜ¡£Í¨³£ÊÓͼÔÚÄܹ»±»Ê¹ÓÃ֮ǰÐèÒª¾¹ý×¼±¸¡£¼Ì³ÐÕâ¸ö»ùÀàµÄÊÓͼ½âÎöÆ÷¼´¿ÉÒÔ»ñµÃ»º´æÊÓͼµÄÄÜÁ¦¡£ |
+| `XmlViewResolver` | ÊÓͼ½âÎöÆ÷½Ó¿Ú`ViewResolver`µÄÒ»¸öʵÏÖ£¬¸ÃÀà½ÓÊÜÒ»¸öXML¸ñʽµÄÅäÖÃÎļþ¡£¸ÃXMLÎļþ±ØÐëÓëSpring XMLµÄbean¹¤³§ÓÐÏàͬµÄDTD¡£Ä¬ÈϵÄÅäÖÃÎļþÃûÊÇ`/WEB-INF/views.xml`¡£ |
+| `ResourceBundleViewResolver` | ÊÓͼ½âÎöÆ÷½Ó¿Ú`ViewResolver`µÄÒ»¸öʵÏÖ£¬²ÉÓÃbundle¸ù·¾¶ËùÖ¸¶¨µÄ`ResourceBundle`ÖеÄbean¶¨Òå×÷ΪÅäÖá£Ò»°ãbundle¶¼¶¨ÒåÔÚclasspath·¾¶ÏµÄÒ»¸öÅäÖÃÎļþÖС£Ä¬ÈϵÄÅäÖÃÎļþÃûΪ`views.properties`¡£ |
+| `UrlBasedViewResolver` | `ViewResolver`½Ó¿ÚµÄÒ»¸ö¼òµ¥ÊµÏÖ¡£ËüÖ±½ÓʹÓÃURLÀ´½âÎöµ½Âß¼ÊÓͼÃû£¬³ý´ËÖ®Íâ²»ÐèÒªÆäËûÈκÎÏÔʽµÄÓ³ÉäÉùÃ÷¡£Èç¹ûÄãµÄÂß¼ÊÓͼÃûÓëÄãÕæÕýµÄÊÓͼ×ÊÔ´ÃûÊÇÖ±½Ó¶ÔÓ¦µÄ£¬ÄÇôÕâÖÖÖ±½Ó½âÎöµÄ·½Ê½¾ÍºÜ·½±ã£¬²»ÐèÒªÄãÔÙÖ¸¶¨¶îÍâµÄÓ³Éä¡£ |
+| `InternalResourceViewResolver` | `UrlBasedViewResolver`µÄÒ»¸öºÃÓõÄ×ÓÀà¡£ËüÖ§³ÖÄÚ²¿×ÊÔ´ÊÓͼ£¨¾ßÌåÀ´Ëµ£¬ServletºÍJSP£©¡¢ÒÔ¼°ÖîÈç`JstlView`ºÍ`TilesView`µÈÀàµÄ×ÓÀà¡£You can specify the view class for all views generated by this resolver by using `setViewClass(..)`¡£¸ü¶àµÄϸ½Ú£¬Çë¼û`UrlBasedViewResolver`ÀàµÄjavaÎĵµ¡£ |
+| `VelocityViewResolver` / `FreeMarkerViewResolver` | `UrlBasedViewResolver`ϵÄʵÓÃ×ÓÀ֧࣬³ÖVelocityÊÓͼ`VelocityView`£¨VelocityÄ£°å£©ºÍFreeMarkerÊÓͼ`FreeMarkerView`ÒÔ¼°ËüÃǶÔÓ¦×ÓÀà¡£ |
+| `ContentNegotiatingViewResolver` | ÊÓͼ½âÎöÆ÷½Ó¿Ú`ViewResolver`µÄÒ»¸öʵÏÖ£¬Ëü»á¸ù¾ÝËùÇëÇóµÄÎļþÃû»òÇëÇóµÄ`Accept`Í·À´½âÎöÒ»¸öÊÓͼ¡£¸ü¶àϸ½ÚÇë¼û[Spring MVC ÄÚÈÝÐÉÌÊÓͼ½âÎöÆ÷](https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/spring_mvc_documentation_linesh_translation-gal927rn.html)һС½Ú¡£ |
+
+ÎÒÃÇ¿ÉÒÔ¾Ù¸öÀý×Ó£¬¼ÙÉèÕâÀïʹÓõÄÊÇJSPÊÓͼ¼¼Êõ£¬ÄÇôÎÒÃÇ¿ÉÒÔʹÓÃÒ»¸ö»ùÓÚURLµÄÊÓͼ½âÎöÆ÷`UrlBasedViewResolver`¡£Õâ¸öÊÓͼ½âÎöÆ÷»á½«URL½âÎö³ÉÒ»¸öÊÓͼÃû£¬²¢½«ÇëÇóת½»¸øÇëÇó·Ö·¢Æ÷À´½øÐÐÊÓͼäÖȾ¡£
+
+```
+
+
+
+
+
+
+```
+
+Èô·µ»ØÒ»¸ö`test`Âß¼ÊÓͼÃû£¬ÄÇô¸ÃÊÓͼ½âÎöÆ÷»á½«ÇëÇóת·¢µ½`RequestDispatcher`£¬ºóÕ߻ὫÇëÇ󽻸ø`/WEB-INF/jsp/test.jsp`ÊÓͼȥäÖȾ¡£
+
+Èç¹ûÐèÒªÔÚÓ¦ÓÃÖÐʹÓöàÖÖ²»Í¬µÄÊÓͼ¼¼Êõ£¬Äã¿ÉÒÔʹÓÃ`ResourceBundleViewResolver`£º
+
+```
+
+
+
+
+
+```
+
+`ResourceBundleViewResolver`»á¼ìË÷ÓÉbundle¸ù·¾¶ÏÂËùÅäÖõÄ`ResourceBundle`£¬¶ÔÓÚÿ¸öÊÓͼ¶øÑÔ£¬ÆäÊÓͼÀàÓÉ`[viewname].(class)`ÊôÐÔµÄÖµÖ¸¶¨£¬ÆäÊÓͼurlÓÉ`[viewname].url`ÊôÐÔµÄÖµÖ¸¶¨¡£ÏÂÒ»½Ú½«Ïêϸ½²½âÊÓͼ¼¼Êõ£¬Äã¿ÉÒÔÔÚÄÇÀïÕÒµ½¸ü¶àÀý×Ó¡£Ä㻹¿ÉÒÔ¿´µ½£¬ÊÓͼ»¹ÔÊÐíÓлùÊÓͼ£¬¼´propertiesÎļþÖÐËùÓÐÊÓͼ¶¼¡°¼Ì³Ð¡±µÄÒ»¸öÎļþ¡£Í¨¹ý¼Ì³Ð¼¼Êõ£¬Äã¿ÉÒÔΪÖÚ¶àÊÓͼָ¶¨Ò»¸öĬÈϵÄÊÓͼ»ùÀà¡£
+
+> `AbstractCachingViewResolver`µÄ×ÓÀàÄܹ»»º´æÒѾ½âÎö¹ýµÄÊÓͼʵÀý¡£¹Ø±Õ»º´æÌØÐÔÒ²ÊÇ¿ÉÒԵģ¬Ö»ÐèÒª½«`cache`ÊôÐÔÉèÖÃΪ`false`¼´¿É¡£ÁíÍ⣬Èç¹ûʵÔÚÐèÒªÔÚÔËÐÐʱˢÐÂij¸öÊÓͼ£¨±ÈÈçÐÞ¸ÄÁËVelocityÄ£°åʱ£©£¬Äã¿ÉÒÔʹÓÃ`removeFromCache(String viewName, Locale loc)`·½·¨¡£`
+
+
+
+
+
+
+
+
+
+# Spring MVC ÊÓͼÁ´
+
+
+
+2018-07-26 14:11 ¸üÐÂ
+
+
+
+
+
+
+
+SpringÖ§³ÖͬʱʹÓöà¸öÊÓͼ½âÎöÆ÷¡£Òò´Ë£¬Äã¿ÉÒÔÅäÖÃÒ»¸ö½âÎöÆ÷Á´£¬²¢×ö¸ü¶àµÄʱÈÈ磬ÔÚÌØ¶¨Ìõ¼þϸ²Ð´Ò»¸öÊÓͼµÈ¡£Äã¿ÉÒÔͨ¹ý°Ñ¶à¸öÊÓͼ½âÎöÆ÷ÉèÖõ½Ó¦ÓÃÉÏÏÂÎÄ(application context)Öеķ½Ê½À´´®ÁªËüÃÇ¡£Èç¹ûÐèÒªÖ¸¶¨ËüÃǵĴÎÐò£¬ÄÇôÉèÖÃ`order`ÊôÐÔ¼´¿É¡£Çë¼Çס£¬orderÊôÐÔµÄÖµÔ½´ó£¬¸ÃÊÓͼ½âÎöÆ÷ÔÚÁ´ÖеÄλÖþÍÔ½¿¿ºó¡£
+
+
+
+ÔÚÏÂÃæµÄ´úÂëÀý×ÓÖУ¬ÊÓͼ½âÎöÆ÷Á´Öаüº¬ÁËÁ½¸ö½âÎöÆ÷£ºÒ»¸öÊÇ`InternalResourceViewResolver`£¬Ëü×ÜÊÇ×Ô¶¯±»·ÅÖÃÔÚ½âÎöÆ÷Á´µÄ×îºó£»ÁíÒ»¸öÊÇ`XmlViewResolver`£¬ËüÓÃÀ´Ö¸¶¨ExcelÊÓͼ¡£`InternalResourceViewResolver`²»Ö§³ÖExcelÊÓͼ¡£
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+Èç¹ûÒ»¸öÊÓͼ½âÎöÆ÷²»ÄÜ·µ»ØÒ»¸öÊÓͼ£¬ÄÇôSpring»á¼ÌÐø¼ì²éÉÏÏÂÎÄÖÐÆäËûµÄÊÓͼ½âÎöÆ÷¡£´ËʱÈç¹û´æÔÚÆäËûµÄ½âÎöÆ÷£¬Spring»á¼ÌÐøµ÷ÓÃËüÃÇ£¬Ö±µ½²úÉúÒ»¸öÊÓͼ·µ»ØÎªÖ¹¡£Èç¹û×îºóËùÓÐÊÓͼ½âÎöÆ÷¶¼²»ÄÜ·µ»ØÒ»¸öÊÓͼ£¬Spring¾ÍÅ׳öÒ»¸ö`ServletException`¡£
+
+ÊÓͼ½âÎöÆ÷µÄ½Ó¿ÚÇå³þÉùÃ÷ÁË£¬Ò»¸öÊÓͼ½âÎöÆ÷ÊÇ_¿ÉÒÔ_·µ»ØnullÖµµÄ£¬Õâ±íʾ²»ÄÜÕÒµ½ÈκκÏÊʵÄÊÓͼ¡£²¢·ÇËùÓеÄÊÓͼ½âÎöÆ÷¶¼Õâô×ö£¬µ«ÊÇÒ²´æÔÚ²»µÃ²»Èç´ËµÄ³¡¾°£¬¼´½âÎöÆ÷ȷʵÎÞ·¨¼ì²â¶ÔÓ¦µÄÊÓͼÊÇ·ñ´æÔÚ¡£±ÈÈ磬`InternalResourceViewResolver`ÔÚÄÚ²¿Ê¹ÓÃÁË`RequestDispatcher`£¬²¢ÇÒ½øÈë·ÖÅɹý³ÌÊǼì²âÒ»¸öJSPÊÓͼÊÇ·ñ´æÔÚµÄΨһ·½·¨£¬µ«Õâ¸ö¹ý³Ì½ö¿ÉÄÜ·¢ÉúΨһһ´Î¡£Í¬ÑùµÄ`VelocityViewResolver`ºÍ²¿·ÖÆäËûµÄÊÓͼ½âÎöÆ÷Ò²´æÔÚÕâÑùµÄÇé¿ö¡£¾ßÌåµÄÇë²éÔÄij¸öÌØ¶¨µÄÊÓͼ½âÎöÆ÷µÄJavaÎĵµ£¬¿´ËüÊÇ·ñ»áreport²»´æÔÚµÄÊÓͼ¡£Òò´Ë£¬Èç¹û²»°Ñ`InternalResourceViewResolver`·ÅÖÃÔÚ½âÎöÆ÷Á´µÄ×îºó£¬½«¿ÉÄܵ¼Ö½âÎöÆ÷Á´ÎÞ·¨ÍêȫִÐУ¬ÒòΪ`InternalResourceViewResolver`_ÓÀÔ¶¶¼»á_ ·µ»ØÒ»¸öÊÓͼ¡£
+
+
+
+
+
+
+
+
+
+# Spring MVC ÊÓÍ¼ÖØ¶¨Ïò
+
+
+
+2018-07-26 14:12 ¸üÐÂ
+
+
+
+
+
+
+
+ÈçǰËùÊö£¬¿ØÖÆÆ÷ͨ³£¶¼»á·µ»ØÒ»¸öÂß¼ÊÓͼÃû£¬È»ºóÊÓͼ½âÎöÆ÷»á°ÑËü½âÎöµ½Ò»¸ö¾ßÌåµÄÊÓͼ¼¼ÊõÉÏÈ¥äÖȾ¡£¶ÔÓÚһЩ¿ÉÒÔÓÉServlet»òJSPÒýÇæÀ´´¦ÀíµÄÊÓͼ¼¼Êõ£¬±ÈÈçJSPµÈ£¬Õâ¸ö½âÎö¹ý³Ìͨ³£ÊÇÓÉ`InternalResourceViewResolver`ºÍ`InternalResourceView`Ð×÷À´Íê³ÉµÄ£¬¶øÕâͨ³£»áµ÷ÓÃServletµÄAPI`RequestDispatcher.forward(..)`·½·¨»ò`RequestDispatcher.include(..)`·½·¨£¬²¢·¢ÉúÒ»´ÎÄÚ²¿µÄת·¢£¨forward£©»òÒýÓã¨include£©¡£¶ø¶ÔÓÚÆäËûµÄÊÓͼ¼¼Êõ£¬±ÈÈçVelocity¡¢XSLTµÈ£¬ÊÓͼ±¾ÉíµÄÄÚÈÝÊÇÖ±½Ó±»Ð´»ØÏìÓ¦Á÷Öеġ£
+
+
+
+ÓÐʱ£¬ÎÒÃÇÏëÒªÔÚÊÓͼäÖȾ֮ǰ£¬ÏȰÑÒ»¸öHTTPÖØ¶¨ÏòÇëÇó·¢Ëͻؿͻ§¶Ë¡£±ÈÈ磬µ±Ò»¸ö¿ØÖÆÆ÷³É¹¦µØ½ÓÊܵ½ÁË`POST`¹ýÀ´µÄÊý¾Ý£¬¶øÏìÓ¦½ö½öÊÇίÍÐÁíÒ»¸ö¿ØÖÆÆ÷À´´¦Àí£¨±ÈÈçÒ»´Î³É¹¦µÄ±íµ¥Ìá½»£©Ê±£¬ÎÒÃÇÏ£Íû·¢ÉúÒ»´ÎÖØ¶¨Ïò¡£ÔÚÕâÖÖ³¡¾°Ï£¬Èç¹ûÖ»ÊǼòµ¥µØÊ¹ÓÃÄÚ²¿×ª·¢£¬ÄÇôÒâζ×ÅÏÂÒ»¸ö¿ØÖÆÆ÷Ò²ÄÜ¿´µ½Õâ´Î`POST`ÇëÇóЯ´øµÄÊý¾Ý£¬Õâ¿ÉÄܵ¼ÖÂһЩDZÔÚµÄÎÊÌ⣬±ÈÈç¿ÉÄÜ»áÓëÆäËûÆÚÍûµÄÊý¾Ý»ìÏý£¬µÈ¡£´ËÍ⣬ÁíÒ»ÖÖÔÚäÖȾÊÓͼǰ¶ÔÇëÇó½øÐÐÖØ¶¨ÏòµÄÐèÇóÊÇ£¬·ÀÖ¹Óû§¶à´ÎÌá½»±íµ¥µÄÊý¾Ý¡£´ËʱÈôʹÓÃÖØ¶¨Ïò£¬Ôòä¯ÀÀÆ÷»áÏÈ·¢Ë͵ÚÒ»¸ö`POST`ÇëÇó£»ÇëÇó±»´¦Àíºóä¯ÀÀÆ÷»áÊÕµ½Ò»¸öÖØ¶¨ÏòÏìÓ¦£¬È»ºóä¯ÀÀÆ÷Ö±½Ó±»Öض¨Ïòµ½Ò»¸ö²»Í¬µÄURL£¬×îºóä¯ÀÀÆ÷»áʹÓÃÖØ¶¨ÏòÏìÓ¦ÖÐЯ´øµÄURL·¢ÆðÒ»´Î`GET`ÇëÇó¡£Òò´Ë£¬´Óä¯ÀÀÆ÷µÄ½Ç¶È¿´£¬µ±Ç°Ëù¼ûµÄÒ³Ãæ²¢²»ÊÇ`POST`ÇëÇóµÄ½á¹û£¬¶øÊÇÒ»´Î`GET`ÇëÇóµÄ½á¹û¡£Õâ¾Í·ÀÖ¹ÁËÓû§ÒòˢеÈÔÒòÒâÍâµØÌá½»Á˶à´ÎͬÑùµÄÊý¾Ý¡£´ËʱˢлáÖØÐÂ`GET`Ò»´Î½á¹ûÒ³£¬¶ø²»ÊǰÑͬÑùµÄ`POST`Êý¾ÝÔÙ·¢ËÍÒ»±é¡£
+
+## ÖØ¶¨ÏòÊÓͼ RedirectView
+
+Ç¿ÖÆÖØ¶¨ÏòµÄÒ»ÖÖ·½·¨ÊÇ£¬ÔÚ¿ØÖÆÆ÷Öд´½¨²¢·µ»ØÒ»¸öSpringÖØ¶¨ÏòÊÓͼ`RedirectView`µÄʵÀý¡£Ëü»áʹµÃ`DispatcherServlet`·ÅÆúʹÓÃÒ»°ãµÄÊÓͼ½âÎö»úÖÆ£¬ÒòΪÄãÒѾ·µ»ØÒ»¸ö£¨Öض¨Ïò£©ÊÓͼ¸ø`DispatcherServlet`ÁË£¬ËùÒÔËü»á¹¹ÔìÒ»¸öÊÓͼÀ´Âú×ãäÖȾµÄÐèÇó¡£½ô½Ó×Å`RedirectView`»áµ÷ÓÃ`HttpServletResponse.sendRedirect()`·½·¨£¬·¢ËÍÒ»¸öHTTPÖØ¶¨ÏòÏìÓ¦¸ø¿Í»§¶Ëä¯ÀÀÆ÷¡£
+
+Èç¹ûÄã¾ö¶¨·µ»Ø`RedirectView`£¬²¢ÇÒÕâ¸öÊÓͼʵÀýÊÇÓÉ¿ØÖÆÆ÷ÄÚ²¿´´½¨³öÀ´µÄ£¬ÄÇÎÒÃǸüÍÆ¼öÔÚÍⲿÅäÖÃÖØ¶¨ÏòURLÈ»ºó×¢Èëµ½¿ØÖÆÆ÷ÖÐÀ´£¬¶ø²»ÊÇдÔÚ¿ØÖÆÆ÷ÀïÃæ¡£ÕâÑùËü¾Í¿ÉÒÔÓëÊÓͼÃûÒ»ÆðÔÚÅäÖÃÎļþÖÐÅäÖ᣹ØÓÚÈçºÎʵÏÖÕâ¸ö½âñÇë²Î¿¼ [ÖØ¶¨Ïòǰ׺¡ª¡ªredirect:](http://docs.spring.io/spring-framework/docs/4.2.4.RELEASE/spring-framework-reference/html/mvc.html#mvc-redirecting-redirect-prefix)һС½Ú¡£
+
+## ÏòÖØ¶¨ÏòÄ¿±ê´«µÝÊý¾Ý
+
+Ä£ÐÍÖеÄËùÓÐÊôÐÔĬÈ϶¼»á¿¼ÂÇ×÷ΪURIÄ£°å±äÁ¿±»Ìí¼Óµ½Öض¨ÏòURLÖС£Ê£ÏÂµÄÆäËûÊôÐÔ£¬Èç¹ûÊÇ»ù±¾ÀàÐÍ»òÕß»ù±¾ÀàÐ͵ļ¯ºÏ»òÊý×飬ÄÇËüÃǽ«±»×Ô¶¯Ìí¼Óµ½URLµÄ²éѯ²ÎÊýÖÐÈ¥¡£Èç¹ûmodelÊÇרÃÅΪ¸ÃÖØ¶¨ÏòËù×¼±¸µÄ£¬ÄÇô°ÑËùÓлù±¾ÀàÐ͵ÄÊôÐÔÌí¼Óµ½²éѯ²ÎÊýÖпÉÄÜÊÇÎÒÃÇÆÚÍûÄǸöµÄ½á¹û¡£µ«ÊÇ£¬ÔÚ°üº¬×¢½âµÄ¿ØÖÆÆ÷ÖУ¬model¿ÉÄܰüº¬ÁËרÃÅ×÷ΪäÖȾÓÃ;µÄÊôÐÔ£¨±ÈÈçÒ»¸öÏÂÀÁбíµÄ×Ö¶ÎÖµµÈ£©¡£ÎªÁ˱ÜÃâ°ÑÕâÑùµÄÊôÐÔÒ²±©Â¶ÔÚURLÖУ¬`@RequestMapping`·½·¨¿ÉÒÔÉùÃ÷Ò»¸ö`RedirectAttributes`ÀàÐ͵ķ½·¨²ÎÊý£¬ÓÃËüÀ´Ö¸¶¨×¨ÃŹ©Öض¨ÏòÊÓͼ`RedirectView`È¡ÓõÄÊôÐÔ¡£Èç¹ûÖØ¶¨Ïò³É¹¦·¢Éú£¬ÄÇô`RedirectAttributes`¶ÔÏóÖеÄÄÚÈݾͻᱻʹÓã»·ñÔòÔòʹÓÃÄ£ÐÍmodelÖеÄÊý¾Ý¡£
+
+`RequestMappingHandlerAdapter`ÌṩÁËÒ»¸ö`"ignoreDefaultModelOnRedirect"`±êÖ¾¡£Ëü±»ÓÃÀ´±ê¼ÇĬÈÏ`Model`ÖеÄÊôÐÔÓÀÔ¶²»Ó¦¸Ã±»ÓÃÓÚ¿ØÖÆÆ÷·½·¨µÄÖØ¶¨ÏòÖС£¿ØÖÆÆ÷·½·¨Ó¦¸ÃÉùÃ÷Ò»¸ö`RedirectAttributes`ÀàµÄ²ÎÊý¡£Èç¹û²»ÉùÃ÷£¬ÄǾÍûÓвÎÊý±»´«µÝµ½Öض¨ÏòµÄÊÓͼ`RedirectView`ÖС£ÔÚMVCÃüÃû¿Õ¼ä»òMVC Java±à³ÌÅäÖ÷½Ê½ÖУ¬ÎªÁËά³ÖÏòºóµÄ¼æÈÝÐÔ£¬Õâ¸ö±êÖ¾¶¼ÈÔ±»±£³ÖΪ`false`¡£µ«Èç¹ûÄãµÄÓ¦ÓÃÊÇÒ»¸öеÄÏîÄ¿£¬ÄÇôÎÒÃÇÍÆ¼ö°ÑËüµÄÖµÉèÖóÉ`true`¡£
+
+Çë×¢Ò⣬µ±Ç°ÇëÇóURIÖеÄÄ£°å±äÁ¿»áÔÚÌî³äÖØ¶¨ÏòURLµÄʱºò×Ô¶¯¶ÔÓ¦Óÿɼû£¬¶ø²»ÐèÒªÏÔʽµØÔÚ`Model`»ò`RedirectAttributes`ÖÐÔÙÌí¼ÓÊôÐÔ¡£Çë¿´ÏÂÃæµÄÀý×Ó£º
+
+```
+@RequestMapping(path = "/files/{path}", method = RequestMethod.POST)
+public String upload(...) {
+ // ...
+ return "redirect:files/{path}";
+}
+
+```
+
+ÁíÍâÒ»ÖÖÏòÖØ¶¨ÏòÄ¿±ê´«µÝÊý¾ÝµÄ·½·¨ÊÇͨ¹ý _ÉÁ´æÊôÐÔ£¨Flash Attributes£©_¡£ÓëÆäËûÖØ¶¨ÏòÊôÐÔ²»Í¬£¬flashÊôÐÔÊÇ´æ´¢ÔÚHTTP sessionÖеģ¨Òò´Ë²»»á³öÏÖÔÚURLÖУ©¡£¸ü¶àÄÚÈÝ£¬Çë²Î¿¼ [21.6 ʹÓÃÉÁ´æÊôÐÔ](http://docs.spring.io/spring-framework/docs/4.2.4.RELEASE/spring-framework-reference/html/mvc.html#mvc-flash-attributes)Ò»½Ú¡£
+
+## ÖØ¶¨Ïòǰ׺¡ª¡ªredirect:
+
+¾¡¹ÜʹÓÃ`RedirectView`À´×öÖØ¶¨ÏòÄܹ¤×÷µÃºÜºÃ£¬µ«Èç¹û¿ØÖÆÆ÷×ÔÉí»¹ÊÇÐèÒª´´½¨Ò»¸ö`RedirectView`£¬ÄÇÎÞÒÉ¿ØÖÆÆ÷»¹ÊÇÁ˽âÖØ¶¨ÏòÕâôһ¼þÊÂÇéµÄ·¢Éú¡£Õ⻹ÊÇÓе㲻¾¡ÍêÃÀ£¬²»Í¬·¶³ëµÄñîºÏ»¹ÊÇ̫ǿ¡£¿ØÖÆÆ÷Æäʵ²»Ó¦¸ÃÈ¥¹ØÐÄÏìÓ¦»áÈçºÎ±»äÖȾ¡£In general it should operate only in terms of view names that have been injected into it.
+
+Ò»¸öÌØ±ðµÄÊÓͼÃûǰ׺ÄÜÍê³ÉÕâ¸ö½âñ`redirect:`¡£Èç¹û·µ»ØµÄÊÓͼÃûÖк¬ÓÐ`redirect:`ǰ׺£¬ÄÇô`UrlBasedViewResolver`£¨¼°ËüµÄËùÓÐ×ÓÀࣩ¾Í»á½ÓÊܵ½Õâ¸öÐźţ¬Òâʶµ½ÕâÀïÐèÒª·¢ÉúÖØ¶¨Ïò¡£È»ºóÊÓͼÃûʣϵIJ¿·Ö»á±»½âÎö³ÉÖØ¶¨ÏòURL¡£
+
+ÕâÖÖ·½Ê½Óëͨ¹ý¿ØÖÆÆ÷·µ»ØÒ»¸öÖØ¶¨ÏòÊÓͼ`RedirectView`Ëù´ïµ½µÄЧ¹ûÊÇÒ»ÑùµÄ£¬²»¹ýÕâÑùÒ»À´¿ØÖÆÆ÷¾Í¿ÉÒÔֻרעÓÚ´¦Àí²¢·µ»ØÂß¼ÊÓͼÃûÁË¡£Èç¹ûÂß¼ÊÓͼÃûÊÇÕâÑùµÄÐÎʽ£º`redirect:/myapp/some/resource`£¬ËûÃÇÖØ¶¨Ïò·¾¶½«ÒÔServletÉÏÏÂÎÄ×÷ΪÏà¶Ô·¾¶½øÐвéÕÒ£¬¶øÂß¼ÊÓͼÃûÈç¹ûÊÇÕâÑùµÄÐÎʽ£º`redirect:http://myhost.com/some/arbitrary/path`£¬ÄÇÃ´ÖØ¶¨ÏòURLʹÓõľÍÊǾø¶Ô·¾¶¡£
+
+×¢ÒâµÄÊÇ£¬Èç¹û¿ØÖÆÆ÷·½·¨×¢½âÁË`@ResponseStatus`£¬ÄÇôע½âÉèÖõÄ״̬ÂëÖµ»á¸²¸Ç`RedirectView`ÉèÖõÄÏìӦ״̬ÂëÖµ¡£
+
+## ÖØ¶¨Ïòǰ׺¡ª¡ªforward:
+
+¶ÔÓÚ×îÖջᱻ`UrlBasedViewResolver`»òÆä×ÓÀà½âÎöµÄÊÓͼÃû£¬Äã¿ÉÒÔʹÓÃÒ»¸öÌØÊâµÄǰ׺£º`forward:`¡£Õâ»áµ¼ÖÂÒ»¸ö`InternalResourceView`ÊÓͼ¶ÔÏóµÄ´´½¨£¨Ëü×îÖÕ»áµ÷ÓÃ`RequestDispatcher.forward()`·½·¨£©£¬ºóÕß»áÈÏΪÊÓͼÃûʣϵIJ¿·ÖÊÇÒ»¸öURL¡£Òò´Ë£¬Õâ¸öǰ׺ÔÚʹÓÃ`InternalResourceViewResolver`ºÍ`InternalResourceView`ʱ²¢Ã»ÓÐÌØ±ðµÄ×÷Ó㨱ÈÈç¶ÔÓÚJSPÀ´Ëµ£©¡£µ«µ±ÄãÖ÷ҪʹÓõÄÊÇÆäËûµÄÊÓͼ¼¼Êõ£¬¶øÓÖÏëÒªÇ¿ÖÆ°ÑÒ»¸ö×ÊԴת·¢¸øServlet/JSPÒýÇæ½øÐд¦Àíʱ£¬Õâ¸öǰ׺¿ÉÄܾͺÜÓÐÓ㨻òÕߣ¬ÄãÒ²¿ÉÄÜͬʱ´®Áª¶à¸öÊÓͼ½âÎöÆ÷£©¡£
+
+Óë`redirect:`ǰ׺һÑù£¬Èç¹û¿ØÖÆÆ÷ÖеÄÊÓͼÃûʹÓÃÁË`forward:`ǰ׺£¬¿ØÖÆÆ÷±¾Éí²¢²»»á·¢¾õÈκÎÒì³££¬Ëü¹Ø×¢µÄÈÔȻֻÊÇÈçºÎ´¦ÀíÏìÓ¦µÄÎÊÌâ¡£
+
+
+
+
+
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\277\207\346\273\244\345\231\250Filter.md" "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\277\207\346\273\244\345\231\250Filter.md"
new file mode 100644
index 0000000..440f4d4
--- /dev/null
+++ "b/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\277\207\346\273\244\345\231\250Filter.md"
@@ -0,0 +1,151 @@
+¼¯³ÉFilter
+
+ÔÚSpring MVCÖУ¬DispatcherServletÖ»ÐèÒª¹Ì¶¨ÅäÖõ½web.xmlÖУ¬Ê£ÏµĹ¤×÷Ö÷ÒªÊÇרעÓÚ±àдController¡£
+
+µ«ÊÇ£¬ÔÚServlet¹æ·¶ÖУ¬ÎÒÃÇ»¹¿ÉÒÔʹÓÃFilter¡£Èç¹ûÒªÔÚSpring MVCÖÐʹÓÃFilter£¬Ó¦¸ÃÔõô×ö£¿
+
+ÓеÄͯЬÔÚÉÏÒ»½ÚµÄWebÓ¦ÓÃÖпÉÄÜ·¢ÏÖÁË£¬Èç¹û×¢²áʱÊäÈëÖÐÎĻᵼÖÂÂÒÂ룬ÒòΪServletĬÈϰ´·ÇUTF-8±àÂë¶ÁÈ¡²ÎÊý¡£ÎªÁËÐÞ¸´ÕâÒ»ÎÊÌ⣬ÎÒÃÇ¿ÉÒÔ¼òµ¥µØÊ¹ÓÃÒ»¸öEncodingFilter£¬ÔÚÈ«¾Ö·¶Î§Àà¸øHttpServletRequestºÍHttpServletResponseÇ¿ÖÆÉèÖÃΪUTF-8±àÂë¡£
+
+¿ÉÒÔ×Ô¼º±àдһ¸öEncodingFilter£¬Ò²¿ÉÒÔÖ±½ÓʹÓÃSpring MVC×Ô´øµÄÒ»¸öCharacterEncodingFilter¡£ÅäÖÃFilterʱ£¬Ö»ÐèÔÚweb.xmlÖÐÉùÃ÷¼´¿É£º
+````
+
+
+ encodingFilter
+ org.springframework.web.filter.CharacterEncodingFilter
+
+ encoding
+ UTF-8
+
+
+ forceEncoding
+ true
+
+
+
+
+ encodingFilter
+ /*
+
+ ...
+
+````
+ÒòΪÕâÖÖFilterºÍÎÒÃÇÒµÎñ¹ØÏµ²»´ó£¬×¢Òâµ½CharacterEncodingFilterÆäʵºÍSpringµÄIoCÈÝÆ÷ûÓÐÈκιØÏµ£¬Á½Õß¾ù»¥²»ÖªÏþ¶Ô·½µÄ´æÔÚ£¬Òò´Ë£¬ÅäÖÃÕâÖÖFilterÊ®·Ö¼òµ¥¡£
+
+ÎÒÃÇÔÙ¿¼ÂÇÕâÑùÒ»¸öÎÊÌ⣺Èç¹ûÔÊÐíÓû§Ê¹ÓÃBasicģʽ½øÐÐÓû§ÑéÖ¤£¬¼´ÔÚHTTPÇëÇóÖÐÌí¼ÓÍ·Authorization: Basic email:password£¬Õâ¸öÐèÇóÈçºÎʵÏÖ£¿
+
+±àдһ¸öAuthFilterÊÇ×î¼òµ¥µÄʵÏÖ·½Ê½£º
+````
+@Component
+public class AuthFilter implements Filter {
+@Autowired
+UserService userService;
+
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ HttpServletRequest req = (HttpServletRequest) request;
+ // »ñÈ¡AuthorizationÍ·:
+ String authHeader = req.getHeader("Authorization");
+ if (authHeader != null && authHeader.startsWith("Basic ")) {
+ // ´ÓHeaderÖÐÌáÈ¡emailºÍpassword:
+ String email = prefixFrom(authHeader);
+ String password = suffixFrom(authHeader);
+ // 怬:
+ User user = userService.signin(email, password);
+ // ·ÅÈëSession:
+ req.getSession().setAttribute(UserController.KEY_USER, user);
+ }
+ // ¼ÌÐø´¦ÀíÇëÇó:
+ chain.doFilter(request, response);
+ }
+}
+````
+ÏÖÔÚÎÊÌâÀ´ÁË£ºÔÚSpringÖд´½¨µÄÕâ¸öAuthFilterÊÇÒ»¸öÆÕͨBean£¬ServletÈÝÆ÷²¢²»ÖªµÀ£¬ËùÒÔËü²»»áÆð×÷Óá£
+
+Èç¹ûÎÒÃÇÖ±½ÓÔÚweb.xmlÖÐÉùÃ÷Õâ¸öAuthFilter£¬×¢Òâµ½AuthFilterµÄʵÀý½«ÓÉServletÈÝÆ÷¶ø²»ÊÇSpringÈÝÆ÷³õʼ»¯£¬Òò´Ë£¬@Autowire¸ù±¾²»ÉúЧ£¬ÓÃÓڵǼµÄUserService³ÉÔ±±äÁ¿ÓÀÔ¶ÊÇnull¡£
+
+ËùÒÔ£¬µÃͨ¹ýÒ»ÖÖ·½Ê½£¬ÈÃServletÈÝÆ÷ʵÀý»¯µÄFilter£¬¼ä½ÓÒýÓÃSpringÈÝÆ÷ʵÀý»¯µÄAuthFilter¡£Spring MVCÌṩÁËÒ»¸öDelegatingFilterProxy£¬×¨ÃÅÀ´¸ÉÕâ¸öÊÂÇ飺
+````
+
+
+ authFilter
+ org.springframework.web.filter.DelegatingFilterProxy
+
+
+
+ authFilter
+ /*
+
+ ...
+
+````
+ÎÒÃÇÀ´¿´ÊµÏÖÔÀí£º
+
+ServletÈÝÆ÷´Óweb.xmlÖжÁÈ¡ÅäÖã¬ÊµÀý»¯DelegatingFilterProxy£¬×¢ÒâÃüÃûÊÇauthFilter£»
+SpringÈÝÆ÷ͨ¹ýɨÃè@ComponentʵÀý»¯AuthFilter¡£
+µ±DelegatingFilterProxyÉúЧºó£¬Ëü»á×Ô¶¯²éÕÒ×¢²áÔÚServletContextÉϵÄSpringÈÝÆ÷£¬ÔÙÊÔͼ´ÓÈÝÆ÷ÖвéÕÒÃûΪauthFilterµÄBean£¬Ò²¾ÍÊÇÎÒÃÇÓÃ@ComponentÉùÃ÷µÄAuthFilter¡£
+
+DelegatingFilterProxy½«ÇëÇó´úÀí¸øAuthFilter£¬ºËÐÄ´úÂëÈçÏ£º
+````
+public class DelegatingFilterProxy implements Filter {
+ private Filter delegate;
+ public void doFilter(...) throws ... {
+ if (delegate == null) {
+ delegate = findBeanFromSpringContainer();
+ }
+ delegate.doFilter(req, resp, chain);
+ }
+}
+````
+Õâ¾ÍÊÇÒ»¸ö´úÀíģʽµÄ¼òµ¥Ó¦Óá£ÎÒÃÇ»¸öͼ±íʾËüÃÇÖ®¼äµÄÒýÓùØÏµÈçÏ£º
+````
+©° ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©´ ©° ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤
+©°©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©´ ©°©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©´ ©¦
+©¦ ©¦DelegatingFilterProxy©¦©¤©¦©¤©¦©¤ ©¤>©¦AuthFilter ©¦
+©¸©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¼ ©¸©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¼ ©¦
+©¦ ©°©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©´ ©¦ ©¦ ©°©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©´
+©¦ DispatcherServlet ©¦©¤ ©¤ ©¤ ©¤>©¦Controllers©¦ ©¦
+©¦ ©¸©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¼ ©¦ ©¦ ©¸©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¤©¼
+©¦
+©¦ Servlet Container ©¦ ©¦ Spring Container
+©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¤ ©¼
+````
+Èç¹ûÔÚweb.xmlÖÐÅäÖõÄFilterÃû×ÖºÍSpringÈÝÆ÷µÄBeanµÄÃû×Ö²»Ò»Ö£¬ÄÇôÐèÒªÖ¸¶¨BeanµÄÃû×Ö£º
+````
+
+ basicAuthFilter
+ org.springframework.web.filter.DelegatingFilterProxy
+
+
+ targetBeanName
+ authFilter
+
+
+````
+ʵ¼ÊÓ¦ÓÃʱ£¬¾¡Á¿±£³ÖÃû×ÖÒ»Ö£¬ÒÔ¼õÉÙ²»±ØÒªµÄÅäÖá£
+
+ҪʹÓÃBasicģʽµÄÓû§ÈÏÖ¤£¬ÎÒÃÇ¿ÉÒÔʹÓÃcurlÃüÁî²âÊÔ¡£ÀýÈ磬Óû§µÇ¼ÃûÊÇtom@example.com£¬¿ÚÁîÊÇtomcat£¬ÄÇôÏȹ¹ÔìÒ»¸öʹÓÃURL±àÂëµÄÓû§Ãû:¿ÚÁîµÄ×Ö·û´®£º
+
+tom%40example.com:tomcat
+¶ÔÆä½øÐÐBase64±àÂ룬×îÖÕ¹¹Ôì³öµÄHeaderÈçÏ£º
+
+Authorization: Basic dG9tJTQwZXhhbXBsZS5jb206dG9tY2F0
+ʹÓÃÈçϵÄcurlÃüÁî²¢»ñµÃÏìÓ¦ÈçÏ£º
+````
+$ curl -v -H 'Authorization: Basic dG9tJTQwZXhhbXBsZS5jb206dG9tY2F0' http://localhost:8080/profile
+> GET /profile HTTP/1.1
+> Host: localhost:8080
+> User-Agent: curl/7.64.1
+> Accept: */*
+> Authorization: Basic dG9tJTQwZXhhbXBsZS5jb206dG9tY2F0
+>
+< HTTP/1.1 200
+< Set-Cookie: JSESSIONID=CE0F4BFC394816F717443397D4FEABBE; Path=/; HttpOnly
+< Content-Type: text/html;charset=UTF-8
+< Content-Language: en-CN
+< Transfer-Encoding: chunked
+< Date: Wed, 29 Apr 2020 00:15:50 GMT
+<
+
+````
+...HTMLÊä³ö...
+ÉÏÊöÏìӦ˵Ã÷AuthFilterÒÑÉúЧ¡£
\ No newline at end of file
diff --git "a/docs/spring/SpringMVC/SpringMVC\345\237\272\346\234\254\344\273\213\347\273\215\344\270\216\345\277\253\351\200\237\345\205\245\351\227\250.md" "b/docs/spring/SpringMVC/SpringMVC\345\237\272\346\234\254\344\273\213\347\273\215\344\270\216\345\277\253\351\200\237\345\205\245\351\227\250.md"
new file mode 100644
index 0000000..21a9ea3
--- /dev/null
+++ "b/docs/spring/SpringMVC/SpringMVC\345\237\272\346\234\254\344\273\213\347\273\215\344\270\216\345\277\253\351\200\237\345\205\245\351\227\250.md"
@@ -0,0 +1,1153 @@
+
+
+
+
+## MVC Éè¼Æ¸ÅÊö
+
+ÔÚÔçÆÚ Java Web µÄ¿ª·¢ÖУ¬Í³Ò»°ÑÏÔʾ²ã¡¢¿ØÖƲ㡢Êý¾Ý²ãµÄ²Ù×÷È«²¿½»¸ø JSP »òÕß JavaBean À´½øÐд¦Àí£¬ÎÒÃdzÆÖ®Îª **Model1£º**
+
+
+
+
+
+
+
+
+
+
+
+* **³öÏֵı׶ˣº**
+* JSP ºÍ Java Bean Ö®¼äÑÏÖØñîºÏ£¬Java ´úÂëºÍ HTML ´úÂëÒ²ñîºÏÔÚÁËÒ»Æð
+* ÒªÇ󿪷¢Õß²»½öÒªÕÆÎÕ Java £¬»¹ÒªÓи߳¬µÄǰ¶Ëˮƽ
+* ǰ¶ËºÍºó¶ËÏ໥ÒÀÀµ£¬Ç°¶ËÐèÒªµÈ´ýºó¶ËÍê³É£¬ºó¶ËÒ²ÒÀÀµÇ°¶ËÍê³É£¬²ÅÄܽøÐÐÓÐЧµÄ²âÊÔ
+* ´úÂëÄÑÒÔ¸´ÓÃ
+
+ÕýÒòΪÉÏÃæµÄÖÖÖÖ±×¶Ë£¬ËùÒԺܿìÕâÖÖ·½Ê½¾Í±» Servlet + JSP + Java Bean ËùÌæ´úÁË£¬ÔçÆÚµÄ MVC Ä£ÐÍ**£¨Model2£©**¾ÍÏñÏÂͼÕâÑù£º
+
+
+
+
+
+
+
+
+
+
+
+Ê×ÏÈÓû§µÄÇëÇó»áµ½´ï Servlet£¬È»ºó¸ù¾ÝÇëÇóµ÷ÓÃÏàÓ¦µÄ Java Bean£¬²¢°ÑËùÓеÄÏÔʾ½á¹û½»¸ø JSP È¥Íê³É£¬ÕâÑùµÄģʽÎÒÃǾͳÆÎª MVC ģʽ¡£
+
+* **M ´ú±í Ä£ÐÍ£¨Model£©**
+ Ä£ÐÍÊÇÊ²Ã´ÄØ£¿ Ä£Ð;ÍÊÇÊý¾Ý£¬¾ÍÊÇ dao,bean
+* **V ´ú±í ÊÓͼ£¨View£©**
+ ÊÓͼÊÇÊ²Ã´ÄØ£¿ ¾ÍÊÇÍøÒ³, JSP£¬ÓÃÀ´Õ¹Ê¾Ä£ÐÍÖеÄÊý¾Ý
+* **C ´ú±í ¿ØÖÆÆ÷£¨controller)**
+ ¿ØÖÆÆ÷ÊÇʲô£¿ ¿ØÖÆÆ÷µÄ×÷ÓþÍÊǰѲ»Í¬µÄÊý¾Ý(Model)£¬ÏÔʾÔÚ²»Í¬µÄÊÓͼ(View)ÉÏ£¬Servlet °çÑݵľÍÊÇÕâÑùµÄ½ÇÉ«¡£
+
+> À©Õ¹ÔĶÁ£º[Web¿ª·¢Ä£Ê½](https://mp.weixin.qq.com/s?__biz=MzI4Njg5MDA5NA==&mid=2247483775&idx=1&sn=c9d7ead744c6e0c3ab2fe55c09bbe61f&chksm=ebd7407edca0c9688f3870d895b760836101271b912899821fb35c5704fe215da2fc5daff2f9#rd)
+
+#### Spring MVC µÄ¼Ü¹¹
+
+Ϊ½â¾ö³Ö¾Ã²ãÖÐһֱδ´¦ÀíºÃµÄÊý¾Ý¿âÊÂÎñµÄ±à³Ì£¬ÓÖΪÁËÓºÏ NoSQL µÄÇ¿ÊÆáÈÆð£¬Spring MVC ¸ø³öÁË·½°¸£º
+
+
+
+
+
+
+
+
+
+
+
+**´«Í³µÄÄ£ÐͲ㱻²ð·ÖΪÁËÒµÎñ²ã(Service)ºÍÊý¾Ý·ÃÎʲ㣨DAO,Data Access Object£©¡£** ÔÚ Service Ï¿ÉÒÔͨ¹ý Spring µÄÉùÃ÷ʽÊÂÎñ²Ù×÷Êý¾Ý·ÃÎʲ㣬¶øÔÚÒµÎñ²ãÉÏ»¹ÔÊÐíÎÒÃÇ·ÃÎÊ NoSQL £¬ÕâÑù¾ÍÄܹ»Âú×ãÒì¾üÍ»ÆðµÄ NoSQL µÄʹÓÃÁË£¬Ëü¿ÉÒÔ´ó´óÌá¸ß»¥ÁªÍøÏµÍ³µÄÐÔÄÜ¡£
+
+* **ÌØµã£º**
+ ½á¹¹ËÉÉ¢£¬¼¸ºõ¿ÉÒÔÔÚ Spring MVC ÖÐʹÓø÷ÀàÊÓͼ
+ ËÉñîºÏ£¬¸÷¸öÄ£¿é·ÖÀë
+ Óë Spring Î޷켯³É
+
+* * *
+
+## Hello Spring MVC
+
+ÈÃÎÒÃÇÀ´Ð´Ò»ÏÂÎÒÃǵĵÚÒ»¸ö Spring MVC ³ÌÐò£º
+
+#### µÚÒ»²½£ºÔÚ IDEA ÖÐн¨ Spring MVC ÏîÄ¿
+
+
+
+
+
+
+
+
+
+
+
+²¢ÇÒÈ¡ÃûΪ ¡¾HelloSpringMVC¡¿£¬µã»÷¡¾Finish¡¿£º
+
+
+
+
+
+
+
+
+
+
+
+IDEA »á×Ô¶¯°ïÎÒÃÇÏÂÔØºÃ±ØÒªµÄ jar °ü£¬²¢ÇÒΪÎÒÃÇ´´½¨ºÃһЩĬÈϵÄĿ¼ºÍÎļþ£¬´´½¨ºÃÒÔºóÏîÄ¿½á¹¹ÈçÏ£º
+
+
+
+
+
+
+
+
+
+
+
+#### µÚ¶þ²½£ºÐÞ¸Ä web.xml
+
+ÎÒÃÇ´ò¿ª web.xml £¬°´ÕÕÏÂͼÍê³ÉÐ޸ģº
+
+
+
+
+
+
+
+
+
+
+
+°Ñ``ÔªËØµÄÖµ¸ÄΪ / £¬±íʾҪÀ¹½ØËùÓеÄÇëÇ󣬲¢½»ÓÉSpring MVCµÄºǫ́¿ØÖÆÆ÷À´´¦Àí£¬¸ÄÍêÖ®ºó£º
+
+
+
+```
+
+ dispatcher
+ /
+
+
+```
+
+
+
+#### µÚÈý²½£º±à¼ dispatcher-servlet.xml
+
+Õâ¸öÎļþÃûµÄ¿ªÍ· dispatcher ÓëÉÏÃæ web.xml ÖÐµÄ `` ÔªËØÅäÖÃµÄ dispatcher ¶ÔÓ¦£¬ÕâÊÇ Spring MVC µÄÓ³ÉäÅäÖÃÎļþ£¨xxx-servlet.xml£©£¬ÎÒÃDZà¼ÈçÏ£º
+
+
+
+```
+
+
+
+
+
+
+
+ helloController
+
+
+
+
+
+
+```
+
+
+
+#### µÚËIJ½£º±àд HelloController
+
+ÔÚ Package¡¾controller¡¿Ï´´½¨ ¡¾HelloController¡¿À࣬²¢ÊµÏÖ org.springframework.web.servlet.mvc.Controller ½Ó¿Ú£º
+
+
+
+```
+package controller;
+
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.Controller;
+
+public class HelloController implements Controller{
+ @Override
+ public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
+ return null;
+ }
+}
+
+```
+
+
+
+* **³öÏÖÁËÎÊÌ⣺** javax.servlet °üÕÒ²»µ½
+* **½â¾ö£º** ½«±¾µØ Tomcat ·þÎñÆ÷µÄĿ¼Ï¡¾lib¡¿Îļþ¼ÐÏ嵀 servlet-api.jar °ü¿½±´µ½¹¤³Ì¡¾lib¡¿Îļþ¼ÐÏ£¬Ìí¼ÓÒÀÀµ
+
+Spring MVC ͨ¹ý ModelAndView ¶ÔÏó°ÑÄ£ÐͺÍÊÓͼ½áºÏÔÚÒ»Æð
+
+
+
+```
+ModelAndView mav = new ModelAndView("index.jsp");
+mav.addObject("message", "Hello Spring MVC");
+
+```
+
+
+
+ÕâÀï±íʾÊÓͼµÄÊÇindex.jsp
+Ä£ÐÍÊý¾ÝµÄÊÇ message£¬ÄÚÈÝÊÇ ¡°Hello Spring MVC¡±
+
+
+
+```
+package controller;
+
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.mvc.Controller;
+
+public class HelloController implements Controller {
+
+ public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
+ ModelAndView mav = new ModelAndView("index.jsp");
+ mav.addObject("message", "Hello Spring MVC");
+ return mav;
+ }
+}
+
+```
+
+
+
+#### µÚÎå²½£º×¼±¸ index.jsp
+
+½« index.jsp µÄÄÚÈÝÐÞ¸ÄΪ£º
+
+
+
+```
+<%@ page language="java" contentType="text/html; charset=UTF-8"
+ pageEncoding="UTF-8" isELIgnored="false"%>
+
+${message}
+
+```
+
+
+
+ÄÚÈݺܼòµ¥£¬ÓÃEl±í´ïʽÏÔʾ message µÄÄÚÈÝ¡£
+
+#### µÚÁù²½£º²¿Êð Tomcat ¼°Ïà¹Ø»·¾³
+
+ÔÚ¡¾Run¡¿²Ëµ¥ÏîÏÂÕÒµ½¡¾Edit Configurations¡¿
+
+
+
+
+
+
+
+
+
+
+
+ÅäÖà Tomcat »·¾³£º
+
+
+
+
+
+
+
+
+
+
+
+Ñ¡ÔñºÃ±¾µØµÄ Tomcat ·þÎñÆ÷£¬²¢¸ÄºÃÃû×Ö£º
+
+
+
+
+
+
+
+
+
+
+
+ÔÚ Deployment ±êǩҳÏÂÍê³ÉÈçϲÙ×÷£º
+
+
+
+
+
+
+
+
+
+
+
+µã»÷ OK ¾ÍºÃÁË£¬ÎÒÃǵã»÷ÓÒÉϽǵÄÈý½ÇÐν« Tomcat ·þÎñÆ÷ÔËÐÐÆðÀ´¡£
+
+* **³öÏÖµÄÎÊÌ⣺** Tomcat ·þÎñÆ÷ÎÞ·¨Õý³£Æô¶¯
+* **ÔÒò£º** Tomcat ·þÎñÆ÷ÕÒ²»µ½Ïà¹ØµÄ jar °ü
+* **½â¾ö·½·¨£º** ½«¡¾lib¡¿Îļþ¼ÐÕû¸ö¼ôÌùµ½¡¾WEB-INF¡¿Ï£¬²¢ÖØÐ½¨Á¢ÒÀÀµ£º
+
+
+
+
+
+
+
+
+
+
+
+#### µÚÆß²½£ºÖØÆô·þÎñÆ÷
+
+ÖØÆô·þÎñÆ÷£¬ÊäÈëµØÖ·£ºlocalhost/hello
+
+
+
+
+
+
+
+
+
+
+
+> ²Î¿¼×ÊÁÏ£º[Spring MVC ½Ì³Ì(how2j.cn)](http://how2j.cn/k/springmvc/springmvc-springmvc/615.html#step1891)
+
+* * *
+
+## ¸ú×Ù Spring MVC µÄÇëÇó
+
+ÿµ±Óû§ÔÚ Web ä¯ÀÀÆ÷Öеã»÷Á´½Ó»òÕßÌá½»±íµ¥µÄʱºò£¬ÇëÇó¾Í¿ªÊ¼¹¤×÷ÁË£¬ÏñÊÇÓʵÝÔ±Ò»Ñù£¬´ÓÀ뿪ä¯ÀÀÆ÷¿ªÊ¼µ½»ñÈ¡ÏìÓ¦·µ»Ø£¬Ëü»á¾ÀúºÜ¶àÕ¾µã£¬ÔÚÿһ¸öÕ¾µã¶¼»áÁôÏÂһЩÐÅϢͬʱҲ»á´øÉÏÆäËûÐÅÏ¢£¬ÏÂͼΪ Spring MVC µÄÇëÇóÁ÷³Ì£º
+
+
+
+
+
+
+
+
+
+
+
+#### µÚÒ»Õ¾£ºDispatcherServlet
+
+´ÓÇëÇóÀ뿪ä¯ÀÀÆ÷ÒԺ󣬵ÚÒ»Õ¾µ½´ïµÄ¾ÍÊÇ DispatcherServlet£¬¿´Ãû×ÖÕâÊÇÒ»¸ö Servlet£¬Í¨¹ý J2EE µÄѧϰ£¬ÎÒÃÇÖªµÀ Servlet ¿ÉÒÔÀ¹½Ø²¢´¦Àí HTTP ÇëÇó£¬DispatcherServlet »áÀ¹½ØËùÓеÄÇëÇ󣬲¢ÇÒ½«ÕâЩÇëÇó·¢Ë͸ø Spring MVC ¿ØÖÆÆ÷¡£
+
+
+
+```
+
+ dispatcher
+ org.springframework.web.servlet.DispatcherServlet
+ 1
+
+
+ dispatcher
+
+ /
+
+
+```
+
+
+
+* **DispatcherServlet µÄÈÎÎñ¾ÍÊÇÀ¹½ØÇëÇó·¢Ë͸ø Spring MVC ¿ØÖÆÆ÷¡£**
+
+#### µÚ¶þÕ¾£º´¦ÀíÆ÷Ó³É䣨HandlerMapping£©
+
+* **ÎÊÌ⣺** µäÐ͵ÄÓ¦ÓóÌÐòÖпÉÄÜ»áÓжà¸ö¿ØÖÆÆ÷£¬ÕâЩÇëÇóµ½µ×Ó¦¸Ã·¢¸øÄÄÒ»¸ö¿ØÖÆÆ÷ÄØ£¿
+
+ËùÒÔ DispatcherServlet »á²éѯһ¸ö»ò¶à¸ö´¦ÀíÆ÷Ó³ÉäÀ´È·¶¨ÇëÇóµÄÏÂÒ»Õ¾ÔÚÄÄÀ´¦ÀíÆ÷Ó³Éä»á**¸ù¾ÝÇëÇóËùЯ´øµÄ URL ÐÅÏ¢À´½øÐоö²ß**£¬ÀýÈçÉÏÃæµÄÀý×ÓÖУ¬ÎÒÃÇͨ¹ýÅäÖà simpleUrlHandlerMapping À´½« /hello µØÖ·½»¸ø helloController ´¦Àí£º
+
+
+
+```
+
+
+
+
+ helloController
+
+
+
+
+
+```
+
+
+
+#### µÚÈýÕ¾£º¿ØÖÆÆ÷
+
+Ò»µ©Ñ¡ÔñÁ˺ÏÊʵĿØÖÆÆ÷£¬ DispatcherServlet »á½«ÇëÇó·¢Ë͸øÑ¡ÖеĿØÖÆÆ÷£¬µ½ÁË¿ØÖÆÆ÷£¬ÇëÇó»áжÏÂÆä¸ºÔØ£¨Óû§Ìá½»µÄÇëÇ󣩵ȴý¿ØÖÆÆ÷´¦ÀíÍêÕâЩÐÅÏ¢£º
+
+
+
+```
+public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
+ // ´¦ÀíÂß¼
+ ....
+}
+
+```
+
+
+
+#### µÚËÄÕ¾£º·µ»Ø DispatcherServlet
+
+µ±¿ØÖÆÆ÷ÔÚÍê³ÉÂß¼´¦Àíºó£¬Í¨³£»á²úÉúһЩÐÅÏ¢£¬ÕâЩÐÅÏ¢¾ÍÊÇÐèÒª·µ»Ø¸øÓû§²¢ÔÚä¯ÀÀÆ÷ÉÏÏÔʾµÄÐÅÏ¢£¬ËüÃDZ»³ÆÎª**Ä£ÐÍ£¨Model£©**¡£½ö½ö·µ»ØÔʼµÄÐÅϢʱ²»¹»µÄ¡ª¡ªÕâЩÐÅÏ¢ÐèÒªÒÔÓû§ÓѺõķ½Ê½½øÐиñʽ»¯£¬Ò»°ã»áÊÇ HTML£¬ËùÒÔ£¬ÐÅÏ¢ÐèÒª·¢Ë͸øÒ»¸ö**ÊÓͼ£¨view£©**£¬Í¨³£»áÊÇ JSP¡£
+
+¿ØÖÆÆ÷Ëù×öµÄ×îºóÒ»¼þʾÍÊǽ«Ä£ÐÍÊý¾Ý´ò°ü£¬²¢ÇÒ±íʾ³öÓÃÓÚäÖȾÊä³öµÄÊÓͼÃû**£¨Âß¼ÊÓͼÃû£©¡£Ëü½ÓÏÂÀ´»á½«ÇëÇóÁ¬Í¬Ä£ÐͺÍÊÓͼÃû·¢ËÍ»Ø DispatcherServlet¡£**
+
+
+
+```
+public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
+ // ´¦ÀíÂß¼
+ ....
+ // ·µ»Ø¸ø DispatcherServlet
+ return mav;
+}
+
+```
+
+
+
+#### µÚÎåÕ¾£ºÊÓͼ½âÎöÆ÷
+
+ÕâÑùÒÔÀ´£¬¿ØÖÆÆ÷¾Í²»»áºÍÌØ¶¨µÄÊÓͼÏàñîºÏ£¬´«µÝ¸ø DispatcherServlet µÄÊÓͼÃû²¢²»Ö±½Ó±íʾij¸öÌØ¶¨µÄ JSP¡££¨Êµ¼ÊÉÏ£¬ËüÉõÖÁ²»ÄÜÈ·¶¨ÊÓͼ¾ÍÊÇ JSP£©Ïà·´£¬**Ëü´«µÝµÄ½ö½öÊÇÒ»¸öÂß¼Ãû³Æ£¬Õâ¸öÃû³Æ½«»áÓÃÀ´²éÕÒ²úÉú½á¹ûµÄÕæÕýÊÓͼ¡£**
+
+DispatcherServlet ½«»áʹÓÃÊÓͼ½âÎöÆ÷£¨view resolver£©À´½«Âß¼ÊÓͼÃûÆ¥ÅäΪһ¸öÌØ¶¨µÄÊÓͼʵÏÖ£¬Ëü¿ÉÄÜÊÇÒ²¿ÉÄܲ»ÊÇ JSP
+
+> ÉÏÃæµÄÀý×ÓÊÇÖ±½Ó°ó¶¨µ½ÁË index.jsp ÊÓͼ
+
+#### µÚÁùÕ¾£ºÊÓͼ
+
+¼ÈÈ» DispatcherServlet ÒѾ֪µÀÓÉÄĸöÊÓͼäÖȾ½á¹ûÁË£¬ÄÇÇëÇóµÄÈÎÎñ»ù±¾ÉÏÒ²¾ÍÍê³ÉÁË¡£
+
+ËüµÄ×îºóÒ»Õ¾ÊÇÊÓͼµÄʵÏÖ£¬ÔÚÕâÀïËü½»¸¶Ä£ÐÍÊý¾Ý£¬ÇëÇóµÄÈÎÎñÒ²¾ÍÍê³ÉÁË¡£ÊÓͼʹÓÃÄ£ÐÍÊý¾ÝäÖȾ³ö½á¹û£¬Õâ¸öÊä³ö½á¹û»áͨ¹ýÏìÓ¦¶ÔÏ󴫵ݸø¿Í»§¶Ë¡£
+
+
+
+```
+<%@ page language="java" contentType="text/html; charset=UTF-8"
+ pageEncoding="UTF-8" isELIgnored="false"%>
+
+${message}
+
+```
+
+
+
+* * *
+
+## ʹÓÃ×¢½âÅäÖà Spring MVC
+
+ÉÏÃæÎÒÃÇÒѾ¶Ô Spring MVC ÓÐÁËÒ»¶¨µÄÁ˽⣬²¢ÇÒͨ¹ý XML ÅäÖõķ½Ê½´´½¨Á˵ÚÒ»¸ö Spring MVC ³ÌÐò£¬ÎÒÃÇÀ´¿´¿´»ùÓÚ×¢½âÓ¦¸ÃÔõôÍê³ÉÉÏÊö³ÌÐòµÄÅäÖãº
+
+#### µÚÒ»²½£ºÎª HelloController Ìí¼Ó×¢½â
+
+
+
+```
+package controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.servlet.ModelAndView;
+
+@Controller
+public class HelloController{
+
+ @RequestMapping("/hello")
+ public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
+ ModelAndView mav = new ModelAndView("index.jsp");
+ mav.addObject("message", "Hello Spring MVC");
+ return mav;
+ }
+}
+
+```
+
+
+
+°ÑʵÏֵĽӿÚÒ²¸øÈ¥µô¡£
+
+* **¼òµ¥½âÊÍһϣº**
+* `@Controller` ×¢½â£º
+ ºÜÃ÷ÏÔ£¬Õâ¸ö×¢½âÊÇÓÃÀ´ÉùÃ÷¿ØÖÆÆ÷µÄ£¬µ«Êµ¼ÊÉÏÕâ¸ö×¢½â¶Ô Spring MVC ±¾ÉíµÄÓ°Ïì²¢²»´ó¡££¨Spring ʵս˵Ëü½ö½öÊǸ¨ÖúʵÏÖ×é¼þɨÃ裬¿ÉÒÔÓà `@Component` ×¢½â´úÌæ£¬µ«ÎÒ×Ô¼º³¢ÊÔÁËһϲ¢²»ÐУ¬ÒòΪÉÏÊöÀý×ÓûÓÐÅäÖà JSP ÊÓͼ½âÎöÆ÷ÎÒ»¹×Ô¼ºÅäÁËÒ»¸öÈÔûÓгɹ¦...£©
+* `@RequestMapping` ×¢½â£º
+ ºÜÏÔÈ»£¬Õâ¾Í±íʾ·¾¶ `/hello` »áÓ³Éäµ½¸Ã·½·¨ÉÏ
+
+#### µÚ¶þ²½£ºÈ¡Ïû֮ǰµÄ XML ×¢ÊÍ
+
+ÔÚ dispatcher-servlet.xml ÎļþÖУ¬×¢Ê͵ô֮ǰµÄÅäÖã¬È»ºóÔö¼ÓÒ»¾ä×é¼þɨÃ裺
+
+
+
+```
+
+
+
+
+ -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+
+
+#### µÚÈý²½£ºÖØÆô·þÎñÆ÷
+
+µ±ÅäÖÃÍê³É£¬ÖØÐÂÆô¶¯·þÎñÆ÷£¬ÊäÈë `localhost/hello` µØÖ·ÈÔÈ»ÄÜ¿´µ½Ð§¹û£º
+
+
+
+
+
+
+
+
+
+
+
+#### @RequestMapping ×¢½âϸ½Ú
+
+Èç¹û `@RequestMapping` ×÷ÓÃÔÚÀàÉÏ£¬ÄÇô¾ÍÏ൱ÓÚÊǸø¸ÃÀàËùÓÐÅäÖõÄÓ³ÉäµØÖ·Ç°¼ÓÉÏÁËÒ»¸öµØÖ·£¬ÀýÈ磺
+
+
+
+```
+@Controller
+@RequestMapping("/wmyskxz")
+public class HelloController {
+ @RequestMapping("/hello")
+ public ModelAndView handleRequest(....) throws Exception {
+ ....
+ }
+}
+
+```
+
+
+
+* Ôò·ÃÎʵØÖ·£º `localhost/wmyskxz/hello`
+
+* * *
+
+## ÅäÖÃÊÓͼ½âÎöÆ÷
+
+»¹¼ÇµÃÎÒÃÇ Spring MVC µÄÇëÇóÁ÷³ÌÂð£¬ÊÓͼ½âÎöÆ÷¸ºÔð¶¨Î»ÊÓͼ£¬Ëü½ÓÊÜÒ»¸öÓÉ DispaterServlet ´«µÝ¹ýÀ´µÄÂß¼ÊÓͼÃûÀ´Æ¥ÅäÒ»¸öÌØ¶¨µÄÊÓͼ¡£
+
+* **ÐèÇó£º** ÓÐÒ»Ð©Ò³ÃæÎÒÃDz»Ï£ÍûÓû§Óû§Ö±½Ó·ÃÎʵ½£¬ÀýÈçÓÐÖØÒªÊý¾ÝµÄÒ³Ãæ£¬ÀýÈçÓÐÄ£ÐÍÊý¾ÝÖ§³ÅµÄÒ³Ãæ¡£
+* **Ôì³ÉµÄÎÊÌ⣺**
+ ÎÒÃÇ¿ÉÒÔÔÚ¡¾web¡¿¸ùĿ¼Ï·ÅÖÃÒ»¸ö¡¾test.jsp¡¿Ä£ÄâÒ»¸öÖØÒªÊý¾ÝµÄÒ³Ãæ£¬ÎÒÃÇʲô¶¼²»ÓÃ×ö£¬ÖØÐÂÆô¶¯·þÎñÆ÷£¬ÍøÒ³ÖÐÊäÈë `localhost/test.jsp` ¾ÍÄܹ»Ö±½Ó·ÃÎʵ½ÁË£¬Õâ»áÔì³É**Êý¾Ýй¶**...
+ ÁíÍâÎÒÃÇ¿ÉÒÔÖ±½ÓÊäÈë `localhost/index.jsp` ÊÔÊÔ£¬¸ù¾ÝÎÒÃÇÉÏÃæµÄ³ÌÐò£¬Õâ»áÊÇÒ»¸ö¿Õ°×µÄÒ³Ãæ£¬ÒòΪ²¢Ã»ÓлñÈ¡µ½ `${message}` ²ÎÊý¾ÍÖ±½Ó·ÃÎÊÁË£¬Õâ»á**Ó°ÏìÓû§ÌåÑé**
+
+#### ½â¾ö·½°¸
+
+ÎÒÃǽ«ÎÒÃÇµÄ JSP ÎļþÅäÖÃÔÚ¡¾WEB-INF¡¿Îļþ¼ÐÖеġ¾page¡¿Îļþ¼ÐÏ£¬¡¾WEB-INF¡¿ÊÇ Java Web ÖÐĬÈϵݲȫĿ¼£¬ÊDz»ÔÊÐíÓû§Ö±½Ó·ÃÎʵÄ_£¨Ò²¾ÍÊÇÄã˵Äãͨ¹ý `localhost/WEB-INF/` ÕâÑùµÄ·½Ê½ÊÇÓÀÔ¶·ÃÎʲ»µ½µÄ£©_
+
+µ«ÊÇÎÒÃÇÐèÒª½«Õâ¸æË߸øÊÓͼ½âÎöÆ÷£¬ÎÒÃÇÔÚ dispatcher-servlet.xml ÎļþÖÐ×öÈçÏÂÅäÖãº
+
+
+
+```
+
+
+
+
+
+```
+
+
+
+ÕâÀïÅäÖÃÁËÒ»¸ö Spring MVC ÄÚÖõÄÒ»¸öÊÓͼ½âÎöÆ÷£¬¸Ã½âÎöÆ÷ÊÇ×ñÑ×ÅÒ»ÖÖÔ¼¶¨£º»á**ÔÚÊÓͼÃûÉÏÌí¼Óǰ׺ºÍºó׺£¬½ø¶øÈ·¶¨Ò»¸ö Web Ó¦ÓÃÖÐÊÓͼ×ÊÔ´µÄÎïÀí·¾¶µÄ¡£**ÈÃÎÒÃÇʵ¼ÊÀ´¿´¿´Ð§¹û£º
+
+#### µÚÒ»²½£ºÐÞ¸Ä HelloController
+
+ÎÒÃǽ«´úÂëÐÞ¸Äһϣº
+
+
+
+
+
+
+
+
+
+
+
+#### µÚ¶þ²½£ºÅäÖÃÊÓͼ½âÎöÆ÷£º
+
+°´ÕÕÉÏÊöµÄÅäÖã¬Íê³É£º
+
+
+
+```
+
+
+
+
+ -->
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+
+
+#### µÚÈý²½£º¼ôÌù index.jsp Îļþ
+
+ÔÚ¡¾WEB-INF¡¿Îļþ¼ÐÏÂн¨Ò»¸ö¡¾page¡¿Îļþ¼Ð£¬²¢½«¡¾index.jsp¡¿Îļþ¼ôÌùµ½ÀïÃæ£º
+
+
+
+
+
+
+
+
+
+
+
+#### µÚËIJ½£º¸üÐÂ×ÊÔ´ÖØÆô·þÎñÆ÷
+
+·ÃÎÊ `localhost/hello` ·¾¶£¬¿´µ½ÕýȷЧ¹û£º
+
+
+
+
+
+
+
+
+
+
+
+* **ÔÀí£º**
+
+
+
+
+
+
+
+
+
+
+
+ÎÒÃÇ´«ÈëµÄÂß¼ÊÓͼÃûΪ index £¬ÔÙ¼ÓÉÏ ¡°`/WEB-INF/page/`¡± ǰ׺ºÍ ¡°`.jsp`¡± ºó׺£¬¾ÍÄÜÈ·¶¨ÎïÀíÊÓͼµÄ·¾¶ÁË£¬ÕâÑùÎÒÃÇÒÔºó¾Í¿ÉÒÔ½«ËùÓеÄÊÓͼ·ÅÈ롾page¡¿Îļþ¼ÐÏÂÁË£¡
+
+* **×¢Ò⣺**´ËʱµÄÅäÖýöÊÇ dispatcher-servlet.xml ϵÄ
+
+* * *
+
+## ¿ØÖÆÆ÷½ÓÊÕÇëÇóÊý¾Ý
+
+ʹÓÿØÖÆÆ÷½ÓÊÕ²ÎÊýÍùÍùÊÇ Spring MVC ¿ª·¢ÒµÎñÂß¼µÄµÚÒ»²½£¬ÎªÌ½Ë÷ Spring MVC µÄ´«²Î·½Ê½£¬Îª´ËÎÒÃÇÏÈÀ´´´½¨Ò»¸ö¼òµ¥µÄ±íµ¥ÓÃÓÚÌá½»Êý¾Ý£º
+
+
+
+```
+
+<%@ page language="java" contentType="text/html; charset=UTF-8"
+ pageEncoding="UTF-8" import="java.util.*" isELIgnored="false"%>
+
+
+
+ Spring MVC ´«²Î·½Ê½
+
+
+
+
+
+
+```
+
+
+
+³ó¾Í³óµã¶ù°É£¬ÎÒÃǾÍÊÇÀ´²âÊÔһϣº
+
+
+
+
+
+
+
+
+
+
+
+#### ʹÓà Servlet ÔÉú API ʵÏÖ£º
+
+ÎÒÃǺÜÈÝÒ×ÖªµÀ£¬±íµ¥»áÌá½»µ½ `/param` Õâ¸öĿ¼£¬ÎÒÃÇÏÈÀ´Ê¹Óà Servlet ÔÉúµÄ API À´¿´¿´Äܲ»ÄÜ»ñÈ¡µ½Êý¾Ý£º
+
+
+
+```
+@RequestMapping("/param")
+public ModelAndView getParam(HttpServletRequest request,
+ HttpServletResponse response) {
+ String userName = request.getParameter("userName");
+ String password = request.getParameter("password");
+
+ System.out.println(userName);
+ System.out.println(password);
+ return null;
+}
+
+```
+
+
+
+²âÊԳɹ¦£º
+
+
+
+
+
+
+
+
+
+
+
+#### ʹÓÃͬÃûÆ¥Å乿Ôò
+
+ÎÒÃÇ¿ÉÒÔ°Ñ·½·¨¶¨ÒåµÄÐβÎÃû×ÖÉèÖóɺÍǰ̨´«Èë²ÎÊýÃûÒ»ÑùµÄ·½·¨£¬À´»ñÈ¡µ½Êý¾Ý£¨Í¬ÃûÆ¥Å乿Ôò£©£º
+
+
+
+```
+@RequestMapping("/param")
+public ModelAndView getParam(String userName,
+ String password) {
+ System.out.println(userName);
+ System.out.println(password);
+ return null;
+}
+
+```
+
+
+
+²âÊԳɹ¦£º
+
+
+
+
+
+
+
+
+
+
+
+* **ÎÊÌ⣺** ÕâÑùÓÖ»áºÍǰ̨²úÉúºÜÇ¿µÄñîºÏ£¬ÕâÊÇÎÒÃDz»Ï£ÍûµÄ
+* **½â¾ö£º** ʹÓà `@RequestParam("ǰ̨²ÎÊýÃû")` À´×¢È룺
+
+
+
+
+
+
+
+
+
+
+
+* **`@RequestParam` ×¢½âϸ½Ú£º**
+ ¸Ã×¢½âÓÐÈý¸ö±äÁ¿£º`value`¡¢`required`¡¢`defaultvalue`
+* `value` £ºÖ¸¶¨ `name` ÊôÐÔµÄÃû³ÆÊÇʲô£¬`value` ÊôÐÔ¶¼¿ÉÒÔĬÈϲ»Ð´
+* `required` £ºÊÇ·ñ±ØÐëÒªÓиòÎÊý£¬¿ÉÒÔÉèÖÃΪ¡¾true¡¿»òÕß¡¾false¡¿
+* `defaultvalue` £ºÉèÖÃĬÈÏÖµ
+
+#### ʹÓÃÄ£ÐÍ´«²Î
+
+* **ÒªÇó£º Ç°Ì¨²ÎÊýÃû×Ö±ØÐëºÍÄ£ÐÍÖеÄ×Ö¶ÎÃûÒ»Ñù**
+
+ÈÃÎÒÃÇÏÈÀ´ÎªÎÒÃÇµÄ±íµ¥´´½¨Ò»¸ö User Ä£ÐÍ£º
+
+
+
+```
+package pojo;
+
+public class User {
+
+ String userName;
+ String password;
+
+ /* getter and setter */
+}
+
+```
+
+
+
+È»ºó²âÊÔÈÔÈ»³É¹¦£º
+
+
+
+
+
+
+
+
+
+
+
+#### ÖÐÎÄÂÒÂëÎÊÌâ
+
+* **×¢Ò⣺** ¸ú Servlet ÖеÄÒ»Ñù£¬¸Ã·½·¨Ö»¶Ô POST ·½·¨ÓÐЧ£¨ÒòΪÊÇÖ±½Ó´¦ÀíµÄ request£©
+
+ÎÒÃÇ¿ÉÒÔͨ¹ýÅäÖà Spring MVC ×Ö·û±àÂë¹ýÂËÆ÷À´Íê³É£¬ÔÚ web.xml ÖÐÌí¼Ó£º
+
+
+
+```
+
+ CharacterEncodingFilter
+ org.springframework.web.filter.CharacterEncodingFilter
+
+ encoding
+
+ utf-8
+
+
+
+ CharacterEncodingFilter
+ /*
+
+
+```
+
+
+
+* * *
+
+## ¿ØÖÆÆ÷»ØÏÔÊý¾Ý
+
+ͨ¹ýÉÏÃæ£¬ÎÒÃÇÖªµÀÁËÔõô½ÓÊÜÇëÇóÊý¾Ý£¬²¢Äܽâ¾ö POST ÂÒÂëµÄÎÊÌ⣬ÄÇôÎÒÃÇÔõô»ØÏÔÊý¾ÝÄØ£¿Îª´ËÎÒÃÇÔÚ¡¾page¡¿Ï´´½¨Ò»¸ö¡¾test2.jsp¡¿£º
+
+
+
+```
+
+<%@ page language="java" contentType="text/html; charset=UTF-8"
+ pageEncoding="UTF-8" import="java.util.*" isELIgnored="false" %>
+
+
+ Spring MVC Êý¾Ý»ØÏÔ
+
+
+»ØÏÔÊý¾Ý£º${message}
+
+
+
+```
+
+
+
+#### ʹÓà Servlet ÔÉú API À´ÊµÏÖ
+
+ÎÒÃÇÏÈÀ´²âÊÔһϠServlet ÔÉúµÄ API ÊÇ·ñÄÜÍê³ÉÕâ¸öÈÎÎñ£º
+
+
+
+```
+@RequestMapping("/value")
+public ModelAndView handleRequest(HttpServletRequest request,
+ HttpServletResponse response) {
+ request.setAttribute("message","³É¹¦£¡");
+ return new ModelAndView("test1");
+}
+
+```
+
+
+
+ÔÚä¯ÀÀÆ÷µØÖ·À¸ÖÐÊäÈ룺`localhost/value` ²âÊÔ
+
+
+
+
+
+
+
+
+
+
+
+#### ʹÓà Spring MVC ËùÌṩµÄ ModelAndView ¶ÔÏó
+
+
+
+
+
+
+
+
+
+
+
+#### ʹÓà Model ¶ÔÏó
+
+ÔÚ Spring MVC ÖУ¬ÎÒÃÇͨ³£¶¼ÊÇʹÓÃÕâÑùµÄ·½Ê½À´°ó¶¨Êý¾Ý£¬
+
+
+
+
+
+
+
+
+
+
+
+* **ʹÓà `@ModelAttribute` ×¢½â£º**
+
+
+
+```
+@ModelAttribute
+public void model(Model model) {
+ model.addAttribute("message", "×¢½â³É¹¦");
+}
+
+@RequestMapping("/value")
+public String handleRequest() {
+ return "test1";
+}
+
+```
+
+
+
+ÕâÑùд¾Í»áÔÚ·ÃÎÊ¿ØÖÆÆ÷·½·¨ handleRequest() ʱ£¬»áÊ×Ïȵ÷Óà model() ·½·¨½« `message` Ìí¼Ó½øÒ³Ãæ²ÎÊýÖÐÈ¥£¬ÔÚÊÓͼÖпÉÒÔÖ±½Óµ÷Ó㬵«ÊÇÕâÑùд»áµ¼Ö¸ÿØÖÆÆ÷ËùÓеķ½·¨¶¼»áÊ×Ïȵ÷Óà model() ·½·¨£¬µ«Í¬ÑùµÄÒ²ºÜ·½±ã£¬ÒòΪ¿ÉÒÔ¼ÓÈë¸÷ÖÖ¸÷ÑùµÄÊý¾Ý¡£
+
+* * *
+
+## ¿Í»§¶ËÌø×ª
+
+Ç°Ãæ²»¹ÜÊǵØÖ· `/hello` Ìø×ªµ½ index.jsp »¹ÊÇ `/test` Ìø×ªµ½ test.jsp£¬ÕâЩ¶¼ÊÇ·þÎñ¶ËµÄÌø×ª£¬Ò²¾ÍÊÇ `request.getRequestDispatcher("µØÖ·").forward(request, response);`
+
+ÄÇÎÒÃÇÈçºÎ½øÐпͻ§¶ËÌø×ªÄØ£¿ÎÒÃǼÌÐøÔÚ HelloController Öбàд£º
+
+
+
+```
+@RequestMapping("/hello")
+public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
+ ModelAndView mav = new ModelAndView("index");
+ mav.addObject("message", "Hello Spring MVC");
+ return mav;
+}
+
+@RequestMapping("/jump")
+public ModelAndView jump() {
+ ModelAndView mav = new ModelAndView("redirect:/hello");
+ return mav;
+}
+
+```
+
+
+
+ÎÒÃÇʹÓà `redirect:/hello` ¾Í±íʾÎÒÃÇÒªÌø×ªµ½ `/hello` Õâ¸ö·¾¶£¬ÎÒÃÇÖØÆô·þÎñÆ÷£¬ÔÚµØÖ·À¸ÖÐÊäÈ룺`localhost/jump` £¬»á×Ô¶¯Ìø×ªµ½ `/hello` ·¾¶Ï£º
+
+
+
+
+
+
+
+
+
+
+
+Ò²¿ÉÒÔÕâÑùÓãº
+
+
+
+```
+@RequestMapping("/jump")
+public String jump() {
+ return "redirect: ./hello";
+}
+
+```
+
+
+
+* * *
+
+## ÎļþÉÏ´«
+
+ÎÒÃÇÏÈÀ´»Ø¹Ëһϴ«Í³µÄÎļþÉÏ´«ºÍÏÂÔØ£º[ÕâÀï](https://www.jianshu.com/p/e7837435bf4c)
+
+ÎÒÃÇÔÙÀ´¿´Ò»ÏÂÔÚ Spring MVC ÖÐÈçºÎʵÏÖÎļþµÄÉÏ´«ºÍÏÂÔØ
+
+* **×¢Ò⣺** ÐèÒªÏȵ¼Èë `commons-io-1.3.2.jar` ºÍ `commons-fileupload-1.2.1.jar` Á½¸ö°ü
+
+#### µÚÒ»²½£ºÅäÖÃÉÏ´«½âÎöÆ÷
+
+ÔÚ dispatcher-servlet.xml ÖÐÐÂÔöÒ»¾ä£º
+
+
+
+```
+
+
+```
+
+
+
+¿ªÆô¶ÔÉÏ´«¹¦ÄܵÄÖ§³Ö
+
+#### µÚ¶þ²½£º±àд JSP
+
+ÎļþÃûΪ upload.jsp£¬ÈÔ´´½¨ÔÚ¡¾page¡¿Ï£º
+
+
+
+```
+<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+
+
+ ²âÊÔÎļþÉÏ´«
+
+
+
+
+
+
+```
+
+
+
+#### µÚÈý²½£º±àд¿ØÖÆÆ÷
+
+ÔÚ Package¡¾controller¡¿ÏÂн¨¡¾UploadController¡¿Àࣺ
+
+
+
+```
+package controller;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.ModelAndView;
+
+@Controller
+public class UploadController {
+
+ @RequestMapping("/upload")
+ public void upload(@RequestParam("picture") MultipartFile picture) throws Exception {
+ System.out.println(picture.getOriginalFilename());
+ }
+
+ @RequestMapping("/test2")
+ public ModelAndView upload() {
+ return new ModelAndView("upload");
+ }
+
+}
+
+```
+
+
+
+#### µÚËIJ½£º²âÊÔ
+
+ÔÚä¯ÀÀÆ÷µØÖ·À¸ÖÐÊäÈ룺`localhost/test2` £¬Ñ¡ÔñÎļþµã»÷ÉÏ´«£¬²âÊԳɹ¦£º
+
+
+
+
+
+
+
+
+
+
+
+* * *
+
+#### ²Î¿¼×ÊÁÏ£º
+
+* ¡¶Java EE »¥ÁªÍøÇáÁ¿¼¶¿ò¼ÜÕûºÏ¿ª·¢¡·
+* ¡¶Spring ʵս¡·
+* [How2j Spring MVC ϵÁн̳Ì](http://how2j.cn/k/springmvc/springmvc-springmvc/615.html)
+* È«ÄܵİٶȺÍÍòÄܵĴóÄÔ
+
+* * *
+
+> »¶Ó×ªÔØ£¬×ªÔØÇë×¢Ã÷³ö´¦£¡
+> ¼òÊéID£º[@ÎÒûÓÐÈý¿ÅÐÄÔà](https://www.jianshu.com/u/a40d61a49221)
+> github£º[wmyskxz](https://github.com/wmyskxz/)
+> »¶Ó¹Ø×¢¹«ÖÚ΢Ðźţºwmyskxz
+> ·ÖÏí×Ô¼ºµÄѧϰ & ѧϰ×ÊÁÏ & Éú»î
+> ÏëÒª½»Á÷µÄÅóÓÑÒ²¿ÉÒÔ¼ÓqqȺ£º3382693
+
+
+
+×÷ÕߣºÎÒûÓÐÈý¿ÅÐÄÔà
+Á´½Ó£ºhttps://www.jianshu.com/p/91a2d0a1e45a
+À´Ô´£º¼òÊé
+Öø×÷Ȩ¹é×÷ÕßËùÓС£ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£
\ No newline at end of file
diff --git "a/docs/spring/SpringMVC/SpringMVC\345\246\202\344\275\225\345\256\236\347\216\260\346\226\207\344\273\266\344\270\212\344\274\240.md" "b/docs/spring/SpringMVC/SpringMVC\345\246\202\344\275\225\345\256\236\347\216\260\346\226\207\344\273\266\344\270\212\344\274\240.md"
new file mode 100644
index 0000000..dd0b576
--- /dev/null
+++ "b/docs/spring/SpringMVC/SpringMVC\345\246\202\344\275\225\345\256\236\347\216\260\346\226\207\344\273\266\344\270\212\344\274\240.md"
@@ -0,0 +1,237 @@
+
+
+
+
+# Spring MVC ÎļþÉÏ´«¸ÅÊö
+
+
+
+
+
+
+
+
+
+
+SpringÄÚÖöԶà·ÉÏ´«µÄÖ§³Ö£¬×¨ÃÅÓÃÓÚ´¦ÀíwebÓ¦ÓÃÖеÄÎļþÉÏ´«¡£Äã¿ÉÒÔͨ¹ý×¢²áÒ»¸ö¿É²å°ÎµÄ`MultipartResolver`¶ÔÏóÀ´ÆôÓöÔÎļþ¶à·ÉÏ´«µÄÖ§³Ö¡£¸Ã½Ó¿ÚÔÚ¶¨ÒåÓÚ`org.springframework.web.multipart`°üÏ¡£SpringΪ[_Ò»°ãµÄÎļþÉÏ´«_](http://jakarta.apache.org/commons/fileupload)ÌṩÁË`MultipartResolver`½Ó¿ÚµÄÒ»¸öʵÏÖ£¬ÎªServlet 3.0¶à·ÇëÇóµÄת»»ÌṩÁËÁíÒ»¸öʵÏÖ¡£
+
+
+
+ĬÈÏÇé¿öÏ£¬SpringµÄ¶à·ÉÏ´«Ö§³ÖÊDz»¿ªÆôµÄ£¬ÒòΪÓÐЩ¿ª·¢ÕßÏ£ÍûÓÉ×Ô¼ºÀ´´¦Àí¶à·ÇëÇó¡£Èç¹ûÏëÆôÓÃSpringµÄ¶à·ÉÏ´«Ö§³Ö£¬ÄãÐèÒªÔÚwebÓ¦ÓõÄÉÏÏÂÎÄÖÐÌí¼ÓÒ»¸ö¶à·´«Êä½âÎöÆ÷¡£Ã¿¸ö½øÀ´µÄÇëÇ󣬽âÎöÆ÷¶¼»á¼ì²éÊDz»ÊÇÒ»¸ö¶à²¿·ÖÇëÇó¡£Èô·¢ÏÖÇëÇóÊÇÍêÕûµÄ£¬ÔòÇëÇó°´Õý³£Á÷³Ì±»´¦Àí£»Èç¹û·¢ÏÖÇëÇóÊÇÒ»¸ö¶à·ÇëÇó£¬ÔòÄãÔÚÉÏÏÂÎÄÖÐ×¢²áµÄ`MultipartResolver`½âÎöÆ÷»á±»ÓÃÀ´´¦Àí¸ÃÇëÇó¡£Ö®ºó£¬ÇëÇóÖеĶà·ÉÏ´«ÊôÐÔ¾ÍÓëÆäËûÊôÐÔÒ»Ñù±»Õý³£¶Ô´ýÁË¡£¡¾×îºóÒ»¾ä·µÄ²»ºÃ£¬multipart·Òë³É¶à·»¹ÊǶಿ·Ö»¹ÔÚÕå×ÃÖС£ÍûÔĶÁÕß×¢Òâ´Ë´¦¡£¡¿
+
+
+
+
+
+
+
+
+
+# Spring MVC ʹÓÃMultipartResolverÓëCommons FileUpload´«ÊäÎļþ
+
+
+
+2018-07-26 14:28 ¸üÐÂ
+
+
+
+
+
+
+
+ÏÂÃæµÄ´úÂëչʾÁËÈçºÎʹÓÃÒ»¸öͨÓõĶà·ÉÏ´«½âÎöÆ÷`CommonsMultipartResolver`£º
+
+
+
+```
+
+
+
+
+
+
+
+```
+
+µ±È»£¬ÒªÈöà·½âÎöÆ÷Õý³£¹¤×÷£¬ÄãÐèÒªÔÚclasspath·¾¶ÏÂ×¼±¸±ØÐëµÄjar°ü¡£Èç¹ûʹÓõÄÊÇͨÓõĶà·ÉÏ´«½âÎöÆ÷`CommonsMultipartResolver`£¬ÄãËùÐèÒªµÄjar°üÊÇ`commons-fileupload.jar`¡£
+
+µ±SpringµÄ`DispatcherServlet`¼ì²âµ½Ò»¸ö¶à²¿·ÖÇëÇóʱ£¬Ëü»á¼¤»îÄãÔÚÉÏÏÂÎÄÖÐÉùÃ÷µÄ¶à·½âÎöÆ÷²¢°ÑÇëÇ󽻸øËü¡£½âÎöÆ÷»á°Ñµ±Ç°µÄ`HttpServletRequest`ÇëÇó¶ÔÏó°ü×°³ÉÒ»¸öÖ§³Ö¶à·ÎļþÉÏ´«µÄÇëÇó¶ÔÏó`MultipartHttpServletRequest`¡£ÓÐÁË`MultipartHttpServletRequest`¶ÔÏó£¬Äã²»½ö¿ÉÒÔ»ñÈ¡¸Ã¶à·ÇëÇóÖеÄÐÅÏ¢£¬»¹¿ÉÒÔÔÚÄãµÄ¿ØÖÆÆ÷ÖлñµÃ¸Ã¶à·ÇëÇóµÄÄÚÈݱ¾Éí¡£
+
+
+
+
+
+
+
+
+
+# Spring MVC ´¦ÀíServlet 3.0ϵÄMultipartResolver
+
+
+
+2018-07-26 14:29 ¸üÐÂ
+
+
+
+
+
+
+
+ҪʹÓûùÓÚServlet 3.0µÄ¶à·´«Êäת»»¹¦ÄÜ£¬Äã±ØÐëÔÚ`web.xml`ÖÐΪ`DispatcherServlet`Ìí¼ÓÒ»¸ö`multipart-config`ÔªËØ£¬»òÕßͨ¹ýServlet±à³ÌµÄ·½·¨Ê¹ÓÃ`javax.servlet.MultipartConfigElement`½øÐÐ×¢²á£¬»òÄã×Ô¼º¶¨ÖÆÁË×Ô¼ºµÄServletÀ࣬ÄÇÄã±ØÐëʹÓÃ`javax.servlet.annotation.MultipartConfig`¶ÔÆä½øÐÐ×¢½â¡£ÆäËûÖîÈç×î´óÎļþ´óС»ò´æ´¢Î»ÖõÈÅäÖÃÑ¡Ïî¶¼±ØÐëÔÚÕâ¸öServlet¼¶±ð½øÐÐ×¢²á£¬ÒòΪServlet 3.0²»ÔÊÐíÔÚ½âÎöÆ÷MultipartResolverµÄ²ã¼¶ÅäÖÃÕâЩÐÅÏ¢¡£
+
+
+
+µ±Äãͨ¹ýÒÔÉÏÈÎÒ»ÖÖ·½Ê½ÆôÓÃÁËServlet 3.0¶à·´«Êäת»»¹¦ÄÜ£¬Äã¾Í¿ÉÒÔ°ÑÒ»¸ö`StandardServletMultipartResolver`½âÎöÆ÷Ìí¼Óµ½ÄãµÄSpringÅäÖÃÖÐÈ¥ÁË£º
+
+```
+
+
+```
+
+
+
+
+
+
+
+
+# Spring MVC ´¦Àí±íµ¥ÖеÄÎļþÉÏ´«
+
+
+
+2018-07-26 14:30 ¸üÐÂ
+
+
+
+
+
+
+
+µ±½âÎöÆ÷`MultipartResolver`Íê³É´¦Àíʱ£¬ÇëÇó±ã»áÏñÆäËûÇëÇóÒ»Ñù±»Õý³£Á÷³Ì´¦Àí¡£Ê×ÏÈ£¬´´½¨Ò»¸ö½ÓÊÜÎļþÉÏ´«µÄ±íµ¥½«ÔÊÐíÓÃÓÚÖ±½ÓÉÏ´«Õû¸ö±íµ¥¡£±àÂëÊôÐÔ£¨`enctype="multipart/form-data"`£©ÄÜÈÃä¯ÀÀÆ÷ÖªµÀÈçºÎ¶Ô¶à·ÉÏ´«ÇëÇóµÄ±íµ¥½øÐбàÂ루encode£©¡£
+
+
+
+```
+
+
+ Upload a file please
+
+
+ Please upload a file
+
+
+
+
+```
+
+ÏÂÒ»²½ÊÇ´´½¨Ò»¸öÄÜ´¦ÀíÎļþÉÏ´«µÄ¿ØÖÆÆ÷¡£ÕâÀïÐèÒªµÄ¿ØÖÆÆ÷Óë[Ò»°ã×¢½âÁË`@Controller`µÄ¿ØÖÆÆ÷](http://docs.spring.io/spring-framework/docs/4.2.4.RELEASE/spring-framework-reference/html/mvc.html#mvc-ann-controller)»ù±¾Ò»Ñù£¬³ýÁËËü½ÓÊܵķ½·¨²ÎÊýÀàÐÍÊÇ`MultipartHttpServletRequest`£¬»ò`MultipartFile`¡£
+
+```
+@Controller
+public class FileUploadController {
+
+ @RequestMapping(path = "/form", method = RequestMethod.POST)
+ public String handleFormUpload(@RequestParam("name") String name, @RequestParam("file") MultipartFile file) {
+
+ if (!file.isEmpty()) {
+ byte[] bytes = file.getBytes();
+ // store the bytes somewhere
+ return "redirect:uploadSuccess";
+ }
+
+ return "redirect:uploadFailure";
+ }
+
+}
+
+```
+
+ÇëÁôÒâ`@RequestParam`×¢½âÊÇÈçºÎ½«·½·¨²ÎÊý¶ÔÓ¦µ½±íµ¥Öе͍ÒåµÄÊäÈë×ֶεġ£ÔÚÉÏÃæµÄÀý×ÓÖУ¬ÎÒÃÇÄõ½ÁË`byte[]`ÎļþÊý¾Ý£¬Ö»ÊÇû¶ÔËü×öÈκÎÊ¡£ÔÚʵ¼ÊÓ¦ÓÃÖУ¬Äã¿ÉÄܻὫËü±£´æµ½Êý¾Ý¿â¡¢´æ´¢ÔÚÎļþϵͳÉÏ£¬»ò×öÆäËûµÄ´¦Àí¡£
+
+µ±Ê¹ÓÃServlet 3.0µÄ¶à·´«Êäת»»Ê±£¬ÄãÒ²¿ÉÒÔʹÓÃ`javax.servlet.http.Part`×÷Ϊ·½·¨²ÎÊý£º
+
+```
+@Controller
+public class FileUploadController {
+
+ @RequestMapping(path = "/form", method = RequestMethod.POST)
+ public String handleFormUpload(@RequestParam("name") String name, @RequestParam("file") Part file) {
+
+ InputStream inputStream = file.getInputStream();
+ // store bytes from uploaded file somewhere
+
+ return "redirect:uploadSuccess";
+ }
+
+}
+```
+
+
+
+
+
+
+
+
+
+# Spring MVC ´¦Àí¿Í»§¶Ë·¢ÆðµÄÎļþÉÏ´«ÇëÇó
+
+
+
+2018-07-26 14:30 ¸üÐÂ
+
+
+
+
+
+
+
+ÔÚʹÓÃÁËRESTful·þÎñµÄ³¡¾°Ï£¬·Çä¯ÀÀÆ÷µÄ¿Í»§¶ËÒ²¿ÉÒÔÖ±½ÓÌá½»¶à·ÎļþÇëÇó¡£ÉÏÒ»½Ú½²ÊöµÄËùÓÐÀý×ÓÓëÅäÖÃÔÚÕâÀïÒ²¶¼Í¬ÑùÊÊÓᣵ«Óëä¯ÀÀÆ÷²»Í¬µÄÊÇ£¬Ìá½»µÄÎļþºÍ¼òµ¥µÄ±íµ¥×ֶΣ¬¿Í»§¶Ë·¢Ë͵ÄÊý¾Ý¿ÉÒÔ¸ü¼Ó¸´ÔÓ£¬Êý¾Ý¿ÉÒÔÖ¸¶¨ÎªÄ³ÖÖÌØ¶¨µÄÄÚÈÝÀàÐÍ£¨content type£©¡ª¡ª±ÈÈ磬һ¸ö¶à·ÉÏ´«ÇëÇó¿ÉÄܵÚÒ»²¿·ÖÊǸöÎļþ£¬¶øµÚ¶þ²¿·ÖÊǸöJSON¸ñʽµÄÊý¾Ý£º
+
+
+
+```
+ POST /someUrl
+ Content-Type: multipart/mixed
+
+ --edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
+ Content-Disposition: form-data; name="meta-data"
+ Content-Type: application/json; charset=UTF-8
+ Content-Transfer-Encoding: 8bit
+
+ {
+ "name": "value"
+ }
+ --edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
+ Content-Disposition: form-data; name="file-data"; filename="file.properties"
+ Content-Type: text/xml
+ Content-Transfer-Encoding: 8bit
+ ... File Data ...
+
+```
+
+¶ÔÓÚÃû³ÆÎª`meta-data`µÄ²¿·Ö£¬Äã¿ÉÒÔͨ¹ý¿ØÖÆÆ÷·½·¨ÉϵÄ`@RequestParam("meta-data") String metadata`²ÎÊýÀ´»ñµÃ¡£µ«¶ÔÓÚÄDz¿·ÖÇëÇóÌåÖÐΪJSON¸ñʽÊý¾ÝµÄÇëÇó£¬Äã¿ÉÄܸüÏëͨ¹ý½ÓÊÜÒ»¸ö¶ÔÓ¦µÄÇ¿ÀàÐͶÔÏ󣬾ÍÏñ`@RequestBody`ͨ¹ý`HttpMessageConverter`½«Ò»°ãÇëÇóµÄÇëÇóÌåת»»³ÉÒ»¸ö¶ÔÏóÒ»Ñù¡£
+
+ÕâÊÇ¿ÉÄܵģ¬Äã¿ÉÒÔʹÓÃ`@RequestPart`×¢½âÀ´ÊµÏÖ£¬¶ø·Ç`@RequestParam`¡£¸Ã×¢½â½«Ê¹µÃÌØ¶¨¶à·ÇëÇóµÄÇëÇóÌå±»´«¸ø`HttpMessageConverter`£¬²¢ÇÒÔÚת»»Ê±¿¼ÂǶà·ÇëÇóÖв»Í¬µÄÄÚÈÝÀàÐͲÎÊý`'Content-Type'`£º
+
+```
+@RequestMapping(path = "/someUrl", method = RequestMethod.POST)
+public String onSubmit(@RequestPart("meta-data") MetaData metadata, @RequestPart("file-data") MultipartFile file) {
+
+ // ...
+
+}
+
+```
+
+Çë×¢Òâ`MultipartFile`·½·¨²ÎÊýÊÇÈçºÎÄܹ»ÔÚ`@RequestParam`»ò`@RequestPart`×¢½âÏ»¥Óõģ¬Á½ÖÖ·½·¨¶¼ÄÜÄõ½Êý¾Ý¡£µ«£¬ÕâÀïµÄ·½·¨²ÎÊý`@RequestPart("meta-data") MetaData`Ôò»áÒòΪÇëÇóÖеÄÄÚÈÝÀàÐÍÇëÇóÍ·`'Content-Type'`±»¶ÁÈë³ÉΪJSONÊý¾Ý£¬È»ºóÔÙͨ¹ý`MappingJackson2HttpMessageConverter`±»×ª»»³ÉÌØ¶¨µÄ¶ÔÏó¡£
+
+
+
+
+
+
diff --git "a/docs/spring/springMVC/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md" "b/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
similarity index 100%
rename from "docs/spring/springMVC/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
rename to "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
diff --git "a/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md" "b/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md"
similarity index 100%
rename from "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md"
rename to "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md"
diff --git "a/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md" "b/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md"
similarity index 100%
rename from "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md"
rename to "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md"
diff --git "a/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md" "b/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md"
rename to "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md"
diff --git "a/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md" "b/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md"
similarity index 100%
rename from "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md"
rename to "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md"
diff --git "a/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md" "b/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md"
similarity index 100%
rename from "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md"
rename to "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md"
diff --git "a/docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md" "b/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md"
similarity index 100%
rename from "docs/spring/springMVC/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md"
rename to "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md"
diff --git "a/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md" "b/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md"
index a77e4a0..de8dba7 100644
--- "a/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md"
+++ "b/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md"
@@ -1,6 +1,4 @@
-# Spring УÑé
-
-
+# Spring УÑé
Java API ¹æ·¶(`JSR303`)¶¨ÒåÁË`Bean`УÑéµÄ±ê×¼`validation-api`£¬µ«Ã»ÓÐÌṩʵÏÖ¡£`hibernate validation`ÊǶÔÕâ¸ö¹æ·¶µÄʵÏÖ£¬²¢Ôö¼ÓÁËУÑé×¢½âÈç`@Email`¡¢`@Length`µÈ¡£`Spring Validation`ÊǶÔ`hibernate validation`µÄ¶þ´Î·â×°£¬ÓÃÓÚÖ§³Ö`spring mvc`²ÎÊý×Ô¶¯Ð£Ñé¡£
@@ -108,7 +106,7 @@ public class ValidatorController {
-£¨3£©Èç¹ûÇëÇó²ÎÊý²»Âú×ãУÑ鹿Ôò£¬Ôò»áÅ׳ö?`ConstraintViolationException`?»ò?`MethodArgumentNotValidException`?Òì³£¡£
+£¨3£©Èç¹ûÇëÇó²ÎÊý²»Âú×ãУÑ鹿Ôò£¬Ôò»áÅ׳ö `ConstraintViolationException` »ò `MethodArgumentNotValidException` Òì³£¡£
### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E7%BB%9F%E4%B8%80%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86)ͳһÒì³£´¦Àí
@@ -324,7 +322,7 @@ public class UserDTO {
### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%A1%E9%AA%8C%E6%B3%A8%E8%A7%A3)×Ô¶¨ÒåУÑé×¢½â
-£¨1£©×Ô¶¨ÒåУÑé×¢½â?`@IsMobile`
+£¨1£©×Ô¶¨ÒåУÑé×¢½â `@IsMobile`
@@ -346,7 +344,7 @@ public @interface IsMobile {
-£¨2£©ÊµÏÖ?`ConstraintValidator`?½Ó¿Ú£¬±àд?`@IsMobile`?УÑé×¢½âµÄ½âÎöÆ÷
+£¨2£©ÊµÏÖ `ConstraintValidator` ½Ó¿Ú£¬±àд `@IsMobile` УÑé×¢½âµÄ½âÎöÆ÷
@@ -380,16 +378,16 @@ public class MobileValidator implements ConstraintValidator {
### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%A1%E9%AA%8C)×Ô¶¨ÒåУÑé
-¿ÉÒÔͨ¹ýʵÏÖ?`org.springframework.validation.Validator`?½Ó¿ÚÀ´×Ô¶¨ÒåУÑé¡£
+¿ÉÒÔͨ¹ýʵÏÖ `org.springframework.validation.Validator` ½Ó¿ÚÀ´×Ô¶¨ÒåУÑé¡£
ÓÐÒÔÏÂÒªµã
-* ʵÏÖ?`supports`?·½·¨
-* ʵÏÖ?`validate`?·½·¨
- * ͨ¹ý?`Errors`?¶ÔÏóÊÕ¼¯´íÎó
+* ʵÏÖ `supports` ·½·¨
+* ʵÏÖ `validate` ·½·¨
+ * ͨ¹ý `Errors` ¶ÔÏóÊÕ¼¯´íÎó
* `ObjectError`£º¶ÔÏó£¨Bean£©´íÎó£º
* `FieldError`£º¶ÔÏó£¨Bean£©ÊôÐÔ£¨Property£©´íÎó
- * ͨ¹ý?`ObjectError`?ºÍ?`FieldError`?¹ØÁª?`MessageSource`?ʵÏÖ»ñÈ¡×îÖյĴíÎóÎݸ
+ * ͨ¹ý `ObjectError` ºÍ `FieldError` ¹ØÁª `MessageSource` ʵÏÖ»ñÈ¡×îÖյĴíÎóÎݸ
@@ -513,8 +511,8 @@ public Validator validator() {
* ½Ó¿ÚÖ°Ôð
* Êý¾Ý°ó¶¨ºÍУÑé´íÎóÊÕ¼¯½Ó¿Ú£¬Óë Java Bean ºÍÆäÊôÐÔÓÐÇ¿¹ØÁªÐÔ
* ºËÐÄ·½·¨
- * `reject`?·½·¨£¨ÖØÔØ£©£ºÊÕ¼¯´íÎóÎݸ
- * `rejectValue`?·½·¨£¨ÖØÔØ£©£ºÊÕ¼¯¶ÔÏó×Ö¶ÎÖеĴíÎóÎݸ
+ * `reject` ·½·¨£¨ÖØÔØ£©£ºÊÕ¼¯´íÎóÎݸ
+ * `rejectValue` ·½·¨£¨ÖØÔØ£©£ºÊÕ¼¯¶ÔÏó×Ö¶ÎÖеĴíÎóÎݸ
* ÅäÌ××é¼þ
* Java Bean ´íÎóÃèÊö£º`org.springframework.validation.ObjectError`
* Java Bean ÊôÐÔ´íÎóÃèÊö£º`org.springframework.validation.FieldError`
@@ -532,7 +530,7 @@ Errors
#### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#requestbody-%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86)RequestBody ²ÎÊýУÑéʵÏÖÔÀí
-ÔÚ spring-mvc ÖУ¬`RequestResponseBodyMethodProcessor`?ÊÇÓÃÓÚ½âÎö?`@RequestBody`?±ê×¢µÄ²ÎÊýÒÔ¼°´¦Àí`@ResponseBody`?±ê×¢·½·¨µÄ·µ»ØÖµµÄ¡£ÆäÖУ¬Ö´ÐвÎÊýУÑéµÄÂß¼¿Ï¶¨¾ÍÔÚ½âÎö²ÎÊýµÄ·½·¨?`resolveArgument()`?ÖУº
+ÔÚ spring-mvc ÖУ¬`RequestResponseBodyMethodProcessor` ÊÇÓÃÓÚ½âÎö `@RequestBody` ±ê×¢µÄ²ÎÊýÒÔ¼°´¦Àí`@ResponseBody` ±ê×¢·½·¨µÄ·µ»ØÖµµÄ¡£ÆäÖУ¬Ö´ÐвÎÊýУÑéµÄÂß¼¿Ï¶¨¾ÍÔÚ½âÎö²ÎÊýµÄ·½·¨ `resolveArgument()` ÖУº
@@ -594,7 +592,7 @@ protected void validateIfApplicable(WebDataBinder binder, MethodParameter parame
-ÒÔÉÏ´úÂ룬¾Í½âÊÍÁË Spring ΪʲôÄÜͬʱ֧³Ö?`@Validated`¡¢`@Valid`?Á½¸ö×¢½â¡£
+ÒÔÉÏ´úÂ룬¾Í½âÊÍÁË Spring ΪʲôÄÜͬʱ֧³Ö `@Validated`¡¢`@Valid` Á½¸ö×¢½â¡£
½ÓÏÂÀ´£¬¿´Ò»Ï WebDataBinder.validate() µÄʵÏÖ£º
@@ -618,7 +616,7 @@ public void validate(Object target, Errors errors, Object... validationHints) {
#### [#](https://dunwu.github.io/spring-tutorial/pages/fe6aad/#%E6%96%B9%E6%B3%95%E7%BA%A7%E5%88%AB%E7%9A%84%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86)·½·¨¼¶±ðµÄ²ÎÊýУÑéʵÏÖÔÀí
-Spring Ö§³Ö¸ù¾Ý·½·¨È¥½øÐÐÀ¹½Ø¡¢Ð£Ñ飬ÔÀí¾ÍÔÚÓÚÓ¦ÓÃÁË AOP ¼¼Êõ¡£¾ßÌåÀ´Ëµ£¬ÊÇͨ¹ý?`MethodValidationPostProcessor`?¶¯Ì¬×¢²á AOP ÇÐÃæ£¬È»ºóʹÓÃ?`MethodValidationInterceptor`?¶ÔÇе㷽·¨Ö¯ÈëÔöÇ¿¡£
+Spring Ö§³Ö¸ù¾Ý·½·¨È¥½øÐÐÀ¹½Ø¡¢Ð£Ñ飬ÔÀí¾ÍÔÚÓÚÓ¦ÓÃÁË AOP ¼¼Êõ¡£¾ßÌåÀ´Ëµ£¬ÊÇͨ¹ý `MethodValidationPostProcessor` ¶¯Ì¬×¢²á AOP ÇÐÃæ£¬È»ºóʹÓà `MethodValidationInterceptor` ¶ÔÇе㷽·¨Ö¯ÈëÔöÇ¿¡£
@@ -642,7 +640,7 @@ public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvis
-½Ó×Å¿´Ò»ÏÂ?`MethodValidationInterceptor`£º
+½Ó×Å¿´Ò»Ï `MethodValidationInterceptor`£º
diff --git "a/docs/spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md" "b/docs/spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md"
index 2c2f21a..99987fa 100644
--- "a/docs/spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md"
+++ "b/docs/spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md"
@@ -65,17 +65,17 @@ public abstract class PropertySource {
#### ****getProperty()ÄÚ²¿Ö´ÐÐÂß¼****
-
+
Ò»°ã£¬_Environment_ ʵÏÖÀàÖлá³ÖÓÐÒ»¸ö`PropertyResolver`ÀàÐ͵ijÉÔ±±äÁ¿£¬½ø¶ø½»ÓÉ _PropertyResolver_ ¸ºÔðÖ´ÐÐ _getProperty()_ Âß¼¡£_PropertyResolver_ ʵÏÖÀàÖÐÓÖ»á³ÖÓÐÁ½¸ö³ÉÔ±±äÁ¿£¬·Ö±ðÊÇ£º`ConversionService`Óë`PropertySources`£»Ê×ÏÈ£¬_PropertyResolver_ ±éÀú `PropertySources` ÖÐµÄ _PropertySource_£¬»ñÈ¡ÔÉúÊôÐÔÖµ£»È»ºóίÅÉ _ConversionService_ ¶ÔÔÉúÊôÐÔÖµ½øÐÐÊý¾ÝÀàÐÍת»» (Èç¹ûÓбØÒªµÄ»°)¡£**ËäÈ» PropertySource ×ÔÉíÊǾ߱¸¸ù¾ÝÊôÐÔÃû»ñÈ¡ÊôÐÔÖµÕâÒ»ÄÜÁ¦µÄ£¬µ«²»¾ß±¸Õ¼Î»·û½âÎöÓëÀàÐÍת»»ÄÜÁ¦£¬ÓÚÊÇÔÚÖмäÒýÈë¾ß±¸ÕâÁ½ÖÖÄÜÁ¦µÄ PropertyResolver£¬ ÕâÒ²Ó¡Ö¤ÁËÒ»¸ö¶Î×Ó£ºÔÚ¼ÆËã»ú¿ÆÑ§ÖУ¬Ã»ÓÐʲôÎÊÌâÊÇÔÚÖмä¼ÓÒ»²ã½â¾ö²»Á˵ģ¬Èç¹ûÓУ¬ÄǾÍÔÙ¼ÓÒ»²ã**¡£
#### ****PropertySourceÄÚ²¿¸üÐÂÂß¼****
-
+
_Environment_ ʵÏÖÀàÖгýÁ˳ÖÓÐ`PropertyResolver`ÀàÐ͵ijÉÔ±±äÁ¿Í⣬»¹ÓÐÒ»¸ö`MutablePropertySources`ÀàÐ͵ijÉÔ±±äÁ¿£¬µ«²¢²»Ìṩֱ½Ó²Ù×÷¸Ã _MutablePropertySources_ µÄ·½·¨£¬ÎÒÃÇÖ»ÄÜͨ¹ý`getPropertySources()`·½·¨»ñÈ¡ _MutablePropertySources_ ʵÀý£¬È»ºó½èÖú _MutablePropertySources_ ÖеÄ`addFirst()`¡¢`addLast()`ºÍ`replace()`µÈ·½·¨È¥¸üР_PropertySource_¡£_MutablePropertySources_ ÊÇ _PropertySources_ Ψһһ¸öʵÏÖÀ࣬ÈçÏÂͼËùʾ£º
-
+
×ܵÄÀ´Ëµ£¬_Environment_ ÊÇ¶Ô _PropertySource_ ºÍ _Profile_ µÄ¶¥¼¶³éÏó£¬ÏÂÃæ½éÉÜ _Profile_ µÄ¸ÅÄî¡£µ±Ó¦ÓóÌÐòÐèÒª²¿Êðµ½²»Í¬µÄÔËÐл·¾³Ê±£¬Ò»Ð©ÊôÐÔÏîͨ³£»áÓÐËù²»Í¬£¬±ÈÈ磬Êý¾ÝÔ´ URL ÔÚ¿ª·¢»·¾³ºÍ²âÊÔ»·¾³¾Í»á²»Ò»Ñù¡£Spring ´Ó3.1°æ±¾¿ªÊ¼Ö§³Ö»ùÓÚ _Profile_ µÄÌõ¼þ»¯ÅäÖá£
@@ -198,7 +198,7 @@ public class ConditionEvaluator {
_Environment_ ÖеÄÕâЩ _PropertySource_ ¾¿¾¹ÓÐɶÓ𡣿µ±È»ÊÇΪÁËÌî³ä _Bean_ à¶£¬·Ï»°²»¶à˵£¬ÉÏͼ¡£
-
+
> ±ÊÕßÒÔǰ¶¼ÊÇÓà visio ºÍ processOn »Í¼£¬µÚÒ»´ÎÌåÑé draw.io£¬Ã»Ïëµ½Èç´ËÓÅÐ㣬ǿÁÒ°²ÀûÒ»²¨£¡
@@ -288,7 +288,7 @@ public class SpringApplication {
`getOrCreateEnvironment()`Ö÷Òª¸ºÔð¹¹½¨ _Environment_ ʵÀý¡£Èç¹ûµ±Ç°Ó¦ÓÃÊÇ»ùÓÚ`ͬ²½×èÈûI/O`Ä£Ð͵ģ¬Ôò _Environment_ Ñ¡ÓÃ`ApplicationServletEnvironment`£»Ïà·´µØ£¬Èç¹ûµ±Ç°Ó¦ÓÃÊÇ»ùÓÚ`Òì²½·Ç×èÈûI/O`Ä£Ð͵ģ¬Ôò _Environment_ Ñ¡ÓÃ`ApplicationReactiveWebEnvironment`¡£ÎÒÃǹ¤×÷Öлù±¾¶¼ÊÇ»ùÓÚ Spring MVC ¿ª·¢Ó¦Óã¬Spring MVC ÊÇÒ»¿î¹¹½¨ÓÚ`Servlet API`Ö®ÉÏ¡¢»ùÓÚͬ²½×èÈû I/O Ä£Ð͵ÄÖ÷Á÷ Java Web ¿ª·¢¿ò¼Ü£¬ÕâÖÖ I/O Ä£ÐÍÒâζ×ÅÒ»¸ö HTTP ÇëÇó¶ÔÓ¦Ò»¸öỊ̈߳¬¼´Ã¿Ò»¸ö HTTP ÇëÇó¶¼ÊÇÔÚ¸÷×ÔÏß³ÌÉÏÏÂÎÄÖÐÍê³É´¦ÀíµÄ¡£_ApplicationServletEnvironment_ ¼Ì³Ð¹ØÏµÈçÏÂͼËùʾ£º
-
+
´ÓÉÏͼ¿ÉÒÔ¿´³ö _ApplicationServletEnvironment_ ¼Ò×åÏ൱ÅÓ´ó£¬ÔÚÖ´ÐÐ _ApplicationServletEnvironment_ ¹¹Ôì·½·¨µÄʱºò±ØÈ»»á´¥·¢¸÷¼¶¸¸À๹Ôì·½·¨ÖеÄÂß¼£¬**ÒÀ´ÎΪ**£º
@@ -832,10 +832,6 @@ public class DefaultPropertyResolver implements EncryptablePropertyResolver {
×ܽáÐÔµÄÎÄ×־Ͳ»ÔÙ˵ÁË£¬±ÊÕßÏÖÔÚÎÄ˼Ȫӿ£¬·ñÔòÓÖÄÜË®300×Ö¡£×îºó£¬Ï£Íû´ó¼Ò¼ÇסÔÚµ±Ç° Spring Boot °æ±¾ÖУ¬ÓÉ`ApplicationServletEnvironment`°çÑÝ _Environment_£¬Æä×îÖÕ½«Î¯ÅÉ`ConfigurationPropertySourcesPropertyResolver`È¥»ñÈ¡ÊôÐÔÖµ¡£
-## 5 ²Î¿¼Îĵµ
-
-1. [docs.spring.io/spring-boot¡](https://link.juejin.cn?target=https%3A%2F%2Fdocs.spring.io%2Fspring-boot%2Fdocs%2F2.5.7%2Freference%2Fhtml%2Ffeatures.html "https://docs.spring.io/spring-boot/docs/2.5.7/reference/html/features.html")
-
×÷Õߣº³ÌÐòÔ³¶ÅСͷ
@@ -844,6 +840,7 @@ public class DefaultPropertyResolver implements EncryptablePropertyResolver {
Öø×÷Ȩ¹é×÷ÕßËùÓС£ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£
# ²Î¿¼ÎÄÕÂ
+
https://www.w3cschool.cn/wkspring
https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
diff --git "a/docs/spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md" "b/docs/spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md"
index 6acb8a1..98c55c3 100644
--- "a/docs/spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md"
+++ "b/docs/spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md"
@@ -18,7 +18,7 @@
## Spring ÖеÄʼþ´¦Àí
-ÄãÒѾ¿´µ½ÁËÔÚËùÓÐÕ½ÚÖÐ Spring µÄºËÐÄÊÇ?**ApplicationContext**£¬Ëü¸ºÔð¹ÜÀí beans µÄÍêÕûÉúÃüÖÜÆÚ¡£µ±¼ÓÔØ beans ʱ£¬ApplicationContext ·¢²¼Ä³Ð©ÀàÐ͵Äʼþ¡£ÀýÈ磬µ±ÉÏÏÂÎÄÆô¶¯Ê±£¬ContextStartedEvent ·¢²¼£¬µ±ÉÏÏÂÎÄֹͣʱ£¬ContextStoppedEvent ·¢²¼¡£
+ÄãÒѾ¿´µ½ÁËÔÚËùÓÐÕ½ÚÖÐ Spring µÄºËÐÄÊÇ **ApplicationContext**£¬Ëü¸ºÔð¹ÜÀí beans µÄÍêÕûÉúÃüÖÜÆÚ¡£µ±¼ÓÔØ beans ʱ£¬ApplicationContext ·¢²¼Ä³Ð©ÀàÐ͵Äʼþ¡£ÀýÈ磬µ±ÉÏÏÂÎÄÆô¶¯Ê±£¬ContextStartedEvent ·¢²¼£¬µ±ÉÏÏÂÎÄֹͣʱ£¬ContextStoppedEvent ·¢²¼¡£
ͨ¹ý ApplicationEvent ÀàºÍ ApplicationListener ½Ó¿ÚÀ´ÌṩÔÚ ApplicationContext Öд¦Àíʼþ¡£Èç¹ûÒ»¸ö bean ʵÏÖ ApplicationListener£¬ÄÇôÿ´Î ApplicationEvent ±»·¢²¼µ½ ApplicationContext ÉÏ£¬ÄǸö bean »á±»Í¨Öª¡£
@@ -36,19 +36,19 @@ Spring
## ¼àÌýÉÏÏÂÎÄʼþ
-ΪÁ˼àÌýÉÏÏÂÎÄʼþ£¬Ò»¸ö bean Ó¦¸ÃʵÏÖÖ»ÓÐÒ»¸ö·½·¨?**onApplicationEvent()**?µÄ ApplicationListener ½Ó¿Ú¡£Òò´Ë£¬ÎÒÃÇдһ¸öÀý×ÓÀ´¿´¿´Ê¼þÊÇÈçºÎ´«²¥µÄ£¬ÒÔ¼°ÈçºÎ¿ÉÒÔÓôúÂëÀ´Ö´ÐлùÓÚijЩʼþËùÐèµÄÈÎÎñ¡£
+ΪÁ˼àÌýÉÏÏÂÎÄʼþ£¬Ò»¸ö bean Ó¦¸ÃʵÏÖÖ»ÓÐÒ»¸ö·½·¨ **onApplicationEvent()** µÄ ApplicationListener ½Ó¿Ú¡£Òò´Ë£¬ÎÒÃÇдһ¸öÀý×ÓÀ´¿´¿´Ê¼þÊÇÈçºÎ´«²¥µÄ£¬ÒÔ¼°ÈçºÎ¿ÉÒÔÓôúÂëÀ´Ö´ÐлùÓÚijЩʼþËùÐèµÄÈÎÎñ¡£
ÈÃÎÒÃÇÔÚÇ¡µ±µÄλÖÃʹÓà Eclipse IDE£¬È»ºó°´ÕÕÏÂÃæµÄ²½ÖèÀ´´´½¨Ò»¸ö Spring Ó¦ÓóÌÐò£º
| ²½Öè | ÃèÊö |
| --- | --- |
-| 1 | ´´½¨Ò»¸öÃû³ÆÎª SpringExample µÄÏîÄ¿£¬²¢ÇÒÔÚ´´½¨ÏîÄ¿µÄ?**src**?Îļþ¼ÐÖд´½¨Ò»¸ö°ü com.tutorialspoint¡£ |
+| 1 | ´´½¨Ò»¸öÃû³ÆÎª SpringExample µÄÏîÄ¿£¬²¢ÇÒÔÚ´´½¨ÏîÄ¿µÄ **src** Îļþ¼ÐÖд´½¨Ò»¸ö°ü com.tutorialspoint¡£ |
| 2 | ʹÓà Add External JARs Ñ¡ÏÌí¼ÓËùÐèµÄ Spring ¿â£¬½âÊͼû Spring Hello World Example Õ½ڡ£ |
| 3 | ÔÚ com.tutorialspoint °üÖд´½¨ Java Àà HelloWorld¡¢CStartEventHandler¡¢CStopEventHandler ºÍ MainApp¡£ |
-| 4 | ÔÚ?**src**?Îļþ¼ÐÖд´½¨ Bean µÄÅäÖÃÎļþ Beans.xml¡£ |
+| 4 | ÔÚ **src** Îļþ¼ÐÖд´½¨ Bean µÄÅäÖÃÎļþ Beans.xml¡£ |
| 5 | ×îºóÒ»²½ÊÇ´´½¨µÄËùÓÐ Java ÎļþºÍ Bean ÅäÖÃÎļþµÄÄÚÈÝ£¬²¢ÔËÐÐÓ¦ÓóÌÐò£¬½âÊÍÈçÏÂËùʾ¡£ |
-ÕâÀïÊÇ?**HelloWorld.java**?ÎļþµÄÄÚÈÝ£º
+ÕâÀïÊÇ **HelloWorld.java** ÎļþµÄÄÚÈÝ£º
```
package com.tutorialspoint;
@@ -63,7 +63,7 @@ public class HelloWorld {
}
```
-ÏÂÃæÊÇ?**CStartEventHandler.java**?ÎļþµÄÄÚÈÝ£º
+ÏÂÃæÊÇ **CStartEventHandler.java** ÎļþµÄÄÚÈÝ£º
```
package com.tutorialspoint;
@@ -77,7 +77,7 @@ public class CStartEventHandler
}
```
-ÏÂÃæÊÇ?**CStopEventHandler.java**?ÎļþµÄÄÚÈÝ£º
+ÏÂÃæÊÇ **CStopEventHandler.java** ÎļþµÄÄÚÈÝ£º
```
package com.tutorialspoint;
@@ -91,7 +91,7 @@ public class CStopEventHandler
}
```
-ÏÂÃæÊÇ?**MainApp.java**?ÎļþµÄÄÚÈÝ£º
+ÏÂÃæÊÇ **MainApp.java** ÎļþµÄÄÚÈÝ£º
```
package com.tutorialspoint;
@@ -117,7 +117,7 @@ public class MainApp {
}
```
-ÏÂÃæÊÇÅäÖÃÎļþ?**Beans.xml**?Îļþ£º
+ÏÂÃæÊÇÅäÖÃÎļþ **Beans.xml** Îļþ£º
```
@@ -160,15 +160,15 @@ ContextStoppedEvent Received
| ²½Öè | ÃèÊö |
| --- | --- |
-| 1 | ´´½¨Ò»¸öÃû³ÆÎª SpringExample µÄÏîÄ¿£¬²¢ÇÒÔÚ´´½¨ÏîÄ¿µÄ?**src**?Îļþ¼ÐÖд´½¨Ò»¸ö°ü com.tutorialspoint¡£ |
+| 1 | ´´½¨Ò»¸öÃû³ÆÎª SpringExample µÄÏîÄ¿£¬²¢ÇÒÔÚ´´½¨ÏîÄ¿µÄ **src** Îļþ¼ÐÖд´½¨Ò»¸ö°ü com.tutorialspoint¡£ |
| 2 | ʹÓà Add External JARs Ñ¡ÏÌí¼ÓËùÐèµÄ Spring ¿â£¬½âÊͼû Spring Hello World Example Õ½ڡ£ |
-| 3 | ͨ¹ýÀ©Õ¹?**ApplicationEvent**,´´½¨Ò»¸öʼþÀà CustomEvent¡£Õâ¸öÀà±ØÐ붨ÒåÒ»¸öĬÈϵĹ¹Ô캯Êý£¬ËüÓ¦¸Ã´Ó ApplicationEvent ÀàÖм̳еĹ¹Ô캯Êý¡£ |
+| 3 | ͨ¹ýÀ©Õ¹ **ApplicationEvent**,´´½¨Ò»¸öʼþÀà CustomEvent¡£Õâ¸öÀà±ØÐ붨ÒåÒ»¸öĬÈϵĹ¹Ô캯Êý£¬ËüÓ¦¸Ã´Ó ApplicationEvent ÀàÖм̳еĹ¹Ô캯Êý¡£ |
| 4 | Ò»µ©¶¨ÒåʼþÀ࣬Äã¿ÉÒÔ´ÓÈκÎÀàÖз¢²¼Ëü£¬¼Ù¶¨ EventClassPublisher ʵÏÖÁË ApplicationEventPublisherAware¡£Ä㻹ÐèÒªÔÚ XML ÅäÖÃÎļþÖÐÉùÃ÷Õâ¸öÀà×÷Ϊһ¸ö bean£¬Ö®ËùÒÔÈÝÆ÷¿ÉÒÔʶ±ð bean ×÷Ϊʼþ·¢²¼Õߣ¬ÊÇÒòΪËüʵÏÖÁË ApplicationEventPublisherAware ½Ó¿Ú¡£ |
| 5 | ·¢²¼µÄʼþ¿ÉÒÔÔÚÒ»¸öÀàÖб»´¦Àí£¬¼Ù¶¨ EventClassHandler ʵÏÖÁË ApplicationListener ½Ó¿Ú£¬¶øÇÒʵÏÖÁË×Ô¶¨ÒåʼþµÄ onApplicationEvent ·½·¨¡£ |
-| 6 | ÔÚ?**src**?Îļþ¼ÐÖд´½¨ bean µÄÅäÖÃÎļþ Beans.xml ºÍ MainApp À࣬Ëü¿ÉÒÔ×÷Ϊһ¸ö Spring Ó¦ÓóÌÐòÀ´ÔËÐС£ |
+| 6 | ÔÚ **src** Îļþ¼ÐÖд´½¨ bean µÄÅäÖÃÎļþ Beans.xml ºÍ MainApp À࣬Ëü¿ÉÒÔ×÷Ϊһ¸ö Spring Ó¦ÓóÌÐòÀ´ÔËÐС£ |
| 7 | ×îºóÒ»²½ÊÇ´´½¨µÄËùÓÐ Java ÎļþºÍ Bean ÅäÖÃÎļþµÄÄÚÈÝ£¬²¢ÔËÐÐÓ¦ÓóÌÐò£¬½âÊÍÈçÏÂËùʾ¡£ |
-Õâ¸öÊÇ?**CustomEvent.java**?ÎļþµÄÄÚÈÝ£º
+Õâ¸öÊÇ **CustomEvent.java** ÎļþµÄÄÚÈÝ£º
```
package com.tutorialspoint;
@@ -184,7 +184,7 @@ public class CustomEvent extends ApplicationEvent{
```
-ÏÂÃæÊÇ?**CustomEventPublisher.java**?ÎļþµÄÄÚÈÝ£º
+ÏÂÃæÊÇ **CustomEventPublisher.java** ÎļþµÄÄÚÈÝ£º
```
package com.tutorialspoint;
@@ -204,7 +204,7 @@ public class CustomEventPublisher
}
```
-ÏÂÃæÊÇ?**CustomEventHandler.java**?ÎļþµÄÄÚÈÝ£º
+ÏÂÃæÊÇ **CustomEventHandler.java** ÎļþµÄÄÚÈÝ£º
```
package com.tutorialspoint;
@@ -217,7 +217,7 @@ public class CustomEventHandler
}
```
-ÏÂÃæÊÇ?**MainApp.java**?ÎļþµÄÄÚÈÝ£º
+ÏÂÃæÊÇ **MainApp.java** ÎļþµÄÄÚÈÝ£º
```
package com.tutorialspoint;
@@ -235,7 +235,7 @@ public class MainApp {
}
```
-ÏÂÃæÊÇÅäÖÃÎļþ?**Beans.xml**£º
+ÏÂÃæÊÇÅäÖÃÎļþ **Beans.xml**£º
```
diff --git "a/docs/spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md" "b/docs/spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md"
index 8589b50..4515cad 100644
--- "a/docs/spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md"
+++ "b/docs/spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md"
@@ -95,12 +95,12 @@ Spring Bean
| Spring ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
| --- | --- | --- |
-| `@Bean` | Ìæ»» XML ÔªËØ?`` | 3.0 |
-| `@DependsOn` | Ìæ´ú XML ÊôÐÔ?` ` | 3.0 |
-| `@Lazy` | Ìæ´ú XML ÊôÐÔ?` ` | 3.0 |
-| `@Primary` | Ìæ»» XML ÔªËØ?` ` | 3.0 |
-| `@Role` | Ìæ»» XML ÔªËØ?` ` | 3.1 |
-| `@Lookup` | Ìæ´ú XML ÊôÐÔ?`` | 4.1 |
+| `@Bean` | Ìæ»» XML ÔªËØ `` | 3.0 |
+| `@DependsOn` | Ìæ´ú XML ÊôÐÔ ` ` | 3.0 |
+| `@Lazy` | Ìæ´ú XML ÊôÐÔ ` ` | 3.0 |
+| `@Primary` | Ìæ»» XML ÔªËØ ` ` | 3.0 |
+| `@Role` | Ìæ»» XML ÔªËØ ` ` | 3.1 |
+| `@Lookup` | Ìæ´ú XML ÊôÐÔ `` | 4.1 |
Spring Bean ÒÀÀµ×¢Èë×¢½â
@@ -109,7 +109,7 @@ Spring Bean
| `@Autowired` | Bean ÒÀÀµ×¢È룬֧³Ö¶àÖÖÒÀÀµ²éÕÒ·½Ê½ | 2.5 |
| `@Qualifier` | ϸÁ£¶ÈµÄ @Autowired ÒÀÀµ²éÕÒ | 2.5 |
-?
+
| Java ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
| --- | --- | --- |
@@ -127,8 +127,8 @@ Spring Bean
| Spring ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
| --- | --- | --- |
-| @PostConstruct | Ìæ»» XML ÔªËØ? »ò InitializingBean | 2.5 |
-| @PreDestroy | Ìæ»» XML ÔªËØ? »ò DisposableBean | 2.5 |
+| @PostConstruct | Ìæ»» XML ÔªËØ »ò InitializingBean | 2.5 |
+| @PreDestroy | Ìæ»» XML ÔªËØ »ò DisposableBean | 2.5 |
Spring BeanDefinition ½âÎöÓë×¢²á
@@ -194,7 +194,7 @@ Spring IoC
| Spring ×¢½â | ³¡¾°ËµÃ÷ | Æðʼ°æ±¾ |
| --- | --- | --- |
-| @ImportResource | Ìæ»» XML ÔªËØ?`` | 3.0 |
+| @ImportResource | Ìæ»» XML ÔªËØ `` | 3.0 |
| @Import | µ¼Èë Configuration Class | 3.0 |
| @ComponentScan | ɨÃèÖ¸¶¨ package ϱê×¢ Spring ģʽע½âµÄÀà | 3.1 |
diff --git "a/docs/spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md" "b/docs/spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md"
index 85723ac..c247c82 100644
--- "a/docs/spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md"
+++ "b/docs/spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md"
@@ -8,7 +8,7 @@
½«¸Ã JAR °üµÄºó׺Ãû jar ¸Ä³É zip µÄÐÎʽºó£¬½âѹѹËõ°ü£¬½øÈë½âѹÎļþ¼ÐÖÐµÄ \org\springframework\transaction Ŀ¼ºó£¬¸ÃĿ¼ÖеÄÎļþÈçͼ 1 Ëùʾ¡£
-
+
ͼ 1 ÊÂÎñ¹ÜÀíºËÐĽӿÚ
ÔÚͼ 1 ÖУ¬·½¿òËù±ê×¢µÄÈý¸öÎļþ¾ÍÊDZ¾½Ú½«Òª½²½âµÄºËÐĽӿڡ£ÕâÈý¸öºËÐĽӿڵÄ×÷Óü°ÆäÌṩµÄ·½·¨ÈçÏ¡£
@@ -35,16 +35,15 @@ TransactionDefinition
ÔÚÉÏÊöÎå¸ö·½·¨µÄÃèÊöÖУ¬ÊÂÎñµÄ´«²¥ÐÐΪÊÇÖ¸ÔÚͬһ¸ö·½·¨ÖУ¬²»Í¬²Ù×÷ǰºóËùʹÓõÄÊÂÎñ¡£´«²¥ÐÐΪµÄÖÖÀàÈç±í 1 Ëùʾ¡£
-±í 1 ´«²¥ÐÐΪµÄÖÖÀà
-| ÊôÐÔÃû³Æ | Öµ | Ãè Êö |
-| --- | --- | --- |
-| PROPAGATION_REQUIRED | required | Ö§³Öµ±Ç°ÊÂÎñ¡£Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò B ÊÂÎñ½«Ö±½ÓʹÓ᣷ñÔò½«´´½¨ÐÂÊÂÎñ |
-| PROPAGATION_SUPPORTS | supports | Ö§³Öµ±Ç°ÊÂÎñ¡£Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò B ÊÂÎñ½«Ö±½ÓʹÓ᣷ñÔò½«ÒÔ·ÇÊÂÎñ״ִ̬ÐÐ |
-| PROPAGATION_MANDATORY | mandatory | Ö§³Öµ±Ç°ÊÂÎñ¡£Èç¹û A ·½·¨Ã»ÓÐÊÂÎñ£¬ÔòÅ׳öÒì³£ |
-| PROPAGATION_REQUIRES_NEW | requires_new | ½«´´½¨ÐµÄÊÂÎñ£¬Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò½« A ÊÂÎñ¹ÒÆð |
-| PROPAGATION_NOT_SUPPORTED | not_supported | ²»Ö§³Öµ±Ç°ÊÂÎñ£¬×ÜÊÇÒÔ·ÇÊÂÎñ״ִ̬ÐС£Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò½«Æä¹ÒÆð |
-| PROPAGATION_NEVER | never | ²»Ö§³Öµ±Ç°ÊÂÎñ£¬Èç¹û A ·½·¨ÔÚÊÂÎñÖУ¬ÔòÅ׳öÒì³£ |
-| PROPAGATION.NESTED | nested | ǶÌ×ÊÂÎñ£¬µ×²ã½«Ê¹Óà Savepoint ÐγÉǶÌ×ÊÂÎñ |
+| ÊôÐÔÃû³Æ | Öµ | Ãè Êö |
+| --- | --- | --- |
+| PROPAGATION_REQUIRED | required | Ö§³Öµ±Ç°ÊÂÎñ¡£Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò B ÊÂÎñ½«Ö±½ÓʹÓ᣷ñÔò½«´´½¨ÐÂÊÂÎñ |
+| PROPAGATION_SUPPORTS | supports | Ö§³Öµ±Ç°ÊÂÎñ¡£Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò B ÊÂÎñ½«Ö±½ÓʹÓ᣷ñÔò½«ÒÔ·ÇÊÂÎñ״ִ̬ÐÐ |
+| PROPAGATION_MANDATORY | mandatory | Ö§³Öµ±Ç°ÊÂÎñ¡£Èç¹û A ·½·¨Ã»ÓÐÊÂÎñ£¬ÔòÅ׳öÒì³£ |
+| PROPAGATION_REQUIRES_NEW | requires_new | ½«´´½¨ÐµÄÊÂÎñ£¬Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò½« A ÊÂÎñ¹ÒÆð |
+| PROPAGATION_NOT_SUPPORTED | not_supported | ²»Ö§³Öµ±Ç°ÊÂÎñ£¬×ÜÊÇÒÔ·ÇÊÂÎñ״ִ̬ÐС£Èç¹û A ·½·¨ÒѾÔÚÊÂÎñÖУ¬Ôò½«Æä¹ÒÆð |
+| PROPAGATION_NEVER | never | ²»Ö§³Öµ±Ç°ÊÂÎñ£¬Èç¹û A ·½·¨ÔÚÊÂÎñÖУ¬ÔòÅ׳öÒì³£ |
+| PROPAGATION.NESTED | nested | ǶÌ×ÊÂÎñ£¬µ×²ã½«Ê¹Óà Savepoint ÐγÉǶÌ×ÊÂÎñ |
ÔÚÊÂÎñ¹ÜÀí¹ý³ÌÖУ¬´«²¥ÐÐΪ¿ÉÒÔ¿ØÖÆÊÇ·ñÐèÒª´´½¨ÊÂÎñÒÔ¼°ÈçºÎ´´½¨ÊÂÎñ¡£
@@ -54,15 +53,15 @@ TransactionDefinition
TransactionStatus ½Ó¿ÚÊÇÊÂÎñµÄ״̬£¬ËüÃèÊöÁËijһʱ¼äµãÉÏÊÂÎñµÄ״̬ÐÅÏ¢¡£ÆäÖаüº¬Áù¸ö²Ù×÷£¬¾ßÌåÈç±í 2 Ëùʾ¡£
-±í 2 ÊÂÎñµÄ²Ù×÷
-| Ãû³Æ | ˵Ã÷ |
-| --- | --- |
-| void flush() | Ë¢ÐÂÊÂÎñ |
-| boolean hasSavepoint() | »ñÈ¡ÊÇ·ñ´æÔÚ±£´æµã |
-| boolean isCompleted() | »ñÈ¡ÊÂÎñÊÇ·ñÍê³É |
-| boolean isNewTransaction() | »ñÈ¡ÊÇ·ñÊÇÐÂÊÂÎñ |
-| boolean isRollbackOnly() | »ñÈ¡ÊÇ·ñ»Ø¹ö |
-| void setRollbackOnly() | ÉèÖÃÊÂÎñ»Ø¹ö |
+±í 2 ÊÂÎñµÄ²Ù×÷
+| Ãû³Æ | ˵Ã÷ |
+| --- | --- |
+| void flush() | Ë¢ÐÂÊÂÎñ |
+| boolean hasSavepoint() | »ñÈ¡ÊÇ·ñ´æÔÚ±£´æµã |
+| boolean isCompleted() | »ñÈ¡ÊÂÎñÊÇ·ñÍê³É |
+| boolean isNewTransaction() | »ñÈ¡ÊÇ·ñÊÇÐÂÊÂÎñ |
+| boolean isRollbackOnly() | »ñÈ¡ÊÇ·ñ»Ø¹ö |
+| void setRollbackOnly() | ÉèÖÃÊÂÎñ»Ø¹ö |
# SpringÉùÃ÷ʽÊÂÎñ¹ÜÀí£¨»ùÓÚXML·½Ê½ÊµÏÖ£©
@@ -81,7 +80,7 @@ Spring ʵ
ÔÚ MyEclipse Öд´½¨Ò»¸öÃûΪ springDemo03 µÄ Web ÏîÄ¿£¬½« Spring Ö§³ÖºÍÒÀÀµµÄ JAR °ü¸´ÖƵ½ Web ÏîÄ¿µÄ lib Ŀ¼ÖУ¬²¢Ìí¼Óµ½Àà·¾¶Ï¡£ËùÌí¼ÓµÄ JAR °üÈçͼ 1 Ëùʾ¡£
-
+
ͼ 1 ÐèÒªµ¼ÈëµÄJAR°ü
´Óͼ 1 ÖпÉÒÔ¿´³ö£¬ÕâÀïÔö¼Óµ¼ÈëÁË spring-tx-3.2.13.RELEASE.jar£¨ÊÂÎñ¹ÜÀí£©£¬ÒÔ¼° [MySQL](http://www.voidme.com/mysql) Çý¶¯¡¢JDBC ºÍ C3P0 µÄ JAR °ü¡£
@@ -90,77 +89,60 @@ Spring ʵ
ÔÚ MySQL Öд´½¨Ò»¸öÃûΪ spring µÄÊý¾Ý¿â£¬È»ºóÔÚ¸ÃÊý¾Ý¿âÖд´½¨Ò»¸ö account ±í£¬²¢Ïò±íÖвåÈëÁ½ÌõÊý¾Ý£¬Æä SQL Ö´ÐÐÓï¾äÈçÏÂËùʾ£º
- CREATE DATABASE spring;
-USE spring;
-CREATE TABLE account (
- id INT (11) PRIMARY KEY AUTO_INCREMENT,
- username VARCHAR(20) NOT NULL,
- money INT DEFAULT NULL
-);
-INSERT INTO account VALUES (1,'zhangsan',1000);
-INSERT INTO account VALUES (2,'lisi',1000);
+CREATE DATABASE spring;
+USE spring;
+CREATE TABLE account (
+id INT (11) PRIMARY KEY AUTO_INCREMENT,
+username VARCHAR(20) NOT NULL,
+money INT DEFAULT NULL
+);
+INSERT INTO account VALUES (1,'zhangsan',1000);
+INSERT INTO account VALUES (2,'lisi',1000);
Ö´ÐкóµÄ account ±íÖеÄÊý¾ÝÈçͼ 2 Ëùʾ¡£
-
+
ͼ 2 Ö´Ðнá¹û
#### 3\. ´´½¨ c3p0-db.properties
ÔÚÏîÄ¿µÄ src Ï´´½¨Ò»¸öÃûΪ c3p0-db.properties µÄÅäÖÃÎļþ£¬ÕâÀïʹÓà C3P0 Êý¾ÝÔ´£¬ÐèÒªÔÚ¸ÃÎļþÖÐÌí¼ÓÈçÏÂÅäÖãº
-
-jdbc.driverClass = com.mysql.jdbc.Driver
-jdbc.jdbcUrl = jdbc:mysql://localhost:3306/spring
-jdbc.user = root
-jdbc.password = root
-
+````
+jdbc.driverClass = com.mysql.jdbc.Driver
+jdbc.jdbcUrl = jdbc:mysql://localhost:3306/spring
+jdbc.user = root
+jdbc.password = root
+````
#### 4\. ʵÏÖ DAO
#### 1£©´´½¨ AccountDao ½Ó¿Ú
ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨Ò»¸öÃûΪ com.mengma.dao µÄ°ü£¬ÔڸðüÏ´´½¨Ò»¸ö½Ó¿Ú AccountDao£¬²¢ÔÚ½Ó¿ÚÖд´½¨»ã¿îºÍÊÕ¿îµÄ·½·¨£¬ÈçÏÂËùʾ¡£
-
- package com.mengma.dao;
-
-public interface AccountDao {
- // »ã¿î
- public void out(String outUser, int money);
-
- // ÊÕ¿î
- public void in(String inUser, int money);
-}
-
-ÉÏÊö´úÂëÖУ¬¶¨ÒåÁË out() ºÍ in() Á½¸ö·½·¨£¬·Ö±ðÓÃÓÚ±íʾ»ã¿îºÍÊÕ¿î¡£
-
-#### 2£©´´½¨DAO²ã½Ó¿ÚʵÏÖÀà
-
-ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨Ò»¸öÃûΪ com.mengma.dao.impl µÄ°ü£¬ÔڸðüÏ´´½¨ÊµÏÖÀà AccountDaoImpl£¬ÈçÏÂËùʾ¡£
-
- package com.mengma.dao.impl;
-
-import org.springframework.jdbc.core.JdbcTemplate;
+````
+package com.mengma.dao;
+public interface AccountDao {
+ // »ã¿î
+ public void out(String outUser, int money);
+ // ÊÕ¿î
+ public void in(String inUser, int money);} ````
+ÉÏÊö´úÂëÖУ¬¶¨ÒåÁË out() ºÍ in() Á½¸ö·½·¨£¬·Ö±ðÓÃÓÚ±íʾ»ã¿îºÍÊÕ¿î¡£
+
+#### 2£©´´½¨DAO²ã½Ó¿ÚʵÏÖÀà
+
+ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨Ò»¸öÃûΪ com.mengma.dao.impl µÄ°ü£¬ÔڸðüÏ´´½¨ÊµÏÖÀà AccountDaoImpl£¬ÈçÏÂËùʾ¡£
+````
+package com.mengma.dao.impl;
+
+import org.springframework.jdbc.core.JdbcTemplate;
import com.mengma.dao.AccountDao;
-public class AccountDaoImpl implements AccountDao {
- private JdbcTemplate jdbcTemplate;
-
- public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
- this.jdbcTemplate = jdbcTemplate;
- }
-
- // »ã¿îµÄʵÏÖ·½·¨
- public void out(String outUser, int money) {
- this.jdbcTemplate.update("update account set money =money-?"
- + "where username =?", money, outUser);
- }
-
- // ÊÕ¿îµÄʵÏÖ·½·¨
- public void in(String inUser, int money) {
- this.jdbcTemplate.update("update account set money =money+?"
- + "where username =?", money, inUser);
- }
-}
-
+public class AccountDaoImpl implements AccountDao {
+private JdbcTemplate jdbcTemplate;
+public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; }
+// »ã¿îµÄʵÏÖ·½·¨
+public void out(String outUser, int money) { this.jdbcTemplate.update("update account set money =money-?" + "where username =?", money, outUser); }
+// ÊÕ¿îµÄʵÏÖ·½·¨
+public void in(String inUser, int money) { this.jdbcTemplate.update("update account set money =money+?" + "where username =?", money, inUser); }} ````
ÉÏÊö´úÂëÖУ¬Ê¹Óà JdbcTemplate ÀàµÄ update() ·½·¨ÊµÏÖÁ˸üвÙ×÷¡£
#### 5\. ʵÏÖ Service
@@ -168,220 +150,107 @@ public class AccountDaoImpl implements AccountDao {
#### 1£©´´½¨ Service ²ã½Ó¿Ú
ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨Ò»¸öÃûΪ com.mengma.service µÄ°ü£¬ÔڸðüÏ´´½¨½Ó¿Ú AccountService£¬ÈçÏÂËùʾ¡£
-
- package com.mengma.service;
-
-public interface AccountService {
- // תÕË
- public void transfer(String outUser, String inUser, int money);
-}
-
-#### 2£©´´½¨ Service ²ã½Ó¿ÚʵÏÖÀà
-
-ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨Ò»¸öÃûΪ com.mengma.service.impl µÄ°ü£¬ÔڸðüÏ´´½¨ÊµÏÖÀà AccountServiceImpl£¬ÈçÏÂËùʾ¡£
-
- package com.mengma.service.impl;
+````
+package com.mengma.service;
+
+public interface AccountService {
+ // תÕË
+ public void transfer(String outUser, String inUser, int money);} ````
+#### 2£©´´½¨ Service ²ã½Ó¿ÚʵÏÖÀà
+
+ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨Ò»¸öÃûΪ com.mengma.service.impl µÄ°ü£¬ÔڸðüÏ´´½¨ÊµÏÖÀà AccountServiceImpl£¬ÈçÏÂËùʾ¡£
+````
+package com.mengma.service.impl;
import com.mengma.dao.AccountDao;
-public class AccountServiceImpl {
- private AccountDao accountDao;
-
- public void setAccountDao(AccountDao accountDao) {
- this.accountDao = accountDao;
- }
-
- public void transfer(String outUser, String inUser, int money) {
- this.accountDao.out(outUser, money);
- this.accountDao.in(inUser, money);
- }
-}
-
+public class AccountServiceImpl {
+private AccountDao accountDao;
+public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; }
+public void transfer(String outUser, String inUser, int money) { this.accountDao.out(outUser, money); this.accountDao.in(inUser, money); }} ````
ÉÏÊö´úÂëÖпÉÒÔ¿´³ö£¬¸ÃÀàʵÏÖÁË AccountService ½Ó¿Ú£¬²¢¶ÔתÕ˵ķ½·¨½øÐÐÁËʵÏÖ£¬¸ù¾Ý²ÎÊýµÄ²»Í¬µ÷Óà DAO ²ãÏàÓ¦µÄ·½·¨¡£
#### 6\. ´´½¨ Spring ÅäÖÃÎļþ
ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨ Spirng ÅäÖÃÎļþ applicationContext.xml£¬±à¼ºóÈçÏÂËùʾ¡£
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-ÉÏÊö´úÂëÖУ¬Ê×ÏÈÔÚ ±ê¼ÇµÄµÚ 6¡¢13 ºÍ 14 ÐдúÂë·Ö±ðÌí¼ÓÁË AOP ËùÐèµÄÃüÃû¿Õ¼äÉùÃ÷¡£µÚ 42¡«50 ÐдúÂëʹÓà ±ê¼ÇÅäÖÃÊÂÎñ֪ͨÄÚÈÝ¡£
-
-µÚ 52¡«58 ÐдúÂëʹÓà ±ê¼Ç¶¨ÒåÇÐÃæ£¬ÆäÖÐµÚ 54 ÐдúÂëÓ¦ÓÃÁË AspectJ ±í´ïʽ£¬´ú±í com.mengma.service °üÏÂËùÓÐÀàµÄËùÓз½·¨¶¼Ó¦ÓÃÊÂÎñ¹æÔò£¬µÚ 57 ÐдúÂëʹÓà ±ê¼Ç½«ÇÐÈëµãÓëÊÂÎñ֪ͨÕûºÏ£¬»ùÓÚ AOP µÄÉùÃ÷ʽÊÂÎñÅäÖÃÍê³É¡£
-
-#### 7\. ´´½¨²âÊÔÀà
-
-ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨ com.mengma.test µÄ°ü£¬ÔڸðüÏ´´½¨²âÊÔÀà AccountTest£¬ÈçÏÂËùʾ¡£
-
- package com.mengma.test;
-import org.junit.Test;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.support.ClassPathXmlApplicationContext;
-import com.mengma.service.AccountService;
-public class AccountTest {
- @Test
- public void test() {
- // »ñµÃSpringÈÝÆ÷£¬²¢²Ù×÷
- String xmlPath = "applicationContext.xml";
- ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
- xmlPath);
- AccountService accountService = (AccountService) applicationContext
- .getBean("accountService");
- accountService.transfer("zhangsan", "lisi", 100);
- }
-}
-
+````
+
+
+ ````
+ÉÏÊö´úÂëÖУ¬Ê×ÏÈÔÚ ±ê¼ÇµÄµÚ 6¡¢13 ºÍ 14 ÐдúÂë·Ö±ðÌí¼ÓÁË AOP ËùÐèµÄÃüÃû¿Õ¼äÉùÃ÷¡£µÚ 42¡«50 ÐдúÂëʹÓà ±ê¼ÇÅäÖÃÊÂÎñ֪ͨÄÚÈÝ¡£
+
+µÚ 52¡«58 ÐдúÂëʹÓà ±ê¼Ç¶¨ÒåÇÐÃæ£¬ÆäÖÐµÚ 54 ÐдúÂëÓ¦ÓÃÁË AspectJ ±í´ïʽ£¬´ú±í com.mengma.service °üÏÂËùÓÐÀàµÄËùÓз½·¨¶¼Ó¦ÓÃÊÂÎñ¹æÔò£¬µÚ 57 ÐдúÂëʹÓà ±ê¼Ç½«ÇÐÈëµãÓëÊÂÎñ֪ͨÕûºÏ£¬»ùÓÚ AOP µÄÉùÃ÷ʽÊÂÎñÅäÖÃÍê³É¡£
+
+#### 7\. ´´½¨²âÊÔÀà
+
+ÔÚÏîÄ¿µÄ src Ŀ¼Ï´´½¨ com.mengma.test µÄ°ü£¬ÔڸðüÏ´´½¨²âÊÔÀà AccountTest£¬ÈçÏÂËùʾ¡£
+````
+package com.mengma.test;
+import org.junit.Test;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import com.mengma.service.AccountService;
+public class AccountTest {
+@Test public void test() { // »ñµÃSpringÈÝÆ÷£¬²¢²Ù×÷
+String xmlPath = "applicationContext.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext( xmlPath); AccountService accountService = (AccountService) applicationContext .getBean("accountService"); accountService.transfer("zhangsan", "lisi", 100); }} ````
ÉÏÊö´úÂëÖÐÄ£ÄâÁËÒøÐÐתÕËÒµÎñ£¬´Ó zhangsan µÄÕË»§Ïò lisi µÄÕË»§ÖÐתÈë 100 Ôª¡£Ê¹Óà JUnit ²âÊÔÔËÐÐ test() ·½·¨£¬ÔËÐгɹ¦ºó£¬²éѯ account ±í£¬Èçͼ 3 Ëùʾ¡£
´Óͼ 3 µÄ²éѯ½á¹ûÖпÉÒÔ¿´³ö£¬zhangsan ³É¹¦Ïò lisi תÕË 100 Ôª¡£
-
+
ͼ 3 ²éѯ½á¹û
ÏÂÃæÍ¨¹ýÐ޸ݸÀýÄ£ÄâתÕËʧ°ÜµÄÇé¿ö£¬ÔÚµÄ transfer() ·½·¨ÖÐÌí¼ÓÒ»ÐдúÂë¡°int i=1/0£»¡±Ä£Äâϵͳ¶ÏµçµÄÇé¿ö£¬¾ßÌå´úÂëÈçÏÂËùʾ£º
-
- public void transfer(String outUser, String inUser, int money) {
- this.accountDao.out(outUser, money);
- //Ä£Äâ¶Ïµç
- int i = 1/0;
- this.accountDao.in(inUser, money);
-}
-
-ÖØÐ²âÊÔÔËÐÐ test() ·½·¨£¬JUnit ¿ØÖÆÌ¨Êä³öµÄÐÅÏ¢Èçͼ 4 Ëùʾ¡£
-
-
-ͼ 4 ¿ØÖÆÌ¨Êä³ö½á¹û
-
-´Óͼ 4 ÖпÉÒÔ¿´³ö£¬ÔÚÖ´ÐвâÊÔ·½·¨Ê±£¬³öÏÖÁ˳ýÒÔ 0 µÄÒì³£ÐÅÏ¢¡£´ËʱÔٴβéѯ account ±í£¬Æä²éѯ½á¹ûÈçͼ 5 Ëùʾ¡£
-
-´Óͼ 5 µÄ²éѯ½á¹ûÖпÉÒÔ¿´³ö£¬±íÖеÄÊý¾Ý²¢Ã»Óз¢Éú±ä»¯¡£ÓÉÓÚ³ÌÐòÔÚÖ´Ðйý³ÌÖÐÅ׳öÁËÒì³££¬ÊÂÎñ²»ÄÜÕý³£±»Ìá½»£¬ËùÒÔתÕËʧ°Ü¡£ÓÉ´Ë¿ÉÖª£¬Spring µÄÊÂÎñ¹ÜÀíÉúЧÁË¡£
-
-
-ͼ 5 ²éѯ½á¹û
-
-# SpringÉùÃ÷ʽÊÂÎñ¹ÜÀí£¨»ùÓÚAnnotation×¢½â·½Ê½ÊµÏÖ£©
-
-ÔÚ [Spring](http://www.voidme.com/spring) ÖУ¬³ýÁËʹÓûùÓÚ XML µÄ·½Ê½¿ÉÒÔʵÏÖÉùÃ÷ʽÊÂÎñ¹ÜÀíÒÔÍ⣬»¹¿ÉÒÔͨ¹ý Annotation ×¢½âµÄ·½Ê½ÊµÏÖÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£
-
-ʹÓà Annotation µÄ·½Ê½·Ç³£¼òµ¥£¬Ö»ÐèÒªÔÚÏîÄ¿ÖÐ×öÁ½¼þÊ£¬¾ßÌåÈçÏ¡£
-
-#### 1£©ÔÚ Spring ÈÝÆ÷ÖÐ×¢²áÇý¶¯£¬´úÂëÈçÏÂËùʾ£º
-
+````
+ public void transfer(String outUser, String inUser, int money) { this.accountDao.out(outUser, money); //Ä£Äâ¶Ïµç
+ int i = 1/0; this.accountDao.in(inUser, money);
+ }
+````
+
+ÖØÐ²âÊÔÔËÐÐ test() ·½·¨£¬JUnit ¿ØÖÆÌ¨Êä³öµÄÐÅÏ¢Èçͼ 4 Ëùʾ¡£
+
+
+ͼ 4 ¿ØÖÆÌ¨Êä³ö½á¹û
+
+´Óͼ 4 ÖпÉÒÔ¿´³ö£¬ÔÚÖ´ÐвâÊÔ·½·¨Ê±£¬³öÏÖÁ˳ýÒÔ 0 µÄÒì³£ÐÅÏ¢¡£´ËʱÔٴβéѯ account ±í£¬Æä²éѯ½á¹ûÈçͼ 5 Ëùʾ¡£
+
+´Óͼ 5 µÄ²éѯ½á¹ûÖпÉÒÔ¿´³ö£¬±íÖеÄÊý¾Ý²¢Ã»Óз¢Éú±ä»¯¡£ÓÉÓÚ³ÌÐòÔÚÖ´Ðйý³ÌÖÐÅ׳öÁËÒì³££¬ÊÂÎñ²»ÄÜÕý³£±»Ìá½»£¬ËùÒÔתÕËʧ°Ü¡£ÓÉ´Ë¿ÉÖª£¬Spring µÄÊÂÎñ¹ÜÀíÉúЧÁË¡£
+
+
+ͼ 5 ²éѯ½á¹û
+
+# SpringÉùÃ÷ʽÊÂÎñ¹ÜÀí£¨»ùÓÚAnnotation×¢½â·½Ê½ÊµÏÖ£©
+
+ÔÚ [Spring](http://www.voidme.com/spring) ÖУ¬³ýÁËʹÓûùÓÚ XML µÄ·½Ê½¿ÉÒÔʵÏÖÉùÃ÷ʽÊÂÎñ¹ÜÀíÒÔÍ⣬»¹¿ÉÒÔͨ¹ý Annotation ×¢½âµÄ·½Ê½ÊµÏÖÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£
+
+ʹÓà Annotation µÄ·½Ê½·Ç³£¼òµ¥£¬Ö»ÐèÒªÔÚÏîÄ¿ÖÐ×öÁ½¼þÊ£¬¾ßÌåÈçÏ¡£
+
+#### 1£©ÔÚ Spring ÈÝÆ÷ÖÐ×¢²áÇý¶¯£¬´úÂëÈçÏÂËùʾ£º
+````
-
-#### 2£©ÔÚÐèҪʹÓÃÊÂÎñµÄÒµÎñÀà»òÕß·½·¨ÖÐÌí¼Ó×¢½â @Transactional£¬²¢ÅäÖà @Transactional µÄ²ÎÊý¡£¹ØÓÚ @Transactional µÄ²ÎÊýÈçͼ 1 Ëùʾ¡£
-
-
-ͼ 1 @Transactional²ÎÊýÁбí
-
-ÏÂÃæÍ¨¹ýÐ޸ġ¶ [Spring»ùÓÚXMLʵÏÖÊÂÎñ¹ÜÀí](http://www.voidme.com/spring/spring-transaction-management-by-xml)¡·½Ì³ÌÖÐÒøÐÐתÕ˵ݸÀý½²½âÈçºÎʹÓà Annotation ×¢½âµÄ·½Ê½ÊµÏÖ Spring ÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£
-
-#### 1\. ×¢²áÇý¶¯
-
-ÐÞ¸Ä Spring ÅäÖÃÎļþ applicationContext.xml£¬Ð޸ĺóÈçÏÂËùʾ¡£
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+````
+#### 2£©ÔÚÐèҪʹÓÃÊÂÎñµÄÒµÎñÀà»òÕß·½·¨ÖÐÌí¼Ó×¢½â @Transactional£¬²¢ÅäÖà @Transactional µÄ²ÎÊý¡£¹ØÓÚ @Transactional µÄ²ÎÊýÈçͼ 1 Ëùʾ¡£
+
+
+ͼ 1 @Transactional²ÎÊýÁбí
+
+ÏÂÃæÍ¨¹ýÐ޸ġ¶ [Spring»ùÓÚXMLʵÏÖÊÂÎñ¹ÜÀí](http://www.voidme.com/spring/spring-transaction-management-by-xml)¡·½Ì³ÌÖÐÒøÐÐתÕ˵ݸÀý½²½âÈçºÎʹÓà Annotation ×¢½âµÄ·½Ê½ÊµÏÖ Spring ÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£
+
+#### 1\. ×¢²áÇý¶¯
+
+ÐÞ¸Ä Spring ÅäÖÃÎļþ applicationContext.xml£¬Ð޸ĺóÈçÏÂËùʾ¡£
+
+
+````
+
+
+
+ ````
+````
ÉÏÊö´úÂëÖпÉÒÔ¿´³ö£¬ÓëÔÀ´µÄÅäÖÃÎļþÏà±È£¬ÕâÀïÖ»ÐÞ¸ÄÁËÊÂÎñ¹ÜÀíÆ÷²¿·Ö£¬ÐÂÌí¼Ó²¢×¢²áÁËÊÂÎñ¹ÜÀíÆ÷µÄÇý¶¯¡£
ÐèҪעÒâµÄÊÇ£¬ÔÚѧϰ AOP ×¢½â·½Ê½¿ª·¢Ê±£¬ÐèÒªÔÚÅäÖÃÎļþÖпªÆô×¢½â´¦ÀíÆ÷£¬Ö¸¶¨É¨ÃèÄÄЩ°üϵÄ×¢½â£¬ÕâÀïûÓпªÆô×¢½â´¦ÀíÆ÷ÊÇÒòΪÔÚµÚ 33¡«35 ÐÐÊÖ¶¯ÅäÖÃÁË AccountServiceImpl£¬¶ø @Transactional ×¢½â¾ÍÅäÖÃÔÚ¸ÃÀàÖУ¬ËùÒÔ»áÖ±½ÓÉúЧ¡£
@@ -389,42 +258,35 @@ public class AccountTest {
#### 2\. Ìí¼Ó @Transactional ×¢½â
ÐÞ¸Ä AccountServiceImpl£¬ÔÚÎļþÖÐÌí¼Ó @Transactional ×¢½â¼°²ÎÊý£¬Ìí¼ÓºóÈçÏÂËùʾ¡£
-
- package com.mengma.service.impl;
-
-import org.springframework.transaction.annotation.Isolation;
-import org.springframework.transaction.annotation.Propagation;
-import org.springframework.transaction.annotation.Transactional;
-
-import com.mengma.dao.AccountDao;
-
-@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
-public class AccountServiceImpl {
- private AccountDao accountDao;
-
- public void setAccountDao(AccountDao accountDao) {
- this.accountDao = accountDao;
- }
-
- public void transfer(String outUser, String inUser, int money) {
- this.accountDao.out(outUser, money);
- // Ä£Äâ¶Ïµç
- int i = 1 / 0;
- this.accountDao.in(inUser, money);
- }
-}
-
-ÐèҪעÒâµÄÊÇ£¬ÔÚʹÓà @Transactional ×¢½âʱ£¬²ÎÊýÖ®¼äÓá°£¬¡±½øÐзָô¡£
-
-ʹÓà JUnit ²âÊÔÔÙ´ÎÔËÐÐ test() ·½·¨Ê±£¬¿ØÖÆÌ¨Í¬Ñù»áÊä³öÈçͼ 2 ËùʾµÄÒì³£ÐÅÏ¢£¬Õâ˵Ã÷ʹÓûùÓÚ Annotation ×¢½âµÄ·½Ê½Í¬ÑùʵÏÖÁË Spring µÄÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£Èç¹û×¢Ê͵ôÄ£Äâ¶ÏµçµÄ´úÂë½øÐвâÊÔ£¬ÔòתÕ˲Ù×÷¿ÉÒÔÕý³£Íê³É¡£
-
-
-ͼ 2 ÔËÐнá¹û
-
-# ²Î¿¼ÎÄÕÂ
-https://www.w3cschool.cn/wkspring
-https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
-http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
-https://dunwu.github.io/spring-tutorial
-https://mszlu.com/java/spring
+````
+package com.mengma.service.impl;
+
+import org.springframework.transaction.annotation.Isolation;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.mengma.dao.AccountDao;
+
+@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, readOnly = false)
+public class AccountServiceImpl {
+ private AccountDao accountDao;
+ public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; }
+ public void transfer(String outUser, String inUser, int money) { this.accountDao.out(outUser, money); // Ä£Äâ¶Ïµç
+ int i = 1 / 0; this.accountDao.in(inUser, money);
+}}
+````
+
+ÐèҪעÒâµÄÊÇ£¬ÔÚʹÓà @Transactional ×¢½âʱ£¬²ÎÊýÖ®¼äÓá°£¬¡±½øÐзָô¡£
+
+ʹÓà JUnit ²âÊÔÔÙ´ÎÔËÐÐ test() ·½·¨Ê±£¬¿ØÖÆÌ¨Í¬Ñù»áÊä³öÈçͼ 2 ËùʾµÄÒì³£ÐÅÏ¢£¬Õâ˵Ã÷ʹÓûùÓÚ Annotation ×¢½âµÄ·½Ê½Í¬ÑùʵÏÖÁË Spring µÄÉùÃ÷ʽÊÂÎñ¹ÜÀí¡£Èç¹û×¢Ê͵ôÄ£Äâ¶ÏµçµÄ´úÂë½øÐвâÊÔ£¬ÔòתÕ˲Ù×÷¿ÉÒÔÕý³£Íê³É¡£
+
+
+ͼ 2 ÔËÐнá¹û
+
+# ²Î¿¼ÎÄÕÂ
+https://www.w3cschool.cn/wkspring
+https://www.runoob.com/w3cnote/basic-knowledge-summary-of-spring.html
+http://codepub.cn/2015/06/21/Basic-knowledge-summary-of-Spring
+https://dunwu.github.io/spring-tutorial
+https://mszlu.com/java/spring
http://c.biancheng.net/spring/aop-module.html
\ No newline at end of file
diff --git "a/docs/spring/Spring\346\246\202\350\277\260.md" "b/docs/spring/Spring\346\246\202\350\277\260.md"
index 1152df8..e9a041f 100644
--- "a/docs/spring/Spring\346\246\202\350\277\260.md"
+++ "b/docs/spring/Spring\346\246\202\350\277\260.md"
@@ -26,14 +26,14 @@ Rod Johnson
ÕâЩ×ÓÏîÄ¿º¸ÇÁË´ÓÆóÒµ¼¶Ó¦Óÿª·¢µ½ÔƼÆËãµÈ¸÷·½ÃæµÄÄÚÈÝ£¬Äܹ»°ïÖú¿ª·¢ÈËÔ±½â¾öÈí¼þ·¢Õ¹¹ý³ÌÖв»¶Ï²úÉúµÄ¸÷ÖÖʵ¼ÊÎÊÌ⣬¸ø¿ª·¢ÈËÔ±´øÀ´Á˸üºÃµÄ¿ª·¢ÌåÑé¡£
-| ÏîÄ¿Ãû³Æ | ÃèÊö |
-| --- | --- |
-| Spring Data | Spring ÌṩµÄÊý¾Ý·ÃÎÊÄ£¿é£¬¶Ô JDBC ºÍ ORM ÌṩÁ˺ܺõÄÖ§³Ö¡£Í¨¹ýËü£¬¿ª·¢ÈËÔ±¿ÉÒÔʹÓÃÒ»ÖÖÏà¶ÔͳһµÄ·½Ê½£¬À´·ÃÎÊλÓÚ²»Í¬ÀàÐÍÊý¾Ý¿âÖеÄÊý¾Ý¡£ |
-| Spring Batch | Ò»¿îרÃÅÕë¶ÔÆóÒµ¼¶ÏµÍ³ÖеÄÈÕ³£Åú´¦ÀíÈÎÎñµÄÇáÁ¿¼¶¿ò¼Ü£¬Äܹ»°ïÖú¿ª·¢ÈËÔ±·½±ãµÄ¿ª·¢³ö½¡×³¡¢¸ßЧµÄÅú´¦ÀíÓ¦ÓóÌÐò¡£ |
-| Spring Security | ǰÉíΪ Acegi£¬ÊÇ Spring ÖнϳÉÊìµÄ×ÓÄ£¿éÖ®Ò»¡£ËüÊÇÒ»¿î¿ÉÒÔ¶¨ÖÆ»¯µÄÉí·ÝÑéÖ¤ºÍ·ÃÎÊ¿ØÖÆ¿ò¼Ü¡£ |
-| Spring Mobile | ÊÇ¶Ô Spring MVC µÄÀ©Õ¹£¬ÓÃÀ´¼ò»¯Òƶ¯¶Ë Web Ó¦ÓõĿª·¢¡£ |
-| Spring Boot | ÊÇ Spring ÍŶÓÌṩµÄȫпò¼Ü£¬ËüΪ Spring ÒÔ¼°µÚÈý·½¿âһЩ¿ªÏä¼´ÓõÄÅäÖ㬿ÉÒÔ¼ò»¯ Spring Ó¦ÓõĴ¼°¿ª·¢¹ý³Ì¡£ |
-| Spring Cloud | Ò»¿î»ùÓÚ Spring Boot ʵÏÖµÄ΢·þÎñ¿ò¼Ü¡£Ëü²¢²»ÊÇijһÃż¼Êõ£¬¶øÊÇһϵÁÐ΢·þÎñ½â¾ö·½°¸»ò¿ò¼ÜµÄÓÐÐò¼¯ºÏ¡£Ëü½«ÊÐÃæÉϳÉÊìµÄ¡¢¾¹ýÑéÖ¤µÄ΢·þÎñ¿ò¼ÜÕûºÏÆðÀ´£¬²¢Í¨¹ý Spring Boot µÄ˼Ïë½øÐÐÔÙ·â×°£¬ÆÁ±Îµ÷ÆäÖи´ÔÓµÄÅäÖúÍʵÏÖÔÀí£¬×îÖÕΪ¿ª·¢ÈËÔ±ÌṩÁËÒ»Ì×¼òµ¥Ò×¶®¡¢Òײ¿ÊðºÍÒ×ά»¤µÄ·Ö²¼Ê½ÏµÍ³¿ª·¢¹¤¾ß°ü¡£ |
+| ÏîÄ¿Ãû³Æ | ÃèÊö |
+| --- | --- |
+| Spring Data | Spring ÌṩµÄÊý¾Ý·ÃÎÊÄ£¿é£¬¶Ô JDBC ºÍ ORM ÌṩÁ˺ܺõÄÖ§³Ö¡£Í¨¹ýËü£¬¿ª·¢ÈËÔ±¿ÉÒÔʹÓÃÒ»ÖÖÏà¶ÔͳһµÄ·½Ê½£¬À´·ÃÎÊλÓÚ²»Í¬ÀàÐÍÊý¾Ý¿âÖеÄÊý¾Ý¡£ |
+| Spring Batch | Ò»¿îרÃÅÕë¶ÔÆóÒµ¼¶ÏµÍ³ÖеÄÈÕ³£Åú´¦ÀíÈÎÎñµÄÇáÁ¿¼¶¿ò¼Ü£¬Äܹ»°ïÖú¿ª·¢ÈËÔ±·½±ãµÄ¿ª·¢³ö½¡×³¡¢¸ßЧµÄÅú´¦ÀíÓ¦ÓóÌÐò¡£ |
+| Spring Security | ǰÉíΪ Acegi£¬ÊÇ Spring ÖнϳÉÊìµÄ×ÓÄ£¿éÖ®Ò»¡£ËüÊÇÒ»¿î¿ÉÒÔ¶¨ÖÆ»¯µÄÉí·ÝÑéÖ¤ºÍ·ÃÎÊ¿ØÖÆ¿ò¼Ü¡£ |
+| Spring Mobile | ÊÇ¶Ô Spring MVC µÄÀ©Õ¹£¬ÓÃÀ´¼ò»¯Òƶ¯¶Ë Web Ó¦ÓõĿª·¢¡£ |
+| Spring Boot | ÊÇ Spring ÍŶÓÌṩµÄȫпò¼Ü£¬ËüΪ Spring ÒÔ¼°µÚÈý·½¿âһЩ¿ªÏä¼´ÓõÄÅäÖ㬿ÉÒÔ¼ò»¯ Spring Ó¦ÓõĴ¼°¿ª·¢¹ý³Ì¡£ |
+| Spring Cloud | Ò»¿î»ùÓÚ Spring Boot ʵÏÖµÄ΢·þÎñ¿ò¼Ü¡£Ëü²¢²»ÊÇijһÃż¼Êõ£¬¶øÊÇһϵÁÐ΢·þÎñ½â¾ö·½°¸»ò¿ò¼ÜµÄÓÐÐò¼¯ºÏ¡£Ëü½«ÊÐÃæÉϳÉÊìµÄ¡¢¾¹ýÑéÖ¤µÄ΢·þÎñ¿ò¼ÜÕûºÏÆðÀ´£¬²¢Í¨¹ý Spring Boot µÄ˼Ïë½øÐÐÔÙ·â×°£¬ÆÁ±Îµ÷ÆäÖи´ÔÓµÄÅäÖúÍʵÏÖÔÀí£¬×îÖÕΪ¿ª·¢ÈËÔ±ÌṩÁËÒ»Ì×¼òµ¥Ò×¶®¡¢Òײ¿ÊðºÍÒ×ά»¤µÄ·Ö²¼Ê½ÏµÍ³¿ª·¢¹¤¾ß°ü¡£ |
### ÏÁÒåµÄ Spring£ºSpring Framework
@@ -43,10 +43,10 @@ Spring
Spring ÓÐÁ½¸öºËÐIJ¿·Ö£º IoC ºÍ AOP¡£
-| ºËÐÄ | ÃèÊö |
-| --- | --- |
-| IOC | Inverse of Control µÄ¼òд£¬ÒëΪ¡°¿ØÖÆ·´×ª¡±£¬Ö¸°Ñ´´½¨¶ÔÏó¹ý³Ì½»¸ø Spring ½øÐйÜÀí¡£ |
-| AOP | Aspect Oriented Programming µÄ¼òд£¬ÒëΪ¡°ÃæÏòÇÐÃæ±à³Ì¡±¡£AOP ÓÃÀ´·â×°¶à¸öÀàµÄ¹«¹²ÐÐΪ£¬½«ÄÇЩÓëÒµÎñÎ޹أ¬È´ÎªÒµÎñÄ£¿éËù¹²Í¬µ÷ÓõÄÂß¼·â×°ÆðÀ´£¬¼õÉÙϵͳµÄÖØ¸´´úÂ룬½µµÍÄ£¿é¼äµÄñîºÏ¶È¡£ÁíÍ⣬AOP »¹½â¾öһЩϵͳ²ãÃæÉϵÄÎÊÌ⣬±ÈÈçÈÕÖ¾¡¢ÊÂÎñ¡¢È¨Ï޵ȡ£ |
+| ºËÐÄ | ÃèÊö |
+| --- | --- |
+| IOC | Inverse of Control µÄ¼òд£¬ÒëΪ¡°¿ØÖÆ·´×ª¡±£¬Ö¸°Ñ´´½¨¶ÔÏó¹ý³Ì½»¸ø Spring ½øÐйÜÀí¡£ |
+| AOP | Aspect Oriented Programming µÄ¼òд£¬ÒëΪ¡°ÃæÏòÇÐÃæ±à³Ì¡±¡£AOP ÓÃÀ´·â×°¶à¸öÀàµÄ¹«¹²ÐÐΪ£¬½«ÄÇЩÓëÒµÎñÎ޹أ¬È´ÎªÒµÎñÄ£¿éËù¹²Í¬µ÷ÓõÄÂß¼·â×°ÆðÀ´£¬¼õÉÙϵͳµÄÖØ¸´´úÂ룬½µµÍÄ£¿é¼äµÄñîºÏ¶È¡£ÁíÍ⣬AOP »¹½â¾öһЩϵͳ²ãÃæÉϵÄÎÊÌ⣬±ÈÈçÈÕÖ¾¡¢ÊÂÎñ¡¢È¨Ï޵ȡ£ |
Spring ÊÇÒ»ÖÖ»ùÓÚ Bean µÄ±à³Ì¼¼Êõ£¬ËüÉî¿ÌµØ¸Ä±ä×Å Java ¿ª·¢ÊÀ½ç¡£Spring ʹÓüòµ¥¡¢»ù±¾µÄ Java Bean À´Íê³ÉÒÔǰֻÓÐ EJB ²ÅÄÜÍê³ÉµÄ¹¤×÷£¬Ê¹µÃºÜ¶à¸´ÔӵĴúÂë±äµÃÓÅÑźͼò½à£¬±ÜÃâÁË EJB Ó·Öס¢µÍЧµÄ¿ª·¢Ä£Ê½£¬¼«´óµÄ·½±ãÏîÄ¿µÄºóÆÚά»¤¡¢Éý¼¶ºÍÀ©Õ¹¡£
@@ -92,13 +92,13 @@ Spring
Spring ¿ò¼Ü»ù±¾º¸ÇÁËÆóÒµ¼¶Ó¦Óÿª·¢µÄ¸÷¸ö·½Ã棬Ëü°üº¬ÁË 20 ¶à¸ö²»Í¬µÄÄ£¿é¡£
-spring-aop spring-context-indexer spring-instrument spring-orm spring-web
-spring-aspects spring-context-support spring-jcl spring-oxm spring-webflux
-spring-beans spring-core spring-jdbc spring-r2dbc spring-webmvc
-spring-context spring-expression spring-jms spring-test spring-websocket
-spring-messaging spring-tx
+ spring-aop spring-context-indexer spring-instrument spring-orm spring-web
+spring-aspects spring-context-support spring-jcl spring-oxm spring-webflux
+spring-beans spring-core spring-jdbc spring-r2dbc spring-webmvc
+spring-context spring-expression spring-jms spring-test spring-websocket
+spring-messaging spring-tx
-
+
ͼ1£ºSpring¼Ü¹¹Í¼
ÉÏͼÖаüº¬ÁË Spring ¿ò¼ÜµÄËùÓÐÄ£¿é£¬ÕâЩģ¿é¿ÉÒÔÂú×ãÒ»ÇÐÆóÒµ¼¶Ó¦Óÿª·¢µÄÐèÇó£¬ÔÚ¿ª·¢¹ý³ÌÖпÉÒÔ¸ù¾ÝÐèÇóÓÐÑ¡ÔñÐÔµØÊ¹ÓÃËùÐèÒªµÄÄ£¿é¡£ÏÂÃæ·Ö±ð¶ÔÕâЩģ¿éµÄ×÷ÓýøÐмòµ¥½éÉÜ¡£
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md" "b/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md"
rename to "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md"
From 3410032d2fc5e0e32560e90ddf160cde88dcc05b Mon Sep 17 00:00:00 2001
From: h2pl <362294931@qq.com>
Date: Sat, 22 Apr 2023 09:28:57 +0800
Subject: [PATCH 04/32] modify catelog
---
ReadMe.md | 415 ++++++++----------
.../Java/JVM/JVM\346\200\273\347\273\223.md" | 0
...70\347\224\250\345\267\245\345\205\267.md" | 0
...75\345\231\250\345\256\236\347\216\260.md" | 0
...04\346\260\270\344\271\205\344\273\243.md" | 0
...06\345\222\214\347\256\227\346\263\225.md" | 0
...03\344\274\230\345\256\236\350\267\265.md" | 0
...15\344\270\216\345\256\236\346\210\230.md" | 0
...12\346\226\255\345\256\236\350\267\265.md" | 0
...06\344\270\216\345\256\236\350\267\265.md" | 0
...43\346\236\220\345\256\236\350\267\265.md" | 0
...14\346\234\237\344\274\230\345\214\226.md" | 0
...\345\217\212GC\345\256\236\350\267\265.md" | 0
...66\345\231\250\350\257\246\350\247\243.md" | 0
...40\350\275\275\346\234\272\345\210\266.md" | 0
...47\350\241\214\345\274\225\346\223\216.md" | 0
...10\346\236\201\346\214\207\345\215\227.md" | 0
.../Java/basic/JavaIO\346\265\201.md" | 0
...\261\273\345\222\214Object\347\261\273.md" | 0
...60\346\215\256\347\261\273\345\236\213.md" | 0
.../basic/Java\345\274\202\345\270\270.md" | 0
...00\344\275\263\345\256\236\350\267\265.md" | 0
...va\347\261\273\345\222\214\345\214\205.md" | 0
...17\347\232\204\347\247\230\345\257\206.md" | 0
...06\346\236\266\346\242\263\347\220\206.md" | 0
...56\345\255\227\347\211\271\346\200\247.md" | 0
.../Java/basic/javac\345\222\214javap.md" | 0
...14\345\214\205\350\243\205\347\261\273.md" | 0
...47\350\241\214\351\241\272\345\272\217.md" | 0
.../Java/basic/\345\217\215\345\260\204.md" | 0
.../\345\244\232\347\272\277\347\250\213.md" | 0
...15\345\272\217\345\210\227\345\214\226.md" | 0
...73\345\222\214\346\216\245\345\217\243.md" | 0
.../\346\236\232\344\270\276\347\261\273.md" | 0
.../Java/basic/\346\263\233\345\236\213.md" | 0
...43\345\206\205\351\203\250\347\261\273.md" | 0
...36\347\216\260\345\216\237\347\220\206.md" | 0
...55\347\232\204\345\233\236\350\260\203.md" | 0
...71\350\261\241\345\237\272\347\241\200.md" | 0
...10\347\261\273\346\200\273\347\273\223.md" | 0
...57\274\232HashMap\345\222\214HashTable.md" | 0
...74\214TreeSet\344\270\216LinkedHashSet.md" | 0
...16\346\257\224\350\276\203\345\231\250.md" | 0
...06\350\212\202\347\262\276\350\256\262.md" | 0
...357\274\232Queue\345\222\214LinkedList.md" | 0
...14\347\272\242\351\273\221\346\240\221.md" | 0
...36\347\216\260\345\216\237\347\220\206.md" | 0
...345\222\214LRU\347\274\223\345\255\230.md" | 0
...71\263\351\224\201\357\274\214Condtion.md" | 0
...73\347\232\204\345\256\236\347\216\260.md" | 0
...27\346\263\225\345\211\226\346\236\220.md" | 0
...56\345\255\227\350\247\243\346\236\220.md" | 0
...7\232\204Unsafe\345\222\214Locksupport.md" | 0
...347\261\273AQS\350\257\246\350\247\243.md" | 0
...ap\345\205\250\350\247\243\346\236\220.md" | 0
...51\224\201Lock\345\222\214synchronized.md" | 0
...345\236\213JMM\346\200\273\347\273\223.md" | 0
...20\347\240\201\345\210\206\346\236\220.md" | 0
...357\274\214CAS\346\223\215\344\275\234.md" | 0
...va\345\244\232\347\272\277\347\250\213.md" | 0
...345\255\230\346\250\241\345\236\213JMM.md" | 0
...20\347\240\201\345\256\236\347\216\260.md" | 0
...6\351\230\237\345\210\227BlockingQueue.md" | 0
...46\344\271\240\346\200\273\347\273\223.md" | 0
...76\350\256\241\346\250\241\345\274\217.md" | 0
...76\350\256\241\346\250\241\345\274\217.md" | 0
...25\344\276\213\347\255\211\357\274\211.md" | 0
...41\345\274\217\347\255\211\357\274\211.md" | 0
...37\350\200\205\347\255\211\357\274\211.md" | 0
...46\344\271\240\346\200\273\347\273\223.md" | 0
...344\270\216NIO\346\200\273\347\273\223.md" | 0
...26\347\250\213\346\250\241\345\236\213.md" | 0
...32\344\277\241\346\234\272\345\210\266.md" | 0
...67\346\261\202\346\250\241\345\236\213.md" | 0
...\345\222\214\345\274\202\346\255\245IO.md" | 0
...37\347\220\206\350\257\246\350\247\243.md" | 0
...346\236\220\357\274\210NIO\357\274\211.md" | 0
...7\250\213\346\241\206\346\236\266Netty.md" | 0
...343\200\201Channel\345\222\214Selector.md" | 0
...46\236\220mmap\345\222\214DirectBuffer.md" | 0
...36\347\216\260\345\216\237\347\220\206.md" | 0
...347\232\204NIO\346\250\241\345\236\213.md" | 0
...00\346\234\257\346\200\273\347\273\223.md" | 0
...43\345\274\217\345\274\200\345\217\221.md" | 0
...45\346\261\240\346\212\200\346\234\257.md" | 0
...17\344\270\216\347\216\260\345\234\250.md" | 0
...72\347\241\200\347\237\245\350\257\206.md" | 0
...37\344\270\216\345\217\221\345\261\225.md" | 0
...274\232Mybatis\345\205\245\351\227\250.md" | 0
...37\347\220\206\350\257\246\350\247\243.md" | 0
...66\346\236\204\345\211\226\346\236\220.md" | 0
...50\347\232\204\345\214\272\345\210\253.md" | 0
...JavaBean\350\256\262\345\210\260Spring.md" | 0
...5\273\272\345\267\245\345\205\267Maven.md" | 0
...67\346\261\202\350\277\207\347\250\213.md" | 0
...0\257\225\346\241\206\346\236\266Junit.md" | 0
...\215\347\275\256\347\232\204SpringBoot.md" | 0
...50\347\275\262\350\277\207\347\250\213.md" | 0
...72\346\234\254\345\216\237\347\220\206.md" | 0
...65\344\270\216\344\275\234\347\224\250.md" | 0
...10\346\240\270\345\277\203\357\274\211.md" | 0
...23\347\232\204\350\256\277\351\227\256.md" | 0
...75\347\232\204\346\224\257\346\214\201.md" | 0
...57\345\242\203\345\217\230\351\207\217.md" | 0
...04\347\220\206\346\234\272\345\210\266.md" | 0
...04\346\272\220\347\256\241\347\220\206.md" | 0
...54\346\225\260\346\215\256\357\274\211.md" | 0
...72\346\234\254\347\224\250\346\263\225.md" | 0
.../Spring/Spring\345\220\210\351\233\206.md" | 0
...345\256\271\345\231\250\344\270\216IOC.md" | 0
...70\350\247\201\346\263\250\350\247\243.md" | 0
.../Spring/Spring\346\246\202\350\277\260.md" | 0
...\270\252Spring\345\272\224\347\224\250.md" | 0
...\260\203\345\272\246\344\270\216@Async.md" | 0
...45\345\277\227\347\256\241\347\220\206.md" | 0
...70\350\247\201\346\263\250\350\247\243.md" | 0
...\210\260\345\244\226\351\203\250Tomcat.md" | 0
...42\203\345\267\245\345\205\267Actuator.md" | 0
...232\204Starter\346\234\272\345\210\266.md" | 0
...15\344\270\226\344\273\212\347\224\237.md" | 0
...72\346\234\254\344\275\277\347\224\250.md" | 0
...07\344\273\266\347\256\241\347\220\206.md" | 0
...50\347\275\262\345\267\245\345\205\267.md" | 0
...52\345\212\250\347\224\237\346\210\220.md" | 0
...45\220\253Spring+SpringMVC+SpringBoot).md" | 0
...345\267\245\345\205\267SpringBootAdmin.md" | 0
...45\350\257\206\346\270\205\345\215\225.md" | 0
...05\345\214\226\345\212\237\350\203\275.md" | 0
...70\347\224\250\345\212\237\350\203\275.md" | 0
...70\345\244\204\347\220\206\345\231\250.md" | 0
...04\346\213\246\346\210\252\345\231\250.md" | 0
...76\350\247\243\346\236\220\345\231\250.md" | 0
...\277\207\346\273\244\345\231\250Filter.md" | 0
...53\351\200\237\345\205\245\351\227\250.md" | 0
...07\344\273\266\344\270\212\344\274\240.md" | 0
...70\350\247\201\346\263\250\350\247\243.md" | 0
...\243\347\241\256\347\232\204Controller.md" | 0
...67\346\261\202\350\275\254\345\217\221.md" | 0
...4\232SpringMVC\346\246\202\350\277\260.md" | 0
...43\346\236\220\345\216\237\347\220\206.md" | 0
...5\277\265\344\270\216DispatcherServlet.md" | 0
...6@ResponseBody\346\263\250\350\247\243.md" | 0
...37\347\220\206\350\257\246\350\247\243.md" | 0
...37\347\220\206\350\257\246\350\247\243.md" | 0
...4\232SpringAOP\346\246\202\350\277\260.md" | 0
...40\350\275\275\350\277\207\347\250\213.md" | 0
...13\345\212\241\346\246\202\350\277\260.md" | 0
...20\347\240\201\345\211\226\346\236\220.md" | 0
...\274\232Spring\346\246\202\350\277\260.md" | 0
...70\345\277\203\346\265\201\347\250\213.md" | 0
...07\347\250\213\345\210\206\346\236\220.md" | 0
...37\346\200\201\346\200\273\347\273\223.md" | 0
...AI\347\232\204\346\225\205\344\272\213.md" | 0
...36\347\216\260\345\216\237\347\220\206.md" | 0
...45\351\227\250\345\256\236\350\267\265.md" | 0
...06\344\270\216\345\256\236\350\267\265.md" | 0
...66\346\236\204\350\256\276\350\256\241.md" | 0
...347\232\204\345\237\272\347\237\263KVM.md" | 0
...15\344\270\226\344\273\212\347\224\237.md" | 0
...03\346\246\202\345\277\265\345\220\247.md" | 0
...70\345\277\203\346\246\202\345\277\265.md" | 0
...72\346\234\254\346\246\202\345\277\265.md" | 0
...22\346\216\222\347\264\242\345\274\225.md" | 0
...45\344\275\234\345\216\237\347\220\206.md" | 0
...37\345\214\226\346\212\200\346\234\257.md" | 0
165 files changed, 189 insertions(+), 226 deletions(-)
rename "docs/java/jvm/JVM\346\200\273\347\273\223.md" => "docs/Java/JVM/JVM\346\200\273\347\273\223.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232GC\350\260\203\344\274\230\346\200\235\350\267\257\344\270\216\345\270\270\347\224\250\345\267\245\345\205\267.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232GC\350\260\203\344\274\230\346\200\235\350\267\257\344\270\216\345\270\270\347\224\250\345\267\245\345\205\267.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JNDI\357\274\214OSGI\357\274\214Tomcat\347\261\273\345\212\240\350\275\275\345\231\250\345\256\236\347\216\260.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JNDI\357\274\214OSGI\357\274\214Tomcat\347\261\273\345\212\240\350\275\275\345\231\250\345\256\236\347\216\260.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\206\205\345\255\230\347\232\204\347\273\223\346\236\204\344\270\216\346\266\210\345\244\261\347\232\204\346\260\270\344\271\205\344\273\243.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\206\205\345\255\230\347\232\204\347\273\223\346\236\204\344\270\216\346\266\210\345\244\261\347\232\204\346\260\270\344\271\205\344\273\243.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\236\203\345\234\276\345\233\236\346\224\266\345\237\272\346\234\254\345\216\237\347\220\206\345\222\214\347\256\227\346\263\225.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\236\203\345\234\276\345\233\236\346\224\266\345\237\272\346\234\254\345\216\237\347\220\206\345\222\214\347\256\227\346\263\225.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\270\270\347\224\250\345\217\202\346\225\260\344\273\245\345\217\212\350\260\203\344\274\230\345\256\236\350\267\265.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\270\270\347\224\250\345\217\202\346\225\260\344\273\245\345\217\212\350\260\203\344\274\230\345\256\236\350\267\265.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\346\200\247\350\203\275\347\256\241\347\220\206\347\245\236\345\231\250VisualVM\344\273\213\347\273\215\344\270\216\345\256\236\346\210\230.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\346\200\247\350\203\275\347\256\241\347\220\206\347\245\236\345\231\250VisualVM\344\273\213\347\273\215\344\270\216\345\256\236\346\210\230.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\347\233\221\346\216\247\345\267\245\345\205\267\344\270\216\350\257\212\346\226\255\345\256\236\350\267\265.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\347\233\221\346\216\247\345\267\245\345\205\267\344\270\216\350\257\212\346\226\255\345\256\236\350\267\265.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\206\205\345\255\230\345\274\202\345\270\270\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\206\205\345\255\230\345\274\202\345\270\270\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\255\227\350\212\202\347\240\201\344\273\213\347\273\215\344\270\216\350\247\243\346\236\220\345\256\236\350\267\265.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\255\227\350\212\202\347\240\201\344\273\213\347\273\215\344\270\216\350\247\243\346\236\220\345\256\236\350\267\265.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\347\232\204\347\274\226\350\257\221\346\234\237\344\274\230\345\214\226\344\270\216\350\277\220\350\241\214\346\234\237\344\274\230\345\214\226.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\347\232\204\347\274\226\350\257\221\346\234\237\344\274\230\345\214\226\344\270\216\350\277\220\350\241\214\346\234\237\344\274\230\345\214\226.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\206\215\350\260\210\345\233\233\347\247\215\345\274\225\347\224\250\345\217\212GC\345\256\236\350\267\265.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\206\215\350\260\210\345\233\233\347\247\215\345\274\225\347\224\250\345\217\212GC\345\256\236\350\267\265.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250\350\257\246\350\247\243.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250\350\257\246\350\247\243.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243JVM\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243JVM\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" (100%)
rename "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\350\231\232\346\213\237\346\234\272\345\255\227\350\212\202\347\240\201\346\211\247\350\241\214\345\274\225\346\223\216.md" => "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\350\231\232\346\213\237\346\234\272\345\255\227\350\212\202\347\240\201\346\211\247\350\241\214\345\274\225\346\223\216.md" (100%)
rename "docs/java/basic/Java8\346\226\260\347\211\271\346\200\247\347\273\210\346\236\201\346\214\207\345\215\227.md" => "docs/Java/basic/Java8\346\226\260\347\211\271\346\200\247\347\273\210\346\236\201\346\214\207\345\215\227.md" (100%)
rename "docs/java/basic/JavaIO\346\265\201.md" => "docs/Java/basic/JavaIO\346\265\201.md" (100%)
rename "docs/java/basic/Java\344\270\255\347\232\204Class\347\261\273\345\222\214Object\347\261\273.md" => "docs/Java/basic/Java\344\270\255\347\232\204Class\347\261\273\345\222\214Object\347\261\273.md" (100%)
rename "docs/java/basic/Java\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213.md" => "docs/Java/basic/Java\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213.md" (100%)
rename "docs/java/basic/Java\345\274\202\345\270\270.md" => "docs/Java/basic/Java\345\274\202\345\270\270.md" (100%)
rename "docs/java/basic/Java\346\263\250\350\247\243\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md" => "docs/Java/basic/Java\346\263\250\350\247\243\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md" (100%)
rename "docs/java/basic/Java\347\261\273\345\222\214\345\214\205.md" => "docs/Java/basic/Java\347\261\273\345\222\214\345\214\205.md" (100%)
rename "docs/java/basic/Java\350\207\252\345\212\250\346\213\206\347\256\261\350\243\205\347\256\261\351\207\214\351\232\220\350\227\217\347\232\204\347\247\230\345\257\206.md" => "docs/Java/basic/Java\350\207\252\345\212\250\346\213\206\347\256\261\350\243\205\347\256\261\351\207\214\351\232\220\350\227\217\347\232\204\347\247\230\345\257\206.md" (100%)
rename "docs/java/basic/Java\351\233\206\345\220\210\346\241\206\346\236\266\346\242\263\347\220\206.md" => "docs/Java/basic/Java\351\233\206\345\220\210\346\241\206\346\236\266\346\242\263\347\220\206.md" (100%)
rename "docs/java/basic/final\345\205\263\351\224\256\345\255\227\347\211\271\346\200\247.md" => "docs/Java/basic/final\345\205\263\351\224\256\345\255\227\347\211\271\346\200\247.md" (100%)
rename "docs/java/basic/javac\345\222\214javap.md" => "docs/Java/basic/javac\345\222\214javap.md" (100%)
rename "docs/java/basic/string\345\222\214\345\214\205\350\243\205\347\261\273.md" => "docs/Java/basic/string\345\222\214\345\214\205\350\243\205\347\261\273.md" (100%)
rename "docs/java/basic/\344\273\243\347\240\201\345\235\227\345\222\214\344\273\243\347\240\201\346\211\247\350\241\214\351\241\272\345\272\217.md" => "docs/Java/basic/\344\273\243\347\240\201\345\235\227\345\222\214\344\273\243\347\240\201\346\211\247\350\241\214\351\241\272\345\272\217.md" (100%)
rename "docs/java/basic/\345\217\215\345\260\204.md" => "docs/Java/basic/\345\217\215\345\260\204.md" (100%)
rename "docs/java/basic/\345\244\232\347\272\277\347\250\213.md" => "docs/Java/basic/\345\244\232\347\272\277\347\250\213.md" (100%)
rename "docs/java/basic/\345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226.md" => "docs/Java/basic/\345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226.md" (100%)
rename "docs/java/basic/\346\212\275\350\261\241\347\261\273\345\222\214\346\216\245\345\217\243.md" => "docs/Java/basic/\346\212\275\350\261\241\347\261\273\345\222\214\346\216\245\345\217\243.md" (100%)
rename "docs/java/basic/\346\236\232\344\270\276\347\261\273.md" => "docs/Java/basic/\346\236\232\344\270\276\347\261\273.md" (100%)
rename "docs/java/basic/\346\263\233\345\236\213.md" => "docs/Java/basic/\346\263\233\345\236\213.md" (100%)
rename "docs/java/basic/\346\267\261\345\205\245\347\220\206\350\247\243\345\206\205\351\203\250\347\261\273.md" => "docs/Java/basic/\346\267\261\345\205\245\347\220\206\350\247\243\345\206\205\351\203\250\347\261\273.md" (100%)
rename "docs/java/basic/\347\273\247\346\211\277\343\200\201\345\260\201\350\243\205\343\200\201\345\244\232\346\200\201\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md" => "docs/Java/basic/\347\273\247\346\211\277\343\200\201\345\260\201\350\243\205\343\200\201\345\244\232\346\200\201\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md" (100%)
rename "docs/java/basic/\350\247\243\350\257\273Java\344\270\255\347\232\204\345\233\236\350\260\203.md" => "docs/Java/basic/\350\247\243\350\257\273Java\344\270\255\347\232\204\345\233\236\350\260\203.md" (100%)
rename "docs/java/basic/\351\235\242\345\220\221\345\257\271\350\261\241\345\237\272\347\241\200.md" => "docs/Java/basic/\351\235\242\345\220\221\345\257\271\350\261\241\345\237\272\347\241\200.md" (100%)
rename "docs/java/collection/Java\351\233\206\345\220\210\347\261\273\346\200\273\347\273\223.md" => "docs/Java/collection/Java\351\233\206\345\220\210\347\261\273\346\200\273\347\273\223.md" (100%)
rename "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashMap\345\222\214HashTable.md" => "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashMap\345\222\214HashTable.md" (100%)
rename "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashSet\357\274\214TreeSet\344\270\216LinkedHashSet.md" => "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashSet\357\274\214TreeSet\344\270\216LinkedHashSet.md" (100%)
rename "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Iterator\357\274\214fail-fast\346\234\272\345\210\266\344\270\216\346\257\224\350\276\203\345\231\250.md" => "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Iterator\357\274\214fail-fast\346\234\272\345\210\266\344\270\216\346\257\224\350\276\203\345\231\250.md" (100%)
rename "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Java\351\233\206\345\220\210\347\261\273\347\273\206\350\212\202\347\262\276\350\256\262.md" => "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Java\351\233\206\345\220\210\347\261\273\347\273\206\350\212\202\347\262\276\350\256\262.md" (100%)
rename "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Queue\345\222\214LinkedList.md" => "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Queue\345\222\214LinkedList.md" (100%)
rename "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232TreeMap\345\222\214\347\272\242\351\273\221\346\240\221.md" => "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232TreeMap\345\222\214\347\272\242\351\273\221\346\240\221.md" (100%)
rename "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\344\270\200\346\226\207\350\257\273\346\207\202ArrayList,Vector\344\270\216Stack\344\275\277\347\224\250\346\226\271\346\263\225\345\222\214\345\256\236\347\216\260\345\216\237\347\220\206.md" => "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\344\270\200\346\226\207\350\257\273\346\207\202ArrayList,Vector\344\270\216Stack\344\275\277\347\224\250\346\226\271\346\263\225\345\222\214\345\256\236\347\216\260\345\216\237\347\220\206.md" (100%)
rename "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243LinkedHashMap\345\222\214LRU\347\274\223\345\255\230.md" => "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243LinkedHashMap\345\222\214LRU\347\274\223\345\255\230.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\344\270\255\347\232\204\345\205\254\345\271\263\351\224\201\344\270\216\351\235\236\345\205\254\345\271\263\351\224\201\357\274\214Condtion.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\344\270\255\347\232\204\345\205\254\345\271\263\351\224\201\344\270\216\351\235\236\345\205\254\345\271\263\351\224\201\357\274\214Condtion.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\345\205\261\344\272\253\346\250\241\345\274\217\344\270\216\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273\347\232\204\345\256\236\347\216\260.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\345\205\261\344\272\253\346\250\241\345\274\217\344\270\216\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273\347\232\204\345\256\236\347\216\260.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232ForkJoin\345\271\266\345\217\221\346\241\206\346\236\266\344\270\216\345\267\245\344\275\234\347\252\203\345\217\226\347\256\227\346\263\225\345\211\226\346\236\220.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232ForkJoin\345\271\266\345\217\221\346\241\206\346\236\266\344\270\216\345\267\245\344\275\234\347\252\203\345\217\226\347\256\227\346\263\225\345\211\226\346\236\220.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JMM\344\270\255\347\232\204final\345\205\263\351\224\256\345\255\227\350\247\243\346\236\220.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JMM\344\270\255\347\232\204final\345\205\263\351\224\256\345\255\227\350\247\243\346\236\220.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\344\270\255\345\270\270\347\224\250\347\232\204Unsafe\345\222\214Locksupport.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\344\270\255\345\270\270\347\224\250\347\232\204Unsafe\345\222\214Locksupport.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\347\232\204\346\240\270\345\277\203\347\261\273AQS\350\257\246\350\247\243.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\347\232\204\346\240\270\345\277\203\347\261\273AQS\350\257\246\350\247\243.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204HashMap\345\222\214ConcurrentHashMap\345\205\250\350\247\243\346\236\220.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204HashMap\345\222\214ConcurrentHashMap\345\205\250\350\247\243\346\236\220.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204\351\224\201Lock\345\222\214synchronized.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204\351\224\201Lock\345\222\214synchronized.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\345\206\205\345\255\230\346\250\241\345\236\213JMM\346\200\273\347\273\223.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\345\206\205\345\255\230\346\250\241\345\236\213JMM\346\200\273\347\273\223.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\350\257\273\345\206\231\351\224\201ReentrantReadWriteLock\346\272\220\347\240\201\345\210\206\346\236\220.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\350\257\273\345\206\231\351\224\201ReentrantReadWriteLock\346\272\220\347\240\201\345\210\206\346\236\220.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\344\270\211\345\244\247\351\227\256\351\242\230\344\270\216volatile\345\205\263\351\224\256\345\255\227\357\274\214CAS\346\223\215\344\275\234.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\344\270\211\345\244\247\351\227\256\351\242\230\344\270\216volatile\345\205\263\351\224\256\345\255\227\357\274\214CAS\346\223\215\344\275\234.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\345\237\272\347\241\200\344\270\216Java\345\244\232\347\272\277\347\250\213.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\345\237\272\347\241\200\344\270\216Java\345\244\232\347\272\277\347\250\213.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243Java\345\206\205\345\255\230\346\250\241\345\236\213JMM.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243Java\345\206\205\345\255\230\346\250\241\345\236\213JMM.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Java\347\272\277\347\250\213\346\261\240\350\256\276\350\256\241\346\200\235\346\203\263\345\217\212\346\272\220\347\240\201\345\256\236\347\216\260.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Java\347\272\277\347\250\213\346\261\240\350\256\276\350\256\241\346\200\235\346\203\263\345\217\212\346\272\220\347\240\201\345\256\236\347\216\260.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\350\247\243\350\257\273Java\351\230\273\345\241\236\351\230\237\345\210\227BlockingQueue.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\350\247\243\350\257\273Java\351\230\273\345\241\236\351\230\237\345\210\227BlockingQueue.md" (100%)
rename "docs/java/concurrency/Java\345\271\266\345\217\221\347\274\226\347\250\213\345\255\246\344\271\240\346\200\273\347\273\223.md" => "docs/Java/concurrency/Java\345\271\266\345\217\221\347\274\226\347\250\213\345\255\246\344\271\240\346\200\273\347\273\223.md" (100%)
rename "docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232JDK\344\270\255\347\232\204\350\256\276\350\256\241\346\250\241\345\274\217.md" => "docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232JDK\344\270\255\347\232\204\350\256\276\350\256\241\346\250\241\345\274\217.md" (100%)
rename "docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232Spring\346\266\211\345\217\212\345\210\260\347\232\204\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217.md" => "docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232Spring\346\266\211\345\217\212\345\210\260\347\232\204\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217.md" (100%)
rename "docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\357\274\210\345\267\245\345\216\202\357\274\214\345\215\225\344\276\213\347\255\211\357\274\211.md" => "docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\357\274\210\345\267\245\345\216\202\357\274\214\345\215\225\344\276\213\347\255\211\357\274\211.md" (100%)
rename "docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\357\274\210\344\273\243\347\220\206\346\250\241\345\274\217\357\274\214\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217\347\255\211\357\274\211.md" => "docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\357\274\210\344\273\243\347\220\206\346\250\241\345\274\217\357\274\214\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217\347\255\211\357\274\211.md" (100%)
rename "docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\357\274\210\347\255\226\347\225\245\357\274\214\350\247\202\345\257\237\350\200\205\347\255\211\357\274\211.md" => "docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\357\274\210\347\255\226\347\225\245\357\274\214\350\247\202\345\257\237\350\200\205\347\255\211\357\274\211.md" (100%)
rename "docs/java/design-parttern/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\346\200\273\347\273\223.md" => "docs/Java/design-parttern/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\346\200\273\347\273\223.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\344\270\216NIO\346\200\273\347\273\223.md" => "docs/Java/network/Java\347\275\221\347\273\234\344\270\216NIO\346\200\273\347\273\223.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232IO\346\250\241\345\236\213\344\270\216Java\347\275\221\347\273\234\347\274\226\347\250\213\346\250\241\345\236\213.md" => "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232IO\346\250\241\345\236\213\344\270\216Java\347\275\221\347\273\234\347\274\226\347\250\213\346\250\241\345\236\213.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JAVA\344\270\255\345\216\237\347\224\237\347\232\204socket\351\200\232\344\277\241\346\234\272\345\210\266.md" => "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JAVA\344\270\255\345\216\237\347\224\237\347\232\204socket\351\200\232\344\277\241\346\234\272\345\210\266.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JavaNIO\344\270\200\346\255\245\346\255\245\346\236\204\345\273\272IO\345\244\232\350\267\257\345\244\215\347\224\250\347\232\204\350\257\267\346\261\202\346\250\241\345\236\213.md" => "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JavaNIO\344\270\200\346\255\245\346\255\245\346\236\204\345\273\272IO\345\244\232\350\267\257\345\244\215\347\224\250\347\232\204\350\257\267\346\261\202\346\250\241\345\236\213.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Java\351\235\236\351\230\273\345\241\236IO\345\222\214\345\274\202\346\255\245IO.md" => "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Java\351\235\236\351\230\273\345\241\236IO\345\222\214\345\274\202\346\255\245IO.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232LinuxEpoll\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" => "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232LinuxEpoll\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Tomcat\344\270\255\347\232\204Connector\346\272\220\347\240\201\345\210\206\346\236\220\357\274\210NIO\357\274\211.md" => "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Tomcat\344\270\255\347\232\204Connector\346\272\220\347\240\201\345\210\206\346\236\220\357\274\210NIO\357\274\211.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\345\237\272\344\272\216NIO\347\232\204\347\275\221\347\273\234\347\274\226\347\250\213\346\241\206\346\236\266Netty.md" => "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\345\237\272\344\272\216NIO\347\232\204\347\275\221\347\273\234\347\274\226\347\250\213\346\241\206\346\236\266Netty.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220NIO\345\214\205\344\270\255\347\232\204Buffer\343\200\201Channel\345\222\214Selector.md" => "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220NIO\345\214\205\344\270\255\347\232\204Buffer\343\200\201Channel\345\222\214Selector.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220mmap\345\222\214DirectBuffer.md" => "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220mmap\345\222\214DirectBuffer.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\350\260\210Linux\344\270\255Selector\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md" => "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\350\260\210Linux\344\270\255Selector\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md" (100%)
rename "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Tomcat\344\270\255\347\232\204NIO\346\250\241\345\236\213.md" => "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Tomcat\344\270\255\347\232\204NIO\346\250\241\345\236\213.md" (100%)
rename "docs/java-web/JavaWeb\346\212\200\346\234\257\346\200\273\347\273\223.md" => "docs/JavaWeb/JavaWeb\346\212\200\346\234\257\346\200\273\347\273\223.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Hibernate\345\205\245\351\227\250\347\273\217\345\205\270\344\270\216\346\263\250\350\247\243\345\274\217\345\274\200\345\217\221.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Hibernate\345\205\245\351\227\250\347\273\217\345\205\270\344\270\216\346\263\250\350\247\243\345\274\217\345\274\200\345\217\221.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JDBC\347\232\204\350\277\233\345\214\226\344\270\216\350\277\236\346\216\245\346\261\240\346\212\200\346\234\257.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JDBC\347\232\204\350\277\233\345\214\226\344\270\216\350\277\236\346\216\245\346\261\240\346\212\200\346\234\257.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JSP\344\270\216Servlet\347\232\204\346\233\276\347\273\217\344\270\216\347\216\260\345\234\250.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JSP\344\270\216Servlet\347\232\204\346\233\276\347\273\217\344\270\216\347\216\260\345\234\250.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JavaWeb\347\232\204\347\224\261\346\235\245\345\222\214\345\237\272\347\241\200\347\237\245\350\257\206.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JavaWeb\347\232\204\347\224\261\346\235\245\345\222\214\345\237\272\347\241\200\347\237\245\350\257\206.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Java\346\227\245\345\277\227\347\263\273\347\273\237\347\232\204\350\257\236\347\224\237\344\270\216\345\217\221\345\261\225.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Java\346\227\245\345\277\227\347\263\273\347\273\237\347\232\204\350\257\236\347\224\237\344\270\216\345\217\221\345\261\225.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Mybatis\345\205\245\351\227\250.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Mybatis\345\205\245\351\227\250.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Servlet\345\267\245\344\275\234\345\216\237\347\220\206\350\257\246\350\247\243.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Servlet\345\267\245\344\275\234\345\216\237\347\220\206\350\257\246\350\247\243.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat5\346\200\273\344\275\223\346\236\266\346\236\204\345\211\226\346\236\220.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat5\346\200\273\344\275\223\346\236\266\346\236\204\345\211\226\346\236\220.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat\345\222\214\345\205\266\344\273\226WEB\345\256\271\345\231\250\347\232\204\345\214\272\345\210\253.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat\345\222\214\345\205\266\344\273\226WEB\345\256\271\345\231\250\347\232\204\345\214\272\345\210\253.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216JavaBean\350\256\262\345\210\260Spring.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216JavaBean\350\256\262\345\210\260Spring.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216\346\211\213\345\212\250\347\274\226\350\257\221\346\211\223\345\214\205\345\210\260\351\241\271\347\233\256\346\236\204\345\273\272\345\267\245\345\205\267Maven.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216\346\211\213\345\212\250\347\274\226\350\257\221\346\211\223\345\214\205\345\210\260\351\241\271\347\233\256\346\236\204\345\273\272\345\267\245\345\205\267Maven.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\210\235\346\216\242Tomcat9\347\232\204HTTP\350\257\267\346\261\202\350\277\207\347\250\213.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\210\235\346\216\242Tomcat9\347\232\204HTTP\350\257\267\346\261\202\350\277\207\347\250\213.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\215\225\345\205\203\346\265\213\350\257\225\346\241\206\346\236\266Junit.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\215\225\345\205\203\346\265\213\350\257\225\346\241\206\346\236\266Junit.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\236\201\347\256\200\351\205\215\347\275\256\347\232\204SpringBoot.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\236\201\347\256\200\351\205\215\347\275\256\347\232\204SpringBoot.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\265\205\346\236\220Tomcat\350\257\267\346\261\202\345\244\204\347\220\206\346\265\201\347\250\213\344\270\216\345\220\257\345\212\250\351\203\250\347\275\262\350\277\207\347\250\213.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\265\205\346\236\220Tomcat\350\257\267\346\261\202\345\244\204\347\220\206\346\265\201\347\250\213\344\270\216\345\220\257\345\212\250\351\203\250\347\275\262\350\277\207\347\250\213.md" (100%)
rename "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\267\261\345\205\245\346\265\205\345\207\272Mybatis\345\237\272\346\234\254\345\216\237\347\220\206.md" => "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\267\261\345\205\245\346\265\205\345\207\272Mybatis\345\237\272\346\234\254\345\216\237\347\220\206.md" (100%)
rename "docs/spring/SpringAOP\347\232\204\346\246\202\345\277\265\344\270\216\344\275\234\347\224\250.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/SpringAOP\347\232\204\346\246\202\345\277\265\344\270\216\344\275\234\347\224\250.md" (100%)
rename "docs/spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md" (100%)
rename "docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\225\260\346\215\256\345\272\223\347\232\204\350\256\277\351\227\256.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\345\257\271\344\272\216\346\225\260\346\215\256\345\272\223\347\232\204\350\256\277\351\227\256.md" (100%)
rename "docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md" (100%)
rename "docs/spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md" (100%)
rename "docs/spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md" (100%)
rename "docs/spring/Spring\344\270\255\347\232\204\350\265\204\346\272\220\347\256\241\347\220\206.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204\350\265\204\346\272\220\347\256\241\347\220\206.md" (100%)
rename "docs/spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md" (100%)
rename "docs/spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md" (100%)
rename "docs/spring/Spring\345\220\210\351\233\206.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\345\220\210\351\233\206.md" (100%)
rename "docs/spring/Spring\345\256\271\345\231\250\344\270\216IOC.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\345\256\271\345\231\250\344\270\216IOC.md" (100%)
rename "docs/spring/Spring\345\270\270\350\247\201\346\263\250\350\247\243.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\345\270\270\350\247\201\346\263\250\350\247\243.md" (100%)
rename "docs/spring/Spring\346\246\202\350\277\260.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\346\246\202\350\277\260.md" (100%)
rename "docs/spring/\347\254\254\344\270\200\344\270\252Spring\345\272\224\347\224\250.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/\347\254\254\344\270\200\344\270\252Spring\345\272\224\347\224\250.md" (100%)
rename "docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\344\273\273\345\212\241\350\260\203\345\272\246\344\270\216@Async.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\344\270\255\347\232\204\344\273\273\345\212\241\350\260\203\345\272\246\344\270\216@Async.md" (100%)
rename "docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\346\227\245\345\277\227\347\256\241\347\220\206.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\344\270\255\347\232\204\346\227\245\345\277\227\347\256\241\347\220\206.md" (100%)
rename "docs/spring/SpringBoot/SpringBoot\345\270\270\350\247\201\346\263\250\350\247\243.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\345\270\270\350\247\201\346\263\250\350\247\243.md" (100%)
rename "docs/spring/SpringBoot/SpringBoot\345\272\224\347\224\250\344\271\237\345\217\257\344\273\245\351\203\250\347\275\262\345\210\260\345\244\226\351\203\250Tomcat.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\345\272\224\347\224\250\344\271\237\345\217\257\344\273\245\351\203\250\347\275\262\345\210\260\345\244\226\351\203\250Tomcat.md" (100%)
rename "docs/spring/SpringBoot/SpringBoot\347\224\237\344\272\247\347\216\257\345\242\203\345\267\245\345\205\267Actuator.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\224\237\344\272\247\347\216\257\345\242\203\345\267\245\345\205\267Actuator.md" (100%)
rename "docs/spring/SpringBoot/SpringBoot\347\232\204Starter\346\234\272\345\210\266.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204Starter\346\234\272\345\210\266.md" (100%)
rename "docs/spring/SpringBoot/SpringBoot\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md" (100%)
rename "docs/spring/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md" (100%)
rename "docs/spring/SpringBoot/SpringBoot\347\232\204\351\205\215\347\275\256\346\226\207\344\273\266\347\256\241\347\220\206.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204\351\205\215\347\275\256\346\226\207\344\273\266\347\256\241\347\220\206.md" (100%)
rename "docs/spring/SpringBoot/SpringBoot\350\207\252\345\270\246\347\232\204\347\203\255\351\203\250\347\275\262\345\267\245\345\205\267.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\350\207\252\345\270\246\347\232\204\347\203\255\351\203\250\347\275\262\345\267\245\345\205\267.md" (100%)
rename "docs/spring/SpringBoot/SpringBoot\351\233\206\346\210\220Swagger\345\256\236\347\216\260API\346\226\207\346\241\243\350\207\252\345\212\250\347\224\237\346\210\220.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\351\233\206\346\210\220Swagger\345\256\236\347\216\260API\346\226\207\346\241\243\350\207\252\345\212\250\347\224\237\346\210\220.md" (100%)
rename "docs/spring/SpringBoot/Spring\345\270\270\350\247\201\346\263\250\350\247\243\344\275\277\347\224\250\346\214\207\345\215\227(\345\214\205\345\220\253Spring+SpringMVC+SpringBoot).md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/Spring\345\270\270\350\247\201\346\263\250\350\247\243\344\275\277\347\224\250\346\214\207\345\215\227(\345\214\205\345\220\253Spring+SpringMVC+SpringBoot).md" (100%)
rename "docs/spring/SpringBoot/\345\237\272\344\272\216SpringBoot\344\270\255\347\232\204\345\274\200\346\272\220\347\233\221\346\216\247\345\267\245\345\205\267SpringBootAdmin.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/\345\237\272\344\272\216SpringBoot\344\270\255\347\232\204\345\274\200\346\272\220\347\233\221\346\216\247\345\267\245\345\205\267SpringBootAdmin.md" (100%)
rename "docs/spring/SpringBoot/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md" (100%)
rename "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\233\275\351\231\205\345\214\226\345\212\237\350\203\275.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\345\233\275\351\231\205\345\214\226\345\212\237\350\203\275.md" (100%)
rename "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\270\270\347\224\250\345\212\237\350\203\275.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\345\270\270\347\224\250\345\212\237\350\203\275.md" (100%)
rename "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\274\202\345\270\270\345\244\204\347\220\206\345\231\250.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\345\274\202\345\270\270\345\244\204\347\220\206\345\231\250.md" (100%)
rename "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\346\213\246\346\210\252\345\231\250.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\346\213\246\346\210\252\345\231\250.md" (100%)
rename "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\231\250.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\231\250.md" (100%)
rename "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\277\207\346\273\244\345\231\250Filter.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\350\277\207\346\273\244\345\231\250Filter.md" (100%)
rename "docs/spring/SpringMVC/SpringMVC\345\237\272\346\234\254\344\273\213\347\273\215\344\270\216\345\277\253\351\200\237\345\205\245\351\227\250.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\345\237\272\346\234\254\344\273\213\347\273\215\344\270\216\345\277\253\351\200\237\345\205\245\351\227\250.md" (100%)
rename "docs/spring/SpringMVC/SpringMVC\345\246\202\344\275\225\345\256\236\347\216\260\346\226\207\344\273\266\344\270\212\344\274\240.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\345\246\202\344\275\225\345\256\236\347\216\260\346\226\207\344\273\266\344\270\212\344\274\240.md" (100%)
rename "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md" (100%)
rename "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md" (100%)
rename "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md" (100%)
rename "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md" (100%)
rename "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md" (100%)
rename "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md" (100%)
rename "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md" (100%)
rename "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md" (100%)
rename "docs/big-backEnd/Hadoop\347\224\237\346\200\201\346\200\273\347\273\223.md" => "docs/backend/Hadoop\347\224\237\346\200\201\346\200\273\347\273\223.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\345\274\200\347\257\207\357\274\232\344\272\221\350\256\241\347\256\227\357\274\214\345\244\247\346\225\260\346\215\256\344\270\216AI\347\232\204\346\225\205\344\272\213.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\345\274\200\347\257\207\357\274\232\344\272\221\350\256\241\347\256\227\357\274\214\345\244\247\346\225\260\346\215\256\344\270\216AI\347\232\204\346\225\205\344\272\213.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Docker \346\240\270\345\277\203\346\212\200\346\234\257\344\270\216\345\256\236\347\216\260\345\216\237\347\220\206.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Docker \346\240\270\345\277\203\346\212\200\346\234\257\344\270\216\345\256\236\347\216\260\345\216\237\347\220\206.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Elasticsearch\344\270\216solr\345\205\245\351\227\250\345\256\236\350\267\265.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Elasticsearch\344\270\216solr\345\205\245\351\227\250\345\256\236\350\267\265.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Lucene\345\237\272\347\241\200\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Lucene\345\237\272\347\241\200\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\346\236\266\346\236\204\350\256\276\350\256\241.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\346\236\266\346\236\204\350\256\276\350\256\241.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\347\232\204\345\237\272\347\237\263KVM.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\347\232\204\345\237\272\347\237\263KVM.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\344\272\221\350\256\241\347\256\227\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\344\272\221\350\256\241\347\256\227\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\205\210\346\220\236\346\207\202Docker\346\240\270\345\277\203\346\246\202\345\277\265\345\220\247.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\205\210\346\220\236\346\207\202Docker\346\240\270\345\277\203\346\246\202\345\277\265\345\220\247.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\215\201\345\210\206\351\222\237\347\220\206\350\247\243Kubernetes\346\240\270\345\277\203\346\246\202\345\277\265.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\215\201\345\210\206\351\222\237\347\220\206\350\247\243Kubernetes\346\240\270\345\277\203\346\246\202\345\277\265.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\215\213\344\270\200\346\215\213\345\244\247\346\225\260\346\215\256\347\240\224\345\217\221\347\232\204\345\237\272\346\234\254\346\246\202\345\277\265.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\215\213\344\270\200\346\215\213\345\244\247\346\225\260\346\215\256\347\240\224\345\217\221\347\232\204\345\237\272\346\234\254\346\246\202\345\277\265.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\237\272\347\241\200\345\200\222\346\216\222\347\264\242\345\274\225.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\237\272\347\241\200\345\200\222\346\216\222\347\264\242\345\274\225.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\267\245\344\275\234\345\216\237\347\220\206.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\267\245\344\275\234\345\216\237\347\220\206.md" (100%)
rename "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\347\231\275\350\257\235\350\231\232\346\213\237\345\214\226\346\212\200\346\234\257.md" => "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\347\231\275\350\257\235\350\231\232\346\213\237\345\214\226\346\212\200\346\234\257.md" (100%)
diff --git a/ReadMe.md b/ReadMe.md
index c73d49b..83bc437 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -29,239 +29,202 @@
-
-
-
-## 目录
-
-- [Java基础](#Java基础)
- - [基础知识](#基础知识)
- - [容器](#容器)
- - [设计模�](#设计模�)
-- [JavaWeb](#JavaWeb)
- - [Spring](#Spring)
- - [SpringMVC](#SpringMVC)
- - [SpringBoot](#SpringBoot)
-- [Java进阶](#Java进阶)
- - [并�](#并�)
- - [JVM](#JVM)
- - [Java网络编程](#Java网络编程)
-- [计算机基础](#计算机基础)
- - [计算机网络](#计算机网络)
- - [�作系统](#�作系统)
- - [Linux相关](#linux相关)
- - [数�结构与算法](#数�结构与算法)
- - [数�结构](#数�结构)
- - [算法](#算法)
-- [数�库](#数�库)
- - [MySQL](#MySQL)
-- [缓å˜](#缓å˜)
- - [Redis](#Redis)
-- [消�队列](#消�队列)
- - [Kafka](#Kafka)
-- [大�端](#大�端)
-- [分布�](#分布�)
- - [�论](#�论)
- - [实战](#实战)
-- [�试指�](#�试指�)
- - [æ ¡æ‹›æŒ‡å�—](#æ ¡æ‹›æŒ‡å�—)
- - [��](#��)
-- [工具](#工具)
- - [Git](#git)
-- [资料](#资料)
- - [书�](#书�)
-- [待办](#待办)
-- [说明](#说明)
-- [微信公众�](#微信公众�)
## Java基础
### 基础知识
-* [��对象基础](docs/java/basic/��对象基础.md)
-* [Java基本数�类型](docs/java/basic/Java基本数�类型.md)
-* [string和包装类](docs/java/basic/string和包装类.md)
-* [final关键å—特性](docs/java/basic/final关键å—特性.md)
-
-* [Java类和包](docs/java/basic/Java类和包.md)
-* [抽象类和接�](docs/java/basic/抽象类和接�.md)
-* [代ç �å�—和代ç �执行顺åº�](docs/java/basic/代ç �å�—和代ç �执行顺åº�.md)
-* [Java自动拆箱装箱里��的秘密](docs/java/basic/Java自动拆箱装箱里��的秘密.md)
-* [Javaä¸çš„Class类和Objectç±»](docs/java/basic/Javaä¸çš„Class类和Objectç±».md)
-* [Java异常](docs/java/basic/Java异常.md)
-* [解读Javaä¸çš„回调](docs/java/basic/解读Javaä¸çš„回调.md)
-* [�射](docs/java/basic/�射.md)
-* [泛型](docs/java/basic/泛型.md)
-* [枚举类](docs/java/basic/枚举类.md)
-* [Java注解和最佳实践](docs/java/basic/Java注解和最佳实践.md)
-* [JavaIO�](docs/java/basic/JavaIO�.md)
-* [多线程](docs/java/basic/多线程.md)
-* [深入�解内部类](docs/java/basic/深入�解内部类.md)
-* [javacå’Œjavap](docs/java/basic/javacå’Œjavap.md)
-* [Java8新特性终�指�](docs/java/basic/Java8新特性终�指�.md)
-* [�列化和��列化](docs/java/basic/�列化和��列化.md)
-* [继承�装多�的实现原�](docs/java/basic/继承�装多�的实现原�.md)
+* [��对象基础](docs/Java/basic/��对象基础.md)
+* [Java基本数�类型](docs/Java/basic/Java基本数�类型.md)
+* [string和包装类](docs/Java/basic/string和包装类.md)
+* [final关键å—特性](docs/Java/basic/final关键å—特性.md)
+
+* [Java类和包](docs/Java/basic/Java类和包.md)
+* [抽象类和接�](docs/Java/basic/抽象类和接�.md)
+* [代ç �å�—和代ç �执行顺åº�](docs/Java/basic/代ç �å�—和代ç �执行顺åº�.md)
+* [Java自动拆箱装箱里��的秘密](docs/Java/basic/Java自动拆箱装箱里��的秘密.md)
+* [Javaä¸çš„Class类和Objectç±»](docs/Java/basic/Javaä¸çš„Class类和Objectç±».md)
+* [Java异常](docs/Java/basic/Java异常.md)
+* [解读Javaä¸çš„回调](docs/Java/basic/解读Javaä¸çš„回调.md)
+* [�射](docs/Java/basic/�射.md)
+* [泛型](docs/Java/basic/泛型.md)
+* [枚举类](docs/Java/basic/枚举类.md)
+* [Java注解和最佳实践](docs/Java/basic/Java注解和最佳实践.md)
+* [JavaIO�](docs/Java/basic/JavaIO�.md)
+* [多线程](docs/Java/basic/多线程.md)
+* [深入�解内部类](docs/Java/basic/深入�解内部类.md)
+* [javacå’Œjavap](docs/Java/basic/javacå’Œjavap.md)
+* [Java8新特性终�指�](docs/Java/basic/Java8新特性终�指�.md)
+* [�列化和��列化](docs/Java/basic/�列化和��列化.md)
+* [继承�装多�的实现原�](docs/Java/basic/继承�装多�的实现原�.md)
### 容器
-* [Java集�类总结](docs/java/collection/Java集�类总结.md)
-* [Java集�详解:一文读懂ArrayList,Vector与Stack使用方法和实现原�](docs/java/collection/Java集�详解:一文读懂ArrayList,Vector与Stack使用方法和实现原�.md)
-* [Java集�详解:Queue和LinkedList](docs/java/collection/Java集�详解:Queue和LinkedList.md)
-* [Java集�详解:Iterator,fail-fast机制与比较器](docs/java/collection/Java集�详解:Iterator,fail-fast机制与比较器.md)
-* [Java集�详解:HashMap和HashTable](docs/java/collection/Java集�详解:HashMap和HashTable.md)
-* [Java集å�ˆè¯¦è§£ï¼šæ·±å…¥ç�†è§£LinkedHashMapå’ŒLRU缓å˜](docs/java/collection/Java集å�ˆè¯¦è§£ï¼šæ·±å…¥ç�†è§£LinkedHashMapå’ŒLRU缓å˜.md)
-* [Java集å�ˆè¯¦è§£ï¼šTreeMapå’Œçº¢é»‘æ ‘](docs/java/collection/Java集å�ˆè¯¦è§£ï¼šTreeMapå’Œçº¢é»‘æ ‘.md)
-* [Java集�详解:HashSet,TreeSet与LinkedHashSet](docs/java/collection/Java集�详解:HashSet,TreeSet与LinkedHashSet.md)
-* [Java集�详解:Java集�类细节精讲](docs/java/collection/Java集�详解:Java集�类细节精讲.md)
-
-### 设计模�
-
-* [设计模å¼�å¦ä¹ 总结](docs/java/design-parttern/设计模å¼�å¦ä¹ 总结.md)
-* [åˆ�探Java设计模å¼�:创建型模å¼�(工厂,å�•例ç‰ï¼‰.md](docs/java/design-parttern/åˆ�探Java设计模å¼�:创建型模å¼�(工厂,å�•例ç‰ï¼‰.md)
-* [åˆ�探Java设计模å¼�:结构型模å¼�(代ç�†æ¨¡å¼�,适é…�器模å¼�ç‰ï¼‰.md](docs/java/design-parttern/åˆ�探Java设计模å¼�:结构型模å¼�(代ç�†æ¨¡å¼�,适é…�器模å¼�ç‰ï¼‰.md)
-* [åˆ�探Java设计模å¼�:行为型模å¼�(ç–略,观察者ç‰ï¼‰.md](docs/java/design-parttern/åˆ�探Java设计模å¼�:行为型模å¼�(ç–略,观察者ç‰ï¼‰.md)
-* [åˆ�探Java设计模å¼�:JDKä¸çš„设计模å¼�.md](docs/java/design-parttern/åˆ�探Java设计模å¼�:JDKä¸çš„设计模å¼�.md)
-* [�探Java设计模�:Spring涉�到的�设计模�.md](docs/java/design-parttern/�探Java设计模�:Spring涉�到的�设计模�.md)
+* [Java集�类总结](docs/Java/collection/Java集�类总结.md)
+* [Java集�详解:一文读懂ArrayList,Vector与Stack使用方法和实现原�](docs/Java/collection/Java集�详解:一文读懂ArrayList,Vector与Stack使用方法和实现原�.md)
+* [Java集�详解:Queue和LinkedList](docs/Java/collection/Java集�详解:Queue和LinkedList.md)
+* [Java集�详解:Iterator,fail-fast机制与比较器](docs/Java/collection/Java集�详解:Iterator,fail-fast机制与比较器.md)
+* [Java集�详解:HashMap和HashTable](docs/Java/collection/Java集�详解:HashMap和HashTable.md)
+* [Java集å�ˆè¯¦è§£ï¼šæ·±å…¥ç�†è§£LinkedHashMapå’ŒLRU缓å˜](docs/Java/collection/Java集å�ˆè¯¦è§£ï¼šæ·±å…¥ç�†è§£LinkedHashMapå’ŒLRU缓å˜.md)
+* [Java集å�ˆè¯¦è§£ï¼šTreeMapå’Œçº¢é»‘æ ‘](docs/Java/collection/Java集å�ˆè¯¦è§£ï¼šTreeMapå’Œçº¢é»‘æ ‘.md)
+* [Java集�详解:HashSet,TreeSet与LinkedHashSet](docs/Java/collection/Java集�详解:HashSet,TreeSet与LinkedHashSet.md)
+* [Java集�详解:Java集�类细节精讲](docs/Java/collection/Java集�详解:Java集�类细节精讲.md)
## JavaWeb
-* [走进JavaWeb技术世界:JavaWeb的由�和基础知识](docs/java-web/走进JavaWeb技术世界:JavaWeb的由�和基础知识.md)
-* [走进JavaWeb技术世界:JSP与Servlet的曾�与现在](docs/java-web/走进JavaWeb技术世界:JSP与Servlet的曾�与现在.md)
-* [èµ°è¿›JavaWeb技术世界:JDBCçš„è¿›åŒ–ä¸Žè¿žæŽ¥æ± æŠ€æœ¯](docs/java-web/èµ°è¿›JavaWeb技术世界:JDBCçš„è¿›åŒ–ä¸Žè¿žæŽ¥æ± æŠ€æœ¯.md)
-* [走进JavaWeb技术世界:Servlet工作原�详解](docs/java-web/走进JavaWeb技术世界:Servlet工作原�详解.md)
-* [走进JavaWeb技术世界:�探Tomcat的HTTP请求过程](docs/java-web/走进JavaWeb技术世界:�探Tomcat的HTTP请求过程.md)
-* [走进JavaWeb技术世界:Tomcat5总体架构剖�](docs/java-web/走进JavaWeb技术世界:Tomcat5总体架构剖�.md)
-* [走进JavaWeb技术世界:Tomcat和其他WEB容器的区别](docs/java-web/走进JavaWeb技术世界:Tomcat和其他WEB容器的区别.md)
-* [走进JavaWeb技术世界:浅�Tomcat9请求处��程与�动部署过程](docs/java-web/走进JavaWeb技术世界:浅�Tomcat9请求处��程与�动部署过程.md)
-* [走进JavaWeb技术世界:Java日志系统的诞生与�展](docs/java-web/走进JavaWeb技术世界:Java日志系统的诞生与�展.md)
-* [走进JavaWeb技术世界:从JavaBean讲到Spring](docs/java-web/走进JavaWeb技术世界:从JavaBean讲到Spring.md)
-* [走进JavaWeb技术世界:�元测试框架Junit](docs/java-web/走进JavaWeb技术世界:�元测试框架Junit.md)
-* [走进JavaWeb技术世界:从手动编译打包到项目构建工具Maven](docs/java-web/走进JavaWeb技术世界:从手动编译打包到项目构建工具Maven.md)
-* [走进JavaWeb技术世界:Hibernate入门�典与注解�开�](docs/java-web/走进JavaWeb技术世界:Hibernate入门�典与注解�开�.md)
-* [走进JavaWeb技术世界:Mybatis入门](docs/java-web/走进JavaWeb技术世界:Mybatis入门.md)
-* [走进JavaWeb技术世界:深入浅出Mybatis基本原�](docs/java-web/走进JavaWeb技术世界:深入浅出Mybatis基本原�.md)
-* [走进JavaWeb技术世界:�简�置的SpringBoot](docs/java-web/走进JavaWeb技术世界:�简�置的SpringBoot.md)
-
-### Spring
-
-
-* [SpringAOP的概念与作用](docs/spring/Spring常�注解.md)
-* [SpringBean的定义与管ç�†ï¼ˆæ ¸å¿ƒï¼‰](docs/spring/Spring常è§�注解.md)
-* [Springä¸å¯¹äºŽæ•°æ�®åº“的访问](docs/spring/Spring常è§�注解.md)
-* [Springä¸å¯¹äºŽæ ¡éªŒåŠŸèƒ½çš„æ”¯æŒ�](docs/spring/Spring常è§�注解.md)
-* [Springä¸çš„Environment环境å�˜é‡�](docs/spring/Spring常è§�注解.md)
-* [Springä¸çš„事件处ç�†æœºåˆ¶](docs/spring/Spring常è§�注解.md)
-* [Springä¸çš„资æº�管ç�†](docs/spring/Spring常è§�注解.md)
-* [Springä¸çš„é…�置元数æ�®ï¼ˆç®¡ç�†é…�置的基本数æ�®ï¼‰](docs/spring/Spring常è§�注解.md)
-* [Spring事务基本用法](docs/spring/Spring常�注解.md)
-* [Spring�集](docs/spring/Spring常�注解.md)
-* [Spring容器与IOC](docs/spring/Spring常�注解.md)
-* [Spring常�注解](docs/spring/Spring常�注解.md)
-* [Spring概述](docs/spring/Spring常�注解.md)
-* [第一个Spring应用](docs/spring/Spring常�注解.md)
-
-* [Springæº�ç �剖æž�:Spring概述](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring概述.md)
-* [Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程.md)
-* [Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹ ](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹.md)
-* [Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�.md)
-* [Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£ ](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£.md)
-* [Springæº�ç �剖æž�:SpringAOP概述](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:SpringAOP概述.md)
-* [Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£ ](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£.md)
-* [Springæº�ç �剖æž�:Spring事务概述](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring事务概述.md)
-* [Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�](docs/spring/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�.md)
-
-### SpringMVC
-
-* [SpringMVCä¸çš„国际化功能](docs/spring/SpringMVC/SpringMVCä¸çš„国际化功能.md)
-* [SpringMVCä¸çš„异常处ç�†å™¨](docs/spring/SpringMVC/SpringMVCä¸çš„异常处ç�†å™¨.md)
-* [SpringMVCä¸çš„æ‹¦æˆªå™¨](docs/spring/SpringMVC/SpringMVCä¸çš„æ‹¦æˆªå™¨.md)
-* [SpringMVCä¸çš„视图解æž�器](docs/spring/SpringMVC/SpringMVCä¸çš„视图解æž�器.md)
-* [SpringMVCä¸çš„过滤器Filter](docs/spring/SpringMVC/SpringMVCä¸çš„过滤器Filter.md)
-* [SpringMVC基本介�与快速入门](docs/spring/SpringMVC/SpringMVC基本介�与快速入门.md)
-* [SpringMVCå¦‚ä½•å®žçŽ°æ–‡ä»¶ä¸Šä¼ ](docs/spring/SpringMVC/SpringMVCå¦‚ä½•å®žçŽ°æ–‡ä»¶ä¸Šä¼ .md)
-* [SpringMVCä¸çš„常用功能](docs/spring/SpringMVC/SpringMVCä¸çš„常用功能.md)
-
-
-* [SpringMVCæº�ç �分æž�:SpringMVC概述](docs/spring/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC概述.md)
-* [SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet](docs/spring/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet.md)
-* [SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘ ](docs/spring/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘.md)
-* [SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller ](docs/spring/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller.md)
-* [SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解](docs/spring/SpringMVC/SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解.md)
-* [SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�† ](docs/spring/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�†.md)
-
-### SpringBoot
-
-* [SpringBoot系列:SpringBoot的�世今生](docs/spring/SpringBoot/SpringBoot的�世今生.md)
-* [ç»™ä½ ä¸€ä»½SpringBoot知识清å�•.md](docs/spring/SpringBoot/ç»™ä½ ä¸€ä»½SpringBoot知识清å�•.md)
-* [Spring常�注解使用指�(包�Spring+SpringMVC+SpringBoot)](docs/spring/SpringBoot/Spring常�注解使用指�(包�Spring+SpringMVC+SpringBoot).md)
-* [SpringBootä¸çš„æ—¥å¿—管ç�†](docs/spring/SpringBoot/SpringBootä¸çš„æ—¥å¿—管ç�†.md)
-* [SpringBoot常�注解](docs/spring/SpringBoot/SpringBoot常�注解.md)
-* [SpringBoot应用也�以部署到外部Tomcat](docs/spring/SpringBoot/SpringBoot应用也�以部署到外部Tomcat.md)
-* [SpringBoot生产环境工具Actuator](docs/spring/SpringBoot/SpringBoot生产环境工具Actuator.md)
-* [SpringBoot的Starter机制](docs/spring/SpringBoot/SpringBoot的Starter机制.md)
-* [SpringBoot的�世今生](docs/spring/SpringBoot/SpringBoot的�世今生.md)
-* [SpringBoot的基本使用](docs/spring/SpringBoot/SpringBoot的基本使用.md)
-* [SpringBoot的�置文件管�](docs/spring/SpringBoot/SpringBoot的�置文件管�.md)
-* [SpringBoot自带的çƒéƒ¨ç½²å·¥å…·](docs/spring/SpringBoot/SpringBoot自带的çƒéƒ¨ç½²å·¥å…·.md)
-* [SpringBootä¸çš„任务调度与@Async](docs/spring/SpringBoot/SpringBootä¸çš„任务调度与@Async.md)
-* [基于SpringBootä¸çš„å¼€æº�监控工具SpringBootAdmin](docs/spring/SpringBoot/基于SpringBootä¸çš„å¼€æº�监控工具SpringBootAdmin.md)
-
-### SpringCloud
-
-todo
+* [走进JavaWeb技术世界:JavaWeb的由�和基础知识](docs/JavaWeb/走进JavaWeb技术世界:JavaWeb的由�和基础知识.md)
+* [走进JavaWeb技术世界:JSP与Servlet的曾�与现在](docs/JavaWeb/走进JavaWeb技术世界:JSP与Servlet的曾�与现在.md)
+* [èµ°è¿›JavaWeb技术世界:JDBCçš„è¿›åŒ–ä¸Žè¿žæŽ¥æ± æŠ€æœ¯](docs/JavaWeb/èµ°è¿›JavaWeb技术世界:JDBCçš„è¿›åŒ–ä¸Žè¿žæŽ¥æ± æŠ€æœ¯.md)
+* [走进JavaWeb技术世界:Servlet工作原�详解](docs/JavaWeb/走进JavaWeb技术世界:Servlet工作原�详解.md)
+* [走进JavaWeb技术世界:�探Tomcat的HTTP请求过程](docs/JavaWeb/走进JavaWeb技术世界:�探Tomcat的HTTP请求过程.md)
+* [走进JavaWeb技术世界:Tomcat5总体架构剖�](docs/JavaWeb/走进JavaWeb技术世界:Tomcat5总体架构剖�.md)
+* [走进JavaWeb技术世界:Tomcat和其他WEB容器的区别](docs/JavaWeb/走进JavaWeb技术世界:Tomcat和其他WEB容器的区别.md)
+* [走进JavaWeb技术世界:浅�Tomcat9请求处��程与�动部署过程](docs/JavaWeb/走进JavaWeb技术世界:浅�Tomcat9请求处��程与�动部署过程.md)
+* [走进JavaWeb技术世界:Java日志系统的诞生与�展](docs/JavaWeb/走进JavaWeb技术世界:Java日志系统的诞生与�展.md)
+* [走进JavaWeb技术世界:从JavaBean讲到Spring](docs/JavaWeb/走进JavaWeb技术世界:从JavaBean讲到Spring.md)
+* [走进JavaWeb技术世界:�元测试框架Junit](docs/JavaWeb/走进JavaWeb技术世界:�元测试框架Junit.md)
+* [走进JavaWeb技术世界:从手动编译打包到项目构建工具Maven](docs/JavaWeb/走进JavaWeb技术世界:从手动编译打包到项目构建工具Maven.md)
+* [走进JavaWeb技术世界:Hibernate入门�典与注解�开�](docs/JavaWeb/走进JavaWeb技术世界:Hibernate入门�典与注解�开�.md)
+* [走进JavaWeb技术世界:Mybatis入门](docs/JavaWeb/走进JavaWeb技术世界:Mybatis入门.md)
+* [走进JavaWeb技术世界:深入浅出Mybatis基本原�](docs/JavaWeb/走进JavaWeb技术世界:深入浅出Mybatis基本原�.md)
+* [走进JavaWeb技术世界:�简�置的SpringBoot](docs/JavaWeb/走进JavaWeb技术世界:�简�置的SpringBoot.md)
## Java进阶
-### 并�
-
-* [Java并�指�:并�基础与Java多线程](docs/java/concurrency/Java并�指�:并�基础与Java多线程.md)
-* [Javaå¹¶å�‘指å�—:深入ç�†è§£Javaå†…å˜æ¨¡åž‹JMM](docs/java/concurrency/Javaå¹¶å�‘指å�—:深入ç�†è§£Javaå†…å˜æ¨¡åž‹JMM.md)
-* [Javaå¹¶å�‘指å�—:并å�‘三大问题与volatile关键å—,CASæ“�作](docs/java/concurrency/Javaå¹¶å�‘指å�—:并å�‘三大问题与volatile关键å—,CASæ“�作.md)
-* [Javaå¹¶å�‘指å�—:Javaä¸çš„é”�Lockå’Œsynchronized](docs/java/concurrency/Javaå¹¶å�‘指å�—:Javaä¸çš„é”�Lockå’Œsynchronized.md)
-* [Javaå¹¶å�‘指å�—:JMMä¸çš„final关键å—è§£æž�](docs/java/concurrency/Javaå¹¶å�‘指å�—:JMMä¸çš„final关键å—è§£æž�.md)
-* [Javaå¹¶å�‘指å�—:Javaå†…å˜æ¨¡åž‹JMM总结](docs/java/concurrency/Javaå¹¶å�‘指å�—:Javaå†…å˜æ¨¡åž‹JMM总结.md)
-* [Javaå¹¶å�‘指å�—:JUCçš„æ ¸å¿ƒç±»AQS详解](docs/java/concurrency/Javaå¹¶å�‘指å�—:JUCçš„æ ¸å¿ƒç±»AQS详解.md)
-* [Javaå¹¶å�‘指å�—:AQSä¸çš„公平é”�与é�žå…¬å¹³é”�,Condtion](docs/java/concurrency/Javaå¹¶å�‘指å�—:AQSä¸çš„公平é”�与é�žå…¬å¹³é”�,Condtion.md)
-* [Java并�指�:AQS共享模�与并�工具类的实现](docs/java/concurrency/Java并�指�:AQS共享模�与并�工具类的实现.md)
-* [Javaå¹¶å�‘指å�—:Java读写é”�ReentrantReadWriteLockæº�ç �分æž�](docs/java/concurrency/Javaå¹¶å�‘指å�—:Java读写é”�ReentrantReadWriteLockæº�ç �分æž�.md)
-* [Java并�指�:解读Java阻塞队列BlockingQueue](docs/java/concurrency/Java并�指�:解读Java阻塞队列BlockingQueue.md)
-* [Javaå¹¶å�‘指å�—:深度解读javaçº¿ç¨‹æ± è®¾è®¡æ€�想å�Šæº�ç �实现](docs/java/concurrency/Javaå¹¶å�‘指å�—:深度解读Javaçº¿ç¨‹æ± è®¾è®¡æ€�想å�Šæº�ç �实现.md)
-* [Javaå¹¶å�‘指å�—:Javaä¸çš„HashMapå’ŒConcurrentHashMap全解æž�](docs/java/concurrency/Javaå¹¶å�‘指å�—:Javaä¸çš„HashMapå’ŒConcurrentHashMap全解æž�.md)
-* [Javaå¹¶å�‘指å�—:JUCä¸å¸¸ç”¨çš„Unsafeå’ŒLocksupport](docs/java/concurrency/Javaå¹¶å�‘指å�—:JUCä¸å¸¸ç”¨çš„Unsafeå’ŒLocksupport.md)
-* [Java并�指�:ForkJoin并�框架与工作窃�算法剖�](docs/java/concurrency/Java并�指�:ForkJoin并�框架与工作窃�算法剖�.md)
-* [Javaå¹¶å�‘编程å¦ä¹ 总结](docs/java/concurrency/Javaå¹¶å�‘编程å¦ä¹ 总结.md)
+### 并�编程
+
+* [Java并�指�:并�基础与Java多线程](docs/Java/concurrency/Java并�指�:并�基础与Java多线程.md)
+* [Javaå¹¶å�‘指å�—:深入ç�†è§£Javaå†…å˜æ¨¡åž‹JMM](docs/Java/concurrency/Javaå¹¶å�‘指å�—:深入ç�†è§£Javaå†…å˜æ¨¡åž‹JMM.md)
+* [Javaå¹¶å�‘指å�—:并å�‘三大问题与volatile关键å—,CASæ“�作](docs/Java/concurrency/Javaå¹¶å�‘指å�—:并å�‘三大问题与volatile关键å—,CASæ“�作.md)
+* [Javaå¹¶å�‘指å�—:Javaä¸çš„é”�Lockå’Œsynchronized](docs/Java/concurrency/Javaå¹¶å�‘指å�—:Javaä¸çš„é”�Lockå’Œsynchronized.md)
+* [Javaå¹¶å�‘指å�—:JMMä¸çš„final关键å—è§£æž�](docs/Java/concurrency/Javaå¹¶å�‘指å�—:JMMä¸çš„final关键å—è§£æž�.md)
+* [Javaå¹¶å�‘指å�—:Javaå†…å˜æ¨¡åž‹JMM总结](docs/Java/concurrency/Javaå¹¶å�‘指å�—:Javaå†…å˜æ¨¡åž‹JMM总结.md)
+* [Javaå¹¶å�‘指å�—:JUCçš„æ ¸å¿ƒç±»AQS详解](docs/Java/concurrency/Javaå¹¶å�‘指å�—:JUCçš„æ ¸å¿ƒç±»AQS详解.md)
+* [Javaå¹¶å�‘指å�—:AQSä¸çš„公平é”�与é�žå…¬å¹³é”�,Condtion](docs/Java/concurrency/Javaå¹¶å�‘指å�—:AQSä¸çš„公平é”�与é�žå…¬å¹³é”�,Condtion.md)
+* [Java并�指�:AQS共享模�与并�工具类的实现](docs/Java/concurrency/Java并�指�:AQS共享模�与并�工具类的实现.md)
+* [Javaå¹¶å�‘指å�—:Java读写é”�ReentrantReadWriteLockæº�ç �分æž�](docs/Java/concurrency/Javaå¹¶å�‘指å�—:Java读写é”�ReentrantReadWriteLockæº�ç �分æž�.md)
+* [Java并�指�:解读Java阻塞队列BlockingQueue](docs/Java/concurrency/Java并�指�:解读Java阻塞队列BlockingQueue.md)
+* [Javaå¹¶å�‘指å�—:深度解读javaçº¿ç¨‹æ± è®¾è®¡æ€�想å�Šæº�ç �实现](docs/Java/concurrency/Javaå¹¶å�‘指å�—:深度解读Javaçº¿ç¨‹æ± è®¾è®¡æ€�想å�Šæº�ç �实现.md)
+* [Javaå¹¶å�‘指å�—:Javaä¸çš„HashMapå’ŒConcurrentHashMap全解æž�](docs/Java/concurrency/Javaå¹¶å�‘指å�—:Javaä¸çš„HashMapå’ŒConcurrentHashMap全解æž�.md)
+* [Javaå¹¶å�‘指å�—:JUCä¸å¸¸ç”¨çš„Unsafeå’ŒLocksupport](docs/Java/concurrency/Javaå¹¶å�‘指å�—:JUCä¸å¸¸ç”¨çš„Unsafeå’ŒLocksupport.md)
+* [Java并�指�:ForkJoin并�框架与工作窃�算法剖�](docs/Java/concurrency/Java并�指�:ForkJoin并�框架与工作窃�算法剖�.md)
+* [Javaå¹¶å�‘编程å¦ä¹ 总结](docs/Java/concurrency/Javaå¹¶å�‘编程å¦ä¹ 总结.md)
### JVM
-* [JVM总结](docs/java/jvm/JVM总结.md)
-* [深入ç�†è§£JVM虚拟机:JVM内å˜çš„结构与消失的永久代](docs/java/jvm/深入ç�†è§£JVM虚拟机:JVM内å˜çš„结构与消失的永久代.md)
-* [深入�解JVM虚拟机:JVM垃圾回收基本原�和算法](docs/java/jvm/深入�解JVM虚拟机:JVM垃圾回收基本原�和算法.md)
-* [深入�解JVM虚拟机:垃圾回收器详解](docs/java/jvm/深入�解JVM虚拟机:垃圾回收器详解.md)
-* [深入ç�†è§£JVM虚拟机:Javaclass介ç»�与解æž�实践](docs/java/jvm/深入ç�†è§£JVM虚拟机:Javaå—节ç �介ç»�与解æž�实践.md)
-* [深入ç�†è§£JVM虚拟机:虚拟机å—节ç �执行引擎](docs/java/jvm/深入ç�†è§£JVM虚拟机:虚拟机å—节ç �执行引擎.md)
-* [深入ç�†è§£JVM虚拟机:深入ç�†è§£JVMç±»åŠ è½½æœºåˆ¶](docs/java/jvm/深入ç�†è§£JVM虚拟机:深入ç�†è§£JVMç±»åŠ è½½æœºåˆ¶.md)
-* [深入ç�†è§£JVM虚拟机:JNDI,OSGI,Tomcatç±»åŠ è½½å™¨å®žçŽ°](docs/java/jvm/深入ç�†è§£JVM虚拟机:JNDI,OSGI,Tomcatç±»åŠ è½½å™¨å®žçŽ°.md)
-* [深入了解JVM虚拟机:Java的编译期优化与�行期优化](docs/java/jvm/深入�解JVM虚拟机:Java的编译期优化与�行期优化.md)
-* [深入ç�†è§£JVM虚拟机:JVM监控工具与诊æ–实践](docs/java/jvm/深入ç�†è§£JVM虚拟机:JVM监控工具与诊æ–实践.md)
-* [深入�解JVM虚拟机:JVM常用�数以�调优实践](docs/java/jvm/深入�解JVM虚拟机:JVM常用�数以�调优实践.md)
-* [深入ç�†è§£JVM虚拟机:Java内å˜å¼‚常原ç�†ä¸Žå®žè·µ](docs/java/jvm/深入ç�†è§£JVM虚拟机:Java内å˜å¼‚常原ç�†ä¸Žå®žè·µ.md)
-* [深入�解JVM虚拟机:JVM性能管�神器VisualVM介�与实战](docs/java/jvm/深入�解JVM虚拟机:JVM性能管�神器VisualVM介�与实战.md)
-* [深入�解JVM虚拟机:�谈四�引用�GC实践](docs/java/jvm/深入�解JVM虚拟机:�谈四�引用�GC实践.md)
-* [深入�解JVM虚拟机:GC调优�路与常用工具](docs/java/jvm/深入�解JVM虚拟机:GC调优�路与常用工具.md)
+* [JVM总结](docs/Java/JVM/JVM总结.md)
+* [深入ç�†è§£JVM虚拟机:JVM内å˜çš„结构与消失的永久代](docs/Java/JVM/深入ç�†è§£JVM虚拟机:JVM内å˜çš„结构与消失的永久代.md)
+* [深入�解JVM虚拟机:JVM垃圾回收基本原�和算法](docs/Java/JVM/深入�解JVM虚拟机:JVM垃圾回收基本原�和算法.md)
+* [深入�解JVM虚拟机:垃圾回收器详解](docs/Java/JVM/深入�解JVM虚拟机:垃圾回收器详解.md)
+* [深入ç�†è§£JVM虚拟机:Javaclass介ç»�与解æž�实践](docs/Java/JVM/深入ç�†è§£JVM虚拟机:Javaå—节ç �介ç»�与解æž�实践.md)
+* [深入ç�†è§£JVM虚拟机:虚拟机å—节ç �执行引擎](docs/Java/JVM/深入ç�†è§£JVM虚拟机:虚拟机å—节ç �执行引擎.md)
+* [深入ç�†è§£JVM虚拟机:深入ç�†è§£JVMç±»åŠ è½½æœºåˆ¶](docs/Java/JVM/深入ç�†è§£JVM虚拟机:深入ç�†è§£JVMç±»åŠ è½½æœºåˆ¶.md)
+* [深入ç�†è§£JVM虚拟机:JNDI,OSGI,Tomcatç±»åŠ è½½å™¨å®žçŽ°](docs/Java/JVM/深入ç�†è§£JVM虚拟机:JNDI,OSGI,Tomcatç±»åŠ è½½å™¨å®žçŽ°.md)
+* [深入了解JVM虚拟机:Java的编译期优化与�行期优化](docs/Java/JVM/深入�解JVM虚拟机:Java的编译期优化与�行期优化.md)
+* [深入ç�†è§£JVM虚拟机:JVM监控工具与诊æ–实践](docs/Java/JVM/深入ç�†è§£JVM虚拟机:JVM监控工具与诊æ–实践.md)
+* [深入�解JVM虚拟机:JVM常用�数以�调优实践](docs/Java/JVM/深入�解JVM虚拟机:JVM常用�数以�调优实践.md)
+* [深入ç�†è§£JVM虚拟机:Java内å˜å¼‚常原ç�†ä¸Žå®žè·µ](docs/Java/JVM/深入ç�†è§£JVM虚拟机:Java内å˜å¼‚常原ç�†ä¸Žå®žè·µ.md)
+* [深入�解JVM虚拟机:JVM性能管�神器VisualVM介�与实战](docs/Java/JVM/深入�解JVM虚拟机:JVM性能管�神器VisualVM介�与实战.md)
+* [深入�解JVM虚拟机:�谈四�引用�GC实践](docs/Java/JVM/深入�解JVM虚拟机:�谈四�引用�GC实践.md)
+* [深入�解JVM虚拟机:GC调优�路与常用工具](docs/Java/JVM/深入�解JVM虚拟机:GC调优�路与常用工具.md)
### Java网络编程
-* [Java网络编程和NIO详解:JAVA ä¸åŽŸç”Ÿçš„ socket 通信机制](docs/java/network-programming/Java网络编程与NIO详解:JAVAä¸åŽŸç”Ÿçš„socket通信机制.md)
-* [Java网络编程与NIO详解:JAVA NIO ä¸€æ¥æ¥æž„建IO多路å¤�用的请求模型](docs/java/network-programming/Java网络编程与NIO详解:JavaNIOä¸€æ¥æ¥æž„建IO多路å¤�用的请求模型.md)
-* [Java网络编程和NIO详解:IO模型与Java网络编程模型](docs/java/network-programming/Java网络编程与NIO详解:IO模型与Java网络编程模型.md)
-* [Java网络编程与NIO详解:浅æž�NIO包ä¸çš„BufferChannelå’ŒSelector](docs/java/network-programming/Java网络编程与NIO详解:浅æž�NIO包ä¸çš„BufferChannelå’ŒSelector.md)
-* [Java网络编程和NIO详解:Javaé�žé˜»å¡žIO和异æ¥IO](docs/java/network-programming/Java网络编程与NIO详解:Javaé�žé˜»å¡žIO和异æ¥IO.md)
-* [Java网络编程与NIO详解:LinuxEpoll实现原�详解](docs/java/network-programming/Java网络编程与NIO详解:LinuxEpoll实现原�详解.md.md)
-* [Java网络编程与NIO详解:浅谈Linuxä¸Selector的实现原ç�†](docs/java/network-programming/Java网络编程与NIO详解:浅谈Linuxä¸Selector的实现原ç�†.md)
-* [Java网络编程与NIO详解:浅�mmap和DirectBuffer](docs/java/network-programming/Java网络编程与NIO详解:浅�mmap和DirectBuffer.md)
-* [Java网络编程与NIO详解:基于NIO的网络编程框架Netty](docs/java/network-programming/Java网络编程与NIO详解:基于NIO的网络编程框架Netty.md)
-* [Java网络编程与NIO详解:Java网络编程与NIO详解](docs/java/network-programming/Java网络编程与NIO详解:深度解读Tomcatä¸çš„NIO模型.md)
-* [Java网络编程与NIO详解:Tomcatä¸çš„Connectoræº�ç �分æž�(NIO)](docs/java/network-programming/Java网络编程与NIO详解:Tomcatä¸çš„Connectoræº�ç �分æž�(NIO).md)
+* [Java网络编程和NIO详解:JAVA ä¸åŽŸç”Ÿçš„ socket 通信机制](docs/Java/network/Java网络编程与NIO详解:JAVAä¸åŽŸç”Ÿçš„socket通信机制.md)
+* [Java网络编程与NIO详解:JAVA NIO ä¸€æ¥æ¥æž„建IO多路å¤�用的请求模型](docs/Java/network/Java网络编程与NIO详解:JavaNIOä¸€æ¥æ¥æž„建IO多路å¤�用的请求模型.md)
+* [Java网络编程和NIO详解:IO模型与Java网络编程模型](docs/Java/network/Java网络编程与NIO详解:IO模型与Java网络编程模型.md)
+* [Java网络编程与NIO详解:浅æž�NIO包ä¸çš„BufferChannelå’ŒSelector](docs/Java/network/Java网络编程与NIO详解:浅æž�NIO包ä¸çš„BufferChannelå’ŒSelector.md)
+* [Java网络编程和NIO详解:Javaé�žé˜»å¡žIO和异æ¥IO](docs/Java/network/Java网络编程与NIO详解:Javaé�žé˜»å¡žIO和异æ¥IO.md)
+* [Java网络编程与NIO详解:LinuxEpoll实现原�详解](docs/Java/network/Java网络编程与NIO详解:LinuxEpoll实现原�详解.md.md)
+* [Java网络编程与NIO详解:浅谈Linuxä¸Selector的实现原ç�†](docs/Java/network/Java网络编程与NIO详解:浅谈Linuxä¸Selector的实现原ç�†.md)
+* [Java网络编程与NIO详解:浅�mmap和DirectBuffer](docs/Java/network/Java网络编程与NIO详解:浅�mmap和DirectBuffer.md)
+* [Java网络编程与NIO详解:基于NIO的网络编程框架Netty](docs/Java/network/Java网络编程与NIO详解:基于NIO的网络编程框架Netty.md)
+* [Java网络编程与NIO详解:Java网络编程与NIO详解](docs/Java/network/Java网络编程与NIO详解:深度解读Tomcatä¸çš„NIO模型.md)
+* [Java网络编程与NIO详解:Tomcatä¸çš„Connectoræº�ç �分æž�(NIO)](docs/Java/network/Java网络编程与NIO详解:Tomcatä¸çš„Connectoræº�ç �分æž�(NIO).md)
+
+## Spring
+
+* [SpringAOP的概念与作用](docs/Spring全家桶/Spring/Spring常�注解.md)
+* [SpringBean的定义与管ç�†ï¼ˆæ ¸å¿ƒï¼‰](docs/Spring全家桶/Spring/Spring常è§�注解.md)
+* [Springä¸å¯¹äºŽæ•°æ�®åº“的访问](docs/Spring全家桶/Spring/Spring常è§�注解.md)
+* [Springä¸å¯¹äºŽæ ¡éªŒåŠŸèƒ½çš„æ”¯æŒ�](docs/Spring全家桶/Spring/Spring常è§�注解.md)
+* [Springä¸çš„Environment环境å�˜é‡�](docs/Spring全家桶/Spring/Spring常è§�注解.md)
+* [Springä¸çš„事件处ç�†æœºåˆ¶](docs/Spring全家桶/Spring/Spring常è§�注解.md)
+* [Springä¸çš„资æº�管ç�†](docs/Spring全家桶/Spring/Spring常è§�注解.md)
+* [Springä¸çš„é…�置元数æ�®ï¼ˆç®¡ç�†é…�置的基本数æ�®ï¼‰](docs/Spring全家桶/Spring/Spring常è§�注解.md)
+* [Spring事务基本用法](docs/Spring全家桶/Spring/Spring常�注解.md)
+* [Spring�集](docs/Spring全家桶/Spring/Spring常�注解.md)
+* [Spring容器与IOC](docs/Spring全家桶/Spring/Spring常�注解.md)
+* [Spring常�注解](docs/Spring全家桶/Spring/Spring常�注解.md)
+* [Spring概述](docs/Spring全家桶/Spring/Spring常�注解.md)
+* [第一个Spring应用](docs/Spring全家桶/Spring/Spring常�注解.md)
+
+## Springæº�ç �分æž�
+
+* [Springæº�ç �剖æž�:Spring概述](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring概述.md)
+* [Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程.md)
+* [Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹ ](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹.md)
+* [Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�.md)
+* [Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£ ](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:JDKå’Œcglib动æ€�代ç�†åŽŸç�†è¯¦è§£.md)
+* [Springæº�ç �剖æž�:SpringAOP概述](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:SpringAOP概述.md)
+* [Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£ ](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:AOP实现原ç�†è¯¦è§£.md)
+* [Springæº�ç �剖æž�:Spring事务概述](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring事务概述.md)
+* [Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�.md)
+
+## SpringMVC
+
+* [SpringMVCä¸çš„国际化功能](docs/Spring全家桶/SpringMVC/SpringMVCä¸çš„国际化功能.md)
+* [SpringMVCä¸çš„异常处ç�†å™¨](docs/Spring全家桶/SpringMVC/SpringMVCä¸çš„异常处ç�†å™¨.md)
+* [SpringMVCä¸çš„æ‹¦æˆªå™¨](docs/Spring全家桶/SpringMVC/SpringMVCä¸çš„æ‹¦æˆªå™¨.md)
+* [SpringMVCä¸çš„视图解æž�器](docs/Spring全家桶/SpringMVC/SpringMVCä¸çš„视图解æž�器.md)
+* [SpringMVCä¸çš„过滤器Filter](docs/Spring全家桶/SpringMVC/SpringMVCä¸çš„过滤器Filter.md)
+* [SpringMVC基本介�与快速入门](docs/Spring全家桶/SpringMVC/SpringMVC基本介�与快速入门.md)
+* [SpringMVCå¦‚ä½•å®žçŽ°æ–‡ä»¶ä¸Šä¼ ](docs/Spring全家桶/SpringMVC/SpringMVCå¦‚ä½•å®žçŽ°æ–‡ä»¶ä¸Šä¼ .md)
+* [SpringMVCä¸çš„常用功能](docs/Spring全家桶/SpringMVC/SpringMVCä¸çš„常用功能.md)
+
+## SpringMVCæº�ç �分æž�
+
+* [SpringMVCæº�ç �分æž�:SpringMVC概述](docs/Spring全家桶/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC概述.md)
+* [SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet](docs/Spring全家桶/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet.md)
+* [SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘ ](docs/Spring全家桶/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:DispatcherServletçš„åˆ�始化与请求转å�‘.md)
+* [SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller ](docs/Spring全家桶/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:DispatcherServlet如何找到æ£ç¡®çš„Controller.md)
+* [SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解](docs/Spring全家桶/SpringMVC/SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解.md)
+* [SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�† ](docs/Spring全家桶/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�†.md)
+
+## SpringBoot
+
+* [SpringBoot系列:SpringBoot的�世今生](docs/Spring全家桶/SpringBoot/SpringBoot的�世今生.md)
+* [ç»™ä½ ä¸€ä»½SpringBoot知识清å�•.md](docs/Spring全家桶/SpringBoot/ç»™ä½ ä¸€ä»½SpringBoot知识清å�•.md)
+* [Spring常�注解使用指�(包�Spring+SpringMVC+SpringBoot)](docs/Spring全家桶/SpringBoot/Spring常�注解使用指�(包�Spring+SpringMVC+SpringBoot).md)
+* [SpringBootä¸çš„æ—¥å¿—管ç�†](docs/Spring全家桶/SpringBoot/SpringBootä¸çš„æ—¥å¿—管ç�†.md)
+* [SpringBoot常�注解](docs/Spring全家桶/SpringBoot/SpringBoot常�注解.md)
+* [SpringBoot应用也�以部署到外部Tomcat](docs/Spring全家桶/SpringBoot/SpringBoot应用也�以部署到外部Tomcat.md)
+* [SpringBoot生产环境工具Actuator](docs/Spring全家桶/SpringBoot/SpringBoot生产环境工具Actuator.md)
+* [SpringBoot的Starter机制](docs/Spring全家桶/SpringBoot/SpringBoot的Starter机制.md)
+* [SpringBoot的�世今生](docs/Spring全家桶/SpringBoot/SpringBoot的�世今生.md)
+* [SpringBoot的基本使用](docs/Spring全家桶/SpringBoot/SpringBoot的基本使用.md)
+* [SpringBoot的�置文件管�](docs/Spring全家桶/SpringBoot/SpringBoot的�置文件管�.md)
+* [SpringBoot自带的çƒéƒ¨ç½²å·¥å…·](docs/Spring全家桶/SpringBoot/SpringBoot自带的çƒéƒ¨ç½²å·¥å…·.md)
+* [SpringBootä¸çš„任务调度与@Async](docs/Spring全家桶/SpringBoot/SpringBootä¸çš„任务调度与@Async.md)
+* [基于SpringBootä¸çš„å¼€æº�监控工具SpringBootAdmin](docs/Spring全家桶/SpringBoot/基于SpringBootä¸çš„å¼€æº�监控工具SpringBootAdmin.md)
+
+## SpringBootæº�ç �分æž�
+
+## SpringCloud
+
+## SpringCloudæº�ç �分æž�
+
+todo
+
+## 设计模�
+
+* [设计模å¼�å¦ä¹ 总结](docs/Java/design-parttern/设计模å¼�å¦ä¹ 总结.md)
+* [åˆ�探Java设计模å¼�:创建型模å¼�(工厂,å�•例ç‰ï¼‰.md](docs/Java/design-parttern/åˆ�探Java设计模å¼�:创建型模å¼�(工厂,å�•例ç‰ï¼‰.md)
+* [åˆ�探Java设计模å¼�:结构型模å¼�(代ç�†æ¨¡å¼�,适é…�器模å¼�ç‰ï¼‰.md](docs/Java/design-parttern/åˆ�探Java设计模å¼�:结构型模å¼�(代ç�†æ¨¡å¼�,适é…�器模å¼�ç‰ï¼‰.md)
+* [åˆ�探Java设计模å¼�:行为型模å¼�(ç–略,观察者ç‰ï¼‰.md](docs/Java/design-parttern/åˆ�探Java设计模å¼�:行为型模å¼�(ç–略,观察者ç‰ï¼‰.md)
+* [åˆ�探Java设计模å¼�:JDKä¸çš„设计模å¼�.md](docs/Java/design-parttern/åˆ�探Java设计模å¼�:JDKä¸çš„设计模å¼�.md)
+* [�探Java设计模�:Spring涉�到的�设计模�.md](docs/Java/design-parttern/�探Java设计模�:Spring涉�到的�设计模�.md)
+
## 计算机基础
@@ -331,19 +294,19 @@ todo
### Kafka
## 大�端
-* [�端技术�谈开篇:云计算,大数�与AI的故事](docs/big-backEnd/�端技术�谈开篇:云计算,大数�与AI的故事.md)
-* [�端技术�谈:�索引擎基础倒排索引](docs/big-backEnd/�端技术�谈:�索引擎基础倒排索引.md)
-* [�端技术�谈:�索引擎工作原�](docs/big-backEnd/�端技术�谈:�索引擎工作原�.md)
-* [�端技术�谈:Lucene基础原�与实践](docs/big-backEnd/�端技术�谈:Lucene基础原�与实践.md)
-* [�端技术�谈:Elasticsearch与solr入门实践](docs/big-backEnd/�端技术�谈:Elasticsearch与solr入门实践.md)
-* [�端技术�谈:云计算的�世今生](docs/big-backEnd/�端技术�谈:云计算的�世今生.md)
-* [�端技术�谈:白�虚拟化技术](docs/big-backEnd/�端技术�谈:白�虚拟化技术.md )
-* [�端技术�谈:OpenStack的基石KVM](docs/big-backEnd/�端技术�谈:OpenStack的基石KVM.md)
-* [�端技术�谈:OpenStack架构设计](docs/big-backEnd/�端技术�谈:OpenStack架构设计.md)
-* [å�Žç«¯æŠ€æœ¯æ�‚谈:先æ�žæ‡‚Dockeræ ¸å¿ƒæ¦‚å¿µå�§](docs/big-backEnd/å�Žç«¯æŠ€æœ¯æ�‚谈:先æ�žæ‡‚Dockeræ ¸å¿ƒæ¦‚å¿µå�§.md)
-* [å�Žç«¯æŠ€æœ¯æ�‚谈:Docker æ ¸å¿ƒæŠ€æœ¯ä¸Žå®žçŽ°åŽŸç�†](docs/big-backEnd/å�Žç«¯æŠ€æœ¯æ�‚谈:Docker%æ ¸å¿ƒæŠ€æœ¯ä¸Žå®žçŽ°åŽŸç�†.md)
-* [å�Žç«¯æŠ€æœ¯æ�‚谈:å��分钟ç�†è§£Kubernetesæ ¸å¿ƒæ¦‚å¿µ](docs/big-backEnd/å�Žç«¯æŠ€æœ¯æ�‚谈:å��分钟ç�†è§£Kubernetesæ ¸å¿ƒæ¦‚å¿µ.md)
-* [å�Žç«¯æŠ€æœ¯æ�‚谈:æ�‹ä¸€æ�‹å¤§æ•°æ�®ç ”å�‘的基本概念](docs/big-backEnd/å�Žç«¯æŠ€æœ¯æ�‚谈:æ�‹ä¸€æ�‹å¤§æ•°æ�®ç ”å�‘的基本概念.md)
+* [�端技术�谈开篇:云计算,大数�与AI的故事](docs/backend/�端技术�谈开篇:云计算,大数�与AI的故事.md)
+* [�端技术�谈:�索引擎基础倒排索引](docs/backend/�端技术�谈:�索引擎基础倒排索引.md)
+* [�端技术�谈:�索引擎工作原�](docs/backend/�端技术�谈:�索引擎工作原�.md)
+* [�端技术�谈:Lucene基础原�与实践](docs/backend/�端技术�谈:Lucene基础原�与实践.md)
+* [�端技术�谈:Elasticsearch与solr入门实践](docs/backend/�端技术�谈:Elasticsearch与solr入门实践.md)
+* [�端技术�谈:云计算的�世今生](docs/backend/�端技术�谈:云计算的�世今生.md)
+* [�端技术�谈:白�虚拟化技术](docs/backend/�端技术�谈:白�虚拟化技术.md )
+* [�端技术�谈:OpenStack的基石KVM](docs/backend/�端技术�谈:OpenStack的基石KVM.md)
+* [�端技术�谈:OpenStack架构设计](docs/backend/�端技术�谈:OpenStack架构设计.md)
+* [å�Žç«¯æŠ€æœ¯æ�‚谈:先æ�žæ‡‚Dockeræ ¸å¿ƒæ¦‚å¿µå�§](docs/backend/å�Žç«¯æŠ€æœ¯æ�‚谈:先æ�žæ‡‚Dockeræ ¸å¿ƒæ¦‚å¿µå�§.md)
+* [å�Žç«¯æŠ€æœ¯æ�‚谈:Docker æ ¸å¿ƒæŠ€æœ¯ä¸Žå®žçŽ°åŽŸç�†](docs/backend/å�Žç«¯æŠ€æœ¯æ�‚谈:Docker%æ ¸å¿ƒæŠ€æœ¯ä¸Žå®žçŽ°åŽŸç�†.md)
+* [å�Žç«¯æŠ€æœ¯æ�‚谈:å��分钟ç�†è§£Kubernetesæ ¸å¿ƒæ¦‚å¿µ](docs/backend/å�Žç«¯æŠ€æœ¯æ�‚谈:å��分钟ç�†è§£Kubernetesæ ¸å¿ƒæ¦‚å¿µ.md)
+* [å�Žç«¯æŠ€æœ¯æ�‚谈:æ�‹ä¸€æ�‹å¤§æ•°æ�®ç ”å�‘的基本概念](docs/backend/å�Žç«¯æŠ€æœ¯æ�‚谈:æ�‹ä¸€æ�‹å¤§æ•°æ�®ç ”å�‘的基本概念.md)
## 分布�
### �论
diff --git "a/docs/java/jvm/JVM\346\200\273\347\273\223.md" "b/docs/Java/JVM/JVM\346\200\273\347\273\223.md"
similarity index 100%
rename from "docs/java/jvm/JVM\346\200\273\347\273\223.md"
rename to "docs/Java/JVM/JVM\346\200\273\347\273\223.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232GC\350\260\203\344\274\230\346\200\235\350\267\257\344\270\216\345\270\270\347\224\250\345\267\245\345\205\267.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232GC\350\260\203\344\274\230\346\200\235\350\267\257\344\270\216\345\270\270\347\224\250\345\267\245\345\205\267.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232GC\350\260\203\344\274\230\346\200\235\350\267\257\344\270\216\345\270\270\347\224\250\345\267\245\345\205\267.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232GC\350\260\203\344\274\230\346\200\235\350\267\257\344\270\216\345\270\270\347\224\250\345\267\245\345\205\267.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JNDI\357\274\214OSGI\357\274\214Tomcat\347\261\273\345\212\240\350\275\275\345\231\250\345\256\236\347\216\260.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JNDI\357\274\214OSGI\357\274\214Tomcat\347\261\273\345\212\240\350\275\275\345\231\250\345\256\236\347\216\260.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JNDI\357\274\214OSGI\357\274\214Tomcat\347\261\273\345\212\240\350\275\275\345\231\250\345\256\236\347\216\260.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JNDI\357\274\214OSGI\357\274\214Tomcat\347\261\273\345\212\240\350\275\275\345\231\250\345\256\236\347\216\260.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\206\205\345\255\230\347\232\204\347\273\223\346\236\204\344\270\216\346\266\210\345\244\261\347\232\204\346\260\270\344\271\205\344\273\243.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\206\205\345\255\230\347\232\204\347\273\223\346\236\204\344\270\216\346\266\210\345\244\261\347\232\204\346\260\270\344\271\205\344\273\243.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\206\205\345\255\230\347\232\204\347\273\223\346\236\204\344\270\216\346\266\210\345\244\261\347\232\204\346\260\270\344\271\205\344\273\243.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\206\205\345\255\230\347\232\204\347\273\223\346\236\204\344\270\216\346\266\210\345\244\261\347\232\204\346\260\270\344\271\205\344\273\243.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\236\203\345\234\276\345\233\236\346\224\266\345\237\272\346\234\254\345\216\237\347\220\206\345\222\214\347\256\227\346\263\225.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\236\203\345\234\276\345\233\236\346\224\266\345\237\272\346\234\254\345\216\237\347\220\206\345\222\214\347\256\227\346\263\225.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\236\203\345\234\276\345\233\236\346\224\266\345\237\272\346\234\254\345\216\237\347\220\206\345\222\214\347\256\227\346\263\225.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\236\203\345\234\276\345\233\236\346\224\266\345\237\272\346\234\254\345\216\237\347\220\206\345\222\214\347\256\227\346\263\225.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\270\270\347\224\250\345\217\202\346\225\260\344\273\245\345\217\212\350\260\203\344\274\230\345\256\236\350\267\265.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\270\270\347\224\250\345\217\202\346\225\260\344\273\245\345\217\212\350\260\203\344\274\230\345\256\236\350\267\265.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\270\270\347\224\250\345\217\202\346\225\260\344\273\245\345\217\212\350\260\203\344\274\230\345\256\236\350\267\265.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\345\270\270\347\224\250\345\217\202\346\225\260\344\273\245\345\217\212\350\260\203\344\274\230\345\256\236\350\267\265.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\346\200\247\350\203\275\347\256\241\347\220\206\347\245\236\345\231\250VisualVM\344\273\213\347\273\215\344\270\216\345\256\236\346\210\230.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\346\200\247\350\203\275\347\256\241\347\220\206\347\245\236\345\231\250VisualVM\344\273\213\347\273\215\344\270\216\345\256\236\346\210\230.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\346\200\247\350\203\275\347\256\241\347\220\206\347\245\236\345\231\250VisualVM\344\273\213\347\273\215\344\270\216\345\256\236\346\210\230.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\346\200\247\350\203\275\347\256\241\347\220\206\347\245\236\345\231\250VisualVM\344\273\213\347\273\215\344\270\216\345\256\236\346\210\230.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\347\233\221\346\216\247\345\267\245\345\205\267\344\270\216\350\257\212\346\226\255\345\256\236\350\267\265.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\347\233\221\346\216\247\345\267\245\345\205\267\344\270\216\350\257\212\346\226\255\345\256\236\350\267\265.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\347\233\221\346\216\247\345\267\245\345\205\267\344\270\216\350\257\212\346\226\255\345\256\236\350\267\265.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232JVM\347\233\221\346\216\247\345\267\245\345\205\267\344\270\216\350\257\212\346\226\255\345\256\236\350\267\265.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\206\205\345\255\230\345\274\202\345\270\270\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\206\205\345\255\230\345\274\202\345\270\270\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\206\205\345\255\230\345\274\202\345\270\270\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\206\205\345\255\230\345\274\202\345\270\270\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\255\227\350\212\202\347\240\201\344\273\213\347\273\215\344\270\216\350\247\243\346\236\220\345\256\236\350\267\265.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\255\227\350\212\202\347\240\201\344\273\213\347\273\215\344\270\216\350\247\243\346\236\220\345\256\236\350\267\265.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\255\227\350\212\202\347\240\201\344\273\213\347\273\215\344\270\216\350\247\243\346\236\220\345\256\236\350\267\265.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\345\255\227\350\212\202\347\240\201\344\273\213\347\273\215\344\270\216\350\247\243\346\236\220\345\256\236\350\267\265.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\347\232\204\347\274\226\350\257\221\346\234\237\344\274\230\345\214\226\344\270\216\350\277\220\350\241\214\346\234\237\344\274\230\345\214\226.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\347\232\204\347\274\226\350\257\221\346\234\237\344\274\230\345\214\226\344\270\216\350\277\220\350\241\214\346\234\237\344\274\230\345\214\226.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\347\232\204\347\274\226\350\257\221\346\234\237\344\274\230\345\214\226\344\270\216\350\277\220\350\241\214\346\234\237\344\274\230\345\214\226.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232Java\347\232\204\347\274\226\350\257\221\346\234\237\344\274\230\345\214\226\344\270\216\350\277\220\350\241\214\346\234\237\344\274\230\345\214\226.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\206\215\350\260\210\345\233\233\347\247\215\345\274\225\347\224\250\345\217\212GC\345\256\236\350\267\265.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\206\215\350\260\210\345\233\233\347\247\215\345\274\225\347\224\250\345\217\212GC\345\256\236\350\267\265.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\206\215\350\260\210\345\233\233\347\247\215\345\274\225\347\224\250\345\217\212GC\345\256\236\350\267\265.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\206\215\350\260\210\345\233\233\347\247\215\345\274\225\347\224\250\345\217\212GC\345\256\236\350\267\265.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250\350\257\246\350\247\243.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250\350\257\246\350\247\243.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250\350\257\246\350\247\243.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\345\236\203\345\234\276\345\233\236\346\224\266\345\231\250\350\257\246\350\247\243.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243JVM\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243JVM\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243JVM\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243JVM\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md"
diff --git "a/docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\350\231\232\346\213\237\346\234\272\345\255\227\350\212\202\347\240\201\346\211\247\350\241\214\345\274\225\346\223\216.md" "b/docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\350\231\232\346\213\237\346\234\272\345\255\227\350\212\202\347\240\201\346\211\247\350\241\214\345\274\225\346\223\216.md"
similarity index 100%
rename from "docs/java/jvm/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\350\231\232\346\213\237\346\234\272\345\255\227\350\212\202\347\240\201\346\211\247\350\241\214\345\274\225\346\223\216.md"
rename to "docs/Java/JVM/\346\267\261\345\205\245\347\220\206\350\247\243JVM\350\231\232\346\213\237\346\234\272\357\274\232\350\231\232\346\213\237\346\234\272\345\255\227\350\212\202\347\240\201\346\211\247\350\241\214\345\274\225\346\223\216.md"
diff --git "a/docs/java/basic/Java8\346\226\260\347\211\271\346\200\247\347\273\210\346\236\201\346\214\207\345\215\227.md" "b/docs/Java/basic/Java8\346\226\260\347\211\271\346\200\247\347\273\210\346\236\201\346\214\207\345\215\227.md"
similarity index 100%
rename from "docs/java/basic/Java8\346\226\260\347\211\271\346\200\247\347\273\210\346\236\201\346\214\207\345\215\227.md"
rename to "docs/Java/basic/Java8\346\226\260\347\211\271\346\200\247\347\273\210\346\236\201\346\214\207\345\215\227.md"
diff --git "a/docs/java/basic/JavaIO\346\265\201.md" "b/docs/Java/basic/JavaIO\346\265\201.md"
similarity index 100%
rename from "docs/java/basic/JavaIO\346\265\201.md"
rename to "docs/Java/basic/JavaIO\346\265\201.md"
diff --git "a/docs/java/basic/Java\344\270\255\347\232\204Class\347\261\273\345\222\214Object\347\261\273.md" "b/docs/Java/basic/Java\344\270\255\347\232\204Class\347\261\273\345\222\214Object\347\261\273.md"
similarity index 100%
rename from "docs/java/basic/Java\344\270\255\347\232\204Class\347\261\273\345\222\214Object\347\261\273.md"
rename to "docs/Java/basic/Java\344\270\255\347\232\204Class\347\261\273\345\222\214Object\347\261\273.md"
diff --git "a/docs/java/basic/Java\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213.md" "b/docs/Java/basic/Java\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213.md"
similarity index 100%
rename from "docs/java/basic/Java\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213.md"
rename to "docs/Java/basic/Java\345\237\272\346\234\254\346\225\260\346\215\256\347\261\273\345\236\213.md"
diff --git "a/docs/java/basic/Java\345\274\202\345\270\270.md" "b/docs/Java/basic/Java\345\274\202\345\270\270.md"
similarity index 100%
rename from "docs/java/basic/Java\345\274\202\345\270\270.md"
rename to "docs/Java/basic/Java\345\274\202\345\270\270.md"
diff --git "a/docs/java/basic/Java\346\263\250\350\247\243\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md" "b/docs/Java/basic/Java\346\263\250\350\247\243\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md"
similarity index 100%
rename from "docs/java/basic/Java\346\263\250\350\247\243\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md"
rename to "docs/Java/basic/Java\346\263\250\350\247\243\345\222\214\346\234\200\344\275\263\345\256\236\350\267\265.md"
diff --git "a/docs/java/basic/Java\347\261\273\345\222\214\345\214\205.md" "b/docs/Java/basic/Java\347\261\273\345\222\214\345\214\205.md"
similarity index 100%
rename from "docs/java/basic/Java\347\261\273\345\222\214\345\214\205.md"
rename to "docs/Java/basic/Java\347\261\273\345\222\214\345\214\205.md"
diff --git "a/docs/java/basic/Java\350\207\252\345\212\250\346\213\206\347\256\261\350\243\205\347\256\261\351\207\214\351\232\220\350\227\217\347\232\204\347\247\230\345\257\206.md" "b/docs/Java/basic/Java\350\207\252\345\212\250\346\213\206\347\256\261\350\243\205\347\256\261\351\207\214\351\232\220\350\227\217\347\232\204\347\247\230\345\257\206.md"
similarity index 100%
rename from "docs/java/basic/Java\350\207\252\345\212\250\346\213\206\347\256\261\350\243\205\347\256\261\351\207\214\351\232\220\350\227\217\347\232\204\347\247\230\345\257\206.md"
rename to "docs/Java/basic/Java\350\207\252\345\212\250\346\213\206\347\256\261\350\243\205\347\256\261\351\207\214\351\232\220\350\227\217\347\232\204\347\247\230\345\257\206.md"
diff --git "a/docs/java/basic/Java\351\233\206\345\220\210\346\241\206\346\236\266\346\242\263\347\220\206.md" "b/docs/Java/basic/Java\351\233\206\345\220\210\346\241\206\346\236\266\346\242\263\347\220\206.md"
similarity index 100%
rename from "docs/java/basic/Java\351\233\206\345\220\210\346\241\206\346\236\266\346\242\263\347\220\206.md"
rename to "docs/Java/basic/Java\351\233\206\345\220\210\346\241\206\346\236\266\346\242\263\347\220\206.md"
diff --git "a/docs/java/basic/final\345\205\263\351\224\256\345\255\227\347\211\271\346\200\247.md" "b/docs/Java/basic/final\345\205\263\351\224\256\345\255\227\347\211\271\346\200\247.md"
similarity index 100%
rename from "docs/java/basic/final\345\205\263\351\224\256\345\255\227\347\211\271\346\200\247.md"
rename to "docs/Java/basic/final\345\205\263\351\224\256\345\255\227\347\211\271\346\200\247.md"
diff --git "a/docs/java/basic/javac\345\222\214javap.md" "b/docs/Java/basic/javac\345\222\214javap.md"
similarity index 100%
rename from "docs/java/basic/javac\345\222\214javap.md"
rename to "docs/Java/basic/javac\345\222\214javap.md"
diff --git "a/docs/java/basic/string\345\222\214\345\214\205\350\243\205\347\261\273.md" "b/docs/Java/basic/string\345\222\214\345\214\205\350\243\205\347\261\273.md"
similarity index 100%
rename from "docs/java/basic/string\345\222\214\345\214\205\350\243\205\347\261\273.md"
rename to "docs/Java/basic/string\345\222\214\345\214\205\350\243\205\347\261\273.md"
diff --git "a/docs/java/basic/\344\273\243\347\240\201\345\235\227\345\222\214\344\273\243\347\240\201\346\211\247\350\241\214\351\241\272\345\272\217.md" "b/docs/Java/basic/\344\273\243\347\240\201\345\235\227\345\222\214\344\273\243\347\240\201\346\211\247\350\241\214\351\241\272\345\272\217.md"
similarity index 100%
rename from "docs/java/basic/\344\273\243\347\240\201\345\235\227\345\222\214\344\273\243\347\240\201\346\211\247\350\241\214\351\241\272\345\272\217.md"
rename to "docs/Java/basic/\344\273\243\347\240\201\345\235\227\345\222\214\344\273\243\347\240\201\346\211\247\350\241\214\351\241\272\345\272\217.md"
diff --git "a/docs/java/basic/\345\217\215\345\260\204.md" "b/docs/Java/basic/\345\217\215\345\260\204.md"
similarity index 100%
rename from "docs/java/basic/\345\217\215\345\260\204.md"
rename to "docs/Java/basic/\345\217\215\345\260\204.md"
diff --git "a/docs/java/basic/\345\244\232\347\272\277\347\250\213.md" "b/docs/Java/basic/\345\244\232\347\272\277\347\250\213.md"
similarity index 100%
rename from "docs/java/basic/\345\244\232\347\272\277\347\250\213.md"
rename to "docs/Java/basic/\345\244\232\347\272\277\347\250\213.md"
diff --git "a/docs/java/basic/\345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226.md" "b/docs/Java/basic/\345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226.md"
similarity index 100%
rename from "docs/java/basic/\345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226.md"
rename to "docs/Java/basic/\345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226.md"
diff --git "a/docs/java/basic/\346\212\275\350\261\241\347\261\273\345\222\214\346\216\245\345\217\243.md" "b/docs/Java/basic/\346\212\275\350\261\241\347\261\273\345\222\214\346\216\245\345\217\243.md"
similarity index 100%
rename from "docs/java/basic/\346\212\275\350\261\241\347\261\273\345\222\214\346\216\245\345\217\243.md"
rename to "docs/Java/basic/\346\212\275\350\261\241\347\261\273\345\222\214\346\216\245\345\217\243.md"
diff --git "a/docs/java/basic/\346\236\232\344\270\276\347\261\273.md" "b/docs/Java/basic/\346\236\232\344\270\276\347\261\273.md"
similarity index 100%
rename from "docs/java/basic/\346\236\232\344\270\276\347\261\273.md"
rename to "docs/Java/basic/\346\236\232\344\270\276\347\261\273.md"
diff --git "a/docs/java/basic/\346\263\233\345\236\213.md" "b/docs/Java/basic/\346\263\233\345\236\213.md"
similarity index 100%
rename from "docs/java/basic/\346\263\233\345\236\213.md"
rename to "docs/Java/basic/\346\263\233\345\236\213.md"
diff --git "a/docs/java/basic/\346\267\261\345\205\245\347\220\206\350\247\243\345\206\205\351\203\250\347\261\273.md" "b/docs/Java/basic/\346\267\261\345\205\245\347\220\206\350\247\243\345\206\205\351\203\250\347\261\273.md"
similarity index 100%
rename from "docs/java/basic/\346\267\261\345\205\245\347\220\206\350\247\243\345\206\205\351\203\250\347\261\273.md"
rename to "docs/Java/basic/\346\267\261\345\205\245\347\220\206\350\247\243\345\206\205\351\203\250\347\261\273.md"
diff --git "a/docs/java/basic/\347\273\247\346\211\277\343\200\201\345\260\201\350\243\205\343\200\201\345\244\232\346\200\201\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md" "b/docs/Java/basic/\347\273\247\346\211\277\343\200\201\345\260\201\350\243\205\343\200\201\345\244\232\346\200\201\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md"
similarity index 100%
rename from "docs/java/basic/\347\273\247\346\211\277\343\200\201\345\260\201\350\243\205\343\200\201\345\244\232\346\200\201\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md"
rename to "docs/Java/basic/\347\273\247\346\211\277\343\200\201\345\260\201\350\243\205\343\200\201\345\244\232\346\200\201\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md"
diff --git "a/docs/java/basic/\350\247\243\350\257\273Java\344\270\255\347\232\204\345\233\236\350\260\203.md" "b/docs/Java/basic/\350\247\243\350\257\273Java\344\270\255\347\232\204\345\233\236\350\260\203.md"
similarity index 100%
rename from "docs/java/basic/\350\247\243\350\257\273Java\344\270\255\347\232\204\345\233\236\350\260\203.md"
rename to "docs/Java/basic/\350\247\243\350\257\273Java\344\270\255\347\232\204\345\233\236\350\260\203.md"
diff --git "a/docs/java/basic/\351\235\242\345\220\221\345\257\271\350\261\241\345\237\272\347\241\200.md" "b/docs/Java/basic/\351\235\242\345\220\221\345\257\271\350\261\241\345\237\272\347\241\200.md"
similarity index 100%
rename from "docs/java/basic/\351\235\242\345\220\221\345\257\271\350\261\241\345\237\272\347\241\200.md"
rename to "docs/Java/basic/\351\235\242\345\220\221\345\257\271\350\261\241\345\237\272\347\241\200.md"
diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\347\261\273\346\200\273\347\273\223.md" "b/docs/Java/collection/Java\351\233\206\345\220\210\347\261\273\346\200\273\347\273\223.md"
similarity index 100%
rename from "docs/java/collection/Java\351\233\206\345\220\210\347\261\273\346\200\273\347\273\223.md"
rename to "docs/Java/collection/Java\351\233\206\345\220\210\347\261\273\346\200\273\347\273\223.md"
diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashMap\345\222\214HashTable.md" "b/docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashMap\345\222\214HashTable.md"
similarity index 100%
rename from "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashMap\345\222\214HashTable.md"
rename to "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashMap\345\222\214HashTable.md"
diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashSet\357\274\214TreeSet\344\270\216LinkedHashSet.md" "b/docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashSet\357\274\214TreeSet\344\270\216LinkedHashSet.md"
similarity index 100%
rename from "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashSet\357\274\214TreeSet\344\270\216LinkedHashSet.md"
rename to "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232HashSet\357\274\214TreeSet\344\270\216LinkedHashSet.md"
diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Iterator\357\274\214fail-fast\346\234\272\345\210\266\344\270\216\346\257\224\350\276\203\345\231\250.md" "b/docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Iterator\357\274\214fail-fast\346\234\272\345\210\266\344\270\216\346\257\224\350\276\203\345\231\250.md"
similarity index 100%
rename from "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Iterator\357\274\214fail-fast\346\234\272\345\210\266\344\270\216\346\257\224\350\276\203\345\231\250.md"
rename to "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Iterator\357\274\214fail-fast\346\234\272\345\210\266\344\270\216\346\257\224\350\276\203\345\231\250.md"
diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Java\351\233\206\345\220\210\347\261\273\347\273\206\350\212\202\347\262\276\350\256\262.md" "b/docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Java\351\233\206\345\220\210\347\261\273\347\273\206\350\212\202\347\262\276\350\256\262.md"
similarity index 100%
rename from "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Java\351\233\206\345\220\210\347\261\273\347\273\206\350\212\202\347\262\276\350\256\262.md"
rename to "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Java\351\233\206\345\220\210\347\261\273\347\273\206\350\212\202\347\262\276\350\256\262.md"
diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Queue\345\222\214LinkedList.md" "b/docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Queue\345\222\214LinkedList.md"
similarity index 100%
rename from "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Queue\345\222\214LinkedList.md"
rename to "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232Queue\345\222\214LinkedList.md"
diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232TreeMap\345\222\214\347\272\242\351\273\221\346\240\221.md" "b/docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232TreeMap\345\222\214\347\272\242\351\273\221\346\240\221.md"
similarity index 100%
rename from "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232TreeMap\345\222\214\347\272\242\351\273\221\346\240\221.md"
rename to "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232TreeMap\345\222\214\347\272\242\351\273\221\346\240\221.md"
diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\344\270\200\346\226\207\350\257\273\346\207\202ArrayList,Vector\344\270\216Stack\344\275\277\347\224\250\346\226\271\346\263\225\345\222\214\345\256\236\347\216\260\345\216\237\347\220\206.md" "b/docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\344\270\200\346\226\207\350\257\273\346\207\202ArrayList,Vector\344\270\216Stack\344\275\277\347\224\250\346\226\271\346\263\225\345\222\214\345\256\236\347\216\260\345\216\237\347\220\206.md"
similarity index 100%
rename from "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\344\270\200\346\226\207\350\257\273\346\207\202ArrayList,Vector\344\270\216Stack\344\275\277\347\224\250\346\226\271\346\263\225\345\222\214\345\256\236\347\216\260\345\216\237\347\220\206.md"
rename to "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\344\270\200\346\226\207\350\257\273\346\207\202ArrayList,Vector\344\270\216Stack\344\275\277\347\224\250\346\226\271\346\263\225\345\222\214\345\256\236\347\216\260\345\216\237\347\220\206.md"
diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243LinkedHashMap\345\222\214LRU\347\274\223\345\255\230.md" "b/docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243LinkedHashMap\345\222\214LRU\347\274\223\345\255\230.md"
similarity index 100%
rename from "docs/java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243LinkedHashMap\345\222\214LRU\347\274\223\345\255\230.md"
rename to "docs/Java/collection/Java\351\233\206\345\220\210\350\257\246\350\247\243\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243LinkedHashMap\345\222\214LRU\347\274\223\345\255\230.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\344\270\255\347\232\204\345\205\254\345\271\263\351\224\201\344\270\216\351\235\236\345\205\254\345\271\263\351\224\201\357\274\214Condtion.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\344\270\255\347\232\204\345\205\254\345\271\263\351\224\201\344\270\216\351\235\236\345\205\254\345\271\263\351\224\201\357\274\214Condtion.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\344\270\255\347\232\204\345\205\254\345\271\263\351\224\201\344\270\216\351\235\236\345\205\254\345\271\263\351\224\201\357\274\214Condtion.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\344\270\255\347\232\204\345\205\254\345\271\263\351\224\201\344\270\216\351\235\236\345\205\254\345\271\263\351\224\201\357\274\214Condtion.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\345\205\261\344\272\253\346\250\241\345\274\217\344\270\216\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273\347\232\204\345\256\236\347\216\260.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\345\205\261\344\272\253\346\250\241\345\274\217\344\270\216\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273\347\232\204\345\256\236\347\216\260.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\345\205\261\344\272\253\346\250\241\345\274\217\344\270\216\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273\347\232\204\345\256\236\347\216\260.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232AQS\345\205\261\344\272\253\346\250\241\345\274\217\344\270\216\345\271\266\345\217\221\345\267\245\345\205\267\347\261\273\347\232\204\345\256\236\347\216\260.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232ForkJoin\345\271\266\345\217\221\346\241\206\346\236\266\344\270\216\345\267\245\344\275\234\347\252\203\345\217\226\347\256\227\346\263\225\345\211\226\346\236\220.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232ForkJoin\345\271\266\345\217\221\346\241\206\346\236\266\344\270\216\345\267\245\344\275\234\347\252\203\345\217\226\347\256\227\346\263\225\345\211\226\346\236\220.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232ForkJoin\345\271\266\345\217\221\346\241\206\346\236\266\344\270\216\345\267\245\344\275\234\347\252\203\345\217\226\347\256\227\346\263\225\345\211\226\346\236\220.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232ForkJoin\345\271\266\345\217\221\346\241\206\346\236\266\344\270\216\345\267\245\344\275\234\347\252\203\345\217\226\347\256\227\346\263\225\345\211\226\346\236\220.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JMM\344\270\255\347\232\204final\345\205\263\351\224\256\345\255\227\350\247\243\346\236\220.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JMM\344\270\255\347\232\204final\345\205\263\351\224\256\345\255\227\350\247\243\346\236\220.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JMM\344\270\255\347\232\204final\345\205\263\351\224\256\345\255\227\350\247\243\346\236\220.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JMM\344\270\255\347\232\204final\345\205\263\351\224\256\345\255\227\350\247\243\346\236\220.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\344\270\255\345\270\270\347\224\250\347\232\204Unsafe\345\222\214Locksupport.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\344\270\255\345\270\270\347\224\250\347\232\204Unsafe\345\222\214Locksupport.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\344\270\255\345\270\270\347\224\250\347\232\204Unsafe\345\222\214Locksupport.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\344\270\255\345\270\270\347\224\250\347\232\204Unsafe\345\222\214Locksupport.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\347\232\204\346\240\270\345\277\203\347\261\273AQS\350\257\246\350\247\243.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\347\232\204\346\240\270\345\277\203\347\261\273AQS\350\257\246\350\247\243.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\347\232\204\346\240\270\345\277\203\347\261\273AQS\350\257\246\350\247\243.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232JUC\347\232\204\346\240\270\345\277\203\347\261\273AQS\350\257\246\350\247\243.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204HashMap\345\222\214ConcurrentHashMap\345\205\250\350\247\243\346\236\220.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204HashMap\345\222\214ConcurrentHashMap\345\205\250\350\247\243\346\236\220.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204HashMap\345\222\214ConcurrentHashMap\345\205\250\350\247\243\346\236\220.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204HashMap\345\222\214ConcurrentHashMap\345\205\250\350\247\243\346\236\220.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204\351\224\201Lock\345\222\214synchronized.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204\351\224\201Lock\345\222\214synchronized.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204\351\224\201Lock\345\222\214synchronized.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\344\270\255\347\232\204\351\224\201Lock\345\222\214synchronized.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\345\206\205\345\255\230\346\250\241\345\236\213JMM\346\200\273\347\273\223.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\345\206\205\345\255\230\346\250\241\345\236\213JMM\346\200\273\347\273\223.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\345\206\205\345\255\230\346\250\241\345\236\213JMM\346\200\273\347\273\223.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\345\206\205\345\255\230\346\250\241\345\236\213JMM\346\200\273\347\273\223.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\350\257\273\345\206\231\351\224\201ReentrantReadWriteLock\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\350\257\273\345\206\231\351\224\201ReentrantReadWriteLock\346\272\220\347\240\201\345\210\206\346\236\220.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\350\257\273\345\206\231\351\224\201ReentrantReadWriteLock\346\272\220\347\240\201\345\210\206\346\236\220.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232Java\350\257\273\345\206\231\351\224\201ReentrantReadWriteLock\346\272\220\347\240\201\345\210\206\346\236\220.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\344\270\211\345\244\247\351\227\256\351\242\230\344\270\216volatile\345\205\263\351\224\256\345\255\227\357\274\214CAS\346\223\215\344\275\234.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\344\270\211\345\244\247\351\227\256\351\242\230\344\270\216volatile\345\205\263\351\224\256\345\255\227\357\274\214CAS\346\223\215\344\275\234.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\344\270\211\345\244\247\351\227\256\351\242\230\344\270\216volatile\345\205\263\351\224\256\345\255\227\357\274\214CAS\346\223\215\344\275\234.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\344\270\211\345\244\247\351\227\256\351\242\230\344\270\216volatile\345\205\263\351\224\256\345\255\227\357\274\214CAS\346\223\215\344\275\234.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\345\237\272\347\241\200\344\270\216Java\345\244\232\347\272\277\347\250\213.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\345\237\272\347\241\200\344\270\216Java\345\244\232\347\272\277\347\250\213.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\345\237\272\347\241\200\344\270\216Java\345\244\232\347\272\277\347\250\213.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\345\271\266\345\217\221\345\237\272\347\241\200\344\270\216Java\345\244\232\347\272\277\347\250\213.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243Java\345\206\205\345\255\230\346\250\241\345\236\213JMM.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243Java\345\206\205\345\255\230\346\250\241\345\236\213JMM.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243Java\345\206\205\345\255\230\346\250\241\345\236\213JMM.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\205\245\347\220\206\350\247\243Java\345\206\205\345\255\230\346\250\241\345\236\213JMM.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Java\347\272\277\347\250\213\346\261\240\350\256\276\350\256\241\346\200\235\346\203\263\345\217\212\346\272\220\347\240\201\345\256\236\347\216\260.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Java\347\272\277\347\250\213\346\261\240\350\256\276\350\256\241\346\200\235\346\203\263\345\217\212\346\272\220\347\240\201\345\256\236\347\216\260.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Java\347\272\277\347\250\213\346\261\240\350\256\276\350\256\241\346\200\235\346\203\263\345\217\212\346\272\220\347\240\201\345\256\236\347\216\260.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Java\347\272\277\347\250\213\346\261\240\350\256\276\350\256\241\346\200\235\346\203\263\345\217\212\346\272\220\347\240\201\345\256\236\347\216\260.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\350\247\243\350\257\273Java\351\230\273\345\241\236\351\230\237\345\210\227BlockingQueue.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\350\247\243\350\257\273Java\351\230\273\345\241\236\351\230\237\345\210\227BlockingQueue.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\350\247\243\350\257\273Java\351\230\273\345\241\236\351\230\237\345\210\227BlockingQueue.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\346\214\207\345\215\227\357\274\232\350\247\243\350\257\273Java\351\230\273\345\241\236\351\230\237\345\210\227BlockingQueue.md"
diff --git "a/docs/java/concurrency/Java\345\271\266\345\217\221\347\274\226\347\250\213\345\255\246\344\271\240\346\200\273\347\273\223.md" "b/docs/Java/concurrency/Java\345\271\266\345\217\221\347\274\226\347\250\213\345\255\246\344\271\240\346\200\273\347\273\223.md"
similarity index 100%
rename from "docs/java/concurrency/Java\345\271\266\345\217\221\347\274\226\347\250\213\345\255\246\344\271\240\346\200\273\347\273\223.md"
rename to "docs/Java/concurrency/Java\345\271\266\345\217\221\347\274\226\347\250\213\345\255\246\344\271\240\346\200\273\347\273\223.md"
diff --git "a/docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232JDK\344\270\255\347\232\204\350\256\276\350\256\241\346\250\241\345\274\217.md" "b/docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232JDK\344\270\255\347\232\204\350\256\276\350\256\241\346\250\241\345\274\217.md"
similarity index 100%
rename from "docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232JDK\344\270\255\347\232\204\350\256\276\350\256\241\346\250\241\345\274\217.md"
rename to "docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232JDK\344\270\255\347\232\204\350\256\276\350\256\241\346\250\241\345\274\217.md"
diff --git "a/docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232Spring\346\266\211\345\217\212\345\210\260\347\232\204\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217.md" "b/docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232Spring\346\266\211\345\217\212\345\210\260\347\232\204\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217.md"
similarity index 100%
rename from "docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232Spring\346\266\211\345\217\212\345\210\260\347\232\204\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217.md"
rename to "docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232Spring\346\266\211\345\217\212\345\210\260\347\232\204\347\247\215\350\256\276\350\256\241\346\250\241\345\274\217.md"
diff --git "a/docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\357\274\210\345\267\245\345\216\202\357\274\214\345\215\225\344\276\213\347\255\211\357\274\211.md" "b/docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\357\274\210\345\267\245\345\216\202\357\274\214\345\215\225\344\276\213\347\255\211\357\274\211.md"
similarity index 100%
rename from "docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\357\274\210\345\267\245\345\216\202\357\274\214\345\215\225\344\276\213\347\255\211\357\274\211.md"
rename to "docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\345\210\233\345\273\272\345\236\213\346\250\241\345\274\217\357\274\210\345\267\245\345\216\202\357\274\214\345\215\225\344\276\213\347\255\211\357\274\211.md"
diff --git "a/docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\357\274\210\344\273\243\347\220\206\346\250\241\345\274\217\357\274\214\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217\347\255\211\357\274\211.md" "b/docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\357\274\210\344\273\243\347\220\206\346\250\241\345\274\217\357\274\214\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217\347\255\211\357\274\211.md"
similarity index 100%
rename from "docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\357\274\210\344\273\243\347\220\206\346\250\241\345\274\217\357\274\214\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217\347\255\211\357\274\211.md"
rename to "docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\347\273\223\346\236\204\345\236\213\346\250\241\345\274\217\357\274\210\344\273\243\347\220\206\346\250\241\345\274\217\357\274\214\351\200\202\351\205\215\345\231\250\346\250\241\345\274\217\347\255\211\357\274\211.md"
diff --git "a/docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\357\274\210\347\255\226\347\225\245\357\274\214\350\247\202\345\257\237\350\200\205\347\255\211\357\274\211.md" "b/docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\357\274\210\347\255\226\347\225\245\357\274\214\350\247\202\345\257\237\350\200\205\347\255\211\357\274\211.md"
similarity index 100%
rename from "docs/java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\357\274\210\347\255\226\347\225\245\357\274\214\350\247\202\345\257\237\350\200\205\347\255\211\357\274\211.md"
rename to "docs/Java/design-parttern/\345\210\235\346\216\242Java\350\256\276\350\256\241\346\250\241\345\274\217\357\274\232\350\241\214\344\270\272\345\236\213\346\250\241\345\274\217\357\274\210\347\255\226\347\225\245\357\274\214\350\247\202\345\257\237\350\200\205\347\255\211\357\274\211.md"
diff --git "a/docs/java/design-parttern/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\346\200\273\347\273\223.md" "b/docs/Java/design-parttern/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\346\200\273\347\273\223.md"
similarity index 100%
rename from "docs/java/design-parttern/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\346\200\273\347\273\223.md"
rename to "docs/Java/design-parttern/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\346\200\273\347\273\223.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\344\270\216NIO\346\200\273\347\273\223.md" "b/docs/Java/network/Java\347\275\221\347\273\234\344\270\216NIO\346\200\273\347\273\223.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\344\270\216NIO\346\200\273\347\273\223.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\344\270\216NIO\346\200\273\347\273\223.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232IO\346\250\241\345\236\213\344\270\216Java\347\275\221\347\273\234\347\274\226\347\250\213\346\250\241\345\236\213.md" "b/docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232IO\346\250\241\345\236\213\344\270\216Java\347\275\221\347\273\234\347\274\226\347\250\213\346\250\241\345\236\213.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232IO\346\250\241\345\236\213\344\270\216Java\347\275\221\347\273\234\347\274\226\347\250\213\346\250\241\345\236\213.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232IO\346\250\241\345\236\213\344\270\216Java\347\275\221\347\273\234\347\274\226\347\250\213\346\250\241\345\236\213.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JAVA\344\270\255\345\216\237\347\224\237\347\232\204socket\351\200\232\344\277\241\346\234\272\345\210\266.md" "b/docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JAVA\344\270\255\345\216\237\347\224\237\347\232\204socket\351\200\232\344\277\241\346\234\272\345\210\266.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JAVA\344\270\255\345\216\237\347\224\237\347\232\204socket\351\200\232\344\277\241\346\234\272\345\210\266.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JAVA\344\270\255\345\216\237\347\224\237\347\232\204socket\351\200\232\344\277\241\346\234\272\345\210\266.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JavaNIO\344\270\200\346\255\245\346\255\245\346\236\204\345\273\272IO\345\244\232\350\267\257\345\244\215\347\224\250\347\232\204\350\257\267\346\261\202\346\250\241\345\236\213.md" "b/docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JavaNIO\344\270\200\346\255\245\346\255\245\346\236\204\345\273\272IO\345\244\232\350\267\257\345\244\215\347\224\250\347\232\204\350\257\267\346\261\202\346\250\241\345\236\213.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JavaNIO\344\270\200\346\255\245\346\255\245\346\236\204\345\273\272IO\345\244\232\350\267\257\345\244\215\347\224\250\347\232\204\350\257\267\346\261\202\346\250\241\345\236\213.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232JavaNIO\344\270\200\346\255\245\346\255\245\346\236\204\345\273\272IO\345\244\232\350\267\257\345\244\215\347\224\250\347\232\204\350\257\267\346\261\202\346\250\241\345\236\213.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Java\351\235\236\351\230\273\345\241\236IO\345\222\214\345\274\202\346\255\245IO.md" "b/docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Java\351\235\236\351\230\273\345\241\236IO\345\222\214\345\274\202\346\255\245IO.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Java\351\235\236\351\230\273\345\241\236IO\345\222\214\345\274\202\346\255\245IO.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Java\351\235\236\351\230\273\345\241\236IO\345\222\214\345\274\202\346\255\245IO.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232LinuxEpoll\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" "b/docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232LinuxEpoll\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232LinuxEpoll\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232LinuxEpoll\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Tomcat\344\270\255\347\232\204Connector\346\272\220\347\240\201\345\210\206\346\236\220\357\274\210NIO\357\274\211.md" "b/docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Tomcat\344\270\255\347\232\204Connector\346\272\220\347\240\201\345\210\206\346\236\220\357\274\210NIO\357\274\211.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Tomcat\344\270\255\347\232\204Connector\346\272\220\347\240\201\345\210\206\346\236\220\357\274\210NIO\357\274\211.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232Tomcat\344\270\255\347\232\204Connector\346\272\220\347\240\201\345\210\206\346\236\220\357\274\210NIO\357\274\211.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\345\237\272\344\272\216NIO\347\232\204\347\275\221\347\273\234\347\274\226\347\250\213\346\241\206\346\236\266Netty.md" "b/docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\345\237\272\344\272\216NIO\347\232\204\347\275\221\347\273\234\347\274\226\347\250\213\346\241\206\346\236\266Netty.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\345\237\272\344\272\216NIO\347\232\204\347\275\221\347\273\234\347\274\226\347\250\213\346\241\206\346\236\266Netty.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\345\237\272\344\272\216NIO\347\232\204\347\275\221\347\273\234\347\274\226\347\250\213\346\241\206\346\236\266Netty.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220NIO\345\214\205\344\270\255\347\232\204Buffer\343\200\201Channel\345\222\214Selector.md" "b/docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220NIO\345\214\205\344\270\255\347\232\204Buffer\343\200\201Channel\345\222\214Selector.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220NIO\345\214\205\344\270\255\347\232\204Buffer\343\200\201Channel\345\222\214Selector.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220NIO\345\214\205\344\270\255\347\232\204Buffer\343\200\201Channel\345\222\214Selector.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220mmap\345\222\214DirectBuffer.md" "b/docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220mmap\345\222\214DirectBuffer.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220mmap\345\222\214DirectBuffer.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\346\236\220mmap\345\222\214DirectBuffer.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\350\260\210Linux\344\270\255Selector\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md" "b/docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\350\260\210Linux\344\270\255Selector\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\350\260\210Linux\344\270\255Selector\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\265\205\350\260\210Linux\344\270\255Selector\347\232\204\345\256\236\347\216\260\345\216\237\347\220\206.md"
diff --git "a/docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Tomcat\344\270\255\347\232\204NIO\346\250\241\345\236\213.md" "b/docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Tomcat\344\270\255\347\232\204NIO\346\250\241\345\236\213.md"
similarity index 100%
rename from "docs/java/network-programming/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Tomcat\344\270\255\347\232\204NIO\346\250\241\345\236\213.md"
rename to "docs/Java/network/Java\347\275\221\347\273\234\347\274\226\347\250\213\344\270\216NIO\350\257\246\350\247\243\357\274\232\346\267\261\345\272\246\350\247\243\350\257\273Tomcat\344\270\255\347\232\204NIO\346\250\241\345\236\213.md"
diff --git "a/docs/java-web/JavaWeb\346\212\200\346\234\257\346\200\273\347\273\223.md" "b/docs/JavaWeb/JavaWeb\346\212\200\346\234\257\346\200\273\347\273\223.md"
similarity index 100%
rename from "docs/java-web/JavaWeb\346\212\200\346\234\257\346\200\273\347\273\223.md"
rename to "docs/JavaWeb/JavaWeb\346\212\200\346\234\257\346\200\273\347\273\223.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Hibernate\345\205\245\351\227\250\347\273\217\345\205\270\344\270\216\346\263\250\350\247\243\345\274\217\345\274\200\345\217\221.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Hibernate\345\205\245\351\227\250\347\273\217\345\205\270\344\270\216\346\263\250\350\247\243\345\274\217\345\274\200\345\217\221.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Hibernate\345\205\245\351\227\250\347\273\217\345\205\270\344\270\216\346\263\250\350\247\243\345\274\217\345\274\200\345\217\221.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Hibernate\345\205\245\351\227\250\347\273\217\345\205\270\344\270\216\346\263\250\350\247\243\345\274\217\345\274\200\345\217\221.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JDBC\347\232\204\350\277\233\345\214\226\344\270\216\350\277\236\346\216\245\346\261\240\346\212\200\346\234\257.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JDBC\347\232\204\350\277\233\345\214\226\344\270\216\350\277\236\346\216\245\346\261\240\346\212\200\346\234\257.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JDBC\347\232\204\350\277\233\345\214\226\344\270\216\350\277\236\346\216\245\346\261\240\346\212\200\346\234\257.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JDBC\347\232\204\350\277\233\345\214\226\344\270\216\350\277\236\346\216\245\346\261\240\346\212\200\346\234\257.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JSP\344\270\216Servlet\347\232\204\346\233\276\347\273\217\344\270\216\347\216\260\345\234\250.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JSP\344\270\216Servlet\347\232\204\346\233\276\347\273\217\344\270\216\347\216\260\345\234\250.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JSP\344\270\216Servlet\347\232\204\346\233\276\347\273\217\344\270\216\347\216\260\345\234\250.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JSP\344\270\216Servlet\347\232\204\346\233\276\347\273\217\344\270\216\347\216\260\345\234\250.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JavaWeb\347\232\204\347\224\261\346\235\245\345\222\214\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JavaWeb\347\232\204\347\224\261\346\235\245\345\222\214\345\237\272\347\241\200\347\237\245\350\257\206.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JavaWeb\347\232\204\347\224\261\346\235\245\345\222\214\345\237\272\347\241\200\347\237\245\350\257\206.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232JavaWeb\347\232\204\347\224\261\346\235\245\345\222\214\345\237\272\347\241\200\347\237\245\350\257\206.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Java\346\227\245\345\277\227\347\263\273\347\273\237\347\232\204\350\257\236\347\224\237\344\270\216\345\217\221\345\261\225.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Java\346\227\245\345\277\227\347\263\273\347\273\237\347\232\204\350\257\236\347\224\237\344\270\216\345\217\221\345\261\225.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Java\346\227\245\345\277\227\347\263\273\347\273\237\347\232\204\350\257\236\347\224\237\344\270\216\345\217\221\345\261\225.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Java\346\227\245\345\277\227\347\263\273\347\273\237\347\232\204\350\257\236\347\224\237\344\270\216\345\217\221\345\261\225.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Mybatis\345\205\245\351\227\250.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Mybatis\345\205\245\351\227\250.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Mybatis\345\205\245\351\227\250.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Mybatis\345\205\245\351\227\250.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Servlet\345\267\245\344\275\234\345\216\237\347\220\206\350\257\246\350\247\243.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Servlet\345\267\245\344\275\234\345\216\237\347\220\206\350\257\246\350\247\243.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Servlet\345\267\245\344\275\234\345\216\237\347\220\206\350\257\246\350\247\243.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Servlet\345\267\245\344\275\234\345\216\237\347\220\206\350\257\246\350\247\243.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat5\346\200\273\344\275\223\346\236\266\346\236\204\345\211\226\346\236\220.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat5\346\200\273\344\275\223\346\236\266\346\236\204\345\211\226\346\236\220.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat5\346\200\273\344\275\223\346\236\266\346\236\204\345\211\226\346\236\220.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat5\346\200\273\344\275\223\346\236\266\346\236\204\345\211\226\346\236\220.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat\345\222\214\345\205\266\344\273\226WEB\345\256\271\345\231\250\347\232\204\345\214\272\345\210\253.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat\345\222\214\345\205\266\344\273\226WEB\345\256\271\345\231\250\347\232\204\345\214\272\345\210\253.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat\345\222\214\345\205\266\344\273\226WEB\345\256\271\345\231\250\347\232\204\345\214\272\345\210\253.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232Tomcat\345\222\214\345\205\266\344\273\226WEB\345\256\271\345\231\250\347\232\204\345\214\272\345\210\253.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216JavaBean\350\256\262\345\210\260Spring.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216JavaBean\350\256\262\345\210\260Spring.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216JavaBean\350\256\262\345\210\260Spring.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216JavaBean\350\256\262\345\210\260Spring.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216\346\211\213\345\212\250\347\274\226\350\257\221\346\211\223\345\214\205\345\210\260\351\241\271\347\233\256\346\236\204\345\273\272\345\267\245\345\205\267Maven.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216\346\211\213\345\212\250\347\274\226\350\257\221\346\211\223\345\214\205\345\210\260\351\241\271\347\233\256\346\236\204\345\273\272\345\267\245\345\205\267Maven.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216\346\211\213\345\212\250\347\274\226\350\257\221\346\211\223\345\214\205\345\210\260\351\241\271\347\233\256\346\236\204\345\273\272\345\267\245\345\205\267Maven.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\344\273\216\346\211\213\345\212\250\347\274\226\350\257\221\346\211\223\345\214\205\345\210\260\351\241\271\347\233\256\346\236\204\345\273\272\345\267\245\345\205\267Maven.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\210\235\346\216\242Tomcat9\347\232\204HTTP\350\257\267\346\261\202\350\277\207\347\250\213.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\210\235\346\216\242Tomcat9\347\232\204HTTP\350\257\267\346\261\202\350\277\207\347\250\213.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\210\235\346\216\242Tomcat9\347\232\204HTTP\350\257\267\346\261\202\350\277\207\347\250\213.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\210\235\346\216\242Tomcat9\347\232\204HTTP\350\257\267\346\261\202\350\277\207\347\250\213.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\215\225\345\205\203\346\265\213\350\257\225\346\241\206\346\236\266Junit.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\215\225\345\205\203\346\265\213\350\257\225\346\241\206\346\236\266Junit.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\215\225\345\205\203\346\265\213\350\257\225\346\241\206\346\236\266Junit.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\345\215\225\345\205\203\346\265\213\350\257\225\346\241\206\346\236\266Junit.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\236\201\347\256\200\351\205\215\347\275\256\347\232\204SpringBoot.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\236\201\347\256\200\351\205\215\347\275\256\347\232\204SpringBoot.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\236\201\347\256\200\351\205\215\347\275\256\347\232\204SpringBoot.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\236\201\347\256\200\351\205\215\347\275\256\347\232\204SpringBoot.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\265\205\346\236\220Tomcat\350\257\267\346\261\202\345\244\204\347\220\206\346\265\201\347\250\213\344\270\216\345\220\257\345\212\250\351\203\250\347\275\262\350\277\207\347\250\213.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\265\205\346\236\220Tomcat\350\257\267\346\261\202\345\244\204\347\220\206\346\265\201\347\250\213\344\270\216\345\220\257\345\212\250\351\203\250\347\275\262\350\277\207\347\250\213.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\265\205\346\236\220Tomcat\350\257\267\346\261\202\345\244\204\347\220\206\346\265\201\347\250\213\344\270\216\345\220\257\345\212\250\351\203\250\347\275\262\350\277\207\347\250\213.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\265\205\346\236\220Tomcat\350\257\267\346\261\202\345\244\204\347\220\206\346\265\201\347\250\213\344\270\216\345\220\257\345\212\250\351\203\250\347\275\262\350\277\207\347\250\213.md"
diff --git "a/docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\267\261\345\205\245\346\265\205\345\207\272Mybatis\345\237\272\346\234\254\345\216\237\347\220\206.md" "b/docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\267\261\345\205\245\346\265\205\345\207\272Mybatis\345\237\272\346\234\254\345\216\237\347\220\206.md"
similarity index 100%
rename from "docs/java-web/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\267\261\345\205\245\346\265\205\345\207\272Mybatis\345\237\272\346\234\254\345\216\237\347\220\206.md"
rename to "docs/JavaWeb/\350\265\260\350\277\233JavaWeb\346\212\200\346\234\257\344\270\226\347\225\214\357\274\232\346\267\261\345\205\245\346\265\205\345\207\272Mybatis\345\237\272\346\234\254\345\216\237\347\220\206.md"
diff --git "a/docs/spring/SpringAOP\347\232\204\346\246\202\345\277\265\344\270\216\344\275\234\347\224\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/SpringAOP\347\232\204\346\246\202\345\277\265\344\270\216\344\275\234\347\224\250.md"
similarity index 100%
rename from "docs/spring/SpringAOP\347\232\204\346\246\202\345\277\265\344\270\216\344\275\234\347\224\250.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/SpringAOP\347\232\204\346\246\202\345\277\265\344\270\216\344\275\234\347\224\250.md"
diff --git "a/docs/spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md"
similarity index 100%
rename from "docs/spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/SpringBean\347\232\204\345\256\232\344\271\211\344\270\216\347\256\241\347\220\206\357\274\210\346\240\270\345\277\203\357\274\211.md"
diff --git "a/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\225\260\346\215\256\345\272\223\347\232\204\350\256\277\351\227\256.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\345\257\271\344\272\216\346\225\260\346\215\256\345\272\223\347\232\204\350\256\277\351\227\256.md"
similarity index 100%
rename from "docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\225\260\346\215\256\345\272\223\347\232\204\350\256\277\351\227\256.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\345\257\271\344\272\216\346\225\260\346\215\256\345\272\223\347\232\204\350\256\277\351\227\256.md"
diff --git "a/docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md"
similarity index 100%
rename from "docs/spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\345\257\271\344\272\216\346\240\241\351\252\214\345\212\237\350\203\275\347\232\204\346\224\257\346\214\201.md"
diff --git "a/docs/spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md"
similarity index 100%
rename from "docs/spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204Environment\347\216\257\345\242\203\345\217\230\351\207\217.md"
diff --git "a/docs/spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md"
similarity index 100%
rename from "docs/spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204\344\272\213\344\273\266\345\244\204\347\220\206\346\234\272\345\210\266.md"
diff --git "a/docs/spring/Spring\344\270\255\347\232\204\350\265\204\346\272\220\347\256\241\347\220\206.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204\350\265\204\346\272\220\347\256\241\347\220\206.md"
similarity index 100%
rename from "docs/spring/Spring\344\270\255\347\232\204\350\265\204\346\272\220\347\256\241\347\220\206.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204\350\265\204\346\272\220\347\256\241\347\220\206.md"
diff --git "a/docs/spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md"
similarity index 100%
rename from "docs/spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\270\255\347\232\204\351\205\215\347\275\256\345\205\203\346\225\260\346\215\256\357\274\210\347\256\241\347\220\206\351\205\215\347\275\256\347\232\204\345\237\272\346\234\254\346\225\260\346\215\256\357\274\211.md"
diff --git "a/docs/spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md"
similarity index 100%
rename from "docs/spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\344\272\213\345\212\241\345\237\272\346\234\254\347\224\250\346\263\225.md"
diff --git "a/docs/spring/Spring\345\220\210\351\233\206.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\345\220\210\351\233\206.md"
similarity index 100%
rename from "docs/spring/Spring\345\220\210\351\233\206.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\345\220\210\351\233\206.md"
diff --git "a/docs/spring/Spring\345\256\271\345\231\250\344\270\216IOC.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\345\256\271\345\231\250\344\270\216IOC.md"
similarity index 100%
rename from "docs/spring/Spring\345\256\271\345\231\250\344\270\216IOC.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\345\256\271\345\231\250\344\270\216IOC.md"
diff --git "a/docs/spring/Spring\345\270\270\350\247\201\346\263\250\350\247\243.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\345\270\270\350\247\201\346\263\250\350\247\243.md"
similarity index 100%
rename from "docs/spring/Spring\345\270\270\350\247\201\346\263\250\350\247\243.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\345\270\270\350\247\201\346\263\250\350\247\243.md"
diff --git "a/docs/spring/Spring\346\246\202\350\277\260.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/spring/Spring\346\246\202\350\277\260.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\346\246\202\350\277\260.md"
diff --git "a/docs/spring/\347\254\254\344\270\200\344\270\252Spring\345\272\224\347\224\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/\347\254\254\344\270\200\344\270\252Spring\345\272\224\347\224\250.md"
similarity index 100%
rename from "docs/spring/\347\254\254\344\270\200\344\270\252Spring\345\272\224\347\224\250.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring/\347\254\254\344\270\200\344\270\252Spring\345\272\224\347\224\250.md"
diff --git "a/docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\344\273\273\345\212\241\350\260\203\345\272\246\344\270\216@Async.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\344\270\255\347\232\204\344\273\273\345\212\241\350\260\203\345\272\246\344\270\216@Async.md"
similarity index 100%
rename from "docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\344\273\273\345\212\241\350\260\203\345\272\246\344\270\216@Async.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\344\270\255\347\232\204\344\273\273\345\212\241\350\260\203\345\272\246\344\270\216@Async.md"
diff --git "a/docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\346\227\245\345\277\227\347\256\241\347\220\206.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\344\270\255\347\232\204\346\227\245\345\277\227\347\256\241\347\220\206.md"
similarity index 100%
rename from "docs/spring/SpringBoot/SpringBoot\344\270\255\347\232\204\346\227\245\345\277\227\347\256\241\347\220\206.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\344\270\255\347\232\204\346\227\245\345\277\227\347\256\241\347\220\206.md"
diff --git "a/docs/spring/SpringBoot/SpringBoot\345\270\270\350\247\201\346\263\250\350\247\243.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\345\270\270\350\247\201\346\263\250\350\247\243.md"
similarity index 100%
rename from "docs/spring/SpringBoot/SpringBoot\345\270\270\350\247\201\346\263\250\350\247\243.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\345\270\270\350\247\201\346\263\250\350\247\243.md"
diff --git "a/docs/spring/SpringBoot/SpringBoot\345\272\224\347\224\250\344\271\237\345\217\257\344\273\245\351\203\250\347\275\262\345\210\260\345\244\226\351\203\250Tomcat.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\345\272\224\347\224\250\344\271\237\345\217\257\344\273\245\351\203\250\347\275\262\345\210\260\345\244\226\351\203\250Tomcat.md"
similarity index 100%
rename from "docs/spring/SpringBoot/SpringBoot\345\272\224\347\224\250\344\271\237\345\217\257\344\273\245\351\203\250\347\275\262\345\210\260\345\244\226\351\203\250Tomcat.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\345\272\224\347\224\250\344\271\237\345\217\257\344\273\245\351\203\250\347\275\262\345\210\260\345\244\226\351\203\250Tomcat.md"
diff --git "a/docs/spring/SpringBoot/SpringBoot\347\224\237\344\272\247\347\216\257\345\242\203\345\267\245\345\205\267Actuator.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\224\237\344\272\247\347\216\257\345\242\203\345\267\245\345\205\267Actuator.md"
similarity index 100%
rename from "docs/spring/SpringBoot/SpringBoot\347\224\237\344\272\247\347\216\257\345\242\203\345\267\245\345\205\267Actuator.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\224\237\344\272\247\347\216\257\345\242\203\345\267\245\345\205\267Actuator.md"
diff --git "a/docs/spring/SpringBoot/SpringBoot\347\232\204Starter\346\234\272\345\210\266.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204Starter\346\234\272\345\210\266.md"
similarity index 100%
rename from "docs/spring/SpringBoot/SpringBoot\347\232\204Starter\346\234\272\345\210\266.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204Starter\346\234\272\345\210\266.md"
diff --git "a/docs/spring/SpringBoot/SpringBoot\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md"
similarity index 100%
rename from "docs/spring/SpringBoot/SpringBoot\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md"
diff --git "a/docs/spring/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md"
similarity index 100%
rename from "docs/spring/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204\345\237\272\346\234\254\344\275\277\347\224\250.md"
diff --git "a/docs/spring/SpringBoot/SpringBoot\347\232\204\351\205\215\347\275\256\346\226\207\344\273\266\347\256\241\347\220\206.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204\351\205\215\347\275\256\346\226\207\344\273\266\347\256\241\347\220\206.md"
similarity index 100%
rename from "docs/spring/SpringBoot/SpringBoot\347\232\204\351\205\215\347\275\256\346\226\207\344\273\266\347\256\241\347\220\206.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204\351\205\215\347\275\256\346\226\207\344\273\266\347\256\241\347\220\206.md"
diff --git "a/docs/spring/SpringBoot/SpringBoot\350\207\252\345\270\246\347\232\204\347\203\255\351\203\250\347\275\262\345\267\245\345\205\267.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\350\207\252\345\270\246\347\232\204\347\203\255\351\203\250\347\275\262\345\267\245\345\205\267.md"
similarity index 100%
rename from "docs/spring/SpringBoot/SpringBoot\350\207\252\345\270\246\347\232\204\347\203\255\351\203\250\347\275\262\345\267\245\345\205\267.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\350\207\252\345\270\246\347\232\204\347\203\255\351\203\250\347\275\262\345\267\245\345\205\267.md"
diff --git "a/docs/spring/SpringBoot/SpringBoot\351\233\206\346\210\220Swagger\345\256\236\347\216\260API\346\226\207\346\241\243\350\207\252\345\212\250\347\224\237\346\210\220.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\351\233\206\346\210\220Swagger\345\256\236\347\216\260API\346\226\207\346\241\243\350\207\252\345\212\250\347\224\237\346\210\220.md"
similarity index 100%
rename from "docs/spring/SpringBoot/SpringBoot\351\233\206\346\210\220Swagger\345\256\236\347\216\260API\346\226\207\346\241\243\350\207\252\345\212\250\347\224\237\346\210\220.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\351\233\206\346\210\220Swagger\345\256\236\347\216\260API\346\226\207\346\241\243\350\207\252\345\212\250\347\224\237\346\210\220.md"
diff --git "a/docs/spring/SpringBoot/Spring\345\270\270\350\247\201\346\263\250\350\247\243\344\275\277\347\224\250\346\214\207\345\215\227(\345\214\205\345\220\253Spring+SpringMVC+SpringBoot).md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/Spring\345\270\270\350\247\201\346\263\250\350\247\243\344\275\277\347\224\250\346\214\207\345\215\227(\345\214\205\345\220\253Spring+SpringMVC+SpringBoot).md"
similarity index 100%
rename from "docs/spring/SpringBoot/Spring\345\270\270\350\247\201\346\263\250\350\247\243\344\275\277\347\224\250\346\214\207\345\215\227(\345\214\205\345\220\253Spring+SpringMVC+SpringBoot).md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/Spring\345\270\270\350\247\201\346\263\250\350\247\243\344\275\277\347\224\250\346\214\207\345\215\227(\345\214\205\345\220\253Spring+SpringMVC+SpringBoot).md"
diff --git "a/docs/spring/SpringBoot/\345\237\272\344\272\216SpringBoot\344\270\255\347\232\204\345\274\200\346\272\220\347\233\221\346\216\247\345\267\245\345\205\267SpringBootAdmin.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/\345\237\272\344\272\216SpringBoot\344\270\255\347\232\204\345\274\200\346\272\220\347\233\221\346\216\247\345\267\245\345\205\267SpringBootAdmin.md"
similarity index 100%
rename from "docs/spring/SpringBoot/\345\237\272\344\272\216SpringBoot\344\270\255\347\232\204\345\274\200\346\272\220\347\233\221\346\216\247\345\267\245\345\205\267SpringBootAdmin.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/\345\237\272\344\272\216SpringBoot\344\270\255\347\232\204\345\274\200\346\272\220\347\233\221\346\216\247\345\267\245\345\205\267SpringBootAdmin.md"
diff --git "a/docs/spring/SpringBoot/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md"
similarity index 100%
rename from "docs/spring/SpringBoot/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/\347\273\231\344\275\240\344\270\200\344\273\275SpringBoot\347\237\245\350\257\206\346\270\205\345\215\225.md"
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\233\275\351\231\205\345\214\226\345\212\237\350\203\275.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\345\233\275\351\231\205\345\214\226\345\212\237\350\203\275.md"
similarity index 100%
rename from "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\233\275\351\231\205\345\214\226\345\212\237\350\203\275.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\345\233\275\351\231\205\345\214\226\345\212\237\350\203\275.md"
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\270\270\347\224\250\345\212\237\350\203\275.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\345\270\270\347\224\250\345\212\237\350\203\275.md"
similarity index 100%
rename from "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\270\270\347\224\250\345\212\237\350\203\275.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\345\270\270\347\224\250\345\212\237\350\203\275.md"
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\274\202\345\270\270\345\244\204\347\220\206\345\231\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\345\274\202\345\270\270\345\244\204\347\220\206\345\231\250.md"
similarity index 100%
rename from "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\345\274\202\345\270\270\345\244\204\347\220\206\345\231\250.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\345\274\202\345\270\270\345\244\204\347\220\206\345\231\250.md"
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\346\213\246\346\210\252\345\231\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\346\213\246\346\210\252\345\231\250.md"
similarity index 100%
rename from "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\346\213\246\346\210\252\345\231\250.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\346\213\246\346\210\252\345\231\250.md"
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\231\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\231\250.md"
similarity index 100%
rename from "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\231\250.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\231\250.md"
diff --git "a/docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\277\207\346\273\244\345\231\250Filter.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\350\277\207\346\273\244\345\231\250Filter.md"
similarity index 100%
rename from "docs/spring/SpringMVC/SpringMVC\344\270\255\347\232\204\350\277\207\346\273\244\345\231\250Filter.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\344\270\255\347\232\204\350\277\207\346\273\244\345\231\250Filter.md"
diff --git "a/docs/spring/SpringMVC/SpringMVC\345\237\272\346\234\254\344\273\213\347\273\215\344\270\216\345\277\253\351\200\237\345\205\245\351\227\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\345\237\272\346\234\254\344\273\213\347\273\215\344\270\216\345\277\253\351\200\237\345\205\245\351\227\250.md"
similarity index 100%
rename from "docs/spring/SpringMVC/SpringMVC\345\237\272\346\234\254\344\273\213\347\273\215\344\270\216\345\277\253\351\200\237\345\205\245\351\227\250.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\345\237\272\346\234\254\344\273\213\347\273\215\344\270\216\345\277\253\351\200\237\345\205\245\351\227\250.md"
diff --git "a/docs/spring/SpringMVC/SpringMVC\345\246\202\344\275\225\345\256\236\347\216\260\346\226\207\344\273\266\344\270\212\344\274\240.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\345\246\202\344\275\225\345\256\236\347\216\260\346\226\207\344\273\266\344\270\212\344\274\240.md"
similarity index 100%
rename from "docs/spring/SpringMVC/SpringMVC\345\246\202\344\275\225\345\256\236\347\216\260\346\226\207\344\273\266\344\270\212\344\274\240.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\345\246\202\344\275\225\345\256\236\347\216\260\346\226\207\344\273\266\344\270\212\344\274\240.md"
diff --git "a/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
similarity index 100%
rename from "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
diff --git "a/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md"
similarity index 100%
rename from "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\345\246\202\344\275\225\346\211\276\345\210\260\346\255\243\347\241\256\347\232\204Controller.md"
diff --git "a/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md"
similarity index 100%
rename from "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232DispatcherServlet\347\232\204\345\210\235\345\247\213\345\214\226\344\270\216\350\257\267\346\261\202\350\275\254\345\217\221.md"
diff --git "a/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\346\246\202\350\277\260.md"
diff --git "a/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md"
similarity index 100%
rename from "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\347\232\204\350\247\206\345\233\276\350\247\243\346\236\220\345\216\237\347\220\206.md"
diff --git "a/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md"
similarity index 100%
rename from "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232SpringMVC\350\256\276\350\256\241\347\220\206\345\277\265\344\270\216DispatcherServlet.md"
diff --git "a/docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md"
similarity index 100%
rename from "docs/spring/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220\357\274\232\346\266\210\346\201\257\350\275\254\346\215\242\345\231\250HttpMessageConverter\344\270\216@ResponseBody\346\263\250\350\247\243.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232AOP\345\256\236\347\216\260\345\216\237\347\220\206\350\257\246\350\247\243.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232JDK\345\222\214cglib\345\212\250\346\200\201\344\273\243\347\220\206\345\216\237\347\220\206\350\257\246\350\247\243.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringAOP\346\246\202\350\277\260.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232SpringIOC\345\256\271\345\231\250\347\232\204\345\212\240\350\275\275\350\277\207\347\250\213.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\246\202\350\277\260.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\344\272\213\345\212\241\346\272\220\347\240\201\345\211\226\346\236\220.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\345\210\235\346\216\242SpringIOC\346\240\270\345\277\203\346\265\201\347\250\213.md"
diff --git "a/docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md"
similarity index 100%
rename from "docs/spring/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232\346\207\222\345\212\240\350\275\275\347\232\204\345\215\225\344\276\213Bean\350\216\267\345\217\226\350\277\207\347\250\213\345\210\206\346\236\220.md"
diff --git "a/docs/big-backEnd/Hadoop\347\224\237\346\200\201\346\200\273\347\273\223.md" "b/docs/backend/Hadoop\347\224\237\346\200\201\346\200\273\347\273\223.md"
similarity index 100%
rename from "docs/big-backEnd/Hadoop\347\224\237\346\200\201\346\200\273\347\273\223.md"
rename to "docs/backend/Hadoop\347\224\237\346\200\201\346\200\273\347\273\223.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\345\274\200\347\257\207\357\274\232\344\272\221\350\256\241\347\256\227\357\274\214\345\244\247\346\225\260\346\215\256\344\270\216AI\347\232\204\346\225\205\344\272\213.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\345\274\200\347\257\207\357\274\232\344\272\221\350\256\241\347\256\227\357\274\214\345\244\247\346\225\260\346\215\256\344\270\216AI\347\232\204\346\225\205\344\272\213.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\345\274\200\347\257\207\357\274\232\344\272\221\350\256\241\347\256\227\357\274\214\345\244\247\346\225\260\346\215\256\344\270\216AI\347\232\204\346\225\205\344\272\213.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\345\274\200\347\257\207\357\274\232\344\272\221\350\256\241\347\256\227\357\274\214\345\244\247\346\225\260\346\215\256\344\270\216AI\347\232\204\346\225\205\344\272\213.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Docker \346\240\270\345\277\203\346\212\200\346\234\257\344\270\216\345\256\236\347\216\260\345\216\237\347\220\206.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Docker \346\240\270\345\277\203\346\212\200\346\234\257\344\270\216\345\256\236\347\216\260\345\216\237\347\220\206.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Docker \346\240\270\345\277\203\346\212\200\346\234\257\344\270\216\345\256\236\347\216\260\345\216\237\347\220\206.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Docker \346\240\270\345\277\203\346\212\200\346\234\257\344\270\216\345\256\236\347\216\260\345\216\237\347\220\206.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Elasticsearch\344\270\216solr\345\205\245\351\227\250\345\256\236\350\267\265.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Elasticsearch\344\270\216solr\345\205\245\351\227\250\345\256\236\350\267\265.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Elasticsearch\344\270\216solr\345\205\245\351\227\250\345\256\236\350\267\265.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Elasticsearch\344\270\216solr\345\205\245\351\227\250\345\256\236\350\267\265.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Lucene\345\237\272\347\241\200\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Lucene\345\237\272\347\241\200\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Lucene\345\237\272\347\241\200\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232Lucene\345\237\272\347\241\200\345\216\237\347\220\206\344\270\216\345\256\236\350\267\265.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\346\236\266\346\236\204\350\256\276\350\256\241.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\346\236\266\346\236\204\350\256\276\350\256\241.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\346\236\266\346\236\204\350\256\276\350\256\241.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\346\236\266\346\236\204\350\256\276\350\256\241.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\347\232\204\345\237\272\347\237\263KVM.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\347\232\204\345\237\272\347\237\263KVM.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\347\232\204\345\237\272\347\237\263KVM.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232OpenStack\347\232\204\345\237\272\347\237\263KVM.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\344\272\221\350\256\241\347\256\227\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\344\272\221\350\256\241\347\256\227\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\344\272\221\350\256\241\347\256\227\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\344\272\221\350\256\241\347\256\227\347\232\204\345\211\215\344\270\226\344\273\212\347\224\237.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\205\210\346\220\236\346\207\202Docker\346\240\270\345\277\203\346\246\202\345\277\265\345\220\247.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\205\210\346\220\236\346\207\202Docker\346\240\270\345\277\203\346\246\202\345\277\265\345\220\247.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\205\210\346\220\236\346\207\202Docker\346\240\270\345\277\203\346\246\202\345\277\265\345\220\247.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\205\210\346\220\236\346\207\202Docker\346\240\270\345\277\203\346\246\202\345\277\265\345\220\247.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\215\201\345\210\206\351\222\237\347\220\206\350\247\243Kubernetes\346\240\270\345\277\203\346\246\202\345\277\265.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\215\201\345\210\206\351\222\237\347\220\206\350\247\243Kubernetes\346\240\270\345\277\203\346\246\202\345\277\265.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\215\201\345\210\206\351\222\237\347\220\206\350\247\243Kubernetes\346\240\270\345\277\203\346\246\202\345\277\265.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\345\215\201\345\210\206\351\222\237\347\220\206\350\247\243Kubernetes\346\240\270\345\277\203\346\246\202\345\277\265.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\215\213\344\270\200\346\215\213\345\244\247\346\225\260\346\215\256\347\240\224\345\217\221\347\232\204\345\237\272\346\234\254\346\246\202\345\277\265.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\215\213\344\270\200\346\215\213\345\244\247\346\225\260\346\215\256\347\240\224\345\217\221\347\232\204\345\237\272\346\234\254\346\246\202\345\277\265.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\215\213\344\270\200\346\215\213\345\244\247\346\225\260\346\215\256\347\240\224\345\217\221\347\232\204\345\237\272\346\234\254\346\246\202\345\277\265.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\215\213\344\270\200\346\215\213\345\244\247\346\225\260\346\215\256\347\240\224\345\217\221\347\232\204\345\237\272\346\234\254\346\246\202\345\277\265.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\237\272\347\241\200\345\200\222\346\216\222\347\264\242\345\274\225.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\237\272\347\241\200\345\200\222\346\216\222\347\264\242\345\274\225.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\237\272\347\241\200\345\200\222\346\216\222\347\264\242\345\274\225.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\237\272\347\241\200\345\200\222\346\216\222\347\264\242\345\274\225.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\267\245\344\275\234\345\216\237\347\220\206.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\267\245\344\275\234\345\216\237\347\220\206.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\267\245\344\275\234\345\216\237\347\220\206.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\346\220\234\347\264\242\345\274\225\346\223\216\345\267\245\344\275\234\345\216\237\347\220\206.md"
diff --git "a/docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\347\231\275\350\257\235\350\231\232\346\213\237\345\214\226\346\212\200\346\234\257.md" "b/docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\347\231\275\350\257\235\350\231\232\346\213\237\345\214\226\346\212\200\346\234\257.md"
similarity index 100%
rename from "docs/big-backEnd/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\347\231\275\350\257\235\350\231\232\346\213\237\345\214\226\346\212\200\346\234\257.md"
rename to "docs/backend/\345\220\216\347\253\257\346\212\200\346\234\257\346\235\202\350\260\210\357\274\232\347\231\275\350\257\235\350\231\232\346\213\237\345\214\226\346\212\200\346\234\257.md"
From f785d7e02af0858e84a16b5869c685c2eaac460b Mon Sep 17 00:00:00 2001
From: h2pl <362294931@qq.com>
Date: Sat, 22 Apr 2023 09:31:54 +0800
Subject: [PATCH 05/32] modify catelog
---
ReadMe.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/ReadMe.md b/ReadMe.md
index 83bc437..610af04 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -33,12 +33,10 @@
## Java基础
### 基础知识
-
* [��对象基础](docs/Java/basic/��对象基础.md)
* [Java基本数�类型](docs/Java/basic/Java基本数�类型.md)
* [string和包装类](docs/Java/basic/string和包装类.md)
* [final关键å—特性](docs/Java/basic/final关键å—特性.md)
-
* [Java类和包](docs/Java/basic/Java类和包.md)
* [抽象类和接�](docs/Java/basic/抽象类和接�.md)
* [代ç �å�—和代ç �执行顺åº�](docs/Java/basic/代ç �å�—和代ç �执行顺åº�.md)
From 9dd3edaf591194fab3f17634046fdf1d6155f570 Mon Sep 17 00:00:00 2001
From: h2pl <362294931@qq.com>
Date: Sat, 22 Apr 2023 09:33:19 +0800
Subject: [PATCH 06/32] modify catelog
---
ReadMe.md | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/ReadMe.md b/ReadMe.md
index 610af04..0c7168b 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -307,7 +307,7 @@ todo
* [å�Žç«¯æŠ€æœ¯æ�‚谈:æ�‹ä¸€æ�‹å¤§æ•°æ�®ç ”å�‘的基本概念](docs/backend/å�Žç«¯æŠ€æœ¯æ�‚谈:æ�‹ä¸€æ�‹å¤§æ•°æ�®ç ”å�‘的基本概念.md)
## 分布�
-### �论
+### 分布��论
* [分布�系统�论基础:一致性PC和PC ](docs/distributed/basic/分布�系统�论基础:一致性PC和PC.md)
* [分布�系统�论基础:CAP ](docs/distributed/basic/分布�系统�论基础:CAP.md)
* [分布�系统�论基础:时间时钟和事件顺�](docs/distributed/basic/分布�系统�论基础:时间时钟和事件顺�.md)
@@ -316,22 +316,15 @@ todo
* [分布�系统�论基础:RaftZab ](docs/distributed/basic/分布�系统�论基础:RaftZab.md)
* [分布�系统�论进阶:Paxos��和优化 ](docs/distributed/basic/分布�系统�论进阶:Paxos��和优化.md)
* [分布�系统�论基础:zookeeper分布��调�务 ](docs/distributed/basic/分布�系统�论基础:zookeeper分布��调�务.md)
+* [分布��论总结](docs/distributed/分布�技术实践总结.md)
-* [分布�技术实践总结](docs/distributed/分布��论总结.md)
-
-### 技术
+### 分布�技术
* [�懂分布�技术:分布�系统的一些基本概念](docs/distributed/practice/�懂分布�技术:分布�系统的一些基本概念.md )
* [�懂分布�技术:分布�一致性�议与Paxos,Raft算法](docs/distributed/practice/�懂分布�技术:分布�一致性�议与Paxos,Raft算法.md)
* [�懂分布�技术:�探分布��调�务zookeeper](docs/distributed/practice/�懂分布�技术:�探分布��调�务zookeeper.md )
* [�懂分布�技术:ZAB�议概述与选主�程详解](docs/distributed/practice/�懂分布�技术:ZAB�议概述与选主�程详解.md )
* [�懂分布�技术:Zookeeper的�置与集群管�实战](docs/distributed/practice/�懂分布�技术:Zookeeper的�置与集群管�实战.md)
* [�懂分布�技术:Zookeeper典型应用场景�实践](docs/distributed/practice/�懂分布�技术:Zookeeper典型应用场景�实践.md )
-
-[//]: # (* [�懂分布�技术:负载�衡概念与主�方案]docs/distributed/practice/�懂分布�技术:负载�衡概念与主�方案.md)
-
-[//]: # (* [�懂分布�技术:负载�衡原�剖� ]docs/distributed/practice/�懂分布�技术:负载�衡原�剖�.md )
-
-[//]: # (* [�懂分布�技术:Nginx负载�衡原�与实践 ]docs/distributed/practice/�懂分布�技术:Nginx负载�衡原�与实践.md)
* [�懂分布�技术:LVS实现负载�衡的原�与实践 ](docs/distributed/practice/�懂分布�技术:LVS实现负载�衡的原�与实践.md )
* [�懂分布�技术:分布�session解决方案与一致性hash](docs/distributed/practice/�懂分布�技术:分布�session解决方案与一致性hash.md)
* [�懂分布�技术:分布�ID生�方案 ](docs/distributed/practice/�懂分布�技术:分布�ID生�方案.md )
@@ -344,8 +337,8 @@ todo
* [�懂分布�技术:使用RocketMQ事务消�解决分布�事务 ](docs/distributed/practice/�懂分布�技术:使用RocketMQ事务消�解决分布�事务.md )
* [æ�žæ‡‚分布å¼�技术:消æ�¯é˜Ÿåˆ—å› ä½•è€Œç”Ÿ](docs/distributed/practice/æ�žæ‡‚分布å¼�技术:消æ�¯é˜Ÿåˆ—å› ä½•è€Œç”Ÿ.md)
* [�懂分布�技术:浅谈分布�消�技术Kafka](docs/distributed/practice/�懂分布�技术:浅谈分布�消�技术Kafka.md )
+* [分布�技术实践总结](docs/distributed/分布��论总结.md)
-* [分布��论总结](docs/distributed/分布�技术实践总结.md)
## �试指�
todo
From fa967a32077072edc98ad362215b2fca15b968d4 Mon Sep 17 00:00:00 2001
From: h2pl <362294931@qq.com>
Date: Sat, 22 Apr 2023 09:51:04 +0800
Subject: [PATCH 07/32] modify catelog
---
ReadMe.md | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/ReadMe.md b/ReadMe.md
index 0c7168b..979b79b 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -139,8 +139,8 @@
* [Java网络编程与NIO详解:基于NIO的网络编程框架Netty](docs/Java/network/Java网络编程与NIO详解:基于NIO的网络编程框架Netty.md)
* [Java网络编程与NIO详解:Java网络编程与NIO详解](docs/Java/network/Java网络编程与NIO详解:深度解读Tomcatä¸çš„NIO模型.md)
* [Java网络编程与NIO详解:Tomcatä¸çš„Connectoræº�ç �分æž�(NIO)](docs/Java/network/Java网络编程与NIO详解:Tomcatä¸çš„Connectoræº�ç �分æž�(NIO).md)
-
-## Spring
+## Spring全家桶
+### Spring
* [SpringAOP的概念与作用](docs/Spring全家桶/Spring/Spring常�注解.md)
* [SpringBean的定义与管ç�†ï¼ˆæ ¸å¿ƒï¼‰](docs/Spring全家桶/Spring/Spring常è§�注解.md)
@@ -157,7 +157,7 @@
* [Spring概述](docs/Spring全家桶/Spring/Spring常�注解.md)
* [第一个Spring应用](docs/Spring全家桶/Spring/Spring常�注解.md)
-## Springæº�ç �分æž�
+### Springæº�ç �分æž�
* [Springæº�ç �剖æž�:Spring概述](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring概述.md)
* [Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程.md)
@@ -169,7 +169,7 @@
* [Springæº�ç �剖æž�:Spring事务概述](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring事务概述.md)
* [Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring事务æº�ç �剖æž�.md)
-## SpringMVC
+### SpringMVC
* [SpringMVCä¸çš„国际化功能](docs/Spring全家桶/SpringMVC/SpringMVCä¸çš„国际化功能.md)
* [SpringMVCä¸çš„异常处ç�†å™¨](docs/Spring全家桶/SpringMVC/SpringMVCä¸çš„异常处ç�†å™¨.md)
@@ -180,7 +180,7 @@
* [SpringMVCå¦‚ä½•å®žçŽ°æ–‡ä»¶ä¸Šä¼ ](docs/Spring全家桶/SpringMVC/SpringMVCå¦‚ä½•å®žçŽ°æ–‡ä»¶ä¸Šä¼ .md)
* [SpringMVCä¸çš„常用功能](docs/Spring全家桶/SpringMVC/SpringMVCä¸çš„常用功能.md)
-## SpringMVCæº�ç �分æž�
+### SpringMVCæº�ç �分æž�
* [SpringMVCæº�ç �分æž�:SpringMVC概述](docs/Spring全家桶/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC概述.md)
* [SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet](docs/Spring全家桶/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC设计ç�†å¿µä¸ŽDispatcherServlet.md)
@@ -189,7 +189,7 @@
* [SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解](docs/Spring全家桶/SpringMVC/SpringMVCæº�ç �剖æž�:消æ�¯è½¬æ�¢å™¨HttpMessageConverter与@ResponseBody注解.md)
* [SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�† ](docs/Spring全家桶/SpringMVCæº�ç �分æž�/SpringMVCæº�ç �分æž�:SpringMVC的视图解æž�原ç�†.md)
-## SpringBoot
+### SpringBoot
* [SpringBoot系列:SpringBoot的�世今生](docs/Spring全家桶/SpringBoot/SpringBoot的�世今生.md)
* [ç»™ä½ ä¸€ä»½SpringBoot知识清å�•.md](docs/Spring全家桶/SpringBoot/ç»™ä½ ä¸€ä»½SpringBoot知识清å�•.md)
@@ -206,11 +206,11 @@
* [SpringBootä¸çš„任务调度与@Async](docs/Spring全家桶/SpringBoot/SpringBootä¸çš„任务调度与@Async.md)
* [基于SpringBootä¸çš„å¼€æº�监控工具SpringBootAdmin](docs/Spring全家桶/SpringBoot/基于SpringBootä¸çš„å¼€æº�监控工具SpringBootAdmin.md)
-## SpringBootæº�ç �分æž�
+### SpringBootæº�ç �分æž�
-## SpringCloud
+### SpringCloud
-## SpringCloudæº�ç �分æž�
+### SpringCloudæº�ç �分æž�
todo
From 63c28e23529834922cb04ca417e4868e9de14e24 Mon Sep 17 00:00:00 2001
From: h2pl <362294931@qq.com>
Date: Sat, 22 Apr 2023 14:44:48 +0800
Subject: [PATCH 08/32] springboot source code analysis
---
...05\344\270\216\345\220\257\345\212\250.md" | 1388 +++++++++++++++++
...otApplication \346\263\250\350\247\243.md" | 382 +++++
...\207\206\345\244\207 SpringApplication.md" | 318 ++++
...345\244\207IOC\345\256\271\345\231\250.md" | 535 +++++++
...20\350\241\214\347\216\257\345\242\203.md" | 508 ++++++
...50\345\206\214\346\265\201\347\250\213.md" | 655 ++++++++
...05\351\205\215\350\277\207\347\250\213.md" | 815 ++++++++++
...14\346\210\220\345\220\257\345\212\250.md" | 108 ++
...01\347\250\213\346\200\273\347\273\223.md" | 41 +
...345\212\250IOC\345\256\271\345\231\250.md" | 389 +++++
...50\350\243\205\351\205\215\347\261\273.md" | 456 ++++++
...05\351\205\215\351\241\272\345\272\217.md" | 568 +++++++
...41\344\273\266\346\263\250\350\247\243.md" | 961 ++++++++++++
13 files changed, 7124 insertions(+)
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/springboot\346\211\223\345\214\205\344\270\216\345\220\257\345\212\250.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/@SpringBootApplication \346\263\250\350\247\243.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\357\274\232\345\207\206\345\244\207 SpringApplication.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\211\357\274\211\357\274\232\345\207\206\345\244\207IOC\345\256\271\345\231\250.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\272\214\357\274\211\357\274\232\345\207\206\345\244\207\350\277\220\350\241\214\347\216\257\345\242\203.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot web\345\272\224\347\224\250\357\274\210\344\270\200\357\274\211\357\274\232servlet \347\273\204\344\273\266\347\232\204\346\263\250\345\206\214\346\265\201\347\250\213.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot web\345\272\224\347\224\250\357\274\210\344\272\214\357\274\211\357\274\232WebMvc \350\243\205\351\205\215\350\277\207\347\250\213.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\272\224\357\274\211\357\274\232\345\256\214\346\210\220\345\220\257\345\212\250.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\205\255\357\274\211\357\274\232\345\220\257\345\212\250\346\265\201\347\250\213\346\200\273\347\273\223.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\233\233\357\274\211\357\274\232\345\220\257\345\212\250IOC\345\256\271\345\231\250.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\270\200\357\274\211\357\274\232\345\212\240\350\275\275\350\207\252\345\212\250\350\243\205\351\205\215\347\261\273.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\270\211\357\274\211\357\274\232\350\207\252\345\212\250\350\243\205\351\205\215\351\241\272\345\272\217.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\272\214\357\274\211\357\274\232\346\235\241\344\273\266\346\263\250\350\247\243.md"
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/springboot\346\211\223\345\214\205\344\270\216\345\220\257\345\212\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/springboot\346\211\223\345\214\205\344\270\216\345\220\257\345\212\250.md"
new file mode 100644
index 0000000..9f13c13
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/springboot\346\211\223\345\214\205\344\270\216\345\220\257\345\212\250.md"
@@ -0,0 +1,1388 @@
+在使用`maven`构建`springboot`项目时,`springboot`相关 jar 包�以使用`parent方�`引入(�在`pom.xml`的`parent`节点引入`springboot`的`GAV`:`org.springframework.boot:spring-boot-starter-parent:2.1.1.RELEASE`),也�以使用`�parent方�`引入(�在 pom 的 dependencyManagement 节点引入`springboot`的`GAV`:`org.springframework.boot:spring-boot-dependencies:2.1.1.RELEASE`)。�时,在打包时,我们�以打� jar 包,也�以打� war 包,本文旨在梳��引入�打包方�的异�。
+
+### 1\. parent 方�引入,打� jar 包
+
+parent æ–¹å¼�,å�³åœ¨ pom 文件ä¸ï¼Œå°† springboot çš„ä¾�赖当æˆ�项目的 parent 引入,pom 文件示例如下:
+
+```
+
+
+ 4.0.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.1.RELEASE
+
+
+ com.gitee.funcy
+ springboot-parent-jar
+ 1.0.0
+ jar
+ springboot parent jar打包方�
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 3.8.1
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+
+```
+
+æ·»åŠ ä¸€ä¸ª controller:
+
+```
+package com.gitee.funcy.mavenparent.jar.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * ï½›è¿™é‡Œæ·»åŠ æ��è¿°ï½�
+ *
+ * @author funcy
+ * @date 2019-12-13 10:43 下�
+ */
+@RestController
+public class IndexController {
+
+ @RequestMapping("/")
+ public String helloWorld() {
+ return "hello world";
+ }
+
+}
+
+```
+
+�引入�动类:
+
+```
+package com.gitee.funcy.mavenparent.jar;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * ï½›è¿™é‡Œæ·»åŠ æ��è¿°ï½�
+ *
+ * @author funcy
+ * @date 2019-12-13 10:36 下�
+ */
+@SpringBootApplication
+public class Main {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Main.class, args);
+ }
+
+}
+
+```
+
+�行 Main 方法,请求`http://localhost:8080/`,结果如下:
+
+```
+ $ curl http://localhost:8080/
+hello world
+
+```
+
+�以看到,项目�行�功。
+
+接�,�试使用 jar 包�动:
+
+```
+# 打包
+ mvn clean install -Dmaven.test.skip=true
+ # �动jar包
+ java -jar target/springboot-parent-jar-1.0.0.jar
+
+```
+
+å�¯ä»¥çœ‹åˆ°ï¼Œé¡¹ç›®å�¯åЍæˆ�功,请求请求`http://localhost:8080/`,也能显示æ£ç¡®ç»“果。
+
+### 2\. � parent 方�引入,打� jar 包
+
+在实际项目ä¸ï¼Œé¡¹ç›®çš„ parent ä¾�èµ–å�¯èƒ½ç»™äº†å…¶ä»–é¡¹ç›®ï¼Œæ¤æ—¶ parent å¼•ç”¨å°±æ— æ³•è¿›è¡Œäº†ï¼Œè¿™æ—¶æˆ‘ä»¬éœ€è¦�é�ž parent 引入。é�ž parent 引入的 pom 如下:
+
+```
+
+
+ 4.0.0
+
+ com.gitee.funcy
+ springboot-jar
+ 1.0.0
+ jar
+ springboot�parent jar打包方�
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 2.1.1.RELEASE
+ 3.8.1
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+
+```
+
+å†�æ·»åŠ ä¸€ä¸ª`ControllerIndexController.java`与å�¯åŠ¨ç±»`Main.java`,这两个文件与上述示例相å�Œï¼Œè¿™é‡Œå°±ä¸�作展示了。
+
+�行 Main 方法,请求`http://localhost:8080/`,结果如下:
+
+```
+ $ curl http://localhost:8080/
+hello world
+
+```
+
+�以看到,项目�行�功。
+
+接�,�试使用 jar 包�动:
+
+```
+# 打包
+ mvn clean install -Dmaven.test.skip=true
+ # �动jar包
+ java -jar target/springboot-jar-1.0.0.jar
+
+```
+
+å�¯ä»¥çœ‹åˆ°ï¼Œé¡¹ç›®å�¯åЍæˆ�功,请求请求`http://localhost:8080/`,也能显示æ£ç¡®ç»“果。
+
+### 3\. parent 方�引入,打� war 包
+
+以上两ç§�æ–¹å¼�都是打æˆ� jarï¼Œä¸ºäº†å…¼å®¹ä¼ ç»Ÿçš„ servlet 应用,springboot 也支æŒ�打包 war 包,parent 引入打包 war 包的 pom 文件如下:
+
+```
+
+
+ 4.0.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.1.RELEASE
+
+
+ com.gitee.funcy
+ springboot-parent-war
+ 1.0.0
+
+ war
+ springboot parent war打包方�
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 3.8.1
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-test
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
+ 3.2.2
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
+
+```
+
+å†�æ·»åŠ ä¸€ä¸ª`ControllerIndexController.java`与å�¯åŠ¨ç±»`Main.java`,这两个文件与上述示例相å�Œï¼Œè¿™é‡Œå°±ä¸�作展示了。
+
+除æ¤ä¹‹å¤–,war 包方å¼�还需è¦�æ·»åŠ ä¸€ä¸ªç±»ï¼Œç”¨ä»¥å®žçŽ°`SpringBootServletInitializer`,该类与å�¯åŠ¨ç±»`Main.java`ä½�于å�Œä¸€ä¸ªåŒ…下,主è¦�是用æ�¥å¼•导 tomcat ç‰ servlet å®¹å™¨åŠ è½½ servlet,内容如下:
+
+```
+/**
+ * ï½›è¿™é‡Œæ·»åŠ æ��è¿°ï½�
+ *
+ * @author funcy
+ * @date 2019-12-20 1:22 下�
+ */
+public class StartApplication extends SpringBootServletInitializer {
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
+ // 注�这里�指�原先用main方法执行的Application�动类
+ return builder.sources(Main.class);
+ }
+}
+
+```
+
+�行 Main 方法,请求`http://localhost:8080/`,结果如下:
+
+```
+ $ curl http://localhost:8080/
+hello world
+
+```
+
+�以看到,项目�行�功。
+
+接�,�试使用 jar 包�动:
+
+```
+# 打包
+ mvn clean install -Dmaven.test.skip=true
+ # �动jar包
+ java -jar target/springboot-parent-war-1.0.0.jar
+
+```
+
+å�¯ä»¥çœ‹åˆ°ï¼Œé¡¹ç›®å�¯åЍæˆ�功,请求请求`http://localhost:8080/`,也能显示æ£ç¡®ç»“果。
+
+### 4\. � parent 方�引入,打� war 包
+
+å�Œæ ·åœ°ï¼Œæ‰“æˆ� war 包时,也å�¯ä½¿ç”¨é�ž parent 引入方å¼�:
+
+```
+
+
+ 4.0.0
+
+ com.gitee.funcy
+ springboot-war
+ 1.0.0
+
+ war
+ springboot�parent war打包方�
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 2.1.1.RELEASE
+ 3.8.1
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-test
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
+ 3.2.2
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+
+```
+
+å†�æ·»åŠ ä¸€ä¸ª`ControllerIndexController.java`ã€�`StartApplication.java`与å�¯åŠ¨ç±»`Main.java`,这三个文件与上述示例相å�Œï¼Œè¿™é‡Œå°±ä¸�作展示了。
+
+�行 Main 方法,请求`http://localhost:8080/`,结果如下:
+
+```
+ $ curl http://localhost:8080/
+hello world
+
+```
+
+�以看到,项目�行�功。
+
+接�,�试使用 jar 包�动:
+
+```
+# 打包
+ mvn clean install -Dmaven.test.skip=true
+ # �动jar包
+ java -jar target/springboot-war-1.0.0.jar
+
+```
+
+å�¯ä»¥çœ‹åˆ°ï¼Œé¡¹ç›®å�¯åЍæˆ�功,请求请求`http://localhost:8080/`,也能显示æ£ç¡®ç»“果。
+
+### 5\. 总结
+
+springboot 引入�打包方�组�下�有如下四�:
+
+| 打包 / 引入 | parent 方� | � parent 方� |
+| --- | --- | --- |
+| jar | parent-jar 方� | � parent-jar 方� |
+| war | parent-war 方� | � parent-war 方� |
+
+### 1\. 开�时�动
+
+在开å�‘æ—¶å�¯åЍ springboot 应用,指的是直接è¿�行æº�ç �,如在开å�‘时在 ide ä¸è¿�行å�¯åŠ¨ç±»çš„ main () 方法。
+
+#### 1.1 在 ide 䏿‰§è¡Œå�¯åŠ¨ç±»çš„`main()`方法
+
+自从有了 springboot å�Žï¼Œweb 项目就ä¸�å¿…å†�放到 web 容器ä¸è¿�行了,直接è¿�行项目的`main()`方法就行了:
+
+
+
+�动日志如下:
+
+```
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 21:11:16.365 INFO 84046 --- [ main] com.gitee.funcy.maven.jar.Main : Starting Main on l with PID 84046 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-jar/target/classes started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo)
+2020-01-07 21:11:16.368 INFO 84046 --- [ main] com.gitee.funcy.maven.jar.Main : No active profile set, falling back to default profiles: default
+2020-01-07 21:11:17.468 INFO 84046 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 21:11:17.497 INFO 84046 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 21:11:17.497 INFO 84046 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 21:11:17.513 INFO 84046 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 21:11:17.605 INFO 84046 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 21:11:17.605 INFO 84046 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1206 ms
+2020-01-07 21:11:17.861 INFO 84046 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 21:11:18.096 INFO 84046 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 21:11:18.100 INFO 84046 --- [ main] com.gitee.funcy.maven.jar.Main : Started Main in 1.988 seconds (JVM running for 2.34)
+2020-01-07 21:11:32.155 INFO 84046 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
+2020-01-07 21:11:32.155 INFO 84046 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2020-01-07 21:11:32.223 INFO 84046 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 68 ms
+
+```
+
+访问`http://localhost:8080/`,结果如下:
+
+```
+$ curl http://localhost:8080
+hello world
+
+```
+
+以上�动方�**war 与 jar 打包方�**都支�。
+
+#### 1.2`mvn spring-boot:run`�动
+
+è¿™ç§�æ–¹å¼�也是æº�ç �å�¯åŠ¨ï¼Œåœ¨å‘½ä»¤è¡Œç•Œé�¢è¿›å…¥é¡¹ç›®å¯¹åº”çš„æº�ç �目录下,然å�Žæ‰§è¡Œ`mvn spring-boot:run`命令:
+
+```
+springboot-parent-war $ mvn spring-boot:run
+[INFO] Scanning for projects...
+[INFO]
+[INFO] ---------------< com.gitee.funcy:springboot-parent-war >----------------
+[INFO] Building springboot parent war打包方� 1.0.0
+[INFO] --------------------------------[ war ]---------------------------------
+[INFO]
+[INFO] >>> spring-boot-maven-plugin:2.1.1.RELEASE:run (default-cli) > test-compile @ springboot-parent-war >>>
+[INFO]
+[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ springboot-parent-war ---
+[INFO] Using 'UTF-8' encoding to copy filtered resources.
+[INFO] Copying 0 resource
+[INFO] Copying 0 resource
+[INFO]
+[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ springboot-parent-war ---
+[INFO] Changes detected - recompiling the module!
+[INFO] Compiling 3 source files to /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-parent-war/target/classes
+[INFO]
+[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ springboot-parent-war ---
+[INFO] Using 'UTF-8' encoding to copy filtered resources.
+[INFO] skip non existing resourceDirectory /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-parent-war/src/test/resources
+[INFO]
+[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ springboot-parent-war ---
+[INFO] No sources to compile
+[INFO]
+[INFO] <<< spring-boot-maven-plugin:2.1.1.RELEASE:run (default-cli) < test-compile @ springboot-parent-war <<<
+[INFO]
+[INFO]
+[INFO] --- spring-boot-maven-plugin:2.1.1.RELEASE:run (default-cli) @ springboot-parent-war ---
+
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 21:40:50.577 INFO 84448 --- [ main] com.gitee.funcy.mavenparent.war.Main : Starting Main on funcydeMacBook-Pro.local with PID 84448 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-parent-war/target/classes started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-parent-war)
+2020-01-07 21:40:50.579 INFO 84448 --- [ main] com.gitee.funcy.mavenparent.war.Main : No active profile set, falling back to default profiles: default
+2020-01-07 21:40:51.311 INFO 84448 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 21:40:51.336 INFO 84448 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 21:40:51.337 INFO 84448 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 21:40:51.347 INFO 84448 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 21:40:51.406 INFO 84448 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 21:40:51.406 INFO 84448 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 800 ms
+2020-01-07 21:40:51.582 INFO 84448 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 21:40:51.736 INFO 84448 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 21:40:51.739 INFO 84448 --- [ main] com.gitee.funcy.mavenparent.war.Main : Started Main in 1.39 seconds (JVM running for 3.943)
+2020-01-07 21:41:04.068 INFO 84448 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
+2020-01-07 21:41:04.069 INFO 84448 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2020-01-07 21:41:04.076 INFO 84448 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 7 ms
+
+```
+
+�以看到,项目�动�功,请求`http://localhost:8080`,也能获得结果:
+
+```
+ $ curl http://localhost:8080
+hello world
+
+```
+
+以上�动方�**war 与 jar 打包方�**都支�。
+
+### 2\. jar 包�动
+
+#### 2.1`java -jar`方��动
+
+对于打�`jar包`的`springboot`项目,使用`java -jar xxx.jar`命令���动:
+
+```
+:target $ java -jar springboot-jar-1.0.0.jar
+
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 21:47:47.075 INFO 85080 --- [ main] com.gitee.funcy.maven.jar.Main : Starting Main on funcydeMacBook-Pro.local with PID 85080 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-jar/target/springboot-jar-1.0.0.jar started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-jar/target)
+2020-01-07 21:47:47.077 INFO 85080 --- [ main] com.gitee.funcy.maven.jar.Main : No active profile set, falling back to default profiles: default
+2020-01-07 21:47:48.152 INFO 85080 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 21:47:48.186 INFO 85080 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 21:47:48.186 INFO 85080 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 21:47:48.202 INFO 85080 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 21:47:48.303 INFO 85080 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 21:47:48.303 INFO 85080 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1177 ms
+2020-01-07 21:47:48.502 INFO 85080 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 21:47:48.677 INFO 85080 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 21:47:48.680 INFO 85080 --- [ main] com.gitee.funcy.maven.jar.Main : Started Main in 1.977 seconds (JVM running for 2.398)
+
+```
+
+访问`http://localhost:8080`,å�Œæ ·ä¹Ÿèƒ½èŽ·å¾—ç»“æžœ.
+
+#### 2.2`java org.springframework.boot.loader.JarLauncher`方��动
+
+è¿™ç§�å�¯åŠ¨æ–¹å¼�å°±é”幻了:好好的一个 jar,è¦�先解压,然å�Žç›´æŽ¥è¿�行里é�¢çš„类,æ“�作如下:
+
+```
+target $ unzip -d ./tmp springboot-jar-1.0.0.jar
+Archive: springboot-jar-1.0.0.jar
+ creating: ./tmp/META-INF/
+ inflating: ./tmp/META-INF/MANIFEST.MF
+ creating: ./tmp/org/
+ creating: ./tmp/org/springframework/
+ creating: ./tmp/org/springframework/boot/
+··· �略其他内容
+target $ cd tmp/
+tmp $ java org.springframework.boot.loader.JarLauncher
+
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 21:56:00.472 INFO 85431 --- [ main] com.gitee.funcy.maven.jar.Main : Starting Main on funcydeMacBook-Pro.local with PID 85431 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-jar/target/tmp/BOOT-INF/classes started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-jar/target/tmp)
+2020-01-07 21:56:00.475 INFO 85431 --- [ main] com.gitee.funcy.maven.jar.Main : No active profile set, falling back to default profiles: default
+2020-01-07 21:56:01.589 INFO 85431 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 21:56:01.619 INFO 85431 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 21:56:01.619 INFO 85431 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 21:56:01.634 INFO 85431 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 21:56:01.722 INFO 85431 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 21:56:01.722 INFO 85431 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1203 ms
+2020-01-07 21:56:01.931 INFO 85431 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 21:56:02.154 INFO 85431 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 21:56:02.157 INFO 85431 --- [ main] com.gitee.funcy.maven.jar.Main : Started Main in 2.025 seconds (JVM running for 2.472)
+
+```
+
+总结下,æ¥éª¤å¦‚下:
+
+1. 进入项目`target/`目录
+2. 解压`jar包`到`tmp`目录:`unzip -d ./tmp springboot-jar-1.0.0.jar`
+3. 进入`tmp目录`:`cd tmp/`
+4. �行:`java org.springframework.boot.loader.JarLauncher`
+
+访问`http://localhost:8080`,也能得到æ£ç¡®ç»“果。
+
+> 注:这ç§�神奇的å�¯åŠ¨æ–¹å¼�在什么情况下会使用呢?我曾ç»�è§�过一些项目组,为了安全会把生产的é…�置文件放在æœ�务器上,在部署项目的时候,先解压 jar 包,然å�Žæ›¿æ�¢ç›¸åº”çš„é…�置文件,å†�è¿�行。这ç§�解压 jar 包ã€�替æ�¢é…�置文件的方å¼�å°±å�¯ä»¥ç”¨æ¤å�¯åŠ¨æ–¹å¼�了。当然,这些解压ã€�替æ�¢ã€�å�¯åŠ¨ç‰æ“�作都会写进 shell 脚本里,自动化è¿�行。
+
+### 3\. war 包�动
+
+#### 3.1`java -jar`方��动
+
+项目都打�`war包`了,还能使用`java -jar`�动?是的,`springboot`就是这么方便:
+
+```
+target $ java -jar springboot-war-1.0.0.war
+
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 22:11:54.284 INFO 85638 --- [ main] com.gitee.funcy.maven.war.Main : Starting Main on funcydeMacBook-Pro.local with PID 85638 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-war/target/springboot-war-1.0.0.war started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-war/target)
+2020-01-07 22:11:54.287 INFO 85638 --- [ main] com.gitee.funcy.maven.war.Main : No active profile set, falling back to default profiles: default
+2020-01-07 22:11:55.257 INFO 85638 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 22:11:55.286 INFO 85638 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 22:11:55.287 INFO 85638 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 22:11:55.299 INFO 85638 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 22:11:55.711 INFO 85638 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 22:11:55.711 INFO 85638 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1379 ms
+2020-01-07 22:11:55.873 INFO 85638 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 22:11:56.031 INFO 85638 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 22:11:56.034 INFO 85638 --- [ main] com.gitee.funcy.maven.war.Main : Started Main in 2.066 seconds (JVM running for 2.469)
+2020-01-07 22:12:01.189 INFO 85638 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
+2020-01-07 22:12:01.190 INFO 85638 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2020-01-07 22:12:01.195 INFO 85638 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
+
+```
+
+看,项目真的跑起�了�
+
+#### 3.2`java org.springframework.boot.loader.WarLauncher`方��动
+
+`springboot`çš„`jar包`å�¯ä»¥è§£åŽ‹ï¼Œç„¶å�Žè¿�行æŸ�个类æ�¥å�¯åŠ¨ï¼Œ`war包`竟然也有这ç§�方法ï¼�`jar包`çš„å�¯åŠ¨ç±»æ˜¯`org.springframework.boot.loader.JarLauncher`,相应的`war包`å�¯åŠ¨ç±»æ˜¯`org.springframework.boot.loader.WarLauncher`,æ¥éª¤å¦‚下:
+
+1. 进入项目`target/`目录
+2. 解压`war包`到`tmp`目录:`unzip -d ./tmp springboot-war-1.0.0.war`
+3. 进入`tmp目录`:`cd tmp/`
+4. �行:`java org.springframework.boot.loader.WarLauncher`
+
+过程如下:
+
+```
+target $ unzip -d ./tmp springboot-war-1.0.0.war
+Archive: springboot-war-1.0.0.war
+ creating: ./tmp/META-INF/
+ inflating: ./tmp/META-INF/MANIFEST.MF
+ creating: ./tmp/org/
+ creating: ./tmp/org/springframework/
+ creating: ./tmp/org/springframework/boot/
+··· �略其他
+target $ cd tmp/
+tmp $ java org.springframework.boot.loader.WarLauncher
+
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 22:17:09.637 INFO 85782 --- [ main] com.gitee.funcy.maven.war.Main : Starting Main on funcydeMacBook-Pro.local with PID 85782 (/Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-war/target/tmp/WEB-INF/classes started by funcy in /Users/funcy/IdeaProjects/myproject/springboot-demo/springboot-maven/springboot-war/target/tmp)
+2020-01-07 22:17:09.640 INFO 85782 --- [ main] com.gitee.funcy.maven.war.Main : No active profile set, falling back to default profiles: default
+2020-01-07 22:17:10.576 INFO 85782 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
+2020-01-07 22:17:10.603 INFO 85782 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
+2020-01-07 22:17:10.604 INFO 85782 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/9.0.13
+2020-01-07 22:17:10.616 INFO 85782 --- [ main] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/funcy/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
+2020-01-07 22:17:10.725 INFO 85782 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
+2020-01-07 22:17:10.725 INFO 85782 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1046 ms
+2020-01-07 22:17:10.942 INFO 85782 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 22:17:11.137 INFO 85782 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
+2020-01-07 22:17:11.140 INFO 85782 --- [ main] com.gitee.funcy.maven.war.Main : Started Main in 1.817 seconds (JVM running for 2.183)
+2020-01-07 22:17:15.024 INFO 85782 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
+2020-01-07 22:17:15.024 INFO 85782 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2020-01-07 22:17:15.029 INFO 85782 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 5 ms
+
+```
+
+�以看到,项目也�动�功了�
+
+#### 3.3 ä¼ ç»Ÿæ–¹å¼�å�¯åŠ¨ï¼šä½¿ç”¨ tomcat 容器
+
+最åˆ�çš„`war包`就是放在 tomcat ç‰å®¹å™¨ä¸è¿�行的,我们也æ�¥è¯•试`war包`在 tomcat 容器ä¸è¿�行情况如何。这里说的 tomcat 容器是指在[tomcat 官网](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Ftomcat.apache.org%2F "tomcat官网")下载的容器,é�ž`springboot`内置容器。这里我下载的是`apache-tomcat-8.5.47`,过程如下:
+
+```
+... �略tomcat日志输出
+ . ____ _ __ _ _
+ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
+( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
+ \\/ ___)| |_)| | | | | || (_| | ) ) ) )
+ ' |____| .__|_| |_|_| |_\__, | / / / /
+ =========|_|==============|___/=/_/_/_/
+ :: Spring Boot :: (v2.1.1.RELEASE)
+
+2020-01-07 22:28:23.519 INFO 85904 --- [ost-startStop-1] c.g.funcy.maven.war.StartApplication : Starting StartApplication on funcydeMacBook-Pro.local with PID 85904 (/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/springboot-war-1.0.0/WEB-INF/classes started by funcy in /Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47)
+2020-01-07 22:28:23.523 INFO 85904 --- [ost-startStop-1] c.g.funcy.maven.war.StartApplication : No active profile set, falling back to default profiles: default
+2020-01-07 22:28:24.256 INFO 85904 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 676 ms
+2020-01-07 22:28:24.655 INFO 85904 --- [ost-startStop-1] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
+2020-01-07 22:28:24.920 INFO 85904 --- [ost-startStop-1] c.g.funcy.maven.war.StartApplication : Started StartApplication in 1.86 seconds (JVM running for 3.98)
+07-Jan-2020 22:28:24.974 ä¿¡æ�¯ [localhost-startStop-1] org.apache.jasper.servlet.TldScanner.scanJars 至少有一个JAR被扫æ��用于TLD但尚未包å�«TLD。 为æ¤è®°å½•器å�¯ç”¨è°ƒè¯•日志记录,以获å�–已扫æ��ä½†æœªåœ¨å…¶ä¸æ‰¾åˆ°TLD的完整JAR列表。 在扫æ��期间跳过ä¸�需è¦�çš„JARå�¯ä»¥ç¼©çŸå�¯åŠ¨æ—¶é—´å’ŒJSP编译时间。
+07-Jan-2020 22:28:24.999 信� [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/springboot-war-1.0.0.war] has finished in [3,468] ms
+07-Jan-2020 22:28:25.000 信� [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程�部署到目录 [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/docs]
+07-Jan-2020 22:28:25.010 信� [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/docs] has finished in [10] ms
+07-Jan-2020 22:28:25.010 信� [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程�部署到目录 [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/manager]
+07-Jan-2020 22:28:25.027 信� [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/manager] has finished in [17] ms
+07-Jan-2020 22:28:25.027 信� [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程�部署到目录 [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/examples]
+07-Jan-2020 22:28:25.181 信� [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/examples] has finished in [154] ms
+07-Jan-2020 22:28:25.181 信� [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程�部署到目录 [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/ROOT]
+07-Jan-2020 22:28:25.191 信� [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/ROOT] has finished in [10] ms
+07-Jan-2020 22:28:25.191 信� [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory 把web 应用程�部署到目录 [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/host-manager]
+07-Jan-2020 22:28:25.202 信� [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/Users/funcy/Applications/Tomcat/apache-tomcat-8.5.47/webapps/host-manager] has finished in [11] ms
+07-Jan-2020 22:28:25.206 信� [main] org.apache.coyote.AbstractProtocol.start 开始�议处��柄["http-nio-8080"]
+07-Jan-2020 22:28:25.212 信� [main] org.apache.coyote.AbstractProtocol.start 开始�议处��柄["ajp-nio-8009"]
+07-Jan-2020 22:28:25.213 信� [main] org.apache.catalina.startup.Catalina.start Server startup in 3717 ms
+2020-01-07 22:29:30.754 INFO 85904 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
+2020-01-07 22:29:30.767 INFO 85904 --- [nio-8080-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 12 ms
+
+```
+
+请求`http://localhost:8080/springboot-war-1.0.0/`,结果如下:
+
+```
+$ curl 'http://localhost:8080/springboot-war-1.0.0/'
+hello world
+
+```
+
+�以看到,已�部署�功了。
+
+### 4\. 总结
+
+| | main () 方法 | mvn 命令 | java -jar | java xxx.WarLauncher | java xxx.JarLauncher | 外置容器 |
+| --- | --- | --- | --- | --- | --- | --- |
+| war | 支� | 支� | 支� | 支� | �支� | 支� |
+| jar | 支� | 支� | 支� | �支� | 支� | �支�
+
+### 1\. maven 打包�的文件
+
+进入`springboot-jar/target`目录,使用`tree`命令,目录结构如下:
+
+```
+ $ tree
+.
+├── classes
+│ └── com
+│ └── gitee
+│ └── funcy
+│ └── maven
+│ └── jar
+│ ├── Main.class
+│ └── controller
+│ └── IndexController.class
+├── generated-sources
+│ └── annotations
+├── maven-archiver
+│ └── pom.properties
+├── maven-status
+│ └── maven-compiler-plugin
+│ └── compile
+│ └── default-compile
+│ ├── createdFiles.lst
+│ └── inputFiles.lst
+├── springboot-jar-1.0.0.jar
+└── springboot-jar-1.0.0.jar.original
+
+14 directories, 7 files
+
+```
+
+注æ„�`springboot-jar-1.0.0.jar`与`springboot-jar-1.0.0.jar.original`的区别:`springboot-jar-1.0.0.jar.original`属于原始 Maven 打包 jar 文件,该文件仅包å�«åº”用本地资æº�,如编译å�Žçš„ classes 目录下的资æº�文件ç‰ï¼Œæœªå¼•入第三方ä¾�赖资æº�;而`springboot-jar-1.0.0.jar`引入了第三方ä¾�赖资æº�(主è¦�为 jar 包)。
+
+使用`unzip springboot-jar-1.0.0.jar -d tmp`解压 jar 包,内容如下:
+
+```
+ $ tree tmp/
+tmp/
+├── BOOT-INF
+│ ├── classes
+│ │ └── com
+│ │ └── gitee
+│ │ └── funcy
+│ │ └── maven
+│ │ └── jar
+│ │ ├── Main.class
+│ │ └── controller
+│ │ └── IndexController.class
+│ └── lib
+│ ├── classmate-1.4.0.jar
+│ ├── hibernate-validator-6.0.13.Final.jar
+│ ├── jackson-annotations-2.9.0.jar
+│ ├── jackson-core-2.9.7.jar
+│ ├── jackson-databind-2.9.7.jar
+│ ├── jackson-datatype-jdk8-2.9.7.jar
+│ ├── jackson-datatype-jsr310-2.9.7.jar
+│ ├── jackson-module-parameter-names-2.9.7.jar
+│ ├── javax.annotation-api-1.3.2.jar
+│ ├── jboss-logging-3.3.2.Final.jar
+│ ├── jul-to-slf4j-1.7.25.jar
+│ ├── log4j-api-2.11.1.jar
+│ ├── log4j-to-slf4j-2.11.1.jar
+│ ├── logback-classic-1.2.3.jar
+│ ├── logback-core-1.2.3.jar
+│ ├── slf4j-api-1.7.25.jar
+│ ├── snakeyaml-1.23.jar
+│ ├── spring-aop-5.1.3.RELEASE.jar
+│ ├── spring-beans-5.1.3.RELEASE.jar
+│ ├── spring-boot-2.1.1.RELEASE.jar
+│ ├── spring-boot-autoconfigure-2.1.1.RELEASE.jar
+│ ├── spring-boot-starter-2.1.1.RELEASE.jar
+│ ├── spring-boot-starter-json-2.1.1.RELEASE.jar
+│ ├── spring-boot-starter-logging-2.1.1.RELEASE.jar
+│ ├── spring-boot-starter-tomcat-2.1.1.RELEASE.jar
+│ ├── spring-boot-starter-web-2.1.1.RELEASE.jar
+│ ├── spring-context-5.1.3.RELEASE.jar
+│ ├── spring-core-5.1.3.RELEASE.jar
+│ ├── spring-expression-5.1.3.RELEASE.jar
+│ ├── spring-jcl-5.1.3.RELEASE.jar
+│ ├── spring-web-5.1.3.RELEASE.jar
+│ ├── spring-webmvc-5.1.3.RELEASE.jar
+│ ├── tomcat-embed-core-9.0.13.jar
+│ ├── tomcat-embed-el-9.0.13.jar
+│ ├── tomcat-embed-websocket-9.0.13.jar
+│ └── validation-api-2.0.1.Final.jar
+├── META-INF
+│ ├── MANIFEST.MF
+│ └── maven
+│ └── com.gitee.funcy
+│ └── springboot-jar
+│ ├── pom.properties
+│ └── pom.xml
+└── org
+ └── springframework
+ └── boot
+ └── loader
+ ├── ExecutableArchiveLauncher.class
+ ├── JarLauncher.class
+ ├── LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
+ ├── LaunchedURLClassLoader.class
+ ├── Launcher.class
+ ├── MainMethodRunner.class
+ ├── PropertiesLauncher$1.class
+ ├── PropertiesLauncher$ArchiveEntryFilter.class
+ ├── PropertiesLauncher$PrefixMatchingArchiveFilter.class
+ ├── PropertiesLauncher.class
+ ├── WarLauncher.class
+ ├── archive
+ │ ├── Archive$Entry.class
+ │ ├── Archive$EntryFilter.class
+ │ ├── Archive.class
+ │ ├── ExplodedArchive$1.class
+ │ ├── ExplodedArchive$FileEntry.class
+ │ ├── ExplodedArchive$FileEntryIterator$EntryComparator.class
+ │ ├── ExplodedArchive$FileEntryIterator.class
+ │ ├── ExplodedArchive.class
+ │ ├── JarFileArchive$EntryIterator.class
+ │ ├── JarFileArchive$JarFileEntry.class
+ │ └── JarFileArchive.class
+ ├── data
+ │ ├── RandomAccessData.class
+ │ ├── RandomAccessDataFile$1.class
+ │ ├── RandomAccessDataFile$DataInputStream.class
+ │ ├── RandomAccessDataFile$FileAccess.class
+ │ └── RandomAccessDataFile.class
+ ├── jar
+ │ ├── AsciiBytes.class
+ │ ├── Bytes.class
+ │ ├── CentralDirectoryEndRecord.class
+ │ ├── CentralDirectoryFileHeader.class
+ │ ├── CentralDirectoryParser.class
+ │ ├── CentralDirectoryVisitor.class
+ │ ├── FileHeader.class
+ │ ├── Handler.class
+ │ ├── JarEntry.class
+ │ ├── JarEntryFilter.class
+ │ ├── JarFile$1.class
+ │ ├── JarFile$2.class
+ │ ├── JarFile$JarFileType.class
+ │ ├── JarFile.class
+ │ ├── JarFileEntries$1.class
+ │ ├── JarFileEntries$EntryIterator.class
+ │ ├── JarFileEntries.class
+ │ ├── JarURLConnection$1.class
+ │ ├── JarURLConnection$JarEntryName.class
+ │ ├── JarURLConnection.class
+ │ ├── StringSequence.class
+ │ └── ZipInflaterInputStream.class
+ └── util
+ └── SystemPropertyUtils.class
+
+21 directories, 91 files
+
+```
+
+å�¯ä»¥çœ‹åˆ°ï¼Œæ–‡ä»¶ä¸ä¸»è¦�åˆ†ä¸ºå¦‚ä¸‹å‡ ä¸ªç›®å½•ï¼š
+
+* `BOOT-INF/classes`ç›®å½•å˜æ”¾åº”用编译å�Žçš„ class 文件;
+* `BOOT-INF/lib`ç›®å½•å˜æ”¾åº”用ä¾�èµ–çš„ jar 包;
+* `META-INF/`ç›®å½•å˜æ”¾åº”用ä¾�èµ–çš„ jar 包;
+* `org/`ç›®å½•å˜æ”¾ spring boot 相关的 class 文件。
+
+### 2.`java -jar`�动 springboot jar 包
+
+java 官方规定,`java -jar`命令引导的具体å�¯åŠ¨ç±»å¿…é¡»é…�置在`MANIFEST.MF`文件ä¸ï¼Œè€Œæ ¹æ�®`jar文件规范`,`MANIFEST.MF`æ–‡ä»¶å¿…é¡»å˜æ”¾åœ¨`/META-INF/`ç›®å½•ä¸‹ã€‚å› æ¤ï¼Œå�¯åŠ¨ç±»é…�置在 jar 包的`/META-INF/MANIFEST.MF`文件ä¸ï¼ŒæŸ¥çœ‹è¯¥æ–‡ä»¶ï¼Œå†…容如下:
+
+```
+$ cat MANIFEST.MF
+Manifest-Version: 1.0
+Archiver-Version: Plexus Archiver
+Built-By: fangchengyan
+Start-Class: com.gitee.funcy.maven.jar.Main
+Spring-Boot-Classes: BOOT-INF/classes/
+Spring-Boot-Lib: BOOT-INF/lib/
+Spring-Boot-Version: 2.1.1.RELEASE
+Created-By: Apache Maven 3.6.0
+Build-Jdk: 1.8.0_222
+Main-Class: org.springframework.boot.loader.JarLauncher
+
+```
+
+å�‘现`Main-Class`属性指å�‘çš„`Class`为`org.springframework.boot.loader.JarLauncher`ï¼Œè€Œè¯¥ç±»å˜æ”¾åœ¨ jar 包的`org/springframework/boot/loader/`目录下,并且项目的引导类定义在`Start-Class`属性性ä¸ï¼Œè¯¥å±žæ€§å¹¶é�ž java å¹³å�°æ ‡å‡†`META-INF/MANIFEST.MF`属性。
+
+> 注:
+>
+> 1. `org.springframework.boot.loader.JarLauncher`是�执行 jar 的�动器,`org.springframework.boot.loader.WarLauncher`是�执行 war 的�动器。
+>
+>
+> 2. `org.springframework.boot.loader.JarLauncher`所在的 jar 文件的 Maven GAV 信�为`org.springframework.boot:spring-boot-loader:${springboot-version}`,通常情况下,这个�赖没有必�引入 springboot 项目的 pom.xml 文件。
+
+查看`JarLauncher`æº�ç �,如下:
+
+```
+public class JarLauncher extends ExecutableArchiveLauncher {
+
+ static final String BOOT_INF_CLASSES = "BOOT-INF/classes/";
+
+ static final String BOOT_INF_LIB = "BOOT-INF/lib/";
+
+ public JarLauncher() {
+ }
+
+ protected JarLauncher(Archive archive) {
+ super(archive);
+ }
+
+ @Override
+ protected boolean isNestedArchive(Archive.Entry entry) {
+ if (entry.isDirectory()) {
+ return entry.getName().equals(BOOT_INF_CLASSES);
+ }
+ return entry.getName().startsWith(BOOT_INF_LIB);
+ }
+
+ public static void main(String[] args) throws Exception {
+ new JarLauncher().launch(args);
+ }
+
+}
+
+```
+
+å�¯ä»¥å�‘现,`BOOT-INF/classes/`与`BOOT-INF/lib/`分别使用常é‡�`BOOT_INF_CLASSES`å’Œ`BOOT_INF_LIB`表示,并且用于`isNestedArchive(Archive.Entry)`方法判æ–,从该方法的实现分æž�,方法å�‚æ•°`Archive.Entry`看似为 jar 文件ä¸çš„资æº�,比如`application.properties`。
+
+`Archive.Entry`有两ç§�实现,其ä¸ä¸€ç§�为`org.springframework.boot.loader.archive.JarFileArchive.JarFileEntry`,基于`java.util.jar.JarEntry`,表示`FAT JAR`嵌入资æº�,å�¦ä¸€ç§�为`org.springframework.boot.loader.archive.ExplodedArchive.FileEntry`,基于文件系统实现。这也说明了`JarLauncher`支æŒ�`JAR`å’Œ`文件系统`两ç§�å�¯åŠ¨æ–¹å¼�。
+
+> 文件系统�动方�如下:
+>
+> 1. 解压 jar 包到`temp`目录:`unzip springboot-jar-1.0.0.jar -d tmp`
+> 2. 进入`temp`目录,è¿�行命令:`java org.springframework.boot.loader.JarLauncher`å�¯ä»¥çœ‹åˆ°ï¼Œé¡¹ç›®å�Œæ ·èƒ½æ£å¸¸å�¯åŠ¨ã€‚
+
+在`JarLauncher`作为引导类时,当执行`java -jar`命令时,`/META-INF`资�的`Main-Class`属性将调用其`main(String[])`方法,实际上调用的是`JarLauncher#launch(args)`方法,而该方法继承于基类`org.springframework.boot.loader.Launcher`,它们之间的继承关系如下:
+
+* `org.springframework.boot.loader.Launcher`
+ * `org.springframework.boot.loader.ExecutableArchiveLauncher`
+ * `org.springframework.boot.loader.JarLauncher`
+ * `org.springframework.boot.loader.WarLauncher`
+
+简��说,springboot jar �动过程如下:
+
+1. `java -jar xxx.jar`�行的是`JarLauncher`
+2. `JarLauncher#main(String[])`方法会调用`Launcher#launch(String[])`方法,创建 ClassLoader () �调用项目的`main`方法
+ * 项目主类的获�实现�于`ExecutableArchiveLauncher#getMainClass()`,主�是从`/META-INF/MANIFEST.MF`获�`Start-Class`属性
+ * 项目主类的 main () 方法调用�于`MainMethodRunner#run()`,使用�射方�进行调用
+
+### 3.`java -jar`�动 springboot war 包
+
+从上�的分�,我们得到了�动 jar 包的`org.springframework.boot.loader.JarLauncher`以��动 war 包的`org.springframework.boot.loader.WarLauncher`,这里我们�分�下`WarLauncher`上如何工作的。
+
+`WarLauncher`代ç �如下:
+
+```
+public class WarLauncher extends ExecutableArchiveLauncher {
+
+ private static final String WEB_INF = "WEB-INF/";
+
+ private static final String WEB_INF_CLASSES = WEB_INF + "classes/";
+
+ private static final String WEB_INF_LIB = WEB_INF + "lib/";
+
+ private static final String WEB_INF_LIB_PROVIDED = WEB_INF + "lib-provided/";
+
+ public WarLauncher() {
+ }
+
+ protected WarLauncher(Archive archive) {
+ super(archive);
+ }
+
+ @Override
+ public boolean isNestedArchive(Archive.Entry entry) {
+ if (entry.isDirectory()) {
+ return entry.getName().equals(WEB_INF_CLASSES);
+ }
+ else {
+ return entry.getName().startsWith(WEB_INF_LIB)
+ || entry.getName().startsWith(WEB_INF_LIB_PROVIDED);
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ new WarLauncher().launch(args);
+ }
+
+}
+
+```
+
+å�¯ä»¥çœ‹åˆ°ï¼Œ`WEB-INF/classes/`ã€�`WEB-INF/lib/`ã€�`WEB-INF/lib-provided/`å�‡ä¸º`WarLauncher`çš„`Class Path`,其ä¸`WEB-INF/classes/`ã€�`WEB-INF/lib/`æ˜¯ä¼ ç»Ÿçš„ Servlet 应用的 ClassPath 路径,而`WEB-INF/lib-provided/`属性 springboot`WarLauncher`定制实现。那么`WEB-INF/lib-provided/`究竟是干嘛的呢?看到`provided`,我们å�¯ä»¥å¤§èƒ†çŒœæƒ³`WEB-INF/lib-provided/`å˜æ”¾çš„æ˜¯`pom.xml`文件ä¸ï¼Œ`scope`为`provided`çš„ jar。
+
+为了验�以上猜想,修改的 pom.xml 文件如下:
+
+```
+
+
+ 4.0.0
+
+ com.gitee.funcy
+ springboot-war
+ 1.0.0
+
+ war
+ springboot�parent war打包方�
+
+
+ UTF-8
+ UTF-8
+ 1.8
+ 2.1.1.RELEASE
+ 3.8.1
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-test
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+
+ 3.2.2
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+
+```
+
+è¿™é‡Œæˆ‘ä»¬æ·»åŠ äº† springboot 的测试 jar`org.springframework.boot:spring-boot-test`,并将其`scope`设置为`provided`. è¿�行 maven 打包命令`mvn clean install -Dmaven.test.skip=true`,å�¯ä»¥çœ‹åˆ°é¡¹ç›®èƒ½æ£å¸¸æ‰“包。
+
+打包完æˆ�å�Žï¼Œè¿›å…¥`target`目录,è¿�行`java -jar springboot-war-1.0.0.war`,项目能æ£å¸¸å�¯åŠ¨ã€‚
+
+接下�,我们�看看`springboot-war-1.0.0.war`有些啥。首先使用`unzip springboot-war-1.0.0.war -d tmp`命令解压,�使用`tree -h`命令查看文件结构,结果如下
+
+```
+ $ tree -h
+.
+├── [ 128] META-INF
+│ ├── [ 311] MANIFEST.MF
+│ └── [ 96] maven
+│ └── [ 96] com.gitee.funcy
+│ └── [ 128] springboot-war
+│ ├── [ 95] pom.properties
+│ └── [3.3K] pom.xml
+├── [ 160] WEB-INF
+│ ├── [ 96] classes
+│ │ └── [ 96] com
+│ │ └── [ 96] gitee
+│ │ └── [ 96] funcy
+│ │ └── [ 96] maven
+│ │ └── [ 160] war
+│ │ ├── [ 688] Main.class
+│ │ ├── [ 891] StartApplication.class
+│ │ └── [ 96] controller
+│ │ └── [ 646] IndexController.class
+│ ├── [1.2K] lib
+│ │ ├── [ 65K] classmate-1.4.0.jar
+│ │ ├── [1.1M] hibernate-validator-6.0.13.Final.jar
+│ │ ├── [ 65K] jackson-annotations-2.9.0.jar
+│ │ ├── [316K] jackson-core-2.9.7.jar
+│ │ ├── [1.3M] jackson-databind-2.9.7.jar
+│ │ ├── [ 33K] jackson-datatype-jdk8-2.9.7.jar
+│ │ ├── [ 98K] jackson-datatype-jsr310-2.9.7.jar
+│ │ ├── [8.4K] jackson-module-parameter-names-2.9.7.jar
+│ │ ├── [ 26K] javax.annotation-api-1.3.2.jar
+│ │ ├── [ 65K] jboss-logging-3.3.2.Final.jar
+│ │ ├── [4.5K] jul-to-slf4j-1.7.25.jar
+│ │ ├── [258K] log4j-api-2.11.1.jar
+│ │ ├── [ 17K] log4j-to-slf4j-2.11.1.jar
+│ │ ├── [284K] logback-classic-1.2.3.jar
+│ │ ├── [461K] logback-core-1.2.3.jar
+│ │ ├── [ 40K] slf4j-api-1.7.25.jar
+│ │ ├── [294K] snakeyaml-1.23.jar
+│ │ ├── [360K] spring-aop-5.1.3.RELEASE.jar
+│ │ ├── [656K] spring-beans-5.1.3.RELEASE.jar
+│ │ ├── [935K] spring-boot-2.1.1.RELEASE.jar
+│ │ ├── [1.2M] spring-boot-autoconfigure-2.1.1.RELEASE.jar
+│ │ ├── [ 413] spring-boot-starter-2.1.1.RELEASE.jar
+│ │ ├── [ 421] spring-boot-starter-json-2.1.1.RELEASE.jar
+│ │ ├── [ 423] spring-boot-starter-logging-2.1.1.RELEASE.jar
+│ │ ├── [ 422] spring-boot-starter-tomcat-2.1.1.RELEASE.jar
+│ │ ├── [ 421] spring-boot-starter-web-2.1.1.RELEASE.jar
+│ │ ├── [1.0M] spring-context-5.1.3.RELEASE.jar
+│ │ ├── [1.2M] spring-core-5.1.3.RELEASE.jar
+│ │ ├── [274K] spring-expression-5.1.3.RELEASE.jar
+│ │ ├── [ 23K] spring-jcl-5.1.3.RELEASE.jar
+│ │ ├── [1.3M] spring-web-5.1.3.RELEASE.jar
+│ │ ├── [782K] spring-webmvc-5.1.3.RELEASE.jar
+│ │ ├── [3.1M] tomcat-embed-core-9.0.13.jar
+│ │ ├── [244K] tomcat-embed-el-9.0.13.jar
+│ │ ├── [257K] tomcat-embed-websocket-9.0.13.jar
+│ │ └── [ 91K] validation-api-2.0.1.Final.jar
+│ └── [ 96] lib-provided
+│ └── [194K] spring-boot-test-2.1.1.RELEASE.jar
+└── [ 96] org
+ └── [ 96] springframework
+ └── [ 96] boot
+ └── [ 544] loader
+ ├── [3.5K] ExecutableArchiveLauncher.class
+ ├── [1.5K] JarLauncher.class
+ ├── [1.5K] LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
+ ├── [5.6K] LaunchedURLClassLoader.class
+ ├── [4.6K] Launcher.class
+ ├── [1.5K] MainMethodRunner.class
+ ├── [ 266] PropertiesLauncher$1.class
+ ├── [1.4K] PropertiesLauncher$ArchiveEntryFilter.class
+ ├── [1.9K] PropertiesLauncher$PrefixMatchingArchiveFilter.class
+ ├── [ 19K] PropertiesLauncher.class
+ ├── [1.7K] WarLauncher.class
+ ├── [ 416] archive
+ │ ├── [ 302] Archive$Entry.class
+ │ ├── [ 437] Archive$EntryFilter.class
+ │ ├── [ 945] Archive.class
+ │ ├── [ 273] ExplodedArchive$1.class
+ │ ├── [1.1K] ExplodedArchive$FileEntry.class
+ │ ├── [1.5K] ExplodedArchive$FileEntryIterator$EntryComparator.class
+ │ ├── [3.7K] ExplodedArchive$FileEntryIterator.class
+ │ ├── [5.1K] ExplodedArchive.class
+ │ ├── [1.7K] JarFileArchive$EntryIterator.class
+ │ ├── [1.1K] JarFileArchive$JarFileEntry.class
+ │ └── [7.2K] JarFileArchive.class
+ ├── [ 224] data
+ │ ├── [ 485] RandomAccessData.class
+ │ ├── [ 282] RandomAccessDataFile$1.class
+ │ ├── [2.6K] RandomAccessDataFile$DataInputStream.class
+ │ ├── [3.2K] RandomAccessDataFile$FileAccess.class
+ │ └── [3.9K] RandomAccessDataFile.class
+ ├── [ 768] jar
+ │ ├── [4.9K] AsciiBytes.class
+ │ ├── [ 616] Bytes.class
+ │ ├── [3.0K] CentralDirectoryEndRecord.class
+ │ ├── [5.1K] CentralDirectoryFileHeader.class
+ │ ├── [4.5K] CentralDirectoryParser.class
+ │ ├── [ 540] CentralDirectoryVisitor.class
+ │ ├── [ 345] FileHeader.class
+ │ ├── [ 12K] Handler.class
+ │ ├── [3.5K] JarEntry.class
+ │ ├── [ 299] JarEntryFilter.class
+ │ ├── [2.0K] JarFile$1.class
+ │ ├── [1.2K] JarFile$2.class
+ │ ├── [1.3K] JarFile$JarFileType.class
+ │ ├── [ 15K] JarFile.class
+ │ ├── [1.6K] JarFileEntries$1.class
+ │ ├── [2.0K] JarFileEntries$EntryIterator.class
+ │ ├── [ 14K] JarFileEntries.class
+ │ ├── [ 702] JarURLConnection$1.class
+ │ ├── [4.2K] JarURLConnection$JarEntryName.class
+ │ ├── [9.6K] JarURLConnection.class
+ │ ├── [3.5K] StringSequence.class
+ │ └── [1.8K] ZipInflaterInputStream.class
+ └── [ 96] util
+ └── [5.1K] SystemPropertyUtils.class
+
+22 directories, 93 files
+
+```
+
+相比于`FAT JAR`的解压目录,`War`å¢žåŠ äº†`WEB-INF/lib-provided`,并且该目录仅有一个 jar 文件,å�³`spring-boot-test-2.1.1.RELEASE.jar`ï¼Œè¿™æ£æ˜¯æˆ‘们在 pom.xml 文件ä¸è®¾ç½®çš„`scope`为`provided`çš„ jar 包。
+
+ç”±æ¤å�¯ä»¥å¾—出结论:**`WEB-INF/lib-provided`å˜æ”¾çš„æ˜¯`scope`为`provided`çš„ jar 包**。
+
+我们现�看下`META-INF/MANIFEST.MF`的内容:
+
+```
+$ cat META-INF/MANIFEST.MF
+Manifest-Version: 1.0
+Built-By: fangchengyan
+Start-Class: com.gitee.funcy.maven.war.Main
+Spring-Boot-Classes: WEB-INF/classes/
+Spring-Boot-Lib: WEB-INF/lib/
+Spring-Boot-Version: 2.1.1.RELEASE
+Created-By: Apache Maven 3.6.0
+Build-Jdk: 1.8.0_222
+Main-Class: org.springframework.boot.loader.WarLauncher
+
+```
+
+å�¯ä»¥çœ‹åˆ°ï¼Œè¯¥æ–‡ä»¶ä¸Ž jar 包ä¸çš„`META-INF/MANIFEST.MF`很相似,在文件ä¸å�Œæ ·å®šä¹‰äº†`Main-Class`与`Start-Class`,这也说明了该 war å�¯ä»¥ä½¿ç”¨`java -jar xxx.jar`å’Œ`java org.springframework.boot.loader.WarLauncher`å�¯åŠ¨ï¼Œè¿™ä¹Ÿä¸Žæˆ‘ä»¬çš„éªŒè¯�结果一致。
+
+### 4\. tomcat ç‰å¤–部容器å�¯åЍ war 包
+
+在 springboo åˆšå¼€å§‹æŽ¨å¹¿çš„æ—¶å€™ï¼Œæˆ‘ä»¬è¿˜æ˜¯ä¹ æƒ¯äºŽå°†é¡¹ç›®æ‰“æˆ� war 包,然å�Žéƒ¨ç½²åˆ° tomcat ç‰ web 容器ä¸è¿�行。那 springboot çš„ war 包是如何å�šåˆ°æ—¢èƒ½ç”¨ java 命令å�¯åŠ¨ï¼Œå�ˆèƒ½æ”¾åœ¨ tomcat 容器ä¸å�¯åŠ¨å‘¢ï¼Ÿè¿™å°±æ˜¯ä¹‹å‰�æ��到的`WEB-INF/lib-provided`目录的功能了。
+
+ä¼ ç»Ÿçš„`servlet`应用的`class path`路径仅关注`WEB-INF/classes/`å’Œ`WEB-INF/lib/`,`WEB-INF/lib-provided/`目录下的 jar 包将被`servlet`容器忽略,如`servlet api`,该 api ç”±`servlet`容器æ��供。我们在打包时,å�¯ä»¥æŠŠ`servlet`相关 jar 包的`scope`设置æˆ�`provided`ï¼Œè¿™æ ·å°±å®Œç¾Žå®žçŽ°äº†`servlet`容器å�¯åŠ¨ä¸Ž`java`命令å�¯åŠ¨çš„å…¼å®¹ï¼š
+
+* 当部署到`servlet`容噍䏿—¶ï¼Œ`WEB-INF/lib-provided/`目录下的 jar 包就被容器忽略了(由于`servlet`容器本身就æ��供了`servlet`的相关 jar 包,如果ä¸�忽略,就会出现 jar 包é‡�å¤�引入问题);
+* 当使用`java`å‘½ä»¤æ‰§è¡Œæ—¶ï¼Œæ¤æ—¶æ— `servlet`容器æ��ä¾›`servlet`的相关 jar 包,而`WarLauncher`在è¿�行过程ä¸ä¼šåŠ è½½`WEB-INF/lib-provided/`目录下的 jar 包。
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/@SpringBootApplication \346\263\250\350\247\243.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/@SpringBootApplication \346\263\250\350\247\243.md"
new file mode 100644
index 0000000..dd72d1f
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/@SpringBootApplication \346\263\250\350\247\243.md"
@@ -0,0 +1,382 @@
+springboot ÔÚÆô¶¯ÀàÉÏ»á±ê×¢Ò»¸ö×¢½â£º`@SpringBootApplication`£¬±¾È˽«´ÓÔ´Âë½âÎö·ÖÎöÕâ ¸ö×¢½âµÄ×÷Óá£
+
+`@SpringBootApplication` ´úÂëÈçÏ£º
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@SpringBootConfiguration
+@EnableAutoConfiguration
+@ComponentScan(excludeFilters = {
+ @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
+ @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
+public @interface SpringBootApplication {
+
+ /**
+ * ×Ô¶¯×°ÅäÒªÅųýµÄÀ࣬¹¦ÄÜÀ´×ÔÓÚ @EnableAutoConfiguration
+ */
+ @AliasFor(annotation = EnableAutoConfiguration.class)
+ Class>[] exclude() default {};
+
+ /**
+ * ×Ô¶¯×°ÅäÒªÅųýµÄÀàÃû£¬¹¦ÄÜÀ´×ÔÓÚ @EnableAutoConfiguration
+ */
+ @AliasFor(annotation = EnableAutoConfiguration.class)
+ String[] excludeName() default {};
+
+ /**
+ * ÅäÖÃɨÃèµÄ°ü£¬¹¦ÄÜÀ´×ÔÓÚ @ComponentScan
+ */
+ @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
+ String[] scanBasePackages() default {};
+
+ /**
+ * ÅäÖÃɨÃèµÄclass£¬¸ÃclassËùÔڵİü¶¼»á±»É¨Ã裬¹¦ÄÜÀ´×ÔÓÚ @ComponentScan
+ */
+ @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
+ Class>[] scanBasePackageClasses() default {};
+
+ /**
+ * ÊÇ·ñÆôÓà @Bean ·½·¨´úÀí£¬¹¦ÄÜÀ´×ÔÓÚ @Configuration
+ */
+ @AliasFor(annotation = Configuration.class)
+ boolean proxyBeanMethods() default true;
+
+}
+
+```
+
+1. `@SpringBootApplication` ÊÇÒ»¸ö×éºÏ×¢½â£¬°üº¬ÁË `@SpringBootConfiguration`¡¢`@EnableAutoConfiguration`¡¢`@ComponentScan` Èý¸ö×¢½âµÄ¹¦ÄÜ£»
+2. `@SpringBootApplication` ÖÐÒ²ÌṩÁËһЩÅäÖÃÊôÐÔ£¬¶øÕâЩÊôÐÔÀ´×ÔÓÚÒÔÉÏÈý¸ö×¢½â¡£
+
+½ÓÏÂÀ´ÎÒÃÇÀ´¿´¿´ÕâÈý¸ö×¢½âµÄ×÷Ó÷ֱðÊÇʲô¡£
+
+### 1. `@SpringBootConfiguration`
+
+½øÈë `@SpringBootConfiguration`£¬´úÂëÈçÏ£º
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Configuration
+public @interface SpringBootConfiguration {
+
+ @AliasFor(annotation = Configuration.class)
+ boolean proxyBeanMethods() default true;
+
+}
+
+```
+
+Õâ¸ö×¢½â±È½Ï¼òµ¥£¬ÉÏÃæ±ê¼ÇÁË `@Configuration`£¬È»ºóÊÇÒ»¸öÊôÐÔ `proxyBeanMethods()`£¬ËüÀ´×ÔÓÚ `@Configuration`¡£Òò´Ë£¬`@SpringBootConfiguration` ²¢Ã»ÓÐ×öʲô£¬½ö½öÖ»Êǽ« `@Configuration` ʹÓÃÁË `@Configuration` µÄ¹¦ÄÜ¡£
+
+¹ØÓÚ `@Configuration`£¬ËüÀ´×ÔÓÚ spring£¬Äܱ» spring ʶ±ðΪ `Component`£¬ÇÒ `proxyBeanMethods != false` ʱ£¬»á±» spring ±ê¼ÇΪ `Full` ÅäÖÃÀ࣬ÔÚºóÐø¶ÔÆäÖÐµÄ `@Bean` ·½·¨´¦Àíʱ£¬»á½øÐÐ cglib ´úÀí£¬¹ØÓÚÕâ·½ÃæµÄÄÚÈÝ£¬¿É²Î¿¼ [ConfigurationClassPostProcessor£¨¶þ£©£º´¦Àí @Bean ×¢½â](https://my.oschina.net/funcy/blog/4492878).
+
+### 2. `@EnableAutoConfiguration`
+
+`@EnableAutoConfiguration` Ö÷Òª ÓÃÀ´¿ªÆô×Ô¶¯×°Å书ÄÜ£¬´úÂëÈçÏ£º
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+// ×Ô¶¯×°ÅäµÄ°ü
+@AutoConfigurationPackage
+// ÒýÈëµÄ×Ô¶¯×°ÅäÀà
+@Import(AutoConfigurationImportSelector.class)
+public @interface EnableAutoConfiguration {
+
+ String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
+
+ /**
+ * ¿É×ÔÐж¨ÒåÅųý×Ô¶¯×°ÅäµÄÀà
+ */
+ Class>[] exclude() default {};
+
+ /**
+ * ¿É×ÔÐж¨ÒåÅųý×Ô¶¯×°ÅäµÄÀàÃû
+ */
+ String[] excludeName() default {};
+
+}
+
+```
+
+´Ó´úÂëÖпÉÒÔ¿´µ½£¬
+
+1. ¸Ã×¢½â×éºÏÁË `@AutoConfigurationPackage` ×¢½âµÄ¹¦ÄÜ£¬¸Ã×¢½âÓÃÀ´Ö¸¶¨×Ô¶¯×°ÅäµÄ°ü£»
+2. ¸Ã×¢½âͨ¹ý `@Import` ×¢½âÒýÈëÁËÒ»¸öÀà `AutoConfigurationImportSelector`£¬Õâ¸öÀàÊÇ×Ô¶¯×°ÅäµÄ¹Ø¼ü£»
+3. ¸Ã×¢½âÌṩÁËÁ½¸öÅäÖã¬ÓÃÀ´ÅųýÖ¸¶¨µÄ×Ô¶¯×°ÅäÀ࣬¿ÉÒÔ¸ù¾ÝÀàÀ´Åųý (`Class` ¶ÔÏó)£¬Ò²¿ÉÒÔ¸ù¾ÝÀàÃû (`°üÃû.ÀàÃû`) Åųý¡£
+
+½ÓÏÂÀ´ÎÒÃÇÀ´¹Ø×¢ `@AutoConfigurationPackage` ¼°ÒýÈëµÄ `AutoConfigurationImportSelector`¡£
+
+#### 2.1 `@AutoConfigurationPackage`
+
+`@AutoConfigurationPackage` Ö¸¶¨ÁË×Ô¶¯×°ÅäµÄ°ü£¬´úÂëÈçÏ£º
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@Import(AutoConfigurationPackages.Registrar.class)
+public @interface AutoConfigurationPackage {
+
+}
+
+```
+
+Õâ¸ö×¢½âµÄÄÚÈݷdz£¼òµ¥£¬½öʹÓà `@Import` ×¢½âÒýÈëÁË `AutoConfigurationPackages.Registrar`£¬ÎÒÃÇÀ´¿´ÏÂËüµÄÄÚÈÝ£º
+
+```
+public abstract class AutoConfigurationPackages {
+
+ private static final String BEAN = AutoConfigurationPackages.class.getName();
+
+ static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
+
+ /**
+ * ¸ù¾Ý ImportBeanDefinitionRegistrar µÄ´¦Àí£¬spring½«µ÷Óà registerBeanDefinitions() ×¢²áÄÚÈÝ
+ */
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata metadata,
+ BeanDefinitionRegistry registry) {
+ register(registry, new PackageImport(metadata).getPackageName());
+ }
+
+ @Override
+ public Set determineImports(AnnotationMetadata metadata) {
+ return Collections.singleton(new PackageImport(metadata));
+ }
+
+ }
+
+ /**
+ * ´¦Àí¾ßÌåµÄ×¢²á²Ù×÷
+ * 1\. Èç¹û beanFacotry Öаüº¬ BEAN£¬Ôò½«´«ÈëµÄ°üÃûÌí¼Óµ½ BEAN ¶ÔÓ¦µÄ BeanDefinition µÄ¹¹Ôì·½·¨²ÎÊýÖµÉÏ£»
+ * 2\. Èç¹û beanFacotry Öв»°üº¬ BEAN£¬Ôò´´½¨ beanDefinition£¬ÉèÖòÎÊýÖµ£¬È»ºó½«Æä×¢²áµ½ beanFacotry¡£
+ * ×¢²áµ½beanFacotryÖеÄbeanΪBasePackages
+ */
+ public static void register(BeanDefinitionRegistry registry, String... packageNames) {
+ if (registry.containsBeanDefinition(BEAN)) {
+ BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
+ // bean ÊÇ BasePackages£¬¹¹Ôì·½·¨ÊÇ BasePackages(String... names)£¬ÕâÀï»ñȡԱ¾µÄ¹¹Ôì²ÎÊýµÄÖµ
+ ConstructorArgumentValues constructorArguments
+ = beanDefinition.getConstructorArgumentValues();
+ // ½«Ô±¾µÄ¹¹Ôì²ÎÊýÖµ£¬ÒÔ¼°´«ÈëµÄ packageNames ͳһÌí¼Óµ½¹¹Ôì·½·¨µÄµÚ0¸ö²ÎÊýÖµÉÏ
+ constructorArguments.addIndexedArgumentValue(0,
+ addBasePackages(constructorArguments, packageNames));
+ }
+ else {
+ GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
+ // ÉèÖÃBeanClassΪBasePackages.class
+ beanDefinition.setBeanClass(BasePackages.class);
+ // ÉèÖù¹Ôì·½·¨µÄ²ÎÊýÖµ
+ beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);
+ beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+ registry.registerBeanDefinition(BEAN, beanDefinition);
+ }
+ }
+
+ /**
+ * packageName µÄ°ü×°Àà
+ * packageName ÊÇ´«ÈëÀàËùÔڵİüÃû£¬ÔÚPackageImportµÄ¹¹Ôì·½·¨ÖлñÈ¡
+ */
+ private static final class PackageImport {
+
+ private final String packageName;
+
+ PackageImport(AnnotationMetadata metadata) {
+ // »ñÈ¡´«ÈëÀàËùÔÚ°üÃû
+ this.packageName = ClassUtils.getPackageName(metadata.getClassName());
+ }
+
+ String getPackageName() {
+ return this.packageName;
+ }
+
+ // Ê¡ÂÔ equals/toString/hashCode ·½·¨
+ ...
+
+ }
+
+ /**
+ * ×¢½âµ½ beanFactory ÖеÄÀà
+ * ¸ÃÀàÖÐÓÐÒ»¸öList½á¹¹£¬ÓÃÀ´±£´æ°üɨÃè·¾¶
+ */
+ static final class BasePackages {
+ // °üɨÃè·¾¶ÔÚÕâÀï±£´æ
+ private final List packages;
+
+ private boolean loggedBasePackageInfo;
+
+ BasePackages(String... names) {
+ List packages = new ArrayList<>();
+ for (String name : names) {
+ if (StringUtils.hasText(name)) {
+ packages.add(name);
+ }
+ }
+ this.packages = packages;
+ }
+
+ // Ê¡ÂÔÁËһЩ´úÂë
+ ...
+ }
+
+}
+
+```
+
+´úÂëÓе㳤£¬µ«Âß¼²¢²»¸´ÔÓ£¬Á÷³ÌÈçÏ£º
+
+1. `AutoConfigurationPackages.Registrar` ʵÏÖÁË `ImportBeanDefinitionRegistrar`£¬`registerBeanDefinitions(...)` ·½·¨Ïò spring ÖÐ×¢²áÁË `BasePackages`£¬×¢²áÂß¼ÔÚ `AutoConfigurationPackages#register` ·½·¨ÖУ»
+2. `AutoConfigurationPackages#register` ·½·¨µÄ×¢²áÂ߼Ϊ£¬ÏÈÅжÏÊÇ·ñÒÑ×¢²áÁË `BasePackages`£¬Èç¹û×¢²áÁË£¬¾Í½«µ±Ç°ÀàËùÔڵİüÌí¼Óµ½ `BasePackages` µÄ¹¹Ôì·½·¨²ÎÊýÖµÖУ¬·ñÔò¾Í´´½¨ `BeanDefinition`£¬ÉèÖù¹Ôì·½·¨µÄ²ÎÊýÖµ£¬È»ºó×¢²áµ½ spring ÖУ»
+
+#### 2.2 `AutoConfigurationImportSelector`
+
+`AutoConfigurationImportSelector` ÊÇ´¦Àí×Ô¶¯ÅäÖõĹؼü£¬´úÂëÈçÏ£º
+
+```
+public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
+
+ ...
+
+}
+
+```
+
+`AutoConfigurationImportSelector` ʵÏÖÁË `DeferredImportSelector`£¬ÕâÊÇÒ»¸ö `ImportSelector` À࣬µ«´¦ÀíµÄÓÅÏȼ¶×îµÍ (ÔÚ `@ComponentScan`¡¢`@Component`¡¢`@Bean`¡¢`@Configuration` ¼°ÆäËû `@Import` ×¢½â´¦ÀíÍêÖ®ºóÔÙ´¦Àí)£¬ÔÚ `AutoConfigurationImportSelector` ÀàÖлᴦÀí×Ô¶¯ÅäÖÃÀàµÄ¼ÓÔØÁ÷³Ì£¬ÕýÊÇͨ¹ýÕâÖÖ·½Ê½£¬½«×Ô¶¯ÅäÖÃÀàÒýÈëÁË spring ÈÝÆ÷ÖС£
+
+¹ØÓÚ spring ¶Ô `@Import` µÄ´¦Àí£¬¿ÉÒԲο¼ [ConfigurationClassPostProcessor Ö®´¦Àí @Import ×¢½â](https://my.oschina.net/funcy/blog/4678152).
+
+¹ØÓÚ `AutoConfigurationImportSelector` »ñÈ¡×Ô¶¯ÅäÖÃÀàµÄÁ÷³Ì£¬½«ÔÚºóÃæµÄÎÄÕÂÖоßÌå·ÖÎö£¬±¾ÎľͲ»Õ¹¿ªÁË¡£
+
+### 3. `@ComponentScan`
+
+Õâ¸ö×¢½âÏë±Ø´ó¼ÒÒѾºÜÊìϤÁË£¬ËüÖ¸¶¨Á˰üɨÃè·¾¶£¬Èç¹û²»Ö¸¶¨£¬¾ÍɨÃèËùÔÚÀàµÄ°ü£¬¹ØÓÚÕâЩ£¬ÔÚ [ConfigurationClassPostProcessor Ö®´¦Àí @ComponentScan ×¢½â](https://my.oschina.net/funcy/blog/4836178)Ò»ÎÄÖÐÒѾÏêϸ·ÖÎö¹ýÁË£¬¾Í²»ÔÙ·ÖÎöÁË¡£
+
+±¾ÎÄÎÒÃÇÀ´·ÖÎöÕâ¸ö×¢½âÊôÐÔÖÐʹÓÃµÄ 2 ¸öÀࣺ
+
+
+
+#### 3.1 `TypeExcludeFilter`
+
+Õâ¸öÀà±íʾÔÚ½øÐаüɨÃèʱ£¬¿ÉÒÔÅųýһЩÀ࣬´úÂëÈçÏ£º
+
+```
+public class TypeExcludeFilter implements TypeFilter, BeanFactoryAware {
+
+ private BeanFactory beanFactory;
+
+ private Collection delegates;
+
+ @Override
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = beanFactory;
+ }
+
+ @Override
+ public boolean match(MetadataReader metadataReader,
+ MetadataReaderFactory metadataReaderFactory) throws IOException {
+ if (this.beanFactory instanceof ListableBeanFactory
+ && getClass() == TypeExcludeFilter.class) {
+ // getDelegates() »ñÈ¡µ±Ç°ÈÝÆ÷ÖÐËùÓÐµÄ TypeExcludeFilter ʵÀý
+ // ¿ÉÒÔ×ÔÖ÷¼Ì³Ð TypeExcludeFilter£¬×Ô¶¨Ò寥Å乿Ôò
+ for (TypeExcludeFilter delegate : getDelegates()) {
+ if (delegate.match(metadataReader, metadataReaderFactory)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private Collection getDelegates() {
+ Collection delegates = this.delegates;
+ if (delegates == null) {
+ delegates = ((ListableBeanFactory) this.beanFactory)
+ .getBeansOfType(TypeExcludeFilter.class).values();
+ this.delegates = delegates;
+ }
+ return delegates;
+ }
+
+ ....
+
+```
+
+´Ó´úÂëÉÏÀ´¿´£¬Èç¹ûÒªÅųýһЩ À࣬ÎÒÃÇ¿ÉÒÔ×ÔÖ÷¼Ì³Ð `TypeExcludeFilter` À࣬ȻºóÖØÐ´ `match(...)` ·½·¨£¬ÔÚÆäÖж¨Ò寥ÅäÂß¼¡£
+
+#### 3.1 `AutoConfigurationExcludeFilter`
+
+`AutoConfigurationExcludeFilter` ÓÃÀ´Åųý×Ô¶¯ÅäÖÃÀ࣬Ҳ¾ÍÊÇ˵£¬spring ÔÚ½øÐаüɨÃèʱ£¬²»»áɨÃè×Ô¶¯ÅäÖÃÀ࣬´úÂëÈçÏ£º
+
+```
+public class AutoConfigurationExcludeFilter implements TypeFilter, BeanClassLoaderAware {
+
+ private ClassLoader beanClassLoader;
+
+ private volatile List autoConfigurations;
+
+ @Override
+ public void setBeanClassLoader(ClassLoader beanClassLoader) {
+ this.beanClassLoader = beanClassLoader;
+ }
+
+ @Override
+ public boolean match(MetadataReader metadataReader,
+ MetadataReaderFactory metadataReaderFactory) throws IOException {
+ // isConfiguration(...)£ºµ±Ç°ÀàÊÇ·ñ±» @Configuration ±ê¼Ç
+ // isAutoConfiguration(...)£ºµ±Ç°ÀàÊÇ·ñΪ×Ô¶¯ÅäÖÃÀà
+ return isConfiguration(metadataReader) && isAutoConfiguration(metadataReader);
+ }
+
+ private boolean isConfiguration(MetadataReader metadataReader) {
+ return metadataReader.getAnnotationMetadata().isAnnotated(Configuration.class.getName());
+ }
+
+ private boolean isAutoConfiguration(MetadataReader metadataReader) {
+ // »ñÈ¡ËùÓеÄ×Ô¶¯ÅäÖÃÀ࣬ȻºóÅжϵ±Ç°ÀàÊÇ·ñ´æÔÚÓÚÆäÖÐ
+ return getAutoConfigurations().contains(metadataReader.getClassMetadata().getClassName());
+ }
+
+ protected List getAutoConfigurations() {
+ if (this.autoConfigurations == null) {
+ this.autoConfigurations = SpringFactoriesLoader
+ .loadFactoryNames(EnableAutoConfiguration.class, this.beanClassLoader);
+ }
+ return this.autoConfigurations;
+ }
+
+}
+
+```
+
+ÎÒÃÇÖ÷Òª¿´ `match(...)` ·½·¨£¬ËüµÄÆ¥ÅäµÄÀàΪ£º
+
+1. ±» `@Configuration` ±ê¼Ç£»
+2. ÊÇ×Ô¶¯ÅäÖÃÀà¡£
+
+Âú×ãÒÔÉÏÁ½¸öÌõ¼þ£¬spring ¾Í²»»á¶ÔÆä½øÐÐɨÃè´¦Àí¡£
+
+ÄÇʲôÊÇ×Ô¶¯ÅäÖÃÀàÄØ£¿´Ó `isAutoConfiguration(...)` ¿ÉÒÔ¿´µ½£¬ÔÚÅжÏÊÇ·ñΪ×Ô¶¯ÅäÖÃÀàÉÏ£¬springboot ÏÈʹÓà `SpringFactoriesLoader` ¼ÓÔØËùÓÐÅäÖÃÀ࣬ȻºóÔÙÅжϴ«ÈëµÄÀàÊÇ·ñΪÆäÖÐÖ®Ò»¡£´ÓÕâÀï¿ÉÒÔ¿´³ö£¬×Ô¶¯ÅäÖÃÀಢ²»½øÐаüɨÃè²Ù×÷¡£
+
+¹ØÓÚ `SpringFactoriesLoader` ÈçºÎ¼ÓÔØÅäÖÃÀ࣬ºóÃæµÄÎÄÕ»áÏêϸ·ÖÎö¡£
+
+### 4\. ×ܽá
+
+±¾ÎÄÖ÷Òª·ÖÎö `@SpringBootApplication` µÄ¹¦ÄÜ£¬×ܽáÈçÏ£º
+
+1. `@SpringBootApplication` ÊÇÒ»¸ö×éºÏ×¢½â£¬°üº¬ÁË `@SpringBootConfiguration`¡¢`@EnableAutoConfiguration`¡¢`@ComponentScan` Èý¸ö×¢½âµÄ¹¦ÄÜ£¬Í¬Ê±ÌṩÁËһЩÊôÐÔÅäÖã¬Ò²ÊÇÀ´×ÔÓÚÒÔÉÏ 3 ¸ö×¢½â£»
+2. `@SpringBootConfiguration` °üº¬ÁË `Configuration` ×¢½âµÄ¹¦ÄÜ£»
+3. `@EnableAutoConfiguration` ÊÇ¿ªÆô×Ô¶¯×°ÅäµÄ¹Ø¼ü×¢½â£¬ÆäÖбê¼ÇÁË `@AutoConfigurationPackage`£¬»á½«±» `@SpringBootApplication` ±ê¼ÇµÄÀàËùÔڵİü£¬°ü×°³É `BasePackages`£¬È»ºó×¢²áµ½ spring ÈÝÆ÷ÖУ»`@EnableAutoConfiguration` »¹Í¨¹ý `@Import` ×¢½âÏòÈÝÆ÷ÖÐÒýÈëÁË `AutoConfigurationImportSelector`£¬¸ÃÀà»á½«µ±Ç°ÏîĿ֧³ÖµÄ×Ô¶¯ÅäÖÃÀàÌí¼Óµ½ spring ÈÝÆ÷ÖУ»
+4. `@ComponentScan` ¶¨ÒåÁ˰üɨÃè·¾¶£¬Æä `excludeFilters` Öµ¿ÉÒÔÓÃÀ´ÅųýÀàµÄɨÃ裬springboot Ö¸¶¨ÁË `TypeExcludeFilter`£¬±íÃ÷ÎÒÃÇ¿ÉÒԼ̳иÃÀàÀ´×ÔÖ÷¶¨ÒåÅųýµÄÀà £»Í¬Ê±Ò²Ö¸¶¨ÁË `AutoConfigurationExcludeFilter` £¬¸Ã `Filter` ¿ÉÒÔÓÃÀ´Åųý×Ô¶¯ÅäÖÃÀ࣬Ҳ¾ÍÊÇ˵£¬×Ô¶¯ÅäÖÃÀ಻»á½øÐаüÃèÊö²Ù×÷¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4870882](https://my.oschina.net/funcy/blog/4870882) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\357\274\232\345\207\206\345\244\207 SpringApplication.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\357\274\232\345\207\206\345\244\207 SpringApplication.md"
new file mode 100644
index 0000000..ece7a22
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\357\274\232\345\207\206\345\244\207 SpringApplication.md"
@@ -0,0 +1,318 @@
+±¾ÎÄÀ´Ì½¾¿ springboot ÊÇÈçºÎÆô¶¯µÄ£¬±¾ÎÄʹÓõ½µÄ demo λÓÚ?[gitee/funcy](https://gitee.com/funcy/spring-boot/tree/v2.2.2.RELEASE_learn/spring-boot-project/spring-boot-learn/src/main/java/org/springframework/boot/learn/autoconfigure/demo01).
+
+## 1\. ´Ó?`Demo01Application#main(...)`?¿ªÊ¼
+
+springboot µÄÆô¶¯·½Ê½·Ç³£¼òµ¥£¬¾ÍÒ»ÐУº
+
+```
+@SpringBootApplication
+public class Demo01Application {
+
+ public static void main(String[] args) {
+ // ÕâÒ»ÐоÍÊÇÓÃÀ´Æô¶¯springbootµÄ
+ SpringApplication.run(Demo01Application.class, args);
+ }
+}
+
+```
+
+È»ºóÎÒÃǾͽøÈëÕâ¸ö·½·¨£¬¿´¿´Ëü¸ÉÁËʲô£º
+
+```
+public class SpringApplication {
+ ...
+ // primarySource ¾ÍÊÇÎÒÃÇ´«ÈëµÄ Demo01Application.class£¬
+ // args ¾ÍÊÇ main() ·½·¨µÄ²ÎÊý
+ public static ConfigurableApplicationContext run(
+ Class> primarySource, String... args) {
+ // ½« primarySource °ü×°³ÉÊý×飬¼ÌÐøµ÷Óà run(...) ·½·¨
+ return run(new Class>[] { primarySource }, args);
+ }
+
+ // primarySources ¾ÍÊÇÎÒÃÇ´«ÈëµÄ Demo01Application.class °ü×°³ÉµÄÊý×飬
+ // args ¾ÍÊÇ main() ·½·¨µÄ²ÎÊý
+ public static ConfigurableApplicationContext run(
+ Class>[] primarySources, String[] args) {
+ // ÕâÀ↑ʼ¸ÉÕýÊÂÁË
+ return new SpringApplication(primarySources).run(args);
+ }
+ ...
+}
+
+```
+
+ͨ¹ý·½·¨Ò»²½²½×·²éÏÂÈ¥ºó£¬×îºóµ½ÁË?`SpringApplication#run(Class>[], String[])`?·½·¨£¬¹Ø¼ü´úÂëÈçÏ£º
+
+```
+return new SpringApplication(primarySources).run(args);
+
+```
+
+Õâ¿é´úÂëÐèÒª²ð¿ªÀ´¿´£¬¿ÉÒÔ²ð³ÉÒÔÏÂÁ½²¿·Ö£º
+
+* ¹¹Ôì·½·¨£º`SpringApplication#SpringApplication(Class>...)`
+* ʵÀý·½·¨£º`SpringApplication#run(String...)`
+
+¿´À´£¬ÕâÁ½¸ö·½·¨¾ÍÊÇ springboot µÄÆô¶¯ËùÓÐÁ÷³ÌÁË£¬½ÓÏÂÀ´ÎÒÃǾÍÀ´·ÖÎöÕâÁ½¸ö·½·¨¡£
+
+## 2\. ´´½¨?`SpringApplication`£º`SpringApplication#SpringApplication(Class>...)`
+
+```
+public class SpringApplication {
+ public SpringApplication(Class>... primarySources) {
+ // ¼ÌÐøµ÷ÓÃ
+ this(null, primarySources);
+ }
+
+ /**
+ * ÕâÀï¾Í×îÖÕµ÷ÓõĹ¹Ôì·½·¨ÁË
+ * resourceLoader Ϊ null
+ * primarySources Ϊ Demo01Application.class
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
+ // 1\. ½«´«ÈëµÄresourceLoaderÉèÖõ½³ÉÔ±±äÁ¿£¬ÕâÀïµÄֵΪnull
+ this.resourceLoader = resourceLoader;
+ Assert.notNull(primarySources, "PrimarySources must not be null");
+ // 2\. ½«´«ÈëµÄprimarySourcesÉèÖõ½³ÉÔ±±äÁ¿£¬ÕâÀïµÄֵΪ Demo01Application.class
+ this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
+ // 3\. µ±Ç°µÄ web Ó¦ÓÃÀàÐÍ£¬REACTIVE£¬NONE£¬SERVLET
+ this.webApplicationType = WebApplicationType.deduceFromClasspath();
+ // 4\. ÉèÖóõʼ»¯Æ÷£¬getSpringFactoriesInstances£º´Ó META-INF/spring.factories ÖлñÈ¡ÅäÖÃ
+ setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
+ // 5\. ÉèÖüàÌýÆ÷£¬getSpringFactoriesInstances£º´Ó META-INF/spring.factories ÖлñÈ¡ÅäÖÃ
+ setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
+ // 6\. ·µ»Ø°üº¬main()·½·¨µÄclass
+ this.mainApplicationClass = deduceMainApplicationClass();
+ }
+}
+
+```
+
+Õâ¸ö·½·¨Ëù×öµÄÊ»¹ÊDZȽÏÇåÎúµÄ£¬Ïà¹ØÄÚÈݶ¼ÒÑÔÚ´úÂëÖÐ×¢ÊÍÁË£¬²»¹ýÓÐЩ·½·¨»¹ÐèÒªÕ¹¿ª£¬½ÓÏÂÀ´ÎÒÃǾÍÀ´¿´¿´¡£
+
+### 2.1 »ñÈ¡µ±Ç° web Ó¦ÓÃÀàÐÍ£º`WebApplicationType.deduceFromClasspath()`
+
+`WebApplicationType.deduceFromClasspath()`?·½·¨ÊÇÓÃÀ´Íƶϵ±Ç°ÏîÄ¿ÊÇʲôÀàÐ͵쬴úÂëÈçÏ£º
+
+```
+public enum WebApplicationType {
+ // ²»ÊÇ web Ó¦ÓÃ
+ NONE,
+
+ // servlet ÀàÐ굀 web Ó¦ÓÃ
+ SERVLET,
+
+ // reactive ÀàÐ굀 web Ó¦ÓÃ
+ REACTIVE;
+
+ ...
+
+ private static final String[] SERVLET_INDICATOR_CLASSES = {
+ "javax.servlet.Servlet",
+ "org.springframework.web.context.ConfigurableWebApplicationContext" };
+
+ private static final String WEBMVC_INDICATOR_CLASS
+ = "org.springframework.web.servlet.DispatcherServlet";
+
+ private static final String WEBFLUX_INDICATOR_CLASS
+ = "org.springframework.web.reactive.DispatcherHandler";
+
+ private static final String JERSEY_INDICATOR_CLASS
+ = "org.glassfish.jersey.servlet.ServletContainer";
+
+ static WebApplicationType deduceFromClasspath() {
+ // classpath Öнö´æÔÚ WEBFLUX Ïà¹ØÀà
+ if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
+ && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
+ && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
+ return WebApplicationType.REACTIVE;
+ }
+ // classpath ²»´æÔÚ SERVLET Ïà¹ØÀà
+ for (String className : SERVLET_INDICATOR_CLASSES) {
+ if (!ClassUtils.isPresent(className, null)) {
+ return WebApplicationType.NONE;
+ }
+ }
+ // ĬÈÏ web ÀàÐÍΪ SERVLET
+ // Ò²¾ÍÊÇ˵£¬Í¬Ê±´æÔÚ WEBFLUX Óë SERVLET Ïà¹ØÀ࣬×îÖÕ·µ»ØµÄÊÇ SERVLET
+ return WebApplicationType.SERVLET;
+ }
+
+ ...
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬springboot ¶¨ÒåÁËÈýÖÖÏîÄ¿ÀàÐÍ£º`NONE`(²»ÊÇ web Ó¦ÓÃ)¡¢`SERVLET`(`servlet`?ÀàÐ굀 web Ó¦ÓÃ)¡¢`REACTIVE`(`reactive`?ÀàÐ굀 web Ó¦ÓÃ)£¬`WebApplicationType.deduceFromClasspath()`?µÄÖ´ÐÐÁ÷³ÌÈçÏ£º
+
+1. Èç¹û?`classpath`?Öнö´æÔÚ?`WEBFLUX`?Ïà¹ØÀ࣬Ôò±íÃ÷µ±Ç°ÏîÄ¿ÊÇ?`reactive`?ÀàÐ굀 web Ó¦Ó㬷µ»Ø£»
+2. Èç¹û?`classpath`?Öв»´æÔÚ?`SERVLET`?Ïà¹ØÀ࣬Ôò±íÃ÷µ±Ç°ÏîÄ¿²»ÊÇ web Ó¦Ó㬷µ»Ø£»
+3. Èç¹ûÒÔÉÏÌõ¼þ¶¼²»Âú×㣬Ôò±íÃ÷µ±Ç°ÏîÄ¿ÊÇ?`servlet`?ÀàÐ굀 web Ó¦Óá£
+
+ÓÉÓÚ demo ÒýÓÃÁË?`spring-boot-starter-web`?Ïà¹ØÒÀÀµ£¬Òò´Ëµ±Ç°ÏîÄ¿ÊÇ?`servlet`?ÀàÐ굀 web Ó¦Óá£
+
+### 2.2 ÉèÖóõʼ»¯Æ÷£º`setInitializers(...)`
+
+Õâ¿é´úÂëÈçÏ£º
+
+```
+setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
+
+```
+
+ÕâÐдúÂë·ÖΪÁ½²¿·Ö:
+
+* »ñÈ¡?`ApplicationContextInitializer`£º`getSpringFactoriesInstances(ApplicationContextInitializer.class)`
+* ÉèÖóõʼ»¯Æ÷£º`setInitializers(...)`
+
+ÎÒÃÇÏÈÀ´¿´¿´»ñÈ¡?`ApplicationContextInitializer`?µÄÁ÷³Ì£¬´úÂëÈçÏ£º
+
+```
+public class SpringApplication {
+ ...
+
+ // type Ϊ ApplicationContextInitializer.class
+ private Collection getSpringFactoriesInstances(Class type) {
+ return getSpringFactoriesInstances(type, new Class>[] {});
+ }
+
+ /**
+ * type Ϊ ApplicationContextInitializer.class
+ * parameterTypes Ϊ ew Class>[] {}
+ * args Ϊ null
+ */
+ private Collection getSpringFactoriesInstances(Class type,
+ Class>[] parameterTypes, Object... args) {
+ ClassLoader classLoader = getClassLoader();
+ // ´Ó META-INF/spring.factories ¼ÓÔØÄÚÈÝ
+ Set names = new LinkedHashSet<>(
+ SpringFactoriesLoader.loadFactoryNames(type, classLoader));
+ // ʵÀý»¯£¬Ê¹Óõķ´Éä²Ù×÷
+ List instances = createSpringFactoriesInstances(
+ type, parameterTypes, classLoader, args, names);
+ // ÅÅÐò£¬±È½ÏµÄÊÇ @Order ×¢½â£¬»òʵÏÖµÄ Orderd ½Ó¿Ú
+ AnnotationAwareOrderComparator.sort(instances);
+ return instances;
+ }
+ ...
+}
+
+```
+
+ÒÔÉÏ´úÂë±È½Ï¼òµ¥£¬ÏÈ´Ó?`META-INF/spring.factories`?»ñÈ¡ÄÚÈÝ£¬È»ºóʹÓ÷´Éä½øÐÐʵÀý»¯£¬½øÐÐÅÅÐòºóÔÙ·µ»Ø¡£
+
+¹ØÓÚ?`SpringFactoriesLoader.loadFactoryNames(...)`£¬Ëü×îÖÕ»á´Ó?`META-INF/spring.factories`?¼ÓÔØÄÚÈÝ£¬`META-INF/spring.factories`?¿ÉÒÔÀí½âΪһ¸öÅäÖÃÎļþ£¬key Ϊ´«ÈëµÄ type£¬¸Ã·½·¨µÄÏêϸ·ÖÎö£¬¿ÉÒԲο¼?[springboot ×Ô¶¯×°ÅäÖ®¼ÓÔØ×Ô¶¯×°ÅäÀà](https://my.oschina.net/funcy/blog/4870868)¡£
+
+×îÖÕ»áÓжàÉÙ¸ö?`ApplicationContextInitializer`?¼ÓÔØ½øÀ´ÄØ£¿Í¨¹ýµ÷ÊÔ£¬·¢ÏÖÒ»¹²ÓÐ 7 ¸ö£º
+
+
+
+¶ÔÕâ 7 ¸ö?`ApplicationContextInitializer`£¬ËµÃ÷ÈçÏ£º
+
+* `ConfigurationWarningsApplicationContextInitializer`£º±¨¸æ IOC ÈÝÆ÷µÄһЩ³£¼ûµÄ´íÎóÅäÖÃ
+* `ContextIdApplicationContextInitializer`£ºÉèÖà Spring Ó¦ÓÃÉÏÏÂÎÄµÄ ID
+* `DelegatingApplicationContextInitializer`£º¼ÓÔØ?`application.properties`?ÖÐ?`context.initializer.classes`?ÅäÖõÄÀà
+* `RSocketPortInfoApplicationContextInitializer`£º½«?`RSocketServer`?ʵ¼ÊʹÓõļàÌý¶Ë¿ÚдÈëµ½?`Environment`?»·¾³ÊôÐÔÖÐ
+* `ServerPortInfoApplicationContextInitializer`£º½«ÄÚÖà servlet ÈÝÆ÷ʵ¼ÊʹÓõļàÌý¶Ë¿ÚдÈëµ½?`Environment`?»·¾³ÊôÐÔÖÐ
+* `SharedMetadataReaderFactoryContextInitializer`£º´´½¨Ò»¸ö?`SpringBoot`?ºÍ?`ConfigurationClassPostProcessor`?¹²ÓõÄ?`CachingMetadataReaderFactory`?¶ÔÏó
+* `ConditionEvaluationReportLoggingListener`£º½«?`ConditionEvaluationReport`?дÈëÈÕÖ¾
+
+»ñÈ¡µ½?`ApplicationContextInitializer`£¬ÎÒÃÇÔÙÀ´¿´¿´?`setInitializers(...)`?·½·¨£º
+
+```
+public class SpringApplication {
+ ...
+ public void setInitializers(
+ Collection extends ApplicationContextInitializer>> initializers) {
+ this.initializers = new ArrayList<>(initializers);
+ }
+ ...
+}
+
+```
+
+ÕâÊÇÒ»¸ö±ê×¼µÄ?`setter`?·½·¨£¬Ëù×öµÄ¾ÍÖ»ÊÇÉèÖóÉÔ±±äÁ¿¡£
+
+### 2.3 ÉèÖüàÌýÆ÷£º`setListeners(...)`
+
+ÉèÖüàÌýÆ÷µÄ´úÂëÈçÏ£º
+
+```
+setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
+
+```
+
+´ÓÐÎʽÉÏ¿´£¬Í¬?`Initializer`?Ò»Ñù£¬Ò²ÊÇÏÈ´Ó?`META-INF/spring.factories`?ÖмÓÔØ?`ApplicationListener`£¬È»ºóÌí¼Óµ½³ÉÔ±±äÁ¿ÖУ¬ÕâÀïÎÒÃÇÖ±½Ó¿´ÄÜ»ñÈ¡µ½ÄÄЩ?`listener`£º
+
+
+
+¿ÉÒÔ¿´µ½£¬Ò»¹²¿ÉÒÔ»ñÈ¡µ½ 11 ¸ö?`listener`£¬ÕâЩ?`listener`?µÄ×÷ÓÃÈçÏ£º
+
+* `ClearCachesApplicationListener`£ºÓ¦ÓÃÉÏÏÂÎļÓÔØÍê³Éºó¶Ô»º´æ×öÇå³ý¹¤×÷
+* `ParentContextCloserApplicationListener`£º¼àÌýË«Ç×Ó¦ÓÃÉÏÏÂÎĵĹرÕʼþ²¢Íù×Ô¼ºµÄ×ÓÓ¦ÓÃÉÏÏÂÎÄÖд«²¥
+* `CloudFoundryVcapEnvironmentPostProcessor`£º¶Ô?`CloudFoundry`?Ìṩ֧³Ö
+* `FileEncodingApplicationListener`£º¼ì²âϵͳÎļþ±àÂëÓëÓ¦Óû·¾³±àÂëÊÇ·ñÒ»Ö£¬Èç¹ûϵͳÎļþ±àÂëºÍÓ¦Óû·¾³µÄ±àÂ벻ͬÔòÖÕÖ¹Ó¦ÓÃÆô¶¯
+* `AnsiOutputApplicationListener`£º¸ù¾Ý?`spring.output.ansi.enabled`?²ÎÊýÅäÖÃ?`AnsiOutput`
+* `ConfigFileApplicationListener`£º´Ó³£¼ûµÄÄÇЩԼ¶¨µÄλÖöÁÈ¡ÅäÖÃÎļþ
+* `DelegatingApplicationListener`£º¼àÌýµ½Ê¼þºóת·¢¸ø?`application.properties`?ÖÐÅäÖõÄ?`context.listener.classes`?µÄ¼àÌýÆ÷
+* `ClasspathLoggingApplicationListener`£º¶Ô»·¾³¾ÍÐ÷ʼþ?`ApplicationEnvironmentPreparedEvent`?ºÍÓ¦ÓÃʧ°Üʼþ?`ApplicationFailedEvent`?×ö³öÏìÓ¦
+* `LoggingApplicationListener`£ºÅäÖÃ?`LoggingSystem`£¬Ê¹ÓÃ?`logging.config`?»·¾³±äÁ¿Ö¸¶¨µÄÅäÖûòÕßȱʡÅäÖÃ
+* `LiquibaseServiceLocatorApplicationListener`£ºÊ¹ÓÃÒ»¸ö¿ÉÒÔºÍ?`SpringBoot`?¿ÉÖ´ÐÐ jar °üÅäºÏ¹¤×÷µÄ°æ±¾Ìæ»»?`LiquibaseServiceLocator`
+* `BackgroundPreinitializer`£ºÊ¹ÓÃÒ»¸öºǫ́Ï߳̾¡Ôç´¥·¢Ò»Ð©ºÄʱµÄ³õʼ»¯ÈÎÎñ
+
+ÔÙÀ´¿´¿´?`SpringApplication#setListeners`£º
+
+```
+public void setListeners(Collection extends ApplicationListener>> listeners) {
+ this.listeners = new ArrayList<>(listeners);
+}
+
+```
+
+ÕâÒ²ÊÇÒ»¸ö±ê×¼µÄ?`setter`?·½·¨¡£
+
+### 2.4 ÍÆ¶ÏÖ÷Àࣺ`deduceMainApplicationClass()`
+
+ËùνÖ÷À࣬¾ÍÊǰüº¬?`main(String[])`£¬Ò²¾ÍÊǵ±Ç° spring Ó¦ÓÃµÄÆô¶¯À࣬`SpringApplication#deduceMainApplicationClass`?´úÂëÈçÏ£º
+
+```
+private Class> deduceMainApplicationClass() {
+ try {
+ // »ñÈ¡µ÷ÓÃÕ»
+ StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
+ // ±éÀúµ÷ÓÃÕ»£¬ÕÒ µ½main·½·¨
+ for (StackTraceElement stackTraceElement : stackTrace) {
+ if ("main".equals(stackTraceElement.getMethodName())) {
+ return Class.forName(stackTraceElement.getClassName());
+ }
+ }
+ }
+ catch (ClassNotFoundException ex) {
+ // Swallow and continue
+ }
+ return null;
+}
+
+```
+
+ÕâÀïÖ÷ÒªÊÇͨ¹ý?`new RuntimeException().getStackTrace()`?»ñÈ¡µ÷ÓÃÕ»£¬È»ºó±éÀú£¬µÃµ½°üº¬?`main`?·½·¨µÄÀ࣬µÃµ½µÄµ÷ÓÃÕ»ÈçÏ£º
+
+
+
+¿ÉÒÔ¿´µ½£¬`main()`?¾Í°üº¬ÔÚµ÷ÓÃÕ»ÖÐÁË¡£
+
+### 2.5 ×ܽá
+
+±¾ÎÄÖ÷ÒªÊǽéÉÜ?`SpringApplication`?µÄ´´½¨¹ý³Ì£¬ÎÒÃÇÖØµã·ÖÎöÁËÒÔϼ¸µã£º
+
+1. ÍÆ¶Ïµ±Ç° web Ó¦ÓÃÀàÐÍ£ºNONE, SERVLET,REACTIVE£»
+2. ÉèÖóõʼ»¯Æ÷£º`ApplicationContextInitializer`£»
+3. ÉèÖüàÌýÆ÷£º`ApplicationListener`£»
+4. ÍÆ¶ÏÖ÷Àà¡£
+
+
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4877610](https://my.oschina.net/funcy/blog/4877610)?£¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\211\357\274\211\357\274\232\345\207\206\345\244\207IOC\345\256\271\345\231\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\211\357\274\211\357\274\232\345\207\206\345\244\207IOC\345\256\271\345\231\250.md"
new file mode 100644
index 0000000..f916074
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\211\357\274\211\357\274\232\345\207\206\345\244\207IOC\345\256\271\345\231\250.md"
@@ -0,0 +1,535 @@
+ÉÏһƪÎÄÕÂ×ܽá springboot Æô¶¯Á÷³ÌÈçÏ£º
+
+
+
+½ÓÉÏÎÄ£¬ÎÒÃǼÌÐø·ÖÎö½ÓÏÂÀ´µÄ²½Öè¡£
+
+### 3.8 ´´½¨ ioc ÈÝÆ÷
+
+´´½¨ ioc ÈÝÆ÷µÄ´úÂëÈçÏ£º
+
+```
+ConfigurableApplicationContext context = null;
+....
+// ´´½¨applicationContext
+context = createApplicationContext();
+
+```
+
+ÎÒÃǽøÈë `SpringApplication#createApplicationContext` ·½·¨£º
+
+```
+/** ĬÈ쵀 ApplicationContext */
+public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ + "annotation.AnnotationConfigApplicationContext";
+
+/** servlet Ó¦ÓÃµÄµÄ ApplicationContext */
+public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
+
+/** Reactive Ó¦ÓÃµÄ ApplicationContext */
+public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
+
+protected ConfigurableApplicationContext createApplicationContext() {
+ Class> contextClass = this.applicationContextClass;
+ if (contextClass == null) {
+ try {
+ // ¸ù¾ÝÓ¦ÓÃÀàÐÍÀ´´´½¨²»Í¬µÄÈÝÆ÷
+ switch (this.webApplicationType) {
+ case SERVLET:
+ // ʹÓõÄÊÇ AnnotationConfigServletWebServerApplicationContext
+ contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
+ break;
+ case REACTIVE:
+ contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
+ break;
+ default:
+ // ĬÈÏʹÓõÄÊÇ AnnotationConfigApplicationContext
+ contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
+ }
+ }
+ catch (ClassNotFoundException ex) {
+ throw new IllegalStateException(...);
+ }
+ }
+ // ʹÓ÷´Éä½øÐÐʵÀý»¯
+ return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
+}
+
+```
+
+Õâ¸ö·½·¨Ö÷Òª¾ÍÊǸù¾ÝÓ¦ÓÃÀàÐÍÀ´´´½¨²»Í¬ `ApplicationContext`£¬Ê¹Ó÷´ÉäµÄ·½·¨½øÐÐʵÀý»¯£¬¸÷Ó¦ÓÃÀàÐͶÔÓ¦µÄ `ApplicationContext` ÈçÏ£º
+
+1. `servlet` Ó¦Óãº`AnnotationConfigServletWebServerApplicationContext`
+2. `reactive` Ó¦Óãº`AnnotationConfigReactiveWebServerApplicationContext`
+3. ÒÔÉ϶¼²»ÊÇ£º`AnnotationConfigApplicationContext`
+
+µ±Ç°Ó¦ÓõÄÀàÐÍÊÇ `servlet`£¬Òò´Ë´´½¨µÄ `ApplicationContext` ÊÇ `AnnotationConfigReactiveWebServerApplicationContext`£¬À´¿´¿´ËüµÄ¹¹Ôì·½·¨£º
+
+```
+public class AnnotationConfigServletWebServerApplicationContext
+ extends ServletWebServerApplicationContext implements AnnotationConfigRegistry {
+
+ // ÓÃÀ´´¦Àí BeanDefinition µÄ×¢²á
+ private final AnnotatedBeanDefinitionReader reader;
+
+ // ÓÃÀ´´¦Àí°üµÄɨÃè
+ private final ClassPathBeanDefinitionScanner scanner;
+
+ ...
+
+ public AnnotationConfigServletWebServerApplicationContext() {
+ this.reader = new AnnotatedBeanDefinitionReader(this);
+ this.scanner = new ClassPathBeanDefinitionScanner(this);
+ }
+
+ ...
+}
+
+```
+
+`AnnotationConfigServletWebServerApplicationContext` µÄ¹¹Ôì·½·¨»¹ÊDZȽϼòµ¥µÄ£¬Ö»ÊÇÉèÖÃÁËÁ½¸öÊôÐÔ£¬¾Í²»¶à˵ÁË¡£²»¹ý£¬ÎÒÃÇÒ²Òª°ÑÄ¿¹â·ÅÔ¶Ò»µã£¬¿´¿´Æä¸¸ÀàµÄ¹¹Ôì·½·¨£¬×îÖÕÔÚ `GenericApplicationContext` µÄ¹¹Ôì·½·¨ÖÐÕÒµ½Õâôһ¾ä£º
+
+```
+public GenericApplicationContext() {
+ this.beanFactory = new DefaultListableBeanFactory();
+}
+
+```
+
+ÕâÐдúÂë´´½¨ÁË `DefaultListableBeanFactory` ²¢½«Æä¸³Öµ¸øÁË `beanFactory`£¬Õâ±íÃ÷ÎÒÃÇÔÚ `ApplicationContext` ʹÓÃµÄ `beanFactory` ¾ÍÊÇ `DefaultListableBeanFactory`¡£
+
+### 3.9 ×¼±¸ ioc ÈÝÆ÷
+
+´´½¨Íê ioc ÈÝÆ÷ºó£¬½ÓמÍÊǶÔÈÝÆ÷½øÐÐһЩ׼±¸²Ù×÷£¬´úÂëÈçÏ£º
+
+```
+public class SpringApplication {
+
+ ...
+
+ private void prepareContext(ConfigurableApplicationContext context,
+ ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
+ ApplicationArguments applicationArguments, Banner printedBanner) {
+ // ½«´´½¨ºÃµÄÓ¦Óû·¾³ÉèÖõ½IOCÈÝÆ÷ÖÐ
+ context.setEnvironment(environment);
+ // ÉèÖÃÈÝÆ÷µÄһЩ²ÎÊý
+ postProcessApplicationContext(context);
+ // Ó¦ÓÃInitializer½øÐгõʼ»¯²Ù×÷
+ applyInitializers(context);
+ // ¼àÌýÆ÷£ºSpringApplicationRunListenersµÄcontextPrepared·½·¨
+ // £¨ÔÚ´´½¨ºÍ×¼±¸ApplicationContextÖ®ºó£¬µ«ÔÚ¼ÓÔØÖ®Ç°£©
+ listeners.contextPrepared(context);
+ // ´òÓ¡¸öÈÕÖ¾
+ if (this.logStartupInfo) {
+ logStartupInfo(context.getParent() == null);
+ logStartupProfileInfo(context);
+ }
+ // »ñÈ¡beanFactory
+ ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
+ // ½«ÔËÐвÎÊý×÷Ϊbean×¢²áµ½beanFactoryÖÐ
+ beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
+ // ½« banner ×÷Ϊbean×¢²áµ½beanFactoryÖÐ
+ if (printedBanner != null) {
+ beanFactory.registerSingleton("springBootBanner", printedBanner);
+ }
+ if (beanFactory instanceof DefaultListableBeanFactory) {
+ // ÊÇ·ñÔÊÐíbeanµÄÐÅÏ¢±»¸²¸Ç
+ ((DefaultListableBeanFactory) beanFactory)
+ .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
+ }
+ // ´¦ÀíÀÁ¼ÓÔØ
+ if (this.lazyInitialization) {
+ context.addBeanFactoryPostProcessor(
+ new LazyInitializationBeanFactoryPostProcessor());
+ }
+ // »ñÈ¡ËùÓÐ×ÊÔ´
+ Set sources = getAllSources();
+ Assert.notEmpty(sources, "Sources must not be empty");
+ // ¼ÓÔØ class
+ load(context, sources.toArray(new Object[0]));
+ // ·¢²¼Ê¼þ
+ listeners.contextLoaded(context);
+ }
+}
+
+```
+
+×¼±¸¹¤×÷µÄ²½Ö軹ÊǺÜÇåÎúµÄ£¬ÖØÒªÄÚÈݶ¼ÒÑÔÚ´úÂëÖнøÐÐÁË×¢ÊÍ£¬ÕâÀï¶ÔһЩ²Ù×÷ÎÒÃÇÉÔ΢չ¿ªÏ¡£
+
+#### 1\. ÉèÖÃ `Environment`
+
+¸Ã²Ù×÷µÄ´úÂëΪ
+
+```
+private void prepareContext(ConfigurableApplicationContext context,
+ ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
+ ApplicationArguments applicationArguments, Banner printedBanner) {
+ // ½«´´½¨ºÃµÄÓ¦Óû·¾³ÉèÖõ½IOCÈÝÆ÷ÖÐ
+ context.setEnvironment(environment);
+ ...
+}
+
+```
+
+Õâ¸ö `environment` ¾ÍÊÇÇ°Ãæ´´½¨µÄ `environment`£¬ioc ÈÝÆ÷Ò²ÊÇʹÓÃÕâ¸ö£¬ÎÒÃÇÀ´¿´¿´ÉèÖòÙ×÷£º
+
+```
+public class AnnotationConfigServletWebServerApplicationContext extends ... {
+
+ ...
+
+ @Override
+ public void setEnvironment(ConfigurableEnvironment environment) {
+ // µ÷Óø¸ÀàµÄ·½·¨½øÐÐÉèÖÃ
+ super.setEnvironment(environment);
+ // Ò²½«environmentÉèÖõ½ÕâÁ½¸öÊôÐÔÖÐ
+ this.reader.setEnvironment(environment);
+ this.scanner.setEnvironment(environment);
+ }
+
+ ....
+}
+
+```
+
+#### 2\. ´¦Àí ioc µÄ²¿·ÖÊôÐÔ
+
+ÎÒÃÇÀ´¿´¿´ `postProcessApplicationContext(context);` Ëù×öµÄ¹¤×÷£º
+
+```
+public class SpringApplication {
+
+ ...
+
+ protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
+ // ÉèÖà beanNameGenerator£¬ÓÃÀ´Éú³É bean µÄÃû³Æ£¬ÕâÀï´«ÈëµÄÊÇnull
+ if (this.beanNameGenerator != null) {
+ context.getBeanFactory().registerSingleton(
+ AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
+ this.beanNameGenerator);
+ }
+ // ÉèÖà resourceLoaderµÄÏà¹Ø²ÎÊý£¬ÓÉÓÚΪnull£¬ifÀïµÄ´úÂë²»»áÖ´ÐÐ
+ if (this.resourceLoader != null) {
+ if (context instanceof GenericApplicationContext) {
+ ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
+ }
+ if (context instanceof DefaultResourceLoader) {
+ ((DefaultResourceLoader) context).setClassLoader(
+ this.resourceLoader.getClassLoader());
+ }
+ }
+ // ÕâÀï»áÖ´ÐÐ
+ if (this.addConversionService) {
+ // ÉèÖÃÀàÐÍת»»Æ÷£¬Èç°ÑStringתNumberµÈ
+ context.getBeanFactory().setConversionService(
+ ApplicationConversionService.getSharedInstance());
+ }
+ }
+
+ ...
+
+}
+
+```
+
+Õⲿ·Ö¾ÍÊÇÉèÖà `ApplicationContext` µÄ¼¸¸öÊôÐÔ£¬ÔÚÎÒÃÇµÄ demo ÖУ¬`beanNameGenerator` Óë `resourceLoader` ¶¼ÊÇ `null`£¬Òò´ËÕâÁ½¿é¶¼²»»áÔËÐУ¬ÄÜÔËÐеľÍÖ»ÓÐÕâ¿é´úÂ룺
+
+```
+ context.getBeanFactory().setConversionService(
+ ApplicationConversionService.getSharedInstance());
+
+```
+
+`ConversionService` ÔÚÇ°ÃæÒ²Ìáµ½¹ý£¬ËüÖ÷ÒªÊÇÓÃÀ´½øÐвÎÊýÀàÐÍת»»µÄ¡£
+
+#### 3\. Ó¦Óóõʼ»¯Æ÷£º`applyInitializers(context)`
+
+`SpringApplication#applyInitializers` ·½·¨ÈçÏ£º
+
+```
+public class SpringApplication {
+
+ ...
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ protected void applyInitializers(ConfigurableApplicationContext context) {
+ // getInitializers()£º»ñÈ¡ËùÓеijõʼ»¯Æ÷
+ for (ApplicationContextInitializer initializer : getInitializers()) {
+ Class> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
+ ApplicationContextInitializer.class);
+ Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
+ // ÖðÒ»µ÷ÓÃinitializerµÄinitialize(...)·½·¨
+ initializer.initialize(context);
+ }
+ }
+
+}
+
+```
+
+Õâ¿é²Ù×÷»¹ÊǺÜÇåÎúµÄ£¬¾ÍÊÇ»ñÈ¡ËùÓÐµÄ `Initializer`£¬È»ºó±éÀú£¬Öð¸öµ÷ÓÃÆä `initialize(...)` ·½·¨¡£
+
+ÕâÀﻹÐèÒªÌáÏ£¬`getInitializers()` ÊÇÔõô»ñÈ¡ `Initializer` µÄÄØ£¿Ïà¹Ø´úÂëÈçÏ£º
+
+```
+public class SpringApplication {
+
+ private List> initializers;
+
+ ...
+
+ // ÔÚ¹¹Ôì·½·¨ÖÐÉèÖÃµÄ initializers
+ public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
+ ...
+
+ // ÉèÖóõʼ»¯Æ÷£¬getSpringFactoriesInstances£º´Ó META-INF/spring.factories ÖлñÈ¡ÅäÖÃ
+ setInitializers((Collection) getSpringFactoriesInstances(
+ ApplicationContextInitializer.class));
+
+ ...
+ }
+
+ // »ñÈ¡ Initializer µÄ²Ù×÷£¬´ÓÊôÐÔÖлñÈ¡
+ public Set> getInitializers() {
+ return asUnmodifiableOrderedSet(this.initializers);
+ }
+
+ ...
+
+```
+
+¿´ÁË´úÂë¾ÍÃ÷°×ÁË£¬ÔÚÇ°Ãæ·ÖÎö `SpringApplication` µÄ¹¹Ôì·½·¨Ê±£¬ÎÒÃÇÌáµ½ springboot »á´Ó `META-INF/spring.factories` »ñÈ¡ÅäÖÃµÄ `Initializer`£¬½«ÆäÉèÖõ½ `initializers` ÊôÐÔ£¬¶øÕâÀï¾ÍÊÇʹÓà `Initializer` µÄµØ·½ÁË¡£
+
+#### 4\. »ñÈ¡ËùÓÐ×ÊÔ´
+
+´úÂëÈçÏ£º
+
+```
+private void prepareContext(ConfigurableApplicationContext context,
+ ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
+ ApplicationArguments applicationArguments, Banner printedBanner) {
+ ...
+ // »ñÈ¡ËùÓÐ×ÊÔ´
+ Set sources = getAllSources();
+ ...
+}
+
+```
+
+½øÈë `getAllSources()` ·½·¨£º
+
+```
+// ½« primarySources ·ÅÈësetÖУ¬È»ºó½«setת»¯Îª²»¿É±äµÄset£¬·µ»Ø
+public Set getAllSources() {
+ Set allSources = new LinkedHashSet<>();
+ if (!CollectionUtils.isEmpty(this.primarySources)) {
+ allSources.addAll(this.primarySources);
+ }
+ // sources Ϊ¿Õ£¬if²»Ö´ÐÐ
+ if (!CollectionUtils.isEmpty(this.sources)) {
+ allSources.addAll(this.sources);
+ }
+ return Collections.unmodifiableSet(allSources);
+}
+
+```
+
+Õâ¸ö·½·¨ºÜ¼òµ¥£¬¾ÍÒ»¸ö»°£º½« `primarySources` ·ÅÈë `set` ÖУ¬È»ºó½« `set` ת»¯Îª²»¿É±äµÄ `set`£¬·µ»Ø¡£
+
+ÄÇÕâ¸ö `primarySources` ÊÇɶĨ£¿Õâ¾ÍÓÖÒª»Øµ½ `SpringApplication` µÄ¹¹Ôì·½·¨ÁË£º
+
+```
+public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
+ ...
+ // ÕâÀïÉèÖÃÁË primarySources
+ Assert.notNull(primarySources, "PrimarySources must not be null");
+ this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
+ ...
+}
+
+```
+
+È»ºó¼ÌÐøÍùÉÏ£¬×îºó·¢ÏÖ `primarySources` ÊÇÎÒÃÇÔÚ `main` ·½·¨Öд«ÈëµÄ£º
+
+```
+@SpringBootApplication
+public class Demo01Application {
+
+ public static void main(String[] args) {
+ // Demo01Application.class ¾ÍÊÇ primarySources
+ SpringApplication.run(Demo01Application.class, args);
+ }
+
+}
+
+```
+
+ÎÒÃÇ´«ÈëµÄ `Demo01Application.class` ¾ÍÊÇ `primarySources`£¡
+
+Òò´Ë£¬`getAllSources()` ·µ»ØÁËÒ»¸ö set£¬set ÖÐÖ»ÓÐÒ»¸öÔªËØ£º`Demo01Application.class`£¬ÎÒÃÇÒ²¿ÉÒÔͨ¹ýµ÷ÊÔÀ´ÑéÖ¤£º
+
+
+
+#### 5\. ¼ÓÔØ×ÊÔ´
+
+Õâ¸ö²Ù×÷µÄ´úÂëÈçÏ£º
+
+```
+private void prepareContext(ConfigurableApplicationContext context,
+ ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
+ ApplicationArguments applicationArguments, Banner printedBanner) {
+ ...
+ // ¼ÓÔØ class
+ load(context, sources.toArray(new Object[0]));
+ ...
+}
+
+```
+
+½øÈë `SpringApplication#load` ·½·¨£º
+
+```
+public class SpringApplication {
+ ...
+
+ protected void load(ApplicationContext context, Object[] sources) {
+ // ´´½¨Ò»¸öBeanDefinitionµÄ¼ÓÔØÆ÷
+ BeanDefinitionLoader loader = createBeanDefinitionLoader(
+ getBeanDefinitionRegistry(context), sources);
+ // µ±Ç° beanNameGenerator Ϊ null£¬²»µ÷ÓÃ
+ if (this.beanNameGenerator != null) {
+ loader.setBeanNameGenerator(this.beanNameGenerator);
+ }
+ // µ±Ç° resourceLoader Ϊ null£¬²»µ÷ÓÃ
+ if (this.resourceLoader != null) {
+ loader.setResourceLoader(this.resourceLoader);
+ }
+ // µ±Ç° environment Ϊ null£¬²»µ÷ÓÃ
+ // Ç°Ãæ´´½¨µÄenvironment²¢Ã»Óи³Öµµ½³ÉÔ±±äÁ¿
+ if (this.environment != null) {
+ loader.setEnvironment(this.environment);
+ }
+ loader.load();
+ }
+ ...
+}
+
+```
+
+Õâ¸ö·½·¨ÏÈÊÇ´´½¨ÁËÒ»¸ö `BeanDefinitionLoader` ʵÀý£¬ÉÏÃæ»ñÈ¡µÄ `source` »áÔÚ `BeanDefinitionLoader` µÄ¹¹Ôì·½·¨Öд«È뵽ʵÀýÖУ¬È»ºó¶Ô¸Ã `loader` ½øÐÐһϵÁеÄÊôÐÔÉèÖã¬×îºóÔÙµ÷ÓÃÆä `load()` ·½·¨¡£ÕâÀïÐèҪ˵Ã÷µÄÊÇ£¬ËäÈ»Ç°Ãæ´´½¨ÁË `environment`£¬µ« `this.environment` »¹ÊÇΪ `null`£¬ÔÒòÊÇÇ°Ãæ´´½¨µÄ `environment` ²¢Ã»Óи³Öµ¸ø `this.environment`¡£
+
+ÎÒÃǼÌÐø£¬½øÈë `BeanDefinitionLoader#load()`£º
+
+```
+class BeanDefinitionLoader {
+
+ ...
+
+ int load() {
+ int count = 0;
+ // ÕâÀïµÄ sources ÖоÍÖ»ÓÐÒ»¸öÔªËØ£ºDemo01Application.class
+ for (Object source : this.sources) {
+ count += load(source);
+ }
+ return count;
+ }
+
+ // ´¦Àí¼ÓÔØ²Ù×÷
+ private int load(Object source) {
+ Assert.notNull(source, "Source must not be null");
+ // Class ÀàÐÍÔÚÕâÀï¼ÓÔØ
+ if (source instanceof Class>) {
+ // source Ϊ Demo01Application.class£¬ÎÒÃÇÖ÷Òª¹Ø×¢Õâ¸ö·½·¨
+ return load((Class>) source);
+ }
+ if (source instanceof Resource) {
+ return load((Resource) source);
+ }
+ if (source instanceof Package) {
+ return load((Package) source);
+ }
+ if (source instanceof CharSequence) {
+ return load((CharSequence) source);
+ }
+ throw new IllegalArgumentException("Invalid source type " + source.getClass());
+ }
+
+ // Class ÀàÐ͵ļÓÔØ²Ù×÷
+ private int load(Class> source) {
+ // ´¦Àí grouovy ÓïÑԵ쬲»ÓùÜ
+ if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
+ GroovyBeanDefinitionSource loader
+ = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
+ load(loader);
+ }
+ // ÊÇ·ñÓÐ @Component ×¢½â
+ if (isComponent(source)) {
+ // ÔÚÕâÀïÉú³É BeanDefinition ¶ÔÏ󣬲¢×¢²áµ½springÖÐ
+ this.annotatedReader.register(source);
+ return 1;
+ }
+ return 0;
+ }
+ ...
+
+```
+
+ÔÚ´´½¨ `BeanDefinitionLoader` ʵÀýʱ£¬Í¨¹ýÆä¹¹Ôì·½·¨½« `sources` ´«ÈëÁË `BeanDefinitionLoader` µÄʵÀýÖУ¬`sources` ÖоÍÖ»ÓÐÒ»¸öÔªËØ£º`Demo01Application.class`£¬Òò´ËÎÒÃÇÖ»Ðè¹Ø×¢ `Class` ÀàÐÍ×ÊÔ´µÄ¼ÓÔØ¾Í¿ÉÒÔÁË£¬×îÖÕµ½ÁË `BeanDefinitionLoader#load(java.lang.Class>)` ·½·¨£¬¸Ã·½·¨Ëù×öµÄ²Ù×÷Ϊ£ºÅжϴ«ÈëµÄ `Class` ÊÇ·ñÓÐ `@Component`£¬Èç¹ûÓоͽ«Æä×¢²áµ½ ioc ÈÝÆ÷ÖС£
+
+ÄÇô `Demo01Application.class` ÊÇ·ñÓÐ `@Component` ×¢½âÄØ£¿Óе쬲»¹ýÒþ²ØµÃ±È½ÏÉÆä×¢½â²ã¼¶ÈçÏ£º
+
+```
+@SpringBootApplication
+public class Demo01Application {
+ ...
+}
+
+```
+
+½øÈë `@SpringBootApplication`£º
+
+```
+...
+@SpringBootConfiguration
+...
+public @interface SpringBootApplication {
+ ...
+}
+
+```
+
+¼ÌÐø½øÈë `@SpringBootApplication`£º
+
+```
+...
+@Configuration
+public @interface SpringBootConfiguration {
+ ...
+}
+
+```
+
+¼ÌÐø½øÈë `@Configuration`£º
+
+```
+...
+@Component
+public @interface Configuration {
+ ...
+}
+
+```
+
+¾¹ýÖØÖØ²¨ÕÛ£¬×îÖÕÔÚ `@Configuration` ×¢½âÉÏÕÒµ½ÁË `@Component`.
+
+¹ØÓÚ `this.annotatedReader.register(source)` ×¢²áµÄ¾ßÌå²Ù×÷£¬Õâ¿éÔÚ [spring ·ÖÎö](https://my.oschina.net/funcy/blog/4527454)ÖУ¬ÒѾ·ÖÎö¹ýÁË£¬ÕâÀï¾Í²»ÔÙ·ÖÎöÁË¡£
+
+ÏÞÓÚÆª·ù£¬±¾Îľ͵½ÕâÀïÁË£¬ÏÂÆª¼ÌÐø·ÖÎöʣϵÄÁ÷³Ì¡£
+
+
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4884127](https://my.oschina.net/funcy/blog/4884127) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\272\214\357\274\211\357\274\232\345\207\206\345\244\207\350\277\220\350\241\214\347\216\257\345\242\203.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\272\214\357\274\211\357\274\232\345\207\206\345\244\207\350\277\220\350\241\214\347\216\257\345\242\203.md"
new file mode 100644
index 0000000..4fceb03
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/SpringBoot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\272\214\357\274\211\357\274\232\345\207\206\345\244\207\350\277\220\350\241\214\347\216\257\345\242\203.md"
@@ -0,0 +1,508 @@
+½ÓÉÏÎÄ£¬ÎÒÃǼÌÐø·ÖÎö£¬±¾ÎĽ«·ÖÎö`SpringApplication#run(String...)`·½·¨¡£
+
+## 3.`springboot`µÄÔËÐУº`SpringApplication#run(String...)`
+
+·½·¨ÄÚÈÝÈçÏ£º
+
+```
+public ConfigurableApplicationContext run(String... args) {
+ // 1\. ´´½¨ StopWatch ʵÀý£¬Æäʵ¾ÍÊǸö¼ÆÊ±Æ÷£¬ÓÃÀ´Í³¼ÆspringbootÆô¶¯ºÄʱ
+ StopWatch stopWatch = new StopWatch();
+ stopWatch.start();
+ // ×¼±¸¿ÕµÄApplicationContext£¬ÒÔ¼°Ò»×éÒì³£±¨¸æÆ÷
+ ConfigurableApplicationContext context = null;
+ Collection exceptionReporters = new ArrayList<>();
+ // 2\. ÅäÖÃÒ»¸öϵͳÊôÐÔ£ºjava.awt.headless£¬java.awt.headlessģʽÊÇϵͳµÄÒ»ÖÖÅäÖÃģʽ£¬
+ // ÔÚϵͳ¿ÉÄÜȱÉÙÏÔʾÉ豸¡¢¼üÅÌ»òÊó±êÕâЩÍâÉèµÄÇé¿öÏ¿ÉÒÔʹÓøÃģʽ
+ configureHeadlessProperty();
+ // 3\. »ñÈ¡¼àÌýÆ÷£¬Ò²ÊÇ´Ó META-INF/spring.factories ÖлñÈ¡
+ SpringApplicationRunListeners listeners = getRunListeners(args);
+ // starting()£ºÊ×´ÎÆô¶¯run·½·¨Ê±Á¢¼´µ÷Ó᣿ÉÓÃÓڷdz£ÔçÆÚµÄ³õʼ»¯£¨×¼±¸ÔËÐÐʱ»·¾³Ö®Ç°£©¡£
+ // 4\. ·¢²¼Ê¼þ
+ listeners.starting();
+ try {
+ // ·â×°´«ÈëµÄ²ÎÊý
+ ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
+ // 5\. ´¦Àí»·¾³²ÎÊý
+ ConfigurableEnvironment environment
+ = prepareEnvironment(listeners, applicationArguments);
+ // 6\. Èç¹ûÓÐÅäÖà spring.beaninfo.ignore£¬Ôò½«¸ÃÅäÖÃÉèÖýøÏµÍ³²ÎÊý
+ configureIgnoreBeanInfo(environment);
+ // 7\. Êä³öbanner
+ Banner printedBanner = printBanner(environment);
+ // 8\. ´´½¨applicationContext
+ context = createApplicationContext();
+ // Æô¶¯´íÎ󱨸æµÄ×Ô¶¨Ò廨µ÷½Ó¿Ú
+ exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
+ new Class[] { ConfigurableApplicationContext.class }, context);
+ // 9\. ×¼±¸ÉÏÏÂÎÄ£¬ÉèÖÃÁËһϵÁеÄÊôÐÔÖµ
+ prepareContext(context, environment, listeners, applicationArguments, printedBanner);
+ // 10\. µ÷Óà AbstractApplicationContext.refresh£¬Æô¶¯springÈÝÆ÷
+ refreshContext(context);
+ // 11\. ˢкóµÄ´¦Àí
+ afterRefresh(context, applicationArguments);
+ stopWatch.stop();
+ if (this.logStartupInfo) {
+ new StartupInfoLogger(this.mainApplicationClass)
+ .logStarted(getApplicationLog(), stopWatch);
+ }
+ // 12\. ·¢²¼Ê¼þ
+ listeners.started(context);
+ // 13\. µ÷Óà runner£¬ÊµÏÖÁË ApplicationRunner»òCommandLineRunner µÄ½Ó¿Ú
+ callRunners(context, applicationArguments);
+ }
+ catch (Throwable ex) {
+ handleRunFailure(context, ex, exceptionReporters, listeners);
+ throw new IllegalStateException(ex);
+ }
+ try {
+ // 14\. ·¢²¼Ê¼þ
+ listeners.running(context);
+ }
+ catch (Throwable ex) {
+ handleRunFailure(context, ex, exceptionReporters, null);
+ throw new IllegalStateException(ex);
+ }
+ return context;
+}
+
+```
+
+Õû¸öÆô¶¯Á÷³ÌÈçÏ£º
+
+
+
+½ÓÏÂÀ´ÎÒÃÇÀ´Öصã·ÖÎöÕâ 13 ¸öÆô¶¯Á÷³Ì¡£
+
+### 3.1`stopWatch`£º´´½¨¼ÆÊ±Æ÷²¢Æô¶¯
+
+Ò»¿ªÊ¼£¬springboot ¾Í´´½¨ÁË`stopWatch`ʵÀý£¬È»ºóµ÷ÓÃ`StopWatch#start()`Æô¶¯¼ÆÊ±¹¦ÄÜ£¬¹ØÓÚÕâ¸öÀàûɶºÃ˵µÄ£¬Ëü¾ÍÊǸö¼ÆÊ±Æ÷£¬ÕâÀïÊÇÓÃÀ´¼ÆËã springboot Æô¶¯ºÄʱ£¬ÒÔÏÂÈÕÖ¾ÖеÄʱ¼ä¾ÍÊÇÓÉÕâ¸ö¼ÆÊ±Æ÷µÃµ½µÄ£º
+
+
+
+### 3.2 ÉèÖÃ`java.awt.headless`ÊôÐÔÖµ
+
+`SpringApplication#configureHeadlessProperty`·½·¨µÄÏà¹Ø´úÂëÈçÏ£º
+
+```
+public class SpringApplication {
+
+ private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
+
+ ...
+
+ private boolean headless = true;
+
+ public void setHeadless(boolean headless) {
+ this.headless = headless;
+ }
+ ...
+
+ private void configureHeadlessProperty() {
+ // ½« java.awt.headless µÄÖµÅäÖõ½ÏµÍ³±äÁ¿
+ System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
+ System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
+ Boolean.toString(this.headless)));
+ }
+ ...
+}
+
+```
+
+Õâ¸ö·½·¨½ö½öÊǽ«`java.awt.headless`µÄÖµÉèÖõ½ÁËϵͳ±äÁ¿£¬ÉèÖóÉ`true`£¬±íʾÆô¶¯`java.awt.headless`ģʽ¡£ÄÇôËüÊǸöÉ¶Ä£Ê½ÄØ£¿¼òµ¥À´Ëµ£¬¸Ãģʽ¾ÍÊÇϵͳȱÉÙÁËÏÔʾÉ豸¡¢¼üÅÌ»òÊó±êµÈÇé¿öµÄģʽ£¬·þÎñÆ÷Ò»°ã¶¼ÊÇÔÚÕâÖÖÇé¿öϹ¤×÷µÄ¡£
+
+### 3.3 »ñÈ¡ÔËÐмàÌýÆ÷
+
+¼ÌÐø£¬ÕâÒ»²½ÊÇ»ñÈ¡ÔËÐмàÌýÆ÷£¬¿ÉÒÔ¼àÌýÔËÐÐÆÚ¼äµÄһЩ״̬£¬¿´´úÂ룺
+
+```
+// »ñÈ¡¼àÌýÆ÷£¬Ò²ÊÇ´Ó META-INF/spring.factories ÖлñÈ¡
+SpringApplicationRunListeners listeners = getRunListeners(args);
+
+```
+
+½øÈë`SpringApplication#getRunListeners`£º
+
+```
+public class SpringApplication {
+ ...
+
+ private SpringApplicationRunListeners getRunListeners(String[] args) {
+ Class>[] types = new Class>[] { SpringApplication.class, String[].class };
+ return new SpringApplicationRunListeners(logger,
+ // ÒÀÈ»ÊÇ´ÓMETA-INF/spring.factories ÖлñÈ¡£¬key ÊÇ SpringApplicationRunListener
+ getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
+ }
+ ...
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`SpringApplicationRunListener`ÒÀÈ»ÊÇ´Ó`META-INF/spring.factories`ÖлñÈ¡£¬ÄÇ`SpringApplicationRunListener`ÊǸöɶĨ£¿ÎÒÃÇÀ´¿´´úÂ룺
+
+```
+public interface SpringApplicationRunListener {
+
+ /**
+ * Ê×´ÎÆô¶¯run·½·¨Ê±Á¢¼´µ÷Ó᣿ÉÓÃÓڷdz£ÔçÆÚµÄ³õʼ»¯¡£
+ */
+ default void starting() {
+ }
+
+ /**
+ * ×¼±¸ºÃ»·¾³£¨Environment¹¹½¨Íê³É£©£¬µ«ÔÚ´´½¨ApplicationContext֮ǰµ÷Óá£
+ */
+ default void environmentPrepared(ConfigurableEnvironment environment) {
+ }
+
+ /**
+ * ÔÚ´´½¨ºÍ¹¹½¨ApplicationContextÖ®ºó£¬µ«ÔÚ¼ÓÔØÖ®Ç°µ÷Óá£
+ */
+ default void contextPrepared(ConfigurableApplicationContext context) {
+ }
+
+ /**
+ * ApplicationContextÒѼÓÔØµ«ÔÚË¢ÐÂ֮ǰµ÷Óá£
+ */
+ default void contextLoaded(ConfigurableApplicationContext context) {
+ }
+
+ /**
+ * ApplicationContextÒÑˢУ¬Ó¦ÓóÌÐòÒÑÆô¶¯£¬
+ * µ«ÉÐδµ÷ÓÃCommandLineRunnersºÍApplicationRunners¡£
+ */
+ default void started(ConfigurableApplicationContext context) {
+ }
+
+ /**
+ * ÔÚÔËÐз½·¨³¹µ×Íê³É֮ǰÁ¢¼´µ÷Óã¬
+ * Ë¢ÐÂApplicationContext²¢µ÷ÓÃËùÓÐCommandLineRunnersºÍApplicationRunner¡£
+ */
+ default void running(ConfigurableApplicationContext context) {
+ }
+
+ /**
+ * ÔÚÔËÐÐÓ¦ÓóÌÐòʱʧ°Üʱµ÷Óá£
+ */
+ default void failed(ConfigurableApplicationContext context, Throwable exception) {
+ }
+}
+
+```
+
+`SpringApplicationRunListener`ÊÇÒ»¸ö½Ó¿Ú£¬¶¨ÒåÁËһϵÁеķ½·¨À´¼àÌý springboot µÄÆô¶¯¹ý³Ì£¬·½·¨µÄ˵Ã÷ÒѾÔÚÎĵµÖÐÓÐÏêϸ¶¨Ò壬Èç¹ûÎÒÃÇÐèÒªÔÚ springboot µÄÆô¶¯ÖеÄij¸ö¹ý³Ì×öһЩÊÂÇ飬¾Í¿ÉÒÔʵÏÖ`SpringApplicationRunListener`È»ºóÖØÐ´¶ÔÓ¦µÄ·½·¨¡£
+
+ͨ¹ýµ÷ÊÔ£¬·¢ÏÖ springboot »ñµÃµÄÔËÐмàÌýÆ÷ÈçÏ£º
+
+
+
+### 3.4 ÔËÐмàÌýÆ÷·½·¨£º`listeners.starting()`
+
+»Øµ½`SpringApplication#run(java.lang.String...)`£¬»ñÈ¡µ½ÔËÐмàÌýÆ÷ºó£¬»áÁ¢¼´µ÷ÓÃ`starting()`·½·¨À´·¢²¼Æô¶¯Ê¼þ£º
+
+```
+// »ñÈ¡¼àÌýÆ÷
+SpringApplicationRunListeners listeners = getRunListeners(args);
+// starting()£ºÊ×´ÎÆô¶¯run·½·¨Ê±Á¢¼´µ÷Ó᣿ÉÓÃÓڷdz£ÔçÆÚµÄ³õʼ»¯£¨×¼±¸ÔËÐÐʱ»·¾³Ö®Ç°£©¡£
+listeners.starting();
+
+```
+
+½øÈë`SpringApplicationRunListeners#starting`·½·¨£º
+
+```
+void starting() {
+ for (SpringApplicationRunListener listener : this.listeners) {
+ listener.starting();
+ }
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬ËùνµÄ·¢²¼Ê¼þ£¬¾ÍÊDZéÀúËùÓеļàÌýÆ÷£¬ÖðÒ»µ÷ÓÃÆä`starting()`°ÕÁË£¬`this.listeners`¾ÍÊÇÉÏÃæ»ñÈ¡µ½µÄËùÓеÄÔËÐмàÌýÆ÷¡£²»½öÈç´Ë£¬`SpringApplicationRunListener`µÄÆäËû·½·¨Èç`environmentPrepared(...)`¡¢`contextPrepared(...)`µÈ¶¼ÊÇÕâÑùµÄµ÷ÓÃÌ×·£¬ºóÃæ¿´µ½Á˾Ͳ»Öظ´·ÖÎöÁË¡£
+
+### 3.5 ×¼±¸ÔËÐÐʱ»·¾³
+
+½ÓÏÂÎÒÃÇÀ´¿´¿´»·¾³²ÎÊýµÄ´¦Àí£¬´úÂëÈçÏ£º
+
+```
+// ·â×°´«ÈëµÄ²ÎÊý
+ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
+// ´¦Àí»·¾³²ÎÊý
+ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
+
+```
+
+½øÈë`SpringApplication#prepareEnvironment`£º
+
+```
+private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
+ ApplicationArguments applicationArguments) {
+ // »ñÈ¡»·¾³£¬Èç¹û²»´æÔÚÔò´´½¨
+ ConfigurableEnvironment environment = getOrCreateEnvironment();
+ // ÅäÖÃÔËÐÐʱ»·¾³
+ configureEnvironment(environment, applicationArguments.getSourceArgs());
+ ConfigurationPropertySources.attach(environment);
+ // SpringApplicationRunListener µÄ environmentPrepared ·½·¨
+ // £¨Environment¹¹½¨Íê³É£¬µ«ÔÚ´´½¨ApplicationContext֮ǰ£©
+ listeners.environmentPrepared(environment);
+ // »·¾³ÓëÓ¦Óðó¶¨
+ bindToSpringApplication(environment);
+ if (!this.isCustomEnvironment) {
+ environment = new EnvironmentConverter(getClassLoader())
+ .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
+ }
+ ConfigurationPropertySources.attach(environment);
+ return environment;
+}
+
+```
+
+¿ÉÒÔ¿´µ½¸÷ÖÖ»·¾³×¼±¸£¬ÔÛÃÇÌôÖØµã½²¡£
+
+#### 1\. »ñÈ¡»ò´´½¨`Environment`
+
+Ö±½Ó½øÈë`SpringApplication#getOrCreateEnvironment`£º
+
+```
+private ConfigurableEnvironment getOrCreateEnvironment() {
+ if (this.environment != null) {
+ return this.environment;
+ }
+ switch (this.webApplicationType) {
+ case SERVLET:
+ return new StandardServletEnvironment();
+ case REACTIVE:
+ return new StandardReactiveWebEnvironment();
+ default:
+ return new StandardEnvironment();
+ }
+}
+
+```
+
+´Ó´úÂëÀ´¿´£¬Õâ¸ö·½·¨ÊǸù¾ÝÓ¦ÓÃÀàÐÍÀ´´´½¨¶ÔÓ¦µÄ`Environment`ʵÀý£¬µ±Ç°Ó¦ÓÃÀàÐÍÊÇ`SERVLET`£¬ÔÛÃÇÖ±½Ó¿´`StandardServletEnvironment`ÊÇÈçºÎ´´½¨µÄ¡£
+
+ÎÒÃÇÖªµÀ£¬ÔÚ java ÖУ¬´´½¨Ààʱ£¬»áÏȵ÷Óø¸ÀàµÄ¹¹Ôì·½·¨£¬ÕâÀïÎÒÃÇÖ±½Ó½øÈë`AbstractEnvironment`¹¹Ôì·½·¨£º
+
+```
+
+public abstract class AbstractEnvironment implements ConfigurableEnvironment {
+
+ ...
+
+ public AbstractEnvironment() {
+ customizePropertySources(this.propertySources);
+ }
+
+ ...
+}
+
+```
+
+·¢ÏÖÔÚ`AbstractEnvironment`µÄ¹¹Ôì·½·¨ÖУ¬µ÷ÓÃÁË`customizePropertySources()`£¬¶øÕâ¸ö·½·¨ÔÚ`StandardServletEnvironment`ʵÏÖ£º
+
+```
+public class StandardServletEnvironment extends StandardEnvironment
+ implements ConfigurableWebEnvironment {
+ public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
+ public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
+ public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
+
+ @Override
+ protected void customizePropertySources(MutablePropertySources propertySources) {
+ // Ìí¼Ó servletConfigInitParams
+ propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
+ // Ìí¼Ó servletContextInitParams
+ propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
+ if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
+ propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
+ }
+ // µ÷Óø¸ÀàµÄ·½·¨
+ super.customizePropertySources(propertySources);
+ }
+
+ @Override
+ public void initPropertySources(@Nullable ServletContext servletContext,
+ @Nullable ServletConfig servletConfig) {
+ // Ìæ»»ÉÏÃæÉèÖÃµÄ servletContextInitParams Ϊ servletContext
+ // Ìæ»»ÉÏÃæÉèÖÃµÄ servletConfigInitParams Ϊ servletConfig
+ WebApplicationContextUtils.initServletPropertySources(
+ getPropertySources(), servletContext, servletConfig);
+ }
+
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`StandardServletEnvironment`µÄ`customizePropertySources()`·½·¨Ö»ÊÇÌí¼ÓÁ˼¸¸ö servlet Ïà¹ØµÄ²ÎÊý£¬È»ºó¾ÍÈ¥µ÷Óø¸ÀàµÄ¹¹Ôì·½·¨ÁË£¬ÎÒÃǼÌÐø½øÈë`StandardEnvironment`£º
+
+Õâ¸öÀàËÆºõ²¢Ã»ÓÐ×öʲô£¬ÎÒÃǼÌÐø×·×Ù£¬¿´Ëü¸¸ÀàµÄ¹¹Ôì·½·¨£º
+
+```
+public class StandardEnvironment extends AbstractEnvironment {
+
+ /** ϵͳ»·¾³ */
+ public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
+
+ /** ϵͳÊôÐÔ */
+ public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
+
+ @Override
+ protected void customizePropertySources(MutablePropertySources propertySources) {
+ // »ñȡϵͳÊôÐÔ£¬µ÷ÓõÄÊÇ System.getenv()
+ propertySources.addLast(new PropertiesPropertySource(
+ SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
+ // »ñȡϵͳ»·¾³£¬µ÷ÓõÄÊÇ System.getProperties()
+ propertySources.addLast(new SystemEnvironmentPropertySource(
+ SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
+ }
+
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`StandardEnvironment`µÄ`customizePropertySources()`·½·¨Ö÷ÒªÊǽ«ÏµÍ³ÊôÐÔÓëϵͳ»·¾³Ìí¼Óµ½`Environment`ÖС£¶øÊµ¼ÊÉÏ£¬`Environment`Öаüº¬ÁËÐí¶àµÄϵͳÓë»·¾³Ïà¹ØµÄ²ÎÊý£¬±¾ÉíÒ²ÌṩÁËһЩ`getter`·½·¨¿ÉÒԺܷ½±ãµØ»ñÈ¡ÕâЩ²ÎÊý£º
+
+
+
+µ½ÕâÀÎÒÃǾÍÃ÷°×ÁË£¬`StandardServletEnvironment`Öаüº¬ÁËÈçÏÂÄÚÈÝ£º
+
+* ϵͳÊôÐÔ£¬ÎÒÃÇÆ½Ê±µ÷ÓÃ`System.getenv()`µÃµ½µÄ²ÎÊý£»
+* ϵͳ»·¾³£¬ÎÒÃÇÆ½Ê±µ÷ÓÃ`System.getProperties()`µÃµ½µÄ²ÎÊý£»
+* `servlet`µÄ`servletContext`Óë`servletConfig`.
+
+#### 2\. ÅäÖû·¾³
+
+ÎÒÃǼÌÐø·ÖÎö£¬½Ó×Å¿´¿´ÅäÖû·¾³µÄÁ÷³Ì£¬Ò²¾ÍÊÇ`SpringApplication#configureEnvironment`·½·¨£º
+
+```
+protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
+ if (this.addConversionService) {
+ // Ìí¼Óת»»Æ÷£¬´¦Àí²ÎÊýÀàÐÍת»»£¬Èç StringתNumber£¬IntegerתEnumµÈ
+ ConversionService conversionService = ApplicationConversionService.getSharedInstance();
+ environment.setConversionService((ConfigurableConversionService) conversionService);
+ }
+ // ½«Æô¶¯²ÎÊýÌí¼Óµ½ environment ÖÐ
+ configurePropertySources(environment, args);
+ // ´¦Àí ActiveProfiles Öµ
+ configureProfiles(environment, args);
+}
+
+```
+
+Õâ¸ö·½·¨´úÂë²»¶à£¬¹Ø¼üµã¶¼ÒÑÔÚ´úÂëÖÐ×¢ÊÍÇå³þÁË£¬ÕâÀïÐèÒªÉÔ΢ÌáÏÂ`SpringApplication#configurePropertySources`£º
+
+```
+protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
+ MutablePropertySources sources = environment.getPropertySources();
+ // ÉèÖÃĬÈÏÊôÐÔ£¬Èç¹ûÖ¸¶¨ÁËĬÈÏÊôÐÔ£¬¾ÍÔÚÕâÀïÅäÖÃ
+ if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
+ sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
+ }
+ if (this.addCommandLineProperties && args.length > 0) {
+ String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
+ if (sources.contains(name)) {
+ PropertySource> source = sources.get(name);
+ CompositePropertySource composite = new CompositePropertySource(name);
+ composite.addPropertySource(
+ // ½âÎöÆô¶¯Ê±´«ÈëµÄ²ÎÊý
+ new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
+ composite.addPropertySource(source);
+ sources.replace(name, composite);
+ }
+ else {
+ sources.addFirst(new SimpleCommandLinePropertySource(args));
+ }
+ }
+}
+
+```
+
+ÔÚÕâ¸ö·½·¨Àï»á¶Ô´«ÈëµÄ²ÎÊý½øÐнâÎö£¬½øÈë`SimpleCommandLinePropertySource`£º
+
+```
+public class SimpleCommandLinePropertySource
+ extends CommandLinePropertySource {
+
+ public SimpleCommandLinePropertySource(String... args) {
+ super(new SimpleCommandLineArgsParser().parse(args));
+ }
+ ...
+}
+
+```
+
+×îÖÕ½âÎöµÄ·½·¨ÊÇ`SimpleCommandLineArgsParser#parse`£º
+
+```
+public class SimpleCommandLineArgsParser {
+ public CommandLineArgs parse(String... args) {
+ CommandLineArgs commandLineArgs = new CommandLineArgs();
+ for (String arg : args) {
+ if (arg.startsWith("--")) {
+ String optionText = arg.substring(2, arg.length());
+ String optionName;
+ String optionValue = null;
+ if (optionText.contains("=")) {
+ // -- ¿ªÍ·ÇÒ°üº¬ = µÄ²ÎÊý£¬»á±»½âÎö³É key/value
+ optionName = optionText.substring(0, optionText.indexOf('='));
+ optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length());
+ }
+ else {
+ optionName = optionText;
+ }
+ if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
+ throw new IllegalArgumentException("Invalid argument syntax: " + arg);
+ }
+ commandLineArgs.addOptionArg(optionName, optionValue);
+ }
+ else {
+ commandLineArgs.addNonOptionArg(arg);
+ }
+ }
+ return commandLineArgs;
+ }
+
+ ...
+}
+
+```
+
+½âÎö·½·¨»¹ÊDZȽϼòµ¥µÄ£¬¾ÍÊÇ×Ö·û´®µÄ´¦Àí¶øÒÑ¡£
+
+springboot µÄÆô¶¯²ÎÊýÓÐɶºÃ½âÎöµÄÄØ£¿ÔÚÆô¶¯ spring ÏîĿʱ£¬ÎÒÃÇ¿ÉÒÔÕâÑùÖ¸¶¨²ÎÊý£º
+
+```
+java -jar xxx.jar --a1=aaa --b1=bbb
+
+```
+
+È»ºóÎÒÃǾÍÄÜͨ¹ý`@Value("${a1}")`»ñÈ¡µ½£¬¹Ø¼ü¾ÍÊÇÔÚÕâÀ¿ÉÒÔ¿´µ½£¬springboot »á°Ñ´«ÈëµÄ`--a1=aaa`¡¢`--b1=bbb`½âÎö³É`a1/aaa`¡¢`b1/bbb`¼üÖµ¶ÔµÄÐÎʽ£¬±£´æµ½`Environment`£¬ºóÐøÒªÓõ½Ê±£¬¾Í¿ÉºÜ·½±ãµØ´Ó`Environment`ÖлñÈ¡ÁË¡£
+
+ºÃÁË£¬×¼±¸»·¾³µÄ·ÖÎö¾Íµ½ÕâÀïÁË¡£
+
+### 3.6 ÅäÖÃϵͳ²ÎÊý
+
+Õâ¿éÖ÷ÒªÊÇÅäÖÃÁËÒ»¸ö²ÎÊý£º`spring.beaninfo.ignore`£¬ÓÃÀ´¿ØÖÆÊÇ·ñÌø¹ý`BeanInfo`ÀàµÄËÑË÷£¬`²¢ÇÒÓÉÔ´Âë¿É֪ĬÈÏÖµÊÇtrue`£¬¸Ð¾õÓõIJ»¶à£¬¾Í²»·ÖÎöÁË¡£
+
+### 3.7 ´òÓ¡`banner`
+
+`banner`ÊÇÔÚÕâÀï´òÓ¡³öµÄ£º
+
+```
+Banner printedBanner = printBanner(environment);
+
+```
+
+ÎÒÃÇÒ²¿ÉÒÔ×Ô¼º¶¨Òå banner£¬Õâ¸öÍøÉϽ̳ÌÒ»´ó¶Ñ£¬demo ¾Í²»ÌṩÁË¡£
+
+¹ØÓÚ`banner`£¬Óë springboot µÄÆô¶¯Á÷³Ì¹ØÏµ²»´ó£¬¾Í²»·ÖÎöÁË£¬Ð¡»ï°éÃÇÖ»ÐèÁ˽âÔõôÑùÓü´¿É¡£
+
+ºÃÁË£¬ÏÞÓÚÆª·ù£¬±¾Îľ͵½ÕâÀïÁË£¬ÏÂÆªÎÒÃǼÌÐø¡£
+
+
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4882417](https://my.oschina.net/funcy/blog/4882417)£¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot web\345\272\224\347\224\250\357\274\210\344\270\200\357\274\211\357\274\232servlet \347\273\204\344\273\266\347\232\204\346\263\250\345\206\214\346\265\201\347\250\213.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot web\345\272\224\347\224\250\357\274\210\344\270\200\357\274\211\357\274\232servlet \347\273\204\344\273\266\347\232\204\346\263\250\345\206\214\346\265\201\347\250\213.md"
new file mode 100644
index 0000000..052d637
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot web\345\272\224\347\224\250\357\274\210\344\270\200\357\274\211\357\274\232servlet \347\273\204\344\273\266\347\232\204\346\263\250\345\206\214\346\265\201\347\250\213.md"
@@ -0,0 +1,655 @@
+ÔÚ springboot ÖУ¬Èç¹ûÎÒÃÇÐèҪע²á servlet Èý´ó×é¼þ£º`servlet`¡¢`filter`¡¢`listener`£¬¸ÃÔõô×öÄØ£¬springboot ÌùÐĵØÎªÎÒÃÇÌṩÁË 3 ÖÖ·½·¨£¬±¾ÎľÍÀ´·ÖÎöÕâ 3 ÖÖ·½·¨µÄÔ´ÂëʵÏÖ¡£
+
+### 1\. ×¢²á·½Ê½
+
+#### 1.1 ʹÓà `XxxRegistrationBean` ×¢²á
+
+springboot ÌṩÁËÈý¸öÀàÐ굀 `RegistrationBean` À´´¦Àí servlet Èý´ó×é¼þµÄ×¢²á£¬·Ö±ðÊÇ `ServletRegistrationBean`¡¢`FilterRegistrationBean`¡¢`ServletListenerRegistrationBean`£¬ÕâÀïÎÒÃǼòµ¥Ê¾ÒâÏÂËüÃǵÄÓ÷¨£º
+
+```
+/**
+ * ×¼±¸ÁËÒ»¸öservlet
+ */
+public class MyServlet extends HttpServlet {
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ // ´¦ÀíһЩ²Ù×÷
+ ...
+ }
+}
+
+/**
+ * ½øÐÐ×¢²á²Ù×÷
+ */
+@Bean
+public ServletRegistrationBean registerServlet() {
+ ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(
+ new MyServlet(), "/myServlet");
+ // ´¦ÀíһЩÅäÖòÙ×÷
+ servletRegistrationBean.setXxx();
+ ...
+ return servletRegistrationBean;
+}
+
+```
+
+ÒÔÉÏÌṩÁË `servlet` µÄ×¢²á·½Ê½£¬Òª×¢²á `filter`¡¢`listener`£¬Ö»ÐèʹÓöÔÓ¦µÄ `RegistrationBean` ¼´¿É£¬ÕâÀï¾Í²»Õ¹Ê¾ÁË¡£
+
+#### 1.2 ʹÓà servlet ×¢½â×¢²á
+
+ÔÚ `Servlet 3.0`£¬servlet ÈÝÆ÷ÌṩÁË 3 ¸ö×¢½âÀ´´¦Àí `servlet` Èý´ó×é¼þµÄ×¢²á£º
+
+* `@WebServlet`: ´¦Àí `servlet` ×¢²á
+* `@WebFilter`: ´¦Àí `filter` ×¢²á
+* `@WebListener`: ´¦Àí `listener` ×¢²á
+
+»¹ÊÇÒÔ `servlet` ×¢²áΪÀý£¬ÏÈÀ´¿´¿´ `@WebServlet`:
+
+```
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface WebServlet {
+ String name() default "";
+
+ String[] value() default {};
+
+ String[] urlPatterns() default {};
+
+ int loadOnStartup() default -1;
+
+ WebInitParam[] initParams() default {};
+
+ boolean asyncSupported() default false;
+
+ String smallIcon() default "";
+
+ String largeIcon() default "";
+
+ String description() default "";
+
+ String displayName() default "";
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`@WebServlet` Ö§³Ö¶à¸öÊôÐÔÅäÖã¬ÏñÖ¸¶¨ servlet µÄÃû³Æ¡¢Ó³ÉäµÄ url ¶¼¿ÉÒÔÔÚÕâÀïÖ¸¶¨£¬ÎÒÃÇÒ²Ìṩһ¸öʾÀý£º
+
+```
+@WebServlet(name = "myServlet", urlPatterns = "/myServlet")
+public class JavaServlet extends HttpServlet {
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ // ´¦ÀíһЩ²Ù×÷
+ ...
+ }
+
+}
+
+```
+
+ÕâÑù´¦Àíºó£¬»¹Òª×öÒ»¸öÖØÒªµÄ²Ù×÷£¬ÄǾÍÊÇʹÓà `@ServletComponentScan` À´¿ªÆôɨÃ蹦ÄÜ£º
+
+```
+// ʹÓà @ServletComponentScan À´¿ªÆô servlet ×é¼þµÄɨÃ蹦ÄÜ
+@ServletComponentScan
+@SpringBootApplication
+public class MyApplication {
+ public static void main(String[] args) {
+ ...
+ }
+}
+
+```
+
+#### 1.3 `ServletContextInitializer` ×¢²á
+
+ʹÓÃÕâÖÖ·½Ê½×¢²á£¬ÐèҪʵÏÖ `ServletContextInitializer` ½Ó¿Ú£º
+
+```
+/**
+ * ×¼±¸Ò»¸öservlet
+ */
+public class MyServlet extends HttpServlet {
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ // ´¦ÀíһЩ²Ù×÷
+ ...
+ }
+}
+
+/**
+ * ʵÏÖ ServletContextInitializer
+ */
+@Component
+public class ServletConfig implements ServletContextInitializer {
+
+ @Override
+ public void onStartup(ServletContext servletContext) {
+ // ʹÓà servletContext ½øÐÐ×¢²á
+ ServletRegistration initServlet = servletContext.addServlet("myServlet", MyServlet.class);
+ // ¿ÉÒÔ½øÐÐһЩÅäÖÃ
+ initServlet.addMapping("/myServlet");
+ }
+
+}
+
+```
+
+ʹÓÃÕâÖÖ·½Ê½×¢²á£¬ÏÈҪʵÏÖ `ServletContextInitializer`£¬È»ºóÖØÐ´ `ServletContextInitializer#onStartup` ·½·¨£¬ÔÚ `ServletContextInitializer#onStartup` ʹÓà `ServletContext` ¶ÔÏó½øÐÐ×¢²á¡£`ServletContext` ¶ÔÏóÓÉ servlet ÈÝÆ÷Ìṩ£¬Õâ¸ö¶ÔÏó¾ÍÊÇ×¢²áµÄÖÕ¼«À࣬²»¹ÜÊÇʹÓà `RegistrationBean` ×¢²á£¬»¹ÊÇʹÓà `@ServletComponentScan` ɨÃè×¢²á£¬×îÖÕ¶¼ÊÇͨ¹ý `ServletContext` ×¢²áµ½ servlet ÈÝÆ÷ÖС£
+
+### 2\. Ô´ÂëʵÏÖ
+
+Á˽âÍêÈçºÎʹÓú󣬽ÓÏÂÀ´ÎÒÃÇ¾Í ½øÈëÔ´Âë¿´¿´ÕâЩÁ÷³ÌÊÇÈçºÎʵÏÖ¡£
+
+#### 2.1 `@ServletComponentScan` ɨÃè
+
+ÎÒÃÇÖ±½Ó½øÈë `@ServletComponentScan`£º
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Import(ServletComponentScanRegistrar.class)
+public @interface ServletComponentScan {
+ ...
+}
+
+```
+
+Õâ¸ö×¢²áÉÏÃæ±ê¼ÇÁË `@Import` ×¢½â£¬ÒýÈëÁËÒ»¸öÀࣺ`ServletComponentScanRegistrar`£¬ÎÒÃÇ¿´¿´Õâ¸öÀ྿¾¹×öÁËɶ£º
+
+```
+/**
+ * ʵÏÖÁËImportBeanDefinitionRegistrar
+ * ÏòÈÝÆ÷ÖÐ×¢²áÁË ServletComponentRegisteringPostProcessor
+ */
+class ServletComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
+
+ private static final String BEAN_NAME = "servletComponentRegisteringPostProcessor";
+
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
+ BeanDefinitionRegistry registry) {
+ Set packagesToScan = getPackagesToScan(importingClassMetadata);
+ if (registry.containsBeanDefinition(BEAN_NAME)) {
+ updatePostProcessor(registry, packagesToScan);
+ }
+ else {
+ // ×¢²á BeanFactoryPostProcessor
+ addPostProcessor(registry, packagesToScan);
+ }
+ }
+
+ /**
+ * ×¢²á BeanFactoryPostProcessor
+ * ×¢²áÁË ServletComponentRegisteringPostProcessor
+ */
+ private void addPostProcessor(BeanDefinitionRegistry registry, Set packagesToScan) {
+ GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
+ // ServletComponentRegisteringPostProcessor: ´¦ÀíɨÃèµÄ BeanFactoryPostProcessor
+ beanDefinition.setBeanClass(ServletComponentRegisteringPostProcessor.class);
+ beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(packagesToScan);
+ beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+ // ServletComponentScanRegistrar ¾ÍÊÇΪÁË×¢²á ServletComponentRegisteringPostProcessor
+ registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
+ }
+
+ ...
+
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬Õâ¸öÀàʵÏÖÁË `ImportBeanDefinitionRegistrar`£¬Ö÷ÒªÊÇÏò spring ÈÝÆ÷ÖÐ×¢²áÁË `ServletComponentRegisteringPostProcessor`¡£ÎÒÃǼÌÐø¿´ÏÂÈ¥£¬½øÈë `ServletComponentRegisteringPostProcessor`£º
+
+```
+class ServletComponentRegisteringPostProcessor implements BeanFactoryPostProcessor,
+ ApplicationContextAware {
+
+ /**
+ * ÐèҪɨÃèµÄ°ü.
+ */
+ private final Set packagesToScan;
+
+ /**
+ * ҪɨÃèµÄ°üÓɹ¹Ôì·½·¨´«Èë
+ */
+ ServletComponentRegisteringPostProcessor(Set packagesToScan) {
+ this.packagesToScan = packagesToScan;
+ }
+
+ /**
+ * ÖØÐ´ÁËBeanFactoryPostProcessorµÄ·½·¨
+ */
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
+ throws BeansException {
+ // ÅжÏÊÇ·ñÔËÐÐÔÚÄÚǶµÄ web ÈÝÆ÷ÖÐ
+ if (isRunningInEmbeddedWebServer()) {
+ // ɨÃèÆ÷£¬ÅäÖÃÁËɨÃè¹æÔò
+ ClassPathScanningCandidateComponentProvider componentProvider
+ = createComponentProvider();
+ for (String packageToScan : this.packagesToScan) {
+ // ½øÐаüɨÃè²Ù×÷
+ scanPackage(componentProvider, packageToScan);
+ }
+ }
+ }
+
+ ...
+
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`ServletComponentRegisteringPostProcessor` ʵÏÖÁË `BeanFactoryPostProcessor`£¬ÔÚÖØÐ´µÄ `BeanFactoryPostProcessor#postProcessBeanFactory` ·½·¨Öд¦ÀíɨÃè²Ù×÷£¬É¨Ãèǰ£¬ÏÈÊÇ´´½¨ÁËɨÃèÆ÷ `ClassPathScanningCandidateComponentProvider`£¬È»ºóÔÙ½øÐÐɨÃè¡£
+
+ÎÒÃÇÏÈÀ´¿´É¨ÃèÆ÷µÄ´´½¨·½·¨ `createComponentProvider()`£º
+
+```
+// ´¦Àí¸÷ÖÖ handler
+private static final List HANDLERS;
+
+static {
+ List servletComponentHandlers = new ArrayList<>();
+ servletComponentHandlers.add(new WebServletHandler());
+ servletComponentHandlers.add(new WebFilterHandler());
+ servletComponentHandlers.add(new WebListenerHandler());
+ HANDLERS = Collections.unmodifiableList(servletComponentHandlers);
+}
+
+/**
+ * ´´½¨É¨ÃèÆ÷
+ */
+private ClassPathScanningCandidateComponentProvider createComponentProvider() {
+ // ´´½¨¶ÔÏó
+ ClassPathScanningCandidateComponentProvider componentProvider
+ = new ClassPathScanningCandidateComponentProvider(false);
+ componentProvider.setEnvironment(this.applicationContext.getEnvironment());
+ componentProvider.setResourceLoader(this.applicationContext);
+ for (ServletComponentHandler handler : HANDLERS) {
+ // ÅäÖùýÂ˹æÔò
+ componentProvider.addIncludeFilter(handler.getTypeFilter());
+ }
+ return componentProvider;
+}
+
+```
+
+`createComponentProvider()` ·½·¨ÖУ¬ÏÈÊÇ´´½¨ÁËɨÃèÆ÷¶ÔÏó£¬È»ºóÉèÖÃÁËһЩÊôÐÔ£¬½ÓמÍÊÇÅäÖùýÂ˹æÔò£¬ÎÒÃÇÕâÀïÖØµãÀ´¿´Ï¹ýÂ˹æÔòµÄÅäÖã¬ÕâЩ¹æÔòÓÉ `WebServletHandler`/`WebFilterHandler`/`WebListenerHandler` µÄ `getTypeFilter()` ·½·¨Ìṩ£º
+
+`getTypeFilter()` ·½·¨Î»ÓÚÒ»¸ö³éÏó·½·¨ÖУº
+
+```
+abstract class ServletComponentHandler {
+
+ private final TypeFilter typeFilter;
+
+ /**
+ * ´«Èë×¢½â£¬×ª»»Îª AnnotationTypeFilter ¶ÔÏó
+ */
+ protected ServletComponentHandler(Class extends Annotation> annotationType) {
+ this.typeFilter = new AnnotationTypeFilter(annotationType);
+ ...
+ }
+
+ /**
+ * ·µ»Ø TypeFilter
+ */
+ TypeFilter getTypeFilter() {
+ return this.typeFilter;
+ }
+ ...
+}
+
+```
+
+ÔÚ `ServletComponentHandler` ÖУ¬ÓÐÒ»¸ö³ÉÔ±±äÁ¿ `typeFilter`£¬ÔÚ¹¹Ôì·½·¨Öд«Èë×¢²áÖµºó»áת»»»á `AnnotationTypeFilter`£¬È»ºó¸³Öµ¸ø `typeFilter`£¬¶ø `getTypeFilter()` ·½·¨·µ»ØµÄ¾ÍÊÇÕâ¸ö `typeFilter`¡£
+
+Á˽âÍêÕâ¸ö `typeFilter` µÄÀ´Ô´ºó£¬ÎÒÃÇÀ´¿´¿´ËüµÄ¼¸¸öʵÏÖÀࣺ
+
+```
+/**
+ * WebFilterHandler ¹¹Ôì·½·¨´«ÈëµÄ²ÎÊýÊÇ WebFilter
+ */
+class WebFilterHandler extends ServletComponentHandler {
+ WebFilterHandler() {
+ super(WebFilter.class);
+ }
+ ...
+}
+
+/**
+ * WebListenerHandler ¹¹Ôì·½·¨´«ÈëµÄ²ÎÊýÊÇ WebListener
+ */
+class WebListenerHandler extends ServletComponentHandler {
+ WebListenerHandler() {
+ super(WebListener.class);
+ }
+ ...
+}
+
+/**
+ * WebServletHandler ¹¹Ôì·½·¨´«ÈëµÄ²ÎÊýÊÇ WebServlet
+ */
+class WebServletHandler extends ServletComponentHandler {
+ WebServletHandler() {
+ super(WebServlet.class);
+ }
+ ...
+}
+
+```
+
+Óɴ˾ÍÃ÷°×ÁË£¬`createComponentProvider()` µÃµ½µÄ `ClassPathScanningCandidateComponentProvider` Ö»´¦Àí°üº¬ 3 ¸ö×¢½âµÄÀࣺ
+
+* `@WebFilter`
+* `@WebListener`
+* `@WebServlet`
+
+ÎÒÃǼÌÐø£¬½ÓÏÂÀ´¿´¿´É¨ÃèÁ÷³Ì£¬·½·¨Îª `ServletComponentRegisteringPostProcessor#scanPackage`:
+
+```
+private void scanPackage(ClassPathScanningCandidateComponentProvider componentProvider,
+ String packageToScan) {
+ for (BeanDefinition candidate : componentProvider.findCandidateComponents(packageToScan)) {
+ if (candidate instanceof AnnotatedBeanDefinition) {
+ // ´¦ÀíµÃµ½µÄ BeanDefinition
+ for (ServletComponentHandler handler : HANDLERS) {
+ handler.handle(((AnnotatedBeanDefinition) candidate),
+ (BeanDefinitionRegistry) this.applicationContext);
+ }
+ }
+ }
+}
+
+```
+
+¹ØÓÚ¾ßÌåµÄɨÃèÁ÷³Ì£¨`ClassPathScanningCandidateComponentProvider#findCandidateComponents` ·½·¨£©£¬Í¬ spring µÄ°üɨÃèÁ÷³Ì»ù±¾Ò»Ö£¬ÕâÀï¾Í²»Õ¹¿ªÏ¸½²ÁË£¬ÎÒÃǰÑÖØµã·ÅÔÚ `BeanDefinition` µÄ´¦ÀíÉÏ£¬Ò²¾ÍÊÇ `ServletComponentHandler#handle` ·½·¨£º
+
+```
+void handle(AnnotatedBeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
+ // ÕâÀïµÄ annotationType ¾ÍÊǹ¹Ôì·½·¨Öд«ÈëµÄ×¢½â£¬Èç@WebFilter£¬@WebListener µÈ
+ Map attributes = beanDefinition.getMetadata()
+ .getAnnotationAttributes(this.annotationType.getName());
+ // Åж϶ÔÓ¦µÄ×¢½âÊÇ·ñ´æÔÚ£¬´æÔÚÔò´¦Àí
+ if (attributes != null) {
+ doHandle(attributes, beanDefinition, registry);
+ }
+}
+
+```
+
+ÔÚ´¦ÀíɨÃèµÃµ½µÄ `BeanDefinition` ʱ£¬ÏȱéÀúËùÓÐµÄ `handler`(`WebServletHandler`/`WebFilterHandler`/`WebListenerHandler`)£¬È»ºóµ÷Óà `ServletComponentHandler#handle` ·½·¨½øÐд¦Àí¡£ÔÚ `ServletComponentHandler#handle` ÖУ¬ÓÖ»á¸ù¾ÝÊÇ·ñ´æÔÚ¶ÔÓ¦µÄ×¢½âÊÇ·ñ´æÔÚ£¨Ê¹Óà `AnnotatedBeanDefinition#getMetadata` »ñÈ¡¶ÔӦע²áµÄÐÅÏ¢£©À´¾ö¶¨ÊÇ·ñµ÷ÓÃ×ÓÀàµÄ `doHandler()` ·½·¨¡£
+
+ÄÇôÕâ¸ö `doHandler()` ·½·¨¸ÉÁËÊ²Ã´ÄØ£¿ÎÒÃǽøÈë `WebServletHandler#doHandle`£º
+
+```
+public void doHandle(Map attributes, AnnotatedBeanDefinition beanDefinition,
+ BeanDefinitionRegistry registry) {
+ // ×¢²áµÄÊÇ ServletRegistrationBean ¶ÔÓ¦µÄ BeanDefinition
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder
+ .rootBeanDefinition(ServletRegistrationBean.class);
+ builder.addPropertyValue("asyncSupported", attributes.get("asyncSupported"));
+ builder.addPropertyValue("initParameters", extractInitParameters(attributes));
+ builder.addPropertyValue("loadOnStartup", attributes.get("loadOnStartup"));
+ // »ñÈ¡ servlet Ãû³Æ£¬Èç¹ûÖ¸¶¨ÁËÃû³Æ£¬¾ÍʹÓÃÖ¸¶¨Ãû³Æ£¬Èç¹ûûÓÐÖ¸¶¨£¬¾ÍʹÓÃÊÇbeanµÄÃû³Æ
+ String name = determineName(attributes, beanDefinition);
+ builder.addPropertyValue("name", name);
+ builder.addPropertyValue("servlet", beanDefinition);
+ builder.addPropertyValue("urlMappings", extractUrlPatterns(attributes));
+ builder.addPropertyValue("multipartConfig", determineMultipartConfig(beanDefinition));
+ registry.registerBeanDefinition(name, builder.getBeanDefinition());
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬Õâ¸ö·½·¨Ö÷ÒªÊÇ´¦Àí `Servlet` µÄÅäÖã¬×îÖÕÏò spring ÈÝÆ÷ÖÐ×¢²áµÄÊÇ `ServletRegistrationBean` ¶ÔÓ¦µÄ `beanDefinition`¡£
+
+ÆäËûÁ½¸ö `Handler` ÀàµÄ `doHandle()` ·½·¨´¦ÀíÁ÷³ÌÒ²²î²»¶à£¬²»¹ý×îÖÕÏò spring ÈÝÆ÷ÖÐ×¢²áµÄ `beanDefinition` ÓÐËù²»Í¬£¬ÕâÀï¾Í²»Ï¸¶ÁÁË¡£
+
+ÕâÀï×ܽáÏÂÕ⼸¸ö×¢½â×îÖÕÏò spring ÈÝÆ÷ÖÐ×¢²áµÄ `beanDefinition`£º
+
+* `@WebServlet`: ×¢²áÁË `ServletRegistrationBean` ¶ÔÓ¦µÄ `beanDefinition`
+* `@WebFilter`: ×¢²áÁË `FilterRegistrationBean` ¶ÔÓ¦µÄ `beanDefinition`
+* `@WebListener`: ×¢²áÁË `ServletListenerRegistrationBean` ¶ÔÓ¦µÄ `beanDefinition`
+
+ÔÚʹÓà `XxxRegistrationBean` ×¢²áʱ£¬ÎÒÃÇÊÇÊÖ¶¯´´½¨ÁË `XxxRegistrationBean`£¬È»ºóͨ¹ý `@Bean` ×¢½â×¢²áµ½ spring ÈÝÆ÷ÖУ¬¶øÊ¹Óà `@WebServlet`/`@WebFilter`/`@WebListener` ÄÖÁËһȦ£¬×îÖÕÒ²Êǻص½ÁË `XxxRegistrationBean`£¡
+
+#### 2.2 `XxxRegistrationBean` µÄ×¢²á
+
+ÎÞÂÛÊÇʹÓà `XxxRegistrationBean` ×¢²á£¬»¹ÊÇʹÓà `@ServletComponentScan` ɨÃè×¢²á£¬×îÖÕ¶¼»áµÃµ½ `XxxRegistrationBean` ¶ÔÓ¦µÄ bean£¬½ÓÏÂÀ´ÎÒÃǾÍÀ´Ì½¾¿ÏÂÕâЩ bean ÊÇÈçºÎ×¢²áµ½ servlet ÈÝÆ÷Öеġ£
+
+´Ó´úÂëÉÏ¿´£¬`ServletRegistrationBean`¡¢`FilterRegistrationBean` Óë `ServletListenerRegistrationBean` ¶¼ÊÇ `ServletContextInitializer` ½Ó¿ÚµÄʵÏÖÀ࣬`ServletRegistrationBean` µÄ¼Ì³Ð½á¹¹ÈçÏ£º
+
+
+
+`ServletContextInitializer` ÖÐÖ»ÓÐÒ»¸ö·½·¨ `onStartup(...)`£º
+
+```
+@FunctionalInterface
+public interface ServletContextInitializer {
+
+ /**
+ * ¾ÍÊÇÕâ¸ö servletContext£¬ÓÐÁËËü£¬¾ÍÊǽøÐÐ Servlet£¬filter£¬listener µÄ×¢²áÁË
+ */
+ void onStartup(ServletContext servletContext) throws ServletException;
+
+}
+
+```
+
+ÎÒÃÇÔÚ½éÉÜ `servlet` Èý´ó×é¼þµÄ×¢²á·½Ê½Ê±£¬ÎÒÃÇÌáµ½¿ÉÒÔͨ¹ýʵÏÖ `ServletContextInitializer`£¬ÖØÐ´Æä `onStartup()` À´ÊµÏÖ `servlet` ×é¼þµÄ×¢²á£¬¶ø `XxxRegistrationBean` µÄµ×²ãʵÏÖÒ²ÊÇÕâô×öµÄ¡£
+
+ÒÔ `ServletRegistrationBean`£¬ÎÒÃÇÀ´¿´¿´ËüµÄ `onStartup(...)` ·½·¨×öÁËɶ£º
+
+`ServletRegistrationBean` ûÓÐÖØÐ´ `onStartup(...)` ·½·¨£¬Ö±½Ó¼Ì³Ð×Ô `RegistrationBean`:
+
+```
+public final void onStartup(ServletContext servletContext) throws ServletException {
+ // »ñÈ¡ÃèÊöÐÅÏ¢
+ String description = getDescription();
+ // ÊÇ·ñ¿ªÆô×¢²á£¬Ä¬ÈÏΪtrue
+ if (!isEnabled()) {
+ logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
+ return;
+ }
+ // ½øÐÐ×¢²á²Ù×÷
+ register(description, servletContext);
+}
+
+```
+
+Õâ¸ö·½·¨²¢²»¸´ÔÓ£¬ÏÈ»ñÈ¡ÁËÒ»ÏÂÃèÊöÐÅÏ¢£¬È»ºóÅжÏÊÇ·ñ¿ªÆôÁË×¢²á£¬½ÓמÍÊǽøÐÐ×¢²á²Ù×÷ÁË¡£ÎÒÃÇÖ±½Ó²é¿´×¢²á²Ù×÷£¬½øÈë `DynamicRegistrationBean#register`:
+
+```
+protected final void register(String description, ServletContext servletContext) {
+ D registration = addRegistration(description, servletContext);
+ if (registration == null) {
+ logger.info(...);
+ return;
+ }
+ // ´¦ÀíÅäÖÃ
+ configure(registration);
+}
+
+```
+
+Õâ¸ö·½·¨Ö÷Òª×öÁËÁ½¸ö¼þÊ£º×¢²á `servlet` Óë´¦ÀíÅäÖã¬ÎÒÃÇÏÈÀ´¿´¿´×¢²á²Ù×÷£¬½øÈë `ServletRegistrationBean#addRegistration` ·½·¨:
+
+```
+protected ServletRegistration.Dynamic addRegistration(String description,
+ ServletContext servletContext) {
+ String name = getServletName();
+ // ×¢²á
+ return servletContext.addServlet(name, this.servlet);
+}
+
+```
+
+×¢²á²Ù×÷»¹ÊDZȽϼòµ¥µÄ£¬Ö±½Óµ÷Óà `ServletContext#addServlet` ½øÐС£
+
+¼ÌÐø²é¿´ÅäÖô¦Àí£¬½øÈë `ServletRegistrationBean#configure` ·½·¨£º
+
+```
+protected void configure(ServletRegistration.Dynamic registration) {
+ // µ÷Óø¸Àà
+ super.configure(registration);
+ // ÅäÖÃurlMapping
+ String[] urlMapping = StringUtils.toStringArray(this.urlMappings);
+ if (urlMapping.length == 0 && this.alwaysMapUrl) {
+ urlMapping = DEFAULT_MAPPINGS;
+ }
+ if (!ObjectUtils.isEmpty(urlMapping)) {
+ registration.addMapping(urlMapping);
+ }
+ // ÅäÖÃloadOnStartup
+ registration.setLoadOnStartup(this.loadOnStartup);
+ // »¹´¦ÀíÁËһЩÆäËûÅäÖÃ
+ if (this.multipartConfig != null) {
+ registration.setMultipartConfig(this.multipartConfig);
+ }
+}
+
+```
+
+Õâ¸ö·½·¨ÏÈÊǵ÷ÓÃÁ˸¸ÀàµÄ·½·¨£¬È»ºó¾ÍÊÇÅäÖô¦ÀíÁË£¬ÔÚÕâ¸ö·½·¨ÀïÖ÷ÒªÊÇ´¦ÀíÁË `urlMapping` Óë `loadOnStartup`£¬¾Í²»¶à×ö·ÖÎöÁË¡£
+
+ÎÒÃÇÔÙÀ´¿´¿´ `super.configure(...)` ÅäÖÃÁËɶ£¬½øÈë `DynamicRegistrationBean#configure`:
+
+```
+/**
+ * Ò²ÊÇ´¦ÀíһЩÅäÖÃ
+ */
+protected void configure(D registration) {
+ registration.setAsyncSupported(this.asyncSupported);
+ // ÅäÖóõʼ»¯²ÎÊý
+ if (!this.initParameters.isEmpty()) {
+ registration.setInitParameters(this.initParameters);
+ }
+}
+
+```
+
+Õâ¸ö·½·¨Ö÷Òª´¦ÀíÁ˳õʼ²ÎÊýµÄÅäÖá£
+
+´ÓÉÏÃæµÄ·ÖÎöÀ´¿´£¬`ServletRegistrationBean` µÄ `onStartup(...)` ·½·¨Ö÷Òª´¦ÀíÁËÁ½¸ö²Ù×÷£º
+
+1. ½« `servlet` Ìí¼Óµ½ÈÝÆ÷ÖÐ
+2. ´¦Àí `servlet` ²ÎÊýÅäÖÃ
+
+`FilterRegistrationBean` Óë `ServletListenerRegistrationBean` µÄ×¢²á²Ù×÷ÀàËÆ£¬ÕâÀï¾Í²»¶à˵ÁË¡£
+
+#### 2.3 `ServletContextInitializer#onStartup` µÄÖ´ÐÐ
+
+×¢²áÁ÷³ÌÒѾÞÛÍêÁË£¬ÎÒÃÇÔÙÀ´¿´¿´ `ServletContextInitializer#onStartup` ÊÇÔÚÄÄÀïÖ´Ðеġ£×¢£ºÕâÒ»²½µÄÁ÷³Ì±È½Ï¸´ÔÓ£¬»áÉæ¼°µ½ tomcat µÄÆô¶¯Á÷³Ì£¬Òò´ËÕⲿ·ÖÖ»¹Ø×¢Öصã´úÂ룬²»¾ßÌå·ÖÎöÒ»²½²½Á÷³Ì¡£
+
+ÒÔ tomcat ÈÝÆ÷ΪÀý£¬¾¹ýһϵÁеĵ÷ÊÔÓë´úÂë×·×Ù£¬·¢ÏÖËüÊÇÔÚ `TomcatStarter` ÖÐÔËÐе쬴úÂëÈçÏ£º
+
+```
+class TomcatStarter implements ServletContainerInitializer {
+
+ private final ServletContextInitializer[] initializers;
+
+ TomcatStarter(ServletContextInitializer[] initializers) {
+ this.initializers = initializers;
+ }
+
+ @Override
+ public void onStartup(Set> classes, ServletContext servletContext)
+ throws ServletException {
+ try {
+ for (ServletContextInitializer initializer : this.initializers) {
+ // ÕâÀïÖ´ÐÐ ServletContextInitializer#onStartup·½·¨
+ initializer.onStartup(servletContext);
+ }
+ }
+ catch (Exception ex) {
+ this.startUpException = ex;
+ ...
+ }
+ }
+
+ ...
+
+}
+
+```
+
+`TomcatStarter` ÊÇ springboot ÌṩµÄÀ࣬ËüʵÏÖÁË `ServletContainerInitializer`£¬Çø±ðÓÚ `ServletContextInitializer`£¬`ServletContainerInitializer` ÊÇÓÉ tomcat ÌṩµÄ£¬ÔÚ tomcat Æô¶¯Ê±£¬»áÖ´ÐÐ `ServletContainerInitializer#onStartup` ·½·¨£¨`servlt 3.0` ¹æ·¶£©¡£
+
+ÄÇô `TomcatStarter` ÊÇÈçºÎÌí¼Óµ½ tomcat ÈÝÆ÷ÖеÄÄØ£¿ËäÈ» `servlt 3.0` ¹æ·¶¿ÉÒÔͨ¹ý `spi` ¼¼ÊõɨÃèµ½ `ServletContainerInitializer` µÄʵÏÖ£¬µ«ÊÇÕâÀïÃ÷ÏÔ²»ÊÇÕâÑù×öµÄ£¬ÒòΪÈç¹ûÓÉ tomcat ͨ¹ý `spi` ɨÃèµÃµ½ `TomcatStarter` µÄʵÀý£¬ÄÇËüµÄ³ÉÔ±±äÁ¿ `initializers` ¾ÍÎÞ·¨¸³ÖµÁË£¬ËùÒÔÔÚÌí¼Óµ½ tomcat ǰ£¬`TomcatStarter` ¾ÍҪʵÀý»¯²¢ÇÒ `initializers` ¾ÍÒª±»¸³Öµ¡£
+
+¾¹ý¶à´Îµ÷ÊÔ£¬·¢ÏÖ `TomcatStarter` ÊÇÔÚ `TomcatServletWebServerFactory#configureContext` ÖÐÌí¼Óµ½ tomcat ÈÝÆ÷µÄ£¬¹Ø¼ü´úÂëÈçÏÂ:
+
+
+
+¿ÉÒÔ¿´µ½£¬`initializers` ±»µ±×÷¹¹Ôì²ÎÊý´«Èëµ½ `TomcatStarter` µÄ¹¹Ôì·½·¨ÖУ¬µÃµ½ `TomcatStarter` µÄʵÀý£¬ÔÙÊÖ¶¯Ìí¼Óµ½ tomcat ÈÝÆ÷ÖÐÁË¡£
+
+ÄÇô£¬Õâ¸ö `initializers` ÊÇÔÚÄÄÀï»ñÈ¡µ½µÄÄØ£¿ÊÂʵÉÏ£¬ÎÒÃÇµÄ `XxxRegistrationBean` ¶¼Òª spring ÈÝÆ÷ÖУ¬Òª»ñÈ¡µÄ»°£¬Ö»Òªµ÷Óà `beanFactory.getBeansOfType(...)` ¾Í¿ÉÒÔÁË£¬`ServletContextInitializerBeans#addServletContextInitializerBean(String, ServletContextInitializer, ListableBeanFactory)` ¾ÍÊǸÉÕâ¼þʵģº
+
+```
+private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
+ for (Class extends ServletContextInitializer> initializerType : this.initializerTypes) {
+ // »ñÈ¡ ServletContextInitializer: getOrderedBeansOfType(beanFactory, initializerType)
+ for (Entry initializerBean
+ : getOrderedBeansOfType(beanFactory, initializerType)) {
+ addServletContextInitializerBean(initializerBean.getKey(),
+ initializerBean.getValue(), beanFactory);
+ }
+ }
+}
+
+/**
+ * ´¦ÀíÌí¼Ó²Ù×÷
+ */
+private void addServletContextInitializerBean(String beanName,
+ ServletContextInitializer initializer, ListableBeanFactory beanFactory) {
+ // Ìí¼Ó ServletRegistrationBean
+ if (initializer instanceof ServletRegistrationBean) {
+ Servlet source = ((ServletRegistrationBean>) initializer).getServlet();
+ addServletContextInitializerBean(Servlet.class, beanName, initializer,
+ beanFactory, source);
+ }
+ // Ìí¼Ó FilterRegistrationBean
+ else if (initializer instanceof FilterRegistrationBean) {
+ Filter source = ((FilterRegistrationBean>) initializer).getFilter();
+ addServletContextInitializerBean(Filter.class, beanName, initializer,
+ beanFactory, source);
+ }
+ // Ìí¼Ó DelegatingFilterProxyRegistrationBean
+ else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
+ String source = ((DelegatingFilterProxyRegistrationBean) initializer).getTargetBeanName();
+ addServletContextInitializerBean(Filter.class, beanName, initializer, beanFactory, source);
+ }
+ // Ìí¼Ó ServletListenerRegistrationBean
+ else if (initializer instanceof ServletListenerRegistrationBean) {
+ EventListener source = ((ServletListenerRegistrationBean>) initializer).getListener();
+ addServletContextInitializerBean(EventListener.class, beanName, initializer,
+ beanFactory, source);
+ }
+ else {
+ // ÆäËûµÄ ServletContextInitializer Bean
+ addServletContextInitializerBean(ServletContextInitializer.class, beanName,
+ initializer, beanFactory, initializer);
+ }
+}
+
+```
+
+### 3\. ×ܽá
+
+±¾ÎÄ·ÖÎöÁË springboot ×¢²á servlet Èý´ó×é¼þµÄÁ÷³Ì£º
+
+1. ÒÔ `Servlet` ΪÀý£¬½éÉÜÁË 3 ÖÖ×¢²á·½Ê½£ºÊ¹Óà `XxxRegistrationBean` ×¢²á¡¢Ê¹Óà `servlet` ×¢½â (`@WebServlet`/`@WebFilter`/`@WebListener`) ×¢²á£¬ÒÔ¼°ÊµÏÖ `ServletContextInitializer` ½Ó¿ÚÊÖ¶¯×¢²á£»
+2. ·ÖÎöÁË `@ServletComponentScan` ×¢²áµÄɨÃèÁ÷³Ì
+3. ÒÔ `ServletRegistrationBean` ΪÀý£¬·ÖÎöÁ˽« `ServletRegistrationBean` ×¢²áµ½ servlet µÄÁ÷³Ì
+4. ·ÖÎöÁË `ServletContainerInitializer#onStartup` µÄÖ´ÐÐ
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4951050](https://my.oschina.net/funcy/blog/4951050) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot web\345\272\224\347\224\250\357\274\210\344\272\214\357\274\211\357\274\232WebMvc \350\243\205\351\205\215\350\277\207\347\250\213.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot web\345\272\224\347\224\250\357\274\210\344\272\214\357\274\211\357\274\232WebMvc \350\243\205\351\205\215\350\277\207\347\250\213.md"
new file mode 100644
index 0000000..46adf6d
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot web\345\272\224\347\224\250\357\274\210\344\272\214\357\274\211\357\274\232WebMvc \350\243\205\351\205\215\350\277\207\347\250\213.md"
@@ -0,0 +1,815 @@
+ƽʱ¹¤×÷ÖУ¬springboot ¾ø´ó¶àÊýÇé¿öÏÂÔËÐеÄÊÇ web ÏîÄ¿£¬±¾ÎĽ«·ÖÎö springboot ×Ô¶¯ springMvc ÏîÄ¿µÄÁ÷³Ì¡£
+
+### 1\. springMvc µÄ×Ô¶¯×°ÅäÀà
+
+springMvc µÄ×Ô¶¯×°ÅäÀàΪ
+
+```
+@Configuration(proxyBeanMethods = false)
+// ¼¸¸ö×°ÅäÌõ¼þ
+@ConditionalOnWebApplication(type = Type.SERVLET)
+@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
+// Èç¹ûûÓÐ×Ô¶¨ÒåWebMvcµÄÅäÖÃÀ࣬ÔòʹÓñ¾ÅäÖÃ
+@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
+// ×°Åä˳Ðò
+@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
+@AutoConfigureAfter({
+ // DispatcherServlet µÄ×Ô¶¯×°Åä
+ DispatcherServletAutoConfiguration.class,
+ // Ï̳߳صÄ×Ô¶¯×°Åä
+ TaskExecutionAutoConfiguration.class,
+ // jsr 303 ÑéÖ¤¿ò¼ÜµÄ×Ô¶¯×°Åä
+ ValidationAutoConfiguration.class })
+public class WebMvcAutoConfiguration {
+ ...
+}
+
+```
+
+´ÓÉÏÃæµÄ `@AutoConfigureAfter` ×¢½âÖУ¬`WebMvcAutoConfiguration` ÐèÒªÔÚ `DispatcherServletAutoConfiguration`¡¢`TaskExecutionAutoConfiguration`¡¢`ValidationAutoConfiguration` µÈÀà×°ÅäÍê³ÉÖ®ºóÔÙ×°Å䣬¶ÔÕâЩÀàµÄ×÷ÓÃÁоÙÈçÏ£º
+
+* `DispatcherServletAutoConfiguration`£º`DispatcherServlet` ×Ô¶¯×°Åä
+* `TaskExecutionAutoConfiguration`£ºÈÎÎñÖ´ÐÐÆ÷£¬Æäʵ¾ÍÊÇ´´½¨ÁËÒ»¸öÏ̳߳Ø
+* `ValidationAutoConfiguration`£ºjsr 303 ÑéÖ¤Æ÷µÄ×Ô¶¯×°Å䣬ÑéÖ¤Æ÷ÓÃÀ´´¦Àí `@NotNull`¡¢`@NotEmpty` µÈ×¢½âµÄÑéÖ¤¹¦ÄÜ
+
+Õâ 3 ¸öÀàÖУ¬Óë springMvc ÓйصÄÖ»ÓÐ `DispatcherServletAutoConfiguration`£¬ÎÒÃÇÀ´ÈÏʶһÏÂËü£º
+
+```
+@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnWebApplication(type = Type.SERVLET)
+@ConditionalOnClass(DispatcherServlet.class)
+// ÐèÒªÔÚ ServletWebServerFactoryAutoConfiguration ×Ô¶¯×°ÅäÍê³Éºó´¦Àí
+@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
+public class DispatcherServletAutoConfiguration {
+ ...
+}
+
+```
+
+`DispatcherServletAutoConfiguration` ÐèÒªµÈ `ServletWebServerFactoryAutoConfiguration` ×Ô¶¯×°ÅäÍê³É²Å½øÐÐ×°Å䣬Õâ¸öÀàÊÇ×öʲôµÄÄØ£¿¾ç͸Ï£¬ËüÊÇ´¦Àí servlet ÈÝÆ÷£¨`tomcat`, `jetty`, `undertow` µÈ£©µÄÉú³ÉµÄ£¬ÎÒÃÇÔÙÀ´¿´¿´ `ServletWebServerFactoryAutoConfiguration`£º
+
+```
+@Configuration(proxyBeanMethods = false)
+@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
+@ConditionalOnClass(ServletRequest.class)
+@ConditionalOnWebApplication(type = Type.SERVLET)
+@EnableConfigurationProperties(ServerProperties.class)
+// ÒýÈëÁËһЩÀà
+@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
+ // 3¸ö web ÈÝÆ÷
+ ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
+ ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
+ ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
+public class ServletWebServerFactoryAutoConfiguration {
+ ...
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬Õâ¸öÀàÖÐ×ÜËãÊÇûÓÐ `@AutoConfigureAfter` ×¢½âÁË£¬Òò´ËÕâ¸öÀà springMvc ¾ÍÊÇ×î³õ×Ô¶¯×°ÅäµÄÀ࣬ÎÒÃǵķÖÎö¾Í´ÓÕâ¸öÀ࿪ʼ¡£
+
+×ܽáÏÂÒÔÉϼ¸¸öÀàµÄ×°Åä˳Ðò£º
+
+1. `ServletWebServerFactoryAutoConfiguration`
+2. `DispatcherServletAutoConfiguration`
+3. `WebMvcAutoConfiguration`
+
+½ÓÏÂÀ´ÎÒÃǵķÖÎöÒ²°´ÕâÑùµÄ˳Ðò£¬ÖðÒ»·ÖÎöÕâЩ×Ô¶¯×°ÅäÀà¡£
+
+### 2. `ServletWebServerFactoryAutoConfiguration` µÄ×Ô¶¯×°Åä
+
+`ServletWebServerFactoryAutoConfiguration` ÀàÈçÏ£º
+
+```
+@Configuration(proxyBeanMethods = false)
+@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
+@ConditionalOnClass(ServletRequest.class)
+@ConditionalOnWebApplication(type = Type.SERVLET)
+@EnableConfigurationProperties(ServerProperties.class)
+// ÒýÈëÁËһЩÀà
+@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
+ // 3¸ö web ÈÝÆ÷
+ ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
+ ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
+ ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
+public class ServletWebServerFactoryAutoConfiguration {
+ ...
+}
+
+```
+
+Õâ¸öÀàÒýÈëÁË `BeanPostProcessorsRegistrar`¡¢`EmbeddedTomcat`¡¢`EmbeddedJetty`¡¢`EmbeddedUndertow`£¬ÎÒÃÇÀ´ÖðÒ»·ÖÎö°É£¡
+
+#### 2.1 `BeanPostProcessorsRegistrar`
+
+`BeanPostProcessorsRegistrar` ÊÇ `ServletWebServerFactoryAutoConfiguration` µÄÄÚ²¿À࣬´úÂëÈçÏ£º
+
+```
+public static class BeanPostProcessorsRegistrar
+ implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
+
+ ...
+
+ /**
+ * À´×Ô ImportBeanDefinitionRegistrar µÄ·½·¨
+ */
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
+ BeanDefinitionRegistry registry) {
+ if (this.beanFactory == null) {
+ return;
+ }
+ // ×¢²á×é¼þ
+ registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
+ WebServerFactoryCustomizerBeanPostProcessor.class);
+ registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
+ ErrorPageRegistrarBeanPostProcessor.class);
+ }
+
+ /**
+ * ¾ßÌåµÄ×¢²á²Ù×÷
+ */
+ private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry,
+ String name, Class> beanClass) {
+ if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
+ beanDefinition.setSynthetic(true);
+ registry.registerBeanDefinition(name, beanDefinition);
+ }
+ }
+}
+
+```
+
+Õâ¸öÀàÖ÷ÒªÊÇÏò spring ÈÝÆ÷ÖÐ×¢²áÁËÁ½¸öÀࣺ`WebServerFactoryCustomizerBeanPostProcessor`¡¢`ErrorPageRegistrarBeanPostProcessor`£¬ÎÒÃÇÀ´¿´ÏÂËüÃÇ·Ö±ðÊǸöɶ¡£
+
+##### 1. `WebServerFactoryCustomizerBeanPostProcessor`
+
+`WebServerFactoryCustomizerBeanPostProcessor` µÄ´úÂëÈçÏ£º
+
+```
+public class WebServerFactoryCustomizerBeanPostProcessor
+ implements BeanPostProcessor, BeanFactoryAware {
+
+ ...
+
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName)
+ throws BeansException {
+ // bean µÄÀàÐÍÊÇ WebServerFactory ²Å´¦Àí
+ if (bean instanceof WebServerFactory) {
+ postProcessBeforeInitialization((WebServerFactory) bean);
+ }
+ return bean;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
+ LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
+ .withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
+ // ´¦ÀíÅäÖÃ
+ .invoke((customizer) -> customizer.customize(webServerFactory));
+ }
+
+ /**
+ * »ñÈ¡ WebServerFactoryCustomizer£¬µÃµ½µÄÊÇÒ»¸ö²»¿É±äµÄ List
+ */
+ private Collection> getCustomizers() {
+ if (this.customizers == null) {
+ this.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());
+ this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
+ this.customizers = Collections.unmodifiableList(this.customizers);
+ }
+ return this.customizers;
+ }
+
+ /**
+ * »ñÈ¡ beanFactory ÖÐËùÓÐµÄ WebServerFactoryCustomizer
+ */
+ private Collection> getWebServerFactoryCustomizerBeans() {
+ return (Collection) this.beanFactory.getBeansOfType(
+ WebServerFactoryCustomizer.class, false, false).values();
+ }
+
+}
+
+```
+
+Õâ¸öÀàÊÇÓÃÀ´´¦Àí `WebServerFactory` µÄ×Ô¶¨ÒåÅäÖõģ¬ËüʵÏÖÁË `BeanPostProcessor`£¬ ÎÒÃÇÖ÷Òª¹Ø×¢ËüµÄ `postProcessBeforeInitialization(...)` ·½·¨¡£
+
+ÔÚ `WebServerFactoryCustomizerBeanPostProcessor` µÄ `postProcessBeforeInitialization(...)` ·½·¨ÖУ¬Èç¹ûµ±Ç° bean µÄÀàÐÍÊÇ `WebServerFactory`£¬»áÏÈ»ñÈ¡ `beanFactory` ÖÐËùÓÐÀàÐÍΪ `WebServerFactoryCustomizer` µÄ bean£¬È»ºó½«ÕâЩ `WebServerFactoryCustomizer` ÅäÖõ½ `WebServerFactory`bean ÖС£
+
+Èç¹ûÎÒÃÇÒª×Ô¶¨Òå `Tomcat` µÄÅäÖ㬿ÉÒÔÕâÑù´¦Àí£º
+
+```
+@Component
+public class MyCustomizer implements WebServerFactoryCustomizer {
+
+ @Override
+ public void customize(TomcatServletWebServerFactory factory) {
+ factory.setPort(8091);
+ factory.setContextPath("/");
+ // ÉèÖÃÆäËûÅäÖÃ
+ ...
+ }
+
+}
+
+```
+
+ÔÚ `ServletWebServerFactoryAutoConfiguration` ÖÐÌṩÁËÁ½¸ö `WebServerFactoryCustomizer`:
+
+```
+public class ServletWebServerFactoryAutoConfiguration {
+
+ @Bean
+ public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(
+ ServerProperties serverProperties) {
+ return new ServletWebServerFactoryCustomizer(serverProperties);
+ }
+
+ @Bean
+ @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
+ public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
+ ServerProperties serverProperties) {
+ return new TomcatServletWebServerFactoryCustomizer(serverProperties);
+ }
+
+ ...
+
+}
+
+```
+
+´Ó·½·¨²ÎÊýÀ´¿´£¬ÕâÁ½¸öÀàµÄÅäÖö¼À´×ÔÓÚ `ServerProperties`£º
+
+```
+@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
+public class ServerProperties {
+ ...
+}
+
+```
+
+ËüÉÏÃæÁË `ConfigurationProperties` ×¢½â£¬`prefix` Ϊ "server"£¬Õâ±íÃ÷ËüµÄÅäÖö¼ÊÇÒÔ `server` ¿ªÍ·£¬Ö§³ÖµÄÅäÖÃÈçÏ£º
+
+
+
+ÀýÈ磬ÎÒÃÇÒªÅäÖÃËüµÄ¶Ë¿Ú£¬Ö»ÐèÔÚ `application.properties` ÖÐÕâÑùÅäÖü´¿É£º
+
+```
+server.port=8080
+
+```
+
+ÖÁÓÚÆäËûÅäÖã¬ÕâÀï¾Í²»¶à×÷·ÖÎöÁË¡£
+
+##### 2. `ErrorPageRegistrarBeanPostProcessor`
+
+`ErrorPageRegistrarBeanPostProcessor` µÄ´úÂëÈçÏ£º
+
+```
+public class ErrorPageRegistrarBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
+
+ /**
+ * À´×ÔBeanPostProcessorµÄ·½·¨£¬ÔÚbean³õʼ»¯Ç°Ö´ÐÐ
+ */
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName)
+ throws BeansException {
+ if (bean instanceof ErrorPageRegistry) {
+ // Èç¹û bean ÊÇ ErrorPageRegistry
+ postProcessBeforeInitialization((ErrorPageRegistry) bean);
+ }
+ return bean;
+ }
+
+ private void postProcessBeforeInitialization(ErrorPageRegistry registry) {
+ for (ErrorPageRegistrar registrar : getRegistrars()) {
+ // ×¢²á´íÎóÒ³
+ registrar.registerErrorPages(registry);
+ }
+ }
+
+ private Collection getRegistrars() {
+ if (this.registrars == null) {
+ // »ñÈ¡ËùÓеĴíÎóÒ³
+ this.registrars = new ArrayList<>(this.beanFactory.getBeansOfType(
+ ErrorPageRegistrar.class, false, false).values());
+ this.registrars.sort(AnnotationAwareOrderComparator.INSTANCE);
+ this.registrars = Collections.unmodifiableList(this.registrars);
+ }
+ return this.registrars;
+ }
+
+ ...
+}
+
+```
+
+ÎÒÃÇÖ÷Òª¹Ø×¢ `postProcessBeforeInitialization` µÄÁ÷³Ì£º
+
+1. Èç¹û bean µÄÀàÐÍÊÇ `ErrorPageRegistry`£¬½øÐÐµÚ 2 ²½
+2. »ñÈ¡ beanFactory ÖÐËùÓÐ `ErrorPageRegistrar` ÀàÐ굀 bean£¬±éÀú½øÐÐµÚ 3 ²½
+3. µ÷Óà `registrar.registerErrorPages(registry)` ½øÐдíÎóÒ³²Ù×÷
+
+ÕâÀïÓÐÁ½¸öÀàÐèҪ˵Ã÷£º
+
+* `ErrorPageRegistrar`£º´íÎóÒ³×¢²áÆ÷£¨Èà `ErrorPageRegistry` ¸É»îµÄÀࣩ
+* `ErrorPageRegistry`£º´íÎóµÄ×¢²áÆ÷Àࣨʵ¼Ê¸É»îµÄÀࣩ
+
+Èç¹ûÎÒÃÇÏëÒª×Ô¶¨Òå´íÎóÒ³£¬¿ÉÒÔʵÏÖ `ErrorPageRegistry` ½Ó¿Ú£º
+
+```
+@Component
+public class MyErrorPage implements ErrorPageRegistrar {
+
+ /**
+ * ×¢²á´íÎóÒ³
+ */
+ @Override
+ public void registerErrorPages(ErrorPageRegistry errorPageRegistry) {
+ // ×îÖÕµ÷ÓõÄÊÇ ErrorPageRegistry#addErrorPages ½øÐÐ×¢²á
+ errorPageRegistry.addErrorPages(new ErrorPage("/error/page"));
+ }
+}
+
+```
+
+#### 2.2 `EmbeddedTomcat`
+
+½øÈë `ServletWebServerFactoryConfiguration.EmbeddedTomcat` Àࣺ
+
+```
+@Configuration(proxyBeanMethods = false)
+class ServletWebServerFactoryConfiguration {
+
+ @Configuration(proxyBeanMethods = false)
+ // Ìõ¼þ×¢½â£¬Ìõ¼þ´æÔÚʱ²ÅÒýÈë
+ @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
+ // ×¢Òâ ServletWebServerFactory£¬ÎÒÃÇ¿ÉÒÔ×ÔÖ÷ʵÏÖ tomcat ÈÝÆ÷µÄ×°Åä
+ @ConditionalOnMissingBean(value = ServletWebServerFactory.class,
+ search = SearchStrategy.CURRENT)
+ public static class EmbeddedTomcat {
+
+ @Bean
+ public TomcatServletWebServerFactory tomcatServletWebServerFactory(
+ ObjectProvider connectorCustomizers,
+ ObjectProvider contextCustomizers,
+ ObjectProvider> protocolHandlerCustomizers) {
+ TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
+ // ÅäÖÃһЩ²ÎÊý
+ factory.getTomcatConnectorCustomizers()
+ .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
+ factory.getTomcatContextCustomizers()
+ .addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
+ factory.getTomcatProtocolHandlerCustomizers()
+ .addAll(protocolHandlerCustomizers.orderedStream()
+ .collect(Collectors.toList()));
+ return factory;
+ }
+
+ }
+
+ ...
+}
+
+```
+
+Õâ¸öÀàÖ÷Òª¾ÍÊÇ·µ»Ø `TomcatServletWebServerFactory` bean£¬¿ÉÒÔ×¢ÈëһЩ `connectorCustomizers`¡¢`contextCustomizers`¡¢`protocolHandlerCustomizers` µÈ²ÎÊý½øÐÐ×Ô¶¨ÒåÅäÖã¬ÕâЩ²ÎÊý¾ÍÊÇ´Ó `BeanPostProcessorsRegistrar` ÖÐÀ´µÄ¡£
+
+ÕâÀïÓиöµØ·½ÐèÒªÌáһϣ¬Èç¹û²»ÏëʹÓà springboot ÌṩµÄ `TomcatServletWebServerFactory`£¬ÎÒÃÇ¿ÉÒÔ×Ô¼ºÊµÏÖ `TomcatServletWebServerFactory`£¬ÏñÕâÑù£º
+
+```
+@Bean
+public ServletWebServerFactory servletWebServerFactory() {
+ TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
+ // ´¦Àí×Ô¶¨ÒåµÄ¸÷ÖÖÅäÖÃ
+ ...
+ return tomcat;
+}
+
+```
+
+ÕâÑù´¦ÀíÖ®ºó£¬springboot ÌṩµÄ `tomcatServletWebServerFactory` ¾Í²»»á´¦ÀíÁË¡£
+
+ÆäËûÁ½¸öÀà `EmbeddedJetty`¡¢`EmbeddedUndertow`£¬¸ú `EmbeddedTomcat` µÄ´¦Àí»ù±¾ÏàËÆ£¬¾Í²»¶à˵ÁË¡£
+
+### 3. `DispatcherServletAutoConfiguration`
+
+ÎÒÃÇÔÙÀ´¿´¿´ `DispatcherServletAutoConfiguration`£¬¹Ø¼ü´úÂëÈçÏ£º
+
+```
+public class DispatcherServletAutoConfiguration {
+
+ public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
+
+ public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME
+ = "dispatcherServletRegistration";
+
+ @Configuration(proxyBeanMethods = false)
+ @Conditional(DefaultDispatcherServletCondition.class)
+ @ConditionalOnClass(ServletRegistration.class)
+ @EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
+ protected static class DispatcherServletConfiguration {
+
+ /**
+ * ´óÃû¶¦¶¦µÄ DispatcherServlet.
+ * @param httpProperties httpÊôÐÔ.
+ * @param webMvcProperties webMvc ÊôÐÔ.
+ * @return ·µ»Ø¶ÔÏó
+ */
+ @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
+ public DispatcherServlet dispatcherServlet(HttpProperties httpProperties,
+ WebMvcProperties webMvcProperties) {
+ DispatcherServlet dispatcherServlet = new DispatcherServlet();
+ dispatcherServlet.setDispatchOptionsRequest(
+ webMvcProperties.isDispatchOptionsRequest());
+ dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
+ dispatcherServlet.setThrowExceptionIfNoHandlerFound(
+ webMvcProperties.isThrowExceptionIfNoHandlerFound());
+ dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
+ dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails());
+ return dispatcherServlet;
+ }
+
+ /**
+ * ÎļþÉÏ´«×é¼þ.
+ * @param resolver ²ÎÊý.
+ * @return ·µ»ØÖµ.
+ */
+ @Bean
+ @ConditionalOnBean(MultipartResolver.class)
+ @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
+ public MultipartResolver multipartResolver(MultipartResolver resolver) {
+ return resolver;
+ }
+
+ }
+
+ /**
+ * Éú³É DispatcherServletRegistrationBean
+ * Ëü»á½«dispatcherServlet×¢²áµ½servletÈÝÆ÷
+ */
+ @Configuration(proxyBeanMethods = false)
+ @Conditional(DispatcherServletRegistrationCondition.class)
+ @ConditionalOnClass(ServletRegistration.class)
+ @EnableConfigurationProperties(WebMvcProperties.class)
+ @Import(DispatcherServletConfiguration.class)
+ protected static class DispatcherServletRegistrationConfiguration {
+
+ @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
+ @ConditionalOnBean(value = DispatcherServlet.class,
+ name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
+ public DispatcherServletRegistrationBean dispatcherServletRegistration(
+ DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties,
+ ObjectProvider multipartConfig) {
+ // Éú³É DispatcherServletRegistrationBean£¨Ëü»á½«dispatcherServlet×¢²áµ½servletÈÝÆ÷£©
+ DispatcherServletRegistrationBean registration =
+ new DispatcherServletRegistrationBean(dispatcherServlet,
+ webMvcProperties.getServlet().getPath());
+ registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
+ registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
+ multipartConfig.ifAvailable(registration::setMultipartConfig);
+ return registration;
+ }
+
+ }
+
+ ...
+
+}
+
+```
+
+ËüÖ÷ÒªÊÇ×¢²áÁË 3 ¸ö bean£º
+
+* `dispatcherServlet`£ºspringMvc µÄÇëÇóÈë¿Ú£¬url ÇëÇóÓɴ˽øÈ룬Ȼºóת»¯µ½ `requestMapping`
+* `multipartResolver`£º´¦ÀíÎļþÉÏ´«
+* `dispatcherServletRegistration`£º´¦Àí `dispatcherServlet` µÄ×¢²á£¬Ëü»á½« `dispatcherServlet` ×¢²áµ½ servlet ÈÝÆ÷ÖУ¨¹ØÓÚ springboot ×¢²á servlet ×é¼þµÄÄÚÈÝ£¬¿ÉÒԲο¼ [springboot web Ó¦ÓÃÖ® servlet ×é¼þµÄ×¢²áÁ÷³Ì](https://my.oschina.net/funcy/blog/4951050)£©
+
+### 4. `WebMvcAutoConfiguration`
+
+¼ÌÐø¿´ `WebMvcAutoConfiguration`:
+
+```
+@Configuration(proxyBeanMethods = false)
+...
+// Èç¹ûûÓÐ×Ô¶¨ÒåWebMvcµÄÅäÖÃÀ࣬ÔòʹÓñ¾ÅäÖÃ
+@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
+...
+public class WebMvcAutoConfiguration {
+ ...
+}
+
+```
+
+`WebMvcAutoConfiguration` ÉÏÓиö×¢½âÐèҪעÒâÏ£º
+
+```
+@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
+
+```
+
+ÕâÐдúÂë±íÃ÷ÁË `WebMvcAutoConfiguration` Ö»ÓÐÔÚ `WebMvcConfigurationSupport` ÀàÐ굀 bean ²»´æÔÚʱ£¬Ëü²Å»á½øÐÐ×Ô¶¯×°Åä¡£
+
+`WebMvcConfigurationSupport` ÊǸöɶĨ£¿ÔÚ [springmvc demo Óë @EnableWebMvc ×¢½â](https://my.oschina.net/funcy/blog/4696657)Ò»ÎÄÖУ¬ÎÒÃÇÌáµ½ÒýÈë springMvc ×é¼þµÄÁ½ÖÖ·½Ê½£º
+
+* ʹÓà `@EnableWebMvc` ×¢½â
+* ¼Ì³Ð `WebMvcConfigurationSupport` Àà
+
+¶øÕâÖÖ·½·¨×îÖÕ¶¼»áÏò spring ÈÝÆ÷ÖÐÒýÈëÀàÐÍΪ `WebMvcConfigurationSupport` µÄ bean£¬Òò´ËÔÚ `springboot` ÏîÄ¿ÖУ¬Èç¹ûÎÒÃǽøÐÐÁËÒÔÉÏÁ½ÖÖ²Ù×÷Ö®Ò»£¬ÄÇô¾ÍÒýÈëÁË `WebMvcConfigurationSupport`£¬`WebMvcAutoConfiguration` µÄ×Ô¶¯×°Åä¾Í²»Ö´ÐÐÁË¡£
+
+ÎÒÃÇÔÙÀ´¿´¿´ `WebMvcAutoConfiguration` ×°ÅäµÄ bean¡£
+
+#### 4.1 `WebMvcAutoConfigurationAdapter`
+
+`WebMvcAutoConfigurationAdapter` ÊÇ `WebMvcAutoConfiguration` µÄÄÚ²¿À࣬¶¨ÒåÈçÏ£º
+
+```
+@Configuration(proxyBeanMethods = false)
+// ÒýÈëÁË EnableWebMvcConfiguration
+@Import(EnableWebMvcConfiguration.class)
+@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
+@Order(0)
+public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
+ ...
+}
+
+```
+
+ËüʵÏÖÁË `WebMvcConfigurer`£¬ÇÒÒýÈëÁË `EnableWebMvcConfiguration`¡£`WebMvcConfigurer` ¿ÉÒÔÓÃÀ´´¦Àí springMvc µÄÅäÖã¬Ö»ÐèÒªÖØÐ´ÆäÖжÔÓ¦µÄ·½·¨¼´¿É£¬`EnableWebMvcConfiguration` ´ÓÃû³ÆÀ´¿´£¬ÊÇ ¡°ÆôÓà webMvc ÅäÖá±£¬ËüÒ²ÊÇ `WebMvcAutoConfiguration` µÄÄÚ²¿À࣬ÎÒÃÇÀ´¿´¿´Ëü×öÁËɶ£º
+
+```
+@Configuration(proxyBeanMethods = false)
+public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration
+ implements ResourceLoaderAware {
+ ...
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬ËüÊÇ `DelegatingWebMvcConfiguration` µÄ×ÓÀ࣬¶ø `DelegatingWebMvcConfiguration` ÓÖÊǸöɶĨ£¿ÎÒÃÇÒ²À´¿´¿´ËüµÄ¶¨Ò壺
+
+```
+@Configuration(proxyBeanMethods = false)
+public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
+ ...
+}
+
+```
+
+`DelegatingWebMvcConfiguration` ÊÇÓÉ springMvc ÌṩµÄ£¬¿ÉÒÔ¿´µ½£¬ËüʵÏÖÁË `WebMvcConfigurationSupport`£¬Òò´Ë£¬springboot ͨ¹ý `@Import(EnableWebMvcConfiguration.class)` µÄ·½Ê½Ïò spring ÈÝÆ÷ÖÐÒýÈëÁË `WebMvcConfigurationSupport` ÀàÐ굀 bean¡£
+
+ÊÂʵÉÏ£¬`DelegatingWebMvcConfiguration` ÕýÊÇ `@EnableWebMvc` ÒýÈëµÄ bean£º
+
+```
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+// ÒýÈëÁË DelegatingWebMvcConfiguration
+@Import(DelegatingWebMvcConfiguration.class)
+public @interface EnableWebMvc {
+ ...
+}
+
+```
+
+springbot ²»Ö±½ÓÒýÈë `DelegatingWebMvcConfiguration` ¶øÊÇÒýÈëËüµÄ×ÓÀà `EnableWebMvcConfiguration`£¬ËäÈ»ËüÊÇ×öÁËһЩ×Ô¶¨ÒåÅäÖõġ£
+
+¹ØÓÚ `EnableWebMvcConfiguration` ÅäÖÃÁËЩɶ£¬ÎÒÃÇÒ»»áÔÙ·ÖÎö£¬¼ÌÐø·ÖÎö `WebMvcAutoConfigurationAdapter` µÄÒýÈë bean£º
+
+```
+/**
+ * http ÏûϢת»»Æ÷.
+ */
+@Override
+public void configureMessageConverters(List> converters) {
+ this.messageConvertersProvider.ifAvailable(
+ (customConverters) -> converters.addAll(customConverters.getConverters()));
+}
+
+/**
+ * ÊÓͼ½âÎöÆ÷.
+ */
+@Bean
+@ConditionalOnMissingBean
+public InternalResourceViewResolver defaultViewResolver() {
+ InternalResourceViewResolver resolver = new InternalResourceViewResolver();
+ resolver.setPrefix(this.mvcProperties.getView().getPrefix());
+ resolver.setSuffix(this.mvcProperties.getView().getSuffix());
+ return resolver;
+}
+
+@Bean
+@ConditionalOnBean(View.class)
+@ConditionalOnMissingBean
+public BeanNameViewResolver beanNameViewResolver() {
+ BeanNameViewResolver resolver = new BeanNameViewResolver();
+ resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
+ return resolver;
+}
+
+@Bean
+@ConditionalOnBean(ViewResolver.class)
+@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
+public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
+ ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
+ resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));
+ resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
+ return resolver;
+}
+
+/**
+ * ÒýÈë¹ú¼Ê»¯ÅäÖÃ.
+ */
+@Bean
+@ConditionalOnMissingBean
+@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
+public LocaleResolver localeResolver() {
+ if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
+ return new FixedLocaleResolver(this.mvcProperties.getLocale());
+ }
+ AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
+ localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
+ return localeResolver;
+}
+
+/**
+ * ¾²Ì¬×ÊÔ´Ó³Éä
+ */
+@Override
+public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ if (!this.resourceProperties.isAddMappings()) {
+ logger.debug("Default resource handling disabled");
+ return;
+ }
+ // Ó³Éäwebjars
+ Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
+ CacheControl cacheControl = this.resourceProperties.getCache()
+ .getCachecontrol().toHttpCacheControl();
+ if (!registry.hasMappingForPattern("/webjars/**")) {
+ customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
+ .addResourceLocations("classpath:/META-INF/resources/webjars/")
+ .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
+ }
+ // Ó³É侲̬×ÊԴ·¾¶
+ String staticPathPattern = this.mvcProperties.getStaticPathPattern();
+ if (!registry.hasMappingForPattern(staticPathPattern)) {
+ customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
+ // staticLocations ĬÈÏΪ classpath:[/META-INF/resources/,
+ // /resources/, /static/, /public/]
+ .addResourceLocations(getResourceLocations(
+ this.resourceProperties.getStaticLocations()))
+ .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
+ }
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`WebMvcAutoConfigurationAdapter` ÒýÈëÁËÈýÀà bean:
+
+1. http ÏûϢת»»Æ÷
+2. ÊÓͼ½âÎöÆ÷
+3. ¹ú¼Ê»¯ÅäÖÃ
+
+ÕâÀïÎÒÃÇÖØµãÀ´¿´¿´ `httpÏûϢת»»Æ÷`¡£ÔÚʹÓà springMvc ʱ£¬Í¨¹ýÔÚ `Controller` Àà»òÆäÖеķ½·¨Éϱê¼Ç `@ResponseBody`£¬·µ»Ø²ÎÊý¾Í»áת»»Îª json£¬Õâ¾ÍÊÇ `httpÏûϢת»»Æ÷`Ëù×öµÄ¹¤×÷ÁË¡£springboot ĬÈ쵀 jaon ´¦ÀíÊÇ `jackson`£¬ËüµÄʵÀý»¯ÔÚ `JacksonAutoConfiguration` ÖУ¬×°ÅäΪ `HttpMessageConverter` µÄ´¦ÀíÔÚ `JacksonHttpMessageConvertersConfiguration`£¬ÕâÀï¾Í²»Õ¹¿ªÁË¡£
+
+ÔÚÉÏÃæ µÄ·ÖÎöÖУ¬¶à´Î³öÏÖÁË `WebMvcProperties` ÅäÖã¬ÎÒÃÇÀ´¿´¿´ËüÊǸöɶ£º
+
+```
+@ConfigurationProperties(prefix = "spring.mvc")
+public class WebMvcProperties {
+ ...
+}
+
+```
+
+ºÜÃ÷ÏÔ£¬ËüÊǸöÅäÖÃÀà £¬¿ÉÒÔ¿´µ½£¬ËüµÄÅäÖÃǰ׺Ϊ `spring.mvc`£¬Ö§³ÖµÄÅäÖÃÈçÏ£º
+
+
+
+#### 4.2 `EnableWebMvcConfiguration`
+
+ÎÒÃÇÀ´¿´¿´ `EnableWebMvcConfiguration` ×Ô¶¨ÒåµÄÅäÖãº
+
+```
+public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration
+ implements ResourceLoaderAware {
+
+ /**
+ * ÅäÖÃÊÊÅäÆ÷
+ */
+ @Bean
+ @Override
+ public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
+ @Qualifier("mvcContentNegotiationManager")
+ ContentNegotiationManager contentNegotiationManager,
+ @Qualifier("mvcConversionService") FormattingConversionService conversionService,
+ @Qualifier("mvcValidator") Validator validator) {
+ RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(
+ contentNegotiationManager, conversionService, validator);
+ adapter.setIgnoreDefaultModelOnRedirect(this.mvcProperties == null
+ || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
+ return adapter;
+ }
+
+ /**
+ * ·¾¶Ó³Éä
+ */
+ @Bean
+ @Primary
+ @Override
+ public RequestMappingHandlerMapping requestMappingHandlerMapping(
+ @Qualifier("mvcContentNegotiationManager")
+ ContentNegotiationManager contentNegotiationManager,
+ @Qualifier("mvcConversionService") FormattingConversionService conversionService,
+ @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
+ // Must be @Primary for MvcUriComponentsBuilder to work
+ return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
+ resourceUrlProvider);
+ }
+
+ /**
+ * »¶ÓÒ³
+ */
+ @Bean
+ public WelcomePageHandlerMapping welcomePageHandlerMapping(
+ ApplicationContext applicationContext,
+ FormattingConversionService mvcConversionService,
+ ResourceUrlProvider mvcResourceUrlProvider) {
+ WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
+ new TemplateAvailabilityProviders(applicationContext), applicationContext,
+ getWelcomePage(), this.mvcProperties.getStaticPathPattern());
+ welcomePageHandlerMapping.setInterceptors(getInterceptors(
+ mvcConversionService, mvcResourceUrlProvider));
+ return welcomePageHandlerMapping;
+ }
+
+ /**
+ * mvcÅäÖã¬Ìí¼ÓÁËÈÕÆÚ¸ñʽµÄ´¦Àí
+ */
+ @Bean
+ @Override
+ public FormattingConversionService mvcConversionService() {
+ WebConversionService conversionService
+ = new WebConversionService(this.mvcProperties.getDateFormat());
+ addFormatters(conversionService);
+ return conversionService;
+ }
+
+ /**
+ * ²ÎÊýУÑéÆ÷
+ */
+ @Bean
+ @Override
+ public Validator mvcValidator() {
+ if (!ClassUtils.isPresent("javax.validation.Validator", getClass().getClassLoader())) {
+ return super.mvcValidator();
+ }
+ return ValidatorAdapter.get(getApplicationContext(), getValidator());
+ }
+
+ /**
+ * Òì³£´¦Àí
+ */
+ @Override
+ protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResolver() {
+ if (this.mvcRegistrations != null
+ && this.mvcRegistrations.getExceptionHandlerExceptionResolver() != null) {
+ return this.mvcRegistrations.getExceptionHandlerExceptionResolver();
+ }
+ return super.createExceptionHandlerExceptionResolver();
+ }
+
+ @Override
+ protected void extendHandlerExceptionResolvers(
+ List exceptionResolvers) {
+ super.extendHandlerExceptionResolvers(exceptionResolvers);
+ if (this.mvcProperties.isLogResolvedException()) {
+ for (HandlerExceptionResolver resolver : exceptionResolvers) {
+ if (resolver instanceof AbstractHandlerExceptionResolver) {
+ ((AbstractHandlerExceptionResolver) resolver).setWarnLogCategory(
+ resolver.getClass().getName());
+ }
+ }
+ }
+ }
+ ...
+}
+
+```
+
+Ïà±ÈÓÚÔÉúµÄ springMvc£¬Ëü¶îÍâÅäÖÃÁËÊÊÅäÆ÷¡¢Â·¾¶Ó³Éä¡¢²ÎÊýУÑé¡¢Òì³£´¦ÀíµÈ¡£
+
+### 5\. ×ܽá
+
+1. `webMvc` ÔÚ×°Åäʱ£¬ÏÈ×°Åä `ServletWebServerFactoryAutoConfiguration`£¬ÔÙ×°Åä `DispatcherServletAutoConfiguration`£¬×îºó×°Åä `WebMvcAutoConfiguration`
+2. `ServletWebServerFactoryAutoConfiguration` ´¦Àí servlet ÈÝÆ÷µÄ×°Å䣬`DispatcherServletAutoConfiguration` ´¦Àí `DispatcherServlet` µÄ×°Å䣬`WebMvcAutoConfiguration` ´¦Àí `webMvc` ×é¼þ£¨ÏûϢת»»Æ÷¡¢ÊÓͼ½âÎöÆ÷¡¢¾²Ì¬×ÊÔ´Ó³ÉäµÈ£©µÄ×°Åä
+3. Èç¹ûÏò spring ÈÝÆ÷ÖÐÒýÈëÁË `WebMvcConfigurationSupport`£¬ `WebMvcAutoConfiguration` µÄ×°Åä²Ù×÷½«²»»áÖ´ÐÐ
+4. `servlet` µÄÏà¹ØÅäÖÃÒÔ `servlet` Ϊǰ׺£¬`webMvc` µÄÅäÖÃÒÔ `spring.mvc` Ϊǰ׺£¬ÎÒÃÇ¿ÉÒÔÔÚÅäÖÃÎļþ£¨Ò»°ãΪ `application.properties/application.yml`£©ÖнøÐÐÅäÖÃ
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4921595](https://my.oschina.net/funcy/blog/4921595) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\272\224\357\274\211\357\274\232\345\256\214\346\210\220\345\220\257\345\212\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\272\224\357\274\211\357\274\232\345\256\214\346\210\220\345\220\257\345\212\250.md"
new file mode 100644
index 0000000..8e6b041
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\272\224\357\274\211\357\274\232\345\256\214\346\210\220\345\220\257\345\212\250.md"
@@ -0,0 +1,108 @@
+ÉÏһƪÎÄÕÂ×ܽá springboot Æô¶¯Á÷³ÌÈçÏ£º
+
+
+
+½ÓÉÏÎÄ£¬ÎÒÃǼÌÐø·ÖÎö½ÓÏÂÀ´µÄ²½Öè¡£
+
+### 3.11 ˢкóµÄ´¦Àí
+
+ˢкóµÄ´¦Àí·½·¨Îª `SpringApplication#afterRefresh`£¬ÄÚÈÝÈçÏ£º
+
+```
+protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
+}
+```
+
+¿ÉÒÔ¿´µ½£¬ÕâÊÇÒ»¸ö¿Õ·½·¨£¬springboot ÌṩµÄÀ©Õ¹¡£
+
+### 3.12 ·¢²¼ `started` ʼþ
+
+¸Ã²Ù×÷µÄ·½·¨Îª `listeners.started(context)`£¬·¢²¼Âß¼Ç°ÃæÒѾ·ÖÎö¹ý£¬ÕâÀï¾Í²»ÔÙ·ÖÎöÁË¡£
+
+### 3.13 ÔËÐÐÆ÷»Øµ÷
+
+´¦ÀíÔËÐÐÆ÷µÄ·½·¨ÊÇ `SpringApplication#callRunners`£¬´úÂëÈçÏ£º
+
+```
+private void callRunners(ApplicationContext context, ApplicationArguments args) {
+ List runners = new ArrayList<>();
+ // »ñÈ¡ËùÓÐµÄ ApplicationRunner Óë CommandLineRunner
+ runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
+ runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
+ // ÅÅÐò
+ AnnotationAwareOrderComparator.sort(runners);
+ // ±éÀúµ÷ÓÃ
+ for (Object runner : new LinkedHashSet<>(runners)) {
+ // µ÷ÓÃ ApplicationRunner#run ·½·¨
+ if (runner instanceof ApplicationRunner) {
+ callRunner((ApplicationRunner) runner, args);
+ }
+ // µ÷ÓÃ CommandLineRunner#run ·½·¨
+ if (runner instanceof CommandLineRunner) {
+ callRunner((CommandLineRunner) runner, args);
+ }
+ }
+}
+
+/**
+ * µ÷ÓÃ ApplicationRunner#run ·½·¨
+ */
+private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
+ try {
+ (runner).run(args);
+ }
+ catch (Exception ex) {
+ throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
+ }
+}
+
+/**
+ * µ÷ÓÃ CommandLineRunner#run ·½·¨
+ */
+private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
+ try {
+ (runner).run(args.getSourceArgs());
+ }
+ catch (Exception ex) {
+ throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
+ }
+}
+```
+
+ÕâÁ½¸ö·½·¨±íʾ£¬springboot ΪÎÒÃÇÌṩÁËÁ½¸ö½Ó¿Ú£º`ApplicationRunner` Óë `CommandLineRunner`£¬ÎÒÃÇ¿ÉÒÔʵÏÖËüÀ´Íê³ÉһЩ²Ù×÷£¬Ó¦ÓÃʾÀýÈçÏ£º
+
+```
+/**
+ * ApplicationRunner ʾÀý
+ */
+@Component
+public class MyApplicationRunner implements ApplicationRunner {
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ System.out.println("MyApplicationRunner: hello world");
+ }
+}
+
+/**
+ * CommandLineRunner ʾÀý
+ */
+@Component
+public class MyCommandLineRunner implements CommandLineRunner {
+ @Override
+ public void run(String... args) throws Exception {
+ System.out.println("MyCommandLineRunner: hello world!");
+ }
+}
+```
+
+### 3.14 ÔËÐмàÌýÆ÷·½·¨£º `listeners.running(...)`
+
+Õâ¸ö·½·¨µÄÔËÐÐÍ¬Ç°Ãæ·ÖÎöµÄ `listeners.starting()` Ì×·һÑù£¬ÕâÀï¾Í²»·ÖÎöÁË¡£
+
+ºÃÁË£¬±¾ÎĵķÖÎö¾Íµ½ÕâÀïÁË£¬¹ØÓÚ springboot µÄÆô¶¯Á÷³ÌµÄ·ÖÎöÒ²µ½ÕâÀïÁË¡£
+
+
+
+------
+
+*±¾ÎÄÔÎÄÁ´½Ó£ºhttps://my.oschina.net/funcy/blog/4906553 £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£*
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\205\255\357\274\211\357\274\232\345\220\257\345\212\250\346\265\201\347\250\213\346\200\273\347\273\223.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\205\255\357\274\211\357\274\232\345\220\257\345\212\250\346\265\201\347\250\213\346\200\273\347\273\223.md"
new file mode 100644
index 0000000..8b2d0ee
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\205\255\357\274\211\357\274\232\345\220\257\345\212\250\346\265\201\347\250\213\346\200\273\347\273\223.md"
@@ -0,0 +1,41 @@
+Ç°Ãæ¼¸ÆªÎÄÕ·ÖÎö springboot µÄÆô¶¯Á÷³Ì£¬±¾ÎÄÀ´×ܽáÏ¡£
+
+ÎÄÕÂÒ»¿ªÊ¼£¬´Ó `SpringApplication.run(Demo01Application.class, args);` ´úÂëÈëÊÖ£¬×ÅÖØ·ÖÎöÁËÁ½¸ö·½·¨£º
+
+* `SpringApplication#SpringApplication(...)`
+* `SpringApplication#run(...)`
+
+ÕâÁ½¸ö·½·¨º¸ÇÁË springboot Æô¶¯µÄÕû¸öÁ÷³Ì£¬ÕâÀïÎÒÃÇÖðÒ»×ܽáÏ ¡£
+
+### `SpringApplication#SpringApplication(...)`
+
+Õâ¸ö·½·¨µÄÁ÷³ÌÈçÏ£º
+
+
+
+ÆäÖУ¬
+
+* `webApplicationType` »áÔÚºóÃæ¾ö¶¨´´½¨Ê²Ã´ÀàÐ굀 `applicationContext`£»
+* `Initialzers` À´×ÔÓÚ `META-INF/spring.factories`£¬»áÔÚ springboot Æô¶¯Ê±×öһЩ³õʼ»¯²Ù×÷£»
+* `Listteners` ͬÑùÀ´×ÔÓÚ `META-INF/spring.factories`£¬ÌṩÁ˶à¸ö·½·¨£¬¿ÉÒÔ·½±ãµØ¼àÌý springboot µÄÖ´Ðйý³Ì¡£
+
+### `SpringApplication#run(...)`
+
+Õⲿ·ÖµÄÁ÷³ÌÈçÏ£º
+
+
+
+ÆäÖУ¬
+
+* `getRunListener()` »á»ñÈ¡ËùÓÐµÄ `Listeners`£¬Ò²¾ÍÊÇÔÚ `SpringApplication#SpringApplication(...)` ÖÐ »ñÈ¡µÄ `Listeners`£¬`Listeners` ÖÐÌṩÁËÖÚ¶à·½·¨£¬¿É¼àÌý springboot µÄÆô¶¯Á÷³Ì£»
+* ×¼±¸ÔËÐл·¾³Ê±£¬»á¸ù¾Ý `webApplicationType` µÄÀàÐÍÀ´´´½¨¡¢ÅäÖ㬵õ½ÏàÓ¦ÀàÐ굀 `Environment` ¶ÔÏó£¬Õâ ¸ö¶ÔÏóºóÃæ»áÉèÖõ½ spring ÈÝÆ÷ÖУ¬spring ÈÝÆ÷ÖÐʹÓÃµÄ `Environment` ¾ÍÊÇÔÚÕâÀï´´½¨¼°ÅäÖõģ»
+* ´´½¨ ioc ÈÝÆ÷ʱ£¬Ò²ÊǸù¾Ý `webApplicationType` µÄÀàÐÍÀ´´´½¨¶ÔÓ¦µÄ `ApplicationContext`£»
+* ÔÚ×¼±¸ ioc ÈÝÆ÷µÄ·½·¨ÖУ¬»á¶Ô `ApplicationContext` ×öÒ»¸öÅäÖà £¬`Initializers` Ò²»áÔÚÕâÀïÔËÐУ»
+* Æô¶¯ ioc ÈÝÆ÷ʱ£¬springboot »á×¢²áÒ»¸ö shutdownhook£¬ÓÃÒÔÔÚÏîÄ¿¹Ø±Õʱ´¦Àí¹Ø±Õ²Ù×÷£¬ÁíÍ⣬¶ÔÓÚ ioc µÄÆô¶¯Á÷³Ì£¬springboot ÔÚÆäÀ©Õ¹Öлᴴ½¨¼°Æô¶¯ web ÈÝÆ÷£»
+* springboot ÌṩÁËÁ½ÖÖÀàÐ͵ÄÔËÐÐÆ÷£º`ApplicationRunner`¡¢`CommandLineRunner`£¬ÔÚÆô¶¯ºó»áµ÷ÓÃÁ½Õߵķ½·¨¡£
+
+ÒÔÉÏÄÚÈݽ²µÄ±È½Ï¼òÂÔ£¬Èç¹ûÒªÏêϸÁ˽⣬¿É×ÔÐÐÔĶÁÇ°ÃæµÄÎÄÕ¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4906588](https://my.oschina.net/funcy/blog/4906588) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\233\233\357\274\211\357\274\232\345\220\257\345\212\250IOC\345\256\271\345\231\250.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\233\233\357\274\211\357\274\232\345\220\257\345\212\250IOC\345\256\271\345\231\250.md"
new file mode 100644
index 0000000..507a1a5
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\233\233\357\274\211\357\274\232\345\220\257\345\212\250IOC\345\256\271\345\231\250.md"
@@ -0,0 +1,389 @@
+ÉÏһƪÎÄÕÂ×ܽá springboot Æô¶¯Á÷³ÌÈçÏ£º
+
+
+
+½ÓÉÏÎÄ£¬ÎÒÃǼÌÐø·ÖÎö½ÓÏÂÀ´µÄ²½Öè¡£
+
+### 3.10 ˢРioc ÈÝÆ÷
+
+½ÓÏÂÀ´ÎÒÃÇÀ´¿´¿´ `SpringApplication#refreshContext` ·½·¨£º
+
+```
+private void refreshContext(ConfigurableApplicationContext context) {
+ // Æô¶¯springÈÝÆ÷
+ refresh(context);
+ if (this.registerShutdownHook) {
+ try {
+ // ×¢²á ShutdownHook
+ context.registerShutdownHook();
+ }
+ catch (AccessControlException ex) {
+ // Not allowed in some environments.
+ }
+ }
+}
+
+```
+
+Õâ¸ö·½·¨²Ù×÷¾ÍÁ½¸ö£º
+
+1. `refresh(context)`£ºÆô¶¯ spring ÈÝÆ÷£¬Ò²²»Êǵ÷Óà `AbstractApplicationContext#refresh` ·½·¨£»
+2. `context.registerShutdownHook()`£º×¢²á `ShutdownHook`£¬¿ÉÒÔÔÚ jvm ½ø³Ì¹Ø±Õʱ´¦ÀíÒ»Ð©ÌØ¶¨µÄ²Ù×÷¡£
+
+#### 3.10.1 Æô¶¯ spring ÈÝÆ÷
+
+½øÈë `SpringApplication#refresh`£º
+
+```
+protected void refresh(ApplicationContext applicationContext) {
+ Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
+ // spring ÈÝÆ÷µÄÆô¶¯²Ù×÷ÁË
+ ((AbstractApplicationContext) applicationContext).refresh();
+}
+
+```
+
+Õâ¸ö·½·¨ºÜ¼òµ¥£¬ÏÈÅÐ¶Ï `applicationContext` µÄÀàÐÍÊÇ·ñΪ `AbstractApplicationContext`£¬È»ºóÔÙµ÷Óà `AbstractApplicationContext#refresh()`¡£
+
+¹ØÓÚ `AbstractApplicationContext#refresh()`£¬ÄÇ¿ÉÊÇ´óÃû¶¦¶¦°¡£¬¸Ã·½·¨º¸ÇÁË spring ÈÝÆ÷µÄÆô¶¯Á÷³Ì¡£ÓÉÓÚ±¾ÎIJ»ÊÇ·ÖÎö spring µÄÎÄÕ£¬Òò´ËÕâ¿é¾Í²»Õ¹¿ª·ÖÎöÁË£¬ÏëÒªÁ˽âµÄÆô¶¯Á÷³ÌµÄС»ï°é¿ÉÒԲο¼ÒÔÏÂÎÄÕ£º
+
+* [¡¾spring Ô´Âë·ÖÎö¡¿spring Æô¶¯Á÷³Ì£¨ËÄ£©£ºÆô¶¯Ç°µÄ×¼±¸¹¤×÷](https://my.oschina.net/funcy/blog/4633169)
+* [¡¾spring Ô´Âë·ÖÎö¡¿spring Æô¶¯Á÷³Ì£¨Î壩£ºÖ´ÐÐ BeanFactoryPostProcessor](https://my.oschina.net/funcy/blog/4641114)
+* [¡¾spring Ô´Âë·ÖÎö¡¿spring Æô¶¯Á÷³Ì£¨Áù£©£º×¢²á BeanPostProcessor](https://my.oschina.net/funcy/blog/4657181)
+* [¡¾spring Ô´Âë·ÖÎö¡¿spring Æô¶¯Á÷³Ì£¨Æß£©£º¹ú¼Ê»¯Óëʼþ´¦Àí](https://my.oschina.net/funcy/blog/4892120)
+* [¡¾spring Ô´Âë·ÖÎö¡¿spring Æô¶¯Á÷³Ì£¨°Ë£©£ºÍê³É BeanFactory µÄ³õʼ»¯](https://my.oschina.net/funcy/blog/4658230)
+* [¡¾spring Ô´Âë·ÖÎö¡¿spring Æô¶¯Á÷³Ì£¨¾Å£©£ºµ¥Àý bean µÄ´´½¨](https://my.oschina.net/funcy/blog/4659524)
+* [¡¾spring Ô´Âë·ÖÎö¡¿spring Æô¶¯Á÷³Ì£¨Ê®£©£ºÆô¶¯Íê³ÉµÄ´¦Àí](https://my.oschina.net/funcy/blog/4892555)
+
+ÔÚ `AbstractApplicationContext#refresh()` ÖУ¬spring ÌṩÁ˼¸¸öÀ©Õ¹µã£º
+
+
+
+ÎÒÃǵ±Ç°Ê¹ÓÃµÄ `applicationContext` Ϊ `AnnotationConfigServletWebServerApplicationContext`£¬ÆäÖÐҲʹÓÃÁËÕâЩÀ©Õ¹µã£¬ÎÒÃÇÖ÷Òª¹Ø×¢ÕâЩÀ©Õ¹µãµÄÓ¦Óá£
+
+##### 1\. Æô¶¯Ç°×¼±¸£º`prepareRefresh()`
+
+¾¹ýµ÷ÊÔ·¢ÏÖ£¬`initPropertySources()` ·½·¨»áÔËÐе½£¬µ÷ÓÃÁ´ÈçÏ£º
+
+```
+AbstractApplicationContext#refresh
+ |- AnnotationConfigServletWebServerApplicationContext#prepareRefresh
+ |- AbstractApplicationContext#prepareRefresh
+ |- GenericWebApplicationContext#initPropertySources
+
+```
+
+×îÖÕµ÷ÓõÄÊÇ `GenericWebApplicationContext#initPropertySources`£º
+
+```
+protected void initPropertySources() {
+ ConfigurableEnvironment env = getEnvironment();
+ if (env instanceof ConfigurableWebEnvironment) {
+ ((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, null);
+ }
+}
+
+```
+
+Õâ¸ö·½·¨ÀïÏÈ»ñÈ¡ `Environment`£¬È»ºóÅжÏÊÇ·ñΪ `ConfigurableWebEnvironment` µÄʵÀý£¬ÔÚÇ°Ãæ·ÖÎö**×¼±¸ÔËÐÐʱ»·¾³**ʱ£¬ÎÒÃǵõ½µÄ `Environment` Ϊ `StandardServletEnvironment`£¬ÊÇ `ConfigurableWebEnvironment` µÄ·ûºÏ£¬È»ºóµ÷Óà `ConfigurableWebEnvironment#initPropertySources` ·½·¨£¬½á¹ûµ½ÁË `StandardServletEnvironment#initPropertySources`£º
+
+```
+public void initPropertySources(@Nullable ServletContext servletContext,
+ @Nullable ServletConfigservletConfig) {
+ // Ìæ»»ÉÏÃæÉèÖÃµÄ servletContextInitParams Ϊ servletContext
+ // Ìæ»»ÉÏÃæÉèÖÃµÄ servletConfigInitParams Ϊ servletConfig
+ WebApplicationContextUtils.initServletPropertySources(getPropertySources(),
+ servletContext, servletConfig);
+}
+
+```
+
+Õâ¸ö·½·¨»¹ÊǺܼòµ¥£¬Ö»Êǽ« `servletContext` Óë `servletConfig` ÉèÖõ½ÁË `Environment` ÖС£
+
+##### 2\. »ñÈ¡ `beanFactory`: `obtainFreshBeanFactory()`
+
+µ±Ç° `applicationContext` ¶Ô¸Ã·½·¨ÎÞÀ©Õ¹£¬²»·ÖÎö¡£
+
+##### 3\. ×¼±¸ `beanFactory`: `prepareBeanFactory(beanFactory)`
+
+µ±Ç° `applicationContext` ¶Ô¸Ã·½·¨ÎÞÀ©Õ¹£¬²»·ÖÎö¡£
+
+##### 4\. À©Õ¹µã£º`postProcessBeanFactory(beanFactory)`
+
+`AnnotationConfigServletWebServerApplicationContext` ÖØÐ´ÁËÕâ¸ö·½·¨£º
+
+```
+@Override
+protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
+ // µ÷Óø¸ÀàµÄ·½·¨
+ super.postProcessBeanFactory(beanFactory);
+ // ½øÐаüɨÃ裬ÕâÀïµÄ°ü²¢²»´æÔÚ
+ if (this.basePackages != null && this.basePackages.length > 0) {
+ this.scanner.scan(this.basePackages);
+ }
+ // ×¢²ábean£¬Îª¿Õ
+ if (!this.annotatedClasses.isEmpty()) {
+ this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
+ }
+}
+
+```
+
+Õâ¸ö·½·¨µÄÖ´Ðйý³ÌÈçÏ£º
+
+1. µ÷ÓÃÁ˸¸ÀàµÄ·½·¨ `super.postProcessBeanFactory(beanFactory)`
+2. ½øÐаüɨÃ裬ͨ¹ýµ÷ÊÔ·¢ÏÖ£¬ÕâÀïµÄ `basePackages` Ϊ nul
+3. ×¢²á `annotatedClasses`£¬ÕâÀïµÄ `annotatedClasses` Ϊ¿Õ
+
+ÎÒÃÇÖ÷ÒªÀ´¿´¿´ `super.postProcessBeanFactory(beanFactory)`£¬¸Ã·½·¨ÔÚ `ServletWebServerApplicationContext` ÖУº
+
+```
+@Override
+protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
+ // Ìí¼ÓÒ»¸ö BeanPostProcessor
+ beanFactory.addBeanPostProcessor(
+ new WebApplicationContextServletContextAwareProcessor(this));
+ // ºöÂÔ ServletContextAware µÄ×Ô¶¯×¢Èë
+ beanFactory.ignoreDependencyInterface(ServletContextAware.class);
+ // ×¢²á web bean µÄ·¶Î§£¬ÕâÀï»á×¢²árequest¡¢session¡¢globalSessionµÄ×÷ÓÃÓò
+ registerWebApplicationScopes();
+}
+
+```
+
+Õâ¸ö·½·¨ÄÚÈݱȽϼòµ¥£¬Ö÷ÒªÊÇ×¢²á `BeanPostProcessor` ÒÔ¼°×¢²á `web bean` µÄ×÷Ó÷¶Î§¡£ÕâÀïÎÒÃÇÖ÷Òª¿´Ï `WebApplicationContextServletContextAwareProcessor` µÄ×÷Ó㬴úÂëÈçÏ£º
+
+```
+public class WebApplicationContextServletContextAwareProcessor
+ extends ServletContextAwareProcessor {
+
+ private final ConfigurableWebApplicationContext webApplicationContext;
+
+ public WebApplicationContextServletContextAwareProcessor(
+ ConfigurableWebApplicationContext webApplicationContext) {
+ Assert.notNull(webApplicationContext, "WebApplicationContext must not be null");
+ this.webApplicationContext = webApplicationContext;
+ }
+
+ /**
+ * »ñÈ¡ ServletContext
+ */
+ @Override
+ protected ServletContext getServletContext() {
+ ServletContext servletContext = this.webApplicationContext.getServletContext();
+ return (servletContext != null) ? servletContext : super.getServletContext();
+ }
+
+ /**
+ * »ñÈ¡ ServletConfig
+ */
+ @Override
+ protected ServletConfig getServletConfig() {
+ ServletConfig servletConfig = this.webApplicationContext.getServletConfig();
+ return (servletConfig != null) ? servletConfig : super.getServletConfig();
+ }
+
+}
+
+```
+
+Õâ¸öÀàËÆºõ²¢Ã»ÓÐ×öʲô£¬ÎÒÃÇÔÙ¸ú½ø¸¸À࣬ÓÉÓÚËüÊǸö `BeanPostProcessor`£¬ÎÒÃÇÖ÷Òª¹Ø×¢ËüµÄ `postProcessBeforeInitialization()` Óë `postProcessAfterInitialization()` Á½¸ö·½·¨£º
+
+```
+public class ServletContextAwareProcessor implements BeanPostProcessor {
+
+ ...
+
+ public Object postProcessBeforeInitialization(Object bean,
+ String beanName) throws BeansException {
+ // ÉèÖÃ ServletContext
+ if (getServletContext() != null && bean instanceof ServletContextAware) {
+ ((ServletContextAware) bean).setServletContext(getServletContext());
+ }
+ // ÉèÖÃ ServletConfig
+ if (getServletConfig() != null && bean instanceof ServletConfigAware) {
+ ((ServletConfigAware) bean).setServletConfig(getServletConfig());
+ }
+ return bean;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName) {
+ return bean;
+ }
+
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬Õâ¸ö `BeanPostProcessor` ÊÇÓÃÀ´´¦Àí `ServletContextAware` Óë `ServletConfigAware` Á½¸ö `Aware` ½Ó¿ÚµÄ£¬Ì×·ͬ´¦Àí `ApplicationAware`¡¢`BeanFactoryAware` µÈÒ»Ñù¡£
+
+##### 5\. Ö´ÐÐ `BeanFactoryPostProcessors`: `invokeBeanFactoryPostProcessors(beanFactory)`
+
+µ±Ç° `applicationContext` ¶Ô¸Ã·½·¨ÎÞÀ©Õ¹£¬²»·ÖÎö¡£
+
+ÖµµÃÒ»ÌáµÄÊÇ£¬ÔÚÕâ¸ö·½·¨ÖУ¬ÓиöÖØµÄ `BeanFactoryPostProcessor` »á±»Ö´ÐУº`ConfigurationClassPostProcessor`£¬springboot µÄ×Ô¶¯×°ÅäµÄÆôÓÃ×¢½â `@EnableAutoConfiguration` »áÔÚÕâÀï´¦Àí£¬×Ô¶¯×°ÅäÀàµÄ¼ÓÔØ¡¢Ìõ¼þ×¢½âÒ²ÊÇÔÚ `ConfigurationClassPostProcessor` ÖС£
+
+##### 6\. ×¢²á `BeanPostProcessor`: `registerBeanPostProcessors(beanFactory)`
+
+µ±Ç° `applicationContext` ¶Ô¸Ã·½·¨ÎÞÀ©Õ¹£¬²»·ÖÎö¡£
+
+##### 7\. ³õʼ»¯` MessageSource`(ÓÃÓÚ¹ú¼Ê»¯²Ù×÷): `initMessageSource()`
+
+µ±Ç° `applicationContext` ¶Ô¸Ã·½·¨ÎÞÀ©Õ¹£¬²»·ÖÎö¡£
+
+##### 8\. ³õʼ»¯Ê¼þ¹ã²¥Æ÷£º`initApplicationEventMulticaster()`
+
+µ±Ç° `applicationContext` ¶Ô¸Ã·½·¨ÎÞÀ©Õ¹£¬²»·ÖÎö¡£
+
+##### 9\. À©Õ¹µã£º`onRefresh()`
+
+µ±Ç° `applicationContext` ¶Ô¸Ã·½·¨µÄÀ©Õ¹Îª `ServletWebServerApplicationContext#onRefresh` ·½·¨£¬´úÂëÈçÏ£º
+
+```
+@Override
+protected void onRefresh() {
+ // µ÷Óø¸Àà·½·¨
+ super.onRefresh();
+ try {
+ // ´´½¨web·þÎñÆ÷£¬Èçtomcat,jettyµÈ
+ createWebServer();
+ }
+ catch (Throwable ex) {
+ throw new ApplicationContextException(...);
+ }
+}
+
+```
+
+¿ÉÒÔ ¿´µ½£¬web ·þÎñÆ÷ÊÇÔÚÕâ¸ö·½·¨Öд´½¨µÄ¡£²»¹ý web ·þÎñÆ÷µÄ´´½¨²¢²»¼òµ¥£¬ÐèÒª¾¹ý¶àÖÖÌõ¼þÅжϣ¬¹ØÓÚÕâµãÎÒÃǺóÃæÔÙÏêϸ˵Ã÷¡£
+
+##### 10\. ×¢²áʼþ¼àÌýÆ÷£º`registerListeners()`
+
+µ±Ç° `applicationContext` ¶Ô¸Ã·½·¨ÎÞÀ©Õ¹£¬²»·ÖÎö¡£
+
+##### 11\. ³õʼ»¯µ¥Àý `bean`: `finishBeanFactoryInitialization(beanFactory)`
+
+µ±Ç° `applicationContext` ¶Ô¸Ã·½·¨ÎÞÀ©Õ¹£¬²»·ÖÎö¡£
+
+##### 12\. Íê³ÉÆô¶¯²Ù×÷: `finishRefresh()`
+
+µ±Ç° `applicationContext` ¶Ô¸Ã·½·¨µÄÀ©Õ¹Îª `ServletWebServerApplicationContext#finishRefresh` ·½·¨£¬´úÂëÈçÏ£º
+
+```
+@Override
+protected void finishRefresh() {
+ super.finishRefresh();
+ // Æô¶¯webÈÝÆ÷
+ WebServer webServer = startWebServer();
+ if (webServer != null) {
+ // ·¢²¼ ServletWebServerInitializedEvent ʼþ
+ publishEvent(new ServletWebServerInitializedEvent(webServer, this));
+ }
+}
+
+/**
+ * Æô¶¯webÈÝÆ÷
+ */
+private WebServer startWebServer() {
+ WebServer webServer = this.webServer;
+ if (webServer != null) {
+ webServer.start();
+ }
+ return webServer;
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬ÕâÀï²ÅÊÇÕæÕýÆô¶¯ web ÈÝÆ÷¡£
+
+##### 13\. Çå³ý»º´æ: `resetCommonCaches()`
+
+µ±Ç° `applicationContext` ¶Ô¸Ã·½·¨ÎÞÀ©Õ¹£¬²»·ÖÎö¡£
+
+#### 3.10.2 ×¢²á `ShutdownHook`
+
+ÎÒÃÇÔÙÀ´¿´ `context.registerShutdownHook()`£¬¸Ã·½·¨ÓÉ `AbstractApplicationContext#registerShutdownHook` Ìṩ£º
+
+```
+public abstract class AbstractApplicationContext extends DefaultResourceLoader
+ implements ConfigurableApplicationContext {
+ ...
+ @Override
+ public void registerShutdownHook() {
+ if (this.shutdownHook == null) {
+ // Ö¸¶¨Ï̵߳ÄÃû×Ö
+ this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) {
+ @Override
+ public void run() {
+ synchronized (startupShutdownMonitor) {
+ // ÕâÀï¾ÍÊÇ ShutdownHook µÄÄÚÈÝ
+ doClose();
+ }
+ }
+ };
+ Runtime.getRuntime().addShutdownHook(this.shutdownHook);
+ }
+ }
+
+ /**
+ * ´¦ÀíÈÝÆ÷µÄ¹Ø±Õ²Ù×÷
+ */
+ protected void doClose() {
+ // Check whether an actual close attempt is necessary...
+ if (this.active.get() && this.closed.compareAndSet(false, true)) {
+ LiveBeansView.unregisterApplicationContext(this);
+
+ try {
+ // ·¢²¼¹Ø±Õʼþ
+ publishEvent(new ContextClosedEvent(this));
+ }
+ catch (Throwable ex) {
+ logger.warn(...);
+ }
+
+ // µ÷Óà lifecycle µÄ onClose() ·½·¨
+ if (this.lifecycleProcessor != null) {
+ try {
+ this.lifecycleProcessor.onClose();
+ }
+ catch (Throwable ex) {
+ logger.warn(...);
+ }
+ }
+
+ // Ïú»Ù bean
+ destroyBeans();
+
+ // ¹Ø±ÕÈÝÆ÷
+ closeBeanFactory();
+
+ // À©Õ¹µã£¬´ý×ÓÀàʵÏÖ
+ onClose();
+
+ // Çå³ý¼àÌýÆ÷
+ if (this.earlyApplicationListeners != null) {
+ this.applicationListeners.clear();
+ this.applicationListeners.addAll(this.earlyApplicationListeners);
+ }
+
+ // ÉèÖà active ±êʶ
+ this.active.set(false);
+ }
+ }
+
+ ...
+
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`context.registerShutdownHook()` ʵ¼ÊÉÏÊÇÔËÐÐÁË `doClose()` ·½·¨£¬ÓÃÀ´´¦ÀíÈÝÆ÷µÄ¹Ø±Õ²Ù×÷¡£¹Ø±Õ spring ÈÝÆ÷µÄ¹Ø±Õ£¬×¢ÊÍÒѾÏ൱Çå³þÁË£¬ÕâÀï¾Í²»ÉîÈëÁË¡£
+
+ºÃÁË£¬ÈÝÆ÷µÄÆô¶¯¾Í·ÖÎöµ½ÕâÀïÁË£¬´ÓÁ÷³ÌÉÏÀ´½²£¬Óë spring ÈÝÆ÷Æô¶¯µÄ×î´óÀ©Õ¹ÔÚÓÚ `onRefresh()` Óë `finishRefresh()`£¬Ç°Õß´´½¨ÁË `webServer` ÈÝÆ÷£¬ºóÕ߯ô¶¯ÁË `webServer` ÈÝÆ÷¡£
+
+
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4888129](https://my.oschina.net/funcy/blog/4888129) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\270\200\357\274\211\357\274\232\345\212\240\350\275\275\350\207\252\345\212\250\350\243\205\351\205\215\347\261\273.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\270\200\357\274\211\357\274\232\345\212\240\350\275\275\350\207\252\345\212\250\350\243\205\351\205\215\347\261\273.md"
new file mode 100644
index 0000000..2dbdfc7
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\270\200\357\274\211\357\274\232\345\212\240\350\275\275\350\207\252\345\212\250\350\243\205\351\205\215\347\261\273.md"
@@ -0,0 +1,456 @@
+×Ô¶¯×°ÅäÊÇ springboot µÄºËÐÄÖ®Ò»£¬±¾ÎĽ«À´Ì½¾¿ springboot ÊÇÈçºÎ¼ÓÔØ×Ô¶¯×°ÅäÀàµÄ¡£
+
+ÔÚ [@SpringBootApplication ×¢½â](https://my.oschina.net/funcy/blog/4870882)Ò»ÎÄÖУ¬ÎÒÃÇÌáµ½ springboot ´¦Àí×Ô¶¯×°ÅäµÄ×¢½âÊÇ `@EnableAutoConfiguration`£¬´úÂëÈçÏ£º
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+// ×Ô¶¯×°ÅäµÄ°ü
+@AutoConfigurationPackage
+// ÒýÈëµÄ×Ô¶¯×°ÅäÀà
+@Import(AutoConfigurationImportSelector.class)
+public @interface EnableAutoConfiguration {
+
+ String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
+
+ /**
+ * ¿É×ÔÐж¨ÒåÅųý×Ô¶¯×°ÅäµÄÀà
+ */
+ Class>[] exclude() default {};
+
+ /**
+ * ¿É×ÔÐж¨ÒåÅųý×Ô¶¯×°ÅäµÄÀàÃû
+ */
+ String[] excludeName() default {};
+
+}
+
+```
+
+ÒÔÉÏ´úÂë°üº¬Èý¸ö²¿·Ö£º
+
+1. `@AutoConfigurationPackage`£ºÖ¸¶¨×Ô¶¯×°ÅäµÄ°ü£»
+2. `@Import(AutoConfigurationImportSelector.class)`£ºÒýÈë×Ô¶¯×°ÅäµÄ´¦ÀíÀà `AutoConfigurationImportSelector`£¬Õâ¸öÀàÊÇ×Ô¶¯×°ÅäµÄ¹Ø¼üËùÔÚ£»
+3. `@EnableAutoConfiguration` µÄÊôÐÔ£º`@EnableAutoConfiguration` ÌṩÁËÁ½¸öÊôÐÔ£º`exclude` Óë `excludeName`£¬¿ÉÒÔÓÃÀ´Åųý²»ÐèÒª×Ô¶¯×°ÅäµÄÀà¡£
+
+±¾ÎÄÖØµãÀ´·ÖÎö `AutoConfigurationImportSelector` Àà¡£
+
+### 1. `AutoConfigurationImportSelector.AutoConfigurationGroup`
+
+`AutoConfigurationImportSelector` ʵÏÖÁË `DeferredImportSelector`£¬¹ØÓÚ `DeferredImportSelector` µÄ·ÖÎö£¬¿ÉÒԲο¼ [ConfigurationClassPostProcessor Ö®´¦Àí @Import ×¢½â](https://my.oschina.net/funcy/blog/4678152)£¬ÕâÀïÎÒÃÇÖ±½Ó¸ø³ö½áÂÛ£º
+
+* `DeferredImportSelector` ÊÇ `ImportSelector` µÄ×Ó½Ó¿Ú£¬ÆäÄÚ²¿ÓÐÒ»¸ö½Ó¿Ú `Group`£¬¸Ã½Ó¿Ú¶¨ÒåÁËÁ½¸ö·½·¨£º
+
+ ```
+ public interface DeferredImportSelector extends ImportSelector {
+ ...
+
+ interface Group {
+
+ /**
+ * ´¦Àíµ¼Èë²Ù×÷
+ */
+ void process(AnnotationMetadata metadata, DeferredImportSelector selector);
+
+ /**
+ * ·µ»Øµ¼ÈëÀà
+ */
+ Iterable selectImports()
+ }
+ }
+
+ ```
+
+ ÔÚ´¦Àí `DeferredImportSelector` µÄµ¼ÈëÀàʱ£¬`DeferredImportSelector.Group#process` ·½·¨»áÏȵ÷Óã¬È»ºóÔÙµ÷Óà `DeferredImportSelector.Group#selectImports` ·µ»Øµ¼ÈëÀࣻ
+
+* `DeferredImportSelector` ¿ÉÒÔÖ¸¶¨µ¼ÈëÀàµÄ·Ö×飬ÔÚ´¦Àíʱ£¬¿ÉÒÔ°´·Ö×é´¦Àíµ¼ÈëÀࣻ
+
+* `DeferredImportSelector` ÔÚ´¦Àíµ¼ÈëÀàʱ£¬ÏȽ«µ¼ÈëÀà°´·Ö×é·ÅÈëÒ»¸ö `map` ÖУ¬ÔÚ´¦ÀíÍêÆäËûÅäÖÃÀࣨspring µÄÅäÖÃÀàΪ `@Component`¡¢`@ComponentScan`¡¢`@Import`¡¢`@Configuration`¡¢`@Bean` ±ê¼ÇµÄÀࣩºóÔÙÀ´´¦Àí·Ö×éÖеĵ¼ÈëÀ࣬Ҳ¾ÍÊÇ˵£¬`DeferredImportSelector` µ¼ÈëµÄÀ࣬»áÔÚÆäËûÀà×¢²áµ½ `beanFactory` Öкó£¬ÔÙ½øÐÐ×¢²á£¨×¢²áǰ»¹ÐèÅжÏÄÜ·ñ×¢²áµ½ `beanFactory`£¬ÈôÄܲÅ×¢²á£©¡£
+
+ÎÒÃÇÀ´¿´¿´ `AutoConfigurationImportSelector` µÄ´úÂ룺
+
+```
+// ʵÏÖÁË DeferredImportSelector
+public class AutoConfigurationImportSelector implements DeferredImportSelector,
+ BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
+
+ ...
+
+ /**
+ * ÕâÀïʵÏÖÁË DeferredImportSelector.Group
+ */
+ private static class AutoConfigurationGroup implements DeferredImportSelector.Group,
+ BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
+
+ /**
+ * ±£´æµ¼ÈëµÄÀà
+ */
+ private final List autoConfigurationEntries = new ArrayList<>();
+
+ /**
+ * ´¦Àíµ¼ÈëÀà
+ */
+ @Override
+ public void process(AnnotationMetadata annotationMetadata,
+ DeferredImportSelector deferredImportSelector) {
+ Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
+ () -> String.format("Only %s implementations are supported, got %s",
+ AutoConfigurationImportSelector.class.getSimpleName(),
+ deferredImportSelector.getClass().getName()));
+ // 1\. µ÷Óà AutoConfigurationImportSelector#getAutoConfigurationEntry(...) ·½·¨£¬
+ // ÔÚÕâ¸ö·½·¨Àï»á¼ÓÔØ×Ô¶¯×°ÅäÀà
+ AutoConfigurationEntry autoConfigurationEntry =
+ ((AutoConfigurationImportSelector) deferredImportSelector)
+ .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
+ // 2\. ½«»ñÈ¡µ½µÄ autoConfigurationEntry ±£´æÆðÀ´
+ this.autoConfigurationEntries.add(autoConfigurationEntry);
+ for (String importClassName : autoConfigurationEntry.getConfigurations()) {
+ this.entries.putIfAbsent(importClassName, annotationMetadata);
+ }
+ }
+
+ /**
+ * ·µ»Øµ¼ÈëÀà
+ */
+ @Override
+ public Iterable selectImports() {
+ if (this.autoConfigurationEntries.isEmpty()) {
+ return Collections.emptyList();
+ }
+ // 3\. µÃµ½¹ýÂËÀà
+ Set allExclusions = this.autoConfigurationEntries.stream()
+ .map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream)
+ .collect(Collectors.toSet());
+ // 4\. ½« autoConfigurationEntries ת»»Îª LinkedHashSet
+ Set processedConfigurations = this.autoConfigurationEntries.stream()
+ .map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
+ .collect(Collectors.toCollection(LinkedHashSet::new));
+ // 5\. È¥³ýÐèÒª¹ýÂ˵ÄÀà
+ processedConfigurations.removeAll(allExclusions);
+ // 6\. ½øÐÐÅÅÐò
+ return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata())
+ .stream().map((importClassName) -> new Entry(
+ this.entries.get(importClassName), importClassName))
+ .collect(Collectors.toList());
+ }
+
+ ...
+ }
+
+}
+
+```
+
+ÕâÀïÎÒÃǽ« `DeferredImportSelector.Group#process` Óë `DeferredImportSelector.Group#selectImports` Á½¸ö·½·¨½áºÏÆðÀ´¿´£¬´¦Àí²½Öè×ܽáÈçÏÂ:
+
+1. µ÷Óà `AutoConfigurationImportSelector#getAutoConfigurationEntry(...)` ·½·¨¼ÓÔØ×Ô¶¯×°ÅäÀࣻ
+2. ½«µÃµ½µÄ×Ô¶¯×°ÅäÀà±£´æµ½ `autoConfigurationEntries` ÖУ»
+3. µÃµ½¹ýÂËÀ࣬ÕâЩ¹ýÂËÀà¾ÍÊÇÓÉ `@EnableAutoConfiguration` µÄ `exclude` »ò `excludeName` Ö¸¶¨µÄ£»
+4. ½« `autoConfigurationEntries` ת»»Îª `LinkedHashSet`£¬½á¹ûΪ `processedConfigurations`£»
+5. È¥³ý `processedConfigurations` ÐèÒª¹ýÂ˵ÄÀࣻ
+6. ½«µÚ 5 ²½µÃµ½µÄÀàÅÅÐòºó£¬·µ»Ø¡£
+
+½ÓÏÂÀ´ÎÒÃǶÔÕâЩ¹Ø¼ü²½Öè½øÐзÖÎö¡£
+
+> ÌØ±ð˵Ã÷£º`DeferredImportSelector` ÊÇ `ImportSelector` µÄ×Ó½Ó¿Ú£¬`ImportSelector` ´¦Àíµ¼ÈëÀàµÄ·½·¨ÊÇ `selectImports(...)`£¬ÔÚ `DeferredImportSelector` ÖÐÒ²ÖØÐ´Á˸÷½·¨£º
+>
+> 
+>
+> Õâ¸ö·½·¨Ëù×öµÄÒ²ÊǼÓÔØ×Ô¶¯×°ÅäÀ࣬·µ»Ø×îÖÕµ¼ÈëµÄÀ࣬µ«ÐèҪעÒâµÄÊÇ£¬springboot µÄ×Ô¶¯µ¼ÈëÀà**²»ÊÇ**ÔÚÕâÀï´¦ÀíµÄ£¬¹ØÓÚÕâµã£¬¿ÉÒÔÔÚ·½·¨ÄÚ´ò¸ö¶Ïµã£¬È»ºó¾Í»á·¢ÏÖÕâ¸ö·½·¨²¢Ã»ÓÐÔËÐе½£¡
+>
+> ×îºóÔÙÉùÃ÷Ï£ºspringboot µÄ×Ô¶¯µ¼ÈëÀà**²»ÊÇ**ÔÚ `AutoConfigurationImportSelector#selectImports` ·½·¨Öд¦ÀíµÄ£¬¶øÊÇÔÚ `AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports` ·½·¨Öд¦ÀíµÄ¡£
+
+### 2\. »ñȡװÅäÀࣺ`AutoConfigurationImportSelector#getAutoConfigurationEntry`
+
+×Ô¶¯ÅäÖà ÀàµÄ¼ÓÔØ´úÂëΪ£º
+
+```
+AutoConfigurationEntry autoConfigurationEntry =
+ ((AutoConfigurationImportSelector) deferredImportSelector)
+ .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
+
+```
+
+¸Ã´úÂë¾ÍÊÇÓÃÀ´¼ÓÔØ×Ô¶¯×°ÅäÀàµÄ£¬ÎÒÃÇÖ±½Ó½øÈë `AutoConfigurationImportSelector#getAutoConfigurationEntry` ·½·¨£º
+
+```
+protected AutoConfigurationEntry getAutoConfigurationEntry(
+ AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
+ // ÓÖÒ»´ÎÅжÏÊÇ·ñ¿ªÆô×Ô¶¯×°Åä
+ if (!isEnabled(annotationMetadata)) {
+ return EMPTY_ENTRY;
+ }
+ // »ñȡע½âµÄÊôÐÔ
+ AnnotationAttributes attributes = getAttributes(annotationMetadata);
+ // 1\. ¼ÓÔØºòÑ¡µÄ×Ô¶¯ÅäÖÃÀà
+ List configurations = getCandidateConfigurations(annotationMetadata, attributes);
+ // 2\. È¥ÖØ£¬×ª»»³Éset£¬ÔÙת»»³Élist
+ configurations = removeDuplicates(configurations);
+ // 3\. È¥³ýÐèÒªÅųýµÄÀ࣬Æäʵ¾ÍÊÇ´¦Àí@EnableAutoConfigurationµÄexcludeÓëexcludeName
+ Set exclusions = getExclusions(annotationMetadata, attributes);
+ checkExcludedClasses(configurations, exclusions);
+ configurations.removeAll(exclusions);
+ // 4\. ¹ýÂ˲»ÐèÒª×Ô¶¯×°ÅäµÄÀà
+ configurations = filter(configurations, autoConfigurationMetadata);
+ // 5\. ´¥·¢ AutoConfigurationImportEvent ʼþ
+ fireAutoConfigurationImportEvents(configurations, exclusions);
+ // 6\. ×îÖÕ·µ»ØµÄÖµ
+ return new AutoConfigurationEntry(configurations, exclusions);
+}
+
+```
+
+Õâ¸ö·½·¨·Ç³£ÖØÒª£¬°üº¬ÁË»ñÈ¡×Ô¶¯×°ÅäÀàµÄÈ«²¿²Ù×÷£¬¸Ã²Ù×÷Á÷³ÌÈçÏ£º
+
+1. ¼ÓÔØºòÑ¡µÄ×Ô¶¯×°ÅäÀ࣬springboot ×Ô¶¯×°ÅäµÄÀàλÓÚ `classpath` Ï嵀 `META-INF/spring.factories` ÎļþÖУ¬key Ϊ `org.springframework.boot.autoconfigure.EnableAutoConfiguration`£¬Õâ¸öÎÒÃǺóÃæÔÙÏêϸ·ÖÎö£»
+
+2. È¥³ýÖØ¸´µÄ×Ô¶¯×°ÅäÀ࣬ÉÏÒ»²½¼ÓÔØµÃµ½µÄ×Ô¶¯×°ÅäÀà¿ÉÄÜ»áÓÐÖØ¸´£¬ÔÚÕâÀï»áÈ¥³ýÖØ¸´µÄÀ࣬ȥ³ý·½Ê½Ò²·Ç³£¼òµ¥£¬springboot ¾ÍÖ»ÊÇÏÈת»»³É `Set`£¬ÔÙת»»³É `List`£»
+
+3. È¥³ýÅųýµÄÀà£¬Ç°ÃæÌáµ½ `@EnableAutoConfiguration` ¿ÉÒÔͨ¹ý `exclude` Óë `excludeName` Ö¸¶¨ÐèÒªÅųýµÄÀ࣬ÕâÒ»²½¾ÍÊÇÀ´´¦ÀíÕâÁ½¸öÊôÐԵģ»
+
+4. ¹ýÂ˲»ÐèÒª×Ô¶¯×°ÅäµÄÀ࣬¸ù¾Ý±¾È˵÷ÊÔ£¬·¢ÏÖ²¢Ã»ÓÐÍê³É¹ýÂË£º
+
+ ¹ýÂËǰÊÇ 124 ¸ö£º
+
+ 
+
+ ¹ýÂ˺ó»¹ÊÇ 124 ¸ö£º
+
+ 
+
+5. ´¥·¢ `AutoConfigurationImportEvent` ʼþ£»
+
+6. ½«µÚ 3 ²½µÃµ½µÄÅųýÀàÓëµÚ 4 ²½µÃµ½µÄ×Ô¶¯×°ÅäÀà°ü×°³É `AutoConfigurationEntry` ·µ»Ø¡£
+
+×¢Òâ×îºóÒ»ÐдúÂ룺
+
+```
+// 6\. ×îÖÕ·µ»ØµÄÖµ
+return new AutoConfigurationEntry(configurations, exclusions);
+
+```
+
+ÕâÀï°Ñ `configurations` Óë `exclusions` ¶¼´«ÈëÁË `AutoConfigurationEntry` µÄ¹¹Ôì·½·¨£¬ÎÒÃÇÀ´¿´¿´ `AutoConfigurationEntry`£º
+
+```
+protected static class AutoConfigurationEntry {
+ // ×Ô¶¯×°ÅäÀà
+ private final List configurations;
+
+ // ÐèÒªÅųýµÄ×Ô¶¯×°ÅäÀà
+ private final Set exclusions;
+
+ /**
+ * ¹¹Ôì·½·¨£¬¶ÔÔÙÕß½øÐи³Öµ
+ */
+ AutoConfigurationEntry(Collection configurations, Collection exclusions) {
+ this.configurations = new ArrayList<>(configurations);
+ this.exclusions = new HashSet<>(exclusions);
+ }
+
+ ...
+}
+
+```
+
+ÓÉЩ¿É¼û£¬×îÖÕ·µ»ØµÄ `AutoConfigurationEntry` °üº¬Á½´óÄÚÈÝ£º
+
+* `configurations`£º×Ô¶¯×°ÅäÀ࣬ÒѾȥ³ýÁËÐèÒªÅųýµÄÀà
+* `exclusions`£ºÍ¨¹ý `@EnableAutoConfiguration` Ö¸¶¨µÄÐèÒªÅųýµÄÀà
+
+Õû¸ö×Ô¶¯×°ÅäÀàµÄ»ñÈ¡¾ÍÊÇÕâÑùÁË£¬ÏÂÃæÎÒÃÇÀ´¿´¿´¼ÓÔØºòÑ¡µÄ×Ô¶¯×°ÅäÀàµÄÁ÷³Ì¡£
+
+### 3\. ¼ÓÔØºòÑ¡µÄ×Ô¶¯×°ÅäÀà
+
+×Ô¶¯×°ÅäÀàµÄ¼ÓÔØÎ»ÓÚ `AutoConfigurationImportSelector#getCandidateConfigurations`£¬´úÂëÈçÏ£º
+
+```
+protected List getCandidateConfigurations(AnnotationMetadata metadata,
+ AnnotationAttributes attributes) {
+ // µ÷ÓõÄÊÇ spring ÌṩµÄ·½·¨£ºSpringFactoriesLoader.loadFactoryNames(...)
+ // getSpringFactoriesLoaderFactoryClass() ·µ»ØµÄÊÇEnableAutoConfiguration
+ List configurations = SpringFactoriesLoader
+ .loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
+ Assert.notEmpty(configurations, "...");
+ return configurations;
+}
+
+protected Class> getSpringFactoriesLoaderFactoryClass() {
+ return EnableAutoConfiguration.class;
+}
+
+```
+
+¼ÌÐø½øÈë `SpringFactoriesLoader#loadFactoryNames`£º
+
+```
+public final class SpringFactoriesLoader {
+
+ public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
+
+ public static List loadFactoryNames(Class> factoryType, @Nullable ClassLoader classLoader) {
+ // µÃµ½µÄ factoryTypeName ÊÇ org.springframework.boot.autoconfigure.EnableAutoConfiguration
+ String factoryTypeName = factoryType.getName();
+ return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
+ }
+
+ /**
+ * ÔÚÕâÀï½øÐмÓÔØ£¬¼ÓÔØµÄÊÇ META-INF/spring.factories ÖеÄÊôÐÔ
+ */
+ private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
+ MultiValueMap result = cache.get(classLoader);
+ if (result != null) {
+ return result;
+ }
+
+ try {
+ // ¼ÓÔØ META-INF/spring.factories µÄÄÚÈÝ
+ Enumeration urls = (classLoader != null ?
+ classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
+ ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
+ result = new LinkedMultiValueMap<>();
+ while (urls.hasMoreElements()) {
+ URL url = urls.nextElement();
+ UrlResource resource = new UrlResource(url);
+ // ½« META-INF/spring.factories µÄÄÚÈÝת»»Îª Properties ¶ÔÏó
+ Properties properties = PropertiesLoaderUtils.loadProperties(resource);
+ for (Map.Entry, ?> entry : properties.entrySet()) {
+ String factoryTypeName = ((String) entry.getKey()).trim();
+ // StringUtils.commaDelimitedListToStringArray(...) ¶ººÅ·Ö¸îΪÊý×é
+ for (String factoryImplementationName :
+ StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
+ result.add(factoryTypeName, factoryImplementationName.trim());
+ }
+ }
+ }
+ cache.put(classLoader, result);
+ return result;
+ }
+ catch (IOException ex) {
+ throw new IllegalArgumentException("Unable to load factories from location [" +
+ FACTORIES_RESOURCE_LOCATION + "]", ex);
+ }
+ }
+ ...
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬ÕâÀï¼ÓÔØµÄÊÇ `classpath` Ï嵀 `META-INF/spring.factories` Îļþ£¬×¢Ò⣺Õâ¸öÎļþ¿ÉÄÜ»áÓжà¸ö£¬Î»ÓÚ²»Í¬µÄ jar °üÖС£
+
+springboot ×Ô´øµÄ `META-INF/spring.factories` λÓÚ `spring-boot-autoconfigure` Ä£¿éÏ£º
+
+
+
+ÎÒÃÇÀ´¿´Ò»ÑÛ `spring.factories`£º
+
+
+
+Õâ¸öÎļþ¶¨ÒåÁËÐí¶àµÄÅäÖÃÀ࣬ÒÔ `key-value` µÄÐÎʽ±£´æ£¬¶à¸öÖµÖ®¼äʹÓà ¡°,¡± ·Ö¿ª£¬ÉÏÃæÌáµ½µÄ×Ô¶¯×°ÅäÀàµÄ key ÊÇ `org.springframework.boot.autoconfigure.EnableAutoConfiguration`£¬¶ÔÓ¦µÄ `value` ·Ç³£¶à£¬ÕâÀï¾Í²»Õ¹Ê¾ÁË¡£
+
+ÕâÒ»²½Ö®ºó£¬×Ô¶¯×°ÅäÀà¾Í±»×¢²áµ½ spring ÈÝÆ÷ÖÐÁË¡£×¢£º´Ëʱ¼ÓÔØµ½ spring ÈÝÆ÷ÖеϹÊÇ `BeanDefinition`£¬ÒªÏë³ÉΪ spring bean£¬»¹µÃ¾¹ý `ConditionalOnBean`¡¢`ConditionalOnClass` µÈ×¢½âµÄ¿¼Ñ飬ÕâЩÎÒÃǺóÃæÔÙ·ÖÎö¡£
+
+### 4\. »ñÈ¡×Ô¶¯×°ÅäÀàºóµÄ´¦Àí
+
+ÈÃÎÒÃÇÔٻص½ `AutoConfigurationImportSelector.AutoConfigurationGroup`£¬ÔÚµÚ 1 ½ÚÎÒÃÇ×ܽáµÄÁ÷³ÌÈçÏ£º
+
+1. µ÷Óà `AutoConfigurationImportSelector#getAutoConfigurationEntry(...)` ·½·¨¼ÓÔØ×Ô¶¯×°ÅäÀࣻ
+2. ½«µÃµ½µÄ×Ô¶¯×°ÅäÀà±£´æµ½ `autoConfigurationEntries` ÖУ»
+3. µÃµ½¹ýÂËÀ࣬ÕâЩ¹ýÂËÀà¾ÍÊÇÓÉ `@EnableAutoConfiguration` µÄ `exclude` »ò `excludeName` Ö¸¶¨µÄ£»
+4. ½« `autoConfigurationEntries` ת»»Îª `LinkedHashSet`£¬½á¹ûΪ `processedConfigurations`£»
+5. È¥³ý `processedConfigurations` ÐèÒª¹ýÂ˵ÄÀࣻ
+6. ½«µÚ 5 ²½µÃµ½µÄÀàÅÅÐòºó£¬·µ»Ø¡£
+
+ÒÔÉÏµÚ 2 ½ÚÓëµÚ 3 ½Ú£¬·ÖÎöµÄÊÇ×Ô¶¯¼ÓÔØÀàµÄ¼ÓÔØ¹ý³Ì£¬ÎÒÃÇÔÙÀ´¿´¿´½ÓÏÂÀ´µÄ²½Öè¡£
+
+¶ÔÕÕ×Å´úÂ룬ÎÒÃǻᷢÏÖ½ÓÏÂÀ´µÄ²½Öè¶¼±È½Ï¼òµ¥£¬ÕâÀïÒ²Öðһ˵Ã÷ϰɡ£
+
+* µÚ 2 ²½£¬±£´æµÃµ½µÄ×Ô¶¯×°ÅäÀ࣬Õâ¸ö²Ù×÷½ö½öÖ»Êǵ÷ÓÃÁË `List#add(...)` ·½·¨£¬½«µÃµ½µÄ `autoConfigurationEntry` ±£´æµ½ `autoConfigurationEntries`£¬Õâ¸ö½á¹¹ÊÇ `AutoConfigurationGroup` µÄ³ÉÔ±±äÁ¿£¬ÔÚ `AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports` ·½·¨ÖлáÓõ½£»
+
+* µÚ 3 ²½£¬µÃµ½µÄÊÇËùÓеĹýÂËÀ࣬¸Ã¹ýÂËÀàÊDZéÀú `autoConfigurationEntries`£¬È»ºóͨ¹ý `autoConfigurationEntry#getExclusions` ·½·¨µÃµ½µÄ £¬Ç°ÃæÎÒÃÇÒ²Ìáµ½¹ý£¬`autoConfigurationEntry` Ö»°üº¬Á½¸ö³ÉÔ±±äÁ¿£º`configurations`(È¥³ýÅųýÀàºóµÄ×Ô¶¯×°ÅäÀà) Óë `exclusions`(ͨ¹ý `@EnableAutoConfiguration` Ö¸¶¨µÄÅųýÀà)£»
+
+* µÚ 4 ²½£¬½« `List` ת»»Îª `LinkedHashSet`£¬²»·ÖÎö£»
+
+* µÚ 5 ²½£¬¶ÔËùÓеÄ×Ô¶¯×°ÅäÀàÔÙ½øÐÐÒ»´ÎÈ¥³ýÅųýÀàµÄ²Ù×÷£¬ÅųýµÄ¶ÔÏóÊÇËùÓеÄÅųýÀ࣬ÕâÖÖÇé¿öÓ¦¸ÃÊÇ»á¶ÔͬһÏîÄ¿ÖÐÓжà¸ö `@EnableAutoConfiguration` µÄÇé¿ö£¬±ÈÈçµÚÒ»¸ö `@EnableAutoConfiguration` ×¢½âÅųý `A`¡¢`B` Á½¸öÀ࣬µÚ¶þ¸ö `@EnableAutoConfiguration` ×¢½âÅųý `C`£¬`D` Á½¸öÀ࣬ÄÇ×îÖÕÅųýµÄÊÇ `A`¡¢`B`¡¢`C`£¬`D` ËĸöÀࣻ
+
+* µÚ 6 ²½£¬ÕâÒ»²½µÄÖ÷Òª²Ù×÷ÊÇÅÅÐò£¬Õâ¸ö˳Ðò¾ö¶¨ÁË×Ô¶¯×°ÅäÀà×¢²áµ½ `beanFactory` ÖеÄ˳Ðò£¬`AutoConfigureOrder`¡¢`@AutoConfigureAfter` Óë `@AutoConfigureBefore` ¾ÍÊÇÔÚÕâÀï´¦ÀíµÄ£¬¹ØÓÚÕâ¿éÄÚÈÝ£¬¿ÉÒԲο¼ [springboot ×Ô¶¯×°ÅäÖ®×Ô¶¯×°Åä˳Ðò](https://my.oschina.net/funcy/blog/4921594).
+
+¾¹ýÕâЩ²½Öèºó£¬×Ô¶¯×°ÅäµÄ»ñÈ¡¾ÍÍê³ÉÁË¡£
+
+### 5\. ×Ô¶¨Òå×Ô¶¯×°ÅäÀà
+
+Á˽âÍê×Ô¶¯×°ÅäÀàµÄ¼ÓÔØ¹ý³Ìºó£¬ÎÒÃÇÒ²¿ÉÒÔ×Ô¶¨ÒåÒ»¸ö×Ô¶¯×°ÅäÀà¡£
+
+1. ×¼±¸Ò»¸ö×Ô¶¯×°ÅäÀà
+
+```
+@Configuration
+public class MyAutoConfiguration {
+
+ @Bean
+ public Object object() {
+ System.out.println("create object");
+ return new Object();
+ }
+}
+
+```
+
+Õâ¸öÀàºÜ¼òµ¥£¬¾ÍÊÇÒ»¸ö±ê¼ÇÁË `@Configuration` µÄÀ࣬ÀàÖÐʹÓà `@Bean` ×¢½â´´½¨ÁËÒ»¸ö bean£¬ÔÚ´´½¨ bean µÄ¹ý³ÌÖÐ»á ´òÓ¡ "create object"¡£
+
+1. ×¼±¸ `META-INF/spring.factories` ÄÚÈÝÈçÏ£º
+
+```
+# Auto Configure
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.springframework.boot.learn.autoconfigure.demo01.configure.MyAutoConfiguration
+
+```
+
+1. Ö÷Àà
+
+```
+@SpringBootApplication
+public class AutoconfigureDemo01Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AutoconfigureDemo01Application.class, args);
+ }
+
+}
+
+```
+
+ÔËÐнá¹ûÈçÏ£º
+
+
+
+¿ÉÒÔ¿´µ½£¬`create object` ³É¹¦´òÓ¡ÁË¡£
+
+ÄÇÕâ¸ö `bean` ÊÇͨ¹ý°üɨÃè´´½¨µÄ£¬»¹ÊÇ×Ô¶¯×°Åäµ¼ÈëµÄÄØ£¿ÎÒÃÇͨ¹ýµ÷ÊԵķ½Ê½À´¿´ÏÂ×Ô¶¯×°ÅäµÃµ½µÄÀࣺ
+
+
+
+¿ÉÒÔ¿´µ½£¬`MyAutoConfiguration` ¾ÍÔÚ×Ô¶¯×°ÅäÀàµÄÁбíÖÐÁË¡£
+
+×¢Òâµ½£¬`MyAutoConfiguration` ¼ÓÁË `@Configuration` ×¢½â£¬ ÄÇôËü¾¿¾¹ÊÇÓÉ sping ÈÝÆ÷ɨÃèµ½µÄ£¬»¹ÊÇÓÉ×Ô¶¯×°ÅäµÃµ½µÄÄØ£¿
+
+ÔÚ[¡¾springboot Ô´Âë·ÖÎö¡¿@SpringBootApplication ×¢½â](https://my.oschina.net/funcy/blog/4870882)Ò»ÎÄÖУ¬ÎÒÃÇÌáµ½ `SpringBootApplication` ×¢½âÖÐµÄ `@ComponentScan` »áÖ¸¶¨Ò»¸ö¹ýÂËÆ÷£º`AutoConfigurationExcludeFilter`£¬Õâ¸ö¹ýÂËÆ÷»á¹ýÂË×Ô¶¯×°ÅäÀ࣬ÕâÀïÎÒÃÇ¿´ÏÂĿǰΪֹ `beanFactory` ¶¼ÓÐÄÄЩ `beanName`£º
+
+
+
+¿ÉÒÔ¿´µ½£¬²¢Ã»ÓÐ `MyAutoConfiguration`£¬Òò´Ë´ËʱËü»¹Ã»±»É¨Ãè½ø `beanFactory` ÖС£
+
+µ±È»£¬ÎÒÃÇÒ²¿ÉÒÔ°Ñ `MyAutoConfiguration` ÉÏÃæµÄ `@Configuration` ×¢½âÈ¥µô£¬ÕâÑù¾Í²»»áÓÐÕâ¸öÀ§»óÁË¡£
+
+### 6\. ×ܽá
+
+±¾ÎÄ´Ó `@EnableAutoConfiguration` ×¢½â³ö·¢£¬·ÖÎöÁË×Ô¶¯×°ÅäÀàµÄ¼ÓÔØÁ÷³Ì£¬¼ÓÔØÁ÷³ÌÔÚ `AutoConfigurationImportSelector#getAutoConfigurationEntry` ·½·¨ÖУ¬×îÖÕ¼ÓÔØµÄÊÇ `META-INF/spring.factories` ÎļþÖÐ key ÊÇ `org.springframework.boot.autoconfigure.EnableAutoConfiguration` µÄÀà¡£
+
+µÃµ½×Ô¶¯×°ÅäÀàºó£¬spring »á½«Æä×¢²áµ½ÈÝÆ÷ÖУ¬´ËʱËüÃÇ»¹ÊÇÒ»¸öµÄ `BeanDefinition`£¬ÒªÏë³ÉΪ spring bean£¬»¹µÃ¾¹ý `ConditionalOnBean`¡¢`ConditionalOnClass` µÈ×¢½âµÄ¿¼Ñ飬ÕâЩÎÒÃǺóÃæÔÙ·ÖÎö¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4870868](https://my.oschina.net/funcy/blog/4870868) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\270\211\357\274\211\357\274\232\350\207\252\345\212\250\350\243\205\351\205\215\351\241\272\345\272\217.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\270\211\357\274\211\357\274\232\350\207\252\345\212\250\350\243\205\351\205\215\351\241\272\345\272\217.md"
new file mode 100644
index 0000000..03744e2
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\270\211\357\274\211\357\274\232\350\207\252\345\212\250\350\243\205\351\205\215\351\241\272\345\272\217.md"
@@ -0,0 +1,568 @@
+ÔÚ [springboot ×Ô¶¯×°ÅäÖ®Ìõ¼þ×¢½â£¨Ò»£©](https://my.oschina.net/funcy/blog/4918863)Ò»ÎÄÖУ¬ÔÚ·ÖÎö `@ConditionalOnBean/@ConditionalOnMissingBean` ×¢½âµÄÌõ¼þÅжÏʱ£¬¹Ù·½Ç¿ÁÒ½¨ÒéÎÒÃÇÔÚ×Ô¶¯×°ÅäÀàÖÐʹÓÃÕâÁ½¸ö×¢½â£¬²¢ÇÒ `@ConditionalOnBean/@ConditionalOnMissingBean` ±ê¼ÇµÄÀàÒªÔÚÖ¸¶¨µÄÀàÖ®ºó³õʼ»¯£¬ÄÇ springboot ÈçºÎÀ´¿ØÖÆ×Ô¶¯×°Åä˳ÐòÄØ£¿±¾ÎĽ«À´Ñо¿Ï¡£
+
+### 1\. springboot ´¦Àí×Ô¶¯×°ÅäÀàµÄ¹ý³Ì
+
+ÐèÒªÃ÷È·µÄÊÇ£¬±¾ÎÄ̽ÌÖµÄ`×Ô¶¯×°Åä˳Ðò`ÊÇÖ¸½« `class` ×¢²áµ½ `beanFactory` µÄ˳Ðò£¬springboot ´¦Àí×Ô¶¯×°ÅäÀàµÄ´óÖ¹ý³ÌÈçÏ£º
+
+1. ¼ÓÔØ×Ô¶¯×°ÅäÀ࣬ÔÚ [springboot ×Ô¶¯×°ÅäÖ®¼ÓÔØ×Ô¶¯×°ÅäÀà](https://my.oschina.net/funcy/blog/4870868) Ò»ÎÄÖÐÒÑ·ÖÎö¹ý£»
+2. ¶Ô×Ô¶¯×°ÅäÀà½øÐÐÅÅÐò£¬ÕâÊDZ¾ÎĽ«Òª·ÖÎöµÄÄÚÈÝ£»
+3. ±éÀú×Ô¶¯×°ÅäÀ࣬¶Ôÿ¸ö×Ô¶¯×°ÅäÀàÖðÒ»½øÐÐÒÔϲÙ×÷£º
+ 1. ¸ù¾ÝÌõ¼þ×¢½âÅжϵ±Ç°×Ô¶¯×°ÅäÀàÊÇ·ñÂú×ã×°ÅäÌõ¼þ£»
+ 2. Èç¹ûµ±Ç°×Ô¶¯×°ÅäÀàÂú×ì×°ÅäÌõ¼þ£¬×¢²áµ½ `beanFactory` ÖС£
+
+Ôٻص½ `@ConditionalOnBean/@ConditionalOnMissingBean`£¬¶ÔÈçÏÂÁ½¸ö×Ô¶¯×°ÅäÀࣺ
+
+```
+// AÊÇ×Ô¶¯×°ÅäÀà
+@Configuration
+public class A {
+ @Bean
+ @ConditionalOnMissingBean("b1")
+ public A1 a1() {
+ return new A1();
+ }
+}
+
+// BÊÇ×Ô¶¯×°ÅäÀà
+@Configuration
+public class B {
+ @Bean
+ public B1 b1() {
+ return new b1();
+ }
+}
+
+```
+
+`a1` Óë `b1` ÔÚÁ½¸ö²»Í¬µÄ×Ô¶¯×°ÅäÀàÖгõʼ»¯£¬ÇÒ `a1` Ö»ÓÐÔÚ `b1` ²»´æÔÚʱ£¬²Å»á³õʼ»¯£¬¸ù¾ÝÉÏÃæ×ܽáµÄ springboot ´¦Àí×Ô¶¯×°ÅäÀàµÄ²½Ö裬ÎÒÃÇÖ»ÒªÖ¸¶¨ `b1` ÔÚ `a1` ֮ǰ³õʼ»¯¾Í²»»á²úÉúÒì³£ÁË¡£
+
+ÄÇô£¬×Ô¶¯×°ÅäÀàµÄ˳ÐòÈçºÎÖ¸¶¨ÄØ£¿
+
+### 2\. ×Ô¶¯×°ÅäÀàµÄ˳Ðò¿ØÖÆ×¢½â
+
+springboot ΪÎÒÃÇÌṩÁËÁ½ÖÖ×Ô¶¯×°ÅäÀàµÄÅÅÐòÊֶΣº
+
+* ¾ø¶Ô×Ô¶¯×°Åä˳Ðò ¡ª¡ª`@AutoConfigOrder`
+* Ïà¶Ô×Ô¶¯×°Åä˳Ðò ¡ª¡ª`@AutoConfigureBefore` Óë `@AutoConfigureAfter`
+
+ÕâÈý¸ö×¢½â¾ÍÊÇÓÃÀ´´¦Àí×Ô¶¯×°ÅäÀàµÄÅÅÐòµÄÁË£¬`@AutoConfigOrder` Ö¸¶¨ÁË×°Åä˳Ðò£¬Í¬ spring ÌṩµÄ `@Order` ÀàËÆ£¬`@AutoConfigureBefore` Óë `@AutoConfigureAfter` ¿ÉÒÔÖ¸¶¨ `class`£¬±íʾÔÚÄĸö `class` ֮ǰ»òÖ®ºó×°Åä¡£
+
+»Øµ½Ê¾Àý£¬ÎÒÃÇ¿ÉÒÔÕâÑùÖ¸¶¨×°Åä˳Ðò£º
+
+```
+// AÊÇ×Ô¶¯×°ÅäÀà
+@Configuration
+// ÔÚB.classÖ®ºó×Ô¶¯×°Åä
+@AutoConfigureAfter(B.class)
+public class A {
+ @Bean
+ @ConditionalOnMissingBean("b1")
+ public A1 a1() {
+ ...
+ }
+}
+
+// BÊÇ×Ô¶¯×°ÅäÀà
+@Configuration
+public class B {
+ ...
+}
+
+```
+
+### 3\. ×Ô¶¯×°ÅäÀàµÄÅÅÐò
+
+Ç°ÃæÎÒÃÇÌáµ½£¬`@AutoConfigOrder`¡¢`@AutoConfigureBefore` Óë `@AutoConfigureAfter` ¿ÉÒÔ¿ØÖÆ×Ô¶¯×°ÅäÀàµÄ×°Åä˳Ðò£¬ÄÇôËüÃÇÊÇÔÚÄÄÀï½øÐÐÅÅÐòµÄÄØ£¿ÔÚ [springboot ×Ô¶¯×°ÅäÖ®¼ÓÔØ×Ô¶¯×°ÅäÀà](https://my.oschina.net/funcy/blog/4870868) Ò»ÎÄÖУ¬ÎÒÃÇÌá×ܽáÁË»ñÈ¡×Ô¶¯×°ÅäÀàµÄ²½ÖèÓÐ 6 ²½£º
+
+1. µ÷Óà `AutoConfigurationImportSelector#getAutoConfigurationEntry(...)` ·½·¨¼ÓÔØ×Ô¶¯×°ÅäÀࣻ
+2. ½«µÃµ½µÄ×Ô¶¯×°ÅäÀà±£´æµ½ `autoConfigurationEntries` ÖУ»
+3. µÃµ½¹ýÂËÀ࣬ÕâЩ¹ýÂËÀà¾ÍÊÇÓÉ `@EnableAutoConfiguration` µÄ `exclude` »ò `excludeName` Ö¸¶¨µÄ£»
+4. ½« `autoConfigurationEntries` ת»»Îª `LinkedHashSet`£¬½á¹ûΪ `processedConfigurations`£»
+5. È¥³ý `processedConfigurations` ÐèÒª¹ýÂ˵ÄÀࣻ
+6. ½«µÚ 5 ²½µÃµ½µÄÀàÅÅÐòºó£¬·µ»Ø¡£
+
+¶ø¶Ô×Ô¶¯×°ÅäÀàµÄÅÅÐòÕýÊÇÔÚµÚ 6 ²½£¬¶ÔÓ¦µÄ·½·¨ÊÇ `AutoConfigurationImportSelector.AutoConfigurationGroup#sortAutoConfigurations`£¬´úÂëÈçÏ£º
+
+```
+private List sortAutoConfigurations(Set configurations,
+ AutoConfigurationMetadata autoConfigurationMetadata) {
+ // ÏÈ´´½¨ÁË AutoConfigurationSorter ¶ÔÏó£¬
+ // È»ºóµ÷Óà AutoConfigurationSorter.getInPriorityOrder ½øÐÐÅÅÐò
+ return new AutoConfigurationSorter(getMetadataReaderFactory(), autoConfigurationMetadata)
+ .getInPriorityOrder(configurations);
+}
+
+```
+
+Õâ¸ö·½·¨µÄ´¦Àí·ÖΪÁ½²½£º
+
+1. ´´½¨ÁË `AutoConfigurationSorter` ¶ÔÏó
+2. µ÷ÓÃ `AutoConfigurationSorter.getInPriorityOrder` ½øÐÐÅÅÐò
+
+ÎÒÃÇÏÈÀ´¿´¿´ `AutoConfigurationSorter` µÄ´´½¨²Ù×÷£º
+
+```
+class AutoConfigurationSorter {
+
+ private final MetadataReaderFactory metadataReaderFactory;
+
+ private final AutoConfigurationMetadata autoConfigurationMetadata;
+
+ /**
+ * ¹¹Ôì·½·¨
+ * ½ö½öÖ»ÊǶԴ«ÈëµÄ²ÎÊý½øÐи³Öµ£¬½«ËûÃǸ³ÖµÎª³ÉÔ±±äÁ¿
+ */
+ AutoConfigurationSorter(MetadataReaderFactory metadataReaderFactory,
+ AutoConfigurationMetadata autoConfigurationMetadata) {
+ Assert.notNull(metadataReaderFactory, "MetadataReaderFactory must not be null");
+ this.metadataReaderFactory = metadataReaderFactory;
+ this.autoConfigurationMetadata = autoConfigurationMetadata;
+ }
+
+ ...
+
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`AutoConfigurationSorter` µÄ¹¹Ôì·½·¨²¢Ã»ÓÐ×öʲôʵÖÊÐԵIJÙ×÷£¬¿´À´ÅÅÐòµÄ¹Ø¼ü»¹µÃ¿´ `AutoConfigurationSorter.getInPriorityOrder` ·½·¨£¬¸Ã·½·¨µÄ´úÂëÈçÏ£º
+
+```
+List getInPriorityOrder(Collection classNames) {
+ // 1\. ½« classNames °ü×°³É AutoConfigurationClasses
+ AutoConfigurationClasses classes = new AutoConfigurationClasses(this.metadataReaderFactory,
+ this.autoConfigurationMetadata, classNames);
+ List orderedClassNames = new ArrayList<>(classNames);
+ // 2\. °´ÀàÃûÅÅÐò
+ Collections.sort(orderedClassNames);
+ // 3\. ʹÓà @AutoConfigureOrder ÅÅÐò
+ orderedClassNames.sort((o1, o2) -> {
+ int i1 = classes.get(o1).getOrder();
+ int i2 = classes.get(o2).getOrder();
+ return Integer.compare(i1, i2);
+ });
+ // 4\. ʹÓà @AutoConfigureBefore£¬@AutoConfigureAfter ÅÅÐò
+ orderedClassNames = sortByAnnotation(classes, orderedClassNames);
+ return orderedClassNames;
+}
+
+```
+
+´Ó´úÂëÀ´ ¿´£¬Õâ¸ö·½·¨µÄÖ´Ðв½ÖèÈçÏ£º
+
+1. ½« `classNames` °ü×°³É `AutoConfigurationClasses`
+2. °´ÀàÃûÅÅÐò
+3. ʹÓà `@AutoConfigureOrder` ÅÅÐò
+4. ʹÓà `@AutoConfigureBefore`£¬`@AutoConfigureAfter` ÅÅÐò
+
+Õâ¸ö·½·¨ÅÅÐò¹²½øÐÐÁË 3 ´Î£¬¶¼ÊÇ¶Ô `orderedClassNames` ½øÐÐÅÅÐò£¬ÕâÑùÒ»À´£¬ºóÃæµÄÅÅÐò»á´òÂÒÇ°ÃæµÄÅÅÐò£¬×îÏȵÄÅÅÐòÊǰ´ÀàÃûÅÅÐò£¬Ò²¾ÍÊÇ˵£¬Èç¹ûûÓÐÖ¸¶¨ `@AutoConfigureOrder`¡¢`@AutoConfigureBefore` µÈ×¢½â£¬¾Í»áʹÓÃÀàÃû½øÐÐÅÅÐò¡£
+
+½ÓÏÂÀ´ÎÒÃǾßÌå·ÖÎöÕ⼸¸ö²Ù×÷°É¡£
+
+### 4\. ½« `classNames` °ü×°³É `AutoConfigurationClasses`
+
+¸Ã²Ù×÷λÓÚ `AutoConfigurationSorter.AutoConfigurationClasses#AutoConfigurationClasses` ·½·¨£¬´úÂëÈçÏ£º
+
+```
+private static class AutoConfigurationClasses {
+
+ // ±£´æ½á¹û
+ private final Map classes = new HashMap<>();
+
+ /**
+ * ¹¹Ôì·½·¨
+ */
+ AutoConfigurationClasses(MetadataReaderFactory metadataReaderFactory,
+ AutoConfigurationMetadata autoConfigurationMetadata, Collection classNames) {
+ // ½øÐз½·¨µ÷ÓÃ
+ addToClasses(metadataReaderFactory, autoConfigurationMetadata, classNames, true);
+ }
+
+ /**
+ * Ìí¼ÓÀ࣬¾ÍÊǽ«Àà°ü×°³É AutoConfigurationClass£¬Ìí¼Óµ½ÃûΪ classes µÄ Map ÖÐ
+ * classNames ¾ÍÊÇÈ¥³ýÁËÅųýÀàµÄËùÓÐ×Ô¶¯×°ÅäÀà
+ */
+ private void addToClasses(MetadataReaderFactory metadataReaderFactory,
+ AutoConfigurationMetadata autoConfigurationMetadata, Collection classNames,
+ boolean required) {
+ for (String className : classNames) {
+ if (!this.classes.containsKey(className)) {
+ // ½« className °ü×°³É AutoConfigurationClass
+ AutoConfigurationClass autoConfigurationClass = new AutoConfigurationClass(
+ className, metadataReaderFactory, autoConfigurationMetadata);
+ boolean available = autoConfigurationClass.isAvailable();
+ // @AutoConfigureBefore Óë @AutoConfigureAfter ±ê¼ÇµÄÀàµÄ required Ϊ false
+ if (required || available) {
+ this.classes.put(className, autoConfigurationClass);
+ }
+ if (available) {
+ // µÝ¹éµ÷ÓÃ
+ addToClasses(metadataReaderFactory, autoConfigurationMetadata,
+ autoConfigurationClass.getBefore(), false);
+ addToClasses(metadataReaderFactory, autoConfigurationMetadata,
+ autoConfigurationClass.getAfter(), false);
+ }
+ }
+ }
+ }
+ ...
+}
+
+```
+
+´ÓÒÔÉÏ´úÂëÀ´¿´£¬
+
+* `AutoConfigurationClasses` °üº¬Ò»¸ö³ÉÔ±±äÁ¿£º`classes`£¬ÀàÐÍÊÇ `Map`£¬`key` ÊÇ `String`£¨Ò²¾ÍÊÇ `className`£©£¬`value` ÊÇ `AutoConfigurationClass`£¨Ò²¾ÍÊÇ `className` µÄ°üº¬Àࣩ;
+* `AutoConfigurationClasses` µÄ¹¹Ôì·½·¨»áµ÷Óà `addToClasses(...)` ¸Ã·½·¨»á±éÀú´«ÈëµÄ `classNames`£¬½«Æä°ü×°³É `AutoConfigurationClass` ºó£¬ÔÙ±£´æµ½ `classes` ÖС£
+
+ÔÚ·ÖÎö `addToClasses(...)` µÄ¾ßÌåÂ߼ǰ£¬ÎÒÃÇÏÈÀ´¿´¿´ `AutoConfigurationClass` ÊǸöɶ£º
+
+
+
+¿ÉÒÔ¿´µ½ £¬`AutoConfigurationClass` ÊÇÀàÃûµÄ°ü×°£¬²¢ÇÒ»¹±£´æÁË `@AutoConfigureBefore` Óë `@AutoConfigureAfter` Ö¸¶¨µÄÀ࣬ÒÔ¼°ÌṩÁ˸ú `@AutoConfigureOrder`¡¢ `@AutoConfigureBefore`¡¢`@AutoConfigureAfter` Ïà¹ØµÄһЩ·½·¨¡£
+
+ÎÒÃÇÔٻعýÍ·¿´ `addToClasses(...)` µÄÖ´ÐÐÁ÷³Ì£¬¸Ã·½·¨µÄÖ´ÐÐÁ÷³ÌÈçÏ£º
+
+1. ±éÀú´«ÈëµÄ `classNames`£¬¶ÔÆäÖÐÿһ¸ö `className`£¬½øÐÐÏÂÃæµÄ²Ù×÷£»
+2. ´´½¨ `AutoConfigurationClass`£¬´«Èë `className`£»
+3. µ÷Óà `AutoConfigurationSorter.AutoConfigurationClass#isAvailable` ·½·¨£¬µÃµ½ `available`£»
+4. ÅÐ¶Ï `available` Óë `required` µÄÖµ£¬Èç¹ûÆäһΪ ture£¬¾Í½«ÆäÌí¼Óµ½ `classes`£»
+5. Èç¹û `available` Ϊ `true`£¬µÝ¹é´¦Àí `className` ÓÉ `@AutoConfigureBefore` Óë `@AutoConfigureAfter` Ö¸¶¨µÄÀà¡£
+
+Á÷³Ì¿´×Ų»¸´ÔÓ£¬²»¹ýÓм¸¸ö¾ÍÈ¥ÐèÒª·ÖÎöÏ £º
+
+1. `AutoConfigurationSorter.AutoConfigurationClass#isAvailable`£ºÅжϵ±Ç° `class` ÊÇ·ñ´æÔÚ
+2. `AutoConfigurationSorter.AutoConfigurationClass#getBefore`£º»ñÈ¡ `class`£ºµ±Ç° `class` ÐèÒªÔÚÕâЩ `class` ֮ǰ´¦Àí
+3. `AutoConfigurationSorter.AutoConfigurationClass#getAfter`£º»ñÈ¡ `class`£ºµ±Ç° `class` ÐèÒªÔÚÕâЩ `class` Ö®ºó´¦Àí
+
+½ÓÏÂÀ´ÎÒÃÇÒ»Ò»À´·ÖÎöÏÂÕ⼸¸ö·½·¨¡£
+
+#### 4.1 `AutoConfigurationSorter.AutoConfigurationClass#isAvailable`
+
+Õâ¸ö·½·¨ÊÇÓÃÀ´Åжϵ±Ç° `class` ÊÇ·ñÔÚµ±Ç°ÏîÄ¿µÄ `classpath` ÖУ¬¿´´úÂ룺
+
+```
+boolean isAvailable() {
+ try {
+ if (!wasProcessed()) {
+ getAnnotationMetadata();
+ }
+ return true;
+ }
+ catch (Exception ex) {
+ return false;
+ }
+}
+
+```
+
+Õâ¸ö·½·¨´úÂë²»¶à£¬ÏÈÊǵ÷Óà `wasProcessed()` ·½·¨£¬ÔÙµ÷Óà `getAnnotationMetadata()`£¬ÐèҪעÒâµÄÊÇ£¬`getAnnotationMetadata()` ¿ÉÄÜ»áÅ׳öÒì³££¬ÕÐÆ¸Òì³£Ò²»á·µ»Ø `false`.
+
+ÎÒÃǼÌÐø¸ú½ø `AutoConfigurationSorter.AutoConfigurationClass#wasProcessed` ·½·¨£º
+
+```
+private boolean wasProcessed() {
+ return (this.autoConfigurationMetadata != null
+ // ÅÐ¶Ï META-INF/spring-autoconfigure-metadata.properties ÎļþÖÐÊÇ·ñ´æÔÚ¸ÃÅäÖÃ
+ && this.autoConfigurationMetadata.wasProcessed(this.className));
+}
+
+```
+
+Õâ¸ö·½·¨ÀïÖ÷Òªµ÷ÓÃÁË `AutoConfigurationMetadataLoader.PropertiesAutoConfigurationMetadata#wasProcessed` ·½·¨À´Åжϣº
+
+```
+@Override
+public boolean wasProcessed(String className) {
+ // ÅÐ¶Ï properties ÊÇ·ñ´æÔÚ¶ÔÓ¦µÄ className
+ return this.properties.containsKey(className);
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬Õâ¸ö·½·¨½öÊÇÅÐ¶Ï `properties` ÀïÊÇ·ñ°üº¬´«ÈëµÄ `className`£¬`properties` µÄÄÚÈÝÀ´×ÔÓÚ `META-INF/spring-autoconfigure-metadata.properties`£¬ÄÚÈÝʾÀýÈçÏ£º
+
+
+
+ÐèҪעÒâµÄÊÇ£¬¸ÃÎļþÔÚÔ´ÂëÖÐÊDz»´æÔڵģ¬ËüÊÇÔÚ±àÒëʱдÈëµÄ£¬¹ØÓÚ¸ÃÎļþµÄдÈë¡¢¼ÓÔØµ½ `properties` µÄÁ÷³Ì£¬±¾ÎľͲ»Õ¹¿ª·ÖÎöÁË£¬ÕâÀïÌṩ¸ö´ó¸Å˼·£º
+
+* ÎļþµÄдÈ룺ÔÚ´úÂë±àÒëʱ£¬springboot »á½«×Ô¶¯×°ÅäÀàµÄһЩÐÅÏ¢ (ÀýÈ磬`@ConditionalOnClass` Ö¸¶¨µÄ `class`£¬`@ConditionalOnBean` Ö¸¶¨µÄ `bean`£¬`@AutoConfigureBefore` Óë `@AutoConfigureAfter` µÄÖ¸¶¨µÄ `class` µÈ) дÈëµ½ `META-INF/spring-autoconfigure-metadata.properties` ÎļþÖУ¬´¦ÀíÀàΪ `AutoConfigureAnnotationProcessor`£¬Õâ¸öÀàÊÇ `javax.annotation.processing.AbstractProcessor` µÄ×ÓÀ࣬¶ø `AbstractProcessor` ÓÉ jdk Ìṩ£¬¿ÉÒÔÔÚ±àÒëÆÚ¶Ô×¢½â½øÐд¦Àí£»
+
+* ÎļþµÄ¼ÓÔØ£ºÔÚ `AutoConfigurationImportSelector.AutoConfigurationGroup#process` ·½·¨Öе÷Óà `AutoConfigurationImportSelector#getAutoConfigurationEntry` ʱ£¬»á´«Èë `AutoConfigurationMetadata`£¬Îļþ `META-INF/spring-autoconfigure-metadata.properties` ÖеÄÄÚÈݾÍÊÇ´ÓÕâÀï¼ÓÔØµ½ `AutoConfigurationMetadataLoader.PropertiesAutoConfigurationMetadata#properties` Öеģ»
+
+ÓÉЩ¿É¼û£¬`AutoConfigurationMetadataLoader.PropertiesAutoConfigurationMetadata#wasProcessed` ·½·¨Êµ¼ÊÉϾÍÊÇÅÐ¶Ï `META-INF/spring-autoconfigure-metadata.properties` ÎļþÖÐÊÇ·ñÓÐ `className` µÄÅäÖá£
+
+ÈÃÎÒÃǻص½ `AutoConfigurationSorter.AutoConfigurationClass#isAvailable`£¬ÔÙÀ´¿´¿´ÁíÒ»¸ö·½·¨£º`getAnnotationMetadata()`£¬¸Ã·½·¨Î»ÓÚ `AutoConfigurationSorter.AutoConfigurationClass` ÖУ¬´úÂëÈçÏ£º
+
+```
+private AnnotationMetadata getAnnotationMetadata() {
+ if (this.annotationMetadata == null) {
+ try {
+ // ¼ÓÔØ`className`¶ÔÓ¦µÄ×ÊÔ´£¬µ± className ¶ÔÓ¦µÄ×ÊÔ´²»´æÔÚʱ£¬»áÅ׳öÒì³£
+ MetadataReader metadataReader = this.metadataReaderFactory
+ .getMetadataReader(this.className);
+ this.annotationMetadata = metadataReader.getAnnotationMetadata();
+ }
+ catch (IOException ex) {
+ throw new IllegalStateException(...);
+ }
+ }
+ return this.annotationMetadata;
+}
+
+```
+
+¼ÌÐø½øÈë `SimpleMetadataReaderFactory#getMetadataReader(String)`£º
+
+```
+@Override
+/**
+ * Õâ¸ö·½·¨»á»ñÈ¡ className ¶ÔÓ¦µÄ .class Îļþ
+ * Èç¹û .class Îļþ²»´æÔÚ£¬¾Í±¨Òì³£ÁË£ºIOException
+ */
+public MetadataReader getMetadataReader(String className) throws IOException {
+ try {
+ // ת»»Ãû³Æ£º"classpath:xxx/xxx/Xxx.class"
+ String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX
+ + lassUtils.convertClassNameToResourcePath(className)
+ + ClassUtils.CLASS_FILE_SUFFIX;
+ // »ñÈ¡×ÊÔ´£¬Ä¬È쵀 resourceLoader Ϊ classLoader
+ Resource resource = this.resourceLoader.getResource(resourcePath);
+ // ½« resource ת»»³É MetadataReader ¶ÔÏ󣬲»´æÔھͻáÅ׳öÒì³££ºIOException
+ return getMetadataReader(resource);
+ }
+ catch (FileNotFoundException ex) {
+ // ÓпÉÄÜÊÇÄÚ²¿À࣬ÔÙ°´ÄÚ²¿ÀàµÄÃüÃû·½Ê½´¦ÀíÒ»´Î
+ int lastDotIndex = className.lastIndexOf('.');
+ if (lastDotIndex != -1) {
+ String innerClassName = className.substring(0, lastDotIndex) + '$'
+ + className.substring(lastDotIndex + 1);
+ // ת»»Ãû³Æ£º"classpath:xxx/Xxx$Xxx.class"
+ String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX
+ + ClassUtils.convertClassNameToResourcePath(innerClassName)
+ + ClassUtils.CLASS_FILE_SUFFIX;
+ Resource innerClassResource = this.resourceLoader.getResource(innerClassResourcePath);
+ // ÅжÏÊÇ·ñ´æÔÚ£¬²»´æÔÚ»¹ÊǻᱨÒì³£µÄ£ºIOException
+ if (innerClassResource.exists()) {
+ return getMetadataReader(innerClassResource);
+ }
+ }
+ throw ex;
+ }
+}
+
+```
+
+Õâ¸ö·½·¨µÄ´¦ÀíÁ÷³ÌÈçÏ£º
+
+1. ½«´«ÈëµÄ `className` ת»»Îª `classpath:xxx/xxx/Xxx.class` µÄÐÎʽ£¬È»ºóÈ¥¼ÓÔØ¶ÔÓ¦µÄ×ÊÔ´£¬Èç¹û×ÊÔ´²»´æÔÚ¼´ `className` ¶ÔÓ¦µÄ`.class` Îļþ²»´æÔÚ£¬ÔòÅ׳öÒì³££»
+2. ÔÚÒì³£µÄ `catch` ¿éÖУ¬ÎªÁË·ÀÖ¹ `className` ÊÇÄÚ²¿À࣬»á½« `className` ת»»Îª `classpath:xxx/Xxx$Xxx.class` µÄÐÎʽ£¬È»ºóÔÙ¼ÓÔØÒ»´Î×ÊÔ´£¬Èç¹û×ÊÔ´´æÔÚ£¬Ö±½Ó·µ»Ø£¬·ñÔò½«Òì³£ÍùÍâÅ×£»
+
+µ½ÁËÕâÀÎÒÃǾÍÃ÷°×ÁË£¬`getAnnotationMetadata()` ¾ÍÊÇÓÃÀ´Åжϵ±Ç° `className` ¶ÔÓ¦µÄ`.class` ÔÚÏîÄ¿µÄ `classpath` ·¾¶ÖÐÊÇ·ñ´æÔÚ¡£
+
+¶ÔÕâÁ½¸ö·½·¨£¬ÎÒÃÇ×ܽáÈçÏ£º
+
+* `AutoConfigurationSorter.AutoConfigurationClass#wasProcessed`£ºµ±Ç° `className` ÊÇ·ñÔÚ `META-INF/spring-autoconfigure-metadata.properties` ÎļþÖÐ
+* `AutoConfigurationSorter.AutoConfigurationClass#isAvailable`£ºµ±Ç° `className` ¶ÔÓ¦µÄ`.class` ÎļþÊÇ·ñ´æÔÚ
+
+×îÖյĽáÂÛ£º`AutoConfigurationSorter.AutoConfigurationClass#isAvailable` ¾ÍÊÇÓÃÀ´Åжϵ±Ç° `className` ¶ÔÓ¦µÄ`.class` ÎļþÔÚÏîÄ¿µÄ `classpath` ·¾¶ÖÐ.
+
+#### 4.2 `AutoConfigurationSorter.AutoConfigurationClass#getBefore/getAfter`
+
+½ÓÏÂÀ´ÎÒÃÇÀ´¿´¿´ `AutoConfigurationSorter.AutoConfigurationClass` ÀàµÄÁ½¸ö·½·¨£º`getAfter()` Óë `getBefore()`£º
+
+```
+Set getBefore() {
+ if (this.before == null) {
+ this.before = (wasProcessed()
+ // Èç¹û´æÔÚÓÚ `META-INF/spring-autoconfigure-metadata.properties` ÎļþÖУ¬Ö±½Ó»ñȡֵ
+ ? this.autoConfigurationMetadata.getSet(this.className, "AutoConfigureBefore",
+ Collections.emptySet())
+ // ·ñÔò´Ó @AutoConfigureBefore ×¢½âÉÏ»ñÈ¡
+ : getAnnotationValue(AutoConfigureBefore.class));
+ }
+ return this.before;
+}
+
+Set getAfter() {
+ if (this.after == null) {
+ this.after = (wasProcessed()
+ // Èç¹û´æÔÚÓÚ `META-INF/spring-autoconfigure-metadata.properties` ÎļþÖУ¬Ö±½Ó»ñȡֵ
+ ? this.autoConfigurationMetadata.getSet(this.className, "AutoConfigureAfter",
+ Collections.emptySet())
+ // ·ñÔò´Ó @AutoConfigureAfter ×¢½âÉÏ»ñÈ¡
+ : getAnnotationValue(AutoConfigureAfter.class));
+ }
+ return this.after;
+}
+
+/**
+ * ´Ó @AutoConfigureBefore/@AutoConfigureAfter ×¢½âÖлñȡֵ£ºvalue Óë name Ö¸¶¨µÄÖµ
+ */
+private Set getAnnotationValue(Class> annotation) {
+ Map attributes = getAnnotationMetadata()
+ .getAnnotationAttributes(annotation.getName(), true);
+ if (attributes == null) {
+ return Collections.emptySet();
+ }
+ Set value = new LinkedHashSet<>();
+ Collections.addAll(value, (String[]) attributes.get("value"));
+ Collections.addAll(value, (String[]) attributes.get("name"));
+ return value;
+}
+
+```
+
+ÕâÁ½¸ö·½·¨ÔÚ´úÂëÐÎʽ»ù±¾Ò»Ö£¬ÏÈ¿´ `getBefore()` µÄÁ÷³Ì£º
+
+1. Èç¹ûµ±Ç° `className` ´æÔÚÓÚ `META-INF/spring-autoconfigure-metadata.properties` ÎļþÖУ¬Ö±½Óȡֵ£¬Ç°Ãæ·ÖÎöÒ²Ìáµ½£¬springboot ÔÚ±àÒëʱ£¬»á°ÑһЩע½âµÄÐÅϢдÈëµ½ `META-INF/spring-autoconfigure-metadata.properties` ÎļþÖУ»
+
+2. Èç¹ûµÚ 1 ²½²»³É¹¦£¬Ôò´Óµ±Ç° `class` µÄ `@AutoConfigureBefore` ȡֵ£»
+
+`getAfter()` ·½·¨µÄÁ÷³ÌÓë `getBefore()` µÄÁ÷³Ì»ù±¾Ò»Ö£¬¾Í²»·ÖÎöÁË¡£
+
+### 5\. ʹÓà `@AutoConfigureOrder` ÅÅÐò
+
+ÈÃÎÒÃǻص½ `AutoConfigurationSorter#getInPriorityOrder` ·½·¨£¬ÎÒÃÇÀ´¿´¿´ `@AutoConfigureOrder` µÄÅÅÐò¹ý³Ì£º
+
+```
+List getInPriorityOrder(Collection classNames) {
+ ...
+ orderedClassNames.sort((o1, o2) -> {
+ int i1 = classes.get(o1).getOrder();
+ int i2 = classes.get(o2).getOrder();
+ return Integer.compare(i1, i2);
+ });
+ ...
+}
+
+```
+
+Õâ¸öÅÅÐò²Ù×÷ʹÓõÄÊÇ `List#sort`£¬`sort(...)` ÀïµÄ²ÎÊýΪ `Comparator`£¬Ö¸¶¨ÁËÅÅÐò¹æÔò¡£´Ó´úÂëÀ´¿´£¬Í¨¹ý `getOrder()` »ñÈ¡µ½µ±Ç°ÀàµÄ˳Ðòºó£¬ÔÙʹÓõÄÊÇ `Integer` µÄ±È½Ï¹æÔò½øÐÐÅÅÐò£¬Òò´Ë `getOrder()` ÊÇÅÅÐòµÄ¹Ø¼ü£¬ËüËù¶Ô¾ÍµÄ·½·¨ÊÇ `AutoConfigurationSorter.AutoConfigurationClass#getOrder`£¬´úÂëÈçÏ£º
+
+```
+private int getOrder() {
+ // ÅÐ¶Ï META-INF/spring-autoconfigure-metadata.properties ÎļþÖÐÊÇ·ñ´æÔÚµ±Ç° className
+ if (wasProcessed()) {
+ // Èç¹û´æÔÚ£¬¾ÍʹÓÃÎļþÖÐÖ¸¶¨µÄ˳Ðò£¬·ñÔò¾ÍʹÓÃĬÈÏ˳Ðò
+ return this.autoConfigurationMetadata.getInteger(this.className,
+ "AutoConfigureOrder", AutoConfigureOrder.DEFAULT_ORDER);
+ }
+ // ´¦Àí²»´æÔÚµÄÇé¿ö£º»ñÈ¡ @AutoConfigureOrder ×¢½âÖ¸¶¨µÄ˳Ðò
+ Map attributes = getAnnotationMetadata()
+ .getAnnotationAttributes(AutoConfigureOrder.class.getName());
+ // Èç¹û @AutoConfigureOrder δÅäÖ㬾ÍʹÓÃĬÈÏ˳Ðò
+ return (attributes != null) ? (Integer) attributes.get("value")
+ : AutoConfigureOrder.DEFAULT_ORDER;
+}
+
+```
+
+Õâ¸ö·½·¨»¹ÊDZȽϼòµ¥µÄ£¬¾ÍÊÇ»ñÈ¡ `@AutoConfigureOrder` ×¢½âÖ¸¶¨µÄ˳Ðò£¬Èç¹ûûÓÐ `@AutoConfigureOrder` ×¢½â£¬¾ÍʹÓÃĬÈÏ˳Ðò£¬Ä¬ÈÏ˳Ðò `AutoConfigureOrder.DEFAULT_ORDER` µÄֵΪ 0¡£
+
+### 6\. ʹÓà `@AutoConfigureBefore`£¬`@AutoConfigureAfter` ÅÅÐò
+
+½ÓÏÂÀ´¾ÍÊÇ×¶¯ÈËÐÄµÄ `@AutoConfigureBefore` Óë `@AutoConfigureAfter` ×¢½âµÄÅÅÐòÁË£¬¶ÔÓ¦µÄ·½·¨Îª `AutoConfigurationSorter#sortByAnnotation`£¬´úÂëÈçÏ£º
+
+```
+/**
+ * ½øÐÐÅÅÐò£¬
+ * ʵ¼ÊÉÏÕâ¸ö·½·¨ÀïÖ»ÊÇ×¼±¸ÁËһЩÊý¾Ý£¬ÕæÕý¸É»îµÄÊÇ doSortByAfterAnnotation(...)
+ */
+private List sortByAnnotation(AutoConfigurationClasses classes, List classNames) {
+ // ÐèÒªÅÅÐòµÄ className
+ List toSort = new ArrayList<>(classNames);
+ toSort.addAll(classes.getAllNames());
+ // ÅÅÐòºÃµÄ className
+ Set sorted = new LinkedHashSet<>();
+ // ÕýÔÚÅÅÐòÖÐµÄ className
+ Set processing = new LinkedHashSet<>();
+ while (!toSort.isEmpty()) {
+ // ÕæÕý´¦ÀíÅÅÐòµÄ·½·¨
+ doSortByAfterAnnotation(classes, toSort, sorted, processing, null);
+ }
+ // ´æÔÚÓÚ¼¯ºÏ sorted ÖУ¬µ«²»´æÔÚÓÚ classNames ÖеÄÔªËØ½«»á±»ÒƳý
+ sorted.retainAll(classNames);
+ return new ArrayList<>(sorted);
+}
+
+/**
+ * ¾ßÌå½øÐÐÅÅÐòµÄ·½·¨
+ */
+private void doSortByAfterAnnotation(AutoConfigurationClasses classes, List toSort,
+ Set sorted, Set processing, String current) {
+ if (current == null) {
+ current = toSort.remove(0);
+ }
+ // ʹÓà processing À´ÅжÏÊÇ·ñ´æÔÚÑ»·±È½Ï£¬±ÈÈ磬ÀàA after ÀàB£¬¶ø ÀàB ÓÖ after ÀàA
+ processing.add(current);
+ // classes.getClassesRequestedAfter£ºµ±Ç° className ÐèÒªÔÚÄÄЩ className Ö®ºóÖ´ÐÐ
+ for (String after : classes.getClassesRequestedAfter(current)) {
+ Assert.state(!processing.contains(after),
+ "AutoConfigure cycle detected between " + current + " and " + after);
+ if (!sorted.contains(after) && toSort.contains(after)) {
+ // µÝ¹éµ÷ÓÃ
+ doSortByAfterAnnotation(classes, toSort, sorted, processing, after);
+ }
+ }
+ processing.remove(current);
+ // Ìí¼Óµ½ÒÑÅÅÐò½á¹ûÖÐ
+ sorted.add(current);
+}
+
+```
+
+`AutoConfigurationSorter#sortByAnnotation` ÌṩÁ˱£´æÊý¾ÝµÄ½á¹¹£¬¶ø `AutoConfigurationSorter#doSortByAfterAnnotation` ²ÅÊÇÕæÕý´¦ÀíÅÅÐòµÄ·½·¨£¬ÅÅÐò²Ù×÷²»Ì«ºÃ¶®£¬´óÖÂÁ÷³ÌÈçÏ£º
+
+1. ²éÕÒµ±Ç° `className` ÐèÒªÔÚÄÄЩ `className` Ö®ºó×°Å䣬½«Æä±£´æÎª `afterClasses`£¬Ò²¾ÍÊÇ˵£¬`afterClasses` ÖеÄÿһ¸ö `className` ¶¼ÒªÔÚµ±Ç° `className` ֮ǰװÅ䣻
+
+2. ±éÀú `afterClasses`£¬¶ÔÆäÖÐÿһ¸ö `className`£¬¼ÌÐø²éÕÒÆä `afterClasses`£¬ÕâÑùµÝ¹éÏÂÈ¥£¬²»¿¼ÂÇÑ»·±È½ÏµÄÇé¿öÏ£¬×îÖÕ±ØÈ»»á´æÔÚÒ»¸ö `className`£¬ËüµÄ `afterClasses` Ϊ¿Õ£¬ÕâÀï¾Í°Ñ `className` ¼ÓÈëµ½ÒÑÍê³ÉÅÅÐòµÄ½á¹¹ÖС£
+
+ÎÒÃÇÔÙÀ´¿´¿´»ñÈ¡ `afterClasses` µÄ²Ù×÷£¬·½·¨Îª `AutoConfigurationSorter.AutoConfigurationClasses#getClassesRequestedAfter`£¬´úÂëÈçÏ£º
+
+```
+Set getClassesRequestedAfter(String className) {
+ // µ±Ç°Àࣺ»ñÈ¡ÔÚÄÄЩÀàÖ®ºóÖ´ÐУ¬¾ÍÊÇ»ñÈ¡ @AutoConfigureAfter ×¢½âÖ¸¶¨µÄÀà
+ Set classesRequestedAfter = new LinkedHashSet<>(get(className).getAfter());
+ // ÆäËûÀࣺÐèҪǰÖÃÖ´ÐеÄÀàÖÐ
+ this.classes.forEach((name, autoConfigurationClass) -> {
+ if (autoConfigurationClass.getBefore().contains(className)) {
+ classesRequestedAfter.add(name);
+ }
+ });
+ return classesRequestedAfter;
+}
+
+```
+
+´Ó´úÂëÀ´µÄÀ´¿´£¬Õâ¸ö `afterClasses` °üº¬Á½¸öÄÚÈÝ£º
+
+* »ñÈ¡ÔÚÄÄЩÀà×°ÅäÍê³ÉÖ®ºó×°Å䣬¾ÍÊÇ»ñÈ¡ `@AutoConfigureAfter` ×¢½âÖ¸¶¨µÄÀà
+* »ñÈ¡ÄÄЩÀàÐèÒªÔÚµ±Ç°Àà×°Åä֮ǰ½øÐÐ×°Åä
+
+### 7\. ÔÙÀ´¿´£º`@ConditionalOnBean/@ConditionalOnMissingBean`
+
+Ç°ÃæÌáµ½ÁË `@ConditionalOnBean/@ConditionalOnMissingBean` µÄ¿Ó£¬Á˽âÍê×Ô¶¯×°ÅäµÄ˳Ðòºó£¬¾ÍÄܺܺùæ±ÜÕâЩ¿ÓÁË£º
+
+1. Á½¸ö `bean` ¶¼ÊÇ×Ô¶¯×°ÅäÀࣺ±Ü¿Ó·½Ê½ÊÇ£¬Ê¹Óà `@AutoConfigureBefore` / `@AutoConfigureAfter` »ò `@AutoConfigureOrder` Ö¸¶¨Ìõ¼þ˳Ðò£¬±£Ö¤Ìõ¼þ×¢½âÖÐµÄ `bean` ÏÈ×°Åä¼´¿É£»
+2. Ò»¸öÊÇÆÕͨ `spring bean`£¬Ò»¸öÊÇ×Ô¶¯×°ÅäÀࣺÈç¹ûÌõ¼þ×¢½âÖÐµÄ `bean` ÊÇÆÕͨ spring bean£¬ÁíÒ»¸öÊÇ×Ô¶¯×°ÅäÀ࣬ÕâÖÖÇé¿öϲ»Óô¦Àí£¬×Ô¶¯×°ÅäµÄ´¦ÀíÀàÊÇ `DeferredImportSelector` µÄ×ÓÀ࣬ÏÈÌì¾ö¶¨×Ô¶¯×°ÅäÀàÔÚÆÕͨ `spring bean` Ö®ºó´¦Àí£»·´Ö® £¬Ìõ¼þ×¢½âÖÐµÄ `bean` ÊÇ×Ô¶¯×°ÅäÀ࣬ÁíÒ»¸öÊÇÆÕͨ `spring bean`£¬ÕâÖÖÒ»¶¨»á³ö´í£¬²»ÒªÊ¹Óã»
+3. Á½¸ö¶¼ÊÇÆÕͨ `spring bean`£ºÎޱܿӷ½·¨£¬`spring bean` ×¢²áµ½ `beanFactory` µÄ˳Ðò²»¿É¿Ø£¬²»½¨ÒéÔÚÕâÖÖÇé¿öÏÂʹÓã»
+
+### 8\. ×ܽá
+
+±¾ÎÄ×ܽáÁË×Ô¶¯×°ÅäÀàµÄ×°Åä˳Ðò£¬Ö÷Òª½éÉÜÁËÈçÏÂÄÚÈÝ£º
+
+1. ¶Ô×Ô¶¯×°ÅäÀàÅÅÐò£º`AutoConfigurationImportSelector.AutoConfigurationGroup#sortAutoConfigurations`
+2. Ö¸¶¨×Ô¶¯×°ÅäÀàµÄ×°Åä˳Ðò£ºÊ¹Óà `@AutoConfigureBefore` / `@AutoConfigureAfter` »ò `@AutoConfigureOrder`
+3. ÅÅÐò·½Ê½ÓÐÈýÖÖ£¬ÒÀ´ÎÊÇ£º
+ 1. °´ className ÅÅÐò£¬ÓÉ `String` ÌṩÅÅÐò¹æÔò
+ 2. ¸ù¾Ý `@AutoConfigureOrder` Ö¸¶¨µÄÖµ½øÐÐÅÅÐò£¬ÓÉ `Integer` ÌṩÅÅÐò¹æÔò
+ 3. ¸ù¾Ý `@AutoConfigureBefore` / `@AutoConfigureAfter` ½øÐÐÅÅÐò ÐèҪעÒâµÄÊÇ£¬ÒÔÉÏÈýÖÖÅÅÐò·½Ê½ÏȺó½øÐУ¬ÒÔ×îºóÅÅÐòÍêµÄ½á¹ûΪ×îÖÕ˳Ðò
+4. ¹ØÓÚ `@ConditionalOnBean/@ConditionalOnMissingBean` ±Ü¿ÓÖ¸ÄÏ£º
+ 1. Á½¸ö `bean` ¶¼ÊÇ×Ô¶¯×°ÅäÀࣺ±Ü¿Ó·½Ê½ÊÇ£¬Ê¹Óà `@AutoConfigureBefore` / `@AutoConfigureAfter` »ò `@AutoConfigureOrder` Ö¸¶¨Ìõ¼þ˳Ðò£¬±£Ö¤Ìõ¼þ×¢½âÖÐµÄ `bean` ÏÈ×°Åä¼´¿É£»
+ 2. Ò»¸öÊÇÆÕͨ `spring bean`£¬Ò»¸öÊÇ×Ô¶¯×°ÅäÀࣺÌõ¼þ×¢½âÖÐµÄ `bean` ±ØÐëΪÆÕͨµÄ `spring bean`£»
+ 3. ÆäËûÇé¿ö²»¿É¿Ø£¬²»½¨ÒéʹÓá£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4921594](https://my.oschina.net/funcy/blog/4921594) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\272\214\357\274\211\357\274\232\346\235\241\344\273\266\346\263\250\350\247\243.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\272\214\357\274\211\357\274\232\346\235\241\344\273\266\346\263\250\350\247\243.md"
new file mode 100644
index 0000000..31d27a9
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot\346\272\220\347\240\201\350\247\243\346\236\220/springboot \350\207\252\345\212\250\350\243\205\351\205\215\357\274\210\344\272\214\357\274\211\357\274\232\346\235\241\344\273\266\346\263\250\350\247\243.md"
@@ -0,0 +1,961 @@
+### 1\. Ìõ¼þ×¢½â¼°ÆäÅжÏÀà
+
+ÔÚ [springboot ×Ô¶¯×°ÅäÖ®¼ÓÔØ×Ô¶¯×°ÅäÀà](https://my.oschina.net/funcy/blog/4870868)Ò»ÎÄÖУ¬ÎÒÃÇ·ÖÎöµ½ springboot »á¼ÓÔØ `META-INF/spring.factories` ÎļþÖж¨ÒåµÄ×Ô¶¯×°ÅäÀ࣬¼ÓÔØµ½ÕâЩ×Ô¶¯×°ÅäÀàºó£¬ÕâЩÀàÖÐµÄ bean ¾ÍÒ»¶¨»á³õʼ»¯Â𣿲¢²»ÊÇ£¬ÎÒÃÇ¿ÉÒÔÔÚ¶ÔÓ¦µÄ Bean Éú³É·½·¨ÉÏʹÓÃ**Ìõ¼þ×¢½â**À´¿ØÖÆÀàÊÇ·ñ½øÐгõʼ»¯£¡
+
+springboot ÌṩµÄÌõ¼þ×¢½âÈçÏ£º
+
+
+
+ÕâÀïÁоٲ¿·ÖÈçÏ£º
+
+| ×¢½âÀàÐÍ | ×¢½âÀàÐÍ | ¹¦ÄÜ˵Ã÷ |
+| --------------------- | ------------------------------------------------------------ | --------------------------------------------- |
+| class Ìõ¼þ×¢½â | `@ConditionalOnClass`/`@ConditionalOnMissingClass` | µ±Ö¸¶¨µÄÀà**´æÔÚ / ȱʧ**ʱ³õʼ»¯¸Ã bean |
+| bean Ìõ¼þ×¢½â | `@ConditionalOnBean`/`@ConditionalOnMissingBean` | µ±Ö¸¶¨µÄ bean **´æÔÚ / ȱʧ**ʱ³õʼ»¯¸Ã bean |
+| ÊôÐÔÌõ¼þ×¢½â | `@ConditionalOnProperty` | µ±Ö¸¶¨µÄÊôÐÔ´æÔÚ³õʼ»¯¸Ã bean |
+| Resource Ìõ¼þ×¢½â | `@ConditionalOnResource` | µ±Ö¸¶¨µÄ×ÊÔ´´æÔÚ³õʼ»¯¸Ã bean |
+| Web Ó¦ÓÃÌõ¼þ×¢½â | `@ConditionalOnWebApplication` / `@ConditionalOnNotWebApplication` | µ±Ç°Ó¦ÓÃ**Ϊ / ²»Îª** web Ó¦ÓÃʱ³õʼ»¯¸Ã bean |
+| spring ±í´ïʽÌõ¼þ×¢½â | `@ConditionalOnExpression` | µ±±í´ïʽ½á¹ûΪ true ʱ³õʼ»¯¸Ã bean |
+
+ÎÒÃǽøÈë `@ConditionalOnClass` ¿´¿´¸Ã×¢½âµÄÄÚÈÝ£º
+
+```
+...
+@Conditional(OnClassCondition.class)
+public @interface ConditionalOnClass {
+ ...
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`ConditionalOnClass` ×éºÏÁË `@Conditional` ×¢½âµÄ¹¦ÄÜ£¬´¦ÀíÀàÊÇ `OnClassCondition.class`¡£
+
+¹ØÓÚ `@Conditional` ×¢½â¿ÉÒԲο¼ [ConfigurationClassPostProcessor Ö®´¦Àí @Conditional ×¢½â](https://my.oschina.net/funcy/blog/4873444)£¬ÕâÀïÎÒÃÇÖ±½Ó˵ `@Conditional` µÄʹÓ÷½Ê½£º
+
+1. `@Conditional` ÊÇ spring ´¦ÀíµÄÌõ¼þ×¢½â£»
+
+2. `@Conditional` ÌṩÁËÒ»¸öÊôÐÔ `value`£¬ÀàÐÍΪ `Class`£¬Æä±ØÐëÊÇ `Condition` µÄ×ÓÀࣺ
+
+ ```
+ Class extends Condition>[] value();
+
+ ```
+
+3. `Condition` ÊÇÒ»¸ö½Ó¿Ú£¬ÆäÖÐÓÐÒ»¸ö `matches(...)` ·½·¨£º
+
+ ```
+ public interface Condition {
+
+ boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
+
+ }
+
+ ```
+
+ Ö»ÓÐÔÚ `matches(...)` ·½·¨·µ»Ø `true` ʱ£¬`ConfigurationClassPostProcessor` ²Å»á½«Æä¶ÔÓ¦µÄ bean ×¢²áµ½ `beanFactory` µÄ `beanDefinitionMap` ÖÐ.
+
+×ܽáÍê `@Conditional` µÄʹÓ÷½Ê½ºó£¬ÎÒÃǾÍÃ÷°×ÁË£º`OnClassCondition.class` ÊÇ `Condition` µÄ×ÓÀ࣬Æä `matches(...)` ·½·¨ÓÃÀ´´¦ÀíÖ÷ÒªÌõ¼þ¹æÔò¡£Í¬Àí£¬ÆäËûÌõ¼þ×¢½âµÄ´¦Àí·½Ê½Ò²ÀàËÆ£¬ÕâÀï×ܽáÏÂÌõ¼þ×¢½âµÄÅжÏÀࣺ
+
+| ×¢½âÀàÐÍ | ×¢½âÀàÐÍ | Ìõ¼þÅжÏÀà |
+| --------------------- | ------------------------------------------------------------ | --------------------------- |
+| class Ìõ¼þ×¢½â | `@ConditionalOnClass`/`@ConditionalOnMissingClass` | `OnClassCondition` |
+| bean Ìõ¼þ×¢½â | `@ConditionalOnBean`/`@ConditionalOnMissingBean` | `OnBeanCondition` |
+| ÊôÐÔÌõ¼þ×¢½â | `@ConditionalOnProperty` | `OnPropertyCondition` |
+| Resource Ìõ¼þ×¢½â | `@ConditionalOnResource` | `OnResourceCondition` |
+| Web Ó¦ÓÃÌõ¼þ×¢½â | `@ConditionalOnWebApplication` / `@ConditionalOnNotWebApplication` | `OnWebApplicationCondition` |
+| spring ±í´ïʽÌõ¼þ×¢½â | `@ConditionalOnExpression` | `OnExpressionCondition` |
+
+½ÓÏÂÀ´£¬·ÖÎöÄ¿µÄ¾ÍºÜÃ÷È·ÁË£ºÒª·ÖÎöÕâЩÌõ¼þ×¢½âµÄÅжÏÂß¼£¬Ö»ÐèÒª·ÖÎö¶ÔÓ¦Ìõ¼þÅжÏÀàµÄ `matches(...)` ·½·¨¾Í¿ÉÒÔÁË¡£
+
+### 2. `SpringBootCondition#matches`
+
+½øÈë `OnClassCondition#matches` ·½·¨£¬·¢ÏÖÀ´µ½µÄÊÇ `SpringBootCondition`£¬Ïà¹Ø·½·¨ÈçÏ£º
+
+```
+public abstract class SpringBootCondition implements Condition {
+
+ private final Log logger = LogFactory.getLog(getClass());
+
+ @Override
+ public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ String classOrMethodName = getClassOrMethodName(metadata);
+ try {
+ // »ñÈ¡Ìõ¼þÆ¥Åä½á¹û
+ ConditionOutcome outcome = getMatchOutcome(context, metadata);
+ // ´òÓ¡Ò»ÌõÈÕÖ¾
+ logOutcome(classOrMethodName, outcome);
+ // ¼Ç¼Ìõ¼þÆÀ¹ÀµÄ·¢Éú£¬¼òµ¥Àí½âΪ¼Ç¼һÌõÌõ¼þÅжϼǼ°É
+ recordEvaluation(context, classOrMethodName, outcome);
+ // ÕâÀï·µ»Ø×îÖÕ½á¹û£ºtrue »ò false
+ return outcome.isMatch();
+ }
+ catch (NoClassDefFoundError ex) {
+ throw new IllegalStateException(...);
+ }
+ catch (RuntimeException ex) {
+ throw new IllegalStateException(...);
+ }
+ }
+
+ /**
+ * ÕâÊǸö³éÏó·½Ê½£¬¾ßÌåÄÚÈÝÓÉ×ÓÀàʵÏÖ
+ */
+ public abstract ConditionOutcome getMatchOutcome(
+ ConditionContext context, AnnotatedTypeMetadata metadata);
+
+ ...
+
+}
+
+```
+
+`SpringBootCondition` µÄ `matches(...)` ¹Ø¼ü¾ÍÁ½ÐУº
+
+```
+...
+ConditionOutcome outcome = getMatchOutcome(context, metadata);
+...
+return outcome.isMatch();
+
+```
+
+¶ø `SpringBootCondition` µÄ `getMatchOutcome(...)` ÓÖÊǸö³éÏó·½·¨£¬¾ßÌåµÄÂß¼ÓÉ×ÓÀàÌṩ£¬`OnClassCondition` ËüµÄʵÏÖÖ®Ò»¡£Êµ¼ÊÉÏ£¬ÉÏÊöÌõ¼þÅжÏÀà¶¼ÊÇ `SpringBootCondition` µÄ×ÓÀ࣬ºóÃæÎÒÃǾÍÖ±½Ó½øÈë¾ßÌåÀàµÄ `getMatchOutcome(...)` ·½·¨·ÖÎöÁË¡£
+
+`getMatchOutcome(...)` ·½·¨·µ»ØµÄ½á¹ûÊÇ `ConditionOutcome`£¬½ÓÏÂÀ´ÎÒÃÇÀ´¿´¿´ `ConditionOutcome` ÊǸöɶ£º
+
+```
+public class ConditionOutcome {
+
+ private final boolean match;
+
+ private final ConditionMessage message;
+
+ /**
+ * ¹¹Ôì·½·¨
+ */
+ public ConditionOutcome(boolean match, String message) {
+ this(match, ConditionMessage.of(message));
+ }
+
+ /**
+ * ¹¹Ôì·½·¨
+ */
+ public ConditionOutcome(boolean match, ConditionMessage message) {
+ Assert.notNull(message, "ConditionMessage must not be null");
+ this.match = match;
+ this.message = message;
+ }
+
+ /**
+ * ·µ»ØÆ¥ÅäµÄ½á¹û
+ */
+ public boolean isMatch() {
+ return this.match;
+ }
+
+ ...
+}
+
+```
+
+´Ó´úÂëÀ´¿´£¬Õâ¸öÀà¾ÍÊÇÓÃÀ´·â×°±È½Ï½á¹ûµÄ£¬ÄÚ²¿ÓÐÁ½¸öÊôÐÔ£º`match` Óë `message`:
+
+* `match` µÄÀàÐÍÊÇ `boolean`£¬Õâ¸ö¾ÍÊÇ×îÖÕÆ¥Åä³É¹¦»¹ÊÇʧ°ÜµÄ±êʶ
+* `message` µÄÀàÐÍÊÇ `ConditionMessage`£¬Ëü±íʾƥÅä½á¹ûµÄ˵Ã÷
+
+ÎÒÃÇÔÙÀ´¿´¿´ `ConditionMessage`:
+
+```
+public final class ConditionMessage {
+
+ private String message;
+
+ private ConditionMessage() {
+ this(null);
+ }
+
+ private ConditionMessage(String message) {
+ this.message = message;
+ }
+
+ ...
+}
+
+```
+
+Ëü½öÓÐÒ»¸öÊôÐÔ£º`message`£¬Õâ±íÃ÷Ëü¾ÍÊǶÔ˵Ã÷ÐÅÏ¢µÄ°ü×°¡£
+
+### 3. `@ConditionalOnClass`: `OnClassCondition#getMatchOutcome`
+
+½ÓÏÂÀ´ÎÒÃÇÀ´·ÖÎö `OnClassCondition` µÄÆ¥ÅäÂß¼£¬Ö±½Ó½øÈë `getMatchOutcome` ·½·¨£º
+
+```
+public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ ClassLoader classLoader = context.getClassLoader();
+ ConditionMessage matchMessage = ConditionMessage.empty();
+ // 1\. ´¦Àí @ConditionalOnClass ×¢½â
+ List onClasses = getCandidates(metadata, ConditionalOnClass.class);
+ if (onClasses != null) {
+ // 1.1 ´¦ÀíÌõ¼þÅжÏ
+ List missing = filter(onClasses, ClassNameFilter.MISSING, classLoader);
+ if (!missing.isEmpty()) {
+ // 1.2 ¹¹½¨·µ»Ø½á¹û£º²»Æ¥ÅäµÄÇé¿ö
+ return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class)
+ .didNotFind("required class", "required classes").items(Style.QUOTE, missing));
+ }
+ matchMessage = matchMessage.andCondition(ConditionalOnClass.class)
+ .found("required class", "required classes")
+ .items(Style.QUOTE, filter(onClasses, ClassNameFilter.PRESENT, classLoader));
+ }
+
+ // 2\. ´¦Àí @ConditionalOnMissingClass ×¢½â
+ List onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);
+ if (onMissingClasses != null) {
+ // 2.1 ´¦ÀíÌõ¼þÅжÏ
+ List present = filter(onMissingClasses, ClassNameFilter.PRESENT, classLoader);
+ if (!present.isEmpty()) {
+ // 2.2 ¹¹½¨·µ»Ø½á¹û£º²»Æ¥ÅäµÄÇé¿ö
+ return ConditionOutcome.noMatch(ConditionMessage
+ .forCondition(ConditionalOnMissingClass.class)
+ .found("unwanted class", "unwanted classes").items(Style.QUOTE, present));
+ }
+ matchMessage = matchMessage.andCondition(ConditionalOnMissingClass.class)
+ .didNotFind("unwanted class", "unwanted classes")
+ .items(Style.QUOTE, filter(onMissingClasses, ClassNameFilter.MISSING, classLoader));
+ }
+ // ×îºó·µ»ØÆ¥ÅäµÄ½á¹û
+ return ConditionOutcome.match(matchMessage);
+}
+
+```
+
+Õâ¸ö·½·¨Í¬Ê±´¦ÀíÁË `@ConditionalOnClass` Óë `@ConditionalOnMissingClass` Á½¸ö×¢½â£¬´¦ÀíÁ÷³Ì¼«ÆäÏàËÆ£¬Á½¸ö×¢½âµÄÌõ¼þÅж϶¼ÊÇͨ¹ý `FilteringSpringBootCondition#filter` ÄÚÈÝÈçÏ£º
+
+```
+protected final List filter(Collection classNames, ClassNameFilter classNameFilter,
+ ClassLoader classLoader) {
+ if (CollectionUtils.isEmpty(classNames)) {
+ return Collections.emptyList();
+ }
+ List matches = new ArrayList<>(classNames.size());
+ for (String candidate : classNames) {
+ // ½øÐÐÌõ¼þÆ¥Åä
+ if (classNameFilter.matches(candidate, classLoader)) {
+ matches.add(candidate);
+ }
+ }
+ return matches;
+}
+
+```
+
+Óɴ˿ɼû£¬´«ÈëµÄ `classNameFilter` ³ÉÁ˹ؼü£º
+
+* ´¦Àí `@ConditionalOnClass` ʱ£¬`classNameFilter` Ϊ `ClassNameFilter.MISSING`
+* ´¦Àí `@ConditionalOnMissingClass` ʱ£¬`classNameFilter` Ϊ `ClassNameFilter.PRESENT`
+
+ÈÃÎÒÃǽøÈë `ClassNameFilter` һ̽¾¿¾¹£¬ËüÊÇ `FilteringSpringBootCondition` µÄ×ÓÀ࣬ÄÚÈÝÈçÏ£º
+
+```
+abstract class FilteringSpringBootCondition extends SpringBootCondition
+ implements AutoConfigurationImportFilter, BeanFactoryAware, BeanClassLoaderAware {
+ ...
+ /**
+ * Èç¹û classLoader ´æÔÚ£¬Ôòµ÷Óà ClassLoader#loadClass ·½·¨
+ * ·ñÔòµ÷ÓÃ Class#forName ·½·¨
+ */
+ protected static Class> resolve(String className, ClassLoader classLoader)
+ throws ClassNotFoundException {
+ if (classLoader != null) {
+ return classLoader.loadClass(className);
+ }
+ return Class.forName(className);
+ }
+
+ /**
+ * ´¦ÀíÌõ¼þÆ¥Åä
+ */
+ protected enum ClassNameFilter {
+
+ PRESENT {
+
+ @Override
+ public boolean matches(String className, ClassLoader classLoader) {
+ return isPresent(className, classLoader);
+ }
+
+ },
+
+ MISSING {
+
+ @Override
+ public boolean matches(String className, ClassLoader classLoader) {
+ return !isPresent(className, classLoader);
+ }
+
+ };
+
+ abstract boolean matches(String className, ClassLoader classLoader);
+
+ /**
+ * Class ÊÇ·ñ´æÔÚ
+ * ͨ¹ý²¶»ñÀà¼ÓÔØÊ±µÄÒì³£À´ÅжÏÀàÊÇ·ñ´æÔÚ£¬Î´Å׳öÒì³£Ôò±íʾÀà´æÔÚ
+ */
+ static boolean isPresent(String className, ClassLoader classLoader) {
+ if (classLoader == null) {
+ classLoader = ClassUtils.getDefaultClassLoader();
+ }
+ try {
+ // ͨ¹ýÒì³£²¶»ñÀ´ÅжÏÊÇ·ñ´æÔÚ¸Ãclass
+ resolve(className, classLoader);
+ return true;
+ }
+ catch (Throwable ex) {
+ return false;
+ }
+ }
+ }
+ ...
+}
+
+```
+
+¿´µ½ÕâÀïÎÒÃǾÍÃ÷°×ÁË£ºÅÐ¶Ï `Class` ÊÇ·ñ´æÔÚ£¬spring ÊÇͨ¹ý²¶»ñ `ClassLoader.load(String)` »ò `Class.forName(String)` ·½·¨µÄÒì³£À´´¦ÀíµÄ£¬Èç¹ûÅ׳öÁËÒì³£¾Í±íÃ÷ `Class` ²»´æÔÚ¡£
+
+ÕâÀï×ܽáÏ `@ConditionalOnClass`/`@ConditionalOnMissingClass` µÄ´¦Àí·½Ê½£º**Á½ÕߵĴ¦ÀíÀ඼Ϊ `OnClassCondition`£¬Í¨¹ý²¶»ñ `ClassLoader.load(String)` »ò `Class.forName(String)` ·½·¨µÄÒì³£À´ÅÐ¶Ï `Class` ÊÇ·ñ´æÔÚ£¬Èç¹ûÅ׳öÁËÒì³£¾Í±íÃ÷ `Class` ²»´æÔÚ**¡£
+
+### 4. `@ConditionalOnBean`: `OnBeanCondition#getMatchOutcome`
+
+¼ÌÐø¿´¿´ `@ConditionalOnBean` µÄ ´¦Àí£¬Ö±½Ó½øÈë `OnBeanCondition#getMatchOutcome`£º
+
+```
+public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ ConditionMessage matchMessage = ConditionMessage.empty();
+ MergedAnnotations annotations = metadata.getAnnotations();
+ // ´¦Àí @ConditionalOnBean
+ if (annotations.isPresent(ConditionalOnBean.class)) {
+ Spec spec = new Spec<>(context, metadata,
+ annotations, ConditionalOnBean.class);
+ // ´¦ÀíÆ¥Åä
+ MatchResult matchResult = getMatchingBeans(context, spec);
+ // ×¢ÒâÅжÏÌõ¼þ
+ if (!matchResult.isAllMatched()) {
+ String reason = createOnBeanNoMatchReason(matchResult);
+ return ConditionOutcome.noMatch(spec.message().because(reason));
+ }
+ matchMessage = spec.message(matchMessage).found("bean", "beans").items(Style.QUOTE,
+ matchResult.getNamesOfAllMatches());
+ }
+
+ // ´¦Àí @ConditionalOnSingleCandidate
+ if (metadata.isAnnotated(ConditionalOnSingleCandidate.class.getName())) {
+ Spec spec
+ = new SingleCandidateSpec(context, metadata, annotations);
+ // ´¦ÀíÆ¥Åä
+ MatchResult matchResult = getMatchingBeans(context, spec);
+ // ×¢ÒâÅжÏÌõ¼þ
+ if (!matchResult.isAllMatched()) {
+ return ConditionOutcome.noMatch(spec.message().didNotFind("any beans").atAll());
+ }
+ else if (!hasSingleAutowireCandidate(context.getBeanFactory(),
+ matchResult.getNamesOfAllMatches(), spec.getStrategy() == SearchStrategy.ALL)) {
+ return ConditionOutcome.noMatch(spec.message().didNotFind("a primary bean from beans")
+ .items(Style.QUOTE, matchResult.getNamesOfAllMatches()));
+ }
+ matchMessage = spec.message(matchMessage).found("a primary bean from beans")
+ .items(Style.QUOTE, matchResult.getNamesOfAllMatches());
+ }
+
+ // ´¦Àí @ConditionalOnMissingBean
+ if (metadata.isAnnotated(ConditionalOnMissingBean.class.getName())) {
+ Spec spec = new Spec<>(context, metadata, annotations,
+ ConditionalOnMissingBean.class);
+ // ´¦ÀíÆ¥Åä
+ MatchResult matchResult = getMatchingBeans(context, spec);
+ // ×¢ÒâÅжÏÌõ¼þ
+ if (matchResult.isAnyMatched()) {
+ String reason = createOnMissingBeanNoMatchReason(matchResult);
+ return ConditionOutcome.noMatch(spec.message().because(reason));
+ }
+ matchMessage = spec.message(matchMessage).didNotFind("any beans").atAll();
+ }
+ return ConditionOutcome.match(matchMessage);
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬Õâ¸ö·½·¨Ò»¹²´¦ÀíÁËÁ½¸ö×¢½âµÄÌõ¼þÆ¥Å䣺`@ConditionalOnBean`¡¢`@ConditionalOnSingleCandidate` Óë `@ConditionalOnMissingBean`£¬ÈýÕß¶¼µ÷ÓÃÁËͬһ¸ö·½·¨ `getMatchingBeans(...)` À´»ñȡƥÅä½á¹û£¬È»ºóʹÓà `matchResult.isAllMatched()` »ò `matchResult.isAnyMatched()` À´×ö×îÖյĽá¹ûÅжϡ£
+
+#### `OnBeanCondition#getMatchingBeans`
+
+`getMatchingBeans(...)` µÄ´úÂëÈçÏ£º
+
+```
+protected final MatchResult getMatchingBeans(ConditionContext context, Spec> spec) {
+ ClassLoader classLoader = context.getClassLoader();
+ ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
+ boolean considerHierarchy = spec.getStrategy() != SearchStrategy.CURRENT;
+ Set> parameterizedContainers = spec.getParameterizedContainers();
+ if (spec.getStrategy() == SearchStrategy.ANCESTORS) {
+ BeanFactory parent = beanFactory.getParentBeanFactory();
+ Assert.isInstanceOf(ConfigurableListableBeanFactory.class, parent,
+ "Unable to use SearchStrategy.ANCESTORS");
+ beanFactory = (ConfigurableListableBeanFactory) parent;
+ }
+ MatchResult result = new MatchResult();
+ // 1\. »ñÈ¡ ignoreType£¬Ö»ÓÐ @ConditionalOnMissingBean ÓÐÕâ¸öÊôÐÔ
+ Set beansIgnoredByType = getNamesOfBeansIgnoredByType(classLoader, beanFactory,
+ considerHierarchy, spec.getIgnoredTypes(), parameterizedContainers);
+
+ // 2\. ´¦Àí types
+ for (String type : spec.getTypes()) {
+ Collection typeMatches = getBeanNamesForType(classLoader, considerHierarchy,
+ beanFactory, type, parameterizedContainers);
+ typeMatches.removeAll(beansIgnoredByType);
+ if (typeMatches.isEmpty()) {
+ result.recordUnmatchedType(type);
+ }
+ else {
+ result.recordMatchedType(type, typeMatches);
+ }
+ }
+
+ // 3\. ´¦ÀíÀàÉϵÄ×¢½â @ConditionalOnMissingBean ÓÐÕâ¸öÊôÐÔ
+ for (String annotation : spec.getAnnotations()) {
+ Set annotationMatches = getBeanNamesForAnnotation(classLoader, beanFactory,
+ annotation, considerHierarchy);
+ annotationMatches.removeAll(beansIgnoredByType);
+ if (annotationMatches.isEmpty()) {
+ result.recordUnmatchedAnnotation(annotation);
+ }
+ else {
+ result.recordMatchedAnnotation(annotation, annotationMatches);
+ }
+ }
+
+ // 4\. ´¦Àí beanName
+ for (String beanName : spec.getNames()) {
+ if (!beansIgnoredByType.contains(beanName) && containsBean(beanFactory, beanName,
+ considerHierarchy)) {
+ result.recordMatchedName(beanName);
+ }
+ else {
+ result.recordUnmatchedName(beanName);
+ }
+ }
+ return result;
+}
+
+```
+
+ÐèҪ˵Ã÷µÄÊÇ£¬Õâ¸ö·½·¨»á´¦Àí 3 ¸ö×¢½âµÄÆ¥Å乿Ôò£º`@ConditionalOnBean`¡¢`@ConditionalOnSingleCandidate` Óë `@ConditionalOnMissingBean`£¬´¦Àí²½ÖèÈçÏ£º
+
+1. »ñÈ¡ `ignoreType`£¬Ö»ÓÐ `@ConditionalOnMissingBean` ÓÐÕâ¸öÊôÐÔ
+2. ´¦Àí `types` µÄÆ¥Å乿Ôò
+3. ´¦Àí×¢½â£¨ÀàÉϵÄ×¢½â£©µÄÆ¥Å乿Ôò£¬ Ö»ÓÐ `@ConditionalOnMissingBean` ÓÐÕâ¸öÊôÐÔ
+4. ´¦Àí `beanName` µÄÆ¥Å乿Ôò
+
+¹ØÓÚÒÔÉϲ½ÖèµÄ¾ßÌåϸ½Ú£¬±¾ÎľͲ»¾ßÌåÕ¹¿ªÁË£¬ÕâÀï½öÌṩÁ÷³Ì£º
+
+1. »ñÈ¡ `ignoreType`£º
+ 1. ʹÓà `ListableBeanFactory#getBeanNamesForType(Class, boolean, boolean)` ·½·¨»ñÈ¡ÈÝÆ÷ÖÐËùÓÐµÄ `ignoreType` µÄ `beanName`
+ 2. ½á¹ûΪ `beansIgnoredByType`(ÀàÐÍÊÇ `Set`)
+2. ´¦Àí `types` µÄÆ¥Å乿Ôò
+ 1. ʹÓà `ListableBeanFactory#getBeanNamesForType(Class, boolean, boolean)` ·½·¨»ñÈ¡ÈÝÆ÷ÖÐËùÓÐµÄ `type` ¶ÔÓ¦µÄ `beanName`£¬½á¹ûΪ `typeMatches`
+ 2. ½« `typeMatches` ÖеÄֵȥ³ý `ignoreType`
+ 3. Åжϵڶþ²½µÃµ½µÄ `typeMatches`£¬Èç¹ûÄÚÈÝΪ¿Õ£¬½«µ±Ç° `Type` ±£´æµ½ `unmatchedTypes` ÖУ¬·ñÔò±£´æµ½ `matchedTypes` Óë `namesOfAllMatches` ÖÐ
+3. ´¦Àí×¢½âµÄÆ¥Å乿Ôò
+ 1. ʹÓà `ListableBeanFactory#getBeanNamesForAnnotation` ·½·¨»ñÈ¡ÈÝÆ÷ÖÐËùÓÐµÄ `annotation` ¶ÔÓ¦µÄ `beanName`£¬½á¹ûΪ `annotationMatches`
+ 2. ½« `annotationMatches` ÖеÄֵȥ³ý `ignoreType`
+ 3. Åжϵڶþ²½µÃµ½µÄ `annotationMatches`£¬Èç¹ûÄÚÈÝΪ¿Õ£¬½«µ±Ç° `Annotation` ±£´æµ½ `unmatchedAnnotations` ÖУ¬·ñÔò±£´æµ½ `matchedAnnotations` Óë `namesOfAllMatches` ÖÐ
+4. ´¦Àí `beanName` µÄÆ¥Å乿Ôò
+ 1. ÅÐ¶Ï `beansIgnoredByType` ÊÇ·ñ°üº¬ `beanName`
+ 2. ʹÓà `BeanFactory#containsBean` ·½·¨ÅжÏÈÝÆ÷ÖÐÓиà `beanName`
+ 3. Èç¹ûµÚ 2 ²½½á¹ûΪ `false`£¬µÚ¶þ²½½á¹ûΪ `true`£¬Ôò½«µ±Ç° `beanName` ¼ÓÈëµ½ `matchedNames` Óë `namesOfAllMatches`£¬·ñÔò±£´æµ½ `unmatchedNames` ÖÐ
+
+µÃµ½ `matchedTypes`¡¢`unmatchedNames` µÈÄÚÈݺó£¬`matchResult.isAllMatched()` »ò `matchResult.isAnyMatched()` ×îÖÕµÄÅжϽá¹û¾ÍÊÇÅжÏÕâЩ½á¹¹ÊÇ·ñ¿Õ£º
+
+```
+boolean isAllMatched() {
+ return this.unmatchedAnnotations.isEmpty() && this.unmatchedNames.isEmpty()
+ && this.unmatchedTypes.isEmpty();
+}
+
+boolean isAnyMatched() {
+ return (!this.matchedAnnotations.isEmpty()) || (!this.matchedNames.isEmpty())
+ || (!this.matchedTypes.isEmpty());
+}
+
+```
+
+¿´À´£¬`@ConditionalOnBean`/`@ConditionalOnMissingBean` µÄ¹Ø¼ü£¬¾ÍÊÇʹÓà `ListableBeanFactory#getBeanNamesForType` »ò `BeanFactory#containsBean` À´ÅÐ¶Ï `beanName`¡¢`beanType` ÊÇ·ñ´æÔÚÁË¡£
+
+ÔÚʹÓà `@ConditionalOnBean`/`@ConditionalOnMissingBean` ʱ£¬ÓÐÒ»¸ö¿ÓÐèÒªÌØ±ð×¢Ò⣺Ìõ¼þ×¢½âµÄÖ´ÐÐʱ»úÊÇÔÚ spring µÄ `ConfigurationClassPostProcessor` Öеģ¬È·ÇеØËµ£¬ÊÇÔÚ½« `bean` ¼ÓÈëµ½ `beanFactory` µÄ `beanDefinitionMap` ֮ǰÅжϵģ¬Èç¹ûÂú×ãÌõ¼þÔòÌí¼Óµ½ `beanDefinitionMap` ÖУ¬·ñÔò¾Í²»Ìí¼Ó¡£ÕâÑù¾Íµ¼ÖÂÁËÒ»¸öÎÊÌ⣺Èç¹ûÔÚ `@ConditionalOnBean`/`@ConditionalOnMissingBean` µÄ `bean` Ôڸà `bean` Ö®ºó¼ÓÈëµ½ `beanDefinitionMap` ÖУ¬¾ÍÓпÉÄܳöÏÖÎóÅУ¬¾ÙÀý˵Ã÷£º
+
+ÏÖÔÚÓÐÁ½¸öÀࣺ
+
+```
+@Component
+@ConditionalOnMissingBean("b")
+public class A {
+
+}
+
+@Component
+public class B {
+
+}
+
+```
+
+ÆäÖÐ `A` Óë `B` ¶¼Ìí¼ÓÁË `@Component`£¬±íÃ÷ÕâÊÇ spring bean£¬È»ºóÔÚ `A` ÉÏÌí¼ÓÁË×¢½â `@ConditionalOnMissingBean("b")`£¬±íÃ÷ÔÚ `b` ²»´æÔÚʱ£¬`A` ²Å½øÐгõʼ»¯¡£ÓÐÁËÕâЩǰÌᣬÎÒÃÇÔÙÀ´¿´¿´Á½ÖÖÇé¿ö£º
+
+1. Èç¹û `b` ÏÈÌí¼Óµ½ `beanDefinitionMap` ÖУ¬ÔÚ½« `a` Ìí¼Óµ½ `beanDefinitionMap` ʱ£¬·¢ÏÖ `b` ÒѾ´æÔÚÁË£¬ÓÚÊǾͲ»Ìí¼ÓÁË£¬·ûºÏÎÒÃǵÄÔ¤ÆÚ£»
+2. Èç¹û `a` Ïȱ»´¦Àí£¬ÔÚÌí¼Óʱ£¬·¢ÏÖ `beanDefinitionMap` Öв¢Ã»ÓÐ `b`£¬ÓÚÊÇ `a` ±»Ìí¼Óµ½ `beanDefinitionMap` ÖУ¬ÔÙ´¦Àí `b`£¬`b` Ò²»á±»Ìí¼Óµ½ `beanDefinitionMap`£¬ÕâÑùÒ»À´£¬`a` Óë `b` ͬʱ´æÔÚÓÚ `beanDefinitionMap` ÖУ¬×îÖÕ¶¼»á±»³õʼ»¯³É spring bean£¬ÕâÓëÎÒÃǵÄÔ¤ÆÚ²»·û¡£
+
+ÄÇô springboot ÈçºÎ½â¾öÒÔÉÏÎÊÌâÄØ£¿ÎÒÃÇÀ´¿´¿´ `@ConditionalOnBean`/`@ConditionalOnMissingBean` µÄ˵Ã÷£º
+
+
+
+ÉÔ΢·ÒëÈçÏ£º
+
+¸ÃÌõ¼þÖ»ÄÜÆ¥Å䵽ĿǰΪֹµÄÓ¦ÓóÌÐòÉÏÏÂÎÄÖÐµÄ bean ´æÔÚÇé¿ö£¬Òò´Ë£¬Ç¿ÁÒ½¨Òé½öÓÚ×Ô¶¯ÅäÖÃÀàÖÐʹÓá£Èç¹ûºòÑ¡ bean ÒªÔÚÁíÒ»ÖÖ×Ô¶¯ÅäÖÃÏ´´½¨£¬ÇëÈ·±£Ê¹ÓôËÌõ¼þµÄÅäÖÃÔÚ´ËÖ®ºóÔËÐС£
+
+¶ÔÒÔÉÏÄÚÈÝ£¬ÎҵĽâ¶ÁÈçÏ£º
+
+* ±» `@ConditionalOnBean`/`@ConditionalOnMissingBean` ±ê¼Ç `bean` ¼ÓÈëµ½ `beanDefinitionMap` ÄÇÒ»¿Ì£¬½öÆ¥ÅäĿǰΪֹ `beanDefinitionMap` ÖÐÒÑ´æÔÚµÄ bean£¬¶ÔÖ®ºó¼ÓÈëµÄ bean ²»¿¼ÂÇ£¬Õâ¾ÍÓпÉÄÜÔì³ÉÎóÅУ¬¿ÉÒԲο¼ÉÏÃæ¾ÙµÄ `a` Óë `b` µÄÀý×Ó
+* Ç¿ÁÒ½¨Òé½öÔÚ×Ô¶¯ÅäÖÃÀàÖÐʹÓà `@ConditionalOnBean`/`@ConditionalOnMissingBean` ÕâÁ½¸ö×¢½â£¬Ò²¾ÍÊÇ˵ÔÚ×Ô¶¯ÅäÖÃÀàÖÐʹÓõϰ£¬ÄÜÕýÈ·´¦ÀíÆ¥Åä
+* »¹ÊÇÄÃÉÏÃæµÄ `a` Óë `b` ¾ÙÀý£¬Èç¹û `a` Óë `b` ·Ö±ðλÓÚ²»Í¬µÄ×Ô¶¯ÅäÖÃÀàÖУ¬ÄÇô `a` ÐèÒªÔÚ `b` Ö®ºó¼ÓÔØµ½ `beanDefinitionMap` ÖУ¬Õâ¸ö¿ÉÒÔͨ¹ý `@AutoConfigureAfter`¡¢`@AutoConfigureBefore`¡¢`@AutoConfigureOrder` µÈ×¢½âÀ´Ö¸¶¨
+
+¹ØÓÚ×Ô¶¯ÅäÖÃÀàµÄ¼ÓÔØË³Ðò£¬ºóÃæÔÙ×ö·ÖÎö°É¡£
+
+ÏÞÓÚÆª·ù£¬±¾ÎľÍÏȵ½ÕâÀïÁË£¬ÏÂÆª¼ÌÐø·ÖÎöʣϵÄÌõ¼þ×¢½â¡£
+
+* * *
+
+±¾ÎÄÊÇ springboot Ìõ¼þ×¢½â·ÖÎöµÄµÚ¶þƪ£¬ÉÏÎÄÎÒÃÇ×ܽáÁË springboot µÄ¼¸¸öÌõ¼þ×ܽ᣺
+
+| ×¢½âÀàÐÍ | ×¢½âÀàÐÍ | Ìõ¼þÅжÏÀà |
+| --------------------- | ------------------------------------------------------------ | --------------------------- |
+| class Ìõ¼þ×¢½â | `@ConditionalOnClass`/`@ConditionalOnMissingClass` | `OnClassCondition` |
+| bean Ìõ¼þ×¢½â | `@ConditionalOnBean`/`@ConditionalOnMissingBean` | `OnBeanCondition` |
+| ÊôÐÔÌõ¼þ×¢½â | `@ConditionalOnProperty` | `OnPropertyCondition` |
+| Resource Ìõ¼þ×¢½â | `@ConditionalOnResource` | `OnResourceCondition` |
+| Web Ó¦ÓÃÌõ¼þ×¢½â | `@ConditionalOnWebApplication` / `@ConditionalOnNotWebApplication` | `OnWebApplicationCondition` |
+| spring ±í´ïʽÌõ¼þ×¢½â | `@ConditionalOnExpression` | `OnExpressionCondition` |
+
+±¾ÎļÌÐø·ÖÎöÌõ¼þÅжϡ£
+
+### 5. `@ConditionalOnProperty`£º`OnPropertyCondition#getMatchOutcome`
+
+ÎÒÃÇÔÙÀ´¿´¿´ `@ConditionalOnProperty` µÄ´¦Àí£¬½øÈë `OnPropertyCondition#getMatchOutcome` ·½·¨£º
+
+```
+class OnPropertyCondition extends SpringBootCondition {
+
+ @Override
+ public ConditionOutcome getMatchOutcome(ConditionContext context,
+ AnnotatedTypeMetadata metadata) {
+ // »ñÈ¡ @ConditionalOnProperty µÄÊôÐÔÖµ
+ List allAnnotationAttributes = annotationAttributesFromMultiValueMap(
+ metadata.getAllAnnotationAttributes(ConditionalOnProperty.class.getName()));
+ List noMatch = new ArrayList<>();
+ List match = new ArrayList<>();
+ for (AnnotationAttributes annotationAttributes : allAnnotationAttributes) {
+ // ÔÚ determineOutcome(...) ·½·¨ÖнøÐÐÅжϣ¬×¢Òâ²ÎÊý£ºcontext.getEnvironment()
+ ConditionOutcome outcome = determineOutcome(annotationAttributes,
+ context.getEnvironment());
+ (outcome.isMatch() ? match : noMatch).add(outcome.getConditionMessage());
+ }
+ if (!noMatch.isEmpty()) {
+ return ConditionOutcome.noMatch(ConditionMessage.of(noMatch));
+ }
+ return ConditionOutcome.match(ConditionMessage.of(match));
+ }
+
+ ...
+
+}
+
+```
+
+Õâ¸ö·½·¨»¹ÊDZȽϼòµ¥µÄ£¬ÏÈÊÇ»ñÈ¡ `@ConditionalOnProperty` µÄÊôÐÔÖµ£¬ÔÙµ÷Óà `determineOutcome(...)` ·½·¨½øÐд¦Àí£¬ÈÃÎÒÃÇÔÙ½øÐÐ `OnPropertyCondition#determineOutcome` ·½·¨£º
+
+```
+/**
+ * ´¦Àí½á¹û
+ * ×¢Ò⣺resolver ´«ÈëµÄµÄÊÇ Environment£¬Õâ¾ÍÊÇ applicationContext ÖÐµÄ Environment
+ */
+private ConditionOutcome determineOutcome(AnnotationAttributes annotationAttributes,
+ PropertyResolver resolver) {
+ Spec spec = new Spec(annotationAttributes);
+ List missingProperties = new ArrayList<>();
+ List nonMatchingProperties = new ArrayList<>();
+ // ´¦Àí²Ù×÷
+ spec.collectProperties(resolver, missingProperties, nonMatchingProperties);
+ // ÅжϽá¹û
+ if (!missingProperties.isEmpty()) {
+ return ConditionOutcome.noMatch(ConditionMessage
+ .forCondition(ConditionalOnProperty.class, spec)
+ .didNotFind("property", "properties").items(Style.QUOTE, missingProperties));
+ }
+ // ÅжϽá¹û
+ if (!nonMatchingProperties.isEmpty()) {
+ return ConditionOutcome.noMatch(ConditionMessage
+ .forCondition(ConditionalOnProperty.class, spec)
+ .found("different value in property", "different value in properties")
+ .items(Style.QUOTE, nonMatchingProperties));
+ }
+ // ÅжϽá¹û
+ return ConditionOutcome.match(ConditionMessage
+ .forCondition(ConditionalOnProperty.class, spec).because("matched"));
+}
+
+/**
+ * ´¦ÀíÊôÐÔ
+ */
+private void collectProperties(PropertyResolver resolver, List missing,
+ List nonMatching) {
+ for (String name : this.names) {
+ String key = this.prefix + name;
+ // resolver ´«ÈëµÄ environment
+ // properties Ìõ¼þÅжϾÍÊÇÅÐ¶Ï environment ÀïÓÐûÓÐÏàÓ¦ÊôÐÔ
+ if (resolver.containsProperty(key)) {
+ if (!isMatch(resolver.getProperty(key), this.havingValue)) {
+ nonMatching.add(name);
+ }
+ }
+ else {
+ if (!this.matchIfMissing) {
+ missing.add(name);
+ }
+ }
+ }
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`@ConditionalOnProperty` ×îÖÕÊÇͨ¹ýÅÐ¶Ï `environment` ÖÐÊÇ·ñÓиÃÊôÐÔÀ´´¦ÀíÌõ¼þÅжϵġ£
+
+### 6. `@ConditionalOnResource`£º`OnResourceCondition#getMatchOutcome`
+
+ÎÒÃÇÔÙÀ´¿´¿´ `@ConditionalOnResource` µÄ´¦Àí£¬Ò»°ãÎÒÃÇÕâÑùʹÓãº
+
+```
+@Bean
+@ConditionalOnResource(resources = "classpath:config.properties")
+public Config config() {
+ return config;
+}
+
+```
+
+±íʾµ± `classpath` ÖдæÔÚ `config.properties` ʱ£¬`config` ²Å»á±»³õʼ»¯ springbean¡£
+
+ÔÙ½øÈë `OnResourceCondition#getOutcomes` ·½·¨£º
+
+```
+@Override
+public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ MultiValueMap attributes = metadata
+ .getAllAnnotationAttributes(ConditionalOnResource.class.getName(), true);
+ // »ñÈ¡ ResourceLoader
+ ResourceLoader loader = context.getResourceLoader();
+ List locations = new ArrayList<>();
+ collectValues(locations, attributes.get("resources"));
+ Assert.isTrue(!locations.isEmpty(),
+ "@ConditionalOnResource annotations must specify at least one resource location");
+ List missing = new ArrayList<>();
+ // ±éÀúÅжÏ×ÊÔ´ÊÇ·ñ´æÔÚ
+ for (String location : locations) {
+ // location ÖпÉÄÜÓÐռλ·û£¬ÔÚÕâÀï´¦Àí
+ String resource = context.getEnvironment().resolvePlaceholders(location);
+ // ÅÐ¶Ï resource ÊÇ·ñ´æÔÚ
+ if (!loader.getResource(resource).exists()) {
+ missing.add(location);
+ }
+ }
+ // ´¦Àí½á¹û
+ if (!missing.isEmpty()) {
+ return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnResource.class)
+ .didNotFind("resource", "resources").items(Style.QUOTE, missing));
+ }
+ return ConditionOutcome.match(ConditionMessage.forCondition(ConditionalOnResource.class)
+ .found("location", "locations").items(locations));
+}
+
+```
+
+ÏÈÊÇͨ¹ý `OnResourceCondition#getOutcomes` ·½·¨À´»ñÈ¡ `ResourceLoader`£¬Í¨¹ýµ÷ÊÔ·½Ê½·¢ÏÖµ±Ç°µÄ `ResourceLoader` Ϊ `AnnotationConfigServletWebServerApplicationContext`£º
+
+
+
+»ñÈ¡µ½ `ResourceLoader` ºó£¬µ÷Óà `ResourceLoader#getResource(String)` À´»ñÈ¡×ÊÔ´£¬È»ºóµ÷Óà `Resource#exists` À´ÅжÏ×ÊÔ´ÊÇ·ñ´æÔÚ£¬×îºó´¦ÀíÆ¥Åä½á¹û¡£
+
+Õû¸öÁ÷³ÌµÄ¹Ø¼üÊÇÔÚ `ResourceLoader#getResource(String)`£¬ÎÒÃÇÀ´¿´¿´¸Ã·½·¨µÄ´¦Àí£¬½øÈëµ½ `GenericApplicationContext#getResource` ·½·¨£º
+
+```
+@Override
+public Resource getResource(String location) {
+ if (this.resourceLoader != null) {
+ return this.resourceLoader.getResource(location);
+ }
+ return super.getResource(location);
+}
+
+```
+
+ÕâÀïµÄ `this.resourceLoader` Ϊ `null`£¬½øÈ븸ÀàµÄ·½·¨ `DefaultResourceLoader#getResource`£º
+
+```
+public Resource getResource(String location) {
+ Assert.notNull(location, "Location must not be null");
+ for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
+ Resource resource = protocolResolver.resolve(location, this);
+ if (resource != null) {
+ return resource;
+ }
+ }
+ // ´¦Àí/¿ªÍ·µÄ×ÊÔ´
+ if (location.startsWith("/")) {
+ return getResourceByPath(location);
+ }
+ else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
+ // ´¦Àíclasspath¿ªÍ·µÄ×ÊÔ´
+ return new ClassPathResource(
+ location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
+ }
+ else {
+ try {
+ // ÒÔÉ϶¼²»Âú×㣬ʹÓà url À´½âÎö
+ URL url = new URL(location);
+ return (ResourceUtils.isFileURL(url)
+ ? new FileUrlResource(url) : new UrlResource(url));
+ }
+ catch (MalformedURLException ex) {
+ // url½âÎö³öÁËÎÊÌ⣬×îÖÕ»¹ÊÇÓà getResourceByPath(...) À´½âÎö
+ return getResourceByPath(location);
+ }
+ }
+}
+
+/**
+ * ͨ¹ý·¾¶µÃµ½ Resource
+ */
+protected Resource getResourceByPath(String path) {
+ return new ClassPathContextResource(path, getClassLoader());
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`DefaultResourceLoader#getResource` ͨ¹ýÅÐ¶Ï `location` µÄǰ׺£¬µÃµ½ÁË 4 ÖÖ `Resource`£º
+
+* `ClassPathContextResource`
+* `FileUrlResource`
+* `UrlResource`
+
+µÃµ½ `Resource` ºó£¬½ÓמÍÊÇÅжϸà `Resource` ÊÇ·ñ´æÔÚÁË£¬ÎÒÃÇÏÈÀ´¿´¿´ `ClassPathContextResource#exist` ·½·¨£¬¸Ã·½·¨ÔÚ `ClassPathResource#exists`£º
+
+```
+/**
+ * ÅÐ¶Ï Resource ÊÇ·ñ´æÔÚ
+ */
+@Override
+public boolean exists() {
+ return (resolveURL() != null);
+}
+
+/**
+ * ×ÊÔ´ÄÜ»ñÈ¡µ½£¬Ôò·µ»Ø×ÊÔ´¶ÔÓ¦µÄurl£¬·ñÔò·µ»Ønull
+ */
+@Nullable
+protected URL resolveURL() {
+ if (this.clazz != null) {
+ // ʹÓõ±Ç°µÄ class ¶ÔÓ¦µÄ classLoader À´»ñÈ¡
+ return this.clazz.getResource(this.path);
+ }
+ else if (this.classLoader != null) {
+ // ʹÓÃÖ¸¶¨µÄ classLoader À´»ñÈ¡
+ return this.classLoader.getResource(this.path);
+ }
+ else {
+ // »ñȡϵͳÀà¼ÓÔØÆ÷»ñÈ¡
+ return ClassLoader.getSystemResource(this.path);
+ }
+}
+
+```
+
+´Ó´úÂë¿ÉÒÔ¿´µ½£¬×îÖÕÊÇͨ¹ý `classLoader` »ñÈ¡ÎļþµÄ `url`£¬Í¨¹ýÅжÏÎļþ `url` ÊÇ·ñΪ `null` À´ÅÐ¶Ï `resource` ÊÇ·ñ´æÔÚ¡£
+
+ÔÙÀ´¿´¿´ `FileUrlResource` µÄÅжϣ¬Êµ¼ÊÉÏ `FileUrlResource` Óë `UrlResource` µÄ `exist()` ·½·¨¶¼ÊÇ `AbstractFileResolvingResource#exists`£¬ÕâÀïͳһ·ÖÎö¾Í¿ÉÒÔÁË£¬¸Ã·½·¨ÄÚÈÝÈçÏ£º
+
+```
+public boolean exists() {
+ try {
+ URL url = getURL();
+ if (ResourceUtils.isFileURL(url)) {
+ // Èç¹ûÊÇÎļþ£¬Ö±½ÓÅжÏÎļþÊÇ·ñ´æÔÚ
+ return getFile().exists();
+ }
+ else {
+ // ·ñÔòʹÓÃÍøÂçÎļþÀ´´¦Àí
+ URLConnection con = url.openConnection();
+ customizeConnection(con);
+ HttpURLConnection httpCon =
+ (con instanceof HttpURLConnection ? (HttpURLConnection) con : null);
+ // Èç¹ûÊÇhttp£¬ÔòÅжϿ´¿´Á´½Ó·µ»ØµÄ״̬Âë
+ if (httpCon != null) {
+ int code = httpCon.getResponseCode();
+ if (code == HttpURLConnection.HTTP_OK) {
+ return true;
+ }
+ else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
+ return false;
+ }
+ }
+ // Á¬½Ó contentLengthLong ´óÓÚ0£¬Ò²µ±³ÉÊÇtrue
+ if (con.getContentLengthLong() > 0) {
+ return true;
+ }
+ if (httpCon != null) {
+ httpCon.disconnect();
+ return false;
+ }
+ else {
+ getInputStream().close();
+ return true;
+ }
+ }
+ }
+ catch (IOException ex) {
+ return false;
+ }
+}
+
+```
+
+Èç¹ûÊDZ¾µØÎļþ£¬Ö±½ÓʹÓà `File#exists()` ·½·¨ÅжÏÎļþÊÇ·ñ´æÔÚ£¬·ñÔò¾ÍÅжÏÍøÂçÎļþÊÇ·ñ´æÔÚ£¬ÅжϷ½Ê½ÕâÀï¾Í²»Ï¸ËµÁË¡£
+
+×ܵÄÀ´Ëµ£¬springboot ¶Ô `@ConditionalOnResource` µÄÅжϻ¹ÊÇÓÐЩ¸´Ôӵģ¬ÕâÀï×ܽáÈçÏ£º
+
+1. Èç¹ûÊÇ `classpath` Îļþ£¬Í¨¹ý `classloader` »ñÈ¡Îļþ¶ÔÓ¦µÄ `url` ÊÇ·ñΪ `null` À´ÅжÏÎļþÊÇ·ñ´æÔÚ£»
+2. Èç¹ûÊÇÆÕͨÎļþ£¬ÔòÖ±½Ó `File#exists()` ·½·¨ÅжÏÎļþÊÇ·ñ´æÔÚ£»
+3. Èç¹ûÊÇÍøÂçÎļþ£¬ÏÈ´ò¿ªÒ»¸öÍøÂçÁ¬½Ó£¬ÅжÏÎļþÊÇ·ñ´æÔÚ¡£
+
+### 7. `@ConditionalOnWebApplication`£º`OnWebApplicationCondition#getMatchOutcome`
+
+ÎÒÃÇÔÙÀ´¿´¿´ `@ConditionalOnWebApplication` µÄ´¦Àí£¬½øÈë `OnWebApplicationCondition#getOutcomes` ·½·¨£º
+
+```
+@Override
+protected ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses,
+ AutoConfigurationMetadata autoConfigurationMetadata) {
+ ConditionOutcome[] outcomes = new ConditionOutcome[autoConfigurationClasses.length];
+ for (int i = 0; i < outcomes.length; i++) {
+ String autoConfigurationClass = autoConfigurationClasses[i];
+ if (autoConfigurationClass != null) {
+ // ´¦Àí½á¹û
+ outcomes[i] = getOutcome(autoConfigurationMetadata.get(autoConfigurationClass,
+ "ConditionalOnWebApplication"));
+ }
+ }
+ return outcomes;
+}
+
+/**
+ * ´¦Àí½á¹û
+ * springbootÖ§³ÖµÄwebÀàÐÍÓÐÁ½ÖÖ£ºSERVLET£¬REACTIVE
+ */
+private ConditionOutcome getOutcome(String type) {
+ if (type == null) {
+ return null;
+ }
+ ConditionMessage.Builder message = ConditionMessage
+ .forCondition(ConditionalOnWebApplication.class);
+ // Èç¹ûÖ¸¶¨µÄÀàÐÍÊÇ SERVLET
+ if (ConditionalOnWebApplication.Type.SERVLET.name().equals(type)) {
+ if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS, getBeanClassLoader())) {
+ return ConditionOutcome.noMatch(
+ message.didNotFind("servlet web application classes").atAll());
+ }
+ }
+ // Èç¹ûÖ¸¶¨µÄÀàÐÍÊÇ REACTIVE
+ if (ConditionalOnWebApplication.Type.REACTIVE.name().equals(type)) {
+ if (!ClassNameFilter.isPresent(REACTIVE_WEB_APPLICATION_CLASS, getBeanClassLoader())) {
+ return ConditionOutcome.noMatch(
+ message.didNotFind("reactive web application classes").atAll());
+ }
+ }
+ // Èç¹ûûÓÐÖ¸¶¨webÀàÐÍ
+ if (!ClassNameFilter.isPresent(SERVLET_WEB_APPLICATION_CLASS, getBeanClassLoader())
+ && !ClassUtils.isPresent(REACTIVE_WEB_APPLICATION_CLASS, getBeanClassLoader())) {
+ return ConditionOutcome.noMatch(
+ message.didNotFind("reactive or servlet web application classes").atAll());
+ }
+ return null;
+}
+
+```
+
+Õâ¸ö·½·¨ºÜ¼òµ¥£¬´¦ÀíÂ߼Ϊ£º¸ù¾Ý `@ConditionalOnWebApplication` ÖÐÖ¸¶¨µÄÀàÐÍ£¬Åж϶ÔÓ¦µÄÀàÊÇ·ñ´æÔÚ£¬ÅжϷ½Ê½Óë `@ConditionalOnClass` ÅжÏÀàÊÇ·ñ´æÔÚÒ»Ö£¬¶øÁ½ÖÖÀàÐͶÔÓ¦µÄÀàÈçÏ£º
+
+* Servlet£º`org.springframework.web.context.support.GenericWebApplicationContext`
+* Reactive£º`org.springframework.web.reactive.HandlerResult`
+
+### 8. `@ConditionalOnExpression`£º`OnExpressionCondition#getMatchOutcome`
+
+ÎÒÃÇÔÙÀ´¿´¿´ `@ConditionalOnExpression` µÄ´¦Àí£¬½øÈë `OnExpressionCondition#getOutcomes` ·½·¨£º
+
+```
+/**
+ * ´¦ÀíÆ¥Åä½á¹û
+ */
+@Override
+public ConditionOutcome getMatchOutcome(ConditionContext context,
+ AnnotatedTypeMetadata metadata) {
+ // »ñÈ¡±í´ïʽ
+ String expression = (String) metadata.getAnnotationAttributes(
+ ConditionalOnExpression.class.getName()).get("value");
+ expression = wrapIfNecessary(expression);
+ ConditionMessage.Builder messageBuilder = ConditionMessage
+ .forCondition(ConditionalOnExpression.class, "(" + expression + ")");
+ // ´¦Àíռλ·û
+ expression = context.getEnvironment().resolvePlaceholders(expression);
+ ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
+ if (beanFactory != null) {
+ // ¼ÆËã±í´ïʽµÄÖµ
+ boolean result = evaluateExpression(beanFactory, expression);
+ return new ConditionOutcome(result, messageBuilder.resultedIn(result));
+ }
+ return ConditionOutcome.noMatch(messageBuilder.because("no BeanFactory available."));
+}
+
+/**
+ * ¼ÆËã±í´ïʽµÄÖµ
+ */
+private Boolean evaluateExpression(ConfigurableListableBeanFactory beanFactory,
+ String expression) {
+ BeanExpressionResolver resolver = beanFactory.getBeanExpressionResolver();
+ if (resolver == null) {
+ resolver = new StandardBeanExpressionResolver();
+ }
+ // ÔÚÕâÀï½âÎö±í´ïʽµÄÖµ
+ BeanExpressionContext expressionContext = new BeanExpressionContext(beanFactory, null);
+ Object result = resolver.evaluate(expression, expressionContext);
+ return (result != null && (boolean) result);
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬springboot ×îÖÕÊÇͨ¹ý `BeanExpressionResolver#evaluate` ·½·¨À´¼ÆËã±í´ïʽ½á¹û£¬¹ØÓÚ spring ±í´ïʽ£¬±¾ÎľͲ»Õ¹¿ª·ÖÎöÁË¡£
+
+ºÃÁË£¬spring Ìõ¼þ×¢½âµÄ·ÖÎö¾Íµ½ÕâÀïÁË£¬ÐèҪ˵Ã÷µÄÊÇ£¬springboot »¹ ÓÐÆäËûÌõ¼þ×¢½â£º
+
+
+
+ÕâЩע½âµÄÅжϷ½Ê½Óë±¾Îĵķ½Ê½ÏàÀàËÆ£¬¾Í²»Ò»Ò»½øÐзÖÎöÁË¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4921590](https://my.oschina.net/funcy/blog/4921590) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
From 684fda33f8634e38f974c9deadf177bd90fb3042 Mon Sep 17 00:00:00 2001
From: h2pl <362294931@qq.com>
Date: Sat, 22 Apr 2023 17:23:24 +0800
Subject: [PATCH 09/32] spring sourcecode
---
ReadMe.md | 1 -
...70\350\247\201\346\263\250\350\247\243.md" | 0
...13\345\214\226\346\265\201\347\250\213.md" | 477 +++++++
...13\345\214\226\346\265\201\347\250\213.md" | 762 +++++++++++
...231\250\345\220\257\345\212\250 Tomcat.md" | 299 +++++
...@EnableWebMvc \346\263\250\350\247\243.md" | 583 +++++++++
...23\346\236\204\346\200\273\347\273\223.md" | 82 ++
...71\213\350\216\267\345\217\226 Handler.md" | 772 +++++++++++
...1\214 Handler \346\226\271\346\263\225.md" | 668 ++++++++++
...o \345\217\212 @EnableAspectJAutoProxy.md" | 230 ++++
...20\357\274\210\344\270\212\357\274\211.md" | 669 ++++++++++
...20\357\274\210\344\270\213\357\274\211.md" | 628 +++++++++
...\274\232cglib \344\273\243\347\220\206.md" | 449 +++++++
...57\274\232aop \346\200\273\347\273\223.md" | 22 +
...50\346\200\201\344\273\243\347\220\206.md" | 742 +++++++++++
...13\345\212\241\347\273\204\344\273\266.md" | 825 ++++++++++++
...347\232\204\345\244\204\347\220\206 01.md" | 387 ++++++
...47\350\241\214\346\265\201\347\250\213.md" | 664 ++++++++++
...347\232\204\345\244\204\347\220\206 03.md" | 500 ++++++++
...347\232\204\345\244\204\347\220\206 04.md" | 433 +++++++
...347\232\204\345\244\204\347\220\206 02.md" | 580 +++++++++
...01\347\250\213\346\246\202\350\247\210.md" | 230 ++++
...13\344\273\266\345\244\204\347\220\206.md" | 166 +++
...53\346\217\217\346\265\201\347\250\213.md" | 800 ++++++++++++
...n \347\232\204\345\210\233\345\273\272.md" | 1105 ++++++++++++++++
...t \347\232\204\345\210\233\345\273\272.md" | 161 +++
...7\350\241\214 BeanFactoryPostProcessor.md" | 495 ++++++++
...04\345\210\235\345\247\213\345\214\226.md" | 377 ++++++
...\263\250\345\206\214 BeanPostProcessor.md" | 146 +++
...01\347\250\213\346\200\273\347\273\223.md" | 15 +
...20\347\232\204\345\244\204\347\220\206.md" | 158 +++
...06\345\244\207\345\267\245\344\275\234.md" | 230 ++++
...\274\232Spring\346\246\202\350\277\260.md" | 157 ---
...04\344\273\266\344\271\213 BeanFactory.md" | 88 ++
...273\266\344\271\213 ApplicationContext.md" | 802 ++++++++++++
...344\273\266\344\271\213 BeanDefinition.md" | 0
...6\344\271\213 BeanFactoryPostProcessor.md" | 129 ++
...\273\266\344\271\213 BeanPostProcessor.md" | 132 ++
...ComponentScan \346\263\250\350\247\243.md" | 622 +++++++++
...0\206 @Import \346\263\250\350\247\243.md" | 849 +++++++++++++
...220\206 @Bean \346\263\250\350\247\243.md" | 946 ++++++++++++++
... @Conditional \346\263\250\350\247\243.md" | 385 ++++++
...47\350\241\214\351\241\272\345\272\217.md" | 671 ++++++++++
...13\344\273\266\346\234\272\345\210\266.md" | 918 ++++++++++++++
...06\350\256\272\345\237\272\347\237\263.md" | 1091 ++++++++++++++++
...20\347\240\201\345\210\206\346\236\220.md" | 1123 +++++++++++++++++
...346\263\250\350\247\243 @EventListener.md" | 662 ++++++++++
...43\347\232\204\345\244\204\347\220\206.md" | 710 +++++++++++
48 files changed, 22783 insertions(+), 158 deletions(-)
rename "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md" => "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md" (100%)
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/DispatcherServlet \345\210\235\345\247\213\345\214\226\346\265\201\347\250\213.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/RequestMapping \345\210\235\345\247\213\345\214\226\346\265\201\347\250\213.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/Spring \345\256\271\345\231\250\345\220\257\345\212\250 Tomcat.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC demo \344\270\216 @EnableWebMvc \346\263\250\350\247\243.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC \346\225\264\344\275\223\346\272\220\347\240\201\347\273\223\346\236\204\346\200\273\347\273\223.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/\350\257\267\346\261\202\346\211\247\350\241\214\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\344\271\213\350\216\267\345\217\226 Handler.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/\350\257\267\346\261\202\346\211\247\350\241\214\346\265\201\347\250\213\357\274\210\344\272\214\357\274\211\344\271\213\346\211\247\350\241\214 Handler \346\226\271\346\263\225.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AOP \347\244\272\344\276\213 demo \345\217\212 @EnableAspectJAutoProxy.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AnnotationAwareAspectJAutoProxyCreator \345\210\206\346\236\220\357\274\210\344\270\212\357\274\211.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AnnotationAwareAspectJAutoProxyCreator \345\210\206\346\236\220\357\274\210\344\270\213\357\274\211.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\344\272\224\357\274\211\357\274\232cglib \344\273\243\347\220\206.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\345\205\255\357\274\211\357\274\232aop \346\200\273\347\273\223.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\345\233\233\357\274\211\357\274\232jdk \345\212\250\346\200\201\344\273\243\347\220\206.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\270\200\357\274\211\357\274\232\350\256\244\350\257\206\344\272\213\345\212\241\347\273\204\344\273\266.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\270\211\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 01.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\272\214\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\346\211\247\350\241\214\346\265\201\347\250\213.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\272\224\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 03.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\345\205\255\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 04.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\345\233\233\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 02.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\357\274\232\345\220\257\345\212\250\346\265\201\347\250\213\346\246\202\350\247\210.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\203\357\274\211\357\274\232\345\233\275\351\231\205\345\214\226\344\270\216\344\272\213\344\273\266\345\244\204\347\220\206.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\211\357\274\211\357\274\232\345\214\205\347\232\204\346\211\253\346\217\217\346\265\201\347\250\213.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\271\235\357\274\211\357\274\232\345\215\225\344\276\213 bean \347\232\204\345\210\233\345\273\272.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\272\214\357\274\211\357\274\232ApplicationContext \347\232\204\345\210\233\345\273\272.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\272\224\357\274\211\357\274\232\346\211\247\350\241\214 BeanFactoryPostProcessor.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\205\253\357\274\211\357\274\232\345\256\214\346\210\220 BeanFactory \347\232\204\345\210\235\345\247\213\345\214\226.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\205\255\357\274\211\357\274\232\346\263\250\345\206\214 BeanPostProcessor.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\215\201\344\270\200\357\274\211\357\274\232\345\220\257\345\212\250\346\265\201\347\250\213\346\200\273\347\273\223.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\215\201\357\274\211\357\274\232\345\220\257\345\212\250\345\256\214\346\210\220\347\232\204\345\244\204\347\220\206.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\345\233\233\357\274\211\357\274\232\345\220\257\345\212\250\345\211\215\347\232\204\345\207\206\345\244\207\345\267\245\344\275\234.md"
delete mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\346\272\220\347\240\201\345\211\226\346\236\220\357\274\232Spring\346\246\202\350\277\260.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\347\273\204\344\273\266\345\210\206\346\236\220/Spring \347\273\204\344\273\266\344\271\213 BeanFactory.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\347\273\204\344\273\266\345\210\206\346\236\220/spring \347\273\204\344\273\266\344\271\213 ApplicationContext.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\347\273\204\344\273\266\345\210\206\346\236\220/spring \347\273\204\344\273\266\344\271\213 BeanDefinition.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\347\273\204\344\273\266\345\210\206\346\236\220/spring \347\273\204\344\273\266\344\271\213 BeanFactoryPostProcessor.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\347\273\204\344\273\266\345\210\206\346\236\220/spring \347\273\204\344\273\266\344\271\213 BeanPostProcessor.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\351\207\215\350\246\201\346\234\272\345\210\266\346\216\242\347\247\230/ConfigurationClassPostProcessor\357\274\210\344\270\200\357\274\211\357\274\232\345\244\204\347\220\206 @ComponentScan \346\263\250\350\247\243.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\351\207\215\350\246\201\346\234\272\345\210\266\346\216\242\347\247\230/ConfigurationClassPostProcessor\357\274\210\344\270\211\357\274\211\357\274\232\345\244\204\347\220\206 @Import \346\263\250\350\247\243.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\351\207\215\350\246\201\346\234\272\345\210\266\346\216\242\347\247\230/ConfigurationClassPostProcessor\357\274\210\344\272\214\357\274\211\357\274\232\345\244\204\347\220\206 @Bean \346\263\250\350\247\243.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\351\207\215\350\246\201\346\234\272\345\210\266\346\216\242\347\247\230/ConfigurationClassPostProcessor\357\274\210\345\233\233\357\274\211\357\274\232\345\244\204\347\220\206 @Conditional \346\263\250\350\247\243.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\351\207\215\350\246\201\346\234\272\345\210\266\346\216\242\347\247\230/Spring \346\216\242\347\247\230\344\271\213 AOP \347\232\204\346\211\247\350\241\214\351\241\272\345\272\217.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\351\207\215\350\246\201\346\234\272\345\210\266\346\216\242\347\247\230/Spring \346\216\242\347\247\230\344\271\213 Spring \344\272\213\344\273\266\346\234\272\345\210\266.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\351\207\215\350\246\201\346\234\272\345\210\266\346\216\242\347\247\230/spring \346\216\242\347\247\230\344\271\213\345\276\252\347\216\257\344\276\235\350\265\226\347\232\204\350\247\243\345\206\263\357\274\210\344\270\200\357\274\211\357\274\232\347\220\206\350\256\272\345\237\272\347\237\263.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\351\207\215\350\246\201\346\234\272\345\210\266\346\216\242\347\247\230/spring \346\216\242\347\247\230\344\271\213\345\276\252\347\216\257\344\276\235\350\265\226\347\232\204\350\247\243\345\206\263\357\274\210\344\272\214\357\274\211\357\274\232\346\272\220\347\240\201\345\210\206\346\236\220.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\351\207\215\350\246\201\346\234\272\345\210\266\346\216\242\347\247\230/spring \346\216\242\347\247\230\344\271\213\347\233\221\345\220\254\345\231\250\346\263\250\350\247\243 @EventListener.md"
create mode 100644 "docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\351\207\215\350\246\201\346\234\272\345\210\266\346\216\242\347\247\230/spring \346\216\242\347\247\230\344\271\213\347\273\204\345\220\210\346\263\250\350\247\243\347\232\204\345\244\204\347\220\206.md"
diff --git a/ReadMe.md b/ReadMe.md
index 979b79b..c23b543 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -159,7 +159,6 @@
### Springæº�ç �分æž�
-* [Springæº�ç �剖æž�:Spring概述](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:Spring概述.md)
* [Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:åˆ�探SpringIOCæ ¸å¿ƒæµ�程.md)
* [Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹ ](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�:SpringIOCå®¹å™¨çš„åŠ è½½è¿‡ç¨‹.md)
* [Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�](docs/Spring全家桶/Springæº�ç �分æž�/Springæº�ç �剖æž�ï¼šæ‡’åŠ è½½çš„å�•例Bean获å�–过程分æž�.md)
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
similarity index 100%
rename from "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
rename to "docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC/SpringMVC\345\270\270\350\247\201\346\263\250\350\247\243.md"
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/DispatcherServlet \345\210\235\345\247\213\345\214\226\346\265\201\347\250\213.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/DispatcherServlet \345\210\235\345\247\213\345\214\226\346\265\201\347\250\213.md"
new file mode 100644
index 0000000..4ffcaa6
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/DispatcherServlet \345\210\235\345\247\213\345\214\226\346\265\201\347\250\213.md"
@@ -0,0 +1,477 @@
+ÔÚ[ÉÏһƪÎÄÕÂ](https://my.oschina.net/funcy/blog/4696657 "ÉÏһƪÎÄÕÂ")ÖУ¬ÎÒÃÇͨ¹ýÒ»¸ö¼òµ¥µÄ demo ³É¹¦Æô¶¯ÁË springmvc Ó¦Óã¬ÔÚÌṩµÄ demo ÖУ¬ÎÒÃÇÖªµÀ tomcat ÔÚÆô¶¯Ê±»áµ÷Óà `MyWebApplicationInitializer#onStartup` ·½·¨£¬È»ºóÆô¶¯ spring ÈÝÆ÷¡£ÄÇô tomcat ¾¿¾¹ÊÇÈçºÎÆô¶¯ spring µÄÄØ£¿
+
+### 1\. servlet ³õʼ»¯£º`DispatcherServlet#init`
+
+ÎÒÃÇÔÙ»ØÒäÏ `MyWebApplicationInitializer#onStartup` ·½·¨£º
+
+```
+@Override
+public void onStartup(ServletContext servletContext) {
+ System.out.println("webApplicationInitializer ...");
+ // ´´½¨ spring µÄ applicationContext
+ AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
+ context.register(MvcConfig.class);
+
+ // ʵÀý»¯ DispatcherServlet
+ DispatcherServlet servlet = new DispatcherServlet(context);
+
+ // ½«DispatcherServlet×¢²áµ½servletÈÝÆ÷
+ ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
+ registration.setLoadOnStartup(1);
+ registration.addMapping("/*");
+}
+
+```
+
+Õâ¶Î´úÂëÏÈ×¼±¸ÁËÒ»¸ö `AnnotationConfigWebApplicationContext`£¬½«Æä×÷Ϊ²ÎÊý´«Èë `DispatcherServlet` ÖУ¬È»ºóÍù servlet ÈÝÆ÷ÖÐÌí¼Ó `DispatcherServlet`¡£ÕâÑù£¬servlet ÈÝÆ÷ÔÚÆô¶¯Ê±£¬¾Í»áÆô¶¯ spring ÈÝÆ÷ÁË¡£ÕâÀï×îÖØÒªµÄ¾ÍÊÇ `DispatcherServlet`£¬½ÓÏÂÀ´ÎÒÃǾÍÀ´·ÖÎöÕâ¸ö servlet.
+
+ÎÒÃÇÏÈÀ´¿´Ï `DispatcherServlet` µÄ¼Ì³Ð½á¹¹£º
+
+
+
+´ÓÉÏͼ¿ÉÒÔ¿´µ½£¬spring ÌṩµÄ¡¢¸ú servlet Ïà¹ØµÄÀàÓÐÈý¸ö£º`HttpServletBean`¡¢`FrameworkServlet` Óë `DispatcherServlet`¡£×÷Ϊ servlet£¬ÎÒÃÇÖªµÀÆä³õʼ»¯·½·¨Îª `GenericServlet#init()`£¬Ò²¾ÍÊÇ servlet µÄÈë¿Ú·½·¨£¬ÎÒÃǵķÖÎöÒ²½«´ÓÕâÀ↑ʼ¡£
+
+ÓÉÓÚ `DispatcherServlet` ʵÏÖÁË `HttpServletBean`¡¢`FrameworkServlet`£¬`DispatcherServlet#init()` ʵ¼ÊÉϼ̳Ð×Ô `HttpServletBean#init`£º
+
+```
+@Override
+public final void init() throws ServletException {
+
+ PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
+ if (!pvs.isEmpty()) {
+ try {
+ BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
+ ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
+ bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
+ initBeanWrapper(bw);
+ bw.setPropertyValues(pvs, true);
+ }
+ catch (BeansException ex) {
+ ...
+ }
+ }
+
+ // ³õʼ»¯ servlet bean£¬springµÄÏà¹ØÅäÖþÍÊÇÔÚÕâÀï½øÐеÄ
+ initServletBean();
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬Õâ¸ö·½·¨¼ÓÔØÁËһЩÅäÖã¬È»ºó¾Íµ÷ÓÃÁË `initServletBean`£¬²¢Ã»ÓÐ×öһЩ spring ʵÖÊÐÔµÄÄÚÈÝ¡£ÎÒÃǼÌÐø¸ú½ø£¬Ìø¹ýÆäÖв»ÖØÒªµÄ·½·¨£¬µ÷ÓÃÁ´Â·ÈçÏ£º
+
+```
+-HttpServletBean#init
+ -FrameworkServlet#initServletBean
+ -FrameworkServlet#initWebApplicationContext
+
+```
+
+Ò»Ö±¸úµ½ `FrameworkServlet#initWebApplicationContext`£º
+
+```
+protected WebApplicationContext initWebApplicationContext() {
+ // »ñÈ¡ÀàÐÍΪWebServerApplicationContextµÄ¸¸ÈÝÆ÷£¬ÕâÀïµÃµ½µÄ½á¹ûΪnull
+ WebApplicationContext rootContext =
+ WebApplicationContextUtils.getWebApplicationContext(getServletContext());
+ WebApplicationContext wac = null;
+
+ if (this.webApplicationContext != null) {
+ // Õâ¸öwebApplicationContext£¬¾ÍÊÇÔÚMyWebApplicationInitializer#onStart·½·¨ÖÐ
+ // ´«ÈëµÄAnnotationConfigWebApplicationContext
+ wac = this.webApplicationContext;
+ if (wac instanceof ConfigurableWebApplicationContext) {
+ ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
+ if (!cwac.isActive()) {
+ if (cwac.getParent() == null) {
+ cwac.setParent(rootContext);
+ }
+ // ÔÚÕâÀïµ÷Óà AbstractApplicationContext#refresh Æô¶¯
+ configureAndRefreshWebApplicationContext(cwac);
+ }
+ }
+ }
+ // wac²»Îªnull,ÕâÀï²»»áÔËÐÐ
+ if (wac == null) {
+ wac = findWebApplicationContext();
+ }
+ // wac²»Îªnull,ÕâÀï²»»áÔËÐÐ
+ if (wac == null) {
+ // ´´½¨WebApplicationContext£¬ÖØÐÂÔËÐÐAbstractApplicationContext#refresh
+ wac = createWebApplicationContext(rootContext);
+ }
+
+ // ʵ¼ÊÉÏ£¬refreshEventReceivedΪtrue£¬if¿éµÄ´úÂë²¢²»Ö´ÐÐ
+ if (!this.refreshEventReceived) {
+ synchronized (this.onRefreshMonitor) {
+ // Ë¢ÐÂÓ¦ÓÃÉÏÏÂÎÄ£¬springmvcÏà¹Ø´úÂëÔÚÕâÀïÔËÐÐ
+ onRefresh(wac);
+ }
+ }
+
+ if (this.publishContext) {
+ // ½« WebApplicationContextÊÓΪservletContext Ò»¸öÊôÐÔ£¬¼ÓÈëµ½ servletContext ÖÐ
+ // Ö®ºó¾Í¿ÉÒÔʹÓÃ
+ // WebApplicationContextUtils.getWebApplicationContext(ServletContext, String attrName)
+ // À´»ñÈ¡
+ String attrName = getServletContextAttributeName();
+ getServletContext().setAttribute(attrName, wac);
+ }
+
+ return wac;
+}
+
+```
+
+Õâ¸ö·½·¨µÄÏà¹Ø²Ù×÷´úÂëÖÐÒÑÓÐ×¢ÊÍ£¬Êµ¼ÊÉÏÕâ¸ö·½·¨×î ÖØÒªµÄ´úÂëΪ
+
+```
+protected WebApplicationContext initWebApplicationContext() {
+ ...
+ // ÔÚÕâÀïµ÷Óà AbstractApplicationContext#refresh Æô¶¯
+ configureAndRefreshWebApplicationContext(cwac);
+ ...
+ return wac;
+}
+
+```
+
+Ïà¹Ø·ÖÎöÈçÏ£º
+
+> FrameworkServlet#configureAndRefreshWebApplicationContext
+
+```
+protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
+ if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
+ if (this.contextId != null) {
+ wac.setId(this.contextId);
+ }
+ else {
+ // Generate default id...
+ wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
+ ObjectUtils.getDisplayString(getServletContext().getContextPath()) +
+ '/' + getServletName());
+ }
+ }
+ wac.setServletContext(getServletContext());
+ wac.setServletConfig(getServletConfig());
+ wac.setNamespace(getNamespace());
+ // Ìí¼Óʼþ¼àÌýÆ÷£¬¼àÌýspringÆô¶¯Íê³Éʼþ
+ // Õâ¸ö¼àÌýÆ÷Ê®·ÖÖØÒª£¬ºóÃæ»á·ÖÎö
+ wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
+ ConfigurableEnvironment env = wac.getEnvironment();
+ if (env instanceof ConfigurableWebEnvironment) {
+ ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
+ }
+ // À©Õ¹µã£¬Ã»ÓÐʲô¹¦ÄÜ£¬´ýÒÔºóÀ©Õ¹
+ postProcessWebApplicationContext(wac);
+ applyInitializers(wac);
+ // µ÷ÓþÍÊÇ AbstractApplicationContext.refresh
+ wac.refresh();
+}
+
+```
+
+Õâ¸ö·½·¨Êµ¼ÊÉÏ»¹ÊÇÅäÖà `ConfigurableWebApplicationContext` µÄһЩÊôÐÔ£¬×îºóµ÷Óà `AbstractApplicationContext#refresh` À´Æô¶¯ spring ÈÝÆ÷¡£¹ØÓÚ `AbstractApplicationContext#refresh` µÄ·ÖÎö£¬¿ÉÒԲο¼ [spring Æô¶¯Á÷³ÌÖ®Æô¶¯Ç°µÄ×¼±¸¹¤×÷](https://my.oschina.net/funcy/blog/4633169 "springÆô¶¯Á÷³ÌÖ®Æô¶¯Ç°µÄ×¼±¸¹¤×÷")¡£
+
+µ½ÕâÀspring ÈÝÆ÷¾ÍÕæÕýÆô¶¯ÁË¡£
+
+### 2. `SourceFilteringListener`£ºÆô¶¯Ê¼þ¼àÌýÆ÷
+
+ÕâÀïÓиöÎÊÌ⣺ÔÚ springmvc ÖУ¬ÎÒÃÇÖªµÀ spring »áʶ±ð `@Controller`£¬½« `RequestMapping`/`@PostMapping`/`@GetMapping` µÈ×¢½âÖеÄ·¾¶·âװΪһ¸ö uri£¬µÈ´ýÍⲿ·ÃÎÊ£¬µ«ÊÇÎÒÃÇһ·¿´À´£¬Ëƺõ spring ²¢Ã»ÓÐ×öÕâЩ¹¤×÷£¬ÄÇôÕⲿ·ÖµÄ¹¤×÷ÊÇÔÚÄÄÀï½øÐеÄÄØ£¿
+
+ʵ¼ÊÉÏ£¬spring Õⲿ·ÖµÄ¹¤×÷ÊÇÔÚÆô¶¯¼àÌýÆ÷ÖÐÍê³ÉµÄ£¬Ò²¾ÍÊÇ
+
+```
+wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
+
+```
+
+Õâ¸ö¼àÌýÆ÷¼àÌýµÄÊÇ spring µÄÆô¶¯ ʼþ£¬½«ÔÚ spring ÈÝÆ÷Æô¶¯Íê³Éºóµ÷Óá£
+
+¹ØÓÚ spring µÄʼþÏà¹ØÄÚÈÝ£¬¿ÉÒԲο¼ [spring Ì½ÃØÖ® spring ʼþ»úÖÆ](https://my.oschina.net/funcy/blog/4713339 "springÌ½ÃØÖ®spring ʼþ»úÖÆ")£¬ÕâÀïÖ±½Ó˵½áÂÛ£ºspring ÖÐÌṩÁË `ApplicationEventPublisher#publishEvent(Object)`£¨Ê¼þ·¢²¼Æ÷£©¡¢`ApplicationEvent`£¨Ê¼þ£©Óë `ApplicationListener` £¨Ê¼þ¼àÌýÆ÷£©£¬µ± spring ͨ¹ý `ApplicationEventPublisher#publishEvent(Object)` ·¢²¼ `ApplicationEvent`£¨Ê¼þ£©Ê±£¬`ApplicationListener` £¨Ê¼þ¼àÌýÆ÷£©½«»á¼àÌýµ½¡£
+
+ÎÒÃÇÀ´¿´¿´ `SourceFilteringListener`£º
+
+```
+public class SourceFilteringListener implements GenericApplicationListener, SmartApplicationListener {
+
+ private final Object source;
+
+ @Nullable
+ private GenericApplicationListener delegate;
+
+ /**
+ * ¹¹Ôì·½·¨£¬´«Èë event Óë listener
+ */
+ public SourceFilteringListener(Object source, ApplicationListener> delegate) {
+ this.source = source;
+ this.delegate = (delegate instanceof GenericApplicationListener ?
+ (GenericApplicationListener) delegate : new GenericApplicationListenerAdapter(delegate));
+ }
+
+ /**
+ * ʼþ¼àÌý·½·¨
+ */
+ @Override
+ public void onApplicationEvent(ApplicationEvent event) {
+ if (event.getSource() == this.source) {
+ // µ÷ÓÃÕæÕýµÄʼþ´¦Àí
+ onApplicationEventInternal(event);
+ }
+ }
+
+ /**
+ * ´¦Àíʼþ
+ */
+ protected void onApplicationEventInternal(ApplicationEvent event) {
+ if (this.delegate == null) {
+ throw new IllegalStateException(...);
+ }
+ // ×îÖÕ»¹Êǵ÷Óô«ÈëµÄʼþ¼àÌýÆ÷µÄonApplicationEvent·½·¨
+ this.delegate.onApplicationEvent(event);
+ }
+
+ // Ê¡ÂÔÁËһЩ´úÂë
+ ...
+
+```
+
+¿ÉÒÔ¿´µ½£¬`SourceFilteringListener` ͨ¹ý¹¹Ôì·½·¨´«ÈëÁË `ContextRefreshListener` µÄʵÀý£¬È»ºóÔÚ `SourceFilteringListener#onApplicationEvent` ·½·¨ÖУ¬×îÖÕµ÷ÓõÄÊÇ `ContextRefreshListener#onApplicationEvent` ·½·¨¡£
+
+½ÓÏÂÀ´ÎÒÃÇÔÙÀ´¿´ `ContextRefreshListener`£º
+
+> FrameworkServlet.ContextRefreshListener
+
+```
+private class ContextRefreshListener implements ApplicationListener {
+
+ @Override
+ public void onApplicationEvent(ContextRefreshedEvent event) {
+ FrameworkServlet.this.onApplicationEvent(event);
+ }
+}
+
+```
+
+Õâ¸öÀàÊÇ `FrameworkServlet` µÄÄÚ²¿À࣬´úÂëºÜ¼òµ¥£¬×îÖÕµ÷ÓõÄÊÇ `FrameworkServlet#onApplicationEvent`£º
+
+```
+public void onApplicationEvent(ContextRefreshedEvent event) {
+ // ÐÞ¸Ä״̬£¬Õâ¸öºÜ¹Ø¼ü£¬ÔËÐÐÁËÕâÐкó£¬
+ // FrameworkServlet#initWebApplicationContextÀïµÄonRefresh(...)¾Í²»»áÔËÐÐ
+ this.refreshEventReceived = true;
+ synchronized (this.onRefreshMonitor) {
+ // ¾ßÌåµÄÂß¼´¦Àí
+ onRefresh(event.getApplicationContext());
+ }
+}
+
+```
+
+½ÓÏÂÀ´¾ÍÊÇ `DispatcherServlet#onRefresh` ·½·¨ÁË£º
+
+```
+@Override
+protected void onRefresh(ApplicationContext context) {
+ initStrategies(context);
+}
+
+/**
+ * springmvcµÄÖÕ¼«°ÂÃØ¾ÍÔÚÕâÀïÁË
+ * Õâ¸ö·½·¨ÖУ¬³õʼ»¯ÁËspringmvcµÄ¸÷ÖÖ×é¼þ
+ */
+protected void initStrategies(ApplicationContext context) {
+ initMultipartResolver(context);
+ initLocaleResolver(context);
+ initThemeResolver(context);
+ initHandlerMappings(context);
+ initHandlerAdapters(context);
+ initHandlerExceptionResolvers(context);
+ initRequestToViewNameTranslator(context);
+ initViewResolvers(context);
+ initFlashMapManager(context);
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬×îÖÕÔËÐеķ½·¨ÊÇ `DispatcherServlet#initStrategies`£¬Õâ¸ö·½·¨ËäÖ»ÁÈÁÈÊýÐУ¬ÇÒ³õʼ»¯ÁË springmvc ¸÷ÒÀÀµ×é¼þ£¡
+
+### 3. `DispatcherServlet#initStrategies`£º³õʼ»¯ springmvc ×é¼þ
+
+spring ÔÚÆô¶¯Íê³Éºó£¬»á·¢²¼Æô¶¯Íê³Éʼþ£¬È»ºóÓɼàÌýÆ÷ `SourceFilteringListener` ¼àÌýµ½¸Ãʼþºó£¬Ö´ÐмàÌýÂß¼£¬×îÖÕµ÷Óõ½ `DispatcherServlet#initStrategies`¡£±¾½ÚÎÒÃǽ«À´·ÖÎö `DispatcherServlet#initStrategies` µÄÖ´Ðйý³Ì¡£
+
+ÆäʵÕâ¸ö·½·¨ºÜ¼òµ¥£¬ÀïÃæÓÐ 9 ÐдúÂ룬ÿÐдúÂë¶¼³õʼ»¯ÁË springmvc µÄÒ»¸ö×é¼þ£¬Èç `initMultipartResolver`£º
+
+```
+public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
+
+private void initMultipartResolver(ApplicationContext context) {
+ try {
+ // ´ÓspringÈÝÆ÷ÖлñÈ¡multipartResolver¶ÔÏó
+ this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
+ }
+ catch (NoSuchBeanDefinitionException ex) {
+ // »ñȡʧ°Ü£¬Ä¬ÈÏΪnull
+ this.multipartResolver = null;
+ }
+ }
+}
+
+```
+
+`multipartResolver` ÊÇÓÃÀ´´¦ÀíÎļþÉÏ´«µÄ bean£¬ÔÚ spring ÖУ¬ÎÒÃÇ´¦ÀíÎļþÉÏ´«Ê±£¬Ò»°ã»áÏñÕâÑùÒýÈë `multipartResolver` bean£»
+
+```
+@Bean(name = "multipartResolver")
+public MultipartResolver multipartResolver() {
+ CommonsMultipartResolver resolver = new CommonsMultipartResolver();
+ resolver.setDefaultEncoding("UTF-8");
+ resolver.setResolveLazily(true);
+ resolver.setMaxInMemorySize(40960);
+ //ÔÊÐíÉÏ´«Îļþ×î´óΪ1G
+ resolver.setMaxUploadSize(1024 * 1024 * 1024);
+ return resolver;
+}
+
+```
+
+Èç¹ûδÒýÈë `multipartResolver` bean£¬spring ĬÈÏΪ null£¬¾Í²»ÄܽøÐÐÎļþÉÏ´«ÁË¡£
+
+ÔÙÀ´¿´¿´ `springmvc` `HandlerMappings` µÄ³õʼ»¯¹ý³Ì£º
+
+> DispatcherServlet
+
+```
+public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
+
+private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
+
+private static final Properties defaultStrategies;
+
+static {
+ try {
+ // ÔÚstatic¿éÖмÓÔØDispatcherServlet.propertiesÎļþ
+ ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH,
+ DispatcherServlet.class);
+ defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
+ }
+ catch (IOException ex) {
+ throw new IllegalStateException(...);
+ }
+}
+
+/**
+ * handlerMappings ÊôÐÔ
+ */
+@Nullable
+private List handlerMappings;
+
+/**
+ * ³õʼ»¯ HandlerMappings
+ * 1\. ´Óspring ÈÝÆ÷ÖлñÈ¡ HandlerMapping bean£¬
+ * Èç¹û»ñÈ¡³É¹¦£¬Ôò°ÑµÃµ½µÄ½á¹û¸³Öµ¸øhandlerMappings
+ * 2\. Èç¹ûδ»ñµÃ£¬Ôò»ñȡĬÈ쵀 HandlerMapping bean
+ */
+private void initHandlerMappings(ApplicationContext context) {
+ this.handlerMappings = null;
+ if (this.detectAllHandlerMappings) {
+ // ¼ÓÔØËùÓÐʵÏÖHandlerMapping½Ó¿ÚµÄbean
+ Map matchingBeans = BeanFactoryUtils
+ .beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
+ // ÕâÀﲻΪ¿Õ£¬»áÔËÐÐ
+ if (!matchingBeans.isEmpty()) {
+ this.handlerMappings = new ArrayList<>(matchingBeans.values());
+ // ÅÅÐò£¬Spring´¦ÀíÇëÇó¾ÍÊǸù¾ÝÕâ¸öÅÅÐòµÄ½á¹û½øÐд¦Àí£¬
+ // Èç¹ûµ±Ç°handlerMapping²»¿ÉÒÔ´¦ÀíÔòÅ׸øÏÂÒ»¸ö
+ AnnotationAwareOrderComparator.sort(this.handlerMappings);
+ }
+ }
+ else {
+ try {
+ HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
+ this.handlerMappings = Collections.singletonList(hm);
+ }
+ catch (NoSuchBeanDefinitionException ex) {
+ // Ignore, we'll add a default HandlerMapping later.
+ }
+ }
+ if (this.handlerMappings == null) {
+ // Èç¹ûδÌí¼ÓhandlerMappings£¬Ôò»ñȡĬÈ쵀 handlerMappings
+ this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
+ }
+}
+
+/**
+ * »ñȡĬÈϵIJßÂÔ
+ */
+protected List getDefaultStrategies(ApplicationContext context, Class strategyInterface) {
+ String key = strategyInterface.getName();
+ // »ñÈ¡ÅäÖÃÎļþDispatcherServlet.propertiesÖÐĬÈ쵀 class ÅäÖÃ
+ String value = defaultStrategies.getProperty(key);
+ if (value != null) {
+ String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
+ List strategies = new ArrayList<>(classNames.length);
+ for (String className : classNames) {
+ try {
+ // ʹÓ÷´Éä´´½¨bean
+ Class> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
+ Object strategy = createDefaultStrategy(context, clazz);
+ strategies.add((T) strategy);
+ }
+ catch (ClassNotFoundException ex) {
+ throw new BeanInitializationException(...);
+ }
+ catch (LinkageError err) {
+ throw new BeanInitializationException(...);
+ }
+ }
+ return strategies;
+ }
+ else {
+ return new LinkedList<>();
+ }
+}
+
+```
+
+³õʼ»¯ `HandlerMappings` ʱ£¬
+
+1. ÏÈ´Ó spring ÈÝÆ÷ÖлñÈ¡ `HandlerMapping` bean£¬Èç¹û»ñÈ¡³É¹¦£¨Êµ¼ÊÉÏÕâÀïÒ²ÄÜ»ñµÃ£©£¬Ôò°ÑµÃµ½µÄ½á¹û¸³Öµ¸ø `DispatcherServlet` µÄ `handlerMappings` ÊôÐÔ£»
+2. Èç¹ûδʧ°Ü£¬±íÃ÷ spring ÈÝÆ÷ÖÐδ´æÔÚ `HandlerMapping` £¬Ôò»ñȡĬÈ쵀 `HandlerMapping` bean.
+3. »ñȡĬÈ쵀 `HandlerMapping` bean ʱ£¬¶ÁÈ¡ `DispatcherServlet.properties` ÅäÖã¬È»ºóʹÓ÷´ÉäʵÀý»¯¡£
+
+ÎÒÃÇÀ´¿´¿´ `DispatcherServlet.properties` Îļþ£¬¸ÃÎļþλÓÚ` spring-webmvc/src/main/resources/org/springframework/web/servlet/DispatcherServlet.properties`£¬²¿·ÖÄÚÈÝÈçÏ£º
+
+```
+org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
+
+org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
+
+org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
+ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
+ org.springframework.web.servlet.function.support.RouterFunctionMapping
+...
+
+```
+
+`DispatcherServlet#initStrategies` ÖÐÆäËû `initXxx()` ÄÚÈÝÀàËÆ£¬ÕâÀï¾Í²»Ò»Ò»·ÖÎöÁË¡£
+
+### 4\. ×ܽá
+
+±¾ÎÄÖ÷Òª·ÖÎöÁË springmvc µÄÆô¶¯¹ý³Ì£¬×ܽáÈçÏ£º
+
+
+
+1. servlet ÈÝÆ÷£¨ÕâÀïÊÇ tomcat£©Æô¶¯Ê±£¬Í¨¹ý spi »úÖÆÖ´ÐÐ `ServletContainerInitializer#onStartup` ·½·¨£¬¶ø springmvc ¶ÔÌṩµÄ `SpringServletContainerInitializer` ¶ÔÆä½øÐÐÁËʵÏÖ£¬ÓÚÊÇ `SpringServletContainerInitializer#onStartup` ·½·¨»á±»µ÷Óã»
+2. `SpringServletContainerInitializer#onStartup` ·½·¨ÖУ¬spring »áµ÷Óà `WebApplicationInitializer#onStartup` ·½·¨£¬¶ø `MyWebApplicationInitializer` ¶ÔÆä½øÐÐÁËʵÏÖ£¬ÓÚÊÇ `MyWebApplicationInitializer#onStartup` »á±»µ÷Óã»
+3. ÔÚ `MyWebApplicationInitializer#onStartup` ·½·¨ÖÐ £¬ÎÒÃÇ´´½¨ÁËÒ»¸ö `applicationContext` ¶ÔÏ󣬽«ÆäÓë `DispatcherServlet` °ó¶¨£¬È»ºó½« `DispatcherServlet` ×¢²áµ½ servlet ÈÝÆ÷ÖУ¨ÕâÀïÊÇ tomcat£©£»
+4. `DispatcherServlet` ×¢²áµ½ servlet ÈÝÆ÷ÖУ¨ÕâÀïÊÇ tomcat£©ºó£¬¸ù¾Ý servlet ÉúÃüÖÜÆÚ£¬`DispatcherServlet#init` ½«»á±»µ÷Óã»
+5. `DispatcherServlet#init` ÖлáÖ´ÐÐ spring ÈÝÆ÷µÄÆô¶¯¹ý³Ì£¬spring ÈÝÆ÷Æô¶¯ºó£¬»á·¢²¼Æô¶¯Íê³Éʼþ£»
+6. spring Æô¶¯Íê³Éºó£¬`ContextRefreshListener` ½«»á¼àÌý spring Æô¶¯Íê³Éʼþ£¬`FrameworkServlet.ContextRefreshListener#onApplicationEvent` ·½·¨»á±»µ÷Ó㬵÷Óõ÷Óõ½ `DispatcherServlet#initStrategies`£»
+7. spring ×îÖÕÔÚ `DispatcherServlet#initStrategies` Öгõʼ»¯ `MultipartResolver`¡¢`LocaleResolver` µÈ×é¼þ£¬ËùνµÄ³õʼ»¯£¬ÆäʵÊÇ»ñÈ¡»ò´´½¨¶ÔÓ¦µÄ bean£¬È»ºó¸³Öµ¸ø `DispatcherServlet` µÄÊôÐÔ¡£
+
+µ½´Ë£¬springmvc Õû¸öÆô¶¯Á÷³Ì¾ÍÍê³ÉÁË¡£²»¹ýµ½´ËÎÒÃǶ¼Ã»Óп´µ½ **spring ´¦Àí `@RequestMapping` µÄÏà¹ØÁ÷³Ì**£¬ÄÇô spring ÊÇÈçºÎ´¦ÀíÕâ¸öÁ÷³ÌÄØ £¬ÏÂһƪÎÄÕ½«½ÒÏþ¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4710330](https://my.oschina.net/funcy/blog/4710330) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/RequestMapping \345\210\235\345\247\213\345\214\226\346\265\201\347\250\213.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/RequestMapping \345\210\235\345\247\213\345\214\226\346\265\201\347\250\213.md"
new file mode 100644
index 0000000..777a297
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/RequestMapping \345\210\235\345\247\213\345\214\226\346\265\201\347\250\213.md"
@@ -0,0 +1,762 @@
+Ç°ÃæµÄÎÄÕÂÖУ¬ÎÒÃÇ·ÖÎöÁË `DispatcherServlet` ³õʼ»¯Á÷³Ì£¬±¾ÎĽ«À´·ÖÎö `RequestMapping` ³õʼ»¯Á÷³Ì¡£ÕâÀïËù˵µÄ `RequestMapping` ³õʼ»¯Á÷³Ì£¬Ö±¹ÛÀ´Ëµ£¬¾ÍÊÇ spring ´¦Àí `@RequestMaping` ×¢½âµÄ¹ý³Ì¡£
+
+### 1\. ÔÙ̸ `@EnableWebMvc`
+
+ÔÚ [spring mvc Ö® springmvc demo Óë @EnableWebMvc ×¢½â ](https://my.oschina.net/funcy/blog/4696657)Ò»ÎÄÖÐÌáµ½£¬spring ͨ¹ý `@EnableWebMvc` ×¢½âÀ´ÆôÓà mvc ¹¦ÄÜ£¬×îÖÕͨ¹ý `@Import` ×¢½âΪÏîÄ¿ÒýÈëÁË `DelegatingWebMvcConfiguration.class`£¬¸ÃÀàͨ¹ý `@Bean` ×¢½âµÄ·½·¨Ïò spring ÖÐÒýÈë´óÁ¿µÄ mvc ×é¼þ£º
+
+* `public RequestMappingHandlerMapping requestMappingHandlerMapping(...)`
+* `public PathMatcher mvcPathMatcher()`
+* `public UrlPathHelper mvcUrlPathHelper()`
+* ...
+
+Õâô×é¼þÖУ¬Óë `@RequestMaping` ×¢½âÏà¹ØµÄÀà¾ÍÊÇ `RequestMappingHandlerMapping`.
+
+### 2. `RequestMappingHandlerMapping#afterPropertiesSet` ·½·¨
+
+`RequestMappingHandlerMapping` ÊÇ´´½¨ÊÇÔÚ `WebMvcConfigurationSupport` ÖУº
+
+```
+@Bean
+public RequestMappingHandlerMapping requestMappingHandlerMapping(
+ @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
+ @Qualifier("mvcConversionService") FormattingConversionService conversionService,
+ @Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
+
+ // ´´½¨bean
+ RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
+ mapping.setOrder(0);
+ mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
+ mapping.setContentNegotiationManager(contentNegotiationManager);
+ mapping.setCorsConfigurations(getCorsConfigurations());
+
+ // ´¦Àí¸÷ÖÖÅäÖã¬ÕâÀï¾ÍÊÇÉÏһƪÎÄÕÂÖÐÌáµ½µÄgetXxx()·½·¨»ñÈ¡ÅäÖÃ
+ PathMatchConfigurer configurer = getPathMatchConfigurer();
+ Boolean useSuffixPatternMatch = configurer.isUseSuffixPatternMatch();
+ if (useSuffixPatternMatch != null) {
+ mapping.setUseSuffixPatternMatch(useSuffixPatternMatch);
+ }
+ Boolean useRegisteredSuffixPatternMatch = configurer.isUseRegisteredSuffixPatternMatch();
+ if (useRegisteredSuffixPatternMatch != null) {
+ mapping.setUseRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch);
+ }
+ Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
+ if (useTrailingSlashMatch != null) {
+ mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
+ }
+ UrlPathHelper pathHelper = configurer.getUrlPathHelper();
+ if (pathHelper != null) {
+ mapping.setUrlPathHelper(pathHelper);
+ }
+ PathMatcher pathMatcher = configurer.getPathMatcher();
+ if (pathMatcher != null) {
+ mapping.setPathMatcher(pathMatcher);
+ }
+ Map>> pathPrefixes = configurer.getPathPrefixes();
+ if (pathPrefixes != null) {
+ mapping.setPathPrefixes(pathPrefixes);
+ }
+
+ return mapping;
+}
+
+// ´´½¨¶ÔÏó
+protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
+ return new RequestMappingHandlerMapping();
+}
+
+```
+
+Õâ¸ö·½·¨¾ÍÊÇÓÃÀ´´´½¨¶ÔÏó `RequestMappingHandlerMapping` ¶ÔÏóµÄ£¬ÏÈÊÇ´´½¨ÁËÒ»¸ö¶ÔÏó£¬È»ºóÉèÖÃÁ˸÷ÖÖÊôÐÔ¡£¶ÔÏó´´½¨ºó£¬¼ÌÐø½øÐÐ spring bean µÄÉúÃüÖÜÆÚ£¬¼Ì¶øµ÷Óà `RequestMappingHandlerMapping#afterPropertiesSet` ·½·¨£º
+
+```
+@Override
+public void afterPropertiesSet() {
+ // ÅäÖÃÁËһЩÊôÐÔ
+ this.config = new RequestMappingInfo.BuilderConfiguration();
+ this.config.setUrlPathHelper(getUrlPathHelper());
+ this.config.setPathMatcher(getPathMatcher());
+ this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
+ this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
+ this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
+ this.config.setContentNegotiationManager(getContentNegotiationManager());
+ // µ÷Óø¸ÀàµÄ·½·¨
+ super.afterPropertiesSet();
+}
+
+```
+
+Õâ¸ö·½·¨ÏÈÊÇ ÅäÖÃÁËһЩÊôÐÔ£¬È»ºóÔÙµ÷Óø¸ÀàµÄ `afterPropertiesSet()`£¬¼ÌÐø×·ÏÂÈ¥£º
+
+> AbstractHandlerMethodMapping#afterPropertiesSet
+
+```
+@Override
+public void afterPropertiesSet() {
+ initHandlerMethods();
+}
+
+protected void initHandlerMethods() {
+ // µ÷ÓÃgetCandidateBeanNames()»ñÈ¡ÈÝÆ÷ÖÐËùÓÐbeanµÄbeanName£¬
+ // È»ºó°¤¸ö´¦ÀíÈÝÆ÷ÖÐËùÓÐ bean
+ for (String beanName : getCandidateBeanNames()) {
+ if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
+ // Öð¸ö bean ´¦Àí£¬¼ÌÐøÍùÏ¿´
+ processCandidateBean(beanName);
+ }
+ }
+ // Õâ¸ö·½·¨½ö´òÁËÒ»¸öÈÕÖ¾£¬Ã»Ê²Ã´¹¦ÄÜ
+ handlerMethodsInitialized(getHandlerMethods());
+}
+
+```
+
+spring ÔÚ´¦Àíʱ£¬»ñÈ¡ÁËÈÝÆ÷ÖÐËùÓÐ bean µÄ beanName£¬È»ºó¶Ô beanName ½øÐа¤¸ö´¦Àí£¬¼ÌÐø¿´ `AbstractHandlerMethodMapping#processCandidateBean`£º
+
+```
+// ´¦ÀíbeanµÄ¾ßÌåÂß¼
+protected void processCandidateBean(String beanName) {
+ // »ñÈ¡ beanName ¶ÔÓ¦µÄ beanType
+ // 1\. Èç¹ûÊÇcglib´úÀí£¬beanType Ϊ Xxx$$EnhancerBySpringCGLIB
+ // 2\. Èç¹ûÊÇjdk¶¯Ì¬´úÀí£¬beanType Ϊ com.sum.proxy.$Proxy
+ Class> beanType = null;
+ try {
+ beanType = obtainApplicationContext().getType(beanName);
+ }
+ catch (Throwable ex) {
+ ...
+ }
+ // isHandler: beanTypeÉÏÊÇ·ñÓÐ @Controller »ò @RequestMapping ×¢½â
+ if (beanType != null && isHandler(beanType)) {
+ // ´¦Àí handlerMethods
+ detectHandlerMethods(beanName);
+ }
+}
+
+```
+
+Õâ¸ö·½·¨»¹ÊDZȽϼòµ¥£¬Ö÷ÒªÊÇ»ñÈ¡ `beanName` ¶ÔÓ¦µÄ `beanType`£¬È»ºóÅжÏÊÇ·ñÓÐ `@Controller/@RequestMapping` ×¢½â£¬Ö®ºó¾Íµ÷Óà `AbstractHandlerMethodMapping#detectHandlerMethods` ½øÒ»²½´¦Àí¡£
+
+²»¹ý¶ÔÓÚ `isHandler(Class)` ÐèÒª×ÅÖØËµÃ÷Ï£º
+
+1. ÄÜʶ±ð `@Controller`£¬Í¬ÑùÄÜʶ±ð `@RestController`£¬ÉõÖÁÆäËû±ê×¢ `@Controller` µÄ×¢½â£¬¼´ÄÜʶ±ðÈçÏÂ×¢½â£º
+
+ ```
+ // ±ê¼ÇÁË @Controller
+ @Controller
+ // Ê¡ÂÔÆäËû×¢½â
+ public @interface XxxController {
+ ...
+ }
+
+ ```
+
+2. Èç¹û `beanName` ¶ÔÓ¦ bean ÊÇ cglib ´úÀí bean£¬beanType Ϊ `Xxx$$EnhancerBySpringCGLIB`£¬ÄÜʶ±ðÆä¸¸Àà (Ò²¾ÍÊÇÄ¿±êÀà) É쵀 `@Controller/@ReestMapping`;
+
+3. Èç¹û `beanName` ¶ÔÓ¦µÄ bean ÊÇ jdk ¶¯Ì¬´úÀí bean£¬beanType Ϊ `com.sum.proxy.$Proxy`£¬ÄÜʶ±ðÆä¸¸½Ó¿ÚÉ쵀 `@Controller/@RequestMapping`;
+
+4. Èç¹û beanType ÊÇ `com.sum.proxy.$Proxy`(jdk ¶¯Ì¬´úÀíÀà)£¬** ÎÞ·¨Ê¶±ðÆäÄ¿±êÀàÉ쵀 `@Controller/@RequestMapping` ** µÄ£»
+
+5. ±ê×¢ `@Controller/@RequestMapping` µÄÀàҪʵÏÖ jdk ¶¯Ì¬´úÀí£¬ÐèÒª½« `@Controller/@RequestMapping` ·ÅÔÚ½Ó¿Ú¼°½Ó¿ÚµÄ·½·¨ÉÏ¡£
+
+µ½ÁËÕâÀ´«Èë `AbstractHandlerMethodMapping#detectHandlerMethods` µÄ `beanType` ¶¼ÊDZê×¢ÁË `@Controller/@RequestMapping` µÄÀà»ò½Ó¿ÚÁË¡£
+
+### 3. `AbstractHandlerMethodMapping#detectHandlerMethods`
+
+¼ÌÐø¿´¿´ `AbstractHandlerMethodMapping#detectHandlerMethods` µÄÄÚÈÝ£º
+
+```
+// ¼ì²âhandler·½·¨
+protected void detectHandlerMethods(Object handler) {
+ Class> handlerType = (handler instanceof String ?
+ obtainApplicationContext().getType((String) handler) : handler.getClass());
+ if (handlerType != null) {
+ // 1\. Õë¶Ôcglib´úÀí¶ÔÏ󣬵õ½Æä¸¸À࣬Ҳ¾ÍÊÇÄ¿±ê¶ÔÏóµÄÀà
+ Class> userType = ClassUtils.getUserClass(handlerType);
+ // 2\. ÕâÀï»á´¦Àí userType¡¢userTypeµÄ²»°üÀ¨ObjectµÄËùÓи¸À༰ userType µÄËùÓнӿڵķ½·¨
+ Map methods = MethodIntrospector.selectMethods(userType,
+ // 3\. ¶Ôÿ¸ö·½·¨£¬Èç¹ûÓÐ @RequestMapping£¬Ôò´´½¨ RequestMappingInfo
+ // ½« @RequestMapping ÐÅÏ¢·â×°µ½¸Ã¶ÔÏóÖÐ
+ (MethodIntrospector.MetadataLookup) method -> {
+ try {
+ // ÔÚÕâÀï´¦Àí·½·¨É쵀 @RequestMapping ×¢½â
+ return getMappingForMethod(method, userType);
+ }
+ catch (Throwable ex) {
+ ...
+ }
+ });
+ methods.forEach((method, mapping) -> {
+ Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
+ // 4\. ÔÚÕâÀォhandler¡¢mappingÓëmethod±£´æÆðÀ´
+ registerHandlerMethod(handler, invocableMethod, mapping);
+ });
+ }
+}
+
+```
+
+Õâ¸ö·½·¨×öÁËÈçϼ¸¼þÊ£º
+
+1. Õë¶Ô cglib ´úÀí¶ÔÏ󣬵õ½Æä¸¸À࣬Ҳ¾ÍÊÇÄ¿±ê¶ÔÏóµÄÀࣨ**ÕâÀïΪºÎÖ»´¦Àí cglib ´úÀí¶ÔÏ󣬶ø²»´¦Àí jdk ¶¯Ì¬´úÀí¶ÔÏóÄØ£¿** ´ÓÉÏÃæ¶Ô `isHandler(Class)` µÄ˵Ã÷¿ÉÖª£¬spring ²¢²»ÄÜʶ±ð jdk ¶¯Ì¬´úÀí¶ÔÏó¶ÔÓ¦ÀàÉ쵀 `@Controller/@RequestMapping` ×¢½â£¬Òò´Ë²»»áÖ´Ðе½ÕâÀ£»
+2. ´¦Àí `userType`¡¢`userType` µÄ²»°üÀ¨ Object µÄËùÓи¸À༰ `userType` µÄËùÓнӿڵķ½·¨£»
+3. ¶Ôÿ¸ö·½·¨£¬Èç¹ûÓÐ `@RequestMapping`£¬Ôò´´½¨ `RequestMappingInfo`£¬½« `@RequestMapping` ÐÅÏ¢·â×°µ½¸Ã¶ÔÏóÖУ»
+4. ×¢²á£¬½« `handler`¡¢`mapping` Óë `method` ±£´æµ½ Map ÖС£
+
+#### 3.1 ²éÕÒ·½·¨
+
+ÔÚ `detectHandlerMethods` ·½·¨µÄ´¦Àí¹ý³ÌÖУ¬»á²éÕÒ `userType`¡¢`userType` µÄËùÓи¸Àࣨ²»°üÀ¨ Object£©¼° `userType` µÄËùÓнӿڵķ½·¨£¬¹ý³ÌÈçÏ£º
+
+> MethodIntrospector#selectMethods(Class, MethodIntrospector.MetadataLookup)
+
+```
+public static Map selectMethods(Class> targetType, final
+ MetadataLookup metadataLookup) {
+ final Map methodMap = new LinkedHashMap<>();
+ Set> handlerTypes = new LinkedHashSet<>();
+ Class> specificHandlerType = null;
+ // ·Çjdk¶¯Ì¬´úÀíÀà
+ if (!Proxy.isProxyClass(targetType)) {
+ // Èç¹ûÊÇcglib´úÀíÀ࣬»ñÈ¡Æä¾ßÌåµÄ¸¸Àà class
+ specificHandlerType = ClassUtils.getUserClass(targetType);
+ handlerTypes.add(specificHandlerType);
+ }
+ // »ñÈ¡ÀàµÄËùÓнӿڣ¬°üÀ¨½Ó¿ÚµÄ¸¸½Ó¿Ú.
+ handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
+ for (Class> currentHandlerType : handlerTypes) {
+ final Class> targetClass = (specificHandlerType != null
+ ? specificHandlerType : currentHandlerType);
+ // ´¦ÀícurrentHandlerType¡¢currentHandlerTypeµÄ²»°üÀ¨ObjectµÄËùÓи¸Àà¡¢
+ // currentHandlerTypeµÄËùÓнӿڵķ½·¨
+ // ´¦Àíaopʱ£¬µ÷ÓõÄÒ²ÊÇÕâ¸ö·½·¨
+ ReflectionUtils.doWithMethods(currentHandlerType, method -> {
+ Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
+ T result = metadataLookup.inspect(specificMethod);
+ if (result != null) {
+ Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
+ if (bridgedMethod == specificMethod ||
+ metadataLookup.inspect(bridgedMethod) == null) {
+ methodMap.put(specificMethod, result);
+ }
+ }
+ }, ReflectionUtils.USER_DECLARED_METHODS);
+ }
+ return methodMap;
+}
+
+```
+
+#### 3.2 ´´½¨ `RequestMappingInfo`
+
+¶Ôÿ¸ö·½·¨£¬Èç¹ûÓÐ `@RequestMapping`£¬Ôò´´½¨ `RequestMappingInfo`£¬½« `@RequestMapping` ÐÅÏ¢·â×°µ½¸Ã¶ÔÏóÖУº
+
+> RequestMappingHandlerMapping#getMappingForMethod
+
+```
+protected RequestMappingInfo getMappingForMethod(Method method, Class> handlerType) {
+ // ´¦Àí·½·¨É쵀 @RequestMapping
+ RequestMappingInfo info = createRequestMappingInfo(method);
+ if (info != null) {
+ // ´¦ÀíÀàÉ쵀 @RequestMapping
+ RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
+ if (typeInfo != null) {
+ // ºÏ²¢·½·¨ÓëÀàÉ쵀 @RequestMapping ½á¹û
+ // ÈçÀàµÄ @RequestMapping("/test")£¬·½·¨É쵀 @RequestMapping("/hello")
+ // ºÏ²¢ºóµÄ½á¹ûΪ /test/hello
+ info = typeInfo.combine(info);
+ }
+ String prefix = getPathPrefix(handlerType);
+ if (prefix != null) {
+ info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
+ }
+ }
+ return info;
+}
+
+@Nullable
+private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
+ // »ñÈ¡ @RequestMapping ×¢½â
+ RequestMapping requestMapping = AnnotatedElementUtils
+ .findMergedAnnotation(element, RequestMapping.class);
+ // ´¦ÀíÇëÇóÌõ¼þ£¬Êµ¼ÊÉÏÕâ¸ö·½·¨Îª¿Õ
+ RequestCondition> condition = (element instanceof Class ?
+ getCustomTypeCondition((Class>) element) : getCustomMethodCondition((Method) element));
+ return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
+}
+
+// ´´½¨ RequestMappingInfo£¬Õâ¸ö RequestMapping ¾ÍÊÇ @RequestMapping ×¢½â
+protected RequestMappingInfo createRequestMappingInfo(
+ RequestMapping requestMapping, @Nullable RequestCondition> customCondition) {
+ // Æäʵ¾ÍÊǽ« @RequestMapping ×¢½â·âװΪRequestMappingInfo¶ÔÏó
+ RequestMappingInfo.Builder builder = RequestMappingInfo
+ .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
+ // ÏÂÃæµÄÊôÐÔ½ÔÀ´×Ô @RequestMapping ×¢½â
+ .methods(requestMapping.method())
+ .params(requestMapping.params())
+ .headers(requestMapping.headers())
+ .consumes(requestMapping.consumes())
+ .produces(requestMapping.produces())
+ .mappingName(requestMapping.name());
+ if (customCondition != null) {
+ builder.customCondition(customCondition);
+ }
+ return builder.options(this.config).build();
+}
+
+```
+
+µ½ÁËÕâÀÎÒÃǾÍÍê³ÉÁËÓÉ `@RequestMapping` µ½ `RequestMappingInfo¶ÔÏó`µÄת»¯¡£
+
+ÔÙÀ´¿´¿´ `RequestMappingInfo` ³¤Ê²Ã´Ñù£º
+
+```
+public final class RequestMappingInfo implements RequestCondition {
+ // ÌṩÁ˺ܶàÊôÐÔ£¬¶ÔÓ¦×Å @RequestMappingµÄÊôÐÔ
+ @Nullable
+ private final String name;
+ private final PatternsRequestCondition patternsCondition;
+ private final RequestMethodsRequestCondition methodsCondition;
+ private final ParamsRequestCondition paramsCondition;
+ private final HeadersRequestCondition headersCondition;
+ private final ConsumesRequestCondition consumesCondition;
+ private final ProducesRequestCondition producesCondition;
+ private final RequestConditionHolder customConditionHolder;
+
+ // ¹¹Ôì·½·¨£¬¾ÍÊÇÔÚ
+ public RequestMappingInfo(@Nullable String name, @Nullable PatternsRequestCondition patterns,
+ @Nullable RequestMethodsRequestCondition methods, @Nullable ParamsRequestCondition params,
+ @Nullable HeadersRequestCondition headers, @Nullable ConsumesRequestCondition consumes,
+ @Nullable ProducesRequestCondition produces, @Nullable RequestCondition> custom) {
+
+ this.name = (StringUtils.hasText(name) ? name : null);
+ this.patternsCondition = (patterns != null ? patterns : new PatternsRequestCondition());
+ this.methodsCondition = (methods != null ? methods : new RequestMethodsRequestCondition());
+ this.paramsCondition = (params != null ? params : new ParamsRequestCondition());
+ this.headersCondition = (headers != null ? headers : new HeadersRequestCondition());
+ this.consumesCondition = (consumes != null ? consumes : new ConsumesRequestCondition());
+ this.producesCondition = (produces != null ? produces : new ProducesRequestCondition());
+ this.customConditionHolder = new RequestConditionHolder(custom);
+ }
+
+ // builder ¹¹½¨Ä£Ê½£¬Ç°ÃæÕýÊÇʹÓÃbuilderÀ´´´½¨RequestMappingInfo¶ÔÏóµÄ
+ private static class DefaultBuilder implements Builder {
+ // Ê¡ÂÔÆäËû
+ ...
+
+ // ʹÓÃbuilder()·½·¨À´´´½¨¶ÔÏó
+ @Override
+ public RequestMappingInfo build() {
+ ContentNegotiationManager manager = this.options.getContentNegotiationManager();
+ PatternsRequestCondition patternsCondition = new PatternsRequestCondition(
+ this.paths, this.options.getUrlPathHelper(), this.options.getPathMatcher(),
+ this.options.useSuffixPatternMatch(), this.options.useTrailingSlashMatch(),
+ this.options.getFileExtensions());
+ // µ÷ÓÃ RequestMappingInfo ¹¹Ôì·½·¨
+ return new RequestMappingInfo(this.mappingName, patternsCondition,
+ new RequestMethodsRequestCondition(this.methods),
+ new ParamsRequestCondition(this.params),
+ new HeadersRequestCondition(this.headers),
+ new ConsumesRequestCondition(this.consumes, this.headers),
+ new ProducesRequestCondition(this.produces, this.headers, manager),
+ this.customCondition);
+ }
+ }
+ // Ê¡ÂÔÆäËû
+ ...
+}
+
+```
+
+#### 3.3 ×¢²á
+
+·â×°Íê `@RequestMapping` ÐÅÏ¢ºó£¬½ÓÏÂÀ´¾ÍÊǽ«½Ó¿ÚÐÅÏ¢×¢²áµ½ springmvc ÖÐÁË£º
+
+> RequestMappingHandlerMapping#registerHandlerMethod
+
+```
+@Override
+protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
+ // µ÷Óø¸ÀàµÄ·½·¨£¬×¢²áÏà¹ØÂß¼ÔÚÕâÀï
+ super.registerHandlerMethod(handler, method, mapping);
+ updateConsumesCondition(mapping, method);
+}
+// ´¦Àí·½·¨²ÎÊýµÄ @RequestBody ×¢½â
+private void updateConsumesCondition(RequestMappingInfo info, Method method) {
+ ConsumesRequestCondition condition = info.getConsumesCondition();
+ if (!condition.isEmpty()) {
+ for (Parameter parameter : method.getParameters()) {
+ // ´¦Àí ·½·¨²ÎÊýµÄ @RequestBody ×¢½â£¬ÉèÖà BodyRequired µÄÖµ
+ MergedAnnotation annot = MergedAnnotations.from(parameter)
+ .get(RequestBody.class);
+ if (annot.isPresent()) {
+ condition.setBodyRequired(annot.getBoolean("required"));
+ break;
+ }
+ }
+ }
+}
+
+```
+
+×îÖÕ£¬·¢ÏÖ¾ßÌåµÄ×¢²áÂß¼ÊÇÔÚ `AbstractHandlerMethodMapping#registerHandlerMethod` ÖÐÍê³ÉµÄ£¬¿´À´Õâ¸ö¾ÍÊÇ×îÖÕ·½·¨ÁË¡£ÔÚ·ÖÎöÕâ¸ö·½·¨Ç°£¬ÎÒÃÇÏÈÀ´¿´¿´ÕâÒ»²½µÃµ½µÄ `Map methods`:
+
+
+
+¿ÉÒÔ¿´µ½£¬¶ÔÓ¦µÄ `T` ¾ÍÊÇ `RequestMappingInfo` ÁË¡£
+
+### 3. `AbstractHandlerMethodMapping#registerHandlerMethod` ·½·¨
+
+½ÓÏÂÀ´ÎÒÃÇÀ´¿´¿´ `AbstractHandlerMethodMapping#registerHandlerMethod` ´úÂ룺
+
+```
+public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMapping
+ implements InitializingBean {
+
+ protected void registerHandlerMethod(Object handler, Method method, T mapping) {
+ this.mappingRegistry.register(mapping, handler, method);
+ }
+
+ // Ê¡ÂÔÁ˺öà´úÂë
+ ...
+
+ class MappingRegistry {
+ // ÐÅÏ¢×îÈ«µÄmap£¬°üº¬mapping, handlerMethod, directUrls, nameµÈÐÅÏ¢
+ private final Map> registry = new HashMap<>();
+ // ËùÓÐµÄ mapping map£¬/test/hello¡¢/test/{name}
+ private final Map mappingLookup = new LinkedHashMap<>();
+ // Ã÷È·µÄurl map£¬Èç /test/hello
+ private final MultiValueMap urlLookup = new LinkedMultiValueMap<>();
+
+ // Ê¡ÂÔÁ˺öà´úÂë
+ ...
+
+ public void register(T mapping, Object handler, Method method) {
+ ...
+ // »ñÈ¡¶ÁÐ´ËøµÄÐ´Ëø
+ this.readWriteLock.writeLock().lock();
+ try {
+ // 1\. »ñÈ¡ÁË handlerMethod£¬Æäʵ¾ÍÊǽ«handler Óë method °ü×°ÁËÒ»²ã
+ HandlerMethod handlerMethod = createHandlerMethod(handler, method);
+ validateMethodMapping(handlerMethod, mapping);
+ // 2\. ·ÅÈë mappingLookup ÖУ¬ÀàÐÍΪ LinkedHashMap
+ // ÕâÊÇspringmvcÖÐÒ»¸öÖØÒªµÄmap
+ this.mappingLookup.put(mapping, handlerMethod);
+
+ // 3\. »ñÈ¡url£¬·ÅÈëurlLookup£¬ÀàÐÍΪMultiValueMap£¬Õâ¸ömap ͬһkey¿ÉÒÔÓжà¸övalue
+ // ÕâÊÇspringmvcÖÐÁíÒ»¸öÖØÒªµÄmap
+ List directUrls = getDirectUrls(mapping);
+ for (String url : directUrls) {
+ this.urlLookup.add(url, mapping);
+ }
+ String name = null;
+ if (getNamingStrategy() != null) {
+ name = getNamingStrategy().getName(handlerMethod, mapping);
+ addMappingName(name, handlerMethod);
+ }
+ CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
+ if (corsConfig != null) {
+ this.corsLookup.put(handlerMethod, corsConfig);
+ }
+
+ // 4\. ½«mapping, handlerMethod, directUrls, nameµÈ·â×°·ÅÈëregistry£¬
+ // registry ÀàÐÍΪHashMap£¬ÕâÊÇspringmvc ÖнӿÚÐÅÏ¢×îÈ«µÄÒ»¸ömap
+ this.registry.put(mapping, new MappingRegistration<>(mapping,
+ handlerMethod, directUrls, name));
+ }
+ finally {
+ this.readWriteLock.writeLock().unlock();
+ }
+ }
+ }
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬×¢²áµÄÂß¼×îÖÕÊÇÔÚ `AbstractHandlerMethodMapping.MappingRegistry#register` ÖÐÍê³ÉµÄ¡£½ÓÏÂÀ´ÎÒÃǾÍÒ»²½²½·ÖÎö×¢²áÂß¼¡£
+
+#### 3.1 »ñÈ¡ `HandlerMethod`
+
+Ïà¹Ø´úÂëÈçÏ£º
+
+```
+protected HandlerMethod createHandlerMethod(Object handler, Method method) {
+ if (handler instanceof String) {
+ return new HandlerMethod((String) handler,
+ obtainApplicationContext().getAutowireCapableBeanFactory(), method);
+ }
+ return new HandlerMethod(handler, method);
+}
+
+```
+
+Õâ¶Î·½·¨¾ÍÊǼòµ¥µØµ÷ÓÃÁË `HandlerMethod` µÄ¹¹Ôì·½·¨£¬¼ÌÐø£º
+
+```
+public class HandlerMethod {
+
+ // ÌṩÁ˷dz£¶àµÄÊôÐÔ
+ protected final Log logger = LogFactory.getLog(getClass());
+ private final Object bean;
+ @Nullable
+ private final BeanFactory beanFactory;
+ private final Class> beanType;
+ private final Method method;
+ private final Method bridgedMethod;
+ private final MethodParameter[] parameters;
+ @Nullable
+ private HttpStatus responseStatus;
+ @Nullable
+ private String responseStatusReason;
+ @Nullable
+ private HandlerMethod resolvedFromHandlerMethod;
+ @Nullable
+ private volatile List interfaceParameterAnnotations;
+ private final String description;
+
+ // ¹¹Ôì·½·¨
+ public HandlerMethod(Object bean, Method method) {
+ Assert.notNull(bean, "Bean is required");
+ Assert.notNull(method, "Method is required");
+ this.bean = bean;
+ this.beanFactory = null;
+ this.beanType = ClassUtils.getUserClass(bean);
+ this.method = method;
+ this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
+ this.parameters = initMethodParameters();
+ evaluateResponseStatus();
+ this.description = initDescription(this.beanType, this.method);
+ }
+
+ // Ê¡ÂÔÆäËû
+ ...
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`HandlerMethod` ÖÐÓзdz£¶àµÄÊôÐÔ£¬¹¹Ôì·½·¨Ëù×öµÄÊÂÒ²½ö½öÊǸ³Öµ¶øÒÑ¡£Óɴ˿ɿ´³ö£¬`HandlerMethod` ¾ÍÊÇ¶Ô `handler` Óë `method` µÄÒ»¸ö°ü×°¡£
+
+#### 3.2 ÑéÖ¤ mapping ÊÇ·ñÖØ¸´
+
+ÔÚ springmvc ʹÓÃÖУ¬Èç¹û²»Ð¡Ð͍ÒåÁËÁ½¸öÏàͬµÄ `requestMapping`£¬»á³öÏÖÈçÏÂÒì³££º
+
+```
+Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map
+'xxxController' method xxxMethod to /xxx/xxx: There is already 'xxxControllter'
+bean method xxxMethod mapped.
+
+```
+
+Õâ¸öÒì³£¾ÍÊÇÔÚÑéÖ¤ mapping ʱ£¬·¢ÏÖÁËÖØ¸´ÁË mapping ¶ø´¥·¢µÄ£¬´úÂëÈçÏ£º
+
+```
+// ËùÓÐµÄ mapping map£¬/test/hello¡¢/test/{name}
+private final Map mappingLookup = new LinkedHashMap<>();
+
+private void validateMethodMapping(HandlerMethod handlerMethod, T mapping) {
+ // ÕÒµ½ÒÑ´æÔÚµÄ method
+ HandlerMethod existingHandlerMethod = this.mappingLookup.get(mapping);
+ // ÒÑ´æÔÚµÄhandlerMethod²»Îª¿Õ£¬ÇÒ²»µÈÓÚµ±Ç° handlerMethod
+ if (existingHandlerMethod != null && !existingHandlerMethod.equals(handlerMethod)) {
+ throw new IllegalStateException(
+ "Ambiguous mapping. Cannot map '" + handlerMethod.getBean() + "' method \n" +
+ handlerMethod + "\nto " + mapping + ": There is already '" +
+ existingHandlerMethod.getBean() + "' bean method\n" +
+ existingHandlerMethod + " mapped.");
+ }
+}
+
+```
+
+Ê×ÏÈÊǸù¾Ý `mapping` ´Ó `mappingLookup` ÖвéÕÒ `HandlerMethod`£¬Èç¹ûÕÒµ½ÁËÇÒÕÒµ½µÄ `handlerMethod` ²»Êǵ±Ç° `handlerMethod`£¬Ôò±íÊ¾ÖØ¸´£¬¾Í±¨Òì³£ÁË¡£
+
+×îºó·Ö±ðÀ´¿´¿´ÅÐ¶Ï `HandlerMethod` Óë `RequestMappingInfo` ÊÇÈçºÎÅжÏÏàµÈµÄ£º
+
+> HandlerMethod#equals
+
+```
+@Override
+public boolean equals(@Nullable Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof HandlerMethod)) {
+ return false;
+ }
+ HandlerMethod otherMethod = (HandlerMethod) other;
+ return (this.bean.equals(otherMethod.bean) && this.method.equals(otherMethod.method));
+}
+
+```
+
+> RequestMappingInfo#equals
+
+```
+@Override
+public boolean equals(@Nullable Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof RequestMappingInfo)) {
+ return false;
+ }
+ RequestMappingInfo otherInfo = (RequestMappingInfo) other;
+ return (this.patternsCondition.equals(otherInfo.patternsCondition) &&
+ this.methodsCondition.equals(otherInfo.methodsCondition) &&
+ this.paramsCondition.equals(otherInfo.paramsCondition) &&
+ this.headersCondition.equals(otherInfo.headersCondition) &&
+ this.consumesCondition.equals(otherInfo.consumesCondition) &&
+ this.producesCondition.equals(otherInfo.producesCondition) &&
+ this.customConditionHolder.equals(otherInfo.customConditionHolder));
+}
+
+```
+
+`RequestMappingInfo` ÐèÒª¸÷ÊôÐÔÏàͬ²ÅÅжÏÏàµÈ£¬Òò´ËÏñÏÂÃæÕâÑùµÄ `@RequestMapping`£¬µÃµ½µÄ `RequestMappingInfo` ²¢²»ÏàµÈ£º
+
+```
+// ÒÔÏÂÈý¸ö @RequestMapping£¬ËäÈ»ÇëÇó·¾¶¶¼ÊÇ¡°/hello¡±£¬µ«Ö§³ÖµÄÇëÇó·½·¨¸÷²»Ïàͬ
+// Òò´ËµÃµ½µÄ RequestMappingInfo ²¢²»ÏàµÈ
+
+@RequestMapping(path = "/hello")
+public String hello1() {
+ ...
+}
+
+@RequestMapping(path = "/hello", method = RequestMethod.GET)
+public String hello2() {
+ ...
+}
+
+@RequestMapping(path = "/hello", method = RequestMethod.POST)
+public String hello3() {
+ ...
+}
+
+```
+
+#### 3.3 »ñÈ¡ `directUrls`
+
+springmvc ÖУ¬ÓÐÁ½ÖÖ url ÀàÐÍ:
+
+1. Ã÷È·µÄ url£¬Èç
+
+ ```
+ @RequestMapping("/hello")
+ public String hello() {
+ ...
+ }
+
+ ```
+
+2. ²»Ã÷È·µÄ url£¬Èç
+
+ ```
+ @RequestMapping("/{name}")
+ public String hello(@PathVariable("name") String name) {
+ ...
+ }
+
+ ```
+
+springmvc ÌṩÁËרÃÅµÄ `urlLookup` À´±£´æÃ÷È·µÄ url£¬½á¹¹ÈçÏ£º
+
+```
+MultiValueMap>
+
+```
+
+ÔÙÀ´¿´¿´ springmvc ÊÇÈçºÎ»ñÈ¡Ã÷È·µÄ url µÄ:
+
+```
+List directUrls = getDirectUrls(mapping);
+
+/**
+ * AbstractHandlerMethodMapping.MappingRegistry#getDirectUrls
+ * »ñÈ¡Ã÷È·µÄurl
+ */
+private List getDirectUrls(T mapping) {
+ List urls = new ArrayList<>(1);
+ // ´ÓRequestMappingInfo»ñÈ¡ËùÓÐµÄ MappingPathPattern
+ for (String path : getMappingPathPatterns(mapping)) {
+ // Åжϵõ½µÄ MappingPathPattern ÊÇ·ñΪÃ÷È·µÄurl
+ if (!getPathMatcher().isPattern(path)) {
+ urls.add(path);
+ }
+ }
+ return urls;
+}
+
+/**
+ * RequestMappingInfoHandlerMapping#getMappingPathPatterns
+ * »ñÈ¡ patterns, ´Ó RequestMappingInfo »ñÈ¡
+ * ʵ¼ÊÉϾÍÊÇ @RequestMapping ÖÐµÄ path() Öµ
+ */
+@Override
+protected Set getMappingPathPatterns(RequestMappingInfo info) {
+ return info.getPatternsCondition().getPatterns();
+}
+
+/**
+ * AntPathMatcher#isPattern
+ * ÅжÏÊÇ·ñΪÃ÷È·µÄ url
+ * Ö»Òª°üº¬ÁË *¡¢£¿Ö®Ò»£¬»òͬʱ°üº¬{¡¢}£¬¾Í²»ÊÇÃ÷È·µÄurl
+ */
+@Override
+public boolean isPattern(@Nullable String path) {
+ if (path == null) {
+ return false;
+ }
+ boolean uriVar = false;
+ for (int i = 0; i < path.length(); i++) {
+ char c = path.charAt(i);
+ if (c == '*' || c == '?') {
+ return true;
+ }
+ if (c == '{') {
+ uriVar = true;
+ continue;
+ }
+ if (c == '}' && uriVar) {
+ return true;
+ }
+ }
+ return false;
+}
+
+```
+
+Á÷³ÌÈçÏ£º
+
+1. »ñÈ¡µ±Ç° `mapping` µÄËùÓÐ `path`£¬Ò²¾ÍÊÇ `@RequestMapping` µÄ `path()` Öµ£»
+2. ±éÀúµÃµ½µÄ `path`£¬ÖðÒ»ÅжÏÊÇ·ñΪÃ÷È·µÄ url (Ö»Òª°üº¬ÁË `*`¡¢`?` Ö®Ò»£¬»òͬʱ°üº¬ `{`¡¢`}`£¬¾Í²»ÊÇÃ÷È·µÄ url).
+
+#### 3.4 ×¢²á½Ó¿ÚÐÅÏ¢
+
+×¢²á½Ó¿ÚÐÅÏ¢¾Í±È½Ï¼òµ¥ÁË£¬Æäʵ¾ÍÊÇÍù map ÖÐÌí¼ÓÊý¾Ý£¬ÕâÀï½éÉÜÈý¸ö map£º
+
+* `urlLookup`£ºÃ÷È·µÄ `url map`£¬ÀàÐÍΪ `MultiValueMap>`£¬`key` ΪÃ÷È·µÄ url£¬Èç `/test/hello`£¬`value` Ϊ `LinkedList`£»
+
+* `mappingLookup`£ºËùÓÐµÄ `mapping map`£¬ËùÓÐµÄ `@RequestMapping` ¶ÔÓ¦µÄ `RequestMappingInfo` ¶¼ÄÜÔÚÕâÀïÕÒµ½£¬°üÀ¨ `/test/hello`¡¢`/test/{name}` ¶ÔÓ¦µÄ `RequestMappingInfo`£¬ÀàÐÍΪ `Map`£»
+
+* `registry`£ºÐÅÏ¢×îÈ«µÄ map£¬ÀàÐÍΪ `Map>`£¬°üº¬ËùÓÐµÄ `RequestMappingInfo`£¬key Ϊ `RequestMappingInfo`£¬value Ϊ `MappingRegistration`£¬¶ø `MappingRegistration` Ϊ `mapping`, `handlerMethod`, `directUrls`, `name` µÄ°ü×°À࣬Ҳ¾ÍÊÇ˵ `MappingRegistration` °üº¬ÁË `mapping`, `handlerMethod`, `directUrls`, `name` µÈÐÅÏ¢¡£
+
+Àí½âÕâЩ map ºó£¬×¢²á¾ÍÏ൱¼òµ¥ÁË£¬¾ÍÊǼòµ¥µØµ÷ÓÃÏ `Map#put` ·½·¨£¬¾Í²»¶à˵ÁË¡£
+
+### 4\. ×ܽá
+
+±¾ÎÄ·ÖÎöÁË spring ´¦Àí´¦Àí `@RequestMapping` ×¢½âµÄÁ÷³Ì£¬Õⲿ·ÖÁ÷³ÌÔÚ `RequestMappingHandlerMapping#afterPropertiesSet` ·½·¨ÖУ¬Á÷³ÌÈçÏ£º
+
+1. »ñÈ¡ÈÝÆ÷ÖÐËùÓÐ bean µÄ `beanName`£¬Öð¸ö´¦Àí£¬´¦Àí·½·¨¼ûµÚ 2 ²½£»
+2. ÕÒµ½Óë `beanName` ¶ÔÓ¦µÄ `beanType`£¬ÅÐ¶ÏÆäÉÏÊÇ·ñÓÐ `@Controller/@RequestMapping` ×¢½â£»
+3. ¶Ô°üº¬ `@Controller/@RequestMapping` µÄ `beanType`£¬ÕÒµ½ÓÐ `@RequestMapping` ×¢½âµÄ·½·¨£¬½«Æä `@RequestMapping` ×¢½â·âװΪ `RequestMappingInfo`£¬ÕâÒ»²½µÃµ½µÄ½á¹ûΪһ¸ö map£º`Map`£»
+4. ½« `beanName`¡¢`beanType` Óë `Map` ×¢²áµ½ springmvc ÖУ¬ÕâÀïÓÐÈý¸ö±È½ÏÖØÒªµÄ map£º
+ * `MultiValueMap>`¡¢
+ * `Map`(`HandlerMethod` Ϊ `Method` µÄ°ü×°Àà)
+ * `Map>`(`MappingRegistration` Ϊ `RequestMappingInfo`, `HandlerMethod`, `directUrls`, `beanName` µÄ°ü×°Àà)£»
+
+
+
+×ܵÄÀ´Ëµ£¬`RequestMapping` µÄ´¦ÀíÁ÷³ÌÒþ²Ø±È½ÏÉ±¾ÈËÒ²Êǵ÷ÊÔÁ˺öà´Î²ÅÕÒµ½¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4715079](https://my.oschina.net/funcy/blog/4715079) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/Spring \345\256\271\345\231\250\345\220\257\345\212\250 Tomcat.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/Spring \345\256\271\345\231\250\345\220\257\345\212\250 Tomcat.md"
new file mode 100644
index 0000000..4623d0f
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/Spring \345\256\271\345\231\250\345\220\257\345\212\250 Tomcat.md"
@@ -0,0 +1,299 @@
+''ÔÚ [spring mvc Ö® springmvc demo Óë @EnableWebMvc ×¢½â](https://my.oschina.net/funcy/blog/4696657)Ò»ÎÄÖУ¬ÎÒÃÇÌṩÁËÒ»¸öʾÀý demo£¬¸Ã demo »áÏÈÆô¶¯ servlet ÈÝÆ÷£¬È»ºóͨ¹ý `servlet3.0` ¹æ·¶½« `DispatcherServlet` ×¢²áµ½ `servlet` ÈÝÆ÷ÖУ¬È»ºóÔÚ `DispatcherServlet#init` ·½·¨ÖÐÆô¶¯ spring ÈÝÆ÷£¬Õû¸öÁ÷³Ì¾ÍÏñÕâÑù£º
+
+
+
+ÕâûʲôÎÊÌ⣬ÄÜÕý³£Æô¶¯Ò²ÔËÐÐÁ¼ºÃ£¬Ö»²»¹ýÎÒÃÇÔÚ spring ÈÝÆ÷ÖÐÎÞ·¨»ñÈ¡ `DispatcherServlet`£¬ÏñÕâÑù£º
+
+```
+@Component
+public class Test {
+ // ÔÚÇ°ÃæÌṩµÄʾÀý£¨tomcatÀïÆô¶¯springÈÝÆ÷£©ÊÇ×¢Èë²»Á˵Ä
+ @Autowired
+ public DispatcherServlet dispatcherServlet;
+
+ ...
+
+}
+
+```
+
+Æô¶¯Ê±£¬spring ¿Ï¶¨»á±¨´í£¬ÒòΪÕÒ²»µ½ `DispatcherServlet` ¶ÔÓ¦µÄ bean¡£
+
+×î½üÔÚ¿´ springboot Ô´Âëʱ£¬·¢ÏÖ spring ÈÝÆ÷²¢²»ÊÇÓÉ tomcat ÈÝÆ÷Æô¶¯µÄ£¬Ïà·´£¬springboot ÊÇÏÈÆô¶¯ spring ÈÝÆ÷£¬È»ºóÓÉ spring ÈÝÆ÷Æô¶¯ tomcat Æô¶¯£¬ÕâÊÇÈçºÎ×öµ½µÄÄØ£¿ÕâÀï±¾ÈËÌṩһ¸ö demo Ä£ÄâÏ¡£
+
+### 1\. ×¼±¸ `DispatcherServlet`
+
+```
+@Component
+@EnableWebMvc
+public class MvcConfig implements WebMvcConfigurer {
+
+ @Override
+ public void configureViewResolvers(ViewResolverRegistry registry) {
+ InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
+ viewResolver.setPrefix("/WEB-INF/views/");
+ viewResolver.setSuffix(".html");
+ registry.viewResolver(viewResolver);
+ }
+
+ /**
+ * dispatcherServlet
+ * @param webApplicationContext
+ * @return
+ */
+ @Bean
+ public DispatcherServlet dispatcherServlet(WebApplicationContext webApplicationContext) {
+ return new DispatcherServlet(webApplicationContext);
+ }
+
+}
+
+```
+
+¶Ô¸ÃÀà˵Ã÷ÈçÏ£º
+
+* `MvcConfig` Àà±» `@EnableWebMvc` ×¢½â±ê¼Ç£¬±íʾÐèÒªÆô¶¯Óà `web mvc` ¹¦ÄÜ
+* `MvcConfig` ʵÏÖÁË `WebMvcConfigurer`£¬¿ÉÒÔͨ¹ýÖØÐ´ `WebMvcConfigurer` µÄ·½·¨À´ÊµÏÖ×Ô¶¨Òå `web mvc` µÄÅäÖÃ
+* `MvcConfig` ÖлáÉú³É `DispatcherServlet` bean£¬¸Ã bean »á±£´æµ½ spring ÈÝÆ÷ÖÐ
+
+### 2\. ×¼±¸Ò»¸ö `WebApplicationInitializer` ʵÏÖÀà
+
+```
+@Component
+public class MyWebApplicationInitializer implements WebApplicationInitializer {
+
+ private static BeanFactory beanFactory;
+
+ private static AbstractRefreshableWebApplicationContext applicationContext;
+
+ @Override
+ public void onStartup(ServletContext servletContext) {
+ // ´Ó beanFactory ÖлñÈ¡ DispatcherServlet ²¢×¢²áµ½servletÈÝÆ÷
+ DispatcherServlet servlet = beanFactory.getBean(DispatcherServlet.class);
+ ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
+ // loadOnStartup ÉèÖÃ³É -1 ʱ£¬Ö»ÓÐÔÚµÚÒ»´ÎÇëÇóʱ£¬²Å»áµ÷Óà init ·½·¨
+ registration.setLoadOnStartup(-1);
+ registration.addMapping("/*");
+
+ // Ϊ applicationContext ÉèÖà servletContext
+ applicationContext.setServletContext(servletContext);
+ }
+
+ /**
+ * ÉèÖÃ beanFactory
+ * ΪʲôҪÉèÖà beanFactoryµÄÖµ£¿ÒòΪ DispatcherServlet Òª´Ó beanFactory ÖлñÈ¡
+ * @param beanFactory
+ * @throws BeansException
+ */
+ public static void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ MyWebApplicationInitializer.beanFactory = beanFactory;
+ }
+
+ /**
+ * ÉèÖÃ applicationContext
+ * ΪʲôҪÉèÖà applicationContext µÄÖµ£¿ÒòΪ servletContext ÒªÉèÖõ½ applicationContext
+ * @param applicationContext
+ */
+ public static void setApplicationContext(
+ AbstractRefreshableWebApplicationContext applicationContext) {
+ MyWebApplicationInitializer.applicationContext = applicationContext;
+ }
+}
+
+```
+
+`WebApplicationInitializer` ÊÇ spring ¶Ô servlet 3.0 ¹æ·¶µÄʵÏÖ£¬ÔÚ [spring mvc Ö® springmvc demo Óë @EnableWebMvc ×¢½â](https://my.oschina.net/funcy/blog/4696657)Ò»ÎÄÒ²Ïêϸ·ÖÎö¹ý£¬tomcat ÔÚÆô¶¯Ê±£¬»áÖ´ÐÐ `WebApplicationInitializer#onStartup` ·½·¨¡£
+
+¶Ô `MyWebApplicationInitializer` ˵Ã÷ÈçÏ£º
+
+* `MyWebApplicationInitializer` ÖÐÓÐÁ½¸ö¾²Ì¬³ÉÔ±±äÁ¿£º`beanFactory` Óë `applicationContext`£¬¶ÔÓ¦µØÌṩÁËÁ½¸ö¾²Ì¬ `set` ·½·¨£¬ÐèҪעÒâµÄÊÇ£¬ÕâÁ½¸ö¾²Ì¬ `set` ·½·¨ÒªÔÚ `onStartup()` ·½·¨Ç°µ÷Óã¬Ò²¾ÍÊÇ tomcat Æô¶¯Ç°µ÷Óõ÷Óã»
+* ÔÚ `MyWebApplicationInitializer#onStartup` ·½·¨ÖУ¬ÎÒÃÇÏÈÊÇ´Ó `beanFactory` ÖлñÈ¡ÁË `DispatcherServlet`£¬È»ºó½«Æä×¢²áµ½ `servlet` ÈÝÆ÷ÖУ¬È»ºó½« `onStartup(...)` ·½·¨µÄ²ÎÊý `servletContext` ÉèÖõ½ `applicationContext` ÖÐ
+
+### 3\. ×¼±¸Ò»¸ö `ServletContextAwareProcessor` µÄ×ÓÀà
+
+```
+public class MyServletContextAwareProcessor extends ServletContextAwareProcessor {
+
+ AbstractRefreshableWebApplicationContext webApplicationContext;
+
+ /**
+ * ´«Èë webApplicationContext
+ * @param webApplicationContext
+ */
+ public MyServletContextAwareProcessor(
+ AbstractRefreshableWebApplicationContext webApplicationContext) {
+ this.webApplicationContext = webApplicationContext;
+ }
+
+ /**
+ * ·µ»Ø ServletContext
+ * ÏÈ´Ó webApplicationContext ÖлñÈ¡£¬Èç¹û»ñÈ¡²»µ½£¬ÔÙ´Ó¸¸Àà·½·¨ÖлñÈ¡
+ * @return
+ */
+ @Override
+ protected ServletContext getServletContext() {
+ ServletContext servletContext = this.webApplicationContext.getServletContext();
+ return (servletContext != null) ? servletContext : super.getServletContext();
+ }
+
+ @Override
+ protected ServletConfig getServletConfig() {
+ ServletConfig servletConfig = this.webApplicationContext.getServletConfig();
+ return (servletConfig != null) ? servletConfig : super.getServletConfig();
+ }
+}
+
+```
+
+ÔÚ `MyWebApplicationInitializer#onStartup` ·½·¨ÖÐ¶Ô `applicationContext` ÉèÖÃµÄ `servletContext` ¾ÍÊÇÔÚÕâÀïʹÓõģ¬`MyServletContextAwareProcessor` µÄ¹¹Ôì·½·¨´«ÈëÁË `webApplicationContext`£¬È»ºóÖØÐ´ÁË `getServletContext()` ·½·¨£¬»ñÈ¡ `servletContext` ʱ£¬ÏÈ´Ó `webApplicationContext` ÖлñÈ¡£¬Èç¹û»ñÈ¡²»µ½£¬ÔÙ´Ó¸¸Àà·½·¨ÖлñÈ¡¡£
+
+### 4\. ×¼±¸Ò»¸ö `ApplicationContext` µÄʵÏÖÀà
+
+`ApplicationContext` ÖÁ¹ØÖØÒª£¬ÕâÀïÎÒÃÇÑ¡ÔñÖ±½ÓÀ©Õ¹ `AnnotationConfigWebApplicationContext`£º
+
+```
+public class MyWebApplicationContext extends AnnotationConfigWebApplicationContext {
+
+ private Tomcat tomcat;
+
+ /**
+ * ÖØÐ´ postProcessBeanFactory ·½·¨
+ * ÔÚÕâ¸ö·½·¨ÀïÌí¼ÓÎÒÃÇ×Ô¶¨ÒåµÄ MyServletContextAwareProcessor
+ * @param beanFactory
+ */
+ @Override
+ protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
+ beanFactory.addBeanPostProcessor(new MyServletContextAwareProcessor(this));
+ beanFactory.ignoreDependencyInterface(ServletContextAware.class);
+ WebApplicationContextUtils.registerWebApplicationScopes(getBeanFactory());
+ }
+
+ /**
+ * ÔÚÕâ¸ö·½·¨ÀïÆô¶¯ tomcat
+ */
+ @Override
+ protected void onRefresh() {
+ // Ïȵ÷Óø¸ÀàµÄ·½·¨
+ super.onRefresh();
+ // ÉèÖà MyWebApplicationInitializer µÄ beanFactory Óë applicationContext
+ MyWebApplicationInitializer.setBeanFactory(getBeanFactory());
+ MyWebApplicationInitializer.setApplicationContext(this);
+
+ // tomcatµÄ´´½¨¼°Æô¶¯
+ tomcat = new Tomcat();
+ Connector connector = new Connector();
+ connector.setPort(8080);
+ connector.setURIEncoding("UTF-8");
+ tomcat.getService().addConnector(connector);
+
+ Context context = tomcat.addContext("", System.getProperty("java.io.tmpdir"));
+ LifecycleListener lifecycleListener = null;
+ try {
+ lifecycleListener = (LifecycleListener)
+ Class.forName(tomcat.getHost().getConfigClass())
+ .getDeclaredConstructor().newInstance();
+ context.addLifecycleListener(lifecycleListener);
+ // Æô¶¯tomcat
+ tomcat.start();
+ } catch (Exception e) {
+ System.out.println("Æô¶¯Òì³££º");
+ e.printStackTrace();
+ }
+ }
+
+}
+
+```
+
+Õâ¸öÀàÀ©Õ¹ÁË spring µÄÆô¶¯Á÷³Ì£¬ÕâÀïÒ»¹²ÖØÐ´ÁËÁ½¸ö·½·¨£¬ÕâÀïÒ»Ò»½éÉÜÏÂ:
+
+* `postProcessBeanFactory()`£ºÕâ¸ö·½·¨Ö÷ÒªÊÇΪÁË×¢²á `MyServletContextAwareProcessor`£¬Ç°ÃæÎÒÃÇ×¼±¸µÄ `MyServletContextAwareProcessor` ¾ÍÊÇÔÚÕâÀï×¢²áµÄ£¬Ö®ËùÒÔÖØÐ´£¬»¹ÊÇΪÁËʹÓà `tomcat` ÌṩµÄ `ServletContext`£»
+* `onRefresh()`£ºÔÚÕâ¸ö·½·¨ÀÏÈÊÇÉèÖà `MyWebApplicationInitializer` µÄ `beanFactory` Óë `applicationContext` ÊôÐÔÖµ£¬È»ºóÆô¶¯ `tomcat`£»
+
+### 5\. ×¼±¸Ò»¸ö¼òµ¥µÄ `Controller`
+
+×¼±¸Ò»¸ö `Controller`£¬Ö÷ÒªÊǰïÖúÎÒÃÇÑéÖ¤ÏîÄ¿ÊÇ·ñÆô¶¯Õý³££º
+
+```
+@RestController
+@RequestMapping("/test")
+public class TestController {
+
+ @RequestMapping("/hello")
+ public String hello() {
+ System.out.println("hello!!!");
+ return "hello world!";
+ }
+
+}
+
+```
+
+### 6\. Ö÷Àà
+
+×îºó¾ÍÊÇÖ÷ÀàÁË£¬Ö÷ÒªÊÇ´¦Àí spring µÄÆô¶¯²Ù×÷£¬Ò²ÊÇÏ൱¼òµ¥£º
+
+```
+@ComponentScan
+public class MvcDemo03Main {
+
+ public static void main(String[] args) throws Exception {
+ MyWebApplicationContext webApplicationContext = new MyWebApplicationContext();
+ webApplicationContext.register(MvcDemo03Main.class);
+ webApplicationContext.refresh();
+ }
+}
+
+```
+
+ÔËÐУ¬·ÃÎÊ `http://localhost:8080/test/hello`£¬½á¹ûÈçÏ£º
+
+Ò³Ãæ£º
+
+
+
+¿ØÖÆÌ¨£º
+
+
+
+### 7\. ÎÊÌ⣺Æô¶¯ºó£¬`DispatcherServlet#init` ·½·¨»áÔÙ´ÎÆô¶¯ spring ÈÝÆ÷Âð£¿
+
+Ç°ÃæÎÒÃÇ·ÖÎöµ½£¬Ê¹Óà tomcat Æô¶¯ spring ÈÝÆ÷µÄ·½Ê½Ê±£¬spring ÈÝÆ÷ÊÇÔÚ `DispatcherServlet#init` ·½·¨ÖÐÆô¶¯µÄ£¬ÔÚÎÒÃÇʹÓà **spring ÈÝÆ÷Æô¶¯ tomcat** µÄÆô¶¯·½Ê½Ê±£¬tomcat Ö´ÐÐ `DispatcherServlet#init` ·½·¨Ê±£¬»áÔÙ´ÎÆô¶¯ spring ÈÝÆ÷Âð£¿
+
+ÕâÀïÎÒÃÇÖ±½Ó½øÈë `FrameworkServlet#initWebApplicationContext` ·½·¨£¬´òÉ϶ϵ㣺
+
+
+
+ÕâÀïµÄ `wac` Óë `this.webApplicationContext` ¾ÍÊÇ `MyWebApplicationContext` µÄʵÀý£¬ÔÚ´´½¨ `DispatcherServlet` ʱ´«ÈëµÄ:
+
+```
+@Bean
+public DispatcherServlet dispatcherServlet(WebApplicationContext webApplicationContext) {
+ // ÔÚ¹¹Ôì·½·¨µÄ²ÎÊýÖд«ÈëÁË webApplicationContext
+ return new DispatcherServlet(webApplicationContext);
+}
+
+```
+
+µ½ÓÚΪʲô´òµ½Õâ¸ö·½·¨£¬ÄÇÊÇÒòΪ `DispatcherServlet#init` ¾¹ý²ã²ãµ÷Óúó£¬×îÖÕÊÇÔÚÕâ¸ö·½·¨Àï´¦Àí spring ÈÝÆ÷µÄÆô¶¯µÄ£¬µ±¶ÏµãÔËÐе½ `if (!cwac.isActive()) {...` ʱ£¬`!cwac.isActive()` ·µ»Ø½á¹ûΪ `false`£¬Òò´Ë `if` ¿éÀïµÄÆô¶¯ spring ÈÝÆ÷¾Í²»»áÖ´Ðе½ÁË¡£
+
+×ÛÉÏËùÊö£¬Í¨¹ý spring ÈÝÆ÷Æô¶¯ tomcat ºó£¬ÔÚ `DispatcherServlet#init` Àï²»»áÔÙ´ÎÆô¶¯ spring ÈÝÆ÷¡£ÕâÑùÆô¶¯ºó£¬`DispatcherServlet` ¾ÍÊÇÒ»¸ö spring bean£¬ÎÒÃǾͿÉÒÔÔÚ´úÂëÀïʹÓà `@Autowired` ×¢½â½«Æä×¢Èëµ½ÆäËûÀàÖÐÁË£º
+
+```
+@Component
+public class Test {
+ // ±¾ÎĵÄʾÀý£¨ÔÚ spring ÈÝÆ÷ÖÐÆô¶¯ tomcat£©ÊÇ¿ÉÒÔ×¢Èë³É¹¦µÄ
+ @Autowired
+ public DispatcherServlet dispatcherServlet;
+
+ ...
+
+}
+
+```
+
+¹ØÓÚ `spring` Æô¶¯ `tomcat` µÄ·ÖÎö¾Íµ½ÕâÀÆäÖеÄÄѵãÔÚÓÚ**ÈçºÎ½« `tomcat` ÌṩµÄ `ServletContext` ÉèÖõ½ `ServletContextAwareProcessor` ÖÐ**£¬ÆäÖеĽâ¾ö·½Ê½×¢ÒâÌå»á¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4928222](https://my.oschina.net/funcy/blog/4928222) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC demo \344\270\216 @EnableWebMvc \346\263\250\350\247\243.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC demo \344\270\216 @EnableWebMvc \346\263\250\350\247\243.md"
new file mode 100644
index 0000000..2682d3d
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC demo \344\270\216 @EnableWebMvc \346\263\250\350\247\243.md"
@@ -0,0 +1,583 @@
+### 1\. demo ×¼±¸
+
+ΪÁ˸üºÃµØ·ÖÎö springmvc Ïà¹ØÔ´Â룬ÎÒÃÇÐèÒªÏÈ×¼±¸Ò»¸ö springmvc µÄ demo£¬ÕâÀïµÄ demo »¹ÊÇ·ÅÔÚ `spring-learn` Ä£¿é¡£
+
+#### 1\. ÒýÈë tomcat °ü
+
+ÔÚ tomcat 8 Ö®ºó£¬tomcat ÌṩÁ˶ÀÁ¢µÄÔËÐаü£¬ÐèҪʱֱ½ÓÒýÈëÏà¹ØÒÀÀµ¾Í¿ÉÒÔÁË£¬¶ÔÓ¦µÄ gradle ÒÀÀµÈçÏÂ:
+
+```
+optional("org.apache.tomcat.embed:tomcat-embed-core")
+
+```
+
+ÔÚ spring ÏîÄ¿µÄ `build.gradle` ÖУ¬ÒѾÒýÈëÁË `tomcat-embed-core-9.0.29.jar`£¬Òò´ËÔÚ `spring-learn` Ä£¿éÖÐÒýÈëʱ²»ÓÃÔÙÖ¸¶¨°æ±¾¡£
+
+#### 2\. ×¼±¸ÅäÖÃÀà
+
+```
+package org.springframework.learn.mvc.demo01;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@Component
+@ComponentScan("org.springframework.learn.mvc.demo01")
+@EnableWebMvc
+public class MvcConfig {
+
+}
+
+```
+
+ÅäÖÃÀàΪ `MvcConfig`£¬¸ÃÀàÖ¸¶¨ÁËÏîÄ¿µÄ°üɨÃè·¾¶£¬ÒÔ¼°Í¨¹ý `@EnableWebMvc` ¿ªÆô mvc ¹¦ÄÜ¡£
+
+#### 3\. ʵÏÖ `WebApplicationInitializer`
+
+```
+package org.springframework.learn.mvc.demo01;
+
+import org.springframework.web.WebApplicationInitializer;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+import org.springframework.web.servlet.DispatcherServlet;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRegistration;
+
+public class MyWebApplicationInitializer implements WebApplicationInitializer {
+
+ @Override
+ public void onStartup(ServletContext servletContext) {
+ AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
+ context.register(MvcConfig.class);
+
+ DispatcherServlet servlet = new DispatcherServlet(context);
+ ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
+ registration.setLoadOnStartup(1);
+ registration.addMapping("/*");
+ }
+}
+
+```
+
+spring ÌṩÁËÒ»¸ö½Ó¿Ú ¡ª¡ª`WebApplicationInitializer`£¬ÊµÏָýӿÚʱ£¬ÎÒÃÇÔÚ `onStartup(...)` ·½·¨Öд´½¨ spring µÄ `applicationContext`£¬È»ºóÍù servelet ÖÐ×¢²á `DispatcherServlet`¡£
+
+#### 4\. ×¼±¸ controller
+
+```
+package org.springframework.learn.mvc.demo01;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/test")
+public class TestController {
+
+ @RequestMapping("/hello")
+ public String hello() {
+ System.out.println("hello!!!");
+ return "hello world!";
+ }
+}
+
+```
+
+ÕâÀï×¼±¸ÁËÒ»¸ö¼òµ¥µÄ controller£¬·µ»ØÒ»¸ö×Ö·û´® "hello world".
+
+#### 5\. Ö÷Àà
+
+½ÓÏÂÀ´¾ÍÊÇÖ÷ÀàÁË£º
+
+```
+package org.springframework.learn.mvc.demo01;
+
+import org.apache.catalina.Context;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.connector.Connector;
+import org.apache.catalina.startup.Tomcat;
+
+public class MvcDemo01Main {
+
+ public static void main(String[] args) throws Exception {
+ Tomcat tomcat = new Tomcat();
+
+ Connector connector = new Connector();
+ connector.setPort(8080);
+ connector.setURIEncoding("UTF-8");
+ tomcat.getService().addConnector(connector);
+
+ Context context = tomcat.addContext("", System.getProperty("java.io.tmpdir"));
+ LifecycleListener lifecycleListener = (LifecycleListener)
+ Class.forName(tomcat.getHost().getConfigClass())
+ .getDeclaredConstructor().newInstance();
+ context.addLifecycleListener(lifecycleListener);
+ tomcat.start();
+ tomcat.getServer().await();
+ }
+}
+
+```
+
+ÔÚ `main` ·½·¨ÖУ¬Ö÷Òª´¦Àí tomcat Æô¶¯Âß¼¡£
+
+ÔËÐУ¬½á¹ûÈçÏ£º
+
+¿ØÖÆÌ¨£º
+
+
+
+Ò³Ãæ·µ»Ø£º
+
+
+
+¿ÉÒÔ¿´µ½£¬Ò»¸ö¼òµ¥µÄ springmvc ÏîÄ¿¾Í´î½¨Íê³ÉÁË¡£
+
+### 2. `servlet 3.0` ¹æ·¶½éÉÜ
+
+»ØÒäϹÅÀ쵀 springmvc ÏîÄ¿£¬Ò»°ãÓÐÕ⼸¸ö xml ÅäÖÃÎļþ£º
+
+* `web.xml`£»servlet ÅäÖÃÎļþ£¬ÅäÖà web Æô¶¯Ê±µÄ²Ù×÷£¬ÒÔ¼° `servlet`/`listener`/`filter`;
+* `spring.xml`£ºspring ÈÝÆ÷µÄÅäÖÃÎļþ£¬Ö÷ÒªÓÃÀ´ÅäÖà spring bean.
+* `spring-mvc.xml`£ºspringmvc ÅäÖÃÎļþ£¬ÓÃÀ´ÅäÖà mvc Ïà¹ØµÄ bean£¬ÈçÎļþÉÏ´«Ïà¹ØµÄ bean£¬ÊÓͼ½âÎö bean£¬controller °ü·¾¶µÈ¡£
+
+ÏîÄ¿ÔÚÆô¶¯Ê±£¬»áÏȼÓÔØ `web.xml`£¬ÔÚ `web.xml` ÖмÓÔØ spring Ïà¹ØÅäÖã¬Æô¶¯ spring ÈÝÆ÷¡£
+
+ÔÚÉÏÃæµÄ demo ÖУ¬ÎÒÃÇ·¢ÏÖ²¢ ûÓÐÕâЩÅäÖã¬ÉõÖÁÁ¬ `web.xml` Îļþ¶¼Ã»ÓУ¡ÄÇô£¬ÉÏÃæµÄ web ÏîÄ¿ÊÇÔõôÆô¶¯µÄÄØ£¿
+
+ÔÚ `servlet` ÔÚ `3.0` Ö®ºó£¬ÌṩÁËÒ»¸ö spi ¹æ·¶£¬spring ¶ÔÆäʵÏÖÈçÏ£º
+
+1. ÔÚ `spring-web` Ä£¿éµÄ `/src/main/resources/META-INF/services/` Îļþ¼ÐÏ£¬´´½¨Îļþ `javax.servlet.ServletContainerInitializer`£¬ÄÚÈÝÈçÏÂ
+
+```
+org.springframework.web.SpringServletContainerInitializer
+
+```
+
+
+
+1. `org.springframework.web.SpringServletContainerInitializer` ʵÏÖÁË servlet ¹æ·¶£º
+
+```
+// @HandlesTypes ×¢½âÀ´×ÔÓÚservlet¹æ·¶£¬±íʾ webAppInitializerClass Ϊ WebApplicationInitializer.class
+@HandlesTypes(WebApplicationInitializer.class)
+public class SpringServletContainerInitializer implements ServletContainerInitializer {
+
+ /*
+ * ÖØÐ´ ServletContainerInitializer µÄ onStartup ·½·¨
+ * ÔÚÕâ¸ö·½·¨ÀÖ÷ÒªÊÇʵÀý»¯ spring ÌṩµÄ WebApplicationInitializer.class£¬È»ºóÖ´ÐÐÆä onStartup ·½·¨
+ *
+ * Set> webAppInitializerClasses ÖеÄÀàÐÍΪ WebApplicationInitializer.class£¬
+ * Õâ¸öÀàÐÍÓÉ @HandlesTypes ×¢½âÖ¸¶¨
+ */
+ @Override
+ public void onStartup(@Nullable Set> webAppInitializerClasses, ServletContext servletContext)
+ throws ServletException {
+
+ List initializers = new LinkedList<>();
+
+ if (webAppInitializerClasses != null) {
+ for (Class> waiClass : webAppInitializerClasses) {
+ if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
+ WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
+ try {
+ // ʹÓ÷´ÉäʵÀý»¯ WebApplicationInitializer µÄʵÏÖÀ࣬Ìí¼Óµ½ initializers ÖÐ
+ initializers.add((WebApplicationInitializer)
+ ReflectionUtils.accessibleConstructor(waiClass).newInstance());
+ }
+ catch (Throwable ex) {
+ ...
+ }
+ }
+ }
+ }
+
+ servletContext.log(initializers.size() + " ...");
+ // ÅÅÐò£¬ÊµÏÖÁËOrderd½Ó¿Ú£¬±ê×¢ @Order ×¢½â£¬»òʵÏÖÁË PriorityOrderd ½Ó¿Ú
+ AnnotationAwareOrderComparator.sort(initializers);
+ for (WebApplicationInitializer initializer : initializers) {
+ // µ÷Óà WebApplicationInitializer ʵÏÖÀàµÄonStartup·½·¨
+ initializer.onStartup(servletContext);
+ }
+ }
+
+}
+
+```
+
+1. `WebApplicationInitializer` µÄʵÏÖ ÎÒÃÇÀ´¿´¿´ demo ÖÐ¶Ô `WebApplicationInitializer` µÄʵÏÖ£º
+
+```
+package org.springframework.learn.mvc.demo01;
+
+import org.springframework.web.WebApplicationInitializer;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+import org.springframework.web.servlet.DispatcherServlet;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletRegistration;
+
+public class MyWebApplicationInitializer implements WebApplicationInitializer {
+
+ /*
+ * ÔÚÕâÀïÆô¶¯ spring ÏîÄ¿
+ */
+ @Override
+ public void onStartup(ServletContext servletContext) {
+ // ´´½¨ spring µÄ ApplicationContext
+ AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
+ context.register(MvcConfig.class);
+
+ // Ìí¼Ó DispatcherServlet µ½ servlet ÖÐ
+ DispatcherServlet servlet = new DispatcherServlet(context);
+ ServletRegistration.Dynamic registration = servletContext.addServlet("app", servlet);
+ registration.setLoadOnStartup(1);
+ registration.addMapping("/*");
+ }
+}
+
+```
+
+×îÖÕÖ´Ðйý³ÌÈçÏ£º
+
+
+
+ÓÉ´Ë£¬spring ÈÝÆ÷¾ÍÆô¶¯ÁË¡£
+
+### 3\. @EnableWebMvc ×÷ÓÃ
+
+ÔÚ demo ÖУ¬ÎÒÃÇͨ¹ý `@EnableWebMvc` À´Æô¶¯ mvc ¹¦ÄÜ£¬ÄÇôÕâ¸ö×¢½â×öÁËÊ²Ã´ÄØ£¿ÎÒÃǽøÈë `EnableWebMvc` Àࣺ
+
+```
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+@Import(DelegatingWebMvcConfiguration.class)
+public @interface EnableWebMvc {
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬Õâ¸ö×¢½âͨ¹ý `@Import` ×¢½âÒýÈëÁË `DelegatingWebMvcConfiguration.class`£¬ÎÒÃÇÔÙÀ´¿´¿´ `DelegatingWebMvcConfiguration`:
+
+```
+@Configuration(proxyBeanMethods = false)
+public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
+ ...
+
+}
+
+```
+
+Õâ¸öÀà±êÓÐ `@Configuration` ×¢½â£¬±íÃ÷ÕâÊǸöÅäÖÃÀ࣬Õâ¸öÀà¼Ì³ÐµÄÊÇ `WebMvcConfigurationSupport`£¬´ÓÃû×ÖÀ´¿´£¬`WebMvcConfigurationSupport` Ϊ "mvc ÅäÖÃÖ§³Ö"£¬Õâ±íÃ÷Õâ¸öÀàÊÇÓÃÀ´Öô¦Àí mvc Ïà¹ØµÄÅäÖõġ£
+
+ΪÁ˸üºÃµØ·ÖÎö£¬ÕâÀïÏȽéÉܼ¸¸öÀࣺ
+
+1. `DelegatingWebMvcConfiguration`£ºÓÉ `@EnableWebMvc` ÒýÈëµÄÀ࣬ÊÇ `WebMvcConfigurationSupport` µÄ×ÓÀà£¬ÖØÐ´ÁË `WebMvcConfigurationSupport` ÌṩµÄÅäÖ÷½·¨£º
+
+ ```
+ /*
+ * @Configuration£º±íÃ÷ÕâÊǸöÅäÖÃÀà
+ * extends WebMvcConfigurationSupport£º¼Ì³ÐÁËWebMvcConfigurationSupportÀà
+ */
+ @Configuration(proxyBeanMethods = false)
+ public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
+
+ // WebMvcConfigurerComposite ÊÇ WebMvcConfigurer µÄ×éºÏ£¬ÏÂÃæ»áÌáµ½
+ private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
+
+ /**
+ * ÉèÖÃconfigurers
+ * Ìí¼ÓÁË@Autowired×¢½â£¬±íʾ½«springÈÝÆ÷ÖеÄËùÓÐWebMvcConfigurer bean ×÷Ϊ
+ * ²ÎÊýconfigurersµÄÖµ £¬È»ºóµ÷Óø÷½·¨
+ */
+ @Autowired(required = false)
+ public void setConfigurers(List configurers) {
+ if (!CollectionUtils.isEmpty(configurers)) {
+ this.configurers.addWebMvcConfigurers(configurers);
+ }
+ }
+
+ /**
+ * ÅäÖÃPathMatch
+ */
+ @Override
+ protected void configurePathMatch(PathMatchConfigurer configurer) {
+ // µ÷Óà WebMvcConfigurerComposite µÄ·½·¨½øÐÐÅäÖÃ
+ this.configurers.configurePathMatch(configurer);
+ }
+
+ // ÆäËûÅäÖ÷½·¨Ò²Êǵ÷Óà WebMvcConfigurerComposite ¶ÔÓ¦µÄ·½·¨½øÐÐÅäÖõÄ
+ ...
+
+ }
+
+ ```
+
+2. `WebMvcConfigurerComposite`£º`WebMvcConfigurer` µÄ×éºÏ£º
+
+ ```
+ /**
+ * ʵÏÖÁË WebMvcConfigurer
+ */
+ class WebMvcConfigurerComposite implements WebMvcConfigurer {
+
+ // delegatesÊôÐÔΪ WebMvcConfigurer µÄ¼¯ºÏ
+ private final List delegates = new ArrayList<>();
+
+ /*
+ * ±»DelegatingWebMvcConfiguration#setConfigurersµ÷ÓÃ
+ * ×îÖÕÊǰѴ«ÈëµÄconfigurersÌí¼Óµ½delegates(Ò²¾ÍÊÇWebMvcConfigurer¼¯ºÏ)ÖÐ
+ */
+ public void addWebMvcConfigurers(List configurers) {
+ if (!CollectionUtils.isEmpty(configurers)) {
+ this.delegates.addAll(configurers);
+ }
+ }
+
+ /**
+ * ÅäÖÃʱ£¬»á±éÀúdelegates(Ò²¾ÍÊÇWebMvcConfigurer¼¯ºÏ)£¬½«´«ÈëµÄÅäÖÃÉèÖõ½
+ * ¼¯ºÏÖеÄÿһ¸öWebMvcConfigurer
+ */
+ @Override
+ public void configurePathMatch(PathMatchConfigurer configurer) {
+ for (WebMvcConfigurer delegate : this.delegates) {
+ delegate.configurePathMatch(configurer);
+ }
+ }
+
+ // ÆäËûÅäÖÃÀàËÆ£¬Ê¡ÂÔ
+ ...
+ }
+
+ ```
+
+3. `WebMvcConfigurer`£ºspringmvc µÄÅäÖýӿڣ¬ÌṩÁ˷dz£¶àµÄÅäÖÃ
+
+ ```
+ public interface WebMvcConfigurer {
+
+ default void configurePathMatch(PathMatchConfigurer configurer) {
+ }
+
+ default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
+ }
+
+ default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
+ }
+
+ ...
+ }
+
+ ```
+
+4. `WebMvcConfigurationSupport`£ºspringmvc µÄÅäÖÃÖ§³ÖÀà
+
+ ```
+ /**
+ * ʵÏÖÁËÁ½¸öaware½Ó¿Ú
+ */
+ public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
+
+ //================= À´×Ô XxxAware ½Ó¿ÚµÄ·½·¨ =================
+ @Override
+ public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ @Override
+ public void setServletContext(@Nullable ServletContext servletContext) {
+ this.servletContext = servletContext;
+ }
+
+ //================= @Bean ·½·¨£¬ÏòspringÖÐÌí¼Ó bean =================
+ @Bean
+ public RequestMappingHandlerMapping requestMappingHandlerMapping(...) {
+ RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
+ mapping.setOrder(0);
+ // getInterceptors(...) »ñÈ¡ interceptors£¬ÍùÏ¿´
+ mapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));
+ mapping.setContentNegotiationManager(contentNegotiationManager);
+ // getCorsConfigurations(...) »ñÈ¡CorsÅäÖã¬ÍùÏ¿´
+ mapping.setCorsConfigurations(getCorsConfigurations());
+ // getPathMatchConfigurer(...) »ñÈ¡PathMatchÅäÖã¬ÍùÏ¿´
+ PathMatchConfigurer configurer = getPathMatchConfigurer();
+
+ ...
+
+ return mapping;
+ }
+ ...
+ //================= get xxx ÅäÖ÷½·¨£¬Ìí¼ÓspringÌṩµÄĬÈÏÅäÖã¬Ìí¼Ó×Ô¶¨ÒåÅäÖà =======
+ // »ñÈ¡ interceptors
+ protected final Object[] getInterceptors(
+ FormattingConversionService mvcConversionService,
+ ResourceUrlProvider mvcResourceUrlProvider) {
+ if (this.interceptors == null) {
+ InterceptorRegistry registry = new InterceptorRegistry();
+ // µ÷ÓÃÅäÖ÷½·¨£¬Ìí¼Ó interceptor£¬ÍùÏ¿´
+ addInterceptors(registry);
+ registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService));
+ registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider));
+ this.interceptors = registry.getInterceptors();
+ }
+ return this.interceptors.toArray();
+ }
+
+ // »ñÈ¡CorsÅäÖÃ
+ protected final Map getCorsConfigurations() {
+ if (this.corsConfigurations == null) {
+ CorsRegistry registry = new CorsRegistry();
+ // µ÷ÓÃÅäÖ÷½·¨£¬Ìí¼Ó CorsMapping£¬ÍùÏ¿´
+ addCorsMappings(registry);
+ this.corsConfigurations = registry.getCorsConfigurations();
+ }
+ return this.corsConfigurations;
+ }
+
+ // »ñÈ¡PathMatchÅäÖÃ
+ protected PathMatchConfigurer getPathMatchConfigurer() {
+ if (this.pathMatchConfigurer == null) {
+ this.pathMatchConfigurer = new PathMatchConfigurer();
+ configurePathMatch(this.pathMatchConfigurer);
+ }
+ return this.pathMatchConfigurer;
+ }
+
+ ...
+
+ //================= ÅäÖ÷½·¨£¬Áô´ý×ÓÀàʵÏÖ =================
+ // Ìí¼Ó×Ô¶¨Òå Interceptor£¬´ý×ÓÀàʵÏÖ
+ protected void addInterceptors(InterceptorRegistry registry) {
+ }
+
+ // Ìí¼Ó×Ô¶¨Òå CorsMapping£¬´ý×ÓÀàʵÏÖ
+ protected void addCorsMappings(CorsRegistry registry) {
+ }
+
+ // ÅäÖÃ×Ô¶¨Òå PathMatch
+ protected void configurePathMatch(PathMatchConfigurer configurer) {
+ }
+ ...
+
+ }
+
+ ```
+
+ ¿ÉÒÔ¿´µ½£¬Õâ¸öÀàµÄ·½·¨·ÖΪËÄÀࣺ
+
+ * À´×Ô `XxxAware` µÄ·½·¨£º`XxxAware` ½Ó¿ÚÓÉ spring Ìṩ£¬bean ³õʼ»¯Íê³Éʱ´¦Àí»Øµ÷£»
+ * ÓÐ `@Bean` ×¢½âµÄ·½·¨£ºÍù spring ÖÐÌí¼Ó bean£¬Éú³É bean ʱ»áµ÷Óà `getXxx` ·½·¨£»
+ * `getXxx` ·½·¨£º»ñÈ¡ÅäÖ÷½·¨£¬Ôڸ÷½·¨ÖУ¬»áÌí¼Ó spring ÌṩµÄĬÈÏÅäÖã¬ÒÔ¼°µ÷Óà `addXxx/configureXxx` ·½·¨Ìí¼Ó×Ô¶¨ÒåÅäÖã»
+ * `addXxx/configureXxx` ·½·¨£ºÓÉ×ÓÀàʵÏÖ£¬¿ÉÒÔÏò springmvc ÖÐÌí¼Ó×Ô¶¨ÒåÅäÖá£
+
+ÕâÀï×ܽáÏÂÕâ 4 ¸öÀàµÄ¹ØÏµ£º
+
+
+
+ÀíÇåÁËÕâËĸöÀàµÄ¹ØÏµ£¬`@EnableWebMvc` µÄÖ´ÐÐÁ÷³Ì¾ÍһĿÁËÈ»ÁË£¬ÕâÀï×ܽáÈçÏ£º
+
+1. `@EnableWebMvc` Ïò spring ÈÝÆ÷ÖÐÒýÈëÁË` DelegatingWebMvcConfiguration`£»
+
+2. `DelegatingWebMvcConfiguration` ÖÐÓаüº¬ `@Autowired` ×¢½âµÄ·½·¨ `setConfigurers(List)`£¬ÔÚ spring bean µÄÖÜÆÚÖлá¶ÔÆäÖ´ÐУ¬×÷ÓÃΪ»ñÈ¡ÈÝÆ÷ÖÐËùÓÐ `WebMvcConfigurer` µÄ bean ½«ÆäÉèÖõ½` DelegatingWebMvcConfiguration` µÄÊôÐÔÖУ»
+
+3. `DelegatingWebMvcConfiguration` ¼Ì³ÐÁË `WebMvcConfigurationSupport`£¬ÔÚ spring bean µÄÖÜÆÚÖлᴦÀí `WebMvcConfigurationSupport` ÖÐÓÐ `@Bean` ×¢½âµÄ·½·¨£¬ÕâÖÖ·½·¨±È½Ï¶à£¬Èç `requestMappingHandlerMapping()`¡¢`mvcPathMatcher` µÈ£¬ÕâЩ¶¼ÊÇ smvc µÄ¹¦ÄÜ×é¼þ£»
+
+4. ÔÚ´¦Àí `WebMvcConfigurationSupport` ÖÐÓÐ `@Bean` ×¢½âµÄ·½·¨Ê±£¬»áµ÷Óà `getXxx()` »ñÈ¡Ïà¹ØÅäÖ㬸ÃÅäÖðüÀ¨ spring ÌṩµÄĬÈÏÅäÖü°×Ô¶¨ÒåÅäÖã¬`getXxx()` ÓÉ `WebMvcConfigurationSupport` Ìṩ£»
+
+5. ÔÚµ÷Óà `WebMvcConfigurationSupport#getXxx()` »ñÈ¡×Ô¶¨ÒåÅäÖÃʱ£¬»áµ÷Óà `addXxx()/configureXxx()`£¬¸Ã·½·¨ÔÚ `WebMvcConfigurationSupport` ÖÐÊǿշ½·¨£¬¾ßÌåÐÝÂß¼ÓÉ×ÓÀà (Ò²¾ÍÊÇ` DelegatingWebMvcConfiguration`) Ìṩ£¬×îÖÕµ÷Ó÷½Ê½ÊÇ**±éÀúÖ´ÐÐµÚ 2 ²½»ñÈ¡µÄ `WebMvcConfigurer` µÄ `addXxx()/configureXxx()`**£»
+
+Õû¸öÁ÷³ÌÈçÏÂͼËùʾ£º
+
+
+
+ÔÚÆôÓà springmvc ¹¦ÄÜ£¬²¢Ìí¼Ó×Ô¶¨ÒåÅäÖÃʱ£¬ÎÒÃÇ¿ÉÒÔÕâô×ö:
+
+1. ·½Ê½ 1£ºÊ¹Óà @EnableWebMvc ×¢½âÆôÓà mvc ¹¦ÄÜ£¬ÊµÏÖ WebMvcConfigurer£¬Ìí¼Ó×Ô¶¨ÒåÅäÖÃ
+
+ ```
+ // ʹÓÃ@EnableWebMvc×¢½âÆôÓÃmvc¹¦ÄÜ
+ @Component
+ @EnableWebMvc
+ public class MvcConfig {
+ ...
+ }
+
+ // ʵÏÖ WebMvcConfigurer£¬Ìí¼Ó×Ô¶¨ÒåÅäÖÃ
+ @Component
+ public class MyWebMvcConfigurer implements WebMvcConfigurer {
+
+ // ÖØÐ´WebMvcConfigurer·½·¨£¬´¦Àí×Ô¶¨ÒåÅäÖÃ
+ }
+
+ ```
+
+2. ·½Ê½ 2£ºÊµÏÖ `WebMvcConfigurationSupport` Àà£¬ÖØÐ´ÆäÖеÄÅäÖ÷½·¨
+
+ ```
+ @Component
+ public class MyWebMvcConfigurationSupport extends WebMvcConfigurationSupport {
+ // ÖØÐ´ÅäÖ÷½·¨£¬´¦Àí×Ô¶¨ÒåÅäÖÃ
+
+ }
+
+ ```
+
+ ²»¹ý²ÉÓÃÕâÖÖ·½Ê½ºó£¬ÔÙʵÏÖ `WebMvcConfigurer` Ìí¼Ó×Ô¶¨ÒåÅäÖþͲ»ÉúЧÁË£¬×Ô¶¨ÒåÅäÖÃÖ»ÄÜÔÚ `WebMvcConfigurationSupport` ½øÐÐÅäÖá£
+
+springmvc ÌṩÁËÄÄЩÅäÖÃÏîÄØ£¿ÎÒÃÇÀ´¿´¿´ `WebMvcConfigurer` ÌṩµÄ·½·¨£º
+
+* `configurePathMatch`£ºÅäÖ÷ÓÉÇëÇó¹æÔò
+* `configureContentNegotiation`£ºÄÚÈÝÐÉÌÅäÖÃ
+* `configureAsyncSupport`£º
+* `configureDefaultServletHandling`£ºÄ¬ÈϾ²Ì¬×ÊÔ´´¦ÀíÆ÷
+* `addFormatters`£º×¢²á×Ô¶¨Òåת»¯Æ÷
+* `addInterceptors`£ºÀ¹½ØÆ÷ÅäÖÃ
+* `addResourceHandlers`£º×ÊÔ´´¦Àí
+* `addCorsMappings`£ºCORS ÅäÖÃ
+* `addViewControllers`£ºÊÓÍ¼Ìø×ª¿ØÖÆÆ÷
+* `configureViewResolvers`£ºÅäÖÃÊÓͼ½âÎö
+* `addArgumentResolvers`£ºÌí¼Ó×Ô¶¨Òå·½·¨²ÎÊý´¦ÀíÆ÷
+* `addReturnValueHandlers`£ºÌí¼Ó×Ô¶¨Òå·µ»Ø½á¹û´¦ÀíÆ÷
+* `configureMessageConverters`£ºÅäÖÃÏûϢת»»Æ÷¡£ÖØÔػḲ¸ÇĬÈÏ×¢²áµÄ `HttpMessageConverter`
+* `extendMessageConverters`£ºÅäÖÃÏûϢת»»Æ÷¡£½öÌí¼ÓÒ»¸ö×Ô¶¨ÒåµÄ `HttpMessageConverter`.
+* `configureHandlerExceptionResolvers`£ºÅäÖÃÒ쳣ת»»Æ÷
+* `extendHandlerExceptionResolvers`£ºÌí¼ÓÒ쳣ת»¯Æ÷
+* `getValidator`:
+* `getMessageCodesResolver`£º
+
+Èç¹ûÐèÒªÅäÖÃÏà¹ØÏֻÐèÒªÖØÐ´Ïà¹Ø·½·¨ ¼´¿É¡£
+
+×îºóÎÒÃÇÔÙÀ´¿´¿´ `WebMvcConfigurationSupport` ÖÐÒýÈëÁËÄÄЩ Bean£¬ÓÐ `@Bean` ×¢½âµÄ·½·¨ÈçÏ£º
+
+* `public RequestMappingHandlerMapping requestMappingHandlerMapping(...)`
+* `public PathMatcher mvcPathMatcher()`
+* `public UrlPathHelper mvcUrlPathHelper()`
+* `public ContentNegotiationManager mvcContentNegotiationManager()`
+* `public HandlerMapping viewControllerHandlerMapping(...)`
+* `public BeanNameUrlHandlerMapping beanNameHandlerMapping(...)`
+* `public RouterFunctionMapping routerFunctionMapping(...)`
+* `public HandlerMapping resourceHandlerMapping(...)`
+* `ResourceUrlProvider mvcResourceUrlProvider()`
+* `public HandlerMapping defaultServletHandlerMapping()`
+* `public RequestMappingHandlerAdapter requestMappingHandlerAdapter(...)`
+* `public HandlerFunctionAdapter handlerFunctionAdapter()`
+* `public FormattingConversionService mvcConversionService()`
+* `public Validator mvcValidator()`
+* `public CompositeUriComponentsContributor mvcUriComponentsContributor(...)`
+* `public HttpRequestHandlerAdapter httpRequestHandlerAdapter()`
+* `public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter()`
+* `public HandlerExceptionResolver handlerExceptionResolver(...)`
+* `public ViewResolver mvcViewResolver(...)`
+* `HandlerMappingIntrospector mvcHandlerMappingIntrospector()`
+
+ÕâЩ¶¼ÊÇ springmvc ÖÐÓõ½µÄһЩ×é¼þ£¬¾ßÌåµÄ¾ßÌåÄÚÈݾͲ»Õ¹¿ªÁË¡£
+
+### 4\. ×ܽá
+
+±¾ÎÄÄÚÈݱȽÏÔÓ£¬ÏÈÌṩÁËÒ»¸ö springmvc µÄ demo£¬È»ºó½éÉÜÁË demo ÖÐ `0 xml` ÅäÖÃÔÀí (Ò²¾ÍÊÇ `servlet 3.0` ¹æ·¶£©£¬½Ó׎éÉÜÁË `@EnableWebMvc` µÄ¹¦ÄÜ£¬×ÅÖØ½éÉÜÁË `WebMvcConfigurationSupport` µÄ×÷Óá£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4696657](https://my.oschina.net/funcy/blog/4696657) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC \346\225\264\344\275\223\346\272\220\347\240\201\347\273\223\346\236\204\346\200\273\347\273\223.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC \346\225\264\344\275\223\346\272\220\347\240\201\347\273\223\346\236\204\346\200\273\347\273\223.md"
new file mode 100644
index 0000000..7fdb68a
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/SpringMVC \346\225\264\344\275\223\346\272\220\347\240\201\347\273\223\346\236\204\346\200\273\347\273\223.md"
@@ -0,0 +1,82 @@
+### 1\. servlet 3.0 ¹æ·¶
+
+±¾ÏµÁÐÒ»¿ªÊ¼£¬ÏȽéÉÜÁË `servlet3.0` ¹æ·¶£¬Í¨¹ý¸Ã¹æ·¶£¬¿ÉÒÔÈÃÎÒÃÇʵÏÖ web ÏîÄ¿µÄ `0xml` ÅäÖÃ.
+
+* `servlet3.0` ¹æ·¶ÖУ¬servlet ͨ¹ý `SPI` »úÖÆÌṩÁËÒ»¸ö½Ó¿Ú£º`ServletContainerInitializer`£»
+* spring ʵÏÖÁ˸ýӿڣ¬ÔÚÆäʵÏÖÀà `SpringServletContainerInitializer` µÄ `onStartup(...)` ·½·¨ÖУ¬»áÖ´ÐÐËùÓÐʵÏÖÁË `WebApplicationInitializer` ½Ó¿ÚµÄÀàµÄ `onStartup(...)` ·½·¨£¬×îÖÕÎÒÃÇÖ»ÐèҪʵÏÖ `WebApplicationInitializer` ½Ó¿Ú¼´¿É£»
+* ÔÚÎÒÃÇ×ÔÖ÷ʵÏÖ `WebApplicationInitializer` ½Ó¿ÚµÄÀàÖУ¬ÔÚ `onStartup(...)` Ïò servlet ÈÝÆ÷ÖÐÊÖ¶¯×¢²áÁËÒ» ¸ö servlet£º`DispatcherServlet`£¬ÔÚÕâ¸ö servlet ÖлáÆô¶¯ spring ÈÝÆ÷£»
+
+ÒÔÉÏÕû¸öÁ÷³Ì¾ÍÕâÑù£º
+
+
+
+### 2\. ÆôÓà webMvc µÄ·½Ê½
+
+ÎÒÃÇ·ÖÎöÁËÆôÓà `webMvc` µÄÁ½ÖÖ·½Ê½£º
+
+#### 1. `@EnableWebMvc`
+
+ÕâÖÖ·½Ê½ºÜ¼òµ¥£¬Ö»ÐèÒªÕâÑù£º
+
+```
+// ʹÓÃ@EnableWebMvc×¢½âÆôÓÃmvc¹¦ÄÜ
+@Component
+@EnableWebMvc
+public class MvcConfig {
+ ...
+}
+
+```
+
+Èç¹ûÎÒÃÇÒª´¦Àí webMvc µÄһЩÅäÖÃʱ£¬ÐèҪʵÏÖ `WebMvcConfigurer`:
+
+```
+// ʵÏÖ WebMvcConfigurer£¬Ìí¼Ó×Ô¶¨ÒåÅäÖÃ
+@Component
+public class MyWebMvcConfigurer implements WebMvcConfigurer {
+
+ // ÖØÐ´WebMvcConfigurer·½·¨£¬´¦Àí×Ô¶¨ÒåÅäÖÃ
+}
+
+```
+
+#### 2\. ʵÏÖ `WebMvcConfigurationSupport`
+
+»¹ÓÐÒ»ÖÖ·½Ê½ÆôÓà `webMvc` µÄ ·½Ê½ÊÇʵÏÖ `WebMvcConfigurationSupport`£º
+
+```
+@Component
+public class MyWebMvcConfigurationSupport extends WebMvcConfigurationSupport {
+ // ÖØÐ´ÅäÖ÷½·¨£¬´¦Àí×Ô¶¨ÒåÅäÖÃ
+ ...
+
+ /**
+ * ±ÈÈ磬Ìí¼Ó¿çÓòÅäÖã¬Ö±½ÓÖØÐ´ addCorsMappings ·½·¨
+ */
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ // Ìí¼Ó×Ô¼ºµÄÅäÖÃ
+ ...
+ }
+
+}
+
+```
+
+ÐèҪעÒâµÄÊÇ£¬Ê¹ÓÃÕâÖÖ·½Ê½ºó£¬ÐèÒª´¦Àí×Ô¶¨ÒåÅäÖÃʱ£¬¾Í²»ÄÜÔÙȥʵÏÖ `WebMvcConfigurer` ½Ó¿ÚÁË£¬¶øÓ¦¸ÃÖ±½ÓÖØÐ´ `WebMvcConfigurationSupport` ÖеÄÏàÓ¦·½·¨£¬ÈçÉÏÃæÖØÐ´ `addCorsMappings()`.
+
+### 3\. Õû¸öÆô¶¯Á÷³Ì
+
+ÓÃÒ»ÕÅͼÀ´×ܽáÕû¸öÆô¶¯Á÷³Ì£º
+
+ 
+
+### 4\. ÇëÇóÁ÷³Ì
+
+Ò²ÓÃÒ»ÕÅͼÀ´×ܽáÕû¸öÇëÇóÁ÷³Ì£º
+
+
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4773418](https://my.oschina.net/funcy/blog/4773418) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/\350\257\267\346\261\202\346\211\247\350\241\214\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\344\271\213\350\216\267\345\217\226 Handler.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/\350\257\267\346\261\202\346\211\247\350\241\214\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\344\271\213\350\216\267\345\217\226 Handler.md"
new file mode 100644
index 0000000..2f1e035
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/\350\257\267\346\261\202\346\211\247\350\241\214\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\344\271\213\350\216\267\345\217\226 Handler.md"
@@ -0,0 +1,772 @@
+ÉÏһƪÎÄÕÂÎÒÃÇ·ÖÎö `RequestMapping` ³õʼ»¯Á÷³Ì£¬±¾ÎĽ«·ÖÎö spring mvc µÄÇëÇóÖ´ÐÐÁ÷³Ì¡£
+
+### 1\. ÇëÇóµÄÖ´ÐÐÈë¿Ú
+
+ÔÚ [spring mvc Ö® DispatcherServlet ³õʼ»¯Á÷³Ì](https://my.oschina.net/funcy/blog/4710330 "spring mvcÖ®DispatcherServlet ³õʼ»¯Á÷³Ì")Ò»ÎÄÖУ¬ÎÒÃÇÉîÈë·ÖÎöÁËÏò `servlet` ÈÝÆ÷Ìí¼ÓÁË `DispatcherServlet` ºó£¬Òý·¢µÄһϵÁгõʼ»¯Á÷³Ì£¬±¾ÎĽ«¼ÌÐøÎ§ÈÆÕâ¸ö `servlet` ·ÖÎö `springmvc` µÄÇëÇóÁ÷³Ì¡£
+
+#### 1.1 »Ø¹Ë servlet µÄÖ´ÐÐÈë¿Ú£º
+
+ÔÚ·ÖÎö `DispatcherServlet` ǰÊ×ÏÈÒª»Ø¹ËÏ servlet µÄÖ´ÐÐÈë¿Ú¡£
+
+ÔÚÎÒÃÇʵÏÖ×Ô¶¨ÒåµÄ servlet ʱ£¬Ò»°ãÊÇʵÏÖ `HttpServlet`£¬È»ºóÖØÐ´ `doGet(xxx)`¡¢`doPost()` ·½·¨£¬¶øÊµ¼ÊÉÏ servlet Ϊ `HttpServlet#service(ServletRequest, ServletResponse)`£º
+
+```
+public abstract class HttpServlet extends GenericServlet {
+ ...
+
+ // Õâ¸ö·½·¨½ö×öÁ˲ÎÊýÀàÐÍת»»
+ @Override
+ public void service(ServletRequest req, ServletResponse res)
+ throws ServletException, IOException {
+
+ HttpServletRequest request;
+ HttpServletResponse response;
+
+ // ÔÚÕâÀï´¦Àí²ÎÊýµÄÀàÐÍת»»
+ try {
+ request = (HttpServletRequest) req;
+ response = (HttpServletResponse) res;
+ } catch (ClassCastException e) {
+ throw new ServletException(lStrings.getString("http.non_http"));
+ }
+ service(request, response);
+ }
+
+ /**
+ * ÔÚÕâÀï´¦ÀíÇëÇó
+ * ´Ó´úÂë¿ÉÒÔ¿´µ½£¬Õâ¸öÀàÆäʵÊÇ×öÒ»¸öת·¢£ºÅжÏÇëÇó·½·¨£¬È»ºóµ÷ÓþßÌåµÄ·½·¨Ö´ÐÐ
+ */
+ protected void service(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+
+ String method = req.getMethod();
+
+ // ÅжϵÄÇëÇó·½·¨£¬È»ºóÕÒµ½¶ÔÓ¦µÄ·½·¨È¥Ö´ÐÐ
+ if (method.equals(METHOD_GET)) {
+ long lastModified = getLastModified(req);
+ if (lastModified == -1) {
+ doGet(req, resp);
+ } else {
+ ...
+ doGet(req, resp);
+ }
+ } else if (method.equals(METHOD_HEAD)) {
+ long lastModified = getLastModified(req);
+ maybeSetLastModified(resp, lastModified);
+ doHead(req, resp);
+ } else if (method.equals(METHOD_POST)) {
+ doPost(req, resp);
+ } else if (method.equals(METHOD_PUT)) {
+ doPut(req, resp);
+ } else if (method.equals(METHOD_DELETE)) {
+ doDelete(req, resp);
+ } else if (method.equals(METHOD_OPTIONS)) {
+ doOptions(req,resp);
+ } else if (method.equals(METHOD_TRACE)) {
+ doTrace(req,resp);
+ } else {
+ // ûÓжÔÓ¦µÄ·½·¨£¬±¨´í
+ ...
+ }
+ }
+
+}
+
+```
+
+ÒÔÉÏÊÇ servlet Ô´Â룬·½·¨±È½Ï¼òµ¥£¬Öص㲿·Ö¶¼×öÁË×¢ÊÍ£¬ÕâÀïÓÐÁ½¸öÐèÒªÔÙ´ÎÇ¿µ÷Ï£º
+
+1. servlet µÄÖ´ÐÐÈë¿ÚΪ `HttpServlet#service(ServletRequest, ServletResponse)`£»
+2. `HttpServlet#service(HttpServletRequest, HttpServletResponse)` ·½·¨»á¸ù¾ÝÇëÇó·½·¨ÕÒµ½¶ÔÓ¦µÄ´¦Àí·½·¨Ö´ÐУ¬Ò»°ãÀ´Ëµ£¬ÎÒÃÇ×Ô¶¨Òå servlet£¬Ö»ÒªÖØÐ´ `doGet(xxx)`¡¢`doPost(xxx)` µÈ·½·¨¼´¿É¡£
+
+ÇëÇóÁ÷³Ì´ó¸ÅÈçÏ£º
+
+
+
+#### 1.2 `DispatcherServlet` µÄ¸¸Àࣺ`FrameworkServlet`
+
+Á˽âÍê servlet µÄÇëÇóÈë¿Úºó£¬½ÓÏÂÀ´¾ÍµÃ·ÖÎöÒ»¸ö²»µÃ²»ÌáµÄÀàÁË£º`FrameworkServlet`¡£`FrameworkServlet` ÊÇ `HttpServlet` µÄ×ÓÀ࣬ʵÏÖÁË `HttpServlet` µÄ¸÷ÖÖ `doXxx()`£¬Í¬Ê±Ò²ÊµÏÖÁË `service(HttpServletRequest, HttpServletResponse)`£º
+
+```
+/**
+ * FrameworkServlet¼Ì³ÐÁËHttpServletBean£¬¶øHttpServletBean¼Ì³ÐÁËHttpServlet
+ * Òò´ËFrameworkServletÒ²ÊÇHttpServletµÄ×ÓÀà
+ */
+public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
+ @Override
+ protected final void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ processRequest(request, response);
+ }
+
+ @Override
+ protected final void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ processRequest(request, response);
+ }
+
+ @Override
+ protected final void doPut(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ processRequest(request, response);
+ }
+
+ @Override
+ protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ processRequest(request, response);
+ }
+
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
+ if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
+ processRequest(request, response);
+ }
+ else {
+ // GET/POST/PUT/DELETE µÈÇëÇó·½·¨£¬»¹ÊÇ»áµ÷Óø¸ÀàµÄ·½·¨
+ super.service(request, response);
+ }
+ }
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬ÒÔÉÏ´úÂëÖУ¬ÓÐÒ»¸ö·½·¨µÄ³ö¾µÂÊÏ൱¸ß£º`FrameworkServlet#processRequest`£¬²»¹ÜÊÇ `doXxx(xxx)`£¬»¹ÊÇ `service(xxx)`£¬¶¼»áµ÷Óà `processRequest(xxx)`£¬½ÓÏÂÀ´ÎÒÃǾÍÀ´¿´¿´Õâ¸ö·½·¨×öÁËʲô£º
+
+> FrameworkServlet#processRequest
+
+```
+protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ // ¼Ç¼¿ªÊ¼Ê±¼ä
+ long startTime = System.currentTimeMillis();
+ Throwable failureCause = null;
+ // ¼Ç¼µ±Ç°Ï̵߳ÄÐÅÏ¢
+ LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
+ LocaleContext localeContext = buildLocaleContext(request);
+ RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
+ ServletRequestAttributes requestAttributes = buildRequestAttributes(
+ request, response, previousAttributes);
+ WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
+ asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(),
+ new RequestBindingInterceptor());
+ initContextHolders(request, localeContext, requestAttributes);
+ try {
+ // ºËÐÄ´¦Àí
+ doService(request, response);
+ }
+ catch (ServletException | IOException ex) {
+ failureCause = ex;
+ throw ex;
+ }
+ catch (Throwable ex) {
+ failureCause = ex;
+ throw new NestedServletException("Request processing failed", ex);
+ }
+ finally {
+ // Çå³ýḬ̈߳ó¶¨ÐÅÏ¢
+ resetContextHolders(request, previousLocaleContext, previousAttributes);
+ if (requestAttributes != null) {
+ requestAttributes.requestCompleted();
+ }
+ logResult(request, response, failureCause, asyncManager);
+ // ·¢ËÍʼþ֪ͨ
+ publishRequestHandledEvent(request, response, startTime, failureCause);
+ }
+}
+
+```
+
+Õâ¸ö·½·¨ËäÈ»Óе㳤£¬µ«´ó²¿·ÖÓëÇëÇó´¦ÀíÁ÷³Ì¹ØÏµ²»´ó£¬ÓëÇëÇó´¦ÀíÁ÷³ÌÏà¹ØµÄÖ»Óм¸ÐУº
+
+```
+ ...
+ try {
+ // ºËÐÄ´¦Àí
+ doService(request, response);
+ }
+ catch (ServletException | IOException ex) {
+ failureCause = ex;
+ throw ex;
+ }
+ ...
+
+```
+
+ÓÉ´Ë¿ÉÒÔ¿´µ½£¬Êµ¼Ê´¦ÀíÇëÇóµÄ·½·¨ÊÇÔÚ `FrameworkServlet#doService` ÖС£²»¹ý£¬`FrameworkServlet#doService` ÊǸö³éÏó·½·¨£º
+
+```
+protected abstract void doService(HttpServletRequest request,
+ HttpServletResponse response) throws Exception;
+
+```
+
+ÕæÕýµÄʵÏÖÊÇÔÚ×ÓÀ࣬Ҳ¾ÍÊÇ `DispatcherServlet#doService` ÖС£
+
+#### 1.3 `DispatcherServlet#doService`
+
+À´¿´¿´ `DispatcherServlet#doService` ×öÁËɶÊ£º
+
+```
+public class DispatcherServlet extends FrameworkServlet {
+ @Override
+ protected void doService(HttpServletRequest request,
+ HttpServletResponse response) throws Exception {
+ logRequest(request);
+ // Ê¡ÂÔÁËÒ»´ó¶ÎÊôÐÔÉèÖÃ
+ ...
+ try {
+ // ¾ßÌåµÄ´¦Àí
+ doDispatch(request, response);
+ }
+ finally {
+ ...
+ }
+ }
+}
+
+```
+
+ÕâÈË·½·¨Ò²Ã»¸ÉʲôÊÂʵ£¬Ö»Êǵ÷ÓÃÁËһϠ`doDispatch` ·½·¨£¬È»ºó¾ÍûÁË¡£ÊÂʵÉÏ£¬`DispatcherServlet#doDispatch` ¾ÍÊÇ×îÖÕ´¦ÀíÇëÇóµÄÂß¼£¬½ÓÏÂÀ´ÎÒÃÇÖØµã·ÖÎöÕâ¸ö·½·¨ ¡£
+
+ÕâÒ»½ÚÎÒÃÇÀ´×ܽáÏ `DispatcherServlet` µÄÇëÇóÁ÷³Ì£º
+
+
+
+### 2\. springmvc ÇëÇó·Ö·¢£º`DispatcherServlet#doDispatch`
+
+ÉÏÒ»½ÚµÄ×îºó£¬ÎÒÃÇ·¢ÏÖ springmvc ´¦ÀíÇëÇóµÄ·½·¨ÊÇ `DispatcherServlet#doDispatch`£¬±¾½Ú¾Í´ÓÕâ¸ö·½·¨ÈëÊÖ£¬¿´¿´Õâ¸ö·½·¨µÄÂß¼£º
+
+```
+protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
+ HttpServletRequest processedRequest = request;
+ HandlerExecutionChain mappedHandler = null;
+ boolean multipartRequestParsed = false;
+ WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
+ try {
+ ModelAndView mv = null;
+ Exception dispatchException = null;
+ try {
+ //Èç¹ûÊÇÎļþÉÏ´«ÇëÇóÔò½øÐÐÌØÊâ´¦Àí
+ processedRequest = checkMultipart(request);
+ multipartRequestParsed = (processedRequest != request);
+ // 1\. »ñÈ¡¶ÔÓ¦µÄhandler,
+ // HandlerÖаüº¬ÕæÕýµØ´¦ÀíÆ÷£¨ControllerÖеķ½·¨£©ºÍÒ»×éHandlerInterceptorÀ¹½ØÆ÷
+ mappedHandler = getHandler(processedRequest);
+ if (mappedHandler == null) {
+ // Èç¹ûûÕÒµ½£¬±¨¸ö404
+ noHandlerFound(processedRequest, response);
+ return;
+ }
+ // 2\. »ñÈ¡¶ÔÓ¦µÄhandlerAdapter£¬ÓÃÀ´ÔËÐÐ handler(xxx)
+ HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
+ // ´¦Àílast-modifiedÇé¿ö
+ String method = request.getMethod();
+ boolean isGet = "GET".equals(method);
+ if (isGet || "HEAD".equals(method)) {
+ long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
+ if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
+ return;
+ }
+ }
+ // 3\. ÔËÐÐspringµÄÀ¹½ØÆ÷, ÔËÐÐ HandlerInterceptor#preHandle ·½·¨
+ if (!mappedHandler.applyPreHandle(processedRequest, response)) {
+ return;
+ }
+ // 4\. ͨ¹ýÉÏÃæ»ñÈ¡µ½µÄhandlerAdapterÀ´µ÷ÓÃhandle
+ mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
+ if (asyncManager.isConcurrentHandlingStarted()) {
+ return;
+ }
+ // Èç¹ûº¯Êýµ÷ÓÃûÓзµ»ØÊÓͼÔòʹÓÃĬÈϵÄ
+ applyDefaultViewName(processedRequest, mv);
+ // 5\. Ö´ÐÐÀ¹½ØÆ÷£¬ÔËÐÐ HandlerInterceptor#postHandle ·½·¨
+ mappedHandler.applyPostHandle(processedRequest, response, mv);
+ }
+ catch (Exception ex) {
+ dispatchException = ex;
+ }
+ catch (Throwable err) {
+ dispatchException = new NestedServletException("Handler dispatch failed", err);
+ }
+ // 6\. ´¦Àí·µ»Ø½á¹û£¬ÔÚÕâ¸ö·½·¨Àï»áäÖȾÊÓͼ£¬ÒÔ¼°Ö´ÐÐ HandlerInterceptor#afterCompletion
+ processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
+ }
+ catch (...) {
+ // ÕâÀï»áÖ´ÐÐ HandlerInterceptor#afterCompletion
+ triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
+ }
+ finally {
+ if (asyncManager.isConcurrentHandlingStarted()) {
+ if (mappedHandler != null) {
+ // »Øµ÷À¹½ØÆ÷£¬Ö´Ðз½·¨ AsyncHandlerInterceptor#afterConcurrentHandlingStarted
+ mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
+ }
+ }
+ else {
+ if (multipartRequestParsed) {
+ cleanupMultipart(processedRequest);
+ }
+ }
+ }
+}
+
+```
+
+Õâ¸ö·½·¨Ôڵ㳤£¬²»¹ýÁ÷³ÌºÜÇåÎú£¬springmvc µÄÕû¸öÇëÇóÁ÷³Ì¶¼ÔÚÕâÀïÁË£¬ÕâÀï°Ñ¹Ø¼ü²½ÖèչʾÈçÏ£º
+
+1. »ñÈ¡¶ÔÓ¦µÄ `HandlerExecutionChain`, »ñÈ¡µÄ `HandlerExecutionChain` Öаüº¬ÕæÕýµØ´¦ÀíÆ÷£¨`Controller` Öеķ½·¨£©ºÍÒ»×é `HandlerInterceptor` À¹½ØÆ÷£»
+2. »ñÈ¡¶ÔÓ¦µÄ `handlerAdapter`£¬¸Ã¶ÔÏóÓÃÀ´ÔËÐÐ `handler(xxx)` ·½·¨£»
+3. Ö´ÐÐ spring µÄÀ¹½ØÆ÷£¬ÔËÐÐ `HandlerInterceptor#preHandle` ·½·¨£»
+4. ´¦ÀíÇëÇó£¬Ò²¾ÍÊÇͨ¹ýÉÏÃæ»ñÈ¡µ½µÄ `handlerAdapter` À´µ÷Óà `handle(xxx)` ·½·¨£»
+5. Ö´ÐÐ spring µÄÀ¹½ØÆ÷£¬ÔËÐÐ `HandlerInterceptor#postHandle` ·½·¨£»
+6. ´¦Àí·µ»Ø½á¹û£¬ÕâÀï»áäÖȾÊÓͼ£¬ÒÔ¼°Ö´ÐÐ spring À¹½ØÆ÷µÄ `HandlerInterceptor#afterCompletion`¡£
+
+×ܵÄÁ÷³ÌÊáÀíÇå³þÁË£¬½ÓÏÂÀ´¾ÍÊÇÖð¸öÁ÷³Ì·ÖÎöÁË¡£
+
+### 3\. »ñÈ¡ `HandlerExecutionChain`
+
+»ñÈ¡ `HandlerExecutionChain` µÄ·½·¨ÔÚ `DispatcherServlet#getHandler` ÖУº
+
+```
+protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
+ if (this.handlerMappings != null) {
+ // ±éÀúËùÓеÄhandlerMapping£¬
+ // ÕâÀïµÄ handlerMapping ÊÇÔÚWebMvcConfigurationSupportÖÐÒýÈëµÄ
+ for (HandlerMapping mapping : this.handlerMappings) {
+ // ÕâÀïµ÷ÓþßÌåµÄhandler£¬ÄĸöhandlerÄܹ»´¦Àí¾ÍÖ±½Ó·µ»Ø
+ HandlerExecutionChain handler = mapping.getHandler(request);
+ if (handler != null) {
+ return handler;
+ }
+ }
+ }
+ return null;
+}
+
+```
+
+ÕâÀïµÄ `handlerMappings` ÊÇÔÚ `WebMvcConfigurationSupport` ÖÐÒýÈëµÄ£¬¹ØÓÚÕâÒ»¿éµÄ·ÖÎö£¬¿ÉÄܲο¼ [springmvc demo Óë @EnableWebMvc ×¢½â](https://my.oschina.net/funcy/blog/4678093 "springmvc demo Óë @EnableWebMvc ×¢½â")Ò»ÎÄ£¬ÕâÀïÀ´¿´¿´Õâ¸ö `handlerMappings` ÓÐЩɶ£º
+
+
+
+¶ÔÓÚ `RequestMappingHandlerMapping` ÏàÐÅ´ó¼ÒÒѾºÜÊìϤ£¬¶ÔÓÚ `@Controller`/`@RequestMapping` ·½Ê½ÊµÏÖµÄ `controller`£¬¶ÔÓ¦µÄ `HandlerMapping` ¾ÍÊÇ `RequestMappingHandlerMapping`¡£ÖÁÓÚÁíÍâµÄÁ½¸ö `HandlerMapping`£¬Ôò·Ö±ð¶ÔÓ¦²»Í¬·½Ê½ÊµÏÖµÄ `controller`£¬¹ØÓÚÕâÒ»µã£¬¸ÐÐËȤµÄС»ï°é¿ÉÒÔ×ÔÐаٶȣ¬ÕâÀï¾Í²»Õ¹¿ªÁË¡£
+
+ÎÒÃǼÌÐø¿´ `AbstractHandlerMapping#getHandler` ·½·¨£º
+
+```
+public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
+ // 1\. µ÷ÓþßÌåµÄʵÏÖÈ¥»ñÈ¡handler
+ Object handler = getHandlerInternal(request);
+ // Èç¹ûΪ¿ÕʹÓÃĬÈϵÄ
+ if (handler == null) {
+ handler = getDefaultHandler();
+ }
+ // ûÓÐĬÈϵķµ»Ø¿Õ
+ if (handler == null) {
+ return null;
+ }
+ // ³¢ÊÔͨ¹ýBeanNameÈ¥»ñÈ¡handler
+ if (handler instanceof String) {
+ String handlerName = (String) handler;
+ handler = obtainApplicationContext().getBean(handlerName);
+ }
+ // 2\. »ñÈ¡ executionChain£¬Æäʵ¾ÍÊÇÕÒµ½ uri ¶ÔÓ¦µÄ Interceptors,
+ // È»ºóÓëÉÏÃæÕÒµ½µÄhandlerÒ»Æð·â×°µ½HandlerExecutionChain¶ÔÏóÖÐ
+ // ÕâÀïµÄInterceptors£¬Ò²ÊÇÔÚWebMvcConfigurationSupportÖÐÅäÖõÄ
+ HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
+ // 3\. ´¦Àí·ÓòÏà¹ØµÄÅäÖãºCorsHandlerExecutionChain
+ // ÕâÀï¿ÉÒÔ¿´µ½£¬ËùνµÄcors¿çÓòÅäÖã¬Ò²ÊÇÓÉÀ¹½ØÆ÷ʵÏÖµÄ
+ if (hasCorsConfigurationSource(handler)) {
+ CorsConfiguration config = (this.corsConfigurationSource != null
+ ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
+ CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
+ config = (config != null ? config.combine(handlerConfig) : handlerConfig);
+ // ½«¿çÓòÏà¹ØµÄÅäÖÃÌí¼Óµ½ Interceptors£¬¼Óµ½À¹½ØÆ÷ListµÄµÚÒ»¸öÖÐ
+ executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
+ }
+ return executionChain;
+}
+
+```
+
+Õâ¸ö·½·¨Ö÷Òª×öÁËÈý¼þÊ£º
+
+1. µ÷ÓþßÌåµÄʵÏÖÈ¥»ñÈ¡ handler£¬Õâ¸ö·½·¨ÊÇÖØµã£¬ÏÂÃæ»á¼ÌÐø½²£»
+2. »ñÈ¡ `executionChain`£¬Õâ¸ö `executionChain` ³ýÁ˰üº¬ÁËÉÏÒ»²½µÄ `handler` Í⣬»¹°üº¬ `uri` ¶ÔÓ¦µÄ `Interceptors`£¬»ñÈ¡·½·¨Îª»ñÈ¡ËùÓÐµÄ `Interceptors` ÅäÖã¨ÔÚ `WebMvcConfigurationSupport` ÖÐÅäÖõģ©£¬ÔÙÖðÒ»ÅÐ¶Ï uri ÊÇ·ñ·ûºÏ `Interceptor` µÄ uri ÅäÖã»
+3. »ñÈ¡ cors ¿çÓòÅäÖã¬È»ºóÌí¼Óµ½ `executionChain` ÖÐµÄ `Interceptors` ÁбíµÄµÚһλ¡£àÅ£¬Ã»´í£¬cors ¿çÓòÅäÖÃÒ²ÊÇÔÚ `WebMvcConfigurationSupport` ÖÐÅäÖõġ£
+
+#### 3.1 ²éÕÒ `HandlerMethod`
+
+ÎÒÃǽøÈë `getHandlerInternal(xxx)` ·½·¨£º
+
+> AbstractHandlerMethodMapping#getHandlerInternal
+
+```
+@Override
+protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
+ // »ñÈ¡ÇëÇóµÄurl
+ String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
+ request.setAttribute(LOOKUP_PATH, lookupPath);
+ this.mappingRegistry.acquireReadLock();
+ try {
+ // ÔÚÕâÀï²éÕÒuri¶ÔÓ¦µÄhandlerMethod
+ HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
+ // Èç¹ûhandlerMethod²»Îª¿Õ£¬ÔòÖØÐ´´½¨Ò»¸öHandlerMethod·µ»Ø
+ return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
+ }
+ finally {
+ this.mappingRegistry.releaseReadLock();
+ }
+}
+
+```
+
+ÕâÀﻹÊǵ÷Óà `lookupHandlerMethod(xxx)` À´²éÕÒ `handlerMethod`£¬¼ÌÐø
+
+> AbstractHandlerMethodMapping#lookupHandlerMethod
+
+```
+protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request)
+ throws Exception {
+ List matches = new ArrayList<>();
+ // ÏÈ´ÓurlLookupÖÐÕÒ£¬urlLookupÊÇÒ»¸ömap£¬keyÊÇurl£¬valueÊÇLinkedList
+ List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
+ if (directPathMatches != null) {
+ // ÓÉÓÚ·µ»ØµÄÊÇÒ»¸ö list£¬ÕâÀï»á°ÑËùÓÐµÄÆ¥ÅäµÄ½á¹û·ÅÈëÒ»¸ömatchesÖÐ
+ addMatchingMappings(directPathMatches, matches, request);
+ }
+ if (matches.isEmpty()) {
+ // Èç¹ûͨ¹ýurlûÕÒµ½£¬Ôò±éÀúËùÓÐµÄ mappings Æ¥Å䣬ƥÅäÀàËÆÓÚ /test/{name} µÄurl
+ // mappingsÒ²ÊÇÒ»¸ömap£¬keyÊÇRequestMappingInfo£¬ valueÊÇHandlerMethod
+ addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
+ }
+ // ÕÒµ½×î¼ÑÆ¥ÅäµÄmapping,·µ»ØÆä¶ÔÓ¦µÄHandlerMethod
+ // ±È½Ï¹æÔòÀ´×ÔÓÚ RequestMappingInfo#compareTo·½·¨
+ if (!matches.isEmpty()) {
+ Comparator comparator = new MatchComparator(getMappingComparator(request));
+ matches.sort(comparator);
+ Match bestMatch = matches.get(0);
+ if (matches.size() > 1) {
+ if (CorsUtils.isPreFlightRequest(request)) {
+ return PREFLIGHT_AMBIGUOUS_MATCH;
+ }
+ Match secondBestMatch = matches.get(1);
+ // ÕÒµ½ÁËÁ½¸ö×î¼ÑÆ¥Å䣬Å׳öÒì³£
+ if (comparator.compare(bestMatch, secondBestMatch) == 0) {
+ Method m1 = bestMatch.handlerMethod.getMethod();
+ Method m2 = secondBestMatch. .,m.bvc .getMethod();
+ String uri = request.getRequestURI();
+ throw new IllegalStateException(...);
+ }
+ }W
+ request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
+ handleMatch(bestMatch.mapping, lookupPath, request);
+ return bestMatch.handlerMethod;
+ }
+ else {
+ return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
+ }
+}
+
+```
+
+Õâ¸ö·½·¨¾ÍÊÇ´¦Àí handler µÄ»ñÈ¡ÁË¡£ÕâÀïµÄ»ñÈ¡·ÖΪ¼¸¸ö²½Ö裺
+
+1. ÏÈ´Ó `urlLookup` ÖÐÕÒ£¬`urlLookup` ÊÇÒ»¸ö `map`£¬`key` ÊÇ `url`£¬`value` ÊÇ `LinkedList`£¬Õâ¸ö²Ù×÷¾ÍÊÇ `map.get(xxx)` ·½·¨£»
+2. Èç¹ûͨ¹ý `url` ûÕÒµ½£¬Ôò±éÀúËùÓÐµÄ `mappings` Æ¥Å䣬ƥÅäÀàËÆÓÚ `/test/{name}` µÄ `url`£¬`mappings` Ò²ÊÇÒ»¸ö `map`£¬`key` ÊÇ `RequestMappingInfo`£¬ `value` ÊÇ `HandlerMethod`£»
+3. Èç¹ûÕÒµ½Á˶à¸ö `HandlerMethod`£¬Ôò¸ù¾Ý `RequestMappingInfo#compareTo` ·½·¨ÌṩµÄ·½·¨£¬ÕÒµ½×î¼ÑµÄ `RequestMappingInfo` ¶ÔÓ¦µÄ `HandlerMethod`¡£
+
+ÎÒÃÇÀ´¿´¿´ÔÚ `mappings` ÀïÊÇÈçºÎÕÒµ½Æ¥ÅäµÄ `RequestMappingInfo` µÄ£º
+
+> AbstractHandlerMethodMapping#addMatchingMappings
+
+```
+private void addMatchingMappings(Collection mappings, List matches,
+ HttpServletRequest request) {
+ for (T mapping : mappings) {
+ // Æ¥ÅäÆäËûÌõ¼þ£¬ÕÒµ½ÆäÖÐËùÓзûºÏÌõ¼þµÄ mappings
+ T match = getMatchingMapping(mapping, request);
+ if (match != null) {
+ matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
+ }
+ }
+}
+
+```
+
+×îÖÕ·¢ÏÖÆ¥ÅäµÄ´¦ÀíÊÇÔÚ `RequestMappingInfo#getMatchingCondition` ·½·¨ÖУ¬`RequestMappingInfo` »¹ÓÐÒ»¸ö `compareTo` ·½·¨£¬ÎÒÃÇÒ²Ò»²¢²é¿´Ï£º
+
+> RequestMappingInfo
+
+```
+/**
+ * Æ¥Å乿Ôò
+ * »á·Ö±ðÆ¥Åä ÇëÇó·½·¨(get,postµÈ)¡¢ÇëÇó²ÎÊý¡¢ÇëÇóÍ·µÈ
+ */
+public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
+ RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
+ if (methods == null) {
+ return null;
+ }
+ ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
+ if (params == null) {
+ return null;
+ }
+ HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
+ if (headers == null) {
+ return null;
+ }
+ ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
+ if (consumes == null) {
+ return null;
+ }
+ ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
+ if (produces == null) {
+ return null;
+ }
+ PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
+ if (patterns == null) {
+ return null;
+ }
+ RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
+ if (custom == null) {
+ return null;
+ }
+ return new RequestMappingInfo(this.name, patterns,
+ methods, params, headers, consumes, produces, custom.getCondition());
+}
+
+/**
+ * ±È½Ï¹æÔò£¬ÕÒµ½×î¼ÑÆ¥Åä
+ * »á·Ö±ð±È½Ï ÇëÇó·½·¨(get,postµÈ)¡¢ÇëÇó²ÎÊý¡¢ÇëÇóÍ·µÈ
+ */
+public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
+ int result;
+ if (HttpMethod.HEAD.matches(request.getMethod())) {
+ result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
+ if (result != 0) {
+ return result;
+ }
+ }
+ result = this.patternsCondition.compareTo(other.getPatternsCondition(), request);
+ if (result != 0) {
+ return result;
+ }
+ result = this.paramsCondition.compareTo(other.getParamsCondition(), request);
+ if (result != 0) {
+ return result;
+ }
+ result = this.headersCondition.compareTo(other.getHeadersCondition(), request);
+ if (result != 0) {
+ return result;
+ }
+ result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);
+ if (result != 0) {
+ return result;
+ }
+ result = this.producesCondition.compareTo(other.getProducesCondition(), request);
+ if (result != 0) {
+ return result;
+ }
+ result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
+ if (result != 0) {
+ return result;
+ }
+ result = this.customConditionHolder.compareTo(other.customConditionHolder, request);
+ if (result != 0) {
+ return result;
+ }
+ return 0;
+}
+
+```
+
+ÎÞÂÛÆ¥Å䣬»¹ÊDZȽϣ¬¶¼»á¶ÔÇëÇó·½·¨ (get,post µÈ)¡¢ÇëÇó²ÎÊý¡¢ÇëÇóÍ·µÈÒ»Ò»½øÐд¦Àí¡£
+
+µ½ÕâÀÎÒÃǾÍÃ÷°×ÁË springmvc ÊÇÈçºÎÕÒµ½ `HandlerMethod` µÄÁË¡£
+
+#### 3.2 ²éÕÒ `Interceptors`
+
+ÎÒÃǻص½ `AbstractHandlerMapping#getHandler`£¬¿´¿´ÊÇÈçºÎ»ñÈ¡ `Interceptor` µÄ£º
+
+```
+public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
+ ...
+ // 2\. »ñÈ¡ executionChain£¬Æäʵ¾ÍÊÇÕÒµ½ uri ¶ÔÓ¦µÄ Interceptors,
+ // È»ºóÓëÉÏÃæÕÒµ½µÄhandlerÒ»Æð·â×°µ½HandlerExecutionChain¶ÔÏóÖÐ
+ // ÕâÀïµÄInterceptors£¬Ò²ÊÇÔÚWebMvcConfigurationSupportÖÐÅäÖõÄ
+ HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
+ ...
+ return executionChain;
+}
+
+```
+
+½øÈë `getHandlerExecutionChain` ·½·¨£º
+
+> AbstractHandlerMapping#getHandlerExecutionChain
+
+```
+protected HandlerExecutionChain getHandlerExecutionChain(Object handler,
+ HttpServletRequest request) {
+ HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
+ (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
+ // »ñÈ¡µ±Ç°µÄÇëÇó·¾¶
+ String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
+ for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
+ if (interceptor instanceof MappedInterceptor) {
+ MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
+ // Åжϵ±Ç°ÇëÇó·¾¶ÊÇ·ñÂú×ãinterceptorÀïÅäÖõÄ·¾¶
+ if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
+ chain.addInterceptor(mappedInterceptor.getInterceptor());
+ }
+ }
+ else {
+ chain.addInterceptor(interceptor);
+ }
+ }
+ return chain;
+}
+
+```
+
+Õâ¸ö·½·¨±È½Ï¼òµ¥£¬Ïà¹ØÄÚÈÝÒѾÔÚ´úÂëÖÐ×öÁË×¢ÊÍ£¬¾Í²»¶à˵ÁË ¡£
+
+#### 3.3 ´¦Àí cors ¿çÓòÅäÖÃ
+
+ÎÒÃÇÔÙÀ´¿´¿´¿çÓòÅäÖõĴ¦Àí£º
+
+```
+public final HandlerExecutionChain getHandler(HttpServletRequest request)
+ throws Exception {
+ ...
+ // 3\. ´¦Àí·ÓòÏà¹ØµÄÅäÖãºCorsHandlerExecutionChain
+ // ÕâÀï¿ÉÒÔ¿´µ½£¬ËùνµÄcors¿çÓòÅäÖã¬Ò²ÊÇÓÉÀ¹½ØÆ÷ʵÏÖµÄ
+ if (hasCorsConfigurationSource(handler)) {
+ // »ñÈ¡¿çÓòÅäÖÃ
+ CorsConfiguration config = (this.corsConfigurationSource != null
+ ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
+ CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
+ config = (config != null ? config.combine(handlerConfig) : handlerConfig);
+ // ½«¿çÓòÏà¹ØµÄÅäÖÃÌí¼Óµ½ Interceptors£¬¼Óµ½À¹½ØÆ÷ListµÄµÚÒ»¸öÖÐ
+ executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
+ }
+ return executionChain;
+}
+
+```
+
+¿çÓòÏà¹ØÅäÖÃÒ²¿ÉÒÔ `WebMvcConfigurationSupport` ÖÐÅäÖãº
+
+```
+protected void addCorsMappings(CorsRegistry registry) {
+ ...
+}
+
+```
+
+springmvc »ñÈ¡µ½¿çÓòÅäÖú󣬻á°ÑÏà¹ØÅäÖÃÌí¼Óµ½ `HandlerExecutionChain` ÖУº
+
+```
+# AbstractHandlerMapping#getCorsHandlerExecutionChain
+protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
+ HandlerExecutionChain chain, @Nullable CorsConfiguration config) {
+ if (CorsUtils.isPreFlightRequest(request)) {
+ HandlerInterceptor[] interceptors = chain.getInterceptors();
+ chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
+ }
+ else {
+ // Ìí¼Óµ½InterceptorsµÄÊ×λ
+ chain.addInterceptor(0, new CorsInterceptor(config));
+ }
+ return chain;
+}
+
+# HandlerExecutionChain#addInterceptor(int, HandlerInterceptor)
+public void addInterceptor(int index, HandlerInterceptor interceptor) {
+ // Æäʵ¾ÍÊDzÙ×÷Ò»¸ölist
+ initInterceptorList().add(index, interceptor);
+}
+
+```
+
+ÔÚ `HandlerExecutionChain` ÖУ¬ÓÐÒ»¸ö `List` ÓÃÀ´´æÈë `Interceptor`£¬»ñÈ¡µ½µÄ¿çÓòÅäÖ㬻áÌí¼Óµ½Õâ¸ö `List` µÄ `index=0` µÄλÖá£
+
+µ½ÕâÀ`handler` ¾Í»ñÈ¡Íê³ÉÁË£¬Õâ¸ö `handler` °üº¬Á½²¿·Ö£º
+
+* `HandlerMethod`: ´¦ÀíÇëÇóµÄ·½·¨£¬ÓÉÓÚ±¾ÎÄÖ»·ÖÎö `@Controller` ·½Ê½µÄ controller£¬¿ÉÒÔ¼òµ¥Àí½âΪÓÐ `@RequestMapping` ×¢½âµÄ·½·¨£»
+* `List`: À¹½ØÆ÷Á´£¬Èç¹ûÓпçÓòÅäÖã¬ÄÇô¿çÓòÅäÖûá·ÅÔÚÕâ¸ö List µÄµÚһλ¡£
+
+### 4\. »ñÈ¡ `HandlerAdapter`
+
+Ôٻص½ `DispatcherServlet#doDispatch` ·½·¨£¬ÎÒÃÇÀ´¿´¿´»ñÈ¡ `HandlerAdapter` µÄ·½·¨£º
+
+```
+protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
+ ...
+ // 2\. »ñÈ¡¶ÔÓ¦µÄhandlerAdapter£¬ÓÃÀ´ÔËÐÐ handler(xxx)
+ HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
+ ...
+
+```
+
+½øÈë `getHandlerAdapter(xxx)` ·½·¨£º
+
+> DispatcherServlet#getHandlerAdapter
+
+```
+protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
+ // handlerAdapters ÀïµÄbean£¬Ò²ÊÇÓÉWebMvcConfigurationSupportÒýÈëµÄ
+ if (this.handlerAdapters != null) {
+ for (HandlerAdapter adapter : this.handlerAdapters) {
+ // ²»Í¬µÄhandlerAdapterµÄÅжϷ½·¨²»Í¬
+ if (adapter.supports(handler)) {
+ return adapter;
+ }
+ }
+ }
+ throw new ServletException(...);
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬ÕâÀï»áÕÒµ½µ±Ç°ËùÓÐµÄ `adapter`£¬È»ºó±éÀú£¬Öð¸öÅжÏÊÇ·ñÄÜ´¦Àíµ±Ç°µÄ `handler`£¬ËùÓÐµÄ `adapter` ÈçÏ£º
+
+
+
+ÔÙÀ´¿´¿´ÈçºÎÅжÏÊÇ·ñÄÜ´¦Àíµ±Ç°µÄ `handler` µÄ£¬ÎÒÃÇ¿´ÆäÖÐÒ»¸ö `handler`£¬½øÈë `AbstractHandlerMethodAdapter#supports` ·½·¨£º
+
+> AbstractHandlerMethodAdapter#supports
+
+```
+@Override
+public final boolean supports(Object handler) {
+ // ÅжÏhandlerÊÇ·ñΪHandlerMethodµÄʵÀý
+ return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
+}
+
+```
+
+ÕâÀï½ö×öÁËÒ»¸ö¼òµ¥µÄÅжϣ¬È»ºóÔÙµ÷Óà `supportsInternal` ·½·¨£¬¼ÌÐø£º
+
+> RequestMappingHandlerAdapter#supportsInternal
+
+```
+protected boolean supportsInternal(HandlerMethod handlerMethod) {
+ return true;
+}
+
+```
+
+Õâ¸ö·½·¨Ö±½Ó·µ»Ø true, ÓÉÓڿɼû£¬Èç¹û `handler` µÄʵÀýÊÇ `HandlerMethod`£¬ÄÇô¾Í»á·µ»Ø `RequestMappingHandlerAdapter`.
+
+ÕâÒ»²½ÕÒµ½µÄ `adapter` Ϊ `RequestMappingHandlerAdapter`£¬Õâ¸ö `adapter` ÓÐʲôÓÃÄØ£¿ÏÞÓÚÆª·ù£¬±¾ÎľÍÏȵ½ÕâÀïÁË£¬Ê£ÏµÄÁ÷³ÌÏÂÆªÎÄÕ¼ÌÐø·ÖÎö¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4717420](https://my.oschina.net/funcy/blog/4717420) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/\350\257\267\346\261\202\346\211\247\350\241\214\346\265\201\347\250\213\357\274\210\344\272\214\357\274\211\344\271\213\346\211\247\350\241\214 Handler \346\226\271\346\263\225.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/\350\257\267\346\261\202\346\211\247\350\241\214\346\265\201\347\250\213\357\274\210\344\272\214\357\274\211\344\271\213\346\211\247\350\241\214 Handler \346\226\271\346\263\225.md"
new file mode 100644
index 0000000..daed837
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringMVC\346\272\220\347\240\201\345\210\206\346\236\220/\350\257\267\346\261\202\346\211\247\350\241\214\346\265\201\347\250\213\357\274\210\344\272\214\357\274\211\344\271\213\346\211\247\350\241\214 Handler \346\226\271\346\263\225.md"
@@ -0,0 +1,668 @@
+±¾ÎÄÊÇ **springmvc ÇëÇóÖ´ÐÐÁ÷³Ì**µÄµÚ¶þƪÎÄÕ£¬ÔÚÉÏһƪÎÄÕÂÖУ¬ÎÒÃÇ·ÖÎöÁË `DispatcherServlet#doDispatch` ·½·¨£¬×ܽá³öÇëÇóÖ´ÐзÖΪÈçϲ½Ö裺
+
+1. »ñÈ¡¶ÔÓ¦µÄ `HandlerExecutionChain`, »ñÈ¡µÄ `HandlerExecutionChain` Öаüº¬ÕæÕýµØ´¦ÀíÆ÷£¨`Controller` Öеķ½·¨£©ºÍÒ»×é `HandlerInterceptor` À¹½ØÆ÷£»
+2. »ñÈ¡¶ÔÓ¦µÄ `handlerAdapter`£¬¸Ã¶ÔÏóÓÃÀ´ÔËÐÐ `handler(xxx)` ·½·¨£»
+3. Ö´ÐÐ spring µÄÀ¹½ØÆ÷£¬ÔËÐÐ `HandlerInterceptor#preHandle` ·½·¨£»
+4. ´¦ÀíÇëÇó£¬Ò²¾ÍÊÇͨ¹ýÉÏÃæ»ñÈ¡µ½µÄ `handlerAdapter` À´µ÷Óà `handle(xxx)` ·½·¨£»
+5. Ö´ÐÐ spring µÄÀ¹½ØÆ÷£¬ÔËÐÐ `HandlerInterceptor#postHandle` ·½·¨£»
+6. ´¦Àí·µ»Ø½á¹û£¬ÕâÀï»áäÖȾÊÓͼ£¬ÒÔ¼°Ö´ÐÐ spring À¹½ØÆ÷µÄ `HandlerInterceptor#afterCompletion`¡£
+
+½Ó×Å£¬ÎÒÃǼÌÐø·ÖÎö `HandlerExecutionChain` µÄ»ñÈ¡ÒÔ¼° `handlerAdapter` µÄ»ñÈ¡£¬Êé½ÓÉϻأ¬±¾ÎĽ«¼ÌÐø·ÖÎö½ÓÏÂÀ´µÄ²½Öè¡£
+
+### 5\. Ö´ÐÐ spring µÄÀ¹½ØÆ÷£º`HandlerInterceptor#preHandle`
+
+```
+protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
+ ...
+ // 3\. ÔËÐÐspringµÄÀ¹½ØÆ÷, ÔËÐÐ HandlerInterceptor#preHandle ·½·¨
+ // Õâ¸ömappedHandler£¬¾ÍÊǵÚ1²½»ñÈ¡µÄHandlerExecutionChain
+ if (!mappedHandler.applyPreHandle(processedRequest, response)) {
+ return;
+ }
+ ...
+}
+
+```
+
+ÉÏÃæµÄ `mappedHandler`£¬¾ÍÊÇµÚ 1 ²½»ñÈ¡µÄ `HandlerExecutionChain`£¬½øÈë `HandlerExecutionChain#applyPreHandle`£º
+
+> HandlerExecutionChain#applyPreHandle
+
+```
+/**
+ * Ö´ÐÐ HandlerInterceptor#preHandle ·½·¨
+ */
+boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
+ // »ñÈ¡ËùÓеÄÀ¹½ØÆ÷
+ HandlerInterceptor[] interceptors = getInterceptors();
+ if (!ObjectUtils.isEmpty(interceptors)) {
+ // ±éÀúÖ´ÐÐ preHandle ·½·¨
+ for (int i = 0; i < interceptors.length; i++) {
+ HandlerInterceptor interceptor = interceptors[i];
+ if (!interceptor.preHandle(request, response, this.handler)) {
+ // ʧ°ÜÁË£¬»¹»á¼ÌÐøÖ´ÐÐ HandlerInterceptor#afterCompletion ·½·¨
+ triggerAfterCompletion(request, response, null);
+ return false;
+ }
+ this.interceptorIndex = i;
+ }
+ }
+ return true;
+}
+
+/**
+ * Ö´ÐÐ HandlerInterceptor#afterCompletion ·½·¨
+ * ΪÁ˱£Ö¤HandlerInterceptor#afterCompletionµÄÖ´ÐУ¬
+ * ½ÓÏÂÀ´µÄ·ÖÎö»á¿´µ½£¬Õâ¸ö·½·¨»áÔÚ¶à¸ö·½·¨µ÷Óõ½
+ */
+void triggerAfterCompletion(HttpServletRequest request,
+ HttpServletResponse response, @Nullable Exception ex) throws Exception {
+ HandlerInterceptor[] interceptors = getInterceptors();
+ if (!ObjectUtils.isEmpty(interceptors)) {
+ // ±éÀúÖ´ÐÐ HandlerInterceptor#afterCompletion ·½·¨
+ for (int i = this.interceptorIndex; i >= 0; i--) {
+ HandlerInterceptor interceptor = interceptors[i];
+ try {
+ interceptor.afterCompletion(request, response, this.handler, ex);
+ }
+ catch (Throwable ex2) {
+ logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
+ }
+ }
+ }
+}
+
+```
+
+ÎÒÃÇÀ´¿´Ò»ÑÛ `HandlerExecutionChain`£º
+
+
+
+ÔÙÀ´¿´¿´´«Èë `HandlerInterceptor` µÄ `handler` ÊÇɶ£º
+
+
+
+Õâ¸ö `handler` ¾ÍÊÇ `HandlerMethod`£¬ÀïÃæ°üº¬µÄÐÅÏ¢»¹ÊÇͦ·á¸»µÄ£¬Ïñ `bean`/`beanFactory`/`method`£¬ÀûÓÃÕ⼸¸öÊôÐÔ£¬ÎÒÃÇ¿ÉÒÔ¶ÔÆä½øÐи÷ÖÖ²Ù×÷¡£
+
+### 6\. ·½·¨µÄÖ´ÐУº`AbstractHandlerMethodAdapter#handle`
+
+ÎÒÃÇÔٻص½ `DispatcherServlet#doDispatch`£¬Ö´ÐÐÍê `HandlerInterceptor#preHandle` ·½·¨ºó£¬¾ÍÀ´µ½ËùÓÐÁ÷³ÌÖеÄÖØÍ·Ï·£º`handler` µÄÖ´ÐУ¬Ò²¾ÍÊÇ `controller` ÖУ¬`url` ¶ÔÓ¦µÄ·½·¨Ö´ÐУº
+
+```
+protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
+ ...
+ // 4\. ͨ¹ýÉÏÃæ»ñÈ¡µ½µÄhandlerAdapterÀ´µ÷ÓÃhandle
+ mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
+ ...
+}
+
+```
+
+һ·¸ú½øÈ¥£¬×îÖÕÀ´µ½ÁË `RequestMappingHandlerAdapter#invokeHandlerMethod` ·½·¨£º
+
+```
+protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
+ HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
+ // °ü×°requesÓërequest¶ÔÏó
+ ServletWebRequest webRequest = new ServletWebRequest(request, response);
+ try {
+ // »ñÈ¡ @InitBinder ×¢½âµÄ·½·¨£¬
+ // °üº¬µ±Ç°controllerÓë @ControllerAdvice ±ê×¢µÄÀàÀïµÄ @InitBinder ×¢½âµÄ·½·¨
+ WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
+ // »ñÈ¡ @ModelAttribute ×¢½âµÄ·½·¨£¬
+ // °üº¬µ±Ç°controllerÓë @ControllerAdvice ±ê×¢µÄÀàÀïµÄ @ModelAttribute ×¢½âµÄ·½·¨
+ ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
+ // ´´½¨·½·¨Ö´ÐжÔÏó
+ ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
+ if (this.argumentResolvers != null) {
+ invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
+ }
+ if (this.returnValueHandlers != null) {
+ invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
+ }
+ invocableMethod.setDataBinderFactory(binderFactory);
+ invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
+ // ´´½¨ModelAndViewµÄÈÝÆ÷
+ ModelAndViewContainer mavContainer = new ModelAndViewContainer();
+ mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
+ modelFactory.initModel(webRequest, mavContainer, invocableMethod);
+ mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
+ // ´¦ÀíÒì²½ÇëÇó
+ AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
+ asyncWebRequest.setTimeout(this.asyncRequestTimeout);
+ WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
+ asyncManager.setTaskExecutor(this.taskExecutor);
+ asyncManager.setAsyncWebRequest(asyncWebRequest);
+ asyncManager.registerCallableInterceptors(this.callableInterceptors);
+ asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
+ if (asyncManager.hasConcurrentResult()) {
+ Object result = asyncManager.getConcurrentResult();
+ mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
+ asyncManager.clearConcurrentResult();
+ LogFormatUtils.traceDebug(logger, traceOn -> {
+ String formatted = LogFormatUtils.formatValue(result, !traceOn);
+ return "Resume with async result [" + formatted + "]";
+ });
+ invocableMethod = invocableMethod.wrapConcurrentResult(result);
+ }
+ // Ö´ÐÐControllerµÄ·½·¨£¨Öص㣩
+ invocableMethod.invokeAndHandle(webRequest, mavContainer);
+ if (asyncManager.isConcurrentHandlingStarted()) {
+ return null;
+ }
+ // ´¦Àí·µ»Ø½á¹û
+ return getModelAndView(mavContainer, modelFactory, webRequest);
+ }
+ finally {
+ webRequest.requestCompleted();
+ }
+}
+
+```
+
+Õâ¸ö·½·¨Óе㳤£¬µ«Öص㷽·¨Ö»ÓÐÒ»ÐУº`invocableMethod.invokeAndHandle(webRequest, mavContainer);`£¬ÔÚÕâ¸ö·½·¨Ç°µÄ²¿·Ö¶¼ÊÇÔÚ×ö·½·¨Ö´ÐÐǰµÄ×¼±¸¹¤×÷£¬Èç»ñÈ¡ `@InitBinder` ×¢½âµÄ·½·¨¡¢»ñÈ¡ `@ModelAttribute` ×¢½âµÄ·½·¨£¬×¼±¸·½·¨²ÎÊý `webRequest`(°ü×° `request` Óë `response` ¶ÔÏó) Óë `mavContainer`(`ModelAndView` °ü×°¶ÔÏó) µÈ¡£ÕâÀïÎÒÃÇÖ±½Ó½øÈë `invocableMethod.invokeAndHandle`£¬¿´¿´·½·¨ÊÇÈçºÎÖ´Ðеģº
+
+> ServletInvocableHandlerMethod#invokeAndHandle
+
+```
+public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
+ Object... providedArgs) throws Exception {
+ // Ö´ÐÐhandler·½·¨
+ Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
+ // ÉèÖà RequestHandled ÊôÐÔÖµ£¬springmvc»á¸ù¾Ý¸ÃÖµÅжÏÒª²»ÒªÌø×ª
+ if (returnValue == null) {
+ if (isRequestNotModified(webRequest) || getResponseStatus() != null
+ || mavContainer.isRequestHandled()) {
+ disableContentCachingIfNecessary(webRequest);
+ mavContainer.setRequestHandled(true);
+ return;
+ }
+ }
+ else if (StringUtils.hasText(getResponseStatusReason())) {
+ mavContainer.setRequestHandled(true);
+ return;
+ }
+ mavContainer.setRequestHandled(false);
+ Assert.state(this.returnValueHandlers != null, "No return value handlers");
+ try {
+ // ´¦Àí·µ»Ø½á¹û
+ this.returnValueHandlers.handleReturnValue(
+ returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
+ }
+ catch (Exception ex) {
+ throw ex;
+ }
+}
+
+```
+
+ÕâÀï·½·¨ÏÈÊǵ÷ÓÃÁË `invokeForRequest` Ö´Ðз½·¨£¬È»ºóÔÙ¸ù¾Ý·½·¨µÄ·µ»ØÖµÀ´ÉèÖà `mavContainer` µÄ `RequestHandled` Öµ£¬×îºó´¦Àí·µ»Ø½á¹û¡£¼ÌÐø¸ú½ø `invokeForRequest` ·½·¨£º
+
+> InvocableHandlerMethod#invokeForRequest
+
+```
+@Nullable
+public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainermavContainer,
+ Object... providedArgs) throws Exception {
+ // ´¦Àí²ÎÊý°ó¶¨
+ Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
+ // ·´Éäµ÷Ó÷½·¨
+ return doInvoke(args);
+}
+
+```
+
+Õâ¸ö·½·¨ÀïÏÈÊÇ´¦ÀíÁ˲ÎÊý½âÎö£¬È»ºóʹÓ÷´Éä½øÐз½·¨µ÷Óá£ÊÂʵÉÏ£¬Õû¸öÖ´ÐÐÁ÷³ÌÖУ¬×îºËÐĵľÍÊDzÎÊý½âÎöÁË£¬ÔÚ controller ÀïµÄ handler ·½·¨ÖУ¬ÎÒÃÇ¿ÉÒÔÕâÑùÖ¸¶¨²ÎÊý£º
+
+```
+// Ö±½Ó´«²Î
+@RequestMapping("xxx")
+public Object test(String name) {
+ ...
+}
+
+// ÔÚ²ÎÊýÉϱêÓÐ@RequestParam¡¢@RequestHeaderµÈ×¢½â
+@RequestMapping("xxx")
+public Object test(@RequestParam("name") String name,
+ @RequestHeader("uid") String uid) {
+ ...
+}
+
+// ½«´«ÈëµÄ²ÎÊý·âװΪ¶ÔÏó
+@RequestMapping("xxx")
+public Object test(User user) {
+ ...
+}
+
+// ÉÏÃæµÄ·½·¨¶¼ÊÇʹÓÃform±íµ¥´«²Î(Ò²¾ÍÊÇk1=v1&2=v2&...µÄ·½·¨)
+// Õâ¸ö·½·¨Ê¹Óà RequestBody ·½Ê½´«²Î£¬½«²ÎÊýÄÚÈÝ·ÅÈëÏûÏ¢ÌåÖÐ
+@RequestMapping("xxx")
+public Object test(@RequestBody User user) {
+ ...
+}
+
+...
+
+```
+
+µ±ÎÒÃǰ´¹æ·¶´«Èë²ÎÊýʱ£¬springmvc ¶¼ÄÜÕý³£´¦Àí£¬ÎÒÃÇÀ´¿´¿´ springmvc ÊÇÈçºÎ×öµ½ÕâÒ»µãµÄ¡£
+
+#### ²ÎÊý½âÎö
+
+¼ÌÐø£¬½øÈë `InvocableHandlerMethod#getMethodArgumentValues` ·½·¨£º
+
+> InvocableHandlerMethod#getMethodArgumentValues
+
+```
+protected Object[] getMethodArgumentValues(NativeWebRequest request,
+ @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
+ // »ñÈ¡·½·¨µÄËùÓвÎÊý£¬¿ÉÒÔ¼òµ¥Àí½âΪÀûÓ÷´Éä»ñÈ¡handler·½·¨²ÎÊý£¬È»ºó°üװΪ MethodParameter
+ MethodParameter[] parameters = getMethodParameters();
+ if (ObjectUtils.isEmpty(parameters)) {
+ return EMPTY_ARGS;
+ }
+ Object[] args = new Object[parameters.length];
+ // ÒÀ´Î´¦Àíÿ¸ö²ÎÊý
+ for (int i = 0; i < parameters.length; i++) {
+ MethodParameter parameter = parameters[i];
+ parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
+ args[i] = findProvidedArgument(parameter, providedArgs);
+ if (args[i] != null) {
+ continue;
+ }
+ // ÅжÏÊÇ·ñÓвÎÊý½âÎöÀàÖ§³Öµ±Ç°²ÎÊýµÄ½âÎö
+ if (!this.resolvers.supportsParameter(parameter)) {
+ throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
+ }
+ try {
+ // ´¦Àí²ÎÊý½âÎö
+ args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request,
+ this.dataBinderFactory);
+ }
+ catch (Exception ex) {
+ throw ex;
+ }
+ }
+ return args;
+}
+
+```
+
+Õâ¸ö·½·¨ÏÈ»ñÈ¡ÁË handler ·½·¨µÄ²ÎÊý (¿ÉÒÔ¼òµ¥Àí½âΪÀûÓ÷´Éä»ñÈ¡ handler ·½·¨²ÎÊý£¬È»ºó°üװΪ `MethodParameter`)£¬È»ºó¶ÔÕâЩ²ÎÊýÖð¸ö½âÎö¡£½âÎöʱ£¬»áÓõ½Á½¸öÖØÒªµÄ·½·¨£º`resolvers.supportsParameter(...)` Óë `resolvers.resolveArgument(...)`£¬ÕâÁ½¸ö·½·¨×îÖÕµ÷Óõķ½·¨ÔÚ `HandlerMethodArgumentResolverComposite` ÖУº
+
+> HandlerMethodArgumentResolverComposite
+
+```
+@Nullable
+public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainermavContainer,
+ NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
+ // »ñȡһ¸ö½âÎöÆ÷
+ HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
+ if (resolver == null) {
+ throw new IllegalArgumentException(...);
+ }
+ // ½âÎö²ÎÊý£¬µ÷Óà HandlerMethodArgumentResolver#resolveArgument ·½·¨
+ return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
+}
+
+private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
+ HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
+ if (result == null) {
+ // ±éÀúËùÓеĽâÎöÆ÷
+ for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
+ // ÕÒµ½ÆäÖÐÒ»¸ö½âÎöÆ÷£¬·µ»Ø
+ // µ÷ÓÃ HandlerMethodArgumentResolver#supportsParameter ·½·¨
+ if (resolver.supportsParameter(parameter)) {
+ result = resolver;
+ this.argumentResolverCache.put(parameter, result);
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+```
+
+ÕâÁ½¸ö·½·¨Ö÷ÒªÊDZéÀú½âÎöÆ÷£¬È»ºóµ÷Óà `HandlerMethodArgumentResolver#supportsParameter` Óë `HandlerMethodArgumentResolver#resolveArgument` ´¦Àí¾ßÌåµÄ²Ù×÷¡£`HandlerMethodArgumentResolver` ÊǸö½Ó¿Ú£¬ÀïÃæ½öÓÐÁ½¸ö·½·¨£º
+
+```
+public interface HandlerMethodArgumentResolver {
+ /**
+ * µ±Ç°ÊÇ·ñÖ§³Ö´¦Àíµ±Ç°²ÎÊý
+ */
+ boolean supportsParameter(MethodParameter parameter);
+
+ /**
+ * ¾ßÌåµÄ½âÎö²Ù×÷
+ */
+ @Nullable
+ Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
+ NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
+}
+
+```
+
+Õâ¸ö¾ÍÊÇÕæÕýµÄ²ÎÊý½âÎöÆ÷ÁË¡£ÔÚ springmvc ÖУ¬ÌṩÁ˶àÉÙÖÖ²ÎÊý½âÎöÆ÷ÄØ£¿¾¹ý±¾È˵ĵ÷ÊÔ£¬·¢ÏÖ¶à´ï 26 ¸ö£º
+
+ 
+
+ÕýÊÇÔÚÕâЩ²ÎÊý½âÎöÆ÷µÄ°ïÖúÏ£¬springmvc ÄÜÖ§³Ö¶àÖÖ²ÎÊý½ÓÊÕ·½Ê½£¡¶ÔÓÚ²ÎÊý½âÎöÆ÷£¬ÓÉÓÚÉè¼Æ±È½Ï¸´ÔÓ£¬Éæ¼°¶àÖÖ´«²Î·½Ê½£¬±¾ÎIJ¢²»ÏëÕ¹¿ªÌÖÂÛ£¬¸ÐÐËȤµÄС»ï°é¿É×ÔÐвéÔÄÏà¹ØÎĵµ¡£
+
+#### Ö´ÐÐ handler ·½·¨
+
+´¦ÀíÍê²ÎÊý½âÎöºó£¬¾Í¿ªÊ¼Ö´ÐÐ handler ·½·¨ÁË¡£ÈÃÎÒÃǻص½ `InvocableHandlerMethod#invokeForRequest` ·½·¨£º
+
+> InvocableHandlerMethod#invokeForRequest
+
+```
+@Nullable
+public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainermavContainer,
+ Object... providedArgs) throws Exception {
+ // ´¦Àí²ÎÊý°ó¶¨
+ Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
+ // ·´Éäµ÷Ó÷½·¨
+ return doInvoke(args);
+}
+
+```
+
+½øÈë `doInvoke` ·½·¨£º
+
+```
+@Nullable
+protected Object doInvoke(Object... args) throws Exception {
+ // ʹÓ÷´ÉäÖ´Ðз½·¨
+ ReflectionUtils.makeAccessible(getBridgedMethod());
+ try {
+ // ÕâÀï¾ÍÊÇ·´Éä²Ù×÷
+ return getBridgedMethod().invoke(getBean(), args);
+ }
+ catch (...) {
+ ...
+ }
+}
+
+```
+
+Õâ¸ö·½·¨ºÜ¼òµ¥£¬¾ÍÊÇÀûÓ÷´ÉäÀ´½øÐз½·¨Ö´Ðеģ¬¾Í²»¹ý¶à·ÖÎöÁË¡£
+
+#### ´¦Àí·µ»Ø²ÎÊý
+
+ÈÃÎÒÃǻص½ `ServletInvocableHandlerMethod#invokeAndHandle` ·½·¨£º
+
+> ServletInvocableHandlerMethod#invokeAndHandle
+
+```
+public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
+ Object... providedArgs) throws Exception {
+ // Ö´ÐÐhandle·½·¨
+ Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
+ ...
+ try {
+ // ´¦Àí·µ»Ø½á¹û
+ this.returnValueHandlers.handleReturnValue(
+ returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
+ }
+ catch (Exception ex) {
+ throw ex;
+ }
+}
+
+```
+
+´¦ÀíÍê·½·¨Ö´Ðк󣬽Óמʹ¦Àí·µ»Ø½á¹û£º
+
+> HandlerMethodReturnValueHandlerComposite#handleReturnValue
+
+```
+@Override
+public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
+ ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
+ // ¸ù¾Ý·µ»ØÀàÐÍÕÒÒ»¸öºÏÊʵÄhandlerÀ´´¦Àí·µ»ØÊý¾Ý
+ HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
+ if (handler == null) {
+ throw new IllegalArgumentException(...);
+ }
+ handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
+}
+
+@Nullable
+private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameterreturnType) {
+ boolean isAsyncValue = isAsyncReturnValue(value, returnType);
+ // ±éÀú£¬Öð¸öÅжÏÊÇ·ñÄÜ´¦Àíµ±Ç°·µ»ØÀàÐÍ
+ for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
+ if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
+ continue;
+ }
+ if (handler.supportsReturnType(returnType)) {
+ return handler;
+ }
+ }
+ return null;
+}
+
+```
+
+»ñÈ¡ `ReturnValueHandler` µÄÌ×·ÓëÇ°Ãæ»ñÈ¡ `ArgumentResolver` µÄÌ×·Ïà¹ØÎÞ¼¸£¬`ReturnValueHandler` ÊÇ `HandlerMethodReturnValueHandler` µÄ×ÓÀ࣬`HandlerMethodReturnValueHandler` ´úÂëÈçÏ£º
+
+```
+public interface HandlerMethodReturnValueHandler {
+
+ /**
+ * Åжϵ±Ç°ReturnValueHandlerÄÜ·ñ´¦Àí´«ÈëµÄreturnType
+ */
+ boolean supportsReturnType(MethodParameter returnType);
+
+ /**
+ * ¾ßÌåµÄ´¦ÀíÂß¼
+ */
+ void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
+ ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
+
+}
+
+```
+
+Í¬Ç°Ãæ²ÎÊý½âÎöÆ÷Ò»Ñù£¬Õâ¸ö½Ó¿ÚÀïÒ²ÓÐÁ½¸ö·½·¨£º
+
+* `boolean supportsReturnType(xxx)`£ºÅжϵ±Ç° `ReturnValueHandler` ÄÜ·ñ´¦Àí´«ÈëµÄ `returnType`
+* `void handleReturnValue(xxx)`£º¾ßÌåµÄ´¦ÀíÂß¼
+
+ͬÑùµØ£¬springmvc Ò²ÌṩÁ˷dz£¶àµÄʵÏÖÀ´´¦Àí·µ»Ø²ÎÊý£º
+
+
+
+¶ÔÓÚ²ÎÊýµÄ·µ»Ø£¬ÎÒÃÇÀ´¿´Ò»¸ö¼òµ¥µÄʾÀý£º
+
+Èç¹ûÎÒÃÇÏñÕâÑù·µ»ØÖµÊ±£º
+
+```
+@Controller
+@RequestMapping("/xxx")
+public class XxxController {
+
+ @RequestMapping("/index")
+ public String index() {
+ return "index";
+ }
+}
+
+```
+
+·µ»Øµ½Ò³ÃæµÄ½«ÊÇÒ»¸öÊÓͼ£¬¶ÔÓ¦µÄ `HandlerMethodReturnValueHandler` Ϊ `ViewNameMethodReturnValueHandler`£º
+
+```
+public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
+
+ @Nullable
+ private String[] redirectPatterns;
+
+ // Ê¡ÂÔ redirectPatterns µÄsetterÓëgetter·½·¨
+ ...
+
+ @Override
+ public boolean supportsReturnType(MethodParameter returnType) {
+ Class> paramType = returnType.getParameterType();
+ // Ö§³Ö´¦ÀíµÄ·µ»ØÖµÀàÐÍ£º·µ»ØÖµÀàÐÍΪvoid£¬»òÕßΪ×Ö·û´®ÀàÐÍ
+ return (void.class == paramType || CharSequence.class.isAssignableFrom(paramType));
+ }
+
+ /**
+ * ¾ßÌåµÄ´¦ÀíÂß¼
+ */
+ @Override
+ public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
+ ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
+
+ if (returnValue instanceof CharSequence) {
+ // viewName ¾ÍÊÇ·µ»ØÖµ
+ String viewName = returnValue.toString();
+ mavContainer.setViewName(viewName);
+ if (isRedirectViewName(viewName)) {
+ // ÊÇ·ñÐèÒªÌø×ª
+ mavContainer.setRedirectModelScenario(true);
+ }
+ }
+ else if (returnValue != null) {
+ throw new UnsupportedOperationException(...);
+ }
+ }
+
+ /**
+ * ÅжÏÊÇ·ñÐèÒªÌø×ª
+ */
+ protected boolean isRedirectViewName(String viewName) {
+ // this.redirectPatterns ĬÈÏΪnull£¬¿ÉÒÔ×ÔÐе÷Óà setter ·½·¨ÉèÖÃ
+ return (PatternMatchUtils.simpleMatch(this.redirectPatterns, viewName)
+ // Æ¥Åä redirect: ¿ªÍ·£¬Ò²¾ÍÊÇ˵£¬Èç¹ûÎÒÃÇ·µ»Ø "redirect:index"£¬¾Í±íÃ÷¸Ã½á¹ûÐèÒªÌø×ª
+ || viewName.startsWith("redirect:"));
+ }
+
+}
+
+```
+
+Õâ¸öÀà±È½Ï¼òµ¥£¬¹Ø¼ü²¿·ÖÒÑÔÚ´úÂëÖÐ×÷ÁË×¢ÊÍ£¬ÕâÀï¾Í²»¶à˵ÁË¡£ÖµµÃÒ»ÌáµÄÊÇ£¬ÔÚ `handleReturnValue(xxx)` ·½·¨ÖУ¬springmvc ½«·µ»ØµÄ×Ö·û´®ÉèÖÃΪ `viewName` ÐèҪעÒâÏ£¬ºóÃæÔÚ´¦ÀíÊÓͼʱ£¬»áÀûÓÃÕâ¸ö `viewName` Äõ½¶ÔÓ¦µÄ `View`¡£
+
+#### »ñÈ¡ ModelAndView
+
+ÈÃÎÒÃǻص½ `RequestMappingHandlerAdapter#invokeHandlerMethod` ·½·¨£º
+
+```
+@Nullable
+protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
+ HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
+ ServletWebRequest webRequest = new ServletWebRequest(request, response);
+ try {
+ ...
+ // Ö´ÐÐControllerµÄ·½·¨
+ invocableMethod.invokeAndHandle(webRequest, mavContainer);
+ if (asyncManager.isConcurrentHandlingStarted()) {
+ return null;
+ }
+ // ´¦ÀíÖ´Ðнá¹û£¬´ÓÖÐÄõ½ ModelAndView
+ return getModelAndView(mavContainer, modelFactory, webRequest);
+ }
+ finally {
+ webRequest.requestCompleted();
+ }
+}
+
+```
+
+Ö´ÐÐÍê `invocableMethod.invokeAndHandle(webRequest, mavContainer)` ·½·¨ºó½ÓמÍÊÇ´ÓÖ´Ðнá¹ûÖÐÄõ½ `ModelAndView` ÁË£¬½øÈë `RequestMappingHandlerAdapter#getModelAndView` ·½·¨£º
+
+```
+private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
+ ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
+ // Õâ¸ö ModelFactory£¬¾ÍÊÇÇ°Ãæ»ñÈ¡µÄ °üº¬@ModelAttribute ×¢½âµÄ·½·¨
+ modelFactory.updateModel(webRequest, mavContainer);
+ if (mavContainer.isRequestHandled()) {
+ return null;
+ }
+ ModelMap model = mavContainer.getModel();
+ // ´´½¨ÊÓͼ¶ÔÏ󣬰ÑmavContainer.getViewName()´«Èëµ½ModelAndViewµÄ¹¹Ôì·½·¨ÖÐ
+ ModelAndView mav = new ModelAndView(mavContainer.getViewName(),
+ model, mavContainer.getStatus());
+ if (!mavContainer.isViewReference()) {
+ mav.setView((View) mavContainer.getView());
+ }
+ // ´¦ÀíÖØ¶¨Ïò²ÎÊý
+ if (model instanceof RedirectAttributes) {
+ Map flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
+ HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
+ if (request != null) {
+ RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
+ }
+ }
+ return mav;
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`ModelAndView` ¾ÍÊÇ´ÓÇ°ÃæÖ´Ðнá¹ûµÄ `viewName` µÃµ½µÄ¡£
+
+ÖÁ´Ë£¬`AbstractHandlerMethodAdapter#handle` Ö´ÐÐÍê±Ï¡£
+
+### 7\. Ö´ÐÐÀ¹½ØÆ÷£º`HandlerInterceptor#postHandle`
+
+ÈÃÎÒÃÇÔٻص½ `DispatcherServlet#doDispatch` ·½·¨£º
+
+> DispatcherServlet#doDispatch
+
+```
+protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
+ ...
+
+ try {
+ ...
+ try {
+ ...
+ // 4.ͨ¹ýÉÏÃæ»ñÈ¡µ½µÄhandlerAdapterÀ´µ÷ÓÃhandle
+ mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
+ // 5.Èç¹ûº¯Êýµ÷ÓÃûÓзµ»ØÊÓͼÔòʹÓÃĬÈϵÄ
+ applyDefaultViewName(processedRequest, mv);
+ // 6\. Ö´ÐÐÀ¹½ØÆ÷£¬ÔËÐÐ HandlerInterceptor#postHandle ·½·¨
+ mappedHandler.applyPostHandle(processedRequest, response, mv);
+ }
+ catch (...) {
+ ...
+ }
+ // 7\. ´¦Àí·µ»Ø½á¹û£¬ÔÚÕâ¸ö·½·¨Àï»áÖ´ÐÐ HandlerInterceptor.afterCompletion
+ processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
+ }
+ catch (...) {
+ ...
+ }
+}
+
+```
+
+Ö´ÐÐÍê `handler` ·½·¨ºó£¬¾Í¿ªÊ¼Ö´ÐÐÀ¹½ØÆ÷µÄ `HandlerInterceptor#postHandle` ·½·¨ÁË£º
+
+> HandlerExecutionChain#applyPostHandle
+
+```
+void applyPostHandle(HttpServletRequest request, HttpServletResponse response,
+ @NullableModelAndView mv) throws Exception {
+ HandlerInterceptor[] interceptors = getInterceptors();
+ if (!ObjectUtils.isEmpty(interceptors)) {
+ // ±éÀúÖ´ÐÐ postHandle(...) ·½·¨
+ for (int i = interceptors.length - 1; i >= 0; i--) {
+ HandlerInterceptor interceptor = interceptors[i];
+ interceptor.postHandle(request, response, this.handler, mv);
+ }
+ }
+}
+
+```
+
+Õâ¸öÍ¬Ç°ÃæÖ´ÐÐÀ¹½ØÆ÷·½·¨ÀàËÆ£¬ÕâÀï¾Í²»¹ý¶à·ÖÎöÁË¡£ÐèҪǿµ÷µÄÊÇ£¬`HandlerInterceptor#postHandle` µÄÖ´ÐÐʱ»úÊÇ**ÔÚÖ´ÐÐÍê `handler` ·½·¨ºóÖ®ºó£¬ÔÚÊÓͼ½âÎö֮ǰ**¡£Òò´Ë£¬ÎÒÃÇ¿ÉÒÔÔÚÀ¹½ØÆ÷µÄÕâ¸ö·½·¨Àï´¦ÀíһЩ¶îÍâµÄäÖȾ²ÎÊý¡£
+
+ÏÞÓÚÆª·ù£¬±¾ÎľÍÏȵ½ÕâÀïÁË£¬request Ö´ÐеĺóÐøÁ÷³Ì£¬ÎÒÃÇÏÂÆªÎÄÕÂÔÙ·ÖÎö¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4741104](https://my.oschina.net/funcy/blog/4741104) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AOP \347\244\272\344\276\213 demo \345\217\212 @EnableAspectJAutoProxy.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AOP \347\244\272\344\276\213 demo \345\217\212 @EnableAspectJAutoProxy.md"
new file mode 100644
index 0000000..841ee00
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AOP \347\244\272\344\276\213 demo \345\217\212 @EnableAspectJAutoProxy.md"
@@ -0,0 +1,230 @@
+在å‰�é�¢çš„æ–‡ç« ä¸ï¼Œæˆ‘们æˆ�功的编译了 spring æº�ç �,也构建了第一个 spring 测试 demo,接下æ�¥æˆ‘们就基于[第一个 spring æº�ç �调试 demo](https://my.oschina.net/funcy/blog/4533250 "第一个springæº�ç �调试demo") ä¸çš„代ç �,æ�¥å¯¹ spring æº�ç �进行æº�ç �分æž�。
+
+### 1\. spring �动�程概览
+
+在å‰�é�¢ demo çš„ `main()` 方法ä¸ï¼Œæœ‰è¿™ä¹ˆä¸€è¡Œï¼š
+
+```
+ApplicationContext context =
+ new AnnotationConfigApplicationContext("org.springframework.learn.demo01");
+
+```
+
+è¿™çŸçŸçš„一行就是 spring 的整个å�¯åЍæµ�程了。上é�¢çš„代ç �ä¸ï¼Œå£°æ˜Žäº†ä¸€ä¸ª `ApplicationContext` 类型的对象 `context`,å�³è¾¹ä½¿ç”¨å…¶å�ç±» `AnnotationConfigApplicationContext` å®žä¾‹åŒ–ï¼Œå¹¶åœ¨æž„é€ æ–¹æ³•ä¸ä¼ 入了包å�� `org.springframework.learn.demo01`,这个包å��就表明了接下æ�¥è¦�扫æ��哪些包。
+
+> 这里我们接触到了 spring 的第一个组件:`ApplicationContext`,关于 `ApplicationContext` 的分æž�,å�¯ä»¥å�‚è€ƒæˆ‘çš„æ–‡ç« [spring 组件(一):ApplicationContext](https://my.oschina.net/funcy/blog/4597456 "spring组件(一):ApplicationContext")。
+
+进入到 `AnnotationConfigApplicationContext`,代ç �如下:
+
+> AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)
+
+```
+public AnnotationConfigApplicationContext(String... basePackages) {
+ // 1\. è°ƒç”¨æ— å�‚æž„é€ å‡½æ•°ï¼Œä¼šå…ˆè°ƒç”¨çˆ¶ç±»GenericApplicationContextçš„æž„é€ å‡½æ•°
+ // 2\. çˆ¶ç±»çš„æž„é€ å‡½æ•°é‡Œé�¢å°±æ˜¯åˆ�始化DefaultListableBeanFactory,并且赋值给beanFactory
+ // 3\. æœ¬ç±»çš„æž„é€ å‡½æ•°é‡Œé�¢ï¼Œåˆ�始化了一个读å�–器:AnnotatedBeanDefinitionReader read,
+ // 一个扫�器ClassPathBeanDefinitionScanner scanner
+ // 4\. 这个scanner,就是下� scan(basePackages) 调用的对象
+ this();
+
+ //å¯¹ä¼ å…¥çš„åŒ…è¿›è¡Œæ‰«æ��,扫æ��完æˆ�å�Žï¼Œä¼šå¾—到一个 BeanDefinition 的集å�ˆ
+ scan(basePackages);
+
+ //�动spring,在这里完�spring容器的�始化�作,
+ //包括bean的实例化ã€�属性注入,将beanä¿�å˜åˆ°spring容器ä¸ç‰
+ refresh();
+}
+
+```
+
+这个类就三行,相关æ“�作都已在代ç �䏿³¨é‡Šäº†ï¼Œè¿™é‡Œç¨�å¾®å†�总结下,这段代ç �主è¦�å�šäº†ä¸‰ä»¶äº‹ï¼š
+
+1. è°ƒç”¨æ— å�‚æž„é€ ï¼Œè¿›è¡Œå±žæ€§åˆ�始化
+2. 进行包扫�,得到 BeanDefinition
+3. �用 spring 容器。
+
+接ç�€ï¼Œæˆ‘们å†�æ�¥çœ‹çœ‹ spring å�¯åЍæµ�程ä¸ï¼Œå�šäº†å“ªäº›äº‹ï¼š
+
+> AbstractApplicationContext#refresh
+
+```
+public void refresh() throws BeansException, IllegalStateException {
+ // 使用synchronized是为了��refresh() 还没结�,�次�起�动或者销�容器引起的冲�
+ synchronized (this.startupShutdownMonitor) {
+ // å�šä¸€äº›å‡†å¤‡å·¥ä½œï¼Œè®°å½•容器的å�¯åŠ¨æ—¶é—´ã€�æ ‡è®°â€œå·²å�¯åЍâ€�状æ€�ã€�检查环境å�˜é‡�ç‰
+ prepareRefresh();
+
+ // �始化BeanFactory容器�注册BeanDefinition, 最终获得了DefaultListableBeanFactory
+ ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
+
+ // 还是一些准备工作:
+ // 1\. è®¾ç½®äº†ä¸€ä¸ªç±»åŠ è½½å™¨
+ // 2\. 设置了bean表达�解�器
+ // 3\. æ·»åŠ äº†å±žæ€§ç¼–è¾‘å™¨çš„æ”¯æŒ�
+ // 4\. æ·»åŠ äº†ä¸€ä¸ªå�Žç½®å¤„ç�†å™¨ï¼šApplicationContextAwareProcessor
+ // 5\. 设置了一些忽略自动装�的接�
+ // 6\. 设置了一些�许自动装�的接�,并且进行了赋值�作
+ // 7\. 在容器ä¸è¿˜æ²¡æœ‰XXçš„bean的时候,帮我们注册beanName为XXçš„singleton bean
+ prepareBeanFactory(beanFactory);
+
+ try {
+ // Spring的一个扩展点. 如果有Bean实现了BeanFactoryPostProcessor接�,
+ // 那么在容器�始化以�,Spring 会负责调用里�的 postProcessBeanFactory 方法。
+ // 具体的å�ç±»å�¯ä»¥åœ¨è¿™æ¥çš„æ—¶å€™æ·»åŠ ç‰¹æ®Šçš„ BeanFactoryPostProcessor 的实现类,æ�¥å�šäº›äº‹
+ postProcessBeanFactory(beanFactory);
+
+ // 调用BeanFactoryPostProcessor�个实现类的postProcessBeanFactory(factory) 方法
+ invokeBeanFactoryPostProcessors(beanFactory);
+
+ // 扩展点,注册 BeanPostProcessor 的实现类,注��是BeanFactoryPostProcessor
+ registerBeanPostProcessors(beanFactory);
+
+ // åˆ�始化当å‰� ApplicationContext çš„ MessageSource,用在国际化æ“�作ä¸
+ initMessageSource();
+
+ // 这个方法主è¦�为åˆ�始化当å‰� ApplicationContext 的事件广æ’器
+ initApplicationEventMulticaster();
+
+ // 这也是spring的一个扩展点
+ onRefresh();
+
+ // Check for listener beans and register them.
+ // 注册事件监�器
+ registerListeners();
+
+ // �始化所有的 singleton beans
+ finishBeanFactoryInitialization(beanFactory);
+
+ // 完��动,
+ finishRefresh();
+ }
+
+ catch (BeansException ex) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Exception encountered during context initialization - " +
+ "cancelling refresh attempt: " + ex);
+ }
+
+ // Destroy already created singletons to avoid dangling resources.
+ // 销�已��始化的的Bean
+ destroyBeans();
+
+ // Reset 'active' flag.
+ // �置 'active' 状�
+ cancelRefresh(ex);
+
+ // Propagate exception to caller.
+ throw ex;
+ }
+
+ finally {
+ // Reset common introspection caches in Spring's core, since we
+ // might not ever need metadata for singleton beans anymore...
+ // 清除缓å˜
+ resetCommonCaches();
+ }
+ }
+}
+
+```
+
+这个方法虽然代ç �ä¸�多,但包å�«äº† spring bean 的整个创建过程,æ¯�个方法å�šäº†äº›ä»€ä¹ˆï¼Œåœ¨ä»£ç �ä¸éƒ½æœ‰æ³¨é‡Šï¼Œè¿™é‡Œå°±ä¸�赘述了。
+
+实际上,`refresh()` 涵盖了 spring 整个创建 bean çš„æµ�程,在å�Žé�¢çš„æ–‡ç« ä¸ï¼Œæˆ‘们也将é‡�点展开这里é�¢çš„æ–¹æ³•æ�¥åˆ†æž�,在现阶段å�ªéœ€è¦�大致了解这些方法å�šäº†ä»€ä¹ˆäº‹å�³å�¯ã€‚
+
+整个�程总结如下:
+
+
+
+### 2\. spring å�¯åŠ¨ä¸ `beanFactory` çš„å�˜åŒ–
+
+本文ä¸çš„æº�ç �解读就到这里了,接下æ�¥æˆ‘们æ�¥çœ‹çœ‹ï¼Œspring å�¯åŠ¨ä¸ `beanFactory` 有些什么å�˜åŒ–。
+
+> `beanFactory` 是 spring çš„é‡�è¦�组件之一,直译为 spring bean 工厂,是 spring 生产 bean 与ä¿�å˜ bean 的地方,关于 `beanFactory` 的详细分æž�,å�¯ä»¥æŸ¥çœ‹ [spring BeanFactory 分æž�](https://my.oschina.net/funcy/blog/4597529 "spring BeanFactory分æž�")。
+
+我们将æ–点打在 `AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)` çš„ `this()` 方法上,然å�Žè¿�行 demo01 çš„ `main()` 方法:
+
+
+
+æ¤æ—¶çš„å�˜é‡�ä¸ï¼Œå¹¶æ²¡æœ‰ `beanFactory`ï¼Œæˆ‘ä»¬è‡ªå·±æ·»åŠ `beanFactory` 到调度窗å�£çš„å�˜é‡�列表ä¸ï¼š
+
+
+
+è¿™æ ·å°±èƒ½çœ‹åˆ°å¯¹åº”çš„å€¼äº†ï¼š
+
+
+
+å�¯ä»¥çœ‹åˆ°ï¼Œæ¤æ—¶çš„ `beanFactory` 为 null,表明 `beanFactory` 并未实例化,我们继ç»è¿�行:
+
+
+
+当�行完 `this()` �,�现 `beanFactory` 已�有值了,类型为 `DefaultListableBeanFactory`。但是,在查看 `beanFactory` 对象时,�现 `beanFactory` 的属性太多了,我们应该�点关注啥呢?
+
+
+
+我们这部分主è¦�关注 spring bean çš„åˆ›å»ºï¼Œå› æ¤å�ªéœ€è¦�关注 `beanFactory` 的两个属性就å�¯ä»¥äº†ï¼š
+
+* beanDefinitionMapï¼šå˜æ”¾ beanDefinition çš„ map.
+* singletonObjectsï¼šå˜æ”¾ spring bean çš„ map,spring bean 创建å�Žéƒ½å˜æ”¾åœ¨è¿™é‡Œï¼Œä¹Ÿå�³ç›´è§‚上ç�†è§£çš„ `spring 容器`.
+
+> `BeanDefinition` 是 spring ��组件之一,为‘spring bean 的�述’,简��说,就是说明了一个 spring bean 应该如何创建。关于 `BeanDefinition` 的详细分�,�以查看 [spring BeanDefinition 分�](https://my.oschina.net/funcy/blog/4597536)。
+
+æˆ‘ä»¬æ‰‹åŠ¨æ·»åŠ å�˜é‡�,如下:
+
+
+
+å�¯ä»¥çœ‹åˆ°ï¼Œæ¤æ—¶çš„ `beanDefinitionMap` ä¸å·²ç»�有 4 个对象了,显然是在 `this()` æ–¹æ³•ä¸æ·»åŠ çš„ï¼Œå…³äºŽè¿™å�—我们å�Žé�¢ä¼šåˆ†æž�。
+
+接��行,�现 `beanDefinitionMap` �多了两个:
+
+
+
+这里的 `beanObj1` 与 `beanObj2` 就是我们自己的类了,由æ¤å�¯ä»¥åˆ¤æ–出 **spring 就是在 `AnnotationConfigApplicationContext#scan` 方法ä¸å¯¹åŒ…进行扫æ��çš„**。
+
+接下æ�¥ï¼Œä»£ç �执行进入 `AbstractApplicationContext#refresh` 方法,我们一行行è¿�行下去,å�‘现è¿�行到 `prepareBeanFactory(beanFactory);` 时,`singletonObjects` ä¸ç¬¬ä¸€æ¬¡å‡ºçŽ°äº†å¯¹è±¡ï¼š
+
+
+
+å�¯ä»¥çœ‹åˆ°ï¼Œè¿™é‡Œå‡ºçŽ°äº† 3 个类,基本都跟系统ã€�环境相关,如 `environment` 是 spring 当å‰�使用的环境 (`profile`),`systemProperties` 当å‰�系统的属性(æ“�作系统ã€�æ“�作系统版本ç‰ï¼‰ã€‚
+
+ç»§ç»å¾€ä¸‹è¿�行,å�‘现代ç �è¿�行到 `invokeBeanFactoryPostProcessors(beanFactory)` 时,å�ˆå¤šäº† 4 个类:
+
+
+
+å…³äºŽè¿™å‡ ä¸ªç±»çš„ä½œç”¨ï¼Œæˆ‘ä»¬å�Žé�¢çš„æ–‡ç« ä¸ä¼šåˆ†æž�,这里先ä¸�必管。继ç»å¾€ä¸‹è¿�行,å�‘现在 `registerBeanPostProcessors(beanFactory);` ä¸ï¼Œå�ˆå¤šäº†ä¸€ä¸ªå¯¹è±¡ï¼š
+
+```
+org.springframework.context.annotation.internalAutowiredAnnotationProcessor
+
+```
+
+这里我们�旧�用管这个对象,接��行下去,�以看到在�行 `initMessageSource()` 时,�多了一个对象:
+
+```
+messageSource -> {DelegatingMessageSource@1847} "Empty MessageSource"
+
+```
+
+显然,这个对象是用æ�¥å¤„ç�†å›½é™…化问题的,ä¸�过由于 demo01 ä¸å¹¶æ²¡æœ‰ç”¨åˆ°å›½é™…化,所以这里显示 `Empty MessageSource`。继ç»è¿�行,å�‘现è¿�行到 `initApplicationEventMulticaster();` 时,å�ˆå¤šäº†ä¸€ä¸ªå¯¹è±¡ï¼š
+
+```
+applicationEventMulticaster -> {SimpleApplicationEventMulticaster@1869}
+
+```
+
+显然,这个对象是用æ�¥å¤„ç�† `ApplicationContext` 的广æ’事件的,我们的 demo ä¸å¹¶æ²¡æœ‰ç”¨åˆ°ï¼Œæš‚æ—¶ä¸�å¿…ç�†ä¼šã€‚ç»§ç»ä¸‹åŽ»ï¼Œå�‘现在è¿�行完 `finishBeanFactoryInitialization(beanFactory);`,`singletonObjects` ä¸ç»ˆäºŽå‡ºçŽ°äº†æˆ‘ä»¬æœŸå¾…çš„å¯¹è±¡ï¼š
+
+
+
+ç”±æ¤å�¯è§�,对象就是在该方法ä¸åˆ›å»ºçš„。
+
+### 总结
+
+1. spring 包的�述:`AnnotationConfigApplicationContext#scan`
+2. spring bean 的创建:`AbstractApplicationContext#finishBeanFactoryInitialization`
+
+本文主è¦�是了解 spring å�¯åЍæµ�程,从整体上把æ�¡ spring å�¯åŠ¨è¿‡ç¨‹ä¸çš„ beanFactory çš„å�˜åŒ–。本文æ„�在了解 spring 的整体å�¯åЍæµ�程,å�Žç»çš„分æž�ä¸ï¼Œæˆ‘们将对这些æµ�程进行展开分æž�。
+
+* * *
+
+_本文原文链接:[https://my.oschina.net/funcy/blog/4597493](https://my.oschina.net/funcy/blog/4597493) ,é™�于作者个人水平,文ä¸éš¾å…�有错误之处,欢迎指æ£ï¼�原创ä¸�易,商业转载请è�”系作者获得授æ�ƒï¼Œé�žå•†ä¸šè½¬è½½è¯·æ³¨æ˜Žå‡ºå¤„。_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AnnotationAwareAspectJAutoProxyCreator \345\210\206\346\236\220\357\274\210\344\270\212\357\274\211.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AnnotationAwareAspectJAutoProxyCreator \345\210\206\346\236\220\357\274\210\344\270\212\357\274\211.md"
new file mode 100644
index 0000000..afcdd55
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AnnotationAwareAspectJAutoProxyCreator \345\210\206\346\236\220\357\274\210\344\270\212\357\274\211.md"
@@ -0,0 +1,669 @@
+在[ä¸Šä¸€ç¯‡æ–‡ç« ](https://my.oschina.net/funcy/blog/4678093 "ä¸Šä¸€ç¯‡æ–‡ç« ")的分æž�ä¸ï¼Œæˆ‘们介ç»�了使用 `@EnableAspectJAutoProxy` å¼€å�¯ç”¨ spring aop 功能,而 `@EnableAspectJAutoProxy` 最终å�‘ spring ä¸å¼•入了一个类:`AnnotationAwareAspectJAutoProxyCreator`,本文就从该类入手,进 一æ¥åˆ†æž� spring aop 功能。
+
+首先我们�看看这个类的继承关系:
+
+
+
+从继承关系上æ�¥çœ‹ï¼Œ`AnnotationAwareAspectJAutoProxyCreator` 是一个 `BeanPostProcessor`,结å�ˆå‰�é�¢çš„分æž�,spring `BeanPostProcessor` 的执行是在 spring bean åˆ�始化å‰�å�Žï¼Œè¿™é‡Œæˆ‘们通过æ–点调试的方å¼�验è¯�下。
+
+### 1\. 调试查看代�对象的产生
+
+我们将æ–点打在 `AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)` 方法上,然å�Žåœ¨ debug 模å¼�下è¿�行:
+
+
+
+æ¤æ—¶çš„ `wrappedBean` 的类型还是 `AopBean1`,继ç»å¾€ä¸‹ï¼Œå½“è¿�行完 `applyBeanPostProcessorsAfterInitialization` å�Žï¼Œ`wrappedBean` 的类型就å�˜äº†æ ·ï¼š
+
+
+
+表现上看还是 `AopBean1`,但å‰�é�¢å‡ºçŽ°äº† `$Poxy19` å—æ ·ï¼Œä¸”多了一个属性:`JdkDynamicAopProxy`,这表明该动æ€�是 jdk 动æ€�代ç�†ç”Ÿæˆ�的对象。
+
+å†�看看 `AopBean2` è¿�行到æ¤å¤„çš„å�˜åŒ–:
+
+
+
+å�¯ä»¥çœ‹åˆ°ï¼Œç±»å��ä¸å‡ºçŽ°äº† `SpringCGLIB` å—æ ·ï¼Œè¿™è¡¨ç¤ºè¯¥å¯¹è±¡æ˜¯ç”± spring cglib 代ç�†ç”Ÿæˆ�的。
+
+从以上调试结果æ�¥çœ‹ï¼Œspring 是在 `AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInitialization` ä¸å®Œæˆ�对象代ç�†çš„。
+
+实际上,`AnnotationAwareAspectJAutoProxyCreator` ä¸å¹¶æœªå®žçް `postProcessAfterInitialization` 方法,`AnnotationAwareAspectJAutoProxyCreator` çš„ `postProcessAfterInitialization` 方法继承自 `AbstractAutoProxyCreator#postProcessAfterInitialization`ï¼Œå› æ¤ spring 对象代ç�†çš„实际完æˆ�是在 `AbstractAutoProxyCreator#postProcessAfterInitialization` ä¸ã€‚
+
+`AnnotationAwareAspectJAutoProxyCreator` 是 `BeanPostProcessor` çš„å�类,spring 在 bean çš„åˆ�始化å‰�å�Žä¼šè°ƒç”¨ `BeanPostProcessor#postProcessBeforeInitialization` 与 `BeanPostProcessor#postProcessAfterInitialization` 方法,我们将从æº�ç �上看看 `AnnotationAwareAspectJAutoProxyCreator` 在 bean çš„åˆ�å§‹å‰�å�Žæ˜¯å¦‚何完æˆ� aop æ“�作。
+
+### 2. `AbstractAutoProxyCreator#postProcessBeforeInitialization` 方法
+
+代ç�†å¯¹è±¡çš„生æˆ�虽然是在 `BeanPostProcessor#postProcessAfterInitialization` æ–¹æ³•ï¼Œä½†æ£æ‰€è°“ “å�šæˆ�å�šå…¨å¥—â€�,本文我们先分æž� `AbstractAutoProxyCreator#postProcessBeforeInitialization` 方法,看看这个方法å�šäº†äº›ä»€ä¹ˆï¼Œè‡³äºŽ `AbstractAutoProxyCreator#postProcessAfterInitialization` æ–¹æ³•ï¼Œå°†ç•™åˆ°ä¸‹ä¸€ç¯‡æ–‡ç« åˆ†æž�。
+
+`AnnotationAwareAspectJAutoProxyCreator` 的 `postProcessBeforeInitialization` 方法继承自 `AbstractAutoProxyCreator`,`AbstractAutoProxyCreator#postProcessBeforeInitialization` 方法如下:
+
+```
+public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) {
+ Object cacheKey = getCacheKey(beanClass, beanName);
+
+ if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
+ if (this.advisedBeans.containsKey(cacheKey)) {
+ return null;
+ }
+ //1\. åŠ è½½æ‰€æœ‰å¢žå¼º
+ if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
+ this.advisedBeans.put(cacheKey, Boolean.FALSE);
+ return null;
+ }
+ }
+
+ // 2\. 如果有自定义的TargetSource,则�行下�的方法�创建代�
+ TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
+ if (targetSource != null) {
+ if (StringUtils.hasLength(beanName)) {
+ this.targetSourcedBeans.add(beanName);
+ }
+ Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
+ Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
+ this.proxyTypes.put(cacheKey, proxy.getClass());
+ return proxy;
+ }
+
+ return null;
+}
+
+```
+
+这个方法主è¦�åŠŸèƒ½å°±æ˜¯åŠ è½½é¡¹ç›®ä¸çš„增强方法,处ç�†ä»£ç �如下:
+
+```
+if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
+ ...
+}
+
+```
+
+这段代ç �包å�«ä¸¤ä¸ªæ–¹æ³•:`isInfrastructureClass(beanClass)` 与 `shouldSkip(beanClass, beanName)`,先æ�¥çœ‹ `isInfrastructureClass(beanClass)`
+
+#### 2.1 `isInfrastructureClass(beanClass)` 方法
+
+> AnnotationAwareAspectJAutoProxyCreator#isInfrastructureClass
+
+```
+@Override
+protected boolean isInfrastructureClass(Class> beanClass) {
+ // 判æ–当å‰�类是å�¦ä¸º Advice/Pointcut/Advisor/AopInfrastructureBean çš„å�ç±»
+ return (super.isInfrastructureClass(beanClass) ||
+ // 判æ–当å‰�beanClass是å�¦ä¸ºåˆ‡é�¢ï¼šåŒ…å�«æœ‰@Aspect注解, 且ä¸�ç”±ajc编译
+ (this.aspectJAdvisorFactory != null && this.aspectJAdvisorFactory.isAspect(beanClass)));
+}
+
+```
+
+以上代ç �就两行,功能注释得很清楚了,简å�•æ�¥è¯´å°±æ˜¯åˆ¤æ–是å�¦ä¸º aop 自身相关的类,如果是 aop 自身相关的类,就ä¸�进行切é�¢æ“�作了。
+
+#### 2.2 `shouldSkip(beanClass, beanName)` 方法
+
+接�,我们�看 `shouldSkip(beanClass, beanName)` 方法:
+
+> AspectJAwareAdvisorAutoProxyCreator#shouldSkip
+
+```
+@Override
+protected boolean shouldSkip(Class> beanClass, String beanName) {
+ //æŸ¥æ‰¾æ‰€æœ‰æ ‡è¯†äº†@Aspect注解的类,这个方法很é‡�è¦� ,下é�¢ä¼šç»§ç»åˆ†æž�
+ List candidateAdvisors = findCandidateAdvisors();
+ for (Advisor advisor : candidateAdvisors) {
+ // 如果当� advisor 为 AspectJPointcutAdvisor 的实例且 AspectName 为 beanName,返回true
+ if (advisor instanceof AspectJPointcutAdvisor &&
+ ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
+ return true;
+ }
+ }
+ // 调用父类的方法,判æ–当å‰� bean 是å�¦ä¸º OriginalInstance
+ return super.shouldSkip(beanClass, beanName);
+}
+
+```
+
+è¿™ä¸ªæ–¹æ³•ä¼šå…ˆæŸ¥æ‰¾æ‰€æœ‰æ ‡è¯†äº† `@Aspect` 注解的类,然å�Žå�šä¸€äº›åˆ¤æ–ï¼Œå…¶ä¸ `findCandidateAdvisors` 很关键,我们æ�¥çœ‹çœ‹è¿™ä¸ªæ–¹æ³•:
+
+> AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
+
+```
+@Override
+protected List findCandidateAdvisors() {
+ // 调用父类的方法,查找当å‰�beanFactoryä¸çš„Advisor bean
+ List advisors = super.findCandidateAdvisors();
+ if (this.aspectJAdvisorsBuilder != null) {
+ // 将包� @Aspect 注解的类构建为 Advisor,这�是关键
+ advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
+ }
+ return advisors;
+}
+
+```
+
+首先�看下 `super.findCandidateAdvisors()` 方法,也就是 `AbstractAdvisorAutoProxyCreator#findCandidateAdvisors`:
+
+```
+protected List findCandidateAdvisors() {
+ Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
+ return this.advisorRetrievalHelper.findAdvisorBeans();
+}
+
+```
+
+这个调用了 `BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans`,继ç»ä¸‹åŽ»ï¼š
+
+```
+public List findAdvisorBeans() {
+ String[] advisorNames = this.cachedAdvisorBeanNames;
+ if (advisorNames == null) {
+ // 1\. 查找当å‰�beanFactory䏿‰€æœ‰ Advisor çš„ bean class
+ advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
+ this.beanFactory, Advisor.class, true, false);
+ this.cachedAdvisorBeanNames = advisorNames;
+ }
+ ...
+
+ List advisors = new ArrayList<>();
+ for (String name : advisorNames) {
+ ...
+ // 2\. 从springä¸èŽ·å�– bean class 对应的 bean,将其放入advisorsä¸
+ advisors.add(this.beanFactory.getBean(name, Advisor.class));
+ ...
+
+ }
+ return advisors;
+}
+
+```
+
+以上代ç �å�šäº†ä¸¤ä»¶äº‹ï¼š
+
+1. 查找当å‰� beanFactory 䏿‰€æœ‰ Advisor çš„ bean class,Advisor å�¯ä»¥æ˜¯ç”¨æˆ·å®žçް Advisor 相关接å�£ï¼Œä¹Ÿå�¯ä»¥æ˜¯ xml 指定的
+2. 从 spring ä¸èŽ·å�– bean class 对应的 bean,将其放入 advisors ä¸
+
+#### 2.3 `aspectJAdvisorsBuilder.buildAspectJAdvisors()` 方法
+
+接�我们�回过头�看看 `aspectJAdvisorsBuilder.buildAspectJAdvisors())` 方法 :
+
+> BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
+
+```
+public List buildAspectJAdvisors() {
+ List aspectNames = this.aspectBeanNames;
+
+ // �有在第一次�行时,�会�立
+ if (aspectNames == null) {
+ synchronized (this) {
+ aspectNames = this.aspectBeanNames;
+ if (aspectNames == null) {
+ List advisors = new ArrayList<>();
+ aspectNames = new ArrayList<>();
+ //1\. 获�所有Bean�称
+ String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
+ this.beanFactory, Object.class, true, false);
+ for (String beanName : beanNames) {
+ ...
+ //2\. 判æ–Beançš„Class上是å�¦æ ‡è¯†@Aspect注解
+ if (this.advisorFactory.isAspect(beanType)) {
+ aspectNames.add(beanName);
+ AspectMetadata amd = new AspectMetadata(beanType, beanName);
+ if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
+ // 创建factory对象,这个对象里包�了beanFactory与@Aspect的beanName
+ MetadataAwareAspectInstanceFactory factory =
+ new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
+ // 3\. 解�所有的增强方法, 这个方法是�点的�点
+ List classAdvisors = this.advisorFactory.getAdvisors(factory);
+ if (this.beanFactory.isSingleton(beanName)) {
+ //将解æž�çš„Beanå��ç§°å�Šç±»ä¸Šçš„增强缓å˜èµ·æ�¥,æ¯�个Beanå�ªè§£æž�一次
+ this.advisorsCache.put(beanName, classAdvisors);
+ }
+ ...
+ }
+ else {
+ ...
+ }
+ }
+ }
+ // 对属性赋值,之�就�会��行了
+ this.aspectBeanNames = aspectNames;
+ return advisors;
+ }
+ }
+ }
+
+ if (aspectNames.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List advisors = new ArrayList<>();
+ for (String aspectName : aspectNames) {
+ //从缓å˜ä¸èŽ·å�–当å‰�Bean的切é�¢å®žä¾‹ï¼Œå¦‚æžœä¸�为空,则指明当å‰�Beançš„Classæ ‡è¯†äº†@Aspect,且有切é�¢æ–¹æ³•
+ List cachedAdvisors = this.advisorsCache.get(aspectName);
+ if (cachedAdvisors != null) {
+ advisors.addAll(cachedAdvisors);
+ }
+ else {
+ MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
+ advisors.addAll(this.advisorFactory.getAdvisors(factory));
+ }
+ }
+ return advisors;
+}
+
+```
+
+方法虽然有点长,�过��了 3 件事:
+
+1. 获�所有 beanName:`BeanFactoryUtils.beanNamesForTypeIncludingAncestors`
+2. æ‰¾å‡ºæ‰€æœ‰æ ‡è®° Aspect 注解的类:`advisorFactory.isAspect(beanType)`
+3. å¯¹æ ‡è®° Aspect 的类æ��å�–增强器:`this.advisorFactory.getAdvisors(factory)`
+
+这里我们�点分�第 3 点,看看 `Advisors` 是如何构建的。
+
+> ReflectiveAspectJAdvisorFactory#getAdvisors
+
+```
+public List getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
+ //获å�–Aspectç±»ã€�ç±»å��ç§°ã€�å¹¶æ ¡éªŒ
+ // aspectInstanceFactory 里包�beanFactory与 @Aspect 的 beanName
+ Class> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
+ String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
+ //æ ¡éªŒç±»çš„å�ˆæ³•性相关
+ validate(aspectClass);
+
+ MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
+ new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
+ List advisors = new ArrayList<>();
+ // 获�这个类除去 @Pointcut 外的所有方法,看下�的分�
+ for (Method method : getAdvisorMethods(aspectClass)) {
+ // 生�增强实例,这个 方法是�点,看��的分�
+ // 注æ„� advisors.size(),这个指定了advisor的顺åº�,由于获å�–之å�Žä¼šä¸ªæ·»åŠ
+ // æ“�ä½œï¼Œå› æ¤è¿™ä¸ªå€¼æ˜¯é€’增且是ä¸�é‡�å¤�çš„
+ Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory,
+ advisors.size(), aspectName);
+ if (advisor != null) {
+ // æ·»åŠ advisors 列表
+ advisors.add(advisor);
+ }
+ }
+ // 如果需è¦�增强且é…�置了延迟增强,则在第一个ä½�ç½®æ·»åŠ å�Œæ¥å®žä¾‹åŒ–增强方法
+ if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory
+ .getAspectMetadata().isLazilyInstantiated()) {
+ Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(
+ lazySingletonAspectInstanceFactory);
+ advisors.add(0, instantiationAdvisor);
+ }
+ // 获å�–属性ä¸é…�ç½®DeclareParents注解的增强
+ for (Field field : aspectClass.getDeclaredFields()) {
+ Advisor advisor = getDeclareParentsAdvisor(field);
+ if (advisor != null) {
+ advisors.add(advisor);
+ }
+ }
+ return advisors;
+}
+
+/**
+ * 获�指定类除@Pointcut外的所有方法
+ */
+private List getAdvisorMethods(Class> aspectClass) {
+ final List methods = new ArrayList<>();
+ // 递归æ“�作 :排除@Pointcutæ ‡è¯†çš„æ–¹æ³•ï¼ŒèŽ·å�–当å‰�类的的方法ã€�æ�¥è‡ªæŽ¥å�£çš„默认方法,å†�对父类进行å�Œæ ·çš„æ“�作
+ // 最终结果:除@Pointcutæ ‡è¯†ä¹‹å¤–çš„æ‰€æœ‰æ–¹æ³•ï¼Œå¾—åˆ°çš„æ–¹æ³•é›†å�ˆåŒ…括:
+ // 1\. 继承自父类的方法,
+ // 2\. �自自接�的默认的方法
+ // 3\. �包�继承自Object的方法
+ ReflectionUtils.doWithMethods(aspectClass, method -> {
+ if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
+ methods.add(method);
+ }
+ }, ReflectionUtils.USER_DECLARED_METHODS);
+ //对得到的所有方法排�,
+ //å¦‚æžœæ–¹æ³•æ ‡è¯†äº†åˆ‡é�¢æ³¨è§£ï¼Œåˆ™æŒ‰@Around, @Before, @After, @AfterReturning, @AfterThrowing的顺åº�排åº�
+ //å¦‚æžœæ²¡æœ‰æ ‡è¯†è¿™äº›æ³¨è§£ï¼Œåˆ™æŒ‰æ–¹æ³•å��ç§°çš„å—符串排åº�,
+ //æœ‰æ³¨è§£çš„æ–¹æ³•æŽ’åœ¨æ— æ³¨è§£çš„æ–¹æ³•ä¹‹å‰�
+ //最å�Žçš„æŽ’åº�åº”è¯¥æ˜¯è¿™æ ·çš„Around, Before, After, AfterReturning, AfterThrowing
+ methods.sort(METHOD_COMPARATOR);
+ return methods;
+}
+
+```
+
+以上方法主��了两件事:
+
+1. 获�当�类除 `@Pointcut` 外的所有增强方法,包括继承自父类的方法,继承自 Object 的方法,以��自接�的默认方法
+2. é��历得到的方法,从符å�ˆæ�¡ä»¶çš„æ–¹æ³•得到 Advisor 实例,ä¿�å˜åˆ°é›†å�ˆä¸
+
+关于第一æ¥ï¼Œä¸Šé�¢çš„代ç �å·²ç»�分æž�了,主è¦�æ˜¯æ ¹æ�®å��å°„æ�¥è¿›è¡Œçš„,就ä¸�å†�深入了,这里我们æ�¥çœ‹ç¬¬äºŒæ¥ï¼Œè¯¥æ“�作是在 `ReflectiveAspectJAdvisorFactory#getAdvisor` 方法ä¸ï¼š
+
+```
+@Override
+@Nullable
+/**
+ * declarationOrderInAspect:指定了Advisor的顺�,��于 AdvisorMethods 的排�,上�已分�
+ */
+public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory
+ aspectInstanceFactory, int declarationOrderInAspect, String aspectName) {
+ //å†�æ¬¡æ ¡éªŒç±»çš„å�ˆæ³•性
+ validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
+ //切点表达�的包装类里�包�这些东西:@Around("testAop()") 里的 testAop()
+ AspectJExpressionPointcut expressionPointcut = getPointcut(
+ candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
+ if (expressionPointcut == null) {
+ return null;
+ }
+ //æ ¹æ�®æ–¹æ³•ã€�切点ã€�AOP实例工厂ã€�ç±»å��ã€�åº�å�·ç”Ÿæˆ�切é�¢å®žä¾‹ï¼Œä¸‹é�¢æˆ‘们先æ�¥çœ‹çœ‹æ˜¯å¦‚何实例化的
+ return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
+ this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
+}
+
+/**
+ * 处�切点表达�
+ */
+@Nullable
+private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod,
+ Class> candidateAspectClass) {
+ // 查询方法上的切é�¢æ³¨è§£ï¼Œæ ¹æ�®æ³¨è§£ç”Ÿæˆ�相应类型的AspectJAnnotation,
+ // 在调用AspectJAnnotationçš„æž„é€ å‡½æ•°çš„å�Œæ—¶ï¼Œæ ¹æ�®æ³¨è§£value或pointcut属性得到切点表达å¼�,
+ // 有argNames则设置�数�称
+ AspectJAnnotation> aspectJAnnotation =
+ AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
+ // 过滤那些��@Before, @Around, @After, @AfterReturning, @AfterThrowing注解的方法
+ if (aspectJAnnotation == null) {
+ return null;
+ }
+
+ //生�带表达�的切�切入点,设置其切入点表达�
+ AspectJExpressionPointcut ajexp =
+ new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class>[0]);
+ ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
+ if (this.beanFactory != null) {
+ ajexp.setBeanFactory(this.beanFactory);
+ }
+ return ajexp;
+}
+
+```
+
+`Advisor` 实例化过程如下:
+
+```
+public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
+ Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
+ MetadataAwareAspectInstanceFactory aspectInstanceFactory,
+ int declarationOrder, String aspectName) {
+ // 处�属性设置
+ this.declaredPointcut = declaredPointcut;
+ this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
+ this.methodName = aspectJAdviceMethod.getName();
+ this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
+ this.aspectJAdviceMethod = aspectJAdviceMethod;
+ this.aspectJAdvisorFactory = aspectJAdvisorFactory;
+ this.aspectInstanceFactory = aspectInstanceFactory;
+ this.declarationOrder = declarationOrder;
+ this.aspectName = aspectName;
+
+ if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
+ ...
+ }
+ else {
+ this.pointcut = this.declaredPointcut;
+ this.lazy = false;
+ //�始化对应的增强器,这里是�点
+ this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
+ }
+}
+
+/**
+ * 实例化过程
+ */
+private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
+ // getAdvice: 处� Advice 实例化�作
+ Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
+ this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
+ return (advice != null ? advice : EMPTY_ADVICE);
+}
+
+```
+
+这段代ç �清晰明了,主è¦�是实例化 `Advisor`,所谓的实例化,就是往 `Advisor` 对象里设置了一些属性。这里 `instantiatedAdvice` 属性需è¦�特别说明一下,这个属性å°�装了切é�¢æ–¹æ³•,也就是增强的内容。
+
+* 切é�¢æ–¹æ³• (切é�¢å…·ä½“的执行代ç �) å°�装为 `Advice`ï¼›
+* `Advice` 是 `Advisor` 的一个属性。
+
+#### 2.4 实例化 `Advice`
+
+接下�看看 `Advice` 的�程:
+
+> ReflectiveAspectJAdvisorFactory#getAdvice
+
+```
+@Override
+@Nullable
+public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
+ MetadataAwareAspectInstanceFactory aspectInstanceFactory,
+ int declarationOrder, String aspectName) {
+
+ Class> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
+ //å�ˆæ˜¯ä¸€æ¬¡æ ¡éªŒ
+ validate(candidateAspectClass);
+
+ AspectJAnnotation> aspectJAnnotation =
+ AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
+ if (aspectJAnnotation == null) {
+ return null;
+ }
+
+ if (!isAspect(candidateAspectClass)) {
+ throw new AopConfigException(...);
+ }
+
+ AbstractAspectJAdvice springAdvice;
+ // æ ¹æ�®æ³¨è§£ç±»åž‹ç”Ÿæˆ�ä¸�å�Œçš„通知实例,
+ // 对应的注解就是 @Before, @Around, @After, @AfterReturning, @AfterThrowing
+ switch (aspectJAnnotation.getAnnotationType()) {
+ case AtPointcut:
+ return null;
+ case AtAround:
+ springAdvice = new AspectJAroundAdvice(
+ candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
+ break;
+ case AtBefore:
+ springAdvice = new AspectJMethodBeforeAdvice(
+ candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
+ break;
+ case AtAfter:
+ springAdvice = new AspectJAfterAdvice(
+ candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
+ break;
+ case AtAfterReturning:
+ springAdvice = new AspectJAfterReturningAdvice(
+ candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
+ AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
+ if (StringUtils.hasText(afterReturningAnnotation.returning())) {
+ springAdvice.setReturningName(afterReturningAnnotation.returning());
+ }
+ break;
+ case AtAfterThrowing:
+ springAdvice = new AspectJAfterThrowingAdvice(
+ candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
+ AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
+ if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
+ springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
+ }
+ break;
+ default:
+ throw new UnsupportedOperationException(...);
+ }
+
+ //设置通知方法所属的类
+ springAdvice.setAspectName(aspectName);
+ //设置通知的åº�å�·,å�Œä¸€ä¸ªç±»ä¸æœ‰å¤šä¸ªåˆ‡é�¢æ³¨è§£æ ‡è¯†çš„æ–¹æ³•æ—¶,按上方说的排åº�规则æ�¥æŽ’åº�,
+ //å…¶åº�å�·å°±æ˜¯æ¤æ–¹æ³•在列表ä¸çš„åº�å�·ï¼Œç¬¬ä¸€ä¸ªå°±æ˜¯0
+ springAdvice.setDeclarationOrder(declarationOrder);
+ //获�通知方法的所有�数
+ String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
+ //将通知方法上的å�‚数设置到通知ä¸
+ if (argNames != null) {
+ springAdvice.setArgumentNamesFromStringArray(argNames);
+ }
+ //计算å�‚æ•°ç»‘å®šå·¥ä½œï¼Œæ¤æ–¹æ³•详解请接ç�€å¾€ä¸‹çœ‹
+ springAdvice.calculateArgumentBindings();
+ return springAdvice;
+}
+
+```
+
+我们知é�“,切é�¢æ³¨è§£æ ‡è¯†çš„æ–¹æ³•第一个å�‚æ•°è¦�求是 `JoinPoint`,如果是 `@Around` 注解,则第一个å�‚æ•°å�¯ä»¥æ˜¯ `ProceedingJoinPoint`,计算å�‚数绑定就是æ�¥éªŒè¯�å�‚数类型的。
+
+对于��的通知,spring 会�装���的 `advice`,这里先�看看 `advice` 的继承结构:
+
+
+
+关于 `advice`,��在分�切�的执行时会详细分�,这里�需知� “��的切�类型,最终会�装为��的 advice� ��。
+
+��看看 spring 计算�数绑定的�程:
+
+> AbstractAspectJAdvice
+
+```
+/**
+ * 处��数绑定
+ */
+public final synchronized void calculateArgumentBindings() {
+ if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
+ return;
+ }
+
+ int numUnboundArgs = this.parameterTypes.length;
+ Class>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
+ //切é�¢æ³¨è§£æ ‡è¯†çš„æ–¹æ³•第一个å�‚æ•°è¦�求是JoinPoint,或StaticPart,若是@Around注解则也å�¯ä»¥æ˜¯ProceedingJoinPoint
+ if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0]) ||
+ maybeBindJoinPointStaticPart(parameterTypes[0])) {
+ numUnboundArgs--;
+ }
+
+ if (numUnboundArgs > 0) {
+ //绑定属性其他属性
+ bindArgumentsByName(numUnboundArgs);
+ }
+
+ this.argumentsIntrospected = true;
+}
+
+```
+
+以上代ç �验è¯�了切é�¢æ³¨è§£æ ‡è¯†çš„æ–¹æ³•第一个å�‚数的类型,æ¤å¤–,如果在方法ä¸å®šä¹‰äº†å¤šä¸ªæ–¹æ³•,spring 还会进一æ¥è¿›è¡Œå�‚数绑定:
+
+> AbstractAspectJAdvice
+
+```
+/**
+ * 绑定属性其他属性
+ */
+private void bindArgumentsByName(int numArgumentsExpectingToBind) {
+ if (this.argumentNames == null) {
+ //获�方法�数的�称
+ this.argumentNames = createParameterNameDiscoverer()
+ .getParameterNames(this.aspectJAdviceMethod);
+ }
+ if (this.argumentNames != null) {
+ // ç»§ç»ç»‘定
+ bindExplicitArguments(numArgumentsExpectingToBind);
+ }
+ else {
+ throw new IllegalStateException(...);
+ }
+}
+
+/**
+ * 针对 @AfterReturning 与 @AfterThrowing 注解,进一æ¥å¤„ç�†å…¶å�‚æ•°
+ */
+private void bindExplicitArguments(int numArgumentsLeftToBind) {
+ Assert.state(this.argumentNames != null, "No argument names available");
+ //æ¤å±žæ€§ç”¨æ�¥å˜å‚¨æ–¹æ³•未绑定的å�‚æ•°å��称,å�Šå�‚æ•°çš„åº�å�·
+ this.argumentBindings = new HashMap<>();
+
+ int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterCount();
+ if (this.argumentNames.length != numExpectedArgumentNames) {
+ throw new IllegalStateException(...);
+ }
+
+ // argumentIndexOffset代表第一个未绑定�数的顺�
+ int argumentIndexOffset = this.parameterTypes.length - numArgumentsLeftToBind;
+ for (int i = argumentIndexOffset; i < this.argumentNames.length; i++) {
+ //å˜å‚¨æœªç»‘定的å�‚æ•°å��ç§°å�Šå…¶é¡ºåº�çš„æ˜ å°„å…³ç³»
+ this.argumentBindings.put(this.argumentNames[i], i);
+ }
+
+ // 如果是@AfterReturning注解的returningName 有值,验�,解�,�时得到定义返回值的类型
+ if (this.returningName != null) {
+ if (!this.argumentBindings.containsKey(this.returningName)) {
+ throw new IllegalStateException(...);
+ }
+ else {
+ Integer index = this.argumentBindings.get(this.returningName);
+ this.discoveredReturningType = this.aspectJAdviceMethod.getParameterTypes()[index];
+ this.discoveredReturningGenericType = this.aspectJAdviceMethod
+ .getGenericParameterTypes()[index];
+ }
+ }
+ // 如果是@AfterThrowing注解的throwingName 有值,验�,解�,�时得到抛出异常的类型
+ if (this.throwingName != null) {
+ if (!this.argumentBindings.containsKey(this.throwingName)) {
+ throw new IllegalStateException(...);
+ }
+ else {
+ Integer index = this.argumentBindings.get(this.throwingName);
+ this.discoveredThrowingType = this.aspectJAdviceMethod.getParameterTypes()[index];
+ }
+ }
+
+ configurePointcutParameters(this.argumentNames, argumentIndexOffset);
+}
+
+/**
+ * 这一æ¥ä»…是将å‰�é�¢æœªå¤„ç�†è¿‡çš„å�‚æ•°å�šä¸€ä¸ªä¿�å˜ï¼Œè®°å½•到 pontcut ä¸ï¼Œå¾…å�Žç»å†�å�šå¤„ç�†
+ */
+private void configurePointcutParameters(String[] argumentNames, int argumentIndexOffset) {
+ int numParametersToRemove = argumentIndexOffset;
+ if (this.returningName != null) {
+ numParametersToRemove++;
+ }
+ if (this.throwingName != null) {
+ numParametersToRemove++;
+ }
+ String[] pointcutParameterNames = new String[argumentNames.length - numParametersToRemove];
+ Class>[] pointcutParameterTypes = new Class>[pointcutParameterNames.length];
+ Class>[] methodParameterTypes = this.aspectJAdviceMethod.getParameterTypes();
+
+ int index = 0;
+ for (int i = 0; i < argumentNames.length; i++) {
+ if (i < argumentIndexOffset) {
+ continue;
+ }
+ if (argumentNames[i].equals(this.returningName) ||
+ argumentNames[i].equals(this.throwingName)) {
+ continue;
+ }
+ pointcutParameterNames[index] = argumentNames[i];
+ pointcutParameterTypes[index] = methodParameterTypes[i];
+ index++;
+ }
+ //剩余的未绑定的å�‚数会赋值给AspectJExpressionPointcut(表达å¼�å½¢å¼�的切入点)的属性,以备å�Žç»ä½¿ç”¨
+ this.pointcut.setParameterNames(pointcutParameterNames);
+ this.pointcut.setParameterTypes(pointcutParameterTypes);
+}
+
+```
+
+### 3\. 总结
+
+本文主è¦�是分æž�了 `AnnotationAwareAspectJAutoProxyCreator#postProcessBeforeInitialization` 方法,也就是 `AbstractAutoProxyCreator#postProcessBeforeInitialization` 方法,在该方法的è¿�行过程ä¸ï¼Œä¸»è¦�是将 `@Aspect` ç±»å°�装æˆ�一个个 `Advisor`,å°�装æ¥éª¤å¦‚下:
+
+1. æ‰¾åˆ°é¡¹ç›®ä¸æ ‡æ³¨äº† `@Aspect` 的类;
+2. é��历上一æ¥å¾—到的类,通过å��射得到该类的方法,包括父接å�£çš„默认方法ã€�父类的方法但ä¸�包括 Object 类的方法;
+3. 从上述方法ä¸ï¼Œæ‰¾åˆ°æ ‡æ³¨äº† `@Around`, `@Before`, `@After`, `@AfterReturning`, `@AfterThrowing` ç‰çš„æ–¹æ³•,将其å°�装为 `Advisor` 对象。
+
+关于 `Advisor`ï¼Œå…¶ä¸æœ‰ä¸ªé‡�è¦�属性为 `Advice`,这个属性就是切é�¢æ–¹æ³•的具体内容。关于 `Advice`,在å�Žé�¢åˆ†æž�切é�¢çš„æ‰§è¡Œæ—¶ä¼šè¯¦ç»†åˆ†æž�。
+
+* * *
+
+_本文原文链接:[https://my.oschina.net/funcy/blog/4678817](https://my.oschina.net/funcy/blog/4678817) ,é™�于作者个人水平,文ä¸éš¾å…�有错误之处,欢迎指æ£ï¼�原创ä¸�易,商业转载请è�”系作者获得授æ�ƒï¼Œé�žå•†ä¸šè½¬è½½è¯·æ³¨æ˜Žå‡ºå¤„。_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AnnotationAwareAspectJAutoProxyCreator \345\210\206\346\236\220\357\274\210\344\270\213\357\274\211.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AnnotationAwareAspectJAutoProxyCreator \345\210\206\346\236\220\357\274\210\344\270\213\357\274\211.md"
new file mode 100644
index 0000000..c21a988
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/AnnotationAwareAspectJAutoProxyCreator \345\210\206\346\236\220\357\274\210\344\270\213\357\274\211.md"
@@ -0,0 +1,628 @@
+[ÉÏһƪÎÄÕÂ](https://my.oschina.net/funcy/blog/4678817 "ÉÏһƪÎÄÕÂ")Ö÷Òª·ÖÎöÁË `AbstractAutoProxyCreator#postProcessAfterInitialization` ·½·¨£¬±¾ÎÄÎÒÃÇÀ´·ÖÎö `AbstractAutoProxyCreator#postProcessAfterInitialization` ·½·¨¡£
+
+ÎÒÃÇÏÈÀ´¿´¿´Õâ¸ö·½·¨µÄµ÷ÓÃÁ´£º
+
+```
+|-AnnotationConfigApplicationContext
+ |-AbstractApplicationContext#refresh
+ |-AbstractApplicationContext#finishBeanFactoryInitialization
+ |-ConfigurableListableBeanFactory#preInstantiateSingletons
+ |-AbstractBeanFactory#getBean(String)
+ |-AbstractBeanFactory#doGetBean
+ |-DefaultSingletonBeanRegistry#getSingleton(String, ObjectFactory>)
+ |-ObjectFactory#getObject
+ |-AbstractBeanFactory#createBean
+ |-AbstractAutowireCapableBeanFactory#doCreateBean
+ |-AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)
+ |-AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
+ |-AbstractAutoProxyCreator#postProcessAfterInitialization
+
+```
+
+ʵ¼ÊÉÏÕâ¸ö·½·¨µÄµ÷ÓÃÁ´¾ÍÊÇ spring bean µÄ´´½¨¹ý³Ì£¬ÎÒÃǽøÈë `AbstractAutoProxyCreator#postProcessAfterInitialization`£º
+
+```
+@Override
+public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
+ if (bean != null) {
+ Object cacheKey = getCacheKey(bean.getClass(), beanName);
+ if (this.earlyProxyReferences.remove(cacheKey) != bean) {
+ // ÉîÈëwrapIfNecessary()·½·¨
+ return wrapIfNecessary(bean, beanName, cacheKey);
+ }
+ }
+ return bean;
+}
+
+```
+
+¼ÌÐø½øÈë `AbstractAutoProxyCreator#wrapIfNecessary`£º
+
+```
+protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
+ //Èç¹ûÒѾ´¦Àí¹ý
+ if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
+ return bean;
+ }
+ //Èç¹ûµ±Ç°ÀàÊÇÔöÇ¿À࣬·µ»Ø
+ if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
+ return bean;
+ }
+
+ // ÖØÒª´úÂëÒ»£ºÅжϵ±Ç°ÀàÊÇ·ñΪÇÐÃæÀ࣬¸Ã´úÂëÔÚÉÏһƪÎÄÕÂÒѾ·ÖÎöÁË£¬¾Í²»¶à˵ÁË
+ if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
+ this.advisedBeans.put(cacheKey, Boolean.FALSE);
+ return bean;
+ }
+
+ // ÖØÒª´úÂë¶þ£ºÐ£Ñé´ËÀàÊÇ·ñÓ¦¸Ã±»´úÀí£¬»ñÈ¡Õâ¸öÀàµÄÔöÇ¿
+ Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
+ //Èç¹û»ñÈ¡µ½ÁËÔöÇ¿ÔòÐèÒªÕë¶ÔÔöÇ¿´´½¨´úÀí
+ if (specificInterceptors != DO_NOT_PROXY) {
+ this.advisedBeans.put(cacheKey, Boolean.TRUE);
+ // ÖØÒª´úÂëÈý£º´´½¨´úÀí
+ Object proxy = createProxy(
+ bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
+ this.proxyTypes.put(cacheKey, proxy.getClass());
+ return proxy;
+ }
+
+ this.advisedBeans.put(cacheKey, Boolean.FALSE);
+ return bean;
+}
+
+```
+
+Õâ¸ö·½·¨ ¿´×ÅÓе㳤£¬µ«´ó¶à´úÂë¶¼ÊÇÔÚ×öÅжϣ¬Óë aop ¹¦ÄܹØÏµ²»´ó¡£ÕæÕýÓйØÏµµÄ´úÂëÖ»ÓÐÈýÐУº
+
+```
+// ÖØÒª´úÂëÒ»£º
+// 1\. isInfrastructureClass£ºÅжϵ±Ç°ÊÇ·ñΪaopÏà¹ØÀ࣬
+// ÈçAdvice/Pointcut/AdvisorµÈµÄ×ÓÀ࣬ÊÇ·ñ°üº¬ @AspectJµÄ×¢½â
+// 2\. shouldSkip£º²éÕÒËùÓÐÇÐÃæÀ࣬ÅжÏÊÇ·ñ±»Åųý
+if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
+ ...
+}
+
+// ÖØÒª´úÂë¶þ£ºÐ£Ñé´ËÀàÊÇ·ñÓ¦¸Ã±»´úÀí£¬»ñÈ¡Õâ¸öÀàµÄÔöÇ¿
+Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
+
+// ÖØÒª´úÂëÈý£º´´½¨´úÀí
+Object proxy = createProxy(
+ bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
+
+```
+
+¶ÔÓÚ`ÖØÒª´úÂëÒ»`£¬ÉÏһƪÎÄÕÂÒѾ·ÖÎö¹ý£¬±¾ÎÄÎÒÃÇÖ÷Òª·ÖÎö`ÖØÒª´úÂë¶þ`Óë`ÖØÒª´úÂëÈý`¡£
+
+### 1\. »ñÈ¡ÀàµÄÔöÇ¿
+
+> AbstractAdvisorAutoProxyCreator
+
+```
+@Override
+@Nullable
+protected Object[] getAdvicesAndAdvisorsForBean(
+ Class> beanClass, String beanName, @Nullable TargetSource targetSource) {
+ // ²éÕÒ·ûºÏÌõ¼þµÄÔöÇ¿£¬¼ÌÐøÍùÏ¿´
+ List advisors = findEligibleAdvisors(beanClass, beanName);
+ if (advisors.isEmpty()) {
+ return DO_NOT_PROXY;
+ }
+ return advisors.toArray();
+}
+
+/**
+ * ²éÕÒ·ûºÏÌõ¼þµÄÔöÇ¿
+ */
+protected List findEligibleAdvisors(Class> beanClass, String beanName) {
+ //»ñÈ¡ÈÝÆ÷ÖеÄËùÓÐÔöÇ¿£¬ÔÚÉÏһƪÎÄÕÂÖÐÒѾ·ÖÎö¹ýÁË
+ List candidateAdvisors = findCandidateAdvisors();
+ //ÑéÖ¤beanClassÊÇ·ñ¸Ã±»´úÀí£¬Èç¹ûÓ¦¸Ã£¬Ôò·µ»ØÊÊÓÃÓÚÕâ¸öbeanµÄÔöÇ¿
+ List eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
+ extendAdvisors(eligibleAdvisors);
+ if (!eligibleAdvisors.isEmpty()) {
+ eligibleAdvisors = sortAdvisors(eligibleAdvisors);
+ }
+ return eligibleAdvisors;
+}
+
+/**
+ * ÑéÖ¤beanClassÊÇ·ñ¸Ã±»´úÀí
+ */
+protected List findAdvisorsThatCanApply(
+ List candidateAdvisors, Class> beanClass, String beanName) {
+ ProxyCreationContext.setCurrentProxiedBeanName(beanName);
+ try {
+ // ÑéÖ¤beanClassÊÇ·ñ¸Ã±»´úÀí
+ return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
+ }
+ finally {
+ ProxyCreationContext.setCurrentProxiedBeanName(null);
+ }
+}
+
+```
+
+spring µÄ·½·¨µ÷ÓñȽÏÉһ·׷×Ù£¬×îÖÕµ½ÁË `AopUtils.findAdvisorsThatCanApply` ·½·¨£¬¼ÌÐøÍùÏ¿´£º
+
+> AopUtils
+
+```
+public static List findAdvisorsThatCanApply(List candidateAdvisors, Class> clazz) {
+ if (candidateAdvisors.isEmpty()) {
+ return candidateAdvisors;
+ }
+ List eligibleAdvisors = new ArrayList<>();
+ // ±éÀú candidateAdvisors£¬ÅжÏÊÇ·ñÂú×ã´úÀíÌõ¼þ
+ for (Advisor candidate : candidateAdvisors) {
+ //´¦ÀíÔöÇ¿£¬Öص㣬ÔÙÍùÏ¿´
+ if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
+ eligibleAdvisors.add(candidate);
+ }
+ }
+ boolean hasIntroductions = !eligibleAdvisors.isEmpty();
+ for (Advisor candidate : candidateAdvisors) {
+ if (candidate instanceof IntroductionAdvisor) {
+ // already processed
+ continue;
+ }
+ //¶ÔÆÕͨbeanµÄ´¦Àí
+ if (canApply(candidate, clazz, hasIntroductions)) {
+ eligibleAdvisors.add(candidate);
+ }
+ }
+ return eligibleAdvisors;
+}
+
+/**
+ * ÅжÏÊÇ·ñÐèÒªÔöÇ¿
+ */
+public static boolean canApply(Advisor advisor, Class> targetClass) {
+ // µ÷ÓÃÏÂÒ»¸ö·½·¨
+ return canApply(advisor, targetClass, false);
+}
+
+/**
+ * ÅжÏÊÇ·ñÐèÒªÔöÇ¿
+ */
+public static boolean canApply(Advisor advisor, Class> targetClass, boolean hasIntroductions) {
+ //Èç¹û´æÔÚÅųýµÄÅäÖÃ
+ if (advisor instanceof IntroductionAdvisor) {
+ return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
+ }
+ else if (advisor instanceof PointcutAdvisor) {
+ PointcutAdvisor pca = (PointcutAdvisor) advisor;
+ //½øÈë¸Ã·½·¨¼ÌÐø
+ return canApply(pca.getPointcut(), targetClass, hasIntroductions);
+ }
+ else {
+ // It doesn't have a pointcut so we assume it applies.
+ return true;
+ }
+}
+
+/**
+ * ÅжÏÊÇ·ñÐèÒªÔöÇ¿
+ */
+public static boolean canApply(Pointcut pc, Class> targetClass, boolean hasIntroductions) {
+ Assert.notNull(pc, "Pointcut must not be null");
+ //ÇеãÉÏÊÇ·ñ´æÔÚÅųýÀàµÄÅäÖÃ
+ if (!pc.getClassFilter().matches(targetClass)) {
+ return false;
+ }
+ //Ñé֤ע½âµÄ×÷ÓÃÓòÊÇ·ñ¿ÉÒÔ×÷ÓÃÓÚ·½·¨ÉÏ
+ MethodMatcher methodMatcher = pc.getMethodMatcher();
+ if (methodMatcher == MethodMatcher.TRUE) {
+ // No need to iterate the methods if we're matching any method anyway...
+ return true;
+ }
+
+ IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
+ if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
+ introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
+ }
+
+ // classes°üº¬targetClass¡¢³ýObjectµÄËùÓи¸Àà¡¢ËùÓнӿÚ
+ Set> classes = new LinkedHashSet<>();
+ if (!Proxy.isProxyClass(targetClass)) {
+ classes.add(ClassUtils.getUserClass(targetClass));
+ }
+ classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
+
+ // Ñ»·ÅжϷ½·¨ÊÇ·ñÐèÒª´úÀí£¬
+ // ÕâÀï¿ÉÒÔ¿´³ö£¬
+ // 1\. Ö»ÒªÒ»¸ö·½·¨Âú×ã´úÀíÒªÇó£¬ÄÇôÕû¸öÀà¾Í»á±»´úÀí
+ // 2\. Èç¹û¸¸ÀàÓз½·¨ÐèÒª±»´úÀí£¬ÄÇô×ÓÀàÒ²»á±»´úÀí
+ for (Class> clazz : classes) {
+ // »ñÈ¡ clazz ¶¨ÒåµÄ·½·¨
+ // °üÀ¨µ±Ç°ÀàµÄ·½·¨¡¢³ýObjectÍâµÄËùÓи¸Àà·½·¨¡¢½Ó¿ÚµÄĬÈÏ·½·¨
+ Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
+ for (Method method : methods) {
+ //»ñÈ¡ÀàËùʵÏÖµÄËùÓнӿںÍËùÓÐÀà²ã¼¶µÄ·½·¨£¬Ñ»·ÑéÖ¤
+ if (introductionAwareMethodMatcher != null ?
+ introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
+ methodMatcher.matches(method, targetClass)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+```
+
+¿´µ½ÕâÀ»ù±¾ÉϾÍÁ˽âÁË spring ÊÇÈçºÎÀ´ÅжÏÒ»¸ö¶ÔÏóÊÇ·ñÐèÒª±»´úÀíµÄ£¬ÕâÀï×ܽáÁ÷³ÌÈçÏ£º
+
+1. »ñÈ¡µ½ÏîÄ¿ÖÐËùÓеÄÇÐÃæ¶ÔÏ󣬽«ÆäÖеÄÇÐÃæ·½·¨·âװΪһ¸ö `List`£¬¾ßÌå²Ù×÷ÔÚÉÏһƪÎÄÕÂÖÐÓÐÏêϸ·ÖÎö£»
+2. ±éÀú `Advisor`£¬¶Ôÿһ¸ö `Advisor`£¬ÀûÓ÷´Éä»ñÈ¡µ±Ç°ÀàµÄ³ý `Object` ÍâµÄËùÓи¸À༰½Ó¿Ú£¬½á¹ûΪ `Set`£»
+3. ±éÀú `Set`£¬¶ÔÆäÖÐÿһ¸ö `Class`£¬ÀûÓ÷´Éä»ñÈ¡¸Ã `Class` ·½·¨¡¢³ý Object ÍâµÄËùÓи¸ÀàµÄ·½·¨¡¢½Ó¿ÚµÄĬÈÏ·½·¨£¬½á¹ûΪ `Method[]`;
+4. ±éÀú `Method[]`£¬Èç¹ûÓÐÒ»¸ö `method` Âú×ã `Advisor` µÄÇÐÃæÌõ¼þ£¬Ôò±íʾµ±Ç° `Advisor` ¿ÉÒÔÓ¦Óõ½µ±Ç° bean£¬¸Ã bean ¾ÍÐèÒª±»´úÀí£¬ÕâÒ»²½×îÖյõ½µÄ½á¹ûÒ²ÊÇÒ»¸ö `List`£¬±íʾ¸ÃÓжà¸ö `Advisor` ÐèÒªÓ¦Óõ½¸Ã¶ÔÏó¡£
+
+α´úÂëÀàËÆÓÚ£º
+
+```
+// 1\. »ñÈ¡ËùÓеÄAdvisor
+List advisorList = getAdvisorList();
+// 2\. ±éÀúAdvisor
+for(Advisor advisor : advisorList) {
+ // »ñÈ¡µ±Ç°ÀàµÄ³ý`Object`ÍâµÄËùÓи¸À༰½Ó¿Ú£¬classSetÒ²°üº¬targetClass
+ Set classSet = getSuperClassAndInterfaces(targetClass);
+ for(Class cls : classSet) {
+ // ±éÀúclsÖж¨ÒåµÄ·½·¨£¬°üÀ¨µ±Ç°ÀàµÄ·½·¨¡¢³ýObjectÍâµÄËùÓи¸Àà·½·¨¡¢½Ó¿ÚµÄĬÈÏ·½·¨
+ Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
+ // ±éÀúÕâЩ·½·¨
+ for (Method method : methods) {
+ // ÅжÏmethodÊÇ·ñÂú×ãÇÐÃæÌõ¼þ
+ }
+ }
+}
+
+```
+
+µÃµ½ `List` ºó£¬½ÓÏÂÀ´¾ÍÊǸù¾Ý `List` À´´´½¨´úÀí¶ÔÏóÁË¡£
+
+### 2\. ´´½¨´úÀí¶ÔÏó
+
+ÎÒÃÇÀ´¿´¿´ spring ´´½¨´úÀí¶ÔÏóµÄÁ÷³Ì¡£
+
+> `AbstractAutoProxyCreator#wrapIfNecessary`£º
+
+```
+protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
+ ...
+ if (specificInterceptors != DO_NOT_PROXY) {
+ this.advisedBeans.put(cacheKey, Boolean.TRUE);
+ // ´úÀí¶ÔÏó¾ÍÊÇÔÚÕâÀï´´½¨µÄ
+ // - specificInterceptors£º¿ÉÒÔÓ¦Óõ½¸Ã¶ÔÏóµÄ Advisor£¬
+ // specificInterceptorsµÄ»ñÈ¡¹ý³Ì£¬ÉÏÒ»²¿·ÖÒѾÏêϸ·ÖÎö¹ýÁË£¬²»ÔÙ׸ÊöÁË
+ // - SingletonTargetSource£º¶ÔÔʼ¶ÔÏóµÄÒ»¸ö°ü×°
+ Object proxy = createProxy(
+ bean.getClass(), beanName, specificInterceptors,
+ new SingletonTargetSource(bean));
+ this.proxyTypes.put(cacheKey, proxy.getClass());
+ return proxy;
+ }
+ this.advisedBeans.put(cacheKey, Boolean.FALSE);
+ return bean;
+}
+
+```
+
+ÎÒÃÇÏÈÀ´¿´¿´ `SingletonTargetSource`£º
+
+```
+public class SingletonTargetSource implements TargetSource, Serializable {
+
+ private static final long serialVersionUID = 9031246629662423738L;
+
+ private final Object target;
+
+ public SingletonTargetSource(Object target) {
+ Assert.notNull(target, "Target object must not be null");
+ this.target = target;
+ }
+
+ @Override
+ public Class> getTargetClass() {
+ return this.target.getClass();
+ }
+
+ @Override
+ public Object getTarget() {
+ return this.target;
+ }
+
+ ...
+}
+
+```
+
+Õâ¸öÀà´úÂëºÜ¼òµ¥£¬¾ÍÊǶÔÔʼ¶ÔÏó×öÁËÒ»²ã°ü×°¡£¼ÌÐøÍùÏ¿´£º
+
+> AbstractAutoProxyCreator#createProxy
+
+```
+protected Object createProxy(Class> beanClass, @Nullable String beanName,
+ @Nullable Object[] specificInterceptors, TargetSource targetSource) {
+
+ if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
+ AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)
+ this.beanFactory, beanName, beanClass);
+ }
+
+ ProxyFactory proxyFactory = new ProxyFactory();
+ //ʹÓÃproxyFactory¶ÔÏócopyµ±Ç°ÀàÖеÄÏà¹ØÊôÐÔ
+ proxyFactory.copyFrom(this);
+
+ // ÅжÏÊÇ·ñʹÓÃCglib¶¯Ì¬´úÀí£¬¿ÉÒÔÔÚ×¢½âÖÐÖ¸¶¨£º
+ // @EnableAspectJAutoProxy(proxyTargetClass = true)
+ if (!proxyFactory.isProxyTargetClass()) {
+ // Èç¹û beanFactory ÊÇ ConfigurableListableBeanFactory£¬
+ // Ôò¿ÉÔÚ BeanDefinition ÉèÖÃÊôÐÔ£¬µ¥¶À¿ØÖÆÄ³Ò»¸öÀàʹÓà cglib ´úÀí
+ if (shouldProxyTargetClass(beanClass, beanName)) {
+ proxyFactory.setProxyTargetClass(true);
+ }
+ else {
+ // Èç¹ûûÓÐÅäÖÿªÆô, ÔòÅжÏbeanÊÇ·ñÓкÏÊʵĽӿÚʹÓÃJDKµÄ¶¯Ì¬´úÀí
+ // ×¢Ò⣺JDK¶¯Ì¬´úÀí±ØÐëÊÇ´øÓнӿڵÄÀà
+ // Èç¹ûÀàûÓÐʵÏÖÈκνӿÚÔòÖ»ÄÜʹÓÃCglib¶¯Ì¬´úÀí£©
+ evaluateProxyInterfaces(beanClass, proxyFactory);
+ }
+ }
+
+ // ¹¹½¨Advisor£¬ÕâÀï°üº¬Á½¸ö²Ù×÷£º
+ // 1\. Ìí¼Ó¹«¹²µÄ Interceptor
+ // 2\. ¶ÔÓÚ¸ø¶¨µÄadvisor£¬ÅÐ¶ÏÆäÀàÐÍ£¬È»ºóת»»ÎªÆä¾ßÌåÀàÐÍ
+ Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
+ //Ìí¼ÓËùÓÐÔöÇ¿
+ proxyFactory.addAdvisors(advisors);
+ //ÉèÖÃÒª´úÀíµÄÀà
+ proxyFactory.setTargetSource(targetSource);
+ //SpringµÄÒ»¸öÀ©Õ¹µã£¬Ä¬ÈÏʵÏÖΪ¿Õ¡£Áô¸øÎÒÃÇÔÚÐèÒª¶Ô´úÀí½øÐÐÌØÊâ²Ù×÷µÄʱºòʵÏÖ
+ customizeProxyFactory(proxyFactory);
+
+ proxyFactory.setFrozen(this.freezeProxy);
+ if (advisorsPreFiltered()) {
+ proxyFactory.setPreFiltered(true);
+ }
+ //ʹÓôúÀí¹¤³§»ñÈ¡´úÀí¶ÔÏó
+ return proxyFactory.getProxy(getProxyClassLoader());
+}
+
+```
+
+ÔÚ `@EnableAspectJAutoProxy` ×¢½âÖУ¬¿ÉÒÔʹÓà `proxyTargetClass = true` À´ÉèÖÃÏîĿʹÓà `cglib` ´úÀí£¬ÕâÔÚ´úÂëÖÐÒ²ÓÐÌåÏÖ£º
+
+```
+// Ö»ÓÐÔÚproxyFactory.isProxyTargetClass()Ϊfalseʱ£¬²Å»á½øÐÐÏÂÃæµÄÅжÏ
+// »»ÑÔÖ®£¬µ± @EnableAspectJAutoProxy(proxyTargetClass = true) ʱ
+// ÏÂÃæµÄ´úÂëÊDz»»áÔËÐеģ¬Ä¬ÈÏʹÓþÍÊÇcglib´úÀí
+if (!proxyFactory.isProxyTargetClass()) {
+ // ÅжÏÓÐûÔÚ BeanDefinition ÖÐÉèÖÃʹÓà cglib´úÀí
+ if (shouldProxyTargetClass(beanClass, beanName)) {
+ proxyFactory.setProxyTargetClass(true);
+ }
+ else {
+ // ÊÇ·ñÂú×ã´úÀí½Ó¿ÚµÄÌõ¼þ£¬¼´ÊÇ·ñÂú×ãjdk¶¯Ì¬´úÀíµÄÌõ¼þ
+ evaluateProxyInterfaces(beanClass, proxyFactory);
+ }
+}
+
+```
+
+spring ÊÇÈçºÎÅжÏÒ»¸öÀàÊÇ·ñÂú×ã jdk ¶¯Ì¬´úÀíµÄÌõ¼þµÄÄØ£¿´ÓÎÒÃÇÀ´ÈÏÖªÉÏÀ´Ëµ£¬ÊµÏÖÁ˽ӿڣ¬¾Í¿ÉÒÔʹÓö¯Ì¬´úÀí£¬·ñÔò¾ÍÖ»ÄÜʹÓà cglib ´úÀí£¬ÎÒÃÇÀ´¿´¿´ spring ÊÇÈçºÎÅжϵģº
+
+> ProxyProcessorSupport#evaluateProxyInterfaces
+
+```
+/**
+ * ÅжÏÊÇ·ñÄÜʹÓÃjdk¶¯Ì¬´úÀí
+ */
+protected void evaluateProxyInterfaces(Class> beanClass, ProxyFactory proxyFactory) {
+ // »ñÈ¡ÀàµÄËùÓнӿÚ
+ Class>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
+ boolean hasReasonableProxyInterface = false;
+ for (Class> ifc : targetInterfaces) {
+ // 1.isConfigurationCallbackInterface: ÅжÏifcÊÇ·ñΪInitializingBean£¬DisposableBean£¬
+ // Closeable£¬AutoCloseable£¬ÒÔ¼°°üº¬ Aware
+ // 2.isInternalLanguageInterface: ÊÇ·ñΪÄÚ²¿ÓïÑÔ½Ó¿Ú£¬Èçgroovy£¬mockµÈ
+ // 3.ifc.getMethods().length > 0£º½Ó¿ÚµÄ·½·¨Êý±ØÐë´óÓÚ1
+ if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
+ ifc.getMethods().length > 0) {
+ hasReasonableProxyInterface = true;
+ break;
+ }
+ }
+ if (hasReasonableProxyInterface) {
+ // ÐèÒª½«ËùÓеĽӿڶ¼ÉèÖõ½proxyFactory
+ // ÊÔÏëһϣ¬Èç¹ûÒ»¸öÀàA ʵÏÖÁË½Ó¿Ú I1 Óë I2£¬
+ // Èç¹ûÀàAµÄ¶ÔÏóa Íйܵ½ÁËspringÈÝÆ÷£¬ÄÇôÎÞÂÛÊÇʹÓà beanFactory.get(I1.class)£¬
+ // »¹ÊÇ beanFactory.get(I1.class)£¬¶¼Ó¦¸ÃÄÜ»ñÈ¡µ½a.
+ for (Class> ifc : targetInterfaces) {
+ proxyFactory.addInterface(ifc);
+ }
+ }
+ else {
+ proxyFactory.setProxyTargetClass(true);
+ }
+}
+
+```
+
+´ÓÔ´ÂëÉÏÀ´¿´£¬spring ÅжÏÊÇ·ñÄÜʹÓà jdk ¶¯Ì¬´úÀíµÄ¹ý³ÌÓëÎÒÃÇÈÏÖªÉϵIJ¶à£¬²»¹ý²¢²»ÊÇʵÏÖÁËÈÎÒâ½Ó¿Ú¾ÍÄÜʹÓà jdk ¶¯Ì¬´úÀí£¬spring »áÅųý `InitializingBean`£¬`DisposableBean`£¬`Closeable`£¬`AutoCloseable` µÈ½Ó¿Ú£¬Í¬Ê±Ò²»áÅųýÎÞÈκη½·¨µÄ½Ó¿Ú¡£
+
+·ÖÎöÍê spring ÈçºÎÅжÏÊÇ·ñʹÓà jdk ¶¯Ì¬´úÀíºó£¬½Ó¿ÚÎÒÃÇÀ´¿´¿´ spring ÊÇÈçºÎ´´½¨´úÀí¶ÔÏóµÄ¡£ÎªÁË˵Ã÷ÎÊÌ⣬Ê×Ïȼò»¯Ï `AbstractAutoProxyCreator#createProxy`£º
+
+```
+protected Object createProxy(Class> beanClass, @Nullable String beanName,
+ @Nullable Object[] specificInterceptors, TargetSource targetSource) {
+ // Ê¡ÂÔһЩ´úÂë
+ ...
+ ProxyFactory proxyFactory = new ProxyFactory();
+ //ʹÓÃproxyFactory¶ÔÏócopyµ±Ç°ÀàÖеÄÏà¹ØÊôÐÔ
+ proxyFactory.copyFrom(this);
+ // ÕâÀïÊ¡ÂÔÁ˺öàµÄÅжÏ
+ proxyFactory.setProxyTargetClass(true);
+ //Ìí¼ÓËùÓÐÔöÇ¿
+ proxyFactory.addAdvisors(advisors);
+ //ÉèÖÃÒª´úÀíµÄÀà
+ proxyFactory.setTargetSource(targetSource);
+ ...
+ //ʹÓôúÀí¹¤³§»ñÈ¡´úÀí¶ÔÏó
+ return proxyFactory.getProxy(getProxyClassLoader());
+}
+
+```
+
+´ÓÕâÀï¿ÉÒÔ¿´³ö£¬Õâ¸ö·½·¨´´½¨ÁËÒ»¸ö `ProxyFactory` ¶ÔÏó£¬È»ºóÍù¸Ã¶ÔÏóµÄÊôÐÔÀïÉèÖÃÁËһЩֵ¡£¼ÌÐøÍùÏ¿´£º
+
+> ProxyFactory#getProxy(java.lang.ClassLoader)
+
+```
+public Object getProxy(@Nullable ClassLoader classLoader) {
+ return createAopProxy().getProxy(classLoader);
+}
+
+```
+
+ÕâÀïÓÐÁ½¸ö·½·¨£º`createAopProxy()` Óë `getProxy(classLoader)`£¬ÎÒÃÇÏÈÀ´¿´ `createAopProxy()`¡£
+
+> ProxyCreatorSupport#createAopProxy
+
+```
+protected final synchronized AopProxy createAopProxy() {
+ if (!this.active) {
+ activate();
+ }
+ return getAopProxyFactory().createAopProxy(this);
+}
+
+```
+
+¼ÌÐø£¬
+
+> DefaultAopProxyFactory#createAopProxy
+
+```
+/**
+ * ÅжϴúÀíÀàÐÍ
+ * Èç¹ûÄÜʹÓÃjdk¶¯Ì¬´úÀí£¬¾Í·µ»Ø JdkDynamicAopProxy
+ * ·ñÔò¾Í·µ»Ø ObjenesisCglibAopProxy
+ */
+public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
+ if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
+ Class> targetClass = config.getTargetClass();
+ if (targetClass == null) {
+ throw new AopConfigException(...);
+ }
+ if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
+ return new JdkDynamicAopProxy(config);
+ }
+ return new ObjenesisCglibAopProxy(config);
+ }
+ else {
+ return new JdkDynamicAopProxy(config);
+ }
+}
+
+```
+
+µ½ÕâÀÎÒÃǾÍÄÜÃ÷°×£¬`JdkDynamicAopProxy` ÊÇÓÃÀ´´¦Àí jdk ¶¯Ì¬´úÀíµÄ£¬`ObjenesisCglibAopProxy` ÊÇÓÃÀ´´¦Àí cglib ´úÀíµÄ¡£½ÓÏÂÀ´£¬ÎÒÃÇÀ´¿´¿´ `getProxy(classLoader)` ·½·¨¡£
+
+> JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
+
+```
+@Override
+public Object getProxy(@Nullable ClassLoader classLoader) {
+ Class>[] proxiedInterfaces = AopProxyUtils
+ .completeProxiedInterfaces(this.advised, true);
+ // ÊÇ·ñÓÐequals()ÓëhashCode()·½·¨
+ findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
+ // µ÷Óà jdk ·½·¨ ´´½¨¶ÔÏó
+ return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
+}
+
+```
+
+×îºóÎÒÃÇÀ´¿´¿´µÃµ½µÄ´úÀí¶ÔÏóÊÇʲôÑùµÄ£º
+
+
+
+¿ÉÒÔ¿´µ½£¬´úÀí¶ÔÏóµÄ `h` ÊôÐÔ±£´æµÄ¾ÍÊÇ `JdkDynamicAopProxy` ¶ÔÏó£¬`JdkDynamicAopProxy` ¶ÔÏóµÄ `advised` ÊôÐÔ±£´æÁË´úÀíµÄ´úÀíµÄÏà¹ØÐÅÏ¢¡£
+
+> CglibAopProxy#getProxy(java.lang.ClassLoader)
+
+```
+public Object getProxy(@Nullable ClassLoader classLoader) {
+ try {
+ Class> rootClass = this.advised.getTargetClass();
+ Assert.state(rootClass != null, "xxx");
+
+ Class> proxySuperClass = rootClass;
+ if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
+ proxySuperClass = rootClass.getSuperclass();
+ Class>[] additionalInterfaces = rootClass.getInterfaces();
+ for (Class> additionalInterface : additionalInterfaces) {
+ this.advised.addInterface(additionalInterface);
+ }
+ }
+
+ validateClassIfNecessary(proxySuperClass, classLoader);
+
+ // ´´½¨ Enhancer ¶ÔÏ󣬲¢setһЩÊôÐÔ
+ Enhancer enhancer = createEnhancer();
+ if (classLoader != null) {
+ enhancer.setClassLoader(classLoader);
+ if (classLoader instanceof SmartClassLoader &&
+ ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
+ enhancer.setUseCache(false);
+ }
+ }
+ // Superclass¾ÍÊÇÒª´úÀíµÄÀà
+ enhancer.setSuperclass(proxySuperClass);
+ // ÉèÖýӿڣ¬Èç SpringProxy£¬Advised
+ enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
+ enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
+ enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
+
+ Callback[] callbacks = getCallbacks(rootClass);
+ Class>[] types = new Class>[callbacks.length];
+ for (int x = 0; x < types.length; x++) {
+ types[x] = callbacks[x].getClass();
+ }
+ enhancer.setCallbackFilter(new ProxyCallbackFilter(
+ this.advised.getConfigurationOnlyCopy(),
+ this.fixedInterceptorMap, this.fixedInterceptorOffset));
+ enhancer.setCallbackTypes(types);
+
+ return createProxyClassAndInstance(enhancer, callbacks);
+ }
+ catch (CodeGenerationException | IllegalArgumentException ex) {
+ throw new AopConfigException(...);
+ }
+ catch (Throwable ex) {
+ throw new AopConfigException("Unexpected AOP exception", ex);
+ }
+}
+
+```
+
+spring ʹÓà cglib ´´½¨¶ÔÏó£¬Ö÷ÒªÓõ½ÁË `Enhancer` À࣬¹ØÓÚÕâÒ»¿éºóÃæ»áÔÙ·ÖÎö¡£
+
+×îºóÎÒÃÇÒ²À´¿´¿´´´½¨ºóµÃµ½µÄ¶ÔÏó£º
+
+
+
+### 3\. ×ܽá
+
+±¾ÎÄÖ÷Òª·ÖÎöÁË `AbstractAutoProxyCreator#postProcessAfterInitialization`£¬¸Ã·½·¨Ö÷Òª×öÁËÈý¼þÊ£º
+
+1. »ñÈ¡ÏîÄ¿ÖÐËùÓÐÇÐÃæÀ࣬½«Çе㷽·¨°üװΪ `List`£ºÊµ¼ÊÉÏ£¬ÕâÒ»²½µÄ²Ù×÷Ò²»áÔÚ `AbstractAutoProxyCreator#postProcessBeforeInitialization` ÖÐÖ´ÐУ¬È»ºó½«½á¹û»º´æÁËÆðÀ´£¬ÕâÒ»²½ÆäʵÊÇÖ±½ÓÔÚ»º´æÖÐÄýá¹û£»
+2. »ñÈ¡µ±Ç°¶ÔÏóµÄËùÓÐÔöÇ¿£ºÕâÒ»²½¾ÍÊÇÅжÏÄÄЩÔöÇ¿¿ÉÒÔÓÃÓÚµ±Ç°¶ÔÏó£¬ÅжÏʱÏÈ»ñÈ¡µ±Ç°ÀàµÄËùÓнӿÚÓë²»°üÀ¨ Object µÄ¸¸À࣬ȻºóÖðÒ»ÅжÏÕâЩ½Ó¿ÚÓëÀàÖеķ½·¨ÊÇ·ñÂú×ãÔöÇ¿Ìõ¼þ£¬Ö»ÒªÓÐÒ»¸ö·½·¨Âú×㣬¾Í±íʾµ±Ç°¶ÔÏóÐèÒª±»´úÀí£»
+3. ´´½¨´úÀí¶ÔÏ󣺴´½¨´úÀí¶ÔÏóʱ£¬Ä¬ÈÏÇé¿öÏ£¬»á¸ù¾ÝÊÇ·ñʵÏÖÁ˽ӿÚÀ´Ñ¡ÔñʹÓà jdk ¶¯Ì¬´úÀí»¹ÊÇ cglib£¬¿ÉÓ¦ÓÃÓÚµ±Ç° bean µÄ `List` Ò²»á·â×°½ø´úÀí¶ÔÏóÖС£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4687961](https://my.oschina.net/funcy/blog/4687961) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\344\272\224\357\274\211\357\274\232cglib \344\273\243\347\220\206.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\344\272\224\357\274\211\357\274\232cglib \344\273\243\347\220\206.md"
new file mode 100644
index 0000000..412483a
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\344\272\224\357\274\211\357\274\232cglib \344\273\243\347\220\206.md"
@@ -0,0 +1,449 @@
+
+
+[ÉÏһƪÎÄÕÂ](https://my.oschina.net/funcy/blog/4696654 "ÉÏһƪÎÄÕÂ")½éÉÜÁË spring µÄ jdK ¶¯Ì¬´úÀí£¬±¾ÎÄÀ´½éÉÜ spring µÄ cglib ´úÀí¡£
+
+### 1\. cglib ´úÀí¼ò½é
+
+jdk ËäÈ»ÌṩÁ˶¯Ì¬´úÀí£¬µ«ÊǶ¯Ì¬´úÀíÓÐÒ»¸ö²»×㣺**Èç¹ûÀàûÓÐʵÏÖ½Ó¿Ú£¬¾ÍÎÞ·¨ jdk ¶¯Ì¬´úÀí**¡£ÎªÁ˽â¾öÕâ¸ö²»×㣬spring ÓÖÒýÈëÁË cglib ´úÀí¡£
+
+cglib µ×²ãÊÇ»ùÓÚ asm µÄ£¬Ò²¾ÍÊÇÖ±½Ó²Ù×÷×Ö½ÚÂ룬Ï൱ÓÚ¶Ô asm ½øÐÐÁËÒ»²ã·â×°¡£Ö±½Ó²Ù×÷×ÖÂ룬ÐèÒª¶Ô java Ö¸Áî¡¢×Ö½ÚÂëÎļþÓÐÉîÈëÀí½â²ÅÄܽøÐУ¬µ«×Ö½ÚÂë»ÞɬÄѶ®£¬Ò»°ã²»½¨ÒéÖ±½Ó²Ù×÷¡£¾ cglib ·â×°ºó£¬×Ö½ÚÂëµÄ²Ù×÷¾Í±äµÃ¼òµ¥¶àÁË£¬Òò´Ë**¾ø´ó¶àÊýÇé¿ö϶¼½¨ÒéʹÓà cglib ·â×°ºÃµÄ·½·¨À´½øÐÐ×Ö½ÚÂë²Ù×÷**¡£
+
+spring cglib ²Ù×÷λÓÚ `spring-core` Ä£¿é£º
+
+
+
+ÔÙÀ´¿´¿´ asm Óë cglib °ü˵Ã÷£º
+
+```
+/**
+ * Spring's repackaging of
+ * ASM 7.0
+ * (with Spring-specific patches; for internal use only).
+ *
+ * This repackaging technique avoids any potential conflicts with
+ * dependencies on ASM at the application level or from third-party
+ * libraries and frameworks.
+ *
+ *
As this repackaging happens at the class file level, sources
+ * and javadocs are not available here.
+ */
+ package org.springframework.asm;
+
+```
+
+×¢ÒâµÚÒ»¾ä£º`Spring's repackaging of ASM 7.0`£¬±íÃ÷ÕâÊÇ spring ¶Ô `asm7.0` ÖØÐ´ò°ü.
+
+```
+/**
+ * Spring's repackaging of
+ * CGLIB 3.3
+ * (with Spring-specific patches; for internal use only).
+ *
+ *
This repackaging technique avoids any potential conflicts with
+ * dependencies on CGLIB at the application level or from third-party
+ * libraries and frameworks.
+ *
+ *
As this repackaging happens at the class file level, sources
+ * and javadocs are not available here.
+ */
+package org.springframework.cglib;
+
+```
+
+×¢ÒâµÚÒ»¾ä£º`Spring's repackaging of CGLIB 3.3`£¬±íÃ÷ÕâÊÇ spring ¶Ô `CGLIB 3.3` ÖØÐ´ò°ü.
+
+ºÎÎ½ÖØÐ´ò°üÄØ£¿¸öÈËÀí½â£¬¾ÍÊǽ« `asm7.0` Óë `CGLIB 3.3` µÄÔ´Âë¸Ä¸ö°üÃû£¬¸´ÖƵ½ spring ÏîĿϡ£Òò´Ë spring ²¢Ã»ÓÐÔÚ `gradle` ÎļþÖÐÒýÈë `asm` Óë `cglib` µÄÏ൱ jar °ü£¬¶øÊÇÔÚÏîÄ¿ÖÐÖ±½ÓÒýÈëÁËÕâÁ½¸öÏîÄ¿µÄÔ´Â룡
+
+### 2\. cglib ´úÀíʾÀý
+
+ÔÚÕýʽ¿ªÊ¼Ö®Ç°£¬ÎÒÃÇÏÈÀ´¿´ ¿´ cglib ´úÀíÊÇÈçºÎ½øÐеġ£
+
+Ê×ÏÈ×¼±¸Ò»¸öÀࣺ
+
+```
+package org.springframework.learn.demo04;
+
+public class CglibProxyService {
+ public void hello01() {
+ System.out.println("hello01");
+ }
+}
+
+```
+
+ÔÙ×¼±¸Ò»¸ö `MethodInterceptor`£¨Àà±È jdk ¶¯Ì¬´úÀíÖÐµÄ `InvocationHandler`£©£º
+
+```
+package org.springframework.learn.demo04;
+
+import org.springframework.cglib.proxy.MethodInterceptor;
+import org.springframework.cglib.proxy.MethodProxy;
+
+import java.lang.reflect.Method;
+
+public class MyMethodInterceptor implements MethodInterceptor {
+
+ /** Ä¿±ê¶ÔÏó */
+ private Object target;
+
+ public MyMethodInterceptor(Object target){
+ this.target = target;
+ }
+
+ @Override
+ public Object intercept(Object proxyObj, Method method, Object[] objects,
+ MethodProxy proxy) throws Throwable {
+ System.out.println("Ö´Ðз½·¨Îª:" + method.getName());
+ return proxy.invoke(target, objects);
+ }
+}
+
+```
+
+×îºóÊÇÖ÷Àࣺ
+
+```
+package org.springframework.learn.demo04;
+
+import org.springframework.cglib.proxy.Enhancer;
+
+/**
+ * £ûÕâÀïÌí¼ÓÃèÊö£ý
+ *
+ * @author fangchengyan
+ * @date 2020-11-01 9:23 ÏÂÎç
+ */
+public class Demo04Main {
+
+ public static void main(String[] args) {
+ CglibProxyService target = new CglibProxyService();
+ MyMethodInterceptor interceptor = new MyMethodInterceptor(target);
+
+ Enhancer enhancer = new Enhancer();
+ // ÉèÖø¸Àà
+ enhancer.setSuperclass(CglibProxyService.class);
+ // ÉèÖÃcallback£¬Õâ¸öcallback¾ÍÊÇÉÏÃæÌṩµÄ MyMethodInterceptor
+ enhancer.setCallback(interceptor);
+ // ʹÓà enhancer ´´½¨´úÀí¶ÔÏó
+ CglibProxyService proxy = (CglibProxyService)enhancer.create();
+ proxy.hello01();
+ }
+}
+
+```
+
+ÔËÐУ¬½á¹ûÈçÏ£º
+
+```
+Ö´Ðз½·¨Îª:hello01
+hello01
+
+```
+
+¿ÉÒÔ¿´µ½£¬×îÖÕÊÇÔÚ `MyMethodInterceptor#intercept` Ö´ÐÐÄ¿±ê¶ÔÏóµÄ·½·¨¡£
+
+ͬ jdk ¶¯Ì¬´úÀí±È½Ïºó£¬·¢ÏÖÁ½Õß´úÂë¸ß¶ÈÏàËÆ£º
+
+* `InvocationHandler` Óë `InvocationHandler`£ºÁ½Õß´úÂëÐÎʽ¼¸ºõÒ»Ö 
+
+* ´úÀí¶ÔÏóµÄ´´½¨£ºÒ»¸öÊÇʹÓà `Enhangcer` ½øÐдúÀí¶ÔÏó´´½¨£¬Ò»¸öÊÇʹÓ÷â×°ºÃµÄ·½·¨½øÐжÔÏó´´½¨¡£ 
+
+´Ó´úÀí¶ÔÏó´´½¨À´¿´£¬¿ÉÒÔ¿´³ö `cglib` Éú³É¶ÔÏóʱ£¬ÅäÖõIJÎÊý½Ï¶à£¬¹¦ÄܽϷḻ¡£
+
+¹ØÓÚ `Enhangcer` ÊÇÈçºÎ´´½¨´úÀí¶ÔÏó£¬ÒÔ¼° `org.springframework.asm` Óë `org.springframework.cglib` ÕâÁ½¸ö°üϵĴúÂ룬ÕâЩÊôÓÚ cglib µÄÄÚÈÝ£¬¾Í²»¹ý¶à·ÖÎöÁË¡£
+
+### 3\. spring ÖÐ `cglib` ´´½¨´úÀí¶ÔÏó
+
+ÎÒÃÇÔÙÀ´¿´¿´ spring ÊÇÈçºÎ´´½¨´úÀí¶ÔÏóµÄ£º
+
+> CglibAopProxy#getProxy(java.lang.ClassLoader)
+
+```
+public Object getProxy(@Nullable ClassLoader classLoader) {
+ try {
+ Class> rootClass = this.advised.getTargetClass();
+ Assert.state(rootClass != null, "...");
+
+ Class> proxySuperClass = rootClass;
+ if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
+ proxySuperClass = rootClass.getSuperclass();
+ Class>[] additionalInterfaces = rootClass.getInterfaces();
+ for (Class> additionalInterface : additionalInterfaces) {
+ this.advised.addInterface(additionalInterface);
+ }
+ }
+
+ // ¶ÔÄ¿±êÀà½øÐмì²é£¬Ö÷Òª¼ì²éµãÓÐÈý¸ö£º
+ // 1\. Ä¿±ê·½·¨²»ÄÜʹÓÃfinalÐÞÊΣ»
+ // 2\. Ä¿±ê·½·¨²»ÄÜÊÇprivateÀàÐ͵ģ»
+ // 3\. Ä¿±ê·½·¨²»ÄÜÊǰü·ÃÎÊȨÏ޵ģ»
+ // ÕâÈý¸öµãÂú×ãÈκÎÒ»¸ö£¬µ±Ç°·½·¨¾Í²»Äܱ»´úÀí£¬´Ëʱ¸Ã·½·¨¾Í»á±»ÂÔ¹ý
+ validateClassIfNecessary(proxySuperClass, classLoader);
+
+ Enhancer enhancer = createEnhancer();
+ if (classLoader != null) {
+ enhancer.setClassLoader(classLoader);
+ if (classLoader instanceof SmartClassLoader &&
+ ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
+ enhancer.setUseCache(false);
+ }
+ }
+ // Superclass¾ÍÊÇÒª´úÀíµÄÀà
+ enhancer.setSuperclass(proxySuperClass);
+ // ÕâÀïAopProxyUtils.completeProxiedInterfaces()·½·¨µÄÖ÷ҪĿµÄÊÇΪҪÉú³ÉµÄ´úÀíÀà
+ // Ôö¼ÓSpringProxy£¬Advised£¬DecoratingProxyÈý¸öÐèҪʵÏֵĽӿڡ£ÕâÀïÈý¸ö½Ó¿ÚµÄ×÷ÓÃÈçÏ£º
+ // 1\. SpringProxy£ºÊÇÒ»¸ö¿Õ½Ó¿Ú£¬ÓÃÓÚ±ê¼Çµ±Ç°Éú³ÉµÄ´úÀíÀàÊÇSpringÉú³ÉµÄ´úÀíÀࣻ
+ // 2\. Advised£ºSpringÉú³É´úÀíÀàËùʹÓõÄÊôÐÔ¶¼±£´æÔڸýӿÚÖУ¬
+ // °üÀ¨Advisor£¬AdviceºÍÆäËûÏà¹ØÊôÐÔ£»
+ // 3\. DecoratingProxy£º¸Ã½Ó¿ÚÓÃÓÚ»ñÈ¡µ±Ç°´úÀí¶ÔÏóËù´úÀíµÄÄ¿±ê¶ÔÏóµÄClassÀàÐÍ¡£
+ enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
+ enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
+ enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
+
+ // Ìí¼Ócallback
+ Callback[] callbacks = getCallbacks(rootClass);
+ Class>[] types = new Class>[callbacks.length];
+ for (int x = 0; x < types.length; x++) {
+ types[x] = callbacks[x].getClass();
+ }
+ // ÉèÖôúÀíÀàÖи÷¸ö·½·¨½«ÒªÊ¹ÓõÄÇÐÃæÂß¼£¬ÕâÀïProxyCallbackFilter.accept()·½·¨·µ»Ø
+ // µÄÕûÐÍÖµÕýºÃÒ»Ò»¶ÔÓ¦ÉÏÃæCallbackÊý×éÖи÷¸öÇÐÃæÂß¼µÄϱ꣬Ҳ¾ÍÊÇ˵ÕâÀïµÄCallbackFilter
+ // µÄ×÷ÓÃÕýºÃÖ¸¶¨ÁË´úÀíÀàÖи÷¸ö·½·¨½«ÒªÊ¹ÓÃCallbackÊý×éÖеÄÄĸö»òÄöÇÐÃæÂß¼
+ enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(),
+ this.fixedInterceptorMap, this.fixedInterceptorOffset));
+ enhancer.setCallbackTypes(types);
+
+ // Éú³É´úÀí¶ÔÏó
+ return createProxyClassAndInstance(enhancer, callbacks);
+ }
+ catch (...) {
+ ...
+ }
+}
+
+```
+
+ÒÔÉÏ´úÂëºËÐÄÊÇÉèÖà `Enhancer` µÄÊôÐÔ£¬Èç `classLoader`¡¢`superclass`¡¢`callbackFilter` µÈ£¬×îºóµ÷Óà `createProxyClassAndInstance(xxx)` ´´½¨´úÀí¶ÔÏó£º
+
+> ObjenesisCglibAopProxy#createProxyClassAndInstance
+
+```
+protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
+ // ´´½¨´úÀíÀà
+ Class> proxyClass = enhancer.createClass();
+ Object proxyInstance = null;
+
+ // ¸ù¾Ý´úÀíÀ࣬ʹÓ÷´ÉäÉú³É¶ÔÏó
+ if (objenesis.isWorthTrying()) {
+ try {
+ proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
+ }
+ catch (Throwable ex) {
+ ...
+ }
+ }
+
+ if (proxyInstance == null) {
+ try {
+ Constructor> ctor = (this.constructorArgs != null ?
+ proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
+ proxyClass.getDeclaredConstructor());
+ ReflectionUtils.makeAccessible(ctor);
+ proxyInstance = (this.constructorArgs != null ?
+ ctor.newInstance(this.constructorArgs) : ctor.newInstance());
+ }
+ catch (Throwable ex) {
+ throw new AopConfigException(...);
+ }
+ }
+ // ÉèÖÃcallbackÊôÐÔ
+ // µ±ÉèÖÃÁ˶à¸ö callback ʱ£¬»áͨ¹ý CallbackFilter À´È·¶¨×îÖÕʹÓÃÄĸö callback
+ ((Factory) proxyInstance).setCallbacks(callbacks);
+ return proxyInstance;
+}
+
+```
+
+ͨ¹ýÔÚµÚ¶þ²¿·ÖµÄ `demo04` ¿ÉÒÔÖªµÀ£¬cglib ·½·¨µÄÖ´ÐУ¬»á¾¹ý `MethodInterceptor#intercept` ·½·¨µ÷Óõģ¬Ò²¾ÍÊÇ `Enhancer` µÄ `callback` ÊôÐÔ£¬Òò´Ë½ÓÏÂÀ´ÎÒÃÇÀ´¿´¿´ `callback` µÄ»ñÈ¡£¬Ïà¹Ø´úÂëλÓÚ `CglibAopProxy#getCallbacks`£º
+
+> CglibAopProxy#getCallbacks
+
+```
+private Callback[] getCallbacks(Class> rootClass) throws Exception {
+ boolean exposeProxy = this.advised.isExposeProxy();
+ boolean isFrozen = this.advised.isFrozen();
+ boolean isStatic = this.advised.getTargetSource().isStatic();
+
+ // Óû§×Ô¶¨ÒåµÄ´úÀíÂß¼µÄcallback£¬¼´¿ª·¢ÖУ¬¶¨ÒåµÄ @Before¡¢@Around¡¢@AfterµÈÇÐÃæ·½·¨£¬
+ // ½«ÔÚDynamicAdvisedInterceptor½øÐе÷ÓÃ
+ Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
+
+ Callback targetInterceptor;
+ // ÅжÏÈç¹ûÒª±©Â¶´úÀí¶ÔÏó£¬Èç¹ûÊÇ£¬ÔòʹÓÃAopContextÉèÖý«´úÀí¶ÔÏóÉèÖõ½ThreadLocalÖÐ
+ // Óû§Ôò¿ÉÒÔͨ¹ýAopContext»ñȡĿ±ê¶ÔÏó
+ if (exposeProxy) {
+ // Åжϱ»´úÀíµÄ¶ÔÏóÊÇ·ñÊǾ²Ì¬µÄ£¬Èç¹ûÊǾ²Ì¬µÄ£¬Ôò½«Ä¿±ê¶ÔÏ󻺴æÆðÀ´£¬Ã¿´Î¶¼Ê¹ÓøöÔÏó¼´¿É£¬
+ // Èç¹ûÄ¿±ê¶ÔÏóÊǶ¯Ì¬µÄ£¬ÔòÔÚDynamicUnadvisedExposedInterceptorÖÐÿ´Î¶¼Éú³ÉÒ»¸öеÄ
+ // Ä¿±ê¶ÔÏó£¬ÒÔÖ¯ÈëºóÃæµÄ´úÀíÂß¼
+ targetInterceptor = (isStatic ?
+ new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
+ new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
+ }
+ else {
+ // ÕâÀïµÄÁ½¸öÀàÓëÉÏÃæÁ½¸öµÄÎ¨Ò»Çø±ð¾ÍÔÚÓÚÊÇ·ñʹÓÃAopContext±©Â¶Éú³ÉµÄ´úÀí¶ÔÏó
+ targetInterceptor = (isStatic ?
+ new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
+ new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
+ }
+
+ // µ±Ç°CallbackÓÃÓÚ²»Óñ»´úÀíµÄ·½·¨
+ Callback targetDispatcher = (isStatic ?
+ new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
+
+ // ½«»ñÈ¡µ½µÄcallback×éװΪһ¸öÊý×é
+ Callback[] mainCallbacks = new Callback[] {
+ // Óû§×Ô¼º¶¨ÒåµÄÀ¹½ØÆ÷
+ aopInterceptor, // for normal advice
+ // ¸ù¾ÝÌõ¼þÊÇ·ñ±©Â¶´úÀí¶ÔÏóµÄÀ¹½ØÆ÷
+ targetInterceptor, // invoke target without considering advice, if optimized
+ // ²»×öÈκβÙ×÷µÄÀ¹½ØÆ÷
+ new SerializableNoOp(), // no override for methods mapped to this
+ // ÓÃÓÚ´æ´¢Advised¶ÔÏóµÄ·Ö·¢Æ÷
+ targetDispatcher, this.advisedDispatcher,
+ // Õë¶Ôequals·½·¨µ÷ÓõÄÀ¹½ØÆ÷
+ new EqualsInterceptor(this.advised),
+ // Õë¶Ôhashcode·½·¨µ÷ÓõÄÀ¹½ØÆ÷
+ new HashCodeInterceptor(this.advised)
+ };
+
+ Callback[] callbacks;
+
+ // Èç¹ûÄ¿±ê¶ÔÏóÊǾ²Ì¬µÄ£¬²¢ÇÒÇÐÃæÂß¼µÄµ÷ÓÃÁ´Êǹ̶¨µÄ£¬Ôò¶ÔÄ¿±ê¶ÔÏóºÍÕû¸öµ÷ÓÃÁ´½øÐлº´æ
+ if (isStatic && isFrozen) {
+ Method[] methods = rootClass.getMethods();
+ Callback[] fixedCallbacks = new Callback[methods.length];
+ this.fixedInterceptorMap = new HashMap<>(methods.length);
+
+ for (int x = 0; x < methods.length; x++) {
+ Method method = methods[x];
+ // »ñȡĿ±ê¶ÔÏóµÄÇÐÃæÂß¼
+ List chain = this.advised
+ .getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
+ fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
+ chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
+ // ¶Ôµ÷ÓÃÁ´½øÐлº´æ
+ this.fixedInterceptorMap.put(method, x);
+ }
+
+ // ½«Éú³ÉµÄ¾²Ì¬µ÷ÓÃÁ´´æÈëCallbackÊý×éÖÐ
+ callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
+ System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
+ System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
+ // ÕâÀïfixedInterceptorOffset¼Ç¼Á˵±Ç°¾²Ì¬µÄµ÷ÓÃÁ´µÄÇÐÃæÂß¼µÄÆðʼλÖã¬
+ // ÕâÀï¼Ç¼µÄÓô¦ÔÚÓÚºóÃæÊ¹ÓÃCallbackFilterµÄʱºò£¬Èç¹û·¢ÏÖÊǾ²Ì¬µÄµ÷ÓÃÁ´£¬
+ // ÔòÖ±½Óͨ¹ý¸Ã²ÎÊý»ñÈ¡ÏàÓ¦µÄµ÷ÓÃÁ´£¬¶øÖ±½ÓÂÔ¹ýÁËÇ°ÃæµÄ¶¯Ì¬µ÷ÓÃÁ´
+ this.fixedInterceptorOffset = mainCallbacks.length;
+ }
+ else {
+ callbacks = mainCallbacks;
+ }
+ return callbacks;
+}
+
+```
+
+ÒÔÉÏ´úÂë±È½Ï³¤£¬Ö÷Òª×÷ÓþÍÊÇ»ñÈ¡ `callback`£¬ËäÈ» spring ÌṩÁËÖÚ¶à `callback`£¬µ«ÓëÎÒÃÇ×Ô¶¨Òå֪ͨÏà¹ØµÄ callback Ö»ÓÐÒ»¸ö£º `DynamicAdvisedInterceptor`£¬ÔÚÕâ¸ö `callback` µÄ `CglibAopProxy.DynamicAdvisedInterceptor#intercept` ·½·¨ÖУ¬ÎÒÃÇÔÚ´úÂëÖеÄ×Ô¶¨Í¨Öª¾ÍÊÇÔÚÕâÀïÖ´Ðеġ£
+
+ÕâÒ»²½ÎÒÃǵõ½ cglib µÄ´úÀí¶ÔÏóºó£¬½ÓÏÂÀ´¾ÍÀ´¿´¿´ÇÐÃæ·½·¨ÊÇÈçºÎÖ´Ðеġ£
+
+### 4\. cglib ÇÐÃæ·½·¨µÄÖ´ÐÐ
+
+cglib ÇÐÃæ·½·¨µÄÖ´ÐÐ `CglibAopProxy.DynamicAdvisedInterceptor#intercept` ·½·¨£º
+
+> `CglibAopProxy.DynamicAdvisedInterceptor#intercept`
+
+```
+public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)
+ throws Throwable {
+ Object oldProxy = null;
+ boolean setProxyContext = false;
+ Object target = null;
+ // ͨ¹ýTargetSource»ñȡĿ±ê¶ÔÏó
+ TargetSource targetSource = this.advised.getTargetSource();
+ try {
+ // ÅжÏÈç¹ûÐèÒª±©Â¶´úÀí¶ÔÏó£¬Ôò½«µ±Ç°´úÀí¶ÔÏóÉèÖõ½ThreadLocalÖÐ
+ if (this.advised.exposeProxy) {
+ oldProxy = AopContext.setCurrentProxy(proxy);
+ setProxyContext = true;
+ }
+ target = targetSource.getTarget();
+ Class> targetClass = (target != null ? target.getClass() : null);
+ // »ñȡĿ±ê¶ÔÏóÇÐÃæÂß¼µÄµ÷ÓÃÁ´
+ List chain = this.advised
+ .getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
+ Object retVal;
+ if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
+ Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
+ // ûÓÐÀ¹½ØÆ÷£¬Ö±½Óµ÷ÓÃÄ¿±ê¶ÔÏóµÄ·½·¨
+ retVal = methodProxy.invoke(target, argsToUse);
+ }
+ else {
+ // ÕâÀïÓÐÁ½¸ö²½Ö裺
+ // 1\. ´´½¨Ö´ÐÐÆ÷£ºnew CglibMethodInvocation()
+ // 2\. Ö´ÐÐÀ¹½ØÆ÷Á´£ºCglibMethodInvocation#proceed
+ retVal = new CglibMethodInvocation(proxy, target, method, args,
+ targetClass, chain, methodProxy).proceed();
+ }
+ // ¶Ô·µ»ØÖµ½øÐд¦Àí£¬Èç¹û·µ»ØÖµ¾ÍÊǵ±Ç°Ä¿±ê¶ÔÏó£¬ÄÇô½«´úÀíÉú³ÉµÄ´úÀí¶ÔÏ󷵻أ»
+ // Èç¹û·µ»ØÖµÎª¿Õ£¬²¢ÇÒ·µ»ØÖµÀàÐÍÊÇ·ÇvoidµÄ»ù±¾Êý¾ÝÀàÐÍ£¬ÔòÅ׳öÒì³££»
+ // Èç¹ûÉÏÊöÁ½¸öÌõ¼þ¶¼²»·ûºÏ£¬ÔòÖ±½Ó½«Éú³ÉµÄ·µ»ØÖµ·µ»Ø
+ retVal = processReturnType(proxy, target, method, retVal);
+ return retVal;
+ }
+ finally {
+ if (target != null && !targetSource.isStatic()) {
+ targetSource.releaseTarget(target);
+ }
+ if (setProxyContext) {
+ AopContext.setCurrentProxy(oldProxy);
+ }
+ }
+}
+
+```
+
+×îÖÕÖ´ÐÐÊÇÔÚ `new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed()`£¬¼ÌÐø¿´ÏÂÈ¥£º
+
+> CglibAopProxy.CglibMethodInvocation#proceed
+
+```
+public Object proceed() throws Throwable {
+ try {
+ return super.proceed();
+ }
+ catch (...) {
+ ....
+ }
+}
+
+```
+
+Ö±½Óµ÷ÓõÄÊǸ¸ÀàµÄ·½·¨£¬`CglibAopProxy.CglibMethodInvocation` µÄ¸¸ÀàÊÇËÄØ£¿Ò»¿´ÏÂÈ¥£¬·¢ÏÖ¾¹È»ÊÇ `ReflectiveMethodInvocation`£¬`super.proceed()` µ÷ÓõÄÊÇ `ReflectiveMethodInvocation#proceed`£¡
+
+ÔÚ[ÉÏÒ» ƪÎÄÕÂ](https://my.oschina.net/funcy/blog/4696654 "ÉÏÒ» ƪÎÄÕÂ")ÖУ¬ÎÒÃǾÍÏêϸ·ÖÎöÁË `ReflectiveMethodInvocation#proceed` µÄµ÷Óùý³Ì£¬¶øÏÖÔÚ£¬ÔÚ cglib ´úÀíÀ×îÖÕÖ´ÐеÄÒ²ÊÇͬÑùµÄ´úÂ룬ÕâÒ»¿éµÄÖ´Ðйý³Ì¾Í²»Öظ´·ÖÎöÁË¡£
+
+×îºóÓÃÒ»ÕÅͼÀ´ËµÃ÷ÇÐÃæÍ¨ÖªµÄÖ´Ðйý³Ì£º
+
+
+
+×îÖÕµÄÖ´ÐÐ˳Ðò£º
+
+
+
+### 5\. ×ܽá
+
+±¾ÎÄ·ÖÎöÁË cglib ´úÀíµÄÖ´Ðйý³Ì£¬ÇÐÃæµÄÖ´ÐÐÁ÷³ÌλÓÚ `CglibAopProxy.DynamicAdvisedInterceptor#intercept`£¬×îÖÕµ÷ÓõÄÊÇ `ReflectiveMethodInvocation#proceed`£¬ÕâÓë jdk ¶¯Ì¬´úÀíµÄÖ´ÐÐÁ÷³ÌÏàͬ¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4696655](https://my.oschina.net/funcy/blog/4696655) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\345\205\255\357\274\211\357\274\232aop \346\200\273\347\273\223.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\345\205\255\357\274\211\357\274\232aop \346\200\273\347\273\223.md"
new file mode 100644
index 0000000..041e629
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\345\205\255\357\274\211\357\274\232aop \346\200\273\347\273\223.md"
@@ -0,0 +1,22 @@
+Ç°Ãæ¼¸ÆªÎÄÕÂÎÒÃÇ·ÖÎöÁË spring aop µÄÏà¹Ø´úÂ룬ÕâÀïÀ´×ö¸ö×ܽᡣ
+
+### 1\. spring ÆôÓà aop ¹¦ÄÜ
+
+ÔÚ [spring aop£¨Ò»£©£ºÊ¾Àý demo ¼° @EnableAspectJAutoProxy](https://my.oschina.net/funcy/blog/4678093 "spring aop£¨Ò»£©£ºÊ¾Àý demo ¼° @EnableAspectJAutoProxy") Ò»ÎÄÖУ¬ÎÒÃÇ·ÖÎöÁË spring ͨ¹ý `@EnableAspectJAutoProxy` ×¢½âÆôÓà aop ¹¦ÄÜ£¬¶øÕâ¸ö×¢½âʵ¼ÊÉÏÊÇÏò spring Öе¼ÈëÁË `AnnotationAwareAspectJAutoProxyCreator`£¬¶øÕâ¸öÀàÊÇÒ»¸ö `BeanPostProcessor`£¬×îÖÕÔÚ bean ³õʼ»¯Ç°ºóÍê³É´úÀí¶ÔÏóµÄÉú³É¡£
+
+### 2\. ´úÀí¶ÔÏóµÄÉú³É
+
+spring aop »ùÓÚ×¢½â·½Ê½µÄʵÏÖÊÇͨ¹ý `AnnotationAwareAspectJAutoProxyCreator` ÀàÀ´²Ù×÷µÄ£¬Õâ¸öÀàÊÇÒ»¸ö `BeanPostProcessor`£¬ÔÚ bean µÄ³õʼ»¯Ç°ºóÖ´ÐеIJÙ×÷ÈçÏ£º
+
+
+
+### 3\. ÇÐÃæ·½·¨µÄÖ´ÐÐ
+
+µ±µ÷ÓôúÀí¶ÔÏóµÄ·½·¨£¬jdk »á¸ù¾Ý´úÀíµÄÀàÐͶøÑ¡ÔñÖ´ÐÐ `InvocationHandler#invoke`(jdk ¶¯Ì¬´úÀí) »¹ÊÇ `MethodInterceptor#intercept`(cglib ´úÀí)£¬ÕâÒ»²½ÔÚ´´½¨´úÀí¶ÔÏóʱ£¬ÒѾÓë´úÀí¶ÔÏó½áºÏÁË£¬¿ª·¢ÕßÎÞ·¨¸ÉÉæµ÷ÓÃÄĸö·½·¨£¬²»¹ýÕâÁ½¸ö·½·¨ÀïµÄÄÚÈÝ¿ª·¢Õß¿ÉÒÔ×ÔÓÉ·¢»Ó¡£ÔÚÕâÁ½¸ö·½·¨ÖУ¬spring »á»ñÈ¡¿ÉÓÃÓõ±Ç°·½·¨µÄËùÓÐ Advisors£¬È»ºóÖ´ÐÐ Advisors ÀïµÄÇÐÃæ·½·¨£¬Õû¸ö¹ý³ÌÈçÏ£º
+
+ 
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4701587](https://my.oschina.net/funcy/blog/4701587) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
+
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\345\233\233\357\274\211\357\274\232jdk \345\212\250\346\200\201\344\273\243\347\220\206.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\345\233\233\357\274\211\357\274\232jdk \345\212\250\346\200\201\344\273\243\347\220\206.md"
new file mode 100644
index 0000000..c2965a5
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/SpringAOP/spring aop\357\274\210\345\233\233\357\274\211\357\274\232jdk \345\212\250\346\200\201\344\273\243\347\220\206.md"
@@ -0,0 +1,742 @@
+
+
+ÉÏһƪÎÄÕµÄ×îºó£¬ÎÒÃÇ·ÖÎöµ½ spring ÖÕÓÚ´´½¨ÁË´úÀí¶ÔÏ󣬯äÖдúÀí¶ÔÏóµÄ·½Ê½Îª `jdk¶¯Ì¬´úÀí`Óë `cglib´úÀí`£¬±¾ÎÄÎÒÃǽ«·ÖÎö spring µÄ¶¯Ì¬´úÀí¡£
+
+### 1. jdk ¶¯Ì¬´úÀí½éÉÜ
+
+À´·ÖÎö spring µÄ¶¯Ì¬´úÀíǰ£¬ÎÒÃÇÏÈÀ´Á˽âÏ jdk µÄ¶¯Ì¬´úÀí¡£jdk ¶¯Ì¬´úÀíÐèÒª½Ó¿Ú£¬Îª´ËÎÒÃÇÏÈ×¼±¸Á½¸ö½Ó¿Ú£º
+
+> IJdkDynamicProxy01
+
+```java
+package org.springframework.learn.demo03;
+
+public interface IJdkDynamicProxy01 {
+ void hello01();
+}
+```
+
+> IJdkDynamicProxy02
+
+```java
+package org.springframework.learn.demo03;
+
+public interface IJdkDynamicProxy02 {
+ void hello02();
+}
+```
+
+ÔÙÀ´×¼±¸Á½¸öʵÏÖÀࣺ
+
+> JdkDynamicProxyImpl01
+
+```java
+package org.springframework.learn.demo03;
+
+public class JdkDynamicProxyImpl01 implements IJdkDynamicProxy01, IJdkDynamicProxy02{
+ @Override
+ public void hello01() {
+ System.out.println("hello01");
+ }
+
+ @Override
+ public void hello02() {
+ System.out.println("hello02");
+ }
+}
+```
+
+> JdkDynamicProxyImpl02
+
+```java
+package org.springframework.learn.demo03;
+
+public class JdkDynamicProxyImpl02 implements IJdkDynamicProxy01 {
+
+ @Override
+ public void hello01() {
+ System.out.println("hello01");
+ }
+
+}
+```
+
+ÕâÀïÐèҪעÒâµÄÊÇ£¬`JdkDynamicProxyImpl01` ʵÏÖÁË `IJdkDynamicProxy01` Óë `IJdkDynamicProxy02` Á½¸ö½Ó¿Ú£¬`JdkDynamicProxyImpl02` ֻʵÏÖÁË `IJdkDynamicProxy01` Ò»¸ö ½Ó¿Ú¡£
+
+½Ó×Å×¼±¸Ò»¸ö `InvocationHandler`:
+
+> MyInvocationHandler
+
+```java
+package org.springframework.learn.demo03;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+public class MyInvocationHandler implements InvocationHandler {
+
+ /** Ä¿±ê¶ÔÏó */
+ private Object target;
+
+ public MyInvocationHandler(Object target){
+ this.target = target;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ System.out.println("Ö´Ðз½·¨Îª:" + method.getName());
+ // ·½·¨µÄÕæÕýÖ´ÐÐÔÚÕâÀï
+ Object rs = method.invoke(target,args);
+ return rs;
+ }
+
+}
+```
+
+×îºóÊÇÖ÷Àà:
+
+```java
+package org.springframework.learn.demo03;
+
+import java.lang.reflect.Proxy;
+
+public class Demo03Main {
+
+ public static void main(String[] args) {
+ System.out.println("------------bean01------------");
+ JdkDynamicProxyImpl01 bean01 = new JdkDynamicProxyImpl01();
+ Object obj1 = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
+ // JdkDynamicProxyImpl01ʵÏÖÁË IJdkDynamicProxy01, IJdkDynamicProxy02
+ // ´«ÈëµÄclassΪ IJdkDynamicProxy01, IJdkDynamicProxy02
+ new Class>[]{ IJdkDynamicProxy01.class, IJdkDynamicProxy02.class },
+ new MyInvocationHandler(bean01));
+ // ¿ÉÒÔ½øÐÐÀàÐÍÇ¿ÖÆ×ª»»
+ ((IJdkDynamicProxy01) obj1).hello01();
+ ((IJdkDynamicProxy02) obj1).hello02();
+
+ System.out.println("------------bean01------------");
+ Object obj2 = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
+ // JdkDynamicProxyImpl01ʵÏÖÁË IJdkDynamicProxy01, IJdkDynamicProxy02
+ // ´«ÈëµÄclassΪ IJdkDynamicProxy01
+ new Class>[]{ IJdkDynamicProxy01.class },
+ new MyInvocationHandler(bean01));
+ ((IJdkDynamicProxy01) obj2).hello01();
+ // ±¨Òì³££ºjava.lang.ClassCastException: class com.sun.proxy.$Proxy1 cannot be cast to class xxx
+ //((IJdkDynamicProxy02) obj2).hello02();
+
+ System.out.println("-----------bean02-------------");
+ JdkDynamicProxyImpl02 bean02 = new JdkDynamicProxyImpl02();
+ Object obj3 = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
+ // JdkDynamicProxyImpl01ʵÏÖÁË IJdkDynamicProxy01
+ // ´«ÈëµÄclassΪ IJdkDynamicProxy01, IJdkDynamicProxy02
+ new Class>[]{ IJdkDynamicProxy01.class, IJdkDynamicProxy02.class },
+ new MyInvocationHandler(bean02));
+ ((IJdkDynamicProxy01) obj3).hello01();
+ IJdkDynamicProxy02 proxy02 = (IJdkDynamicProxy02) obj3;
+ // ±¨Òì³££ºjava.lang.IllegalArgumentException: object is not an instance of declaring class
+ //proxy02.hello02();
+
+ }
+}
+```
+
+ÔËÐнá¹û£º
+
+```
+Ö´Ðз½·¨Îª:hello01
+hello01
+Ö´Ðз½·¨Îª:hello02
+hello02
+------------bean01------------
+Ö´Ðз½·¨Îª:hello01
+hello01
+-----------bean02-------------
+Ö´Ðз½·¨Îª:hello01
+hello01
+```
+
+¶Ô½á¹û·ÖÎöÈçÏ£º
+
+1. `Proxy#newProxyInstance(ClassLoader, Class>[], InvocationHandler)` µÄµÚ¶þ¸ö²ÎÊý´«ÈëµÄ½Ó¿Ú£¬ÉùÃ÷µÄÊÇ´úÀí¶ÔÏóËùÊôµÄ½Ó¿ÚÀàÐÍ£¬µÚÈý¸ö²ÎÊýÊÇÖ´ÐÐÆ÷£¬´úÀíÀà¶ÔÏóµÄÖ´ÐÐΪÆä `invoke()` ·½·¨£»
+2. `JdkDynamicProxyImpl01` ͬʱʵÏÖÁË `IJdkDynamicProxy01` Óë `IJdkDynamicProxy02` ½Ó¿Ú£¬µ«´«Èë½Ó¿ÚÀàÐÍʱ£¬Ö»´«ÈëÁË `IJdkDynamicProxy01`£¬µ±´úÀí¶ÔÏó obj2 ǿתΪ `IJdkDynamicProxy02` ʱ£¬¾Í»á±¨ `ClassCastException`£¬Ç¿×ªÊ§°Ü£¬Õâ±íÃ÷ `Proxy#newProxyInstance(ClassLoader, Class>[], InvocationHandler)` ÉùÃ÷µÄÊÇ´úÀí¶ÔÏóËùÊôµÄ½Ó¿ÚÀàÐÍ£»
+3. `JdkDynamicProxyImpl02` ֻʵÏÖÁË `IJdkDynamicProxy01` ½Ó¿Ú£¬µ«´«Èë½Ó¿ÚÀàÐÍʱ£¬´«ÈëÁË `IJdkDynamicProxy01` Óë `IJdkDynamicProxy02`£¬µ±´úÀí¶ÔÏó `obj3` ǿתΪ `IJdkDynamicProxy02` ʱ£¬²¢Î´±¨Òì³££¬µ«ÊÇÔÚÖ´ÐÐ `proxy02.hello02()` ʱ£¬È´±¨ÁË `java.lang.IllegalArgumentException: object is not an instance of declaring class`£¬Í¬Ñù±íÃ÷ÁË `Proxy#newProxyInstance(ClassLoader, Class>[], InvocationHandler)` ÉùÃ÷µÄÊÇ´úÀí¶ÔÏóËùÊôµÄ½Ó¿ÚÀàÐÍ£¬¸úÄ¿±ê¶ÔÏóµÄÀàÐÍÎ޹ء£
+
+### 2. ÔٴηÖÎö spring jdk ¶¯Ì¬´úÀí¶ÔÏóµÄ´´½¨
+
+ÓÐÁËÉÏÃæµÄ·ÖÎö£¬ÎÒÃÇÔÙÀ´¿´¿´ spring ÊÇÈçºÎ´´½¨´úÀí¶ÔÏóµÄ£º
+
+```java
+@Override
+public Object getProxy(@Nullable ClassLoader classLoader) {
+ // »ñȡĿ±ê¶ÔÏóʵÏֵĽӿÚ
+ Class>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
+ // ÊÇ·ñÓÐequals()ÓëhashCode()·½·¨
+ findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
+ // µ÷Óà jdk ·½·¨ ´´½¨¶ÔÏó
+ return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
+}
+```
+
+1. ´«ÈëµÄ½Ó¿ÚΪ `proxiedInterfaces`£¬Õâ¸öÖµ°üº¬ÁËÄ¿±êÀàʵÏÖµÄËùÓнӿڣ¬Í¬Ê± spring Ò²»áÌí¼Ó×ÔÉíµÄ½Ó¿Ú£¬Èç `SpringProxy`¡¢`Advised`£¬ÕâЩÔÚÉÏһƪÎÄÕÂÒѾÏêϸ·ÖÎö¹ýÁË£»
+2. Ö¸¶¨ `InvocationHandler` Ϊ `this`£¬Ò²¾ÍÊÇ `JdkDynamicAopProxy` µÄ¶ÔÏó£¬Êµ¼ÊÉÏ `JdkDynamicAopProxy` ʵÏÖÁË `InvocationHandler`.
+
+ÓɵÚÒ»²¿·ÖµÄ·ÖÎö¿ÉÖª£¬jdk ¶¯Ì¬´úÀí¶ÔÏóµÄ·½·¨×îÖÕÊÇÔÚ `java.lang.reflect.InvocationHandler#invoke` ÖÐÖ´Ðеģ¬Ò²¾ÍÊÇ `JdkDynamicAopProxy#invoke`£¬½ÓÏÂÀ´ÎÒÃǾÍÀ´·ÖÎö `JdkDynamicAopProxy#invoke` ·½·¨£¬À´¿´¿´ spring ÊÇÈçºÎÖ´ÐдúÀí·½·¨µÄ¡£
+
+### 3. jdk ¶¯Ì¬´úÀí·½·¨µÄÖ´ÐÐ
+
+spring jdk ¶¯Ì¬´úÀí·½·¨µÄÖ´ÐÐÔÚ `JdkDynamicAopProxy#invoke`£º
+
+> JdkDynamicAopProxy#invoke
+
+```java
+public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ Object oldProxy = null;
+ boolean setProxyContext = false;
+
+ TargetSource targetSource = this.advised.targetSource;
+ Object target = null;
+
+ try {
+ // ÈôÖ´ÐÐµÄ equals ·½·¨£¬²»ÐèÒª´úÀíÖ´ÐÐ
+ if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
+ return equals(args[0]);
+ }
+ // ÈôÖ´ÐÐµÄ hashCode ·½·¨£¬²»ÐèÒª´úÀíÖ´ÐÐ
+ else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
+ return hashCode();
+ }
+ // Èç¹ûÖ´ÐеÄclass¶ÔÏóÊÇDecoratingProxy£¬Ò²²»ÐèÒª´úÀíÖ´ÐÐ
+ else if (method.getDeclaringClass() == DecoratingProxy.class) {
+ return AopProxyUtils.ultimateTargetClass(this.advised);
+ }
+ else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
+ method.getDeclaringClass().isAssignableFrom(Advised.class)) {
+ return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
+ }
+
+ Object retVal;
+
+ // ÅÐ¶Ï advisedµÄexposeProxy ÖµÊÇ·ñΪ true
+ // advisedµÄexposeProxyÀ´Ô´ÓÚ @EnableAspectJAutoProxy µÄ exposeProxy
+ // ¼´ ÏñÕâÑùÖ¸¶¨Ê±£¬@EnableAspectJAutoProxy(exposeProxy = true)£¬ÒÔÏ´úÂëÖ´ÐÐ
+ if (this.advised.exposeProxy) {
+ // ½«µ±Ç°µÄ proxy ¶ÔÏó·Åµ½ threadLocal ÖÐ
+ // ºóÐø¿ÉÒÔ (UserService (AopContext.currentProxy)).getUser() ·½Ê½µ÷ÓÃ
+ oldProxy = AopContext.setCurrentProxy(proxy);
+ setProxyContext = true;
+ }
+
+ // »ñȡĿ±ê¶ÔÏó¼°Ä¿±ê¶ÔÏóµÄclass
+ target = targetSource.getTarget();
+ Class> targetClass = (target != null ? target.getClass() : null);
+
+ // ½« aop µÄ advisor ת»¯ÎªÀ¹½ØÆ÷£¬ÔÚÕâÀïÅжϸ÷½·¨¿ÉÒÔʹÓÃÄÄЩÇÐÃæ·½·¨
+ List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(
+ method, targetClass);
+ if (chain.isEmpty()) {
+ // Èç¹û¼ÓÈëµÄÀ¹½ØÆ÷Á´Îª¿Õ£¬±íÃ÷¸Ã·½·¨Ã»Óб»À¹½Ø£¬Í¨¹ý·´ÉäÖ±½ÓÖ´ÐÐ
+ Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
+ retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
+ }
+ else {
+ // ´´½¨Ò»¸ö·½·¨µ÷ÓöÔÏó
+ MethodInvocation invocation =
+ new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
+ // µ÷ÓÃÖ´ÐУ¬Öصã
+ retVal = invocation.proceed();
+ }
+
+ Class> returnType = method.getReturnType();
+ if (retVal != null && retVal == target &&
+ returnType != Object.class && returnType.isInstance(proxy) &&
+ !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
+ retVal = proxy;
+ }
+ else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
+ throw new AopInvocationException(...);
+ }
+ return retVal;
+ }
+ finally {
+ if (target != null && !targetSource.isStatic()) {
+ targetSource.releaseTarget(target);
+ }
+ if (setProxyContext) {
+ AopContext.setCurrentProxy(oldProxy);
+ }
+ }
+}
+```
+
+ÒÔÉÏ·½·¨Á÷³ÌÈçÏ£º
+
+1. ÅжÏÒªÖ´Ðеķ½·¨ÊÇ·ñΪ `equals`¡¢`hashcode` µÈ£¬ÕâЩ·½·¨²»ÐèÒª´úÀí£»
+2. »ñÈ¡¿ÉÓÃÓÚÒªÖ´Ðеķ½·¨µÄËùÓÐÇÐÃæ·½·¨£¬µÃµ½Ò»¸öÀ¹½ØÆ÷¼¯ºÏ£»
+3. µ÷ÓÃÇÐÃæ·½·¨¼¯ºÏÓë¼°Ä¿±ê·½·¨¡£
+
+ÕâÀïÎÒÃÇÖØµã¹Ø×¢ÇÐÃæ·½·¨ÓëÄ¿±ê·½·¨µÄÖ´ÐУ¬¹Ø¼ü´úÂëÈçÏ£º
+
+```java
+// ½« aop µÄ advisor ת»¯ÎªÀ¹½ØÆ÷£¬ÔÚÕâÀïÅжϸ÷½·¨¿ÉÒÔʹÓÃÄÄЩÇÐÃæ·½·¨
+List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(
+ method, targetClass);
+// ´´½¨Ò»¸ö·½·¨µ÷ÓöÔÏó
+MethodInvocation invocation =
+ new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
+// µ÷ÓÃÖ´ÐУ¬Öصã
+retVal = invocation.proceed();
+```
+
+#### »ñÈ¡ `MethodInterceptor`
+
+ÔÚ·ÖÎö·½·¨µÄÖ´ÐÐǰ£¬ÎÒÃÇÏÈÀ´¿´¿´ `getInterceptorsAndDynamicInterceptionAdvice(...)`£¬Õâ¸ö·½·¨ÊÇÓÃÀ´»ñȡִÐеÄÇÐÃæ·½·¨µÄ£¬Ò²¾ÍÊÇ `MethodInterceptor`£º
+
+> AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
+
+```java
+public List getInterceptorsAndDynamicInterceptionAdvice(Method method,
+ @Nullable Class>targetClass) {
+ MethodCacheKey cacheKey = new MethodCacheKey(method);
+ List cached = this.methodCache.get(cacheKey);
+ if (cached == null) {
+ // ÔÚÕâ¸ö·½·¨Àï¼ÌÐø»ñÈ¡£¬ÏÂÃæ»áÔÙ·ÖÎö
+ cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
+ this, method, targetClass);
+ this.methodCache.put(cacheKey, cached);
+ }
+ return cached;
+}
+```
+
+¼ÌÐø£¬
+
+```java
+/**
+ * »ñÈ¡ Interceptor£¬¹ý³ÌÈçÏ£º
+ */
+@Override
+public List getInterceptorsAndDynamicInterceptionAdvice(
+ Advised config, Method method, @Nullable Class> targetClass) {
+ AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
+ // »ñÈ¡ advisors£¬aopµÄadvisorsÈçÏ£º
+ Advisor[] advisors = config.getAdvisors();
+ List interceptorList = new ArrayList<>(advisors.length);
+ Class> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
+ Boolean hasIntroductions = null;
+ for (Advisor advisor : advisors) {
+ // Èç¹ûadvisorÊÇPointcutAdvisor£¬ÔòʹÓÃPointcutAdvisorÀïµÄPointcut½øÐÐÆ¥Åä
+ if (advisor instanceof PointcutAdvisor) {
+ PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
+ // ÕâÀïÅжÏÇÐÃæÂß¼µÄµ÷ÓÃÁ´ÊÇ·ñÌáǰ½øÐйý¹ýÂË£¬Èç¹û½øÐйý£¬Ôò²»ÔÙ½øÐÐÄ¿±ê·½·¨µÄÆ¥Å䣬
+ // Èç¹ûûÓУ¬ÔòÔÙ½øÐÐÒ»´ÎÆ¥Åä¡£
+ if (config.isPreFiltered()
+ || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
+ MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
+ boolean match;
+ if (mm instanceof IntroductionAwareMethodMatcher) {
+ if (hasIntroductions == null) {
+ hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
+ }
+ match = ((IntroductionAwareMethodMatcher) mm)
+ .matches(method, actualClass, hasIntroductions);
+ }
+ else {
+ match = mm.matches(method, actualClass);
+ }
+ if (match) {
+ // ½«Advisor¶ÔÏóת»»ÎªMethodInterceptorÊý×é
+ MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
+ if (mm.isRuntime()) {
+ for (MethodInterceptor interceptor : interceptors) {
+ // ½« interceptorÓëmethodMatcher°ü×°³ÉInterceptorAndDynamicMethodMatcher
+ interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
+ }
+ }
+ else {
+ interceptorList.addAll(Arrays.asList(interceptors));
+ }
+ }
+ }
+ }
+ else if (advisor instanceof IntroductionAdvisor) {
+ // ÅжÏÈç¹ûΪIntroductionAdvisorÀàÐ͵ÄAdvisor£¬Ôò½«µ÷ÓÃÁ´·âװΪInterceptorÊý×é
+ IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
+ if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
+ Interceptor[] interceptors = registry.getInterceptors(advisor);
+ interceptorList.addAll(Arrays.asList(interceptors));
+ }
+ }
+ else {
+ // ÕâÀïÊÇÌṩµÄʹÓÃ×Ô¶¨ÒåµÄת»»Æ÷¶ÔAdvisor½øÐÐת»»µÄÂß¼£¬ÒòΪgetInterceptors()·½·¨ÖÐ
+ // »áʹÓÃÏàÓ¦µÄAdapter¶ÔÄ¿±êAdvisor½øÐÐÆ¥Å䣬Èç¹ûÄÜÆ¥ÅäÉÏ£¬Í¨¹ýÆägetInterceptor()·½·¨
+ // ½«×Ô¶¨ÒåµÄAdviceת»»ÎªMethodInterceptor¶ÔÏó
+ Interceptor[] interceptors = registry.getInterceptors(advisor);
+ interceptorList.addAll(Arrays.asList(interceptors));
+ }
+ }
+ return interceptorList;
+}
+```
+
+ÎÒÃǸù¾ÝÒÔÉÏ·½·¨À´×ܽáÏ»ñÈ¡ `MethodInterceptor` µÄ¹ý³Ì¹ý³ÌÈçÏ£º
+
+1. »ñÈ¡ÏîÄ¿ÖÐËùÓÐµÄ `advisors`
+
+2. ±éÀú£¬¶Ôÿ¸ö
+
+
+
+ ```
+ advisor
+ ```
+
+
+
+¼ÌÐø°´ÒÔÏÂÁ÷³Ì´¦Àí£º
+
+1. Èç¹û `advisor` ÊÇ `PointcutAdvisor`£¬ÔòʹÓÃÆäÖÐµÄ `Pointcut` ½øÐÐÆ¥Å䣬ƥÅä³É¹¦ºó£¬»ñÈ¡ `MethodInterceptor` ·µ»Ø£»
+2. Èç¹û `advisor` ÊÇ `IntroductionAdvisor`£¬ÔòʹÓÃÆäÖÐµÄ `ClassFilter` ½øÐÐÆ¥Å䣬ƥÅä³É¹¦ºó£¬»ñÈ¡ `MethodInterceptor` ·µ»Ø£»
+3. Èç¹ûÒÔÉÏÌõ¼þ²»Âú×㣬ֱ½Ó»ñÈ¡ `MethodInterceptor` ·µ»Ø£»
+
+ÄÇô `MethodInterceptor` ÊÇÈçºÎ»ñÈ¡µÄÄØ£¿ÎÒÃǼÌÐøÍùÏ¿´£º
+
+```java
+// ´æ·Å AdvisorAdapter µÄµØ·½
+private final List adapters = new ArrayList<>(3);
+
+// Ìí¼Ó adapter
+public DefaultAdvisorAdapterRegistry() {
+ // @Before
+ registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
+ // @AfterReturning
+ registerAdvisorAdapter(new AfterReturningAdviceAdapter());
+ // @AfterThrowing
+ registerAdvisorAdapter(new ThrowsAdviceAdapter());
+}
+
+/**
+ * »ñÈ¡advisor¶ÔÓ¦µÄMethodInterceptor
+ */
+@Override
+public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
+ List interceptors = new ArrayList<>(3);
+ // »ñÈ¡µ±Ç°advisorÀïµÄMethodInterceptor
+ Advice advice = advisor.getAdvice();
+ // Èç¹û advice ÊÇ MethodInterceptorµÄʵÀý£¬Ìí¼Ó
+ if (advice instanceof MethodInterceptor) {
+ interceptors.add((MethodInterceptor) advice);
+ }
+ //
+ // ʹÓà AdvisorAdapter ½« advice ת»»Îª MethodInterceptor
+ // Èç¹ûadviceÂú×ãadapter£¬µ÷Óà adapter.getInterceptor »ñÈ¡ MethodInterceptor
+ for (AdvisorAdapter adapter : this.adapters) {
+ if (adapter.supportsAdvice(advice)) {
+ interceptors.add(adapter.getInterceptor(advisor));
+ }
+ }
+ if (interceptors.isEmpty()) {
+ throw new UnknownAdviceTypeException(advisor.getAdvice());
+ }
+ return interceptors.toArray(new MethodInterceptor[0]);
+}
+```
+
+¶ÔÕâ¸ö·½·¨µÄÁ÷³Ì×ܽáÈçÏ£º
+
+1. Èç¹û `advice` ÊÇ `MethodInterceptor`£¬Ö±½Ó½«Æäת»»³É `MethodInterceptor`£»
+2. Èç¹ûÒÔÉϲ»Âú×㣬ÔòʹÓà `AdvisorAdapter` ½« advice ת»»³É `MethodInterceptor`.
+
+¹ØÓÚ `adapters`£¬spring ΪÌṩÁËÈý¸ö `Adapter`£º
+
+- MethodBeforeAdviceAdapter£º´¦Àí `@Before`
+- AfterReturningAdviceAdapter£º´¦Àí `@AfterReturning`
+- ThrowsAdviceAdapter£º´¦Àí `@AfterThrowing`
+
+ÕâÈý¸ö `Adapter` ¾ÍÖ»ÓÐÒ»¸ö¹¦ÄÜ£º·µ»Ø `advice` ¶ÔÓ¦µÄ `MethodInterceptor`£¬ÎÒÃÇÀ´¿´Ï `MethodBeforeAdviceAdapter` µÄ´úÂë¾ÍÃ÷°×ÁË£º
+
+```java
+class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
+ /**
+ * ÊÇ·ñÄÜ´¦Àíµ±Ç°advice
+ */
+ @Override
+ public boolean supportsAdvice(Advice advice) {
+ return (advice instanceof MethodBeforeAdvice);
+ }
+
+ /**
+ * ·µ»Ø¶ÔÓ¦µÄMethodInterceptor
+ */
+ @Override
+ public MethodInterceptor getInterceptor(Advisor advisor) {
+ MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
+ return new MethodBeforeAdviceInterceptor(advice);
+ }
+}
+```
+
+ÆäËûÁ½¸ö `Adapter` µÄ¹¦Äܼ«ÆäÏàËÆ£¬¾Í²»·ÖÎöÁË£¬ÕâÀï×ܽáϸ÷×¢½â¶ÔÓ¦µÄ `advice`¡¢`methodInterceptor`£º
+
+| ×¢½â | advice | methodInterceptor |
+| --------------- | --------------------------- | ------------------------------- |
+| @Before | AspectJMethodBeforeAdvice | MethodBeforeAdviceInterceptor |
+| @After | AspectJAfterAdvice | AspectJAfterAdvice |
+| @Around | AspectJAroundAdvice | AspectJAroundAdvice |
+| @AfterReturning | AspectJAfterReturningAdvice | AfterReturningAdviceInterceptor |
+| @AfterThrowing | AspectJAfterThrowingAdvice | ThrowsAdviceInterceptor |
+
+#### ReflectiveMethodInvocation#proceed
+
+»ñÈ¡Íê `MethodInterceptor` ºó£¬¾Í¿ªÊ¼½øÐз½·¨µÄÖ´ÐÐÁË£¬ÎÒÃÇÖ±½Ó½øÈë `ReflectiveMethodInvocation#proceed` ·½·¨£º
+
+```java
+public Object proceed() throws Throwable {
+ // Ö´ÐÐÍêËùÓеÄÔöÇ¿ºóÖ´ÐÐÄ¿±ê·½·¨
+ // ÕâÀïʹÓÃÁËÔðÈÎÁ´Ä£Ê½£¬Õâ¸ö·½·¨ÔÚÔðÈÎÁ´Öе÷Óã¬Âú×ãÌõ¼þ±íʾµ±Ç°ÔðÈÎÁ´ÒѾִÐе½×îºóÁË
+ if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
+ return invokeJoinpoint();
+ }
+
+ // »ñÈ¡ÏÂÒ»¸öÒªÖ´ÐеÄÀ¹½ØÆ÷
+ Object interceptorOrInterceptionAdvice =
+ this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
+ if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
+ InterceptorAndDynamicMethodMatcher dm =
+ (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
+ Class> targetClass = (this.targetClass != null
+ ? this.targetClass : this.method.getDeclaringClass());
+ if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
+ // Æ¥Å䣬¾Íµ÷ÓÃÀ¹½ØÆ÷µÄ·½·¨£¬Ò²¾ÍÊÇÇÐÃæ·½·¨
+ // ÔÚ MethodInterceptor#invokeÀ»áÔÙ´Î ReflectiveMethodInvocation#proceed£¬ÓÖµ÷»ØÁ˵±Ç°·½·¨
+ return dm.interceptor.invoke(this);
+ }
+ else {
+ // ²»Æ¥Å䣬ÔòµÝ¹éµ÷Óõ±Ç°·½·¨
+ return proceed();
+ }
+ }
+ else {
+ // ×¢Ò⣬Õâ¸ö·½·¨´«ÈëµÄ²ÎÊýÊÇ this£¬±íʾµ±Ç°¶ÔÏó
+ // ÔÚ MethodInterceptor#invokeÀ»áÔÙ´Î ReflectiveMethodInvocation#proceed£¬ÓÖµ÷»ØÁ˵±Ç°·½·¨
+ return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
+ }
+}
+
+/**
+ * µ÷ÓÃÄ¿±ê·½·¨
+ */
+protected Object invokeJoinpoint() throws Throwable {
+ // ʹÓ÷´Éäµ÷ÓÃÄ¿±ê¶ÔÏó·½·¨£¬×¢ÒâÕâÀï´«ÈëµÄÓ¦¸ÃÊÇÄ¿±ê¶ÔÏ󣬶ø²»ÊÇ´úÀí¶ÔÏó
+ return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
+}
+```
+
+ÒÔÉÏ´úÂëµÄµ÷ÓÃʹÓÃÁËÔðÈÎÁ´Ä£Ê½£¬Ö´ÐÐÂß¼ÈçÏ£º
+
+1. ÅжÏÊÇ·ñÖ´ÐÐÍêËùÓеÄÇÐÃæ·½·¨£¬ÈôÊÇ£¬ÔòÖ´ÐÐÄ¿±ê·½·¨£¬·ñÔòÖ´ÐÐÏÂÒ»²½£»
+2. »ñÈ¡ÏÂÒ»¸öÀ¹½ØÆ÷£¬ÅжÏÄÜ·ñÖ´ÐУ¬ÈôÄÜ£¬Ôòµ÷ÓÃÀ¹½ØÆ÷·½·¨£¬·ñÔòÖ´ÐÐµÚ Ò»²½²Ù×÷£»
+
+ÒÔÉÏÂß¼¿´×Åͦ¼òµ¥£¬µ«¾ßÌåÊÇÔõôִÐеÄÄØ£¿ÔÚ spring ÖУ¬ÇÐÃæÍ¨ÖªÓÐÎåÖÖÀàÐÍ£º`@Before`¡¢`@After`¡¢`@AfterReturning`¡¢`@AfterThrowing` Óë `@Around`£¬ÕâÀïÎÒÃÇÒ»Ò»À´¿´¿´ÕâÎåÖÖ֪ͨÊÇÈçºÎµ÷Óõġ£
+
+#### 1. `@Before`
+
+> MethodBeforeAdviceInterceptor#invoke
+
+```java
+@Override
+public Object invoke(MethodInvocation mi) throws Throwable {
+ // Ö´ÐÐǰÖÃ֪ͨ£¬¿´ÏÂÃæ
+ this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
+ // ¼ÌÐøÖ´ÐÐÏÂÒ»¸öÀ¹½ØÆ÷
+ return mi.proceed();
+}
+```
+
+½øÈë `advice.before(xxx)` ·½·¨£º
+
+> AspectJMethodBeforeAdvice#before
+
+```java
+@Override
+public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
+ invokeAdviceMethod(getJoinPointMatch(), null, null);
+}
+```
+
+¼ÌÐø¸úÏÂÈ¥£º
+
+> AbstractAspectJAdvice#invokeAdviceMethod(JoinPointMatch, Object, Throwable)
+
+```java
+protected Object invokeAdviceMethod(
+ @Nullable JoinPointMatch jpMatch, @Nullable Object returnValue, @Nullable Throwable ex)
+ throws Throwable {
+
+ return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
+}
+
+/**
+ * µ÷Ó÷´ÉäÖ´ÐÐ
+ */
+protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
+ Object[] actualArgs = args;
+ if (this.aspectJAdviceMethod.getParameterCount() == 0) {
+ actualArgs = null;
+ }
+ try {
+ // ÊìϤµÄjdk·´Éä´úÂë
+ ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
+ return this.aspectJAdviceMethod.invoke(
+ this.aspectInstanceFactory.getAspectInstance(), actualArgs);
+ }
+ catch (...) {
+ ...
+}
+```
+
+¿ÉÒÔ¿´µ½£¬×îÖÕÊǵ÷Óà jdk ·´ÉäÀ´µ÷Óõġ£
+
+#### 2. `@After`
+
+> AspectJAfterAdvice#invoke
+
+```java
+@Override
+public Object invoke(MethodInvocation mi) throws Throwable {
+ try {
+ // ¼ÌÐøÖ´ÐÐÏÂÒ»¸öÀ¹½ØÆ÷
+ return mi.proceed();
+ }
+ finally {
+ // µ÷ÓÃÇÐÃæ·½·¨£º·ÅÔÚ finally ¿é£¬±íʾһ¶¨»áÖ´ÐУ¬×îÖÕÒ²ÊÇʹÓ÷´Éäµ÷ÓÃ
+ invokeAdviceMethod(getJoinPointMatch(), null, null);
+ }
+}
+```
+
+#### 3. `@AfterReturning`
+
+> AfterReturningAdviceInterceptor#invoke
+
+```java
+@Override
+public Object invoke(MethodInvocation mi) throws Throwable {
+ // ¼ÌÐøÖ´ÐÐÏÂÒ»¸öÀ¹½ØÆ÷
+ Object retVal = mi.proceed();
+ // µ÷ÓÃÇÐÃæ·½·¨£¬¼ÌÐøÍùÏ¿´
+ this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
+ return retVal;
+}
+```
+
+> AspectJAfterReturningAdvice#afterReturning
+
+```java
+public void afterReturning(@Nullable Object returnValue, Method method,
+ Object[] args, @Nullable Object target) throws Throwable {
+ if (shouldInvokeOnReturnValueOf(method, returnValue)) {
+ // µ÷ÓÃÇÐÃæ·½·¨£¬ÒÀÈ»Êǵ÷Ó÷´ÉäÖ´ÐÐ
+ invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
+ }
+}
+```
+
+#### 4. `@AfterThrowing`
+
+> AspectJAfterThrowingAdvice#invoke
+
+```java
+@Override
+public Object invoke(MethodInvocation mi) throws Throwable {
+ try {
+ // µ÷ÓÃ ReflectiveMethodInvocation#proceed
+ return mi.proceed();
+ }
+ catch (Throwable ex) {
+ if (shouldInvokeOnThrowing(ex)) {
+ // µ÷ÓÃÇÐÃæ·½·¨£¬Ö»ÓÐÔÚÅ׳öÒ쳣ʱ²Å»á±»µ÷ÓÃ
+ invokeAdviceMethod(getJoinPointMatch(), null, ex);
+ }
+ throw ex;
+ }
+}
+```
+
+#### 5. `@Around`
+
+> AspectJAroundAdvice#invoke
+
+```java
+@Override
+public Object invoke(MethodInvocation mi) throws Throwable {
+ if (!(mi instanceof ProxyMethodInvocation)) {
+ throw new IllegalStateException(...);
+ }
+ ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
+ ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
+ JoinPointMatch jpm = getJoinPointMatch(pmi);
+ // µ÷ÓÃÇÐÃæ·½·¨
+ return invokeAdviceMethod(pjp, jpm, null, null);
+}
+```
+
+ÎÒÃÇÔÚʵÏÖ»·ÈÆÍ¨ÖªÊ±£¬Ò»°ãÏñÕâÑùʵÏÖ£º
+
+```java
+@Around(xxx)
+public Object around(ProceedingJoinPoint p){
+ // Ö´ÐÐÄ¿±ê·½·¨Ç°µÄ²Ù×÷
+ ...
+
+ // Ö´ÐÐÄ¿±ê·½·¨£¬ÕâÒ»¾äÊǹؼü
+ // ʵ¼ÊÕâÀï²¢²»½ö½öÊÇÖ´ÐÐÄ¿±ê·½·¨£¬×îÖÕµ÷ÓõÄÊÇ ReflectiveMethodInvocation#proceed
+ // ¼´Èç¹ûÓÐÀ¹½ØÆ÷£¬Ôò¼ÌÐøÖ´ÐÐÏÂÒ»¸öÀ¹½ØÆ÷£¬·ñÔòÖ´ÐÐÄ¿±ê·½·¨
+ Object o = p.proceed();
+
+ // Ö´ÐÐÄ¿±ê·½·¨ºóµÄ²Ù×÷
+ ...
+ return o;
+}
+```
+
+spring ¶ÔÒÔÉÏÎåÖÖ֪ͨµÄÖ´ÐУ¬Ö÷Òª·ÖΪÁ½¸ö²¿·Ö£º
+
+1. ʹÓ÷´É䷽ʽִÐÐÇÐÃæ·½·¨£¬Ò²¾ÍÊÇËùνµÄ ¡°ÔöÇ¿¡±£»
+2. µ÷Óà `ReflectiveMethodInvocation#proceed` ¼ÌÐøÖ´ÐÐÏÂÒ»¸öÀ¹½ØÆ÷£¬»òÖ´ÐÐÄ¿±ê·½·¨¡£
+
+ÒÔÉÏÁ½¸ö²¿·ÖµÄ²î±ð½öÔÚÓÚÖ´ÐдÎÐò¼°Ö´ÐеÄλÖã¬Èç
+
+- `@Before` ֪ͨ£¬`1` ÔÚǰ£¬`2` ÔÚºó£»
+- `@AfterReturning` ֪ͨ£¬`2` ÔÚǰ£¬`1` ÔÚºó£¬Èç¹ûÖ´ÐÐ `2` ʱ·¢ÉúÁËÒì³££¬`1` ¾Í²»»áÖ´ÐÐÁË£»
+- `@AfterThrowing` ֪ͨ£¬`2` ÔÚǰ£¬`1` ÔÚºó£¬ÇÒ `1` ÊÇ·ÅÔÚ `catch` ¿éÖÐÖ´ÐУ¬¼´Ö»Óз¢ÉúÁËÒì³££¬`1` ²Å»áÖ´ÐУ»
+- `@After` ֪ͨ£¬`2` ÔÚǰ£¬`1` ÔÚºó£¬`1` ÊÇ·ÅÔÚ `finally` ¿éÖÐÖ´ÐУ¬ÓÉÓÚ `finally` µÄÌØÊâÐÔ£¬¼´Ê¹·¢ÉúÁËÒì³££¬`1` ͬÑù»áÖ´ÐУ»
+- `@Around` ֪ͨ£¬ÔÚÇÐÃæ·½·¨ÖÐ×ÔÐÐÖ¸¶¨ÁË `2` µÄÖ´ÐÐʱ»ú¡£
+
+×¢ÒâÇø±ð `@AfterReturning`¡¢`@AfterThrowing` Óë `@After` ֪ͨµÄÖ´ÐÐʱ»ú¡£
+
+×îºó£¬ÎÒÃÇÔÙÀ´¿´¿´Õ⼸¸ö֪ͨÊÇÈçºÎÖ´Ðеġ£
+
+ͨ¹ýµ÷ÊԵķ½Ê½£¬·¢ÏÖ spring Ö´ÐÐ֪ͨµÄ˳ÐòÈçÏ£º
+
+1. Ê×ÏÈÖ´ÐÐ `@AfterThrowing` ֪ͨ£¬Ïȵ÷Óà `mi.proceed()` Ö´ÐÐÏÂÒ»¸öÀ¹½ØÆ÷£¬È»ºóÔÚ `catch` ¿éÖÐÖ´ÐÐÇÐÃæ·½·¨£¬±íÃ÷Ö»ÓгöÏÖÒ쳣ʱ£¬¸ÃÇÐÃæ·½·¨²Å»áÖ´ÐУ»
+2. ÉÏÒ»²½²Ù×÷ÖУ¬µ÷Óà `mi.proceed()` ʱ»áÖ´ÐÐ `@AfterReturning` ֪ͨ£¬Ö´ÐÐʱÏȵ÷Óà `mi.proceed()` Ö´ÐÐÏÂÒ»¸öÀ¹½ØÆ÷£¬È»ºóÔÙÖ´ÐÐÇÐÃæ·½·¨£»
+3. ÉÏÒ»²½²Ù×÷ÖУ¬µ÷Óà `mi.proceed()` ʱ»áÖ´ÐÐ `@After` ֪ͨ£¬Ö´ÐÐʱÏȵ÷Óà `mi.proceed()` Ö´ÐÐÏÂÒ»¸öÀ¹½ØÆ÷£¬È»ºóÔÚ `finally` ¿éÖÐÖ´ÐÐÇÐÃæ·½·¨£¬±íÃ÷¼´Ê¹³öÏÖÒì³££¬ÇÐÃæ·½·¨»¹ÊÇ»áÖ´ÐУ»
+4. ÉÏÒ»²½²Ù×÷ÖУ¬µ÷Óà `mi.proceed()` ʱ»áÖ´ÐÐ `@Around` ֪ͨ£¬Ö´ÐÐʱֱ½ÓÖ´ÐÐÇÐÃæ·½·¨£¬ÓÉÓÚ `@Around` ֪ͨµÄÇÐÃæ·½·¨Àï»áµ÷Óà `ProceedingJoinPoint#proceed()`£¬×îÖÕ»¹ÊÇ»áÖ´ÐÐÏÂÒ»¸öÀ¹½ØÆ÷£»
+5. ÉÏÒ»²½²Ù×÷ÖУ¬µ÷Óà `mi.proceed()` ʱ»áÖ´ÐÐ `@Before` ֪ͨ£¬Ö´ÐÐʱ»áÏÈÖ´ÐÐÇÐÃæ·½·¨£¬ÔÙµ÷Óà `mi.proceed()` Ö´ÐÐÏÂÒ»¸öÀ¹½ØÆ÷£»
+6. À¹½ØÆ÷Á´Ö´Ðе½×îºó£¬·¢ÏÖûÓпÉÖ´ÐеÄÀ¹½ØÆ÷ÁË£¬´Ëʱ¾Í¿ªÊ¼Ö´ÐÐÄ¿±ê·½·¨¡£
+
+»Í¼Ê¾Òâ֪ͨµÄÖ´Ðйý³ÌÈçÏ£º
+
+
+
+×îÖÕµÄÖ´ÐÐ˳Ðò£º
+
+
+
+### 4. ×ܽá
+
+±¾ÎÄÖ÷Òª·ÖÎöÁË jdk ¶¯Ì¬´úÀíµÄÖ´Ðйý³Ì£¬ÊáÀíÁ˸÷¸öÇÐÃæÍ¨ÖªµÄÖ´ÐÐ˳Ðò¡£±¾ÎľÍÏȵ½ÕâÀïÁË£¬ÏÂһƪÎÄÕ½«½éÉÜ cglib µÄÖ´Ðйý³Ì¡£
+
+------
+
+*±¾ÎÄÔÎÄÁ´½Ó£ºhttps://my.oschina.net/funcy/blog/4696654 £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£*
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\270\200\357\274\211\357\274\232\350\256\244\350\257\206\344\272\213\345\212\241\347\273\204\344\273\266.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\270\200\357\274\211\357\274\232\350\256\244\350\257\206\344\272\213\345\212\241\347\273\204\344\273\266.md"
new file mode 100644
index 0000000..d46a99e
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\270\200\357\274\211\357\274\232\350\256\244\350\257\206\344\272\213\345\212\241\347\273\204\344\273\266.md"
@@ -0,0 +1,825 @@
+Ç°Ãæ·ÖÎöÍêÁË spring aop Ïà¹Ø¹¦Äܺ󣬱¾ÎĽ«À´·ÖÎö spring aop µÄÒ»¸öÓ¦Óà ¡ª¡ª ÊÂÎñ¹ÜÀí¡£
+
+### 1\. ´ÓÁ½¸ö demo ½²Æð
+
+ÔÚÕýʽ·ÖÎöǰ£¬ÎÒÃÇÏÈÀ´Ë¼¿¼Ï£¬Èç¹ûÈÃÎÒÃÇ×Ô¼ºÀ´»ùÓÚ spring aop À´Éè¼ÆÒ»Ì×ÊÂÎñ´¦Àí»úÖÆ£¬¸ÃÈçºÎʵÏÖÄØ£¿Èç¹ûûÓÐ spring£¬ÎÒÃǵÄÊÂÎñ´¦Àí´úÂëÒ»°ã³¤ÕâÑù£º
+
+```
+public void fun() {
+ // ¿ªÆôÊÂÎñ
+ start();
+ try {
+ // ÒµÎñ´¦Àí
+ xxx();
+ // Ìá½»ÊÂÎñ
+ commit();
+ } catch(Exception e) {
+ // »Ø¹öÊÂÎñ
+ rollback();
+ throw e;
+ }
+}
+
+```
+
+´ÓÉÏÃæµÄ´úÂëÀ´¿´£¬Ïñ¿ªÆôÊÂÎñ¡¢Ìá½»ÊÂÎñ¡¢»Ø¹öÊÂÎñ£¬¶¼¸úÒµÎñ´úÂëÎ޹أ¬ÕâЩ¿ÉÒÔʹÓà spring aop À´ÊµÏÖ£¬Òò´Ë¾ÍÓÐÁËÏÂÃæÁ½¸ö demo.
+
+#### demo01£º»ùÓÚ `@Around` ×¢½âʵÏÖÊÂÎñ
+
+ÔÛÃÇ¿ÉÒÔʹÓà `@Around` ×¢½âÀ´²Ù×÷£¬´úÂëÈçÏ£º
+
+1. ¶¨ÒåÒ»¸ö×¢½â£º`@MyTransactional`
+
+```
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface MyTransactional {
+}
+
+```
+
+1. ¶¨Òå aop ²Ù×÷
+
+```
+@Aspect
+@Component
+public class MyAopAspectj {
+ @Pointcut("@annotation(org.springframework.learn.tx.demo02.MyTransactional)")
+ public void testAop(){
+
+ }
+
+ @Around("testAop()")
+ public Object around(ProceedingJoinPoint p) throws Throwable {
+ System.out.println("Ö´ÐÐǰ£¬¿ªÆôÊÂÎñ....");
+ try {
+ Object o = p.proceed();
+ System.out.println("Ö´ÐÐÍê³É£¬Ìá½»ÊÂÎñ....");
+ return o;
+ } catch (Throwable e) {
+ System.out.println("³öÏÖÁËÒì³££¬¸ù¾ÝÒì³£ÀàÐͻعöÊÂÎñ....");
+ throw e;
+ } finally {
+ System.out.println("Ö´Ðкó....");
+ }
+ }
+
+}
+
+```
+
+1. config£¬½øÐÐһЩ±ØÒªµÄÅäÖÃ
+
+```
+@Configuration
+@ComponentScan("org.springframework.learn.tx.demo02")
+@EnableAspectJAutoProxy(proxyTargetClass = true)
+public class TxDemo02Config {
+
+}
+
+```
+
+1. Ìí¼ÓÒ»¸ö service À࣬ÆäÖÐÒ»¸ö·½·¨ÉÏÓÐ `@MyTransactional` ×¢½â
+
+```
+@Service
+public class TxTestService {
+
+ @MyTransactional
+ public void test01() {
+ System.out.println("Ö´ÐÐtest01·½·¨");
+ }
+
+ public void test02() {
+ System.out.println("Ö´ÐÐtest02·½·¨");
+ }
+
+}
+
+```
+
+1. Ö÷Àà
+
+```
+public class TxDemo02Main {
+
+ public static void main(String[] args) {
+ AnnotationConfigApplicationContext applicationContext
+ = new AnnotationConfigApplicationContext(TxDemo02Config.class);
+ TxTestService service = applicationContext.getBean(TxTestService.class);
+ System.out.println("-------------------");
+ service.test01();
+ System.out.println("-------------------");
+ service.test02();
+
+ }
+}
+
+```
+
+ÔËÐУ¬½á¹ûÈçÏ£º
+
+```
+-------------------
+Ö´ÐÐǰ£¬¿ªÆôÊÂÎñ....
+Ö´ÐÐtest01·½·¨
+Ö´ÐÐÍê³É£¬Ìá½»ÊÂÎñ....
+Ö´Ðкó....
+-------------------
+Ö´ÐÐtest02·½·¨
+
+```
+
+Õâ¸ö demo ÖУ¬ÎÒÃÇʹÓà `@Around` ×¢½âÀ´À¹½ØÒµÎñ´úÂëÖ´ÐÐǰºóµÄÇé¿ö£¬¿ÉÒÔ¿´µ½£¬`@Around` ×¢½â¿ÉÒÔÔÚ´úÂëÔËÐÐǰºóÉõÖÁÊdzöÏÖÒ쳣ʱ´¦ÀíһЩ¶îÍâµÄ²Ù×÷¡£
+
+#### demo02£º×Ô¶¨Òå `advisor` ʵÏÖÊÂÎñ
+
+ÈÃÎÒÃÇ»ØÒäÏ spring aop ¶Ô `@Around` ×¢½âµÄ´¦Àí£¬Êµ¼ÊÉÏ `@Around` ×îÖÕ»á·âװΪ `InstantiationModelAwarePointcutAdvisorImpl` ¶ÔÏ󣬺óÃæµÄ´¦Àí¾Í¸ú `@Around` ÎÞ¹ØÁË£¬`@Around` µ½ `InstantiationModelAwarePointcutAdvisorImpl` ¶ÔÏóµÄ¹ý³Ì£¬¿É²Î¿¼ [spring aop Ö® AnnotationAwareAspectJAutoProxyCreator ·ÖÎö£¨ÉÏ£©](https://my.oschina.net/funcy/blog/4678817).
+
+`InstantiationModelAwarePointcutAdvisorImpl` ÊǸöʲô¶«Î÷ÄØ£¿ÕâÊǸö `advisor`£¬¾ßÌåÀ´Ëµ¾ÍÊÇ¿ÉÓÃÓÚ·½·¨µÄÔöÇ¿¡£¹ØÓÚ spring aop ÊÇÈçºÎÕÒµ½ÄÜÓ¦ÓÃÓÚµ±Ç°·½·¨µÄ `advisor` µÄ£¬¿É²Î¿¼ [spring aop Ö® AnnotationAwareAspectJAutoProxyCreator ·ÖÎö£¨Ï£©](https://my.oschina.net/funcy/blog/4687961)¡£
+
+ͨ¹ýÒÔÉÏ·ÖÎö£¬¸øÎÒÃÇÌṩÁËÁíÒ»¸ö˼·£ºÎÒÃÇ¿ÉÒÔʵÏÖ `advisor` ½Ó¿Ú£¬¶¨ÖÆ»¯×Ô¼ºµÄÂß¼£¬´úÂëÈçÏ£º
+
+1. ×¼±¸ `advice`
+
+```
+/**
+ * Õâ¸öadvice¾ÍÊÇadvisorµÄÒ»¸öÊôÐÔ£¬ÇÐÃæÂß¼ÔÚÕâÀï´¦Àí
+ */
+public class MyAdvice implements MethodInterceptor {
+
+ @Override
+ public Object invoke(MethodInvocation invocation) throws Throwable {
+ System.out.println("Ö´ÐÐǰ£¬¿ªÆôÊÂÎñ....");
+ try {
+ Object val = invocation.proceed();
+ System.out.println("Ö´ÐÐÍê³É£¬Ìá½»ÊÂÎñ....");
+ return val;
+ } catch (Throwable e) {
+ System.out.println("³öÏÖÁËÒì³££¬¸ù¾ÝÒì³£ÀàÐͻعöÊÂÎñ....");
+ throw e;
+ } finally {
+ System.out.println("Ö´Ðкó....");
+ }
+ }
+}
+
+```
+
+1. ×¼±¸ `pointcut`
+
+```
+/**
+ * Çеã
+ * ÅжÏÄÄЩ·½·¨ÄÜÓÃÓÚ¸Ãadvisor
+ */
+public class MyPointcut extends StaticMethodMatcherPointcut {
+ /**
+ * Æ¥Åä·½·¨£¬ÓÐ @MyTransactional µÄÀà»ò·½·¨¾Í·µ»Øtrue
+ */
+ @Override
+ public boolean matches(Method method, Class> targetClass) {
+ return null != AnnotationUtils.getAnnotation(method, MyTransactional.class)
+ || null != AnnotationUtils.getAnnotation(targetClass, MyTransactional.class);
+ }
+}
+
+```
+
+1. ×¼±¸ `advisor`
+
+```
+/**
+ * advisor ¿É¿´×÷ÊÇ advice Óë pointcut µÄ°ü×°
+ */
+@Component
+public class MyAdvisor extends AbstractBeanFactoryPointcutAdvisor {
+
+ private static final long serialVersionUID = 2651364800145442305L;
+
+ private MyPointcut pointcut;
+
+ public MyAdvisor() {
+ this.pointcut = new MyPointcut();
+ this.setAdvice(new MyAdvice());
+ }
+
+ @Override
+ public Pointcut getPointcut() {
+ return this.pointcut;
+ }
+
+}
+
+```
+
+ÒÔÉÏÊDz»Í¬ÓÚ×¢½âµÄʵÏÖ·½Ê½£¬½ÓÏÂÀ´µÄ´úÂë¾ÍÓë×¢½âÒ»ÑùÁË¡£
+
+1. ×¼±¸Ò»¸ö×¢½â£º`@MyTransactional`
+
+```
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface MyTransactional {
+}
+
+```
+
+1. ´¦ÀíÏîÄ¿ÅäÖÃ
+
+```
+@Configuration
+@ComponentScan("org.springframework.learn.tx.demo01")
+@EnableAspectJAutoProxy(proxyTargetClass = true)
+public class TxDemo01Config {
+
+}
+
+```
+
+1. ×¼±¸Ò»¸ö service
+
+```
+@Service
+public class TxTestService {
+
+ @MyTransactional
+ public void test01() {
+ System.out.println("Ö´ÐÐtest01·½·¨");
+ }
+
+ public void test02() {
+ System.out.println("Ö´ÐÐtest02·½·¨");
+ }
+
+}
+
+```
+
+1. Ö÷Àà
+
+```
+public class TxDemo01Main {
+
+ public static void main(String[] args) {
+ AnnotationConfigApplicationContext applicationContext
+ = new AnnotationConfigApplicationContext(TxDemo01Config.class);
+ TxTestService service = applicationContext.getBean(TxTestService.class);
+ System.out.println("-------------------");
+ service.test01();
+ System.out.println("-------------------");
+ service.test02();
+
+ }
+}
+
+```
+
+ÔËÐУ¬½á¹ûÈçÏ£º
+
+```
+-------------------
+Ö´ÐÐǰ£¬¿ªÆôÊÂÎñ....
+Ö´ÐÐtest01·½·¨
+Ö´ÐÐÍê³É£¬Ìá½»ÊÂÎñ....
+Ö´Ðкó....
+-------------------
+Ö´ÐÐtest02·½·¨
+
+```
+
+### 2\. ʹÓà spring ÊÂÎñ¹ÜÀí
+
+ÓÐÁËÇ°ÃæµÄÁ½¸öС demo ×÷Ϊ¿ªÎ¸²Ë£¬¶ÔÓÚ spring ÊÂÎñ´¦ÀíÏë±ØÄãÒÑÓÐÁËÒ»¸öÇåÎúµÄÈÏʶ£¬spring ÔÚ´¦ÀíÊÂÎñʱ£¬Ê¹ÓõľÍÊǵڶþÖÖ·½Ê½£¬¼´Íù×Ô¶¨ÒåÒ»¸ö `advisor` Ìí¼Óµ½ spring ÈÝÆ÷ÖС£¹ØÓÚ spring ʵÏÖÈÎÎñµÄ¾ßÌåϸ½Ú£¬ÎÒÃÇ´ý»á·ÖÎö£¬ÕâÀïÎÒÃÇÔÙÉÏÒ»¸ö demo£¬ÌåÑéÏÂÎÒÃÇÆ½Ê±ÊÇÔõôʹÓÃÊÂÎñµÄ¡£
+
+ΪÁ˽øÐÐÊý¾Ý¿âÁ¬½Ó£¬ÎÒÃÇÐèÒªÒýÈëÊý¾Ý¿âÁ¬½Ó³Ø£¬ÕâÀïÎÒÃÇʹÓõÄÊÇ mysql£¬ÐèÒªÔÚ `spring-learn.gradle` ÖÐÌí¼ÓÒÀÀµ£º
+
+```
+optional("mysql:mysql-connector-java:5.1.48")
+
+```
+
+½ÓמÍÊÇ´úÂëÁË¡£
+
+1. ÅäÖÃÀà
+
+```
+@Configuration
+@ComponentScan("org.springframework.learn.tx.demo03")
+@EnableTransactionManagement(proxyTargetClass = true)
+public class TxDemo01Config {
+
+ /**
+ * Éú³ÉÊý¾ÝÔ´
+ * @return
+ * @throws Exception
+ */
+ @Bean
+ public DataSource dataSource() throws Exception {
+ Driver driver = new com.mysql.jdbc.Driver();
+ String url = "jdbc:mysql://localhost:3306/test";
+ String username = "root";
+ String password = "123";
+ return new SimpleDriverDataSource(driver, url, username, password);
+ }
+
+ /**
+ * Éú³ÉjdbcTemplate£¬ºóÃæ¾ÍÊÇÓÃÕâ¸öÀàÀ´´¦ÀíÊý¾Ý¿âµÄ²Ù×÷
+ * @param dataSource
+ * @return
+ */
+ @Bean
+ public JdbcTemplate jdbcTemplate(DataSource dataSource) {
+ return new JdbcTemplate(dataSource);
+ }
+
+ /**
+ * ÊÂÎñ¹ÜÀíÆ÷
+ * @param dataSource
+ * @return
+ */
+ @Bean
+ public DataSourceTransactionManager transactionManager(DataSource dataSource) {
+ return new DataSourceTransactionManager(dataSource);
+ }
+
+}
+
+```
+
+1. Êý¾Ý¿â²Ù×÷Àà
+
+```
+@Service
+public class UserService {
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ /**
+ * Êý¾Ý¿â²åÈë²Ù×÷£¬Ê¹Óà @Transactional ¿ªÆôÊÂÎñ
+ * @return
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public int insert() {
+ String sql = "insert into `user`(`login_name`, `nick`, `create_time`, `update_time`)"
+ + "values (?, ?, ?, ?)";
+ int result = jdbcTemplate.update(sql, "test", "test", new Date(), new Date());
+ if(true) {
+ //throw new RuntimeException("Å׳ö¸öÒì³£");
+ }
+ System.out.println(result);
+ return result;
+ }
+
+}
+
+```
+
+1. Ö÷Àà
+
+```
+public class TxDemo01Main {
+
+ public static void main(String[] args) {
+ AnnotationConfigApplicationContext applicationContext
+ = new AnnotationConfigApplicationContext(TxDemo01Config.class);
+ UserService userService = applicationContext.getBean(UserService.class);
+ userService.insert();
+
+ }
+}
+
+```
+
+demo ÖУ¬`DataSource` ʹÓà spring ×Ô´øµÄ `SimpleDriverDataSource`£¬`orm` ¿ò¼ÜÒ²ÊÇ spring ÌṩµÄ `jdbcTemplate`£¬Ê¹ÓÃµÄ `user` ±í sql ÈçÏ£º
+
+```
+CREATE TABLE `user` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Ö÷¼üid',
+ `login_name` varchar(32) NOT NULL DEFAULT '0' COMMENT 'µÇ¼Ãû',
+ `nick` varchar(32) NOT NULL DEFAULT '0' COMMENT 'êdzÆ',
+ `create_time` datetime DEFAULT NULL COMMENT '´´½¨Ê±¼ä',
+ `update_time` datetime DEFAULT NULL COMMENT '¸üÐÂʱ¼ä',
+ PRIMARY KEY (`id`),
+ KEY `create_time` (`create_time`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='Óû§±í';
+
+```
+
+Ö´Ðнá¹ûÈçÏ£º
+
+µÚÒ»´Î²»Å׳öÒì³££¬Êý¾Ý¿â½á¹û£º
+
+
+
+µÚ¶þ´ÎÅ׳öÒì³££¬Êý¾Ý¿â½á¹û£º
+
+
+
+µÚÈý´Î²»Å׳öÒì³££¬Êý¾Ý¿â½á¹û£º
+
+
+
+¿ÉÒÔ¿´µ½£¬µÚ¶þ´ÎÅ׳öÒ쳣ʱ£¬Êý¾ÝÕý³£»Ø¹öÁË¡£
+
+ÎÒÃÇÔÙÀ´·ÖÎöÏÂÕâ¸ö demo£¬¸úÊÂÎñÓйصĴúÂëÓÐÈý´¦£º
+
+* `@EnableTransactionManagement(proxyTargetClass = true)`£ºÆôÓÃÊÂÎñ
+* `DataSourceTransactionManager`£ºÊÂÎñ¹ÜÀíÆ÷
+* `@Transactional`£ºÖ¸¶¨¿ªÆôÊÂÎñµÄ·½·¨
+
+Àà±ÈÓÚ aop µÄ `@EnableAspectJAutoProxy`£¬`@EnableTransactionManagement` ÊÇÆô¶¯ÊÂÎñµÄÈë¿Ú£¬½Ó×ÅÎÒÃǾʹÓÕâ¸ö×¢½âÈëÊÖ£¬·ÖÎö spring ÊÂÎñµÄÆôÓÃÁ÷³Ì¡£
+
+### 3. `@EnableTransactionManagement` ×¢½â
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Import(TransactionManagementConfigurationSelector.class)
+public @interface EnableTransactionManagement {
+
+ /**
+ * ѧÍêaopºó£¬Ïë±Ø¶ÔÕâ¸öÊôÐÔÒѾºÜÊìϤ
+ * true: ±íÊ¾Ç¿ÖÆÊ¹ÓÃcglib´úÀí
+ * false£ºÈç¹ûÄ¿±êÀàʵÏÖÁ˽ӿڣ¬ÔòʹÓÃjdk¶¯Ì¬´úÀí£¬·ñÔòʹÓÃcglib´úÀí
+ * ½öÔÚ mode Ϊ PROXY ÏÂÉúЧ
+ */
+ boolean proxyTargetClass() default false;
+
+ /**
+ * adviceģʽ£¬Ê¹ÓôúÀí£¬»¹ÊÇʹÓà aspectJ
+ */
+ AdviceMode mode() default AdviceMode.PROXY;
+
+ /**
+ * Ö´ÐÐ˳Ðò£¬µ±Ò»¸ö´úÀí¶ÔÏóÓжà¸öÔöǿʱ£¬°´Ê²Ã´ÑùµÄ˳ÐòÀ´Ö´ÐÐ
+ */
+ int order() default Ordered.LOWEST_PRECEDENCE;
+
+}
+
+```
+
+Õâ¸ö×¢½â±¾Éíûʲô£¬¾ÍÈý¸öÊôÐÔ£¬×¢ÊÍÒѾºÜÃ÷È·ÁË£¬ÎÒÃǹؼü»¹ÊÇ¿´Õâ¸ö×¢½âÒýÈëµÄÀࣺ`TransactionManagementConfigurationSelector`£º
+
+```
+public class TransactionManagementConfigurationSelector extends
+ AdviceModeImportSelector {
+ @Override
+ protected String[] selectImports(AdviceMode adviceMode) {
+ switch (adviceMode) {
+ case PROXY:
+ // »ùÓÚ´úÀíµÄÊÂÎñ¹ÜÀí£¬»áÒýÈëÁ½¸öÀà
+ return new String[] {AutoProxyRegistrar.class.getName(),
+ ProxyTransactionManagementConfiguration.class.getName()};
+ case ASPECTJ:
+ // »ùÓÚaspectJµÄÊÂÎñ¹ÜÀí£¬»áÒýÈëÕâ¸öÀ࣬±¾ÎIJ»·ÖÎö
+ return new String[] {determineTransactionAspectClass()};
+ default:
+ return null;
+ }
+ }
+ // Ê¡ÂÔÆäËû
+ ...
+
+}
+
+```
+
+»ùÓÚ´úÀíµÄÊÂÎñ¹ÜÀí£¬»áÒýÈëÁ½¸öÀࣺ`AutoProxyRegistrar`¡¢`ProxyTransactionManagementConfiguration`£¬½ÓÏÂÀ´ÎÒÃǾÍÀ´·ÖÎöÕâÁ½¸öÀà¡£
+
+#### 3.1 `AutoProxyRegistrar`
+
+´ÓÃû×ÖÉÏÀ´¿´£¬`AutoProxyRegistrar` ÊÇÒ»¸ö×¢²áÆ÷£¬»¹¼ÇµÃÇ°Ãæ aop µÄ×¢²áÆ÷ `AspectJAutoProxyRegistrar` Âð£¬Á½ÕßÒ»ÑùµÄÌ×·£¡
+
+ÎÒÃÇÀ´¿´¿´ÀïÃæ¾¿¾¹×öÁËɶ£º
+
+```
+public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
+
+ private final Log logger = LogFactory.getLog(getClass());
+
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
+ BeanDefinitionRegistry registry) {
+ boolean candidateFound = false;
+ Set annTypes = importingClassMetadata.getAnnotationTypes();
+ for (String annType : annTypes) {
+ AnnotationAttributes candidate = AnnotationConfigUtils
+ .attributesFor(importingClassMetadata, annType);
+ if (candidate == null) {
+ continue;
+ }
+ Object mode = candidate.get("mode");
+ Object proxyTargetClass = candidate.get("proxyTargetClass");
+ // Âú×ãifÌõ¼þµÄ£¬¾ÍÊÇ @EnableTransactionManagement ×¢½â
+ if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
+ Boolean.class == proxyTargetClass.getClass()) {
+ candidateFound = true;
+ if (mode == AdviceMode.PROXY) {
+ // ×¢²á²Ù×÷£¬×îÖÕ×¢²áÁË InfrastructureAdvisorAutoProxyCreator À࣬½ÓÏÂÀ´»á¼ÌÐø·ÖÎö
+ AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
+ if ((Boolean) proxyTargetClass) {
+ // ʹÓÃcglib´úÀí
+ AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
+ return;
+ }
+ }
+ }
+ }
+ if (!candidateFound && logger.isInfoEnabled()) {
+ String name = getClass().getSimpleName();
+ logger.info(...);
+ }
+ }
+}
+
+```
+
+ÕâÐдúÂë¹Ø¼üµÄ¾ÍÖ»ÓÐ if ÀïµÄ¼¸ÐУ¬ÏÈ˵Ï if Ìõ¼þ£º`mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&Boolean.class == proxyTargetClass.getClass()`£¬Í¨¹ýÉÏÃæµÄ¶Ô `@EnableTransactionManagement`£¬Õâ˵µÄ¾ÍÊÇËüÁË£»¶ÔÓÚ `mode == AdviceMode.PROXY`£¬¼ÌÐøµ÷Óà `AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)`£¨¹ØÓÚÕâ¸ö·½·¨µÄµ÷Óã¬ÎÒÃǽÓÏÂÀ´»á¼ÌÐø·ÖÎö£©£»È»ºó´¦Àí `proxyTargetClass`£¬Õâ¸öÊôÐÔµÄ×÷ÓÃÓë `@EnableAspectJAutoProxy` ÖÐµÄ `proxyTargetClass` Ò»Ö£¬Ò²ÊÇ¿ÉÒÔÇ¿ÖÆÊ¹Óà cglib ´úÀí¡£
+
+½Ó×ÅÎÒÃÇÀ´·ÖÎöÏ `AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)` µÄ¹ý³Ì£¬¸ú½ø´úÂ룺
+
+> AopConfigUtils
+
+```
+ @Nullable
+ public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
+ // ¼ÌÐøÍùÏ¿´
+ return registerAutoProxyCreatorIfNecessary(registry, null);
+ }
+
+ @Nullable
+ public static BeanDefinition registerAutoProxyCreatorIfNecessary(
+ BeanDefinitionRegistry registry, @Nullable Object source) {
+ // ´«Èë InfrastructureAdvisorAutoProxyCreator À࣬¼ÌÐøµ÷ÓÃ
+ return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class,
+ registry, source);
+ }
+
+```
+
+¿´µ½ÕâÀÊDz»ÊÇÓÐÖÖÉîÉîµÄÊìϤ¸Ð£¿aop ÖÐµÄ `AspectJAnnotationAutoProxyCreator` Ò² ÊÇÕâôע²áµÄ£¡½øÈë `AopConfigUtils#registerOrEscalateApcAsRequired` ·½·¨£º
+
+```
+// AopConfigUtils ¿É×¢²áµÄÀà¶¼ÔÚÕâÀïÁË
+private static final List> APC_PRIORITY_LIST = new ArrayList<>(3);
+
+static {
+ APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
+ APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
+ APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
+}
+
+/**
+ * ×¢²á²Ù×÷
+ */
+private static BeanDefinition registerOrEscalateApcAsRequired(
+ Class> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
+ Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
+ //Èç¹ûÒÑ´æÔÚÕâ¸öbean
+ if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
+ BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
+ //ÅжÏÓÅÏȼ¶£¬Èç¹ûÓÅÏȼ¶½Ï¸ßÔòÌæ»»ÔÏȵÄbean
+ if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
+ int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
+ int requiredPriority = findPriorityForClass(cls);
+ // ÒÑ´æÔÚÀà µÄÓÅÏȼ¶ СÓÚÕýÔÚ×¢²áµÄ£¬ÔòʹÓÃÕýÔÚ×¢²áµÄ£¬ÒÑ´æÔÚµÄÈý¸öÀàµÄÓÅÏȼ¶Îª
+ // 0: InfrastructureAdvisorAutoProxyCreator(´¦ÀíÊÂÎñ)
+ // 1: AspectJAwareAdvisorAutoProxyCreator(´¦Àí»ùÓÚxmlµÄaop)
+ // 2: AnnotationAwareAspectJAutoProxyCreator(´¦Àí»ùÓÚ×¢½âµÄaop)
+ if (currentPriority < requiredPriority) {
+ apcDefinition.setBeanClassName(cls.getName());
+ }
+ }
+ return null;
+ }
+ //×¢²áXxxAutoProxyCreatorµ½ÈÝÆ÷ÖÐ
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
+ beanDefinition.setSource(source);
+ beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
+ beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+ registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
+ return beanDefinition;
+}
+
+/**
+ * ²éÕÒ×¢²áÀàµÄÓÅÏȼ¶
+ */
+private static int findPriorityForClass(@Nullable String className) {
+ for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
+ Class> clazz = APC_PRIORITY_LIST.get(i);
+ if (clazz.getName().equals(className)) {
+ return i;
+ }
+ }
+ throw new IllegalArgumentException(
+ "Class name [" + className + "] is not a known auto-proxy creator class");
+}
+
+```
+
+`AopConfigUtils` ¿É×¢²áµÄÀàÓÐÓÐÈý¸ö£º
+
+* `InfrastructureAdvisorAutoProxyCreator`£º´¦ÀíÊÂÎñ
+* `AspectJAwareAdvisorAutoProxyCreator`£º´¦Àí»ùÓÚ xml µÄ aop
+* `AnnotationAwareAspectJAutoProxyCreator`£º´¦Àí»ùÓÚ×¢½âµÄ aop
+
+ÕâÈýÕßµÄÓÅÏȼ¶Îª `AnnotationAwareAspectJAutoProxyCreator` > `AspectJAwareAdvisorAutoProxyCreator` > `InfrastructureAdvisorAutoProxyCreator`£¬×¢Èëʱ£¬»áÅжÏ×¢ÈëÀàµÄÓÅÏȼ¶£¬ÓÅÏȼ¶¸ßµÄ×îÖջᱻעÈëµ½ spring ÈÝÆ÷ÖС£ÕâÑù¾Íµ¼ÖÂÁËÒ»¸öÎÊÌ⣺**Èç¹ûÏîÄ¿ÖÐͬʱ¿ªÆôÁË aop (`@EnableAspectJAutoProxy`) ÓëÊÂÎñ (`@EnableTransactionManagement`)£¬ÄÇô×îÖÕ×¢Èëµ½ÈÝÆ÷µÄ½«ÊÇ `AnnotationAwareAspectJAutoProxyCreator`£¬ÕâÒ²¾ÍÊÇ˵£¬`AnnotationAwareAspectJAutoProxyCreator` Ò²ÄÜ´¦ÀíÊÂÎñ£¡** Õâ¾ä»°·Ç³£¹Ø¼ü£¬ËüÒâζ×ÅÊÂÎñµÄ´¦Àí¹ý³Ì£¬Êµ¼ÊÉϾͰüº¬ÔÚÇ°Ãæ·ÖÎöµÄ aop µÄ¹ý³ÌÖÐÁË£¡
+
+ÎÒÃÇÒ²À´¿´¿´ `InfrastructureAdvisorAutoProxyCreator`£º
+
+```
+// ¼Ì³ÐÁË AbstractAdvisorAutoProxyCreator£¬Õâ¸öÀà·Ç³£¹Ø¼ü
+public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
+
+ @Nullable
+ private ConfigurableListableBeanFactory beanFactory;
+
+ @Override
+ protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
+ super.initBeanFactory(beanFactory);
+ this.beanFactory = beanFactory;
+ }
+
+ @Override
+ protected boolean isEligibleAdvisorBean(String beanName) {
+ return (this.beanFactory != null &&
+ this.beanFactory.containsBeanDefinition(beanName)
+ && this.beanFactory.getBeanDefinition(beanName).getRole()
+ == BeanDefinition.ROLE_INFRASTRUCTURE);
+ }
+
+}
+
+```
+
+`InfrastructureAdvisorAutoProxyCreator` Æäʵ²¢Ã»ÓÐ×öʲôÓë aop Ïà¹ØµÄÊ£¬µ«Ëü¼Ì³ÐÁËÒ»¸ö¹Ø¼üµÄÀࣺ`AbstractAdvisorAutoProxyCreator`£¬Õâ¸öÀà¿ÉÊÇ´óÓÐÀ´Í·£º
+
+
+
+´Ó¼Ì³Ð¹ØÏµÀ´¿´£¬Õâ¸öÀà¼Ì³ÐÁË `AbstractAutoProxyCreator`£¬¶ø `AbstractAutoProxyCreator` ÕýÊÇÎÒÃÇÔÚ - [spring aop Ö® AnnotationAwareAspectJAutoProxyCreator ·ÖÎö£¨ÉÏ£©](https://my.oschina.net/funcy/blog/4678817) Óë [spring aop Ö® AnnotationAwareAspectJAutoProxyCreator ·ÖÎö£¨Ï£©](https://my.oschina.net/funcy/blog/4687961)ÖÐÖØµã·ÖÎöµÄ¡¢´úÀí¶ÔÏóµÄ²úÉúËùÔÚ£¡
+
+ÎÒÃÇÔÙÀ´¿´Ï `AnnotationAwareAspectJAutoProxyCreator`¡¢`AspectJAwareAdvisorAutoProxyCreator` ¡¢`InfrastructureAdvisorAutoProxyCreator` ÕâÈýÕߵĹØÏµ£º
+
+
+
+¿ÉÒÔ¿´µ½£¬`AspectJAwareAdvisorAutoProxyCreator` ¡¢`InfrastructureAdvisorAutoProxyCreator` ¶¼¼Ì³ÐÁË `AbstractAdvisorAutoProxyCreator`£¬`AnnotationAwareAspectJAutoProxyCreator` Óּ̳ÐÁË `AspectJAwareAdvisorAutoProxyCreator`¡£
+
+ͨ¹ýÒÔÉÏ·ÖÎö£¬`AutoProxyRegistrar` ×îÖÕÏò spring ÈÝÆ÷×¢²áÁË `InfrastructureAdvisorAutoProxyCreator`(`aop` δÆôÓõÄÇé¿öÏÂ)£¬Èç¹ûÆôÓÃÁË `aop`£¬Ôò»á×¢²á `AspectJAwareAdvisorAutoProxyCreator`(»ùÓÚ `xml` µÄ `aop`) »ò `AnnotationAwareAspectJAutoProxyCreator`(»ùÓÚ `annotation` µÄ `aop`)¡£
+
+#### 3.2 `ProxyTransactionManagementConfiguration`
+
+½ÓÏÂÀ´ÎÒÃÇÀ´¿´¿´ `ProxyTransactionManagementConfiguration` Àà¡£Ãû×ÖÉÏÀ´¿´£¬ÕâÊǸöÅäÖÃÀࣺ
+
+```
+@Configuration(proxyBeanMethods = false)
+public class ProxyTransactionManagementConfiguration
+ extends AbstractTransactionManagementConfiguration {
+
+ /**
+ * ¶ÁÈ¡SpringµÄ @Transactional ×¢½â£¬²¢½«ÏàÓ¦µÄÊÂÎñÊôÐÔ¹«¿ª¸øSpringµÄÊÂÎñ»ù´¡½á¹¹
+ */
+ @Bean
+ @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+ public TransactionAttributeSource transactionAttributeSource() {
+ return new AnnotationTransactionAttributeSource();
+ }
+
+ /**
+ * TransactionInterceptor¼Ì³ÐÁËAdvice£¬Õâ¸öÀàÊǸöadvice£¬ÓÃÀ´´¦ÀíÊÂÎñµÄÖ´ÐвÙ×÷
+ * @param transactionAttributeSource£ºÀ´×ÔÓÚÉÏÃæµÄ transactionAttributeSource() ·½·¨
+ */
+ @Bean
+ @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+ public TransactionInterceptor transactionInterceptor(
+ TransactionAttributeSource transactionAttributeSource) {
+ TransactionInterceptor interceptor = new TransactionInterceptor();
+ // ÉèÖÃÊÂÎñÊôÐÔ´¦Àí¶ÔÏ󣬾ÍÊÇÓÃÀ´´¦Àí @Transactional ×¢½â µÄ¶ÁÈ¡
+ interceptor.setTransactionAttributeSource(transactionAttributeSource);
+ if (this.txManager != null) {
+ interceptor.setTransactionManager(this.txManager);
+ }
+ return interceptor;
+ }
+
+ /**
+ * ÊÂÎñÔöÇ¿Æ÷.
+ * @param transactionAttributeSource£ºÀ´×ÔÓÚÉÏÃæµÄ transactionAttributeSource() ·½·¨
+ * @param transactionInterceptor£ºÀ´×ÔÓÚÉÏÃæµÄ transactionInterceptor(...) ·½·¨
+ */
+ @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
+ @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+ public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
+ TransactionAttributeSource transactionAttributeSource,
+ TransactionInterceptor transactionInterceptor) {
+ BeanFactoryTransactionAttributeSourceAdvisor advisor
+ = new BeanFactoryTransactionAttributeSourceAdvisor();
+ // ÊÂÎñÊôÐÔÀ࣬ÓÃÀ´±£´æ @Transactional µÄÊôÐÔ
+ advisor.setTransactionAttributeSource(transactionAttributeSource);
+ // ÅäÖÃadvice£¬ÔÚadviceÀï´¦ÀíÊÂÎñ
+ advisor.setAdvice(transactionInterceptor);
+ if (this.enableTx != null) {
+ advisor.setOrder(this.enableTx.getNumber("order"));
+ }
+ return advisor;
+ }
+
+}
+
+```
+
+¿ÉÒÔ¿´µ½Õâ¸öÀàÒýÈëÁËÒ» Щ `bean`£º
+
+* `transactionAttributeSource`£ºÀàÐÍΪ `AnnotationTransactionAttributeSource`£¬ÓÃÀ´½âÎö `@Transactional` ×¢½â£»
+* `transactionInterceptor`£ºÀàÐÍΪ `TransactionInterceptor`£¬`Advice` µÄ×ÓÀ࣬´¦ÀíÊÂÎñµÄÂß¼ÔÚÕâ¸öÀàÀ
+* `transactionAdvisor`£ºÀàÐÍΪ `BeanFactoryTransactionAttributeSourceAdvisor`£¬ÕâÊǸö `Advisor`£¬ÓÃÀ´´¦ÀíÇÐÃæÂß¼£¬ÄÚ²¿¼¯³ÉÁËÉÏÃæÁ½¸ö¶ÔÏó£º`transactionAttributeSource` Óë `transactionInterceptor`£»
+
+`ProxyTransactionManagementConfiguration` ¼Ì³ÐÁË `AbstractTransactionManagementConfiguration`£¬¶ø `AbstractTransactionManagementConfiguration` ÖÐÒ²ÒýÈëÁËһЩ `bean`£º
+
+```
+@Configuration
+public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
+
+ @Nullable
+ protected AnnotationAttributes enableTx;
+
+ /**
+ * ±£´æÊÂÎñ¹ÜÀíÆ÷
+ */
+ @Nullable
+ protected TransactionManager txManager;
+
+ /**
+ * À´×ÔÓÚ ImportAware ½Ó¿ÚµÄ·½·¨
+ */
+ @Override
+ public void setImportMetadata(AnnotationMetadata importMetadata) {
+ this.enableTx = AnnotationAttributes.fromMap(importMetadata
+ .getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
+ if (this.enableTx == null) {
+ throw new IllegalArgumentException(
+ "@EnableTransactionManagement is not present on importing class "
+ + importMetadata.getClassName());
+ }
+ }
+
+ /**
+ * ÅäÖÃÊÂÎñ¹ÜÀíÆ÷.
+ * ×¢ÈëspringÈÝÆ÷ÖÐËùÓÐµÄ TransactionManagementConfigurer ¶ÔÏó
+ * TransactionManagementConfigurer¾ÍÖ»ÓÐÒ»¸ö·½·¨£º
+ * TransactionManager annotationDrivenTransactionManager()
+ * Õâ¸ö·½·¨ÓÃÀ´·µ»ØÒ»¸öÊÂÎñ¹ÜÀíÆ÷
+ */
+ @Autowired(required = false)
+ void setConfigurers(Collection configurers) {
+ if (CollectionUtils.isEmpty(configurers)) {
+ return;
+ }
+ if (configurers.size() > 1) {
+ throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
+ }
+ TransactionManagementConfigurer configurer = configurers.iterator().next();
+ this.txManager = configurer.annotationDrivenTransactionManager();
+ }
+
+ /**
+ * ´¦Àíʼþ¼àÌý£¬ÓÃÀ´´¦Àí @TransactionalEventListener ×¢½âµÄ·½·¨.
+ */
+ @Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
+ @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+ public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
+ return new TransactionalEventListenerFactory();
+ }
+
+}
+
+```
+
+* `void setConfigurers(Collection configurers)`£º×¢Èë `TransactionManagementConfigurer` ¶ÔÏ󣬾ßÌå×÷ÓÃÒÑÔÚ´úÂë×¢ÊÍÖÐ˵Ã÷£»
+* `TransactionalEventListenerFactory`£ºÀàÐÍΪ `TransactionalEventListenerFactory`£¬ÓÃÀ´´¦ÀíÊÂÎñʼþ£¨Ö÷ÒªÊÇ `@TransactionalEventListener` ×¢½âµÄ·½·¨£¬¹ØÓÚÕⲿ·ÖµÄÄÚÈÝ£¬±¾ÎľͲ»Õ¹¿ªÁË£©¡£
+
+ºÃÁË£¬ÓÐÁËÕâЩ¶ÔÏóºó£¬spring ¾Í¿ÉÒÔ½øÐÐÊÂÎñ´¦ÀíÁË£¬ÕâЩÎÒÃÇÁôµ½ÏÂÆªÎÄÕÂÔÙ·ÖÎö¡£
+
+### 4\. ×ܽá
+
+±¾ÎÄÏÈÊÇ´ÓÁ½¸ö demo ÈëÊÖ£¬Ê¾·¶ÁËÈç¹ûÊÇÓÉÎÒÃÇ×Ô¼º¿ª·¢Ò»¸ö»ùÓÚ spring aop µÄÊÂÎñ¹ÜÀí¹¦ÄÜÊÇÈçºÎ½øÐе쬽Ó×ÅÓÖÓÃÒ»¸ö demo ʾ·¶ÁËÈçºÎʹÓà spring ÌṩµÄÊÂÎñ¹ÜÀí¹¦ÄÜ£¬È»ºó¾Í¾ßÌå·ÖÎöÁË spring ÊÂÎñÆôÓÃ×¢½â `@EnableTransactionManagement` µÄ¹¦ÄÜ¡£
+
+`@EnableTransactionManagement` ÊÇ spring ÖÐÓÃÀ´ÆôÓÃÊÂÎñ¹ÜÀí¹¦Äܵģ¬ÔÚ `AdviceMode` Ϊ `proxy` ģʽÏ£¬¸Ã×¢½âÏò spring ÖÐÒýÈëÁËÁ½¸öÀࣺ`AutoProxyRegistrar`¡¢`ProxyTransactionManagementConfiguration`£¬×÷ÓÃÈçÏ£º
+
+* `AutoProxyRegistrar`£º`aop` δÆôÓõÄÇé¿öÏ£¬»áÏò spring ÈÝÆ÷ÖÐ×¢²á `InfrastructureAdvisorAutoProxyCreator`£»Èç¹ûÆôÓÃÁË `aop`£¬Ôò»á×¢²á `AspectJAwareAdvisorAutoProxyCreator`(»ùÓÚ `xml` µÄ `aop`) »ò `AnnotationAwareAspectJAutoProxyCreator`(»ùÓÚ `annotation` µÄ `aop`)¡£ÕâÈý¸öÀà¶¼ÊÇ `AbstractAdvisorAutoProxyCreator` µÄ×ÓÀ࣬ÓÃÀ´Éú³É´úÀí¶ÔÏó¡£
+
+* `ProxyTransactionManagementConfiguration`£ºÕâÊÇÒ»¸öÅäÖÃÀ࣬ͨ¹ý´øÓÐ `@Bean` ×¢½âµÄ·½·¨ÏòÈÝÆ÷ÖÐÒýÈëÁËһϵÁÐµÄ bean£¬ÓÃÀ´´¦ÀíÊÂÎñÂß¼£¬¶ÔÕâЩ bean£¬±¾ÎÄÖ»Ðè´ó¸ÅÁ˽⼴¿É¡£
+
+±¾ÎľÍÏȵ½ÕâÀïÁË£¬ÏÂÆªÎÄÕ¼ÌÐø·ÖÎöÊÂÎñ´¦Àí»úÖÆ¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4773454](https://my.oschina.net/funcy/blog/4773454) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\270\211\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 01.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\270\211\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 01.md"
new file mode 100644
index 0000000..73a5691
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\270\211\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 01.md"
@@ -0,0 +1,387 @@
+ÔÚÉÏһƪÎÄÕµÄ×îºó£¬ÎÒÃÇÌáµ½ÊÂÎñµÄÖ´ÐÐÔÚ `TransactionAspectSupport#invokeWithinTransaction` ·½·¨ÖУ¬±¾ÎĽ«´ÓÕâ¸ö·½·¨³ö·¢£¬Ì½¾¿ spring µÄÊÂÎñ»úÖÆ¡£
+
+×¢£º±¾ÎÄËù̽ÌÖµÄÊý¾Ý¿âÊÇ `mysql`£¬ÆäËûÊý¾Ý¿â¿ÉÄÜ»áÓÐËù²îÒì¡£
+
+### 1. ÊÂÎñÏà¹Ø¸ÅÄî
+
+ÔÚÕýʽ·ÖÎöÊÂÎñÔ´Âëǰ£¬Ò»Ð©Ç°ÖÃ֪ʶ»¹ÊÇÒªÁ˽âһϵģ¬ÕâÀïÖ÷Òª½éÉÜÓë spring Ïà¹ØµÄÊÂÎñ¸ÅÄî¡£
+
+#### 1.1 ÊÂÎñµÄ¸ôÀë¼¶±ð
+
+ÊÂÎñÓÐËÄ´óÌØÐÔ `ACID`£¬ÁоÙÈçÏ£º
+
+- Ô×ÓÐÔ£¨`Atomicity`£©
+- Ò»ÖÂÐÔ£¨`Consistency`£©
+- ¸ôÀëÐÔ£¨`Isolation`£©
+- ³Ö¾ÃÐÔ£¨`Durability`£©
+
+¶øÊÂÎñµÄ¸ôÀë¼¶±ðÕýÊǶԸôÀëÐÔ£¨`Isolation`£©µÄ½øÒ»²½»®·Ö£¬ÕâЩ¸ôÀë¼¶±ðÈçÏ£º
+
+- `¶ÁδÌá½»`
+- `¶ÁÌá½»`
+- `¿ÉÖØ¸´¶Á`
+- `´®Ðл¯`
+
+¹ØÓÚÕâЩ¸ÅÄî±¾ÎIJ¢²»»áÉîÈë½â¶Á£¬ÎÒÃÇÖØµã»¹ÊǹØ×¢ spring Ïà¹ØµÄÄÚÈÝ£¬spring ¶ÔÊÂÎñ¸ôÀë¼¶±ðµÄ¶¨ÒåÔÚ `org.springframework.transaction.annotation.Isolation` ÖУ¬´úÂëÈçÏ£º
+
+```
+public enum Isolation {
+
+ /**
+ * ĬÈÏÖµ£¬²»ÉèÖøôÀë¼¶±ð£¬×îÖÕʹÓõÄÊÇÊý¾Ý¿âÉèÖõĸôÀë¼¶±ð
+ */
+ DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),
+
+ /**
+ * ¶ÁδÌá½»
+ */
+ READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
+
+ /**
+ * ¶ÁÌá½»
+ */
+ READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
+
+ /**
+ * ¿ÉÖØ¸´¶Á
+ */
+ REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
+
+ /**
+ * ´®Ðл¯
+ */
+ SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
+
+ ...
+}
+```
+
+ÎÒÃÇ¿ÉÒÔʹÓà `@Transactional` ×¢½âµÄ `isolation` À´ÉèÖøôÀë¼¶±ð
+
+#### 1.2 ÊÂÎñµÄ³¬Ê±Ê±¼ä
+
+- ¿ÉÒÔ¸øÊÂÎñÖ¸¶¨Ò»¸öÖ´ÐÐʱ¼ä£¬Èç¹ûÖ´ÐÐÏûºÄµÄʱ¼ä³¬¹ýÁËÖ¸¶¨Ê±¼ä£¬ÊÂÎñ¾Í»áÅ׳öÒì³£´Ó¶ø»Ø¹ö
+- ¿ÉÒÔÔÚ `@Transactional` ×¢½âµÄ `timeout` À´ÉèÖó¬Ê±Ê±¼ä
+
+#### 1.3 Ö»¶ÁÊÂÎñ
+
+- ¿ÉÒÔ½«ÊÂÎñÉèÖÃΪ`Ö»¶Áģʽ`£¬Õâ¸öÎÒÆ½Ê±Óûù±¾Ã»Óõ½£¬²éµ½Ò»Ð©ÎÄÕÂ˵£¬½«ÊÂÎñÉèÖÃΪ`Ö»¶Áģʽ`ºó£¬ÆäËûÊÂÎñÖеĸüÐÂÖ»¶ÁÊÂÎñ¿´²»µ½£¬ÇÒÖ»¶ÁÊÂÎñÖв»ÄÜÓÐд²Ù×÷£¬ÕæÊµÐÔÓдýÑéÖ¤
+- ÎÒÃÇ¿ÉÒÔʹÓà `@Transactional` ×¢½âµÄ `readOnly` À´ÉèÖÃÖ»¶Áģʽ
+
+#### 1.4 ÊÂÎñµÄ´«²¥ÀàÐÍ
+
+ÎÒÃÇÊÔÏëÒ»ÖÖÇé¿ö£º`·½·¨A` Óë`·½Ê½B` ¶¼¿ªÆôÁËÊÂÎñ£¬ÔÚ`·½·¨B` Öе÷ÓÃ`·½·¨A`£¬Èç¹ûÔÚ`·½·¨A` Ö´ÐÐÍê³Éºó£¬`·½·¨B` ±¨´íÁË£¬´úÂëʾÒâÈçÏ£º
+
+```
+class A {
+ // ¿ªÆôÁËÊÂÎñ
+ @Transactional
+ public void methdA() {
+ // ´¦ÀíһЩ²Ù×÷
+ ...
+ }
+}
+
+class B {
+ // ¿ªÆôÁËÊÂÎñ
+ @Transactional
+ public void methodB() {
+ // 1. ´¦ÀíһЩ²Ù×÷
+ ...
+ // 2. µ÷ÓÃ methodA()
+ a.methodA();
+ // 3. ÕâÀﱨ¸ö´í
+ throw new RuntimeException();
+ }
+}
+```
+
+ÓÉÓÚ¿ªÆôÁËÊÂÎñ£¬`·½·¨B` ÊÇÒ»¶¨»á»Ø¹öµÄ£¬ÄÇô`·½·¨A` Òª²»Òª»Ø¹öÄØ£¿
+
+- Èç¹ûÎÒÃǰÑ`·½·¨A` Óë`·½·¨B` µÄÊÂÎñ¿´³ÉÊÇͬһ¸öÊÂÎñ£¬`·½·¨A` Ó¦¸ÃÒ²ÊÇÒª»Ø¹öµÄ
+- Èç¹ûÎÒÃǰÑ`·½·¨A` Óë`·½·¨B` ¿´³ÉÊÇÔÚÁ½¸ö¶ÀÁ¢µÄÊÂÎñÖÐÖ´ÐУ¬`·½·¨A` µÄÖ´ÐÐÓë`·½·¨B` µÄ±¨´íÎ޹أ¬`·½·¨A` ¾Í²»Ó¦¸Ã»Ø¹ö
+
+ΪÁË´¦ÀíÕâÖÖ¾À·×£¬spring ÒýÈëÁË`ÊÂÎñµÄ´«²¥ÀàÐÍ`µÄ¸ÅÄÎÒÃÇ¿ÉÒÔʹÓà `@Transactional` ×¢½âµÄ `propagation` À´ÉèÖÃÖ»¶Áģʽ£º
+
+```
+public @interface Transactional {
+ ...
+
+ // ĬÈϵļ¶±ðΪ Propagation.REQUIRED
+ Propagation propagation() default Propagation.REQUIRED;
+
+}
+```
+
+spring Ò»¹²¶¨ÒåÁË 7 ÖÖÊÂÎñµÄ´«²¥ÀàÐÍ£¬ÁоÙÈçÏ£º
+
+| ÊÂÎñ´«²¥ÐÐΪ | ÃèÊö |
+| --------------------------- | ------------------------------------------------------------ |
+| `PROPAGATION_REQUIRED` | ¡¾Ä¬ÈÏÖµ£º±ØÐè¡¿µ±Ç°·½·¨±ØÐëÔÚÊÂÎñÖÐÔËÐУ¬Èç¹ûµ±Ç°Ïß³ÌÖÐûÓÐÊÂÎñ£¬Ôò¿ªÆôÒ»¸öеÄÊÂÎñ£»Èç¹ûµ±Ç°Ïß³ÌÖÐÒѾ´æÔÚÊÂÎñ£¬Ôò·½·¨½«»áÔÚ¸ÃÊÂÎñÖÐÔËÐС£ |
+| `PROPAGATION_MANDATORY` | ¡¾Ç¿ÖÆ¡¿µ±Ç°·½·¨±ØÐëÔÚÊÂÎñÖÐÔËÐУ¬Èç¹ûµ±Ç°Ïß³ÌÖв»´æÔÚÊÂÎñ£¬Ôò**Å׳öÒì³£** |
+| `PROPAGATION_SUPPORTS` | ¡¾Ö§³Ö¡¿µ±Ç°·½·¨µ¥¶ÀÔËÐÐʱ²»ÐèÒªÊÂÎñ£¬µ«Èç¹ûµ±Ç°Ïß³ÌÖдæÔÚÊÂÎñʱ£¬·½·¨»áÔÚÊÂÎñÖÐÔËÐÐ |
+| `PROPAGATION_REQUIRES_NEW` | ¡¾ÐÂÊÂÎñ¡¿µ±Ç°·½·¨±ØÐëÔÚ¶ÀÁ¢µÄÊÂÎñÖÐÔËÐУ¬Èç¹ûµ±Ç°Ïß³ÌÖÐÒѾ´æÔÚÊÂÎñ£¬Ôò½«¸ÃÊÂÎñ¹ÒÆð£¬ÖØÐ¿ªÆôÒ»¸öÊÂÎñ£¬Ö±µ½·½·¨ÔËÐнáÊøÔÙ»Ö¸´Ö®Ç°µÄÊÂÎñ |
+| `PROPAGATION_NESTED` | ¡¾Ç¶Ìס¿µ±Ç°·½·¨±ØÐëÔÚÊÂÎñÖÐÔËÐУ¬Èç¹ûµ±Ç°Ïß³ÌÖдæÔÚÊÂÎñ£¬Ôò½«¸ÃÊÂÎñ±ê×¢**±£´æµã**£¬ÐγÉǶÌ×ÊÂÎñ¡£Ç¶Ì×ÊÂÎñÖеÄ×ÓÊÂÎñ³öÏÖÒì³£²»»áÓ°Ïìµ½¸¸ÊÂÎñ±£´æµã֮ǰµÄ²Ù×÷¡£ |
+| `PROPAGATION_NOT_SUPPORTED` | ¡¾²»Ö§³Ö¡¿µ±Ç°·½·¨²»»áÔÚÊÂÎñÖÐÔËÐУ¬Èç¹ûµ±Ç°Ïß³ÌÖдæÔÚÊÂÎñ£¬Ôò½«ÊÂÎñ¹ÒÆð£¬Ö±µ½·½·¨ÔËÐнáÊø |
+| `PROPAGATION_NEVER` | ¡¾²»ÔÊÐí¡¿µ±Ç°·½·¨²»ÔÊÐíÔÚÊÂÎñÖÐÔËÐУ¬Èç¹ûµ±Ç°Ïß³ÌÖдæÔÚÊÂÎñ£¬Ôò**Å׳öÒì³£** |
+
+×¢ÒâÌå»áÒÔÏÂÀàÐ͵ÄÇø±ð£º
+
+1. `PROPAGATION_REQUIRED` Óë `PROPAGATION_MANDATORY`
+ - `PROPAGATION_REQUIRED`£º±ØÐëÒªÔÚÊÂÎñÖÐÔËÐУ¬Ã»ÓÐÊÂÎñ¾Í**¿ªÆôÐÂÊÂÎñ**
+ - `PROPAGATION_MANDATORY`£º±ØÐëÒªÔÚÊÂÎñÖÐÔËÐУ¬Ã»ÓÐÊÂÎñ¾Í**Å×Òì³£**
+2. `PROPAGATION_NOT_SUPPORTED` Óë `PROPAGATION_NEVER`
+ - `PROPAGATION_NOT_SUPPORTED`£º²»ÄÜÔÚÊÂÎñÖÐÔËÐУ¬ÓÐÊÂÎñ¾Í**¹ÒÆðÊÂÎñ**
+ - `PROPAGATION_NEVER`£º²»ÄÜÔÚÊÂÎñÖÐÔËÐУ¬ÓÐÊÂÎñ¾Í**Å×Òì³£**
+3. `PROPAGATION_REQUIRES_NEW` Óë `PROPAGATION_NESTED`
+ - `PROPAGATION_REQUIRES_NEW`£ºÐÂÊÂÎñÖ´ÐÐÍê³Éºó£¬¾ÉÊÂÎñ±¨´í£¬Ö»»Ø¹ö¾ÉÊÂÎñ£¬ÐÂÊÂÎñ²»»Ø¹ö£»ÐÂÊÂÎñÖ´Ðб¨´í£¬Ð¾ÉÊÂÎñÒ»Æð»Ø¹ö
+ - `PROPAGATION_NESTED`£º×ÓÊÂÎñÖ´ÐÐÍê³Éºó£¬¸¸ÊÂÎñ±¨´í£¬»Ø¹öµ½±£´æµã£»×ÓÊÂÎñÖ´Ðб¨´í£¬Ò²Êǻعöµ½±£´æµã
+
+### 2. demo ×¼±¸
+
+Ã÷È·ÁËÒÔÉϸÅÄîºó£¬½ÓÏÂÀ´¾Í¿ªÊ¼·ÖÎöÁË£¬ÎÒÃÇÏÈ×¼±¸¸ö¼òµ¥µÄ demo£º
+
+ÏÈÊÇ×¼±¸Ò»Ð©ÅäÖãº
+
+```
+@Configuration
+@ComponentScan("org.springframework.learn.tx.demo03")
+@EnableTransactionManagement(proxyTargetClass = true)
+public class TxDemo03Config {
+
+ /**
+ * Éú³ÉÊý¾ÝÔ´
+ */
+ @Bean
+ public DataSource dataSource() throws Exception {
+ Driver driver = new com.mysql.jdbc.Driver();
+ String url = "jdbc:mysql://localhost:3306/test";
+ String username = "root";
+ String password = "123";
+ return new SimpleDriverDataSource(driver, url, username, password);
+ }
+
+ /**
+ * Éú³ÉjdbcTemplate£¬ºóÃæ¾ÍÊÇÓÃÕâ¸öÀàÀ´´¦ÀíÊý¾Ý¿âµÄ²Ù×÷
+ */
+ @Bean
+ public JdbcTemplate jdbcTemplate(DataSource dataSource) {
+ return new JdbcTemplate(dataSource);
+ }
+
+ /**
+ * ÊÂÎñ¹ÜÀíÆ÷
+ */
+ @Bean
+ public DataSourceTransactionManager transactionManager(DataSource dataSource) {
+ return new DataSourceTransactionManager(dataSource);
+ }
+
+}
+```
+
+¶ÔÒÔÉÏ´úÂë˵Ã÷ÈçÏ£º
+
+- Êý¾ÝÔ´£ºÊ¹ÓõÄÊÇ spring ÌṩµÄ `SimpleDriverDataSource`£¬Õâ¸öÊý¾ÝÔ´¹¦Äܲ»¶à£¬ÊʺÏÕâ¸ö¼òµ¥µÄ demo
+- ´¦Àí jdbc Ïà¹Ø²Ù×÷£ºÒ²ÊÇʹÓà spring ÌṩµÄ `jdbcTemplate`£¬×÷Ϊһ¸ö¼òµ¥µÄ demo£¬²»ÏëÒýÈë `mybatis`£¬`jpa` µÈ
+- ÊÂÎñ¹ÜÀíÆ÷£ºÊ¹ÓõÄÒ²ÊÇ spring ÌṩµÄ `DataSourceTransactionManager` £¬¶Ôµ¥Êý¾ÝÔ´À´Ëµ£¬Õâ¸öÍêÈ«¹»ÓÃÁË
+
+×¼±¸Ò»¸ö mysql µÄ²Ù×÷£¬Òª¿ªÆôÊÂÎñ£º
+
+```
+@Service
+public class UserService {
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ /**
+ * Êý¾Ý¿â²åÈë²Ù×÷£¬Ê¹Óà @Transactional ¿ªÆôÊÂÎñ
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public int insert() {
+ String sql = "insert into `user`(`login_name`, `nick`, `create_time`, `update_time`)"
+ + "values (?, ?, ?, ?)";
+ int result = jdbcTemplate.update(sql, "test", "test", new Date(), new Date());
+ if(true) {
+ //throw new RuntimeException("Å׳ö¸öÒì³£");
+ }
+ System.out.println(result);
+ return result;
+ }
+
+}
+```
+
+×îºóÊÇÖ÷Àࣺ
+
+```
+public class TxDemo03Main {
+
+ public static void main(String[] args) {
+ AnnotationConfigApplicationContext applicationContext
+ = new AnnotationConfigApplicationContext(TxDemo03Config.class);
+ UserService userService = applicationContext.getBean(UserService.class);
+ userService.insert();
+
+ }
+}
+```
+
+Õâ¸ö demo Ê®·Ö¼òµ¥£¬¾Í²»¶à×ö·ÖÎöÁË£¬ÎÒÃǽÓÏÂÀ´»áͨ¹ýÕâ¸ö demo ½øÐÐһЩµ÷¶È²Ù×÷£¬Ì½¾¿Ï spring ¶ÔÊÂÎñµÄ¸ôÀë¼¶±ð¡¢´«²¥·½Ê½µÄ´¦Àí¡£
+
+### 3. `TransactionAspectSupport#invokeWithinTransaction`
+
+±¾ÎÄÒ»¿ªÆªÎÒÃǾÍ˵¹ý£¬ÊÂÎñµÄ´¦ÀíÔÚ `TransactionAspectSupport#invokeWithinTransaction` ·½·¨£¬½ÓÏÂÀ´ÎÒÃǽ«Öصã·ÖÎöÕâ¸ö·½·¨¡£
+
+ÉÏ´úÂ룺
+
+```
+protected Object invokeWithinTransaction(Method method, @Nullable Class> targetClass,
+ final InvocationCallback invocation) throws Throwable {
+ TransactionAttributeSource tas = getTransactionAttributeSource();
+
+ // 1. »ñÈ¡ @Transactional µÄÊôÐÔÅäÖÃ
+ final TransactionAttribute txAttr = (tas != null
+ ? tas.getTransactionAttribute(method, targetClass) : null);
+
+ // 2. »ñÈ¡ÊÂÎñ¹ÜÀíÆ÷£¨IOCÈÝÆ÷ÖлñÈ¡£©
+ final TransactionManager tm = determineTransactionManager(txAttr);
+
+ // Õⲿ·ÖµÄ´úÂëÊÇÕë¶Ô TransactionManager ÊÇ ReactiveTransactionManager µÄÇé¿ö£¬²»×÷·ÖÎö
+ ...
+
+ // 3. ½« TransactionManager ת»»Îª PlatformTransactionManager
+ PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
+ // 4. »ñÈ¡·½·¨µÄÈ«ÏÞ¶¨Ãû£¬¸ñʽΪ£º"°üÃû.ÀàÐÍ.·½·¨Ãû"
+ final String joinpointIdentification
+ = methodIdentification(method, targetClass, txAttr);
+ if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
+ // 5. »ñÈ¡ÊÂÎñÐÅÏ¢£¬»áÔÚÕâÀ↑ÆôÊÂÎñ
+ TransactionInfo txInfo = createTransactionIfNecessary(
+ ptm, txAttr, joinpointIdentification);
+ Object retVal;
+ try {
+ // 6. Ö´ÐоßÌåµÄÒµÎñ
+ retVal = invocation.proceedWithInvocation();
+ }
+ catch (Throwable ex) {
+ // 7. Òì³£»Ø¹ö
+ completeTransactionAfterThrowing(txInfo, ex);
+ throw ex;
+ }
+ finally {
+ // 8. ÖØÖÃÊÂÎñÐÅÏ¢£¬¾ÍÊǽ«ÊÂÎñÐÅÏ¢ÉèÖÃΪ¾ÉµÄ
+ cleanupTransactionInfo(txInfo);
+ }
+
+ if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
+ TransactionStatus status = txInfo.getTransactionStatus();
+ if (status != null && txAttr != null) {
+ retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
+ }
+ }
+ // 9. Ìá½»ÊÂÎñ
+ commitTransactionAfterReturning(txInfo);
+ return retVal;
+ }
+ else {
+ // ´¦Àí CallbackPreferringPlatformTransactionManager ÀàÐ굀 TransactionManager£¬²»×÷·ÖÎö
+ ...
+ }
+}
+```
+
+¶Ô `TransactionAspectSupport#invokeWithinTransaction` ·½·¨µÄÄÚÈÝ£¬×¢ÊÍÖÐÒÑÏêϸ˵Ã÷£¬½ÓÏÂÀ´ÎªÎÒÃÇÀ´·ÖÎöÕâЩִÐйý³Ì¡£
+
+#### 3.1 »ñÈ¡ `@Transactional` µÄÊôÐÔÅäÖÃ
+
+Õâ¸ö¾ÍÊÇ»ñÈ¡ `UserService#insert` ·½·¨Éϱê¼ÇµÄ `@Transactional` µÄÊôÐÔÅäÖ㬵õ½µÄ½á¹ûÈçÏ£º
+
+
+
+#### 3.2 »ñÈ¡ÊÂÎñ¹ÜÀíÆ÷
+
+»ñÈ¡ÊÂÎñ¹ÜÀíÆ÷µÄ·½·¨Îª `TransactionAspectSupport#determineTransactionManager`£¬Ö±½Ó¿´´úÂ룺
+
+```
+protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
+ if (txAttr == null || this.beanFactory == null) {
+ return getTransactionManager();
+ }
+
+ // Èç¹ûÔÚ @Transaction ×¢½âÉÏÖ¸¶¨ÁËÊÂÎñ¹ÜÀíÆ÷£¬¾Í´ÓspringÈÝÆ÷ÖлñÈ¡Õâ¸öÊÂÎñ¹ÜÀíÆ÷
+ String qualifier = txAttr.getQualifier();
+ if (StringUtils.hasText(qualifier)) {
+ return determineQualifiedTransactionManager(this.beanFactory, qualifier);
+ }
+ // Ö¸¶¨ÊÂÎñ¹ÜÀíÆ÷Ãû³Æ£¬×îÖÕÒ²ÊÇ´ÓspringÈÝÆ÷ÖлñÈ¡
+ else if (StringUtils.hasText(this.transactionManagerBeanName)) {
+ return determineQualifiedTransactionManager(
+ this.beanFactory, this.transactionManagerBeanName);
+ }
+ else {
+ // Ö¸¶¨ÊÂÎñ¹ÜÀíÆ÷¶ÔÏó£¬Ö±½Ó·µ»Ø
+ TransactionManager defaultTransactionManager = getTransactionManager();
+ if (defaultTransactionManager == null) {
+ // ´Ó»º´æÖлñȡĬÈϵÄ
+ defaultTransactionManager = this.transactionManagerCache
+ .get(DEFAULT_TRANSACTION_MANAGER_KEY);
+ if (defaultTransactionManager == null) {
+ // ¸ù¾ÝÀàÐÍ´Ó spring ÈÝÆ÷Öлñȡһ¸öÊÂÎñ¹ÜÀíÆ÷
+ defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
+ this.transactionManagerCache.putIfAbsent(
+ DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
+ }
+ }
+ return defaultTransactionManager;
+ }
+}
+```
+
+´úÂëËäÈ»Óе㳤£¬µ«Âß¼·Ç³£ÇåÎú£¬ÕâÀï¶Ô¸Ã·½·¨µÄÁ÷³Ì×ܽáÈçÏ£º
+
+1. Èç¹ûÔÚ `@Transaction` ×¢½âÉÏÖ¸¶¨ÁËÊÂÎñ¹ÜÀíÆ÷£¬¾Í´Ó spring ÈÝÆ÷ÖлñÈ¡¸ÃÊÂÎñ¹ÜÀíÆ÷
+2. Èç¹ûÖ¸¶¨ÊÂÎñ¹ÜÀíÆ÷Ãû³Æ£¬¾Í´Ó spring ÈÝÆ÷ÖлñÈ¡¸ÃÊÂÎñ¹ÜÀíÆ÷
+3. Èç¹ûÖ¸¶¨ÊÂÎñ¹ÜÀíÆ÷¶ÔÏó£¬Ö±½Ó·µ»Ø
+4. ÒÔÉ϶¼²»Âú×㣬ֱ½Ó´Ó spring ÈÝÆ÷ÖлñÈ¡ÀàÐÍΪ `TransactionManager` µÄ bean
+
+ÔÚ `TxDemo03Config` ÖУ¬ÎÒÃÇÅäÖÃÊÂÎñ¹ÜÀíÆ÷Ϊ `DataSourceTransactionManager`£º
+
+```
+public DataSourceTransactionManager transactionManager(DataSource dataSource) {
+ return new DataSourceTransactionManager(dataSource);
+}
+```
+
+ÕâÀïµÃµ½µÄÒ²ÊÇ `DataSourceTransactionManager`£º
+
+
+
+#### 3.3 ½« `TransactionManager` ת»»Îª `PlatformTransactionManager`
+
+Õâ¸öûɶºÃ˵µÄ£¬`DataSourceTransactionManager` ¾ÍÊÇ `PlatformTransactionManager` µÄ×ÓÀ࣬´úÂëÀï×öÁËÒ»¸öÀàÐÍת»»¡£
+
+```
+private PlatformTransactionManager asPlatformTransactionManager(
+ @Nullable Object transactionManager) {
+ if (transactionManager == null || transactionManager instanceof PlatformTransactionManager) {
+ return (PlatformTransactionManager) transactionManager;
+ } else {
+ // Å׸öÒì³£
+ ...
+ }
+}
+```
+
+#### 3.4 »ñÈ¡·½·¨µÄÈ«ÏÞ¶¨Ãû
+
+ÕâÒ»²½»áÄõ½·½·¨µÄÈ«ÏÞ¶¨Ãû£¬¸ñʽΪ£º"°üÃû¡£ÀàÐÍ¡£·½·¨Ãû"£¬ÕâҲûɶºÃ˵µÄ£¬ÕâÒ»²½µÃµ½µÄ½á¹ûÈçÏ£º
+
+
+
+ÏÞÓÚÆª·ù£¬±¾ÎľÍÏÈ·ÖÎöµ½ÕâÀïÁË£¬ÏÂÆªÎÒÃǼÌÐø¡£
+
+------
+
+*±¾ÎÄÔÎÄÁ´½Ó£ºhttps://my.oschina.net/funcy/blog/4773459 £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£*
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\272\214\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\346\211\247\350\241\214\346\265\201\347\250\213.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\272\214\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\346\211\247\350\241\214\346\265\201\347\250\213.md"
new file mode 100644
index 0000000..f086983
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\272\214\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\346\211\247\350\241\214\346\265\201\347\250\213.md"
@@ -0,0 +1,664 @@
+ÔÚ [spring ÊÂÎñÖ®ÈÏʶÊÂÎñ×é¼þ](https://my.oschina.net/funcy/blog/4773454)Ò»ÎÄÖУ¬ÎÒÃÇͨ¹ýÒ»¸ö demo ÑÝʾÁËÈçºÎʹÓà spring ÊÂÎñ¹ÜÀí¹¦ÄÜ£¬È»ºó·ÖÎöÁË `@EnableTransactionManagement` ×¢½âµÄ¹¦ÄÜ£¬±¾ÎĽ«¼ÌÐø·ÖÎö spring ÊÂÎñÏà¹Ø´úÂë¡£
+
+### 1\. ´úÀí¶ÔÏó´´½¨Á÷³Ì
+
+spring ÊÂÎñ¹ÜÀí¹¦ÄÜÊÇ»ùÓÚ aop µÄ£¬Ê¹ÓôúÀí¶ÔÏóÀ´½øÐÐÊÂÎñµÄһϵÁвÙ×÷£¬±¾ÎĽ«Í¨¹ýµ÷ÊԵķ½Ê½À´·ÖÎö´úÀí¶ÔÏóµÄ´´½¨¹ý³Ì¡£
+
+ÔÚ [spring ÊÂÎñÖ®ÈÏʶÊÂÎñ×é¼þ](https://my.oschina.net/funcy/blog/4773454)ÖÐÎÒÃÇͨ¹ý·ÖÎö `@EnableTransactionManagement` ×¢½â£¬·¢ÏÖ¸Ã×¢½â»áÏò spring ÈÝÆ÷ÖÐ×¢²á `InfrastructureAdvisorAutoProxyCreator`£¬Õâ¸öÀàÊÇ `AbstractAdvisorAutoProxyCreator` µÄ×ÓÀ࣬ÓÃÀ´Éú³É´úÀí¶ÔÏóµÄ£¬±¾½Ú½«»ùÓÚ `InfrastructureAdvisorAutoProxyCreator` À´·ÖÎö¶ÔÏóµÄ´´½¨¹ý³Ì¡£
+
+> ¹ØÓÚ `AbstractAdvisorAutoProxyCreator` µÄ·ÖÎöÒÔ¼°´úÀí¶ÔÏóµÄÉú³É£¬ÔÚ [spring aop Ö® AnnotationAwareAspectJAutoProxyCreator ·ÖÎö£¨ÉÏ£©](https://my.oschina.net/funcy/blog/4678817) Óë [spring aop Ö® AnnotationAwareAspectJAutoProxyCreator ·ÖÎö£¨Ï£©](https://my.oschina.net/funcy/blog/4687961)ÒѾ×÷ÁËÏêϸ·ÖÎö£¬ÕâÀïÎÒÃÇÖ÷Òª·ÖÎöÓë aop ÓвîÒìµÄµØ·½£¬ÐèÒªÏêϸÁ˽â spring aop ´úÀí¶ÔÏóÈçºÎ²úÉúµÄС»ï°é£¬¿ÉÒÔÔĶÁÉÏÊöÁ½ÆªÎÄÕ¡£
+
+ÎÒÃÇÒÀ¾ÉÊǽøÈë `AbstractAutoProxyCreator#postProcessBeforeInitialization`£º
+
+```
+public Object postProcessBeforeInstantiation(Class> beanClass, String beanName) {
+ ...
+ if (...) {
+ //1\. shouldSkip:
+ // - AspectJAwareAdvisorAutoProxyCreator µÄ shouldSkip ·½·¨»á´¦Àí @Aspect ×¢½âµÄÀ࣬
+ // ½«ÆäÖеÄ@Before/@After/@AroundµÈ×¢½â°üװΪAdvisor£¬ÔÙµ÷Óø¸Àà(Ò²¾ÍÊÇ
+ // AbstractAutoProxyCreator)µÄshouldSkip·½·¨
+ // - InfrastructureAdvisorAutoProxyCreatorÖ±½ÓÖ´ÐÐAbstractAutoProxyCreatorµÄshouldSkip·½·¨
+ if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
+ this.advisedBeans.put(cacheKey, Boolean.FALSE);
+ return null;
+ }
+ }
+ if(...) {
+ ...
+
+ // 2\. getAdvicesAndAdvisorsForBean£º»ñÈ¡ÊÊÓÃÓÃÓÚµ±Ç°¶ÔÏóµÄadvisor
+ Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(
+ beanClass, beanName, targetSource);
+ Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
+ ...
+ return proxy;
+ }
+ return null;
+}
+
+```
+
+Õâ¸ö·½·¨ÓÐÁ½´¦²»Í¬µã£¬´úÂëÖÐÒѾעÃ÷ÁËÆäÖеIJîÒ죬¹ØÓÚ `shouldSkip`£¬Ã»É¶ºÃ˵µÄ£¬ÎÒÃÇÖØµãÕ¹¿ª `getAdvicesAndAdvisorsForBean(...)` ·½·¨¡£
+
+#### 1.1 `BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans`
+
+һ·¸ú½ø `getAdvicesAndAdvisorsForBean(...)` ·½·¨£¬ÆäÖеIJÙ×÷Óë `AspectJAwareAdvisorAutoProxyCreator` µÄ²Ù×÷²¢²»Ì«´óÇø±ð£¬²»¹ýÓиö·½·¨¸öÈËÈÏΪÐèҪǿµ÷Ï£¬·½·¨ÈçÏ£º
+
+> BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans
+
+```
+public List findAdvisorBeans() {
+ String[] advisorNames = this.cachedAdvisorBeanNames;
+ if (advisorNames == null) {
+ // ²éÕÒµ±Ç°beanFactoryÖÐËùÓÐ Advisor µÄ bean class
+ // Advisor¿ÉÒÔÊÇÓû§ÊµÏÖAdvisorÏà¹Ø½Ó¿Ú£¬Ò²¿ÉÒÔÊÇxmlÖ¸¶¨µÄ
+ advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
+ this.beanFactory, Advisor.class, true, false);
+ this.cachedAdvisorBeanNames = advisorNames;
+ }
+ ...
+ List advisors = new ArrayList<>();
+ for (String name : advisorNames) {
+ ...
+ // ¸ù¾ÝadvisorµÄbean name£¬´ÓspringÈÝÆ÷ÖлñÈ¡ bean
+ advisors.add(this.beanFactory.getBean(name, Advisor.class));
+ ...
+ }
+ ...
+ return advisors;
+}
+
+```
+
+Õâ¸ö·½·¨Ö÷ÒªµÄ×÷ÓÃÊÇ»ñÈ¡ spring ÈÝÆ÷ÖеÄËùÓÐ `advisor`£¬ÆäʵÔÚ `AnnotationAwareAspectJAutoProxyCreator` ÖÐÒ²ÊÇÕâô»ñÈ¡µÄ£¬Ö»²»¹ýÔÚ»ñȡǰ£¬`AnnotationAwareAspectJAutoProxyCreator` »áÔÚ `shouldSkip(...)` ·½·¨ÖÐ°Ñ `@Aspect` ÀàÖаüº¬ `@Befor/@After/@Around` µÈ×¢½âµÄ·½·¨°ü×°³É¶ÔÓ¦µÄ `Advisor`£¬¶ø `InfrastructureAdvisorAutoProxyCreator` Ôò²»»á£¬±¾½ÚÒ»¿ªÊ¼Ò²Ìáµ½¹ýÁË¡£
+
+ÔÚ [spring ÊÂÎñÖ®ÈÏʶÊÂÎñ×é¼þ](https://my.oschina.net/funcy/blog/4773454)Ò»ÎÄÖУ¬·ÖÎö `@EnableTransactionManagement` ×¢½â¹¦ÄÜʱ£¬ÎÒÃÇ·ÖÎöµ½¸Ã×¢½â»áͨ¹ý `@Bean` ×¢½âÏò spring ÖÐÒýÈë `BeanFactoryTransactionAttributeSourceAdvisor`£¬Õâ¸ö bean ¾Í»áÔÚ `BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans` ±»»ñÈ¡µ½¡£
+
+#### 1.2 `AopUtils#canApply(...)`
+
+¸ú×Å·½·¨Ò»Â·ÍùÏÂ×ߣ¬½ÓמÍÀ´µ½ÁËÅÐ¶Ï `advisor` ÄÜ·ñÊÊÓÃÓÚÄ¿±ê `class` µÄµØ·½ÁË£º
+
+```
+/**
+ * ÅжÏadvisorÄÜ·ñÊÊÓÃÓÚÄ¿±êclass
+ */
+public static boolean canApply(Advisor advisor, Class> targetClass, boolean hasIntroductions) {
+ ...
+ // ÅжÏÊÇ·ñΪ PointcutAdvisor£¬´¦ÀíÊÂÎñµÄadvisorΪBeanFactoryTransactionAttributeSourceAdvisor£¬
+ // ËüʵÏÖÁËPointcutAdvisor£¬Òò´ËÏÂÃæµÄ´úÂë»áÖ´ÐÐ
+ else if (advisor instanceof PointcutAdvisor) {
+ PointcutAdvisor pca = (PointcutAdvisor) advisor;
+ //ʹÓà PointcutAdvisor ¼ÌÐøÅжÏ
+ return canApply(pca.getPointcut(), targetClass, hasIntroductions);
+ }
+ ...
+}
+
+/**
+ * ÅжÏadvisorÄÜ·ñÊÊÓÃÓÚÄ¿±êclass
+ */
+public static boolean canApply(Pointcut pc, Class> targetClass, boolean hasIntroductions) {
+ Assert.notNull(pc, "Pointcut must not be null");
+ //1\. ÇеãÉÏÊÇ·ñ´æÔÚÅųýÀàµÄÅäÖÃ
+ if (!pc.getClassFilter().matches(targetClass)) {
+ return false;
+ }
+ // »ñÈ¡·½·¨Æ¥Åä¶ÔÏó£¬MethodMatcher.TRUE ΪĬÈ쵀 MethodMatcher ¶ÔÏó
+ MethodMatcher methodMatcher = pc.getMethodMatcher();
+ if (methodMatcher == MethodMatcher.TRUE) {
+ return true;
+ }
+ ...
+ // classes°üº¬targetClass¡¢³ýObjectµÄËùÓи¸Àà¡¢ËùÓнӿÚ
+ Set> classes = new LinkedHashSet<>();
+ // Ê¡ÂÔ»ñÈ¡targetClassµÄ¸¸ÀಽÖè
+ ...
+ for (Class> clazz : classes) {
+ // »ñÈ¡ clazz ¶¨ÒåµÄ·½·¨£¬°üÀ¨µ±Ç°ÀàµÄ·½·¨¡¢³ýObjectÍâµÄËùÓи¸Àà·½·¨¡¢½Ó¿ÚµÄĬÈÏ·½·¨
+ Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
+ for (Method method : methods) {
+ // 2\. Æ¥ÅäµÄ¹Ø¼üÔÚÕâÀï
+ if (introductionAwareMethodMatcher != null ?
+ introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
+ methodMatcher.matches(method, targetClass)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+```
+
+ÕâÒ»¿éµÄ´úÂëÓë `AnnotationAwareAspectJAutoProxyCreator` һģһÑù£¬ËûÃǶ¼Êǵ÷ÓÃͬÑùµÄ·½·¨À´Åжϣ¬µ«ÓÉÓÚ´«ÈëµÄµÄ `advisor` ²»Í¬£¬×îÖÕµ÷Óõ½µÄ¾ßÌåµÄÆ¥Å乿ÔòÒ²²»Ïàͬ¡£
+
+´Ó´úÂëµÄ·ÖÎöÀ´¿´£¬Æ¥ÅäµÄÂß¼¶¼ÔÚ `Pointcut` ÖУ¬¶ø `Pointcut` ÓÖÀ´×ÔÓÚ `Advisor`£¬¿É¼û `Advisor` Ê®·Ö¹Ø¼ü¡£´¦ÀíÊÂÎñµÄ `Advisor` Ϊ `BeanFactoryTransactionAttributeSourceAdvisor`£¬½ÓÏÂÀ´ÎÒÃǾÍÀ´·ÖÎöÕâ¸öÀà¡£
+
+#### 1.3 `BeanFactoryTransactionAttributeSourceAdvisor` Æ¥Å乿Ôò·ÖÎö
+
+´ÓÉÏһС ½ÚµÄ·ÖÎöÖУ¬ÎÒÃÇÖªµÀÅÐ¶Ï `targetClass` ÄÜ·ñÓ¦Óõ±Ç° `advisor` µÄ¹æÔòÀ´Ô´ÓÚ `advisor` µÄ `pointcut`£¬`pointcut` ÓÐÁ½¸öµØ·½°üº¬ÁËÅжϹæÔò£º
+
+* Æ¥ÅäÀࣺ`pc.getClassFilter().matches(targetClass)`
+* Æ¥Åä·½·¨£º`pc.getMethodMatcher().matches(method, targetClass)`
+
+ÕâһС ½ÚÎÒÃÇ´Ó `BeanFactoryTransactionAttributeSourceAdvisor` ÈëÊÖ£¬Ò»²½²½·ÖÎöÆ¥Å乿Ôò¡£
+
+```
+public class BeanFactoryTransactionAttributeSourceAdvisor
+ extends AbstractBeanFactoryPointcutAdvisor {
+
+ @Nullable
+ private TransactionAttributeSource transactionAttributeSource;
+
+ /**
+ * Õâ¸ö¾ÍÊÇ pointcut
+ */
+ private final TransactionAttributeSourcePointcut pointcut =
+ new TransactionAttributeSourcePointcut() {
+ @Override
+ @Nullable
+ protected TransactionAttributeSource getTransactionAttributeSource() {
+ return transactionAttributeSource;
+ }
+ };
+
+ /**
+ * ÉèÖÃ transactionAttributeSource
+ */
+ public void setTransactionAttributeSource(TransactionAttributeSource
+ transactionAttributeSource) {
+ this.transactionAttributeSource = transactionAttributeSource;
+ }
+
+ /**
+ * ÉèÖÃ ClassFilter
+ */
+ public void setClassFilter(ClassFilter classFilter) {
+ this.pointcut.setClassFilter(classFilter);
+ }
+
+ /**
+ * »ñÈ¡ pointcut
+ */
+ @Override
+ public Pointcut getPointcut() {
+ return this.pointcut;
+ }
+}
+
+```
+
+ÉÏÃæµÄ´úÂë¹Ø¼ü²¿·ÖÒѾעÊÍÁË£¬ÕâÀïÀ´×ܽáÏ£º`BeanFactoryTransactionAttributeSourceAdvisor#getPointcut` µÃµ½µÄ `pointcut` Ϊ `TransactionAttributeSourcePointcut`£¬¾ÍÊÇÔÚ `private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {...}` Öд´½¨µÄ¡£
+
+`BeanFactoryTransactionAttributeSourceAdvisor` µÄ `transactionAttributeSource` ÊÇÊ²Ã´ÄØ£¿»ØÒäÏ `ProxyTransactionManagementConfiguration` Öд´½¨ `transactionAdvisor` µÄ´úÂ룺
+
+```
+public class ProxyTransactionManagementConfiguration
+ extends AbstractTransactionManagementConfiguration {
+
+ // Ê¡ÂÔÆäËû
+ ...
+
+ /**
+ * ¶ÁÈ¡SpringµÄ @Transactional ×¢½â£¬²¢½«ÏàÓ¦µÄÊÂÎñÊôÐÔ¹«¿ª¸øSpringµÄÊÂÎñ»ù´¡½á¹¹
+ */
+ @Bean
+ @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+ public TransactionAttributeSource transactionAttributeSource() {
+ return new AnnotationTransactionAttributeSource();
+ }
+
+ /**
+ * ÊÂÎñÔöÇ¿Æ÷.
+ * transactionAttributeSource£ºtransactionAttributeSource() ·µ»ØµÄ¶ÔÏó
+ */
+ @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
+ @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
+ public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
+ TransactionAttributeSource transactionAttributeSource,
+ TransactionInterceptor transactionInterceptor) {
+ BeanFactoryTransactionAttributeSourceAdvisor advisor =
+ new BeanFactoryTransactionAttributeSourceAdvisor();
+ // ÉèÖÃÊÂÎñÊôÐÔÀ࣬ÓÃÀ´±£´æ @Transactional µÄÊôÐÔ
+ advisor.setTransactionAttributeSource(transactionAttributeSource);
+ ...
+ return advisor;
+ }
+
+}
+
+```
+
+ÓÉ´Ë¿ÉÖª£¬`BeanFactoryTransactionAttributeSourceAdvisor` µÄ `transactionAttributeSource` ÊôÐÔΪ `AnnotationTransactionAttributeSource`.
+
+ÎÒÃÇÔٻص½ `BeanFactoryTransactionAttributeSourceAdvisor`£¬´ÓÉÏÃæµÄ·ÖÎö¿ÉÖª£¬`getPointcut()` µÃµ½µÄÊÇ `TransactionAttributeSourcePointcut` ¶ÔÏó£¬È»ºó½øÈëÕâ¸öÀࣺ
+
+```
+abstract class TransactionAttributeSourcePointcut
+ extends StaticMethodMatcherPointcut implements Serializable {
+
+ protected TransactionAttributeSourcePointcut() {
+ // ÔÚ¹¹Ôì·½·¨ÖÐÉèÖÃ ClassFilter
+ setClassFilter(new TransactionAttributeSourceClassFilter());
+ }
+
+ /**
+ * pointcut µÄ matches ·½·¨
+ */
+ @Override
+ public boolean matches(Method method, Class> targetClass) {
+ // µÃµ½µÄ½á¹ûΪAnnotationTransactionAttributeSource
+ TransactionAttributeSource tas = getTransactionAttributeSource();
+ return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
+ }
+
+ /**
+ * ÔÚ BeanFactoryTransactionAttributeSourceAdvisor ÖÐÒÑÖ¸¶¨
+ */
+ @Nullable
+ protected abstract TransactionAttributeSource getTransactionAttributeSource();
+
+ /**
+ * ÄÚ²¿À࣬ʵÏÖÁË ClassFilter
+ */
+ private class TransactionAttributeSourceClassFilter implements ClassFilter {
+
+ /**
+ * ClassFilter µÄ matches
+ */
+ @Override
+ public boolean matches(Class> clazz) {
+ // ÊÇ·ñΪTransactionalProxy¡¢PlatformTransactionManager¡¢PersistenceExceptionTranslatorµÄʵÏÖÀà
+ if (TransactionalProxy.class.isAssignableFrom(clazz) ||
+ PlatformTransactionManager.class.isAssignableFrom(clazz) ||
+ PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
+ return false;
+ }
+ //ÅÐ¶Ï TransactionAttributeSource »ñÈ¡ÊÂÎñÊôÐÔÊÇ·ñΪ¿Õ
+ // µÃµ½µÄ½á¹ûΪAnnotationTransactionAttributeSource
+ TransactionAttributeSource tas = getTransactionAttributeSource();
+ return (tas == null || tas.isCandidateClass(clazz));
+ }
+ }
+
+}
+
+```
+
+´ÓÉÏÃæµÄ·½·¨£¬ÎÒÃǵõ½ÁËÒ»¸öÖØÒªµÄ¹æÔò£º
+
+* Æ¥ÅäÀࣺ`pc.getClassFilter().matches(targetClass)`£¬`ClassFilter` Ϊ `TransactionAttributeSourceClassFilter`
+
+Æ¥ÅäÀàµÄ¹æÔòÊÇÕÒµ½ÁË£¬ÄÇÆ¥Åä·½·¨µÄ¹æÔòÄØ£¿ÎÒÃǽøÈë `TransactionAttributeSourcePointcut#getMethodMatcher()` ·½·¨£¬½øÈëµÄÊÇ `StaticMethodMatcherPointcut`£º
+
+```
+public abstract class StaticMethodMatcherPointcut
+ extends StaticMethodMatcher implements Pointcut {
+ // Ê¡ÂÔÁËһЩ´úÂë
+ ...
+
+ @Override
+ public final MethodMatcher getMethodMatcher() {
+ return this;
+ }
+}
+
+```
+
+·µ»ØµÄ¾¹È»ÊÇ `this`£¡ÕâÊǸöɶ£¿²»Òª»Å£¬ÔÙϸ¿´ `TransactionAttributeSourcePointcut`£¬·¢ÏÖËü¼Ì³ÐÁË `StaticMethodMatcherPointcut`£º
+
+```
+abstract class TransactionAttributeSourcePointcut
+ extends StaticMethodMatcherPointcut implements Serializable {
+ // Ê¡ÂÔÁËһЩ´úÂë
+ ...
+}
+
+```
+
+ËùÒÔ£¬`pc.getMethodMatcher()` µÃµ½µÄ¾ÍÊÇ `TransactionAttributeSourcePointcut`£¬Æä `mathes(...)` ·½·¨¾ÍÊÇ `TransactionAttributeSourcePointcut#matches`.
+
+ÔÚ±¾Ð¡½ÚµÄ×îºó£¬ÎÒÃÇÀ´×ܽáÏ·ÖÎöµÄ½á¹û£º
+
+* Æ¥ÅäÀࣺ`pc.getClassFilter().matches(targetClass)`£¬`ClassFilter` Ϊ `TransactionAttributeSourceClassFilter`£»
+* Æ¥Åä·½·¨£º`pc.getMethodMatcher().matches(method, targetClass)`£¬`methodMatcher` Ϊ `TransactionAttributeSourcePointcut`£»
+* ÔÚÉÏÃæÁ½¸ö¹æÔòÖУ¬¶¼»áµ÷Óà `TransactionAttributeSourcePointcut#getTransactionAttributeSource`£¬Õâ¸ö·½·¨·µ»ØµÄ½á¹ûΪ `AnnotationTransactionAttributeSource`.
+
+#### 1.4 Æ¥ÅäÁ÷³Ì
+
+ÔÚ 1.2 ²¿·Ö£¬ÎÒÃÇÖªµÀ£¬µ±Ç° `advisor` ÄÜ·ñÓ¦ÓÃÓÚÄ¿±ê class£¬ÐèҪͬʱÂú×ãÁ½¸öÆ¥Å乿Ôò£º
+
+* Æ¥ÅäÀࣺ`pc.getClassFilter().matches(targetClass)`£¬`ClassFilter` Ϊ `TransactionAttributeSourceClassFilter`£»
+* Æ¥Åä·½·¨£º`pc.getMethodMatcher().matches(method, targetClass)`£¬`methodMatcher` Ϊ `TransactionAttributeSourcePointcut`£»
+
+ÎÒÃÇÀ´¿´ÏÂÕâÁ½¸ö·½·¨£º
+
+
+
+* `TransactionAttributeSourceClassFilter#matches`£ºÏÈÅжϵ±Ç°ÀàÊÇ·ñΪÊÇ·ñΪ `TransactionalProxy`¡¢`PlatformTransactionManager`¡¢`PersistenceExceptionTranslator` »òÆäʵÏÖÀ࣬Ȼºóµ÷Óà `AnnotationTransactionAttributeSource#isCandidateClass` ¼ÌÐøÅжϣ»
+* `TransactionAttributeSourcePointcut#matches`£ºµ÷Óà `AnnotationTransactionAttributeSource#getTransactionAttribute`£¨ÓÉÓڼ̳йØÏµ£¬Êµ¼Êµ÷ÓõÄÊÇ `AbstractFallbackTransactionAttributeSource#getTransactionAttribute`£©Åжϡ£
+
+½ÓÏÂÀ´ÎÒÃǾÍÀ´·ÖÎöϾßÌ寥ÅäÁ÷³Ì¡£
+
+##### `AnnotationTransactionAttributeSource#isCandidateClass`
+
+ÈÃÎÒÃÇÖ±±¼Ö÷Ì⣬½øÈë `isCandidateClass` ·½·¨£º
+
+> AnnotationTransactionAttributeSource#isCandidateClass
+
+```
+@Override
+public boolean isCandidateClass(Class> targetClass) {
+ // ÕÒµ½ËùÓеÄannotationParsers£¬Ñ»·Æ¥Åä
+ for (TransactionAnnotationParser parser : this.annotationParsers) {
+ if (parser.isCandidateClass(targetClass)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬ÕâÊÇÔÚÑ»·Àïµ÷Óà `TransactionAnnotationParser` µÄ `isCandidateClass` ·½·¨¡£`this.annotationParsers` ÊÇɶĨ£¿Í¨¹ýµ÷ÊÔ£¬ÄÚÈÝÈçÏ£º
+
+
+
+`this.annotationParsers` ÖÐÖ»ÓÐ `SpringTransactionAnnotationParser`£¬ÎÒÃǽøÈëÆä `isCandidateClass` ·½·¨£º
+
+```
+public class SpringTransactionAnnotationParser
+ implements TransactionAnnotationParser, Serializable {
+
+ /**
+ * ÅжÏÀàÉÏÊÇ·ñÓÐ @Transactional ×¢½â
+ */
+ @Override
+ public boolean isCandidateClass(Class> targetClass) {
+ return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
+ }
+}
+
+```
+
+Õâ¸ö·½·¨×îÖÕµ÷ÓõÄÊÇ `AnnotationUtils.isCandidateClass`£¬ÓÃÀ´ÅжÏÖ¸¶¨µÄÀàÉÏÊÇ·ñÓÐ `@Transactional` ×¢½â¡£
+
+µ½ÕâÀÎÒÃǾÍÃ÷°×ÁË£¬`TransactionAttributeSourceClassFilter#matches` ÏÈÅųýһЩÀà (`TransactionalProxy`/`PlatformTransactionManager`/`PersistenceExceptionTranslator` ¼°Æä×ÓÀà) ºó£¬×îÖÕ»áÆ¥Åä´øÓÐ `@Transactional` ×¢½âµÄÀà¡£
+
+##### `AnnotationTransactionAttributeSource#getTransactionAttribute`
+
+ÉÏÃæµÄ·½·¨Æ¥Åä³É¹¦ºó£¬²¢²»Äܱíʾ³É¹¦Æ¥Å䣬»¹µÃÆ¥Åä `TransactionAttributeSourcePointcut#matches`£¬Á½ÕßͬʱÂú×ã²Å»áÆ¥Åä³É¹¦¡£`TransactionAttributeSourcePointcut#matches` µ÷Óà `AnnotationTransactionAttributeSource#getTransactionAttribute` Íê³ÉÆ¥ÅäµÄ£¬ÎÒÃǸú½øÈ¥£º
+
+```
+public abstract class AbstractFallbackTransactionAttributeSource
+ implements TransactionAttributeSource {
+
+ /**
+ * »ñÈ¡ @Transactional ×¢½âµÄÊôÐÔ
+ */
+ public TransactionAttribute getTransactionAttribute(Method method,
+ @Nullable Class> targetClass) {
+ if (method.getDeclaringClass() == Object.class) {
+ return null;
+ }
+
+ // Ê¡ÂÔ´Ó»º´æÖлñÈ¡
+ ...
+ else {
+ // »ñÈ¡ Transaction ÊôÐÔ£¬¼´ @Transactional ×¢½âµÄÊôÐÔ
+ TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
+ // Ê¡ÂÔ·ÅÈ뻺´æ²Ù×÷
+ ...
+ return txAttr;
+ }
+ }
+}
+
+```
+
+`AnnotationTransactionAttributeSource` µÄ `getTransactionAttribute` ÊǼ̳Ð×Ô `AbstractFallbackTransactionAttributeSource` µÄ£¬Òò´ËÎÒÃǽøÈëµÄ·½·¨ÊÇ `AbstractFallbackTransactionAttributeSource#getTransactionAttribute`£¬Õâ¸ö·½·¨ÓÃÀ´»ñÈ¡·½·¨É쵀 `@Transactional` ×¢½âµÄÊôÐÔ£¬ÎÒÃǸú½ø `computeTransactionAttribute(...)`£º
+
+> AbstractFallbackTransactionAttributeSource
+
+```
+protected TransactionAttribute computeTransactionAttribute(Method method,
+ @Nullable Class> targetClass) {
+ // ĬÈϱØÐëÒª public ·½·¨²ÅÖ§³ÖÊÂÎñ
+ if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
+ return null;
+ }
+ // 1\. »ñȡȷÇеķ½·¨£¬ÀýÈç´«ÈëµÄclassÊÇIFoo£¬Êµ¼ÊµÄµÄclassÊÇDefaultFoo£¬
+ // ÄÇôӦ¸Ã½« IFoo#method ת»»Îª DefaultFoo#method
+ Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
+ // 2\. ´Ó·½·¨ÉÏ»ñÈ¡ @Transactional µÄÊôÐÔ
+ TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
+ if (txAttr != null) {
+ return txAttr;
+ }
+ // 3\. ´ÓÀàÉÏ»ñÈ¡ @Transaction µÄÊôÐÔ
+ txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
+ if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
+ return txAttr;
+ }
+ if (specificMethod != method) {
+ // 4\. È·Çеķ½·¨ÉÏÕÒ²»µ½£¬¾ÍÕÒ´«ÈëµÄ·½·¨ÉϵÄ
+ txAttr = findTransactionAttribute(method);
+ if (txAttr != null) {
+ return txAttr;
+ }
+ // 5\. ÒÔÉ϶¼Ã»ÕÒµ½£¬¾ÍÕÒÈ·ÇеÄÀàÉϵÄ
+ txAttr = findTransactionAttribute(method.getDeclaringClass());
+ if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
+ return txAttr;
+ }
+ }
+ // 6\. ûÓлñÈ¡µ½£¬×îÖÕ·µ»Ønull
+ return null;
+}
+
+```
+
+´ÓÒÔÉÏ·½·¨µÄÁ÷³Ì£¬¿É×ܽá»ñÈ¡ `@Transactional` ÊôÐÔÁ÷³ÌÈçÏ£º
+
+1. ½«´«ÈëµÄ·½·¨×ª»»ÎªÈ·Çеķ½·¨£¬ÀýÈç´«ÈëµÄ `class` ÊÇ `IFoo`£¬Êµ¼ÊµÄµÄ `class` ÊÇ `DefaultFoo`£¬ÕâÀï¾Í»á½« `IFoo#method` ת»»Îª `DefaultFoo#method`
+2. ´ÓÈ·Çеķ½·¨ÉÏ»ñÈ¡ `@Transactional` µÄÊôÐÔ
+3. Èç¹ûûÓлñÈ¡µ½£¬¾Í´ÓÈ·ÇеĴÓÀàÉÏ»ñÈ¡ `@Transaction` µÄÊôÐÔ
+4. Èç¹ûûÓлñÈ¡µ½£¬¾Í´«ÈëµÄ·½·¨ÉÏ»ñÈ¡ `@Transaction` µÄÊôÐÔ
+5. Èç¹ûûÓлñÈ¡µ½£¬¾Í´«ÈëµÄÀàÉÏ»ñÈ¡ `@Transaction` µÄÊôÐÔ
+6. Èç¹ûÒÔÉ϶¼Ã»ÓлñÈ¡µ½£¬¾Í·µ»Ø `null`
+
+spring ÓÖÊÇÈçºÎ´Ó·½·¨»òÀàÉÏ»ñÈ¡ `@Transactional` µÄÊôÐÔÄØ£¿¼ÌÐø¿´ÏÂÈ¥£º
+
+> AnnotationTransactionAttributeSource
+
+```
+ // ´Ó·½·¨ÉÏ»ñÈ¡ @Transactional ÊôÐÔ
+ protected TransactionAttribute findTransactionAttribute(Method method) {
+ return determineTransactionAttribute(method);
+ }
+
+ // ´ÓÀàÉÏ»ñÈ¡ @Transactional ÊôÐÔ
+ protected TransactionAttribute findTransactionAttribute(Class> clazz) {
+ return determineTransactionAttribute(clazz);
+ }
+
+ // ×îÖÕµ÷Óõķ½·¨
+ protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
+ for (TransactionAnnotationParser parser : this.annotationParsers) {
+ // ½âÎö @Transactional ×¢½âµÄÊôÐÔ
+ TransactionAttribute attr = parser.parseTransactionAnnotation(element);
+ if (attr != null) {
+ return attr;
+ }
+ }
+ return null;
+ }
+
+```
+
+×îÖÕËûÃǶ¼Êǵ÷Óà `AnnotationTransactionAttributeSource#determineTransactionAttribute` À´»ñÈ¡µÄ£¬¶øÔÚ `AnnotationTransactionAttributeSource#determineTransactionAttribute` µ÷ÓÃÁË `TransactionAnnotationParser#parseTransactionAnnotation` ·½·¨¡£¶ÔÓÚ `this.annotationParsers` »¹ÑÛÊìÂð£¬ÔÚÇ°ÃæÒѾ·ÖÎö¹ýÁË£¬ÀïÃæÖ»ÓÐÒ»¸öÀࣺ`SpringTransactionAnnotationParser`£¬ÎÒÃǸú½øÈ¥£º
+
+> SpringTransactionAnnotationParser
+
+```
+ /**
+ * »ñÈ¡ Transactional ×¢½â£¬´æÔÚÔò¼ÌÐø½âÎö£¬²»´æÔÚÔò·µ»Ø null
+ */
+ public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
+ // »ñÈ¡ Transactional ×¢½â£¬´æÔÚÔò¼ÌÐø½âÎö£¬²»´æÔÚÔò·µ»Ø null
+ AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
+ element, Transactional.class, false, false);
+ if (attributes != null) {
+ return parseTransactionAnnotation(attributes);
+ }
+ else {
+ return null;
+ }
+ }
+
+ /**
+ * ½âÎö Transactional ×¢½âµÄ¾ßÌå²Ù×÷
+ */
+ protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
+ RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
+ // ÊÂÎñµÄ´«²¥·½Ê½
+ Propagation propagation = attributes.getEnum("propagation");
+ rbta.setPropagationBehavior(propagation.value());
+ // ÊÂÎñµÄ¸ôÀë¼¶±ð
+ Isolation isolation = attributes.getEnum("isolation");
+ rbta.setIsolationLevel(isolation.value());
+ // ÊÂÎñµÄ³¬Ê±Ê±¼ä
+ rbta.setTimeout(attributes.getNumber("timeout").intValue());
+ // ÊÇ·ñΪֻ¶Á
+ rbta.setReadOnly(attributes.getBoolean("readOnly"));
+ rbta.setQualifier(attributes.getString("value"));
+ // ´¦Àí»Ø¹öÒì³£
+ List rollbackRules = new ArrayList<>();
+ for (Class> rbRule : attributes.getClassArray("rollbackFor")) {
+ rollbackRules.add(new RollbackRuleAttribute(rbRule));
+ }
+ for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
+ rollbackRules.add(new RollbackRuleAttribute(rbRule));
+ }
+ // ´¦Àí²»»Ø¹öÒì³£
+ for (Class> rbRule : attributes.getClassArray("noRollbackFor")) {
+ rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
+ }
+ for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
+ rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
+ }
+ rbta.setRollbackRules(rollbackRules);
+
+ return rbta;
+ }
+
+```
+
+¿ÉÒÔ¿´µ½£¬`Transactional` ×¢½âµÄ¸÷ÊôÐÔ½âÎö³ÉÁË `RuleBasedTransactionAttribute`.
+
+ÖÁ´Ë£¬ÎÒÃǾÍÃ÷°×ÁË£¬`TransactionAttributeSourcePointcut#matches` ¾ÍÊÇÓÃÀ´ÅжÏÀà»ò·½·¨ÉÏÓÐûÓÐ `Transactional` ×¢½â¡£
+
+#### 1.5 ´úÀí¶ÔÏóµÄ´´½¨
+
+´úÀí¶ÔÏóµÄ´´½¨ÔÚ `AbstractAutoProxyCreator#postProcessAfterInitialization` ·½·¨ÖÐÍê³ÉµÄ£¬Õâ¸öÁ÷³Ìͬ aop Á÷³ÌÕæµÄÊÇһģһÑù£¬ÕâÀï¾Í²»ÔÙ·ÖÎöÁË£¬ÏëÁ˽âµÄС»ï°é¿É²é¿´ [spring aop Ö® AnnotationAwareAspectJAutoProxyCreator ·ÖÎö£¨Ï£©](https://my.oschina.net/funcy/blog/4687961)¡£
+
+### 2\. ·½·¨µÄÖ´ÐÐ
+
+·½·¨µÄÖ´Ðз½Ã棬ÊÂÎñÓë aop µÄÖ´ÐÐÁ÷³Ì²¢ÎÞÇø±ð£¬Ò»ÑùÊÇͨ¹ý `Advisor` ÕÒµ½¶ÔÓ¦µÄ `Advice`£¬ÔÙͨ¹ý `Advice` ÕÒµ½¶ÔÓ¦µÄ `methodInterceptor`£¬×îÖÕÖ´ÐеÄÊÇ `MethodInterceptor#invoke` ·½·¨£¬ÔÚÊÂÎñÕâÀï `MethodInterceptor` Ϊ `TransactionInterceptor`£¬Õâ¸öÀàÊÇÔÚ `ProxyTransactionManagementConfiguration` ÖÐͨ¹ý `@Bean` ×¢½âÒýÈëµÄ¡£
+
+¹ØÓÚ aop µÄÁ÷³Ì£¬ÎÒÃDz¢²»´òËã·ÖÎö£¬Ïà¹Ø·ÖÎöÔÚ [spring aop Ö® jdk ¶¯Ì¬´úÀí](https://my.oschina.net/funcy/blog/4696654) Óë[ spring aop Ö® cglib ´úÀí](https://my.oschina.net/funcy/blog/4696655) ÒÑÓÐÏêϸ·ÖÎö£¬¸ÐÐËȤµÄС»ï°é¿É×ÔÐвéÔÄ£¬ÕâÀïÎÒÃÇÖ±½ÓÀ´¿´ `TransactionInterceptor#invoke` µÄÖ´ÐÐÁ÷³Ì¡£
+
+ÊÂÎñµÄ´¦ÀíµÄÁ÷³ÌÔÚ `TransactionInterceptor#invoke` ·½·¨ÖУº
+
+> TransactionInterceptor#invoke
+
+```
+public Object invoke(MethodInvocation invocation) throws Throwable {
+ Class> targetClass = (invocation.getThis() != null
+ ? AopUtils.getTargetClass(invocation.getThis()) : null);
+ // ¼ÌÐøÍùÏ¿´
+ return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
+}
+
+```
+
+ÕæÕýµÄ´¦ÀíÂß¼ÔÚ `TransactionAspectSupport#invokeWithinTransaction` ·½·¨ÖУº
+
+> TransactionAspectSupport#invokeWithinTransaction
+
+```
+protected Object invokeWithinTransaction(Method method, @Nullable Class> targetClass,
+ final InvocationCallback invocation) throws Throwable {
+ TransactionAttributeSource tas = getTransactionAttributeSource();
+ // »ñÈ¡@TransactionalµÄÊôÐÔÅäÖÃ
+ final TransactionAttribute txAttr = (tas != null
+ ? tas.getTransactionAttribute(method, targetClass) : null);
+ // »ñÈ¡ÊÂÎñ¹ÜÀíÆ÷£¨IOCÈÝÆ÷ÖлñÈ¡£©
+ final TransactionManager tm = determineTransactionManager(txAttr);
+
+ // Ê¡ÂÔ ReactiveTransactionManager µÄ´¦Àí
+ ...
+
+ PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
+ // »ñÈ¡·½·¨µÄÈ«ÏÞ¶¨Ãû£¬¸ñʽΪ£º"°üÃû.ÀàÐÍ.·½·¨Ãû"
+ final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
+
+ // ÊÂÎñµÄ´¦ÀíÂß¼£¬ÕâÒ²ÊÇÎÒÃǽÓÏÂÀ´Ö÷Òª·ÖÎöµÄµØ·½
+ if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
+ // 1\. ¿ªÆôÊÂÎñ
+ TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
+ Object retVal;
+ try {
+ // 2\. Ö´ÐоßÌåµÄÒµÎñ
+ retVal = invocation.proceedWithInvocation();
+ }
+ catch (Throwable ex) {
+ // 3\. Òì³£»Ø¹ö
+ completeTransactionAfterThrowing(txInfo, ex);
+ throw ex;
+ }
+ finally {
+ // ÖØÖÃÊÂÎñÐÅÏ¢
+ cleanupTransactionInfo(txInfo);
+ }
+ if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
+ TransactionStatus status = txInfo.getTransactionStatus();
+ if (status != null && txAttr != null) {
+ retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
+ }
+ }
+ // 4\. Ìá½»ÊÂÎñ£¬´úÂëÖлáÅжÏÊÇ·ñÄÜÖ§³Ö
+ commitTransactionAfterReturning(txInfo);
+ return retVal;
+ }
+ else {
+ // Ê¡ÂÔÆäËû
+ ...
+ }
+}
+
+```
+
+ÒÔÉÏ·½·¨¾ÍÊÇÊÂÎñµÄÈ«²¿Á÷³ÌÁË£¬²½ÖèÈçÏ£º
+
+1. ¿ªÆôÊÂÎñ
+2. Ö´ÐÐÒµÎñ´úÂë
+3. Òì³£»Ø¹ö
+4. Ìá½»ÊÂÎñ
+
+¹ØÓÚÊÂÎñµÄ¾ßÌå·ÖÎö£¬ÎÒÃǽ«ÔÚÏÂһƪÎÄÕ·ÖÎö£¬±¾ÎÄÖ»ÐèÒª¶ÔÊÂÎñµÄ´¦ÀíÁ÷³ÌÓдóÖÂÁ˽⼴¿É¡£
+
+### 3\. ×ܽá
+
+±¾ÎÄÖ÷Òª·ÖÎöÁËÊÂÎñÖдúÀí¶ÔÏóµÄ´´½¨¼°Ö´ÐÐÁ÷³Ì£¬Êµ¼ÊÉÏÕâЩ²½Öèͬ aop »ù±¾Ò»Ö£¬±¾ÎÄ×ÅÖØ·ÖÎöÁËÓë aop ²»Í¬µÄ²¿·Ö£º
+
+* ÔÚ´úÀí¶ÔÏóµÄ´´½¨·½Ã棬·ÖÎöÁËÈçºÎÅжϵ±Ç°·½·¨ÄÜ·ñʹÓà `BeanFactoryTransactionAttributeSourceAdvisor`£¬Öصã·ÖÎöÁË `TransactionAttributeSourceClassFilter#matches` Óë `TransactionAttributeSourcePointcut#matches` ·½·¨£¬ÕâÊÇÅжϵĺËÐÄËùÔÚ£»
+
+* ÔÚ·½·¨µÄÖ´ÐÐÉϵ쬴ÖÂÔ·ÖÎöÁË `TransactionInterceptor#invoke` µÄÖ´ÐÐÁ÷³Ì£¬ÕâЩÊÂÎñµÄ¿ªÆô¡¢Ìá½»¡¢Òì³£»Ø¹öµÈÁ÷³Ì¸úÎÒÃÇÆ½³£Ê¹ÓõIJî±ð²»´ó£¬²»¹ýÀïÃæµÄ¾ßÌåϸ½ÚÎÒÃDz¢Ã»ÓзÖÎö¡£
+
+±¾ÎÄÖØµãÊÇ´úÀí¶ÔÏóµÄ´´½¨¼°Ö´ÐÐÁ÷³Ì£¬ÊÂÎñÖ´ÐеľßÌåϸ½ÚÎÒÃÇÏÂÆªÔÙ·ÖÎö¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4773457](https://my.oschina.net/funcy/blog/4773457) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\272\224\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 03.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\272\224\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 03.md"
new file mode 100644
index 0000000..8ac63de
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\344\272\224\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 03.md"
@@ -0,0 +1,500 @@
+±¾ÎÄÊÇ¡¶ÊÂÎñµÄ¸ôÀë¼¶±ðÓë´«²¥·½Ê½µÄ´¦Àí¡··ÖÎöµÄµÚ 3 ƪ£¬½ÓÉÏÎÄ£¬ÎÒÃǼÌÐø¡£
+
+ÉÏÎÄÖÐÎÒÃÇÌáµ½ÁËÊÂÎñµÄ¿ªÆô£¨`doBegin(...)`£©¡¢¹ÒÆð£¨`suspend(...)`£©Óë´´½¨±£´æµã£¨`createAndHoldSavepoint(...)`£©µÄ²Ù×÷£¬±¾ÎĽ«À´·ÖÎöÕâЩ²Ù×÷µÄʵÏÖ¡£
+
+### 1. `doBegin(...)`£ºÆô¶¯ÐµÄÊÂÎñ
+
+Æô¶¯ÐÂÊÂÎñµÄ·½·¨Îª `DataSourceTransactionManager#doBegin`£¬´úÂëÈçÏ£º
+
+```
+protected void doBegin(Object transaction, TransactionDefinition definition) {
+ DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
+ Connection con = null;
+
+ try {
+ // 1\. »ñÈ¡Êý¾Ý¿âÁ¬½Ó
+ if (!txObject.hasConnectionHolder() ||
+ txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
+ // getConnection(): »ñÈ¡Êý¾Ý¿âÁ¬½Ó£¬obtainDataSource()£º»ñÈ¡Êý¾ÝÔ´
+ Connection newCon = obtainDataSource().getConnection();
+ txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
+ }
+ // ÕâÀォ synchronizedWithTransaction ÉèÖÃΪtrue
+ txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
+ con = txObject.getConnectionHolder().getConnection();
+
+ // 2\. ÉèÖÃÊÂÎñµÄ¸ôÀë¼¶±ð
+
+ Integer previousIsolationLevel
+ = DataSourceUtils.prepareConnectionForTransaction(con, definition);
+ txObject.setPreviousIsolationLevel(previousIsolationLevel);
+ // ÉèÖÃÖ»¶ÁÊôÐÔ
+ txObject.setReadOnly(definition.isReadOnly());
+
+ // 3\. ¿ªÆôÊÂÎñ
+ if (con.getAutoCommit()) {
+ txObject.setMustRestoreAutoCommit(true);
+ // ¹Ø±ÕÊÂÎñµÄ×Ô¶¯Ìá½»£¬Ò²¾ÍÊÇ¿ªÆôÊÂÎñ
+ con.setAutoCommit(false);
+ }
+ // 4\. Èç¹ûÊÇÖ»¶ÁÊÂÎñ£¬ÔÚÕâÀïÉèÖÃ
+ prepareTransactionalConnection(con, definition);
+ // ÉèÖÃÊÂÎñµÄ¼¤»î±ê¼Ç
+ txObject.getConnectionHolder().setTransactionActive(true);
+ // 5\. ÉèÖÃÊÂÎñµÄ³¬Ê±Ê±¼ä
+ int timeout = determineTimeout(definition);
+ if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
+ txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
+ }
+
+ // 6\. °ó¶¨Êý¾ÝÔ´ÓëÁ¬½Óµ½µ±Ç°Ïß³Ì
+ if (txObject.isNewConnectionHolder()) {
+ TransactionSynchronizationManager.bindResource(
+ obtainDataSource(), txObject.getConnectionHolder());
+ }
+ }
+ } catch (Throwable ex) {
+ // ´¦ÀíÒì³£²Ù×÷£¬Èç¹ûÊÇÐÂÁ¬½ÓÔò¹Ø±Õ¸ÃÁ¬½Ó
+ if (txObject.isNewConnectionHolder()) {
+ DataSourceUtils.releaseConnection(con, obtainDataSource());
+ txObject.setConnectionHolder(null, false);
+ }
+ throw new CannotCreateTransactionException(...);
+ }
+}
+
+```
+
+ÒÔÉÏ´úÂ뻹ÊÇͦÇåÎúµÄ£¬×¢ÊÍÒ²ºÜÃ÷È·ÁË£¬ÕâÀï¶Ô¹Ø¼ü²½Öè×÷½øÒ»²½·ÖÎö¡£
+
+#### 1.1 »ñÈ¡Êý¾Ý¿âÁ¬½Ó
+
+Êý¾Ý¿âÁ¬½ÓµÄ»ñÈ¡»¹ÊǺܼòµ¥µÄ£¬´úÂëÈçÏ£º
+
+```
+Connection newCon = obtainDataSource().getConnection();
+
+```
+
+Æäʵ¾ÍÊǵ÷Óà `javax.sql.DataSource#getConnection()` ·½·¨¡£
+
+#### 1.2 ÉèÖÃÊÂÎñµÄ¸ôÀë¼¶±ð
+
+ÔÚ `@Transactional` ÖУ¬ÎÒÃÇ¿ÉÒÔʹÓà `isolation` Ö¸¶¨ÊÂÎñµÄ¸ôÀë¼¶±ð£º
+
+```
+public @interface Transactional {
+ /**
+ * Ö¸¶¨ÊÂÎñµÄ¸ôÀë¼¶±ð
+ */
+ Isolation isolation() default Isolation.DEFAULT;
+ ...
+}
+
+```
+
+Èç¹û²»Ö¸¶¨£¬¾ÍʹÓÃĬÈϵĸôÀë¼¶±ð£¬Ò²¾ÍÊÇʹÓÃÊý¾Ý¿âÅäÖõġ£
+
+spring ÉèÖÃÊÂÎñ¸ôÀë¼¶±ðµÄ·½·¨Îª `DataSourceUtils#prepareConnectionForTransaction`£¬´úÂëÈçÏ£º
+
+```
+public static Integer prepareConnectionForTransaction(Connection con,
+ @Nullable TransactionDefinition definition) throws SQLException {
+ Assert.notNull(con, "No Connection specified");
+ if (definition != null && definition.isReadOnly()) {
+ try {
+ // ÉèÖÃΪֻ¶Áģʽ
+ con.setReadOnly(true);
+ }
+ catch (SQLException | RuntimeException ex) {
+ ...
+ }
+ }
+
+ Integer previousIsolationLevel = null;
+ if (definition != null && definition.getIsolationLevel()
+ != TransactionDefinition.ISOLATION_DEFAULT) {
+ int currentIsolation = con.getTransactionIsolation();
+ if (currentIsolation != definition.getIsolationLevel()) {
+ // Äõ½Ö®Ç°µÄ¸ôÀë¼¶±ð£¬ÊÂÎñÍê³ÉÊ£¬ÐèÒªÖØÖÃΪÔÀ´µÄ¸ôÀë¼¶±ð
+ previousIsolationLevel = currentIsolation;
+ // ÔÚÕâÀïÉèÖÃÊý¾Ý¿âµÄ¸ôÀë¼¶±ð£¬µ÷ÓõÄÊÇ£º
+ // java.sql.Connection.setTransactionIsolation
+ con.setTransactionIsolation(definition.getIsolationLevel());
+ }
+ }
+ return previousIsolationLevel;
+}
+
+```
+
+Õâ ¸ö·½·¨´¦ÀíÁËÁ½¸öÉèÖãº
+
+1. ÉèÖÃΪֻ¶Áģʽ£ºµ÷ÓõÄÊÇ `java.sql.Connection#setReadOnly` ·½·¨
+2. ÉèÖøôÀë¼¶±ð£ºµ÷ÓõÄÊÇ `java.sql.Connection.setTransactionIsolation` ·½·¨
+
+¹ØÓÚÖ»¶Áģʽ£¬Ò²ÊÇ¿ÉÒÔÔÚ `@Transactional` ÖÐÉèÖõģº
+
+```
+public @interface Transactional {
+ /**
+ * ÉèÖÃÖ»¶ÁÊÂÎñ
+ */
+ boolean readOnly() default false;
+ ...
+}
+
+```
+
+#### 1.3 ¿ªÆôÊÂÎñ
+
+¼¤¶¯ÈËÐĵÄʱ¿ÌÖÕÓÚÀ´ÁË£¬Ç°ÃæÆÌµæÁËÄÇô¶à£¬¾ÍÊÇΪÁËÕâÒ»²½µÄ²Ù×÷£º¿ªÆôÊÂÎñ¡£¿ªÆôÊÂÎñµÄ´úÂëÈçÏ£º
+
+```
+if (con.getAutoCommit()) {
+ txObject.setMustRestoreAutoCommit(true);
+ // ¹Ø±ÕÊÂÎñµÄ×Ô¶¯Ìá½»£¬Ò²¾ÍÊÇ¿ªÆôÊÂÎñ
+ con.setAutoCommit(false);
+}
+
+```
+
+¾ßÌåÁ÷³ÌΪ£¬ÏÈÅжÏ×Ô¶¯Ìá½»ÊÇ·ñ¿ªÆô£¬Èç¹û¿ªÉèÖÃÁË£¬¾Í½«ÆäÉèÖÃΪ false£¬µ÷ÓõÄÒ²ÊÇ `java.sql` µÄ·½·¨£º
+
+* »ñÈ¡×Ô¶¯Ìύ״̬£º`java.sql.Connection#getAutoCommit`
+* ÉèÖÃ×Ô¶¯Ìύ״̬£º`java.sql.Connection#setAutoCommit`
+
+#### 1.4 Èç¹ûÊÇÖ»¶ÁÊÂÎñ£¬ÔÚÕâÀïÉèÖÃ
+
+ÔÚÇ°Ãæ·ÖÎö `1.2 ÉèÖÃÊÂÎñµÄ¸ôÀë¼¶±ð`ÖУ¬Í¨¹ýµ÷Óà `java.sql.Connection#setReadOnly` ½«Á¬½ÓÉèÖÃΪֻ¶ÁÁË£¬ÕâÀﻹ»áÔÙÒ»´ÎÉèÖ㬷½·¨Îª `DataSourceTransactionManager#prepareTransactionalConnection`£º
+
+```
+protected void prepareTransactionalConnection(Connection con, TransactionDefinition definition)
+ throws SQLException {
+ if (isEnforceReadOnly() && definition.isReadOnly()) {
+ try (Statement stmt = con.createStatement()) {
+ // ÉèÖÃÖ»¶ÁÀàÐÍÒªÔËÐÐsql
+ stmt.executeUpdate("SET TRANSACTION READ ONLY");
+ }
+ }
+}
+
+```
+
+ÕâÒ»´ÎÊÇͨ¹ýÖ´ÐÐ sql Óï¾ä `SET TRANSACTION READ ONLY` ½«ÊÂÎñÉèÖÃΪֻ¶Á¡£
+
+#### 1.5 ÉèÖÃÊÂÎñµÄ³¬Ê±Ê±¼ä
+
+ÔÚ `@Transactional` ×¢½âÖУ¬ÎÒÃÇ¿ÉÒÔʹÓà `timeout` À´Ö¸¶¨ÊÂÎñµÄ³¬Ê±Ê±¼ä£º
+
+```
+public @interface Transactional {
+ /**
+ * ÉèÖó¬Ê±Ê±¼ä
+ */
+ int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
+ ...
+}
+
+```
+
+ÕâÑùÉèÖõij¬Ê±Ê±¼ä»áÔÚÕâÀïÓõ½£¬ÎÒÃǽøÈë `ResourceHolderSupport#setTimeoutInSeconds`£º
+
+```
+public abstract class ResourceHolderSupport implements ResourceHolder {
+ /**
+ * ½ØÖ¹Ê±¼ä
+ */
+ private Date deadline;
+
+ /**
+ * ÉèÖÃʱ¼ä£¬µ¥Î»£ºÃë
+ */
+ public void setTimeoutInSeconds(int seconds) {
+ setTimeoutInMillis(seconds * 1000L);
+ }
+
+ /**
+ * ÉèÖÃʱ¼ä£¬µ¥Î»£ººÁÃë
+ * ×îºó»áת»¯Îª ½ØÖ¹Ê±¼ä
+ */
+ public void setTimeoutInMillis(long millis) {
+ this.deadline = new Date(System.currentTimeMillis() + millis);
+ }
+
+ /**
+ * »ñÈ¡½ØÖ¹Ê±¼ä
+ */
+ @Nullable
+ public Date getDeadline() {
+ return this.deadline;
+ }
+
+ /**
+ * »ñȡʣÓàʱ¼ä£¬µ¥Î»£ºÃë
+ */
+ public int getTimeToLiveInSeconds() {
+ double diff = ((double) getTimeToLiveInMillis()) / 1000;
+ int secs = (int) Math.ceil(diff);
+ checkTransactionTimeout(secs <= 0);
+ return secs;
+ }
+
+ /**
+ * »ñȡʣÓàʱ¼ä£¬µ¥Î»£ººÁÃë
+ */
+ public long getTimeToLiveInMillis() throws TransactionTimedOutException{
+ if (this.deadline == null) {
+ throw new IllegalStateException("No timeout specified for this resource holder");
+ }
+ long timeToLive = this.deadline.getTime() - System.currentTimeMillis();
+ checkTransactionTimeout(timeToLive <= 0);
+ return timeToLive;
+ }
+
+ ...
+}
+
+```
+
+ÔÚ `ResourceHolderSupport` ÖÐά»¤ÁËÒ»¸ö³ÉÔ±±äÁ¿ `deadline`£¨½ØÖ¹Ê±¼ä£©£¬´«ÈëµÄ³¬Ê±Ê±¼ä×îÖÕ¶¼»áת»¯Îª `deadline`¡£
+
+»ñȡʣÓàʱ¼äʱ£¬Ò²ÊÇÓÉ `deadline` ¼ÆËãµÃµ½£¬·µ»ØµÄÊ£Óàʱ¼äÓÐÃëÓëºÁÃëÁ½ÖÖ¡£
+
+¿´µ½ÕâÀ`txObject.getConnectionHolder().setTimeoutInSeconds(timeout)` Ö»Êǽ«³¬Ê±Ê±¼äÉèÖõ½ `ConnectionHolder` µÄ³ÉÔ±±äÁ¿ÖУ¨`ConnectionHolder` ÊÇ `ResourceHolderSupport` µÄ×ÓÀࣩ£¬Ëƺõ¸úÊý¾Ý¿âûɶ¹ØÏµ£¬Êý¾Ý¿âÊÇÔõô¿ØÖÆÊÂÎñ³¬Ê±µÄÄØ£¿
+
+²»µÃ²»Ëµ£¬Õâ¸ö³¬Ê±µÄ¿ØÖÆÊÇÓеãÄÑÕÒ£¬±¾ÎÄÊÇͨ¹ýµ÷ÊÔÕÒµ½µÄ£¬³¬Ê±Ê±¼äµÄÉèÖÃÔÚÔÚ `DataSourceUtils#applyTimeout` ·½·¨ÖУ¬ÕâÆäÖпÉνÊǾ¹ýÁËǧɽÍòË®£º
+
+
+
+¸Ðлµ÷ÊÔ¹¦ÄÜ£¬Ã»ÓÐËü£¬ÌìÖªµÀÒª¶à¾Ã²ÅÄÜÕÒµ½Õâ¸öʱ¼äµÄÉèÖã¡ÎÒÕâÀïʹÓõÄÊÇ `jdbcTemplate`£¬ÔÚÆäËû `orm` ¿ò¼ÜÏ£¬ÉèÖó¬Ê±Ê±¼äÓ¦¸Ã»áÓÐËù²»Í¬ ¡£
+
+ÎÒÃÇ¿´¿´ `DataSourceUtils#applyTimeout` ÊÇÔõôÉèÖó¬Ê±Ê±¼äµÄ£º
+
+```
+public static void applyTimeout(Statement stmt, @Nullable DataSource dataSource, int timeout)
+ throws SQLException {
+ Assert.notNull(stmt, "No Statement specified");
+ ConnectionHolder holder = null;
+ if (dataSource != null) {
+ holder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
+ }
+ if (holder != null && holder.hasTimeout()) {
+ // ÕâÀï¾ÍÊÇ»ñȡʣÓàµÄ³¬Ê±Ê±¼ä£¬ÓÉ ConnectionHolder.dateline ¼ÆËãµÃµ½µÄ
+ stmt.setQueryTimeout(holder.getTimeToLiveInSeconds());
+ }
+ else if (timeout >= 0) {
+ // jdbcTemplate ×ÔÉíÒ²¿ÉÒÔÉèÖòéѯ³¬Ê±Ê±¼ä
+ stmt.setQueryTimeout(timeout);
+ }
+}
+
+```
+
+×îÖÕµ÷ÓõÄÊÇ `java.sql.Statement#setQueryTimeout` À´ÉèÖó¬Ê±Ê±¼äµÄ¡£
+
+#### 1.6 °ó¶¨Êý¾ÝÔ´ÓëÁ¬½Óµ½µ±Ç°Ïß³Ì
+
+ÒÔÉÏÊÂÇé´¦ÀíÍê³Éºó£¬½ÓÏÂÀ´¾ÍÊǰó¶¨Êý¾ÝÔ´ÓëÁ¬½ÓÁË£¬´¦Àí·½·¨Îª `TransactionSynchronizationManager#bindResource`:
+
+```
+/**
+ * resources ´æ·Åµ±Ç°Ïß³ÌÖеÄÊý¾ÝÔ´ÓëÁ¬½Ó
+ * ÆäÖдæ·ÅµÄÄÚÈÝΪһ¸ö Map£¬Map µÄ key ΪÊý¾ÝÔ´£¬value ΪÊý¾ÝÔ´¶ÔÓ¦µÄÁ¬½Ó
+ */
+private static final ThreadLocal> resources =
+ new NamedThreadLocal<>("Transactional resources");
+
+/**
+ * °ó¶¨²Ù×÷
+ */
+public static void bindResource(Object key, Object value) throws IllegalStateException {
+ Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
+ Assert.notNull(value, "Value must not be null");
+ Map map = resources.get();
+ if (map == null) {
+ map = new HashMap<>();
+ resources.set(map);
+ }
+ // ½«Êý¾ÝÔ´ÓëÁ¬½Ó´æ·Åµ½mapÖÐ
+ Object oldValue = map.put(actualKey, value);
+ if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {
+ oldValue = null;
+ }
+ if (oldValue != null) {
+ throw new IllegalStateException("Already value [" + oldValue + "] for key [" +
+ actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");
+ }
+
+```
+
+Õâ Ò»²½µÄ²Ù×÷»¹ÊDZȽϼòµ¥µÄ£¬¾ÍÊǽ«Êý¾ÝÔ´ÓëÁ¬½Ó·Å½ø `resources` ÖУ¬´Ó¶øÍê³ÉÓ뵱ǰÏ̵߳İ󶨲Ù×÷¡£
+
+### 2. `suspend(...)`£º¹ÒÆðÊÂÎñ
+
+¹ÒÆðÊÂÎñµÄ²Ù×÷Ϊ `AbstractPlatformTransactionManager#suspend`£¬´úÂëÈçÏ£º
+
+```
+protected final SuspendedResourcesHolder suspend(@Nullable Object transaction)
+ throws TransactionException {
+ // Èç¹ûÓÐͬ²½µÄÊÂÎñ£¬ÔòÓÅÏÈ¹ÒÆðͬ²½µÄÊÂÎñ
+ if (TransactionSynchronizationManager.isSynchronizationActive()) {
+ List suspendedSynchronizations = doSuspendSynchronization();
+ try {
+ Object suspendedResources = null;
+ if (transaction != null) {
+ // ¹ÒÆð²Ù×÷
+ suspendedResources = doSuspend(transaction);
+ }
+ // ÖØÖÃÊÂÎñÃû³Æ
+ String name = TransactionSynchronizationManager.getCurrentTransactionName();
+ TransactionSynchronizationManager.setCurrentTransactionName(null);
+ // ÖØÖÃÖ»¶Á״̬
+ boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
+ TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
+ // ÖØÖøôÀë¼¶±ð
+ Integer isolationLevel = TransactionSynchronizationManager
+ .getCurrentTransactionIsolationLevel();
+ TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
+ // ÖØÖÃÊÂÎñ¼¤»î״̬
+ boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
+ TransactionSynchronizationManager.setActualTransactionActive(false);
+ // ·µ»Ø¹ÒÆðµÄÊÂÎñ
+ return new SuspendedResourcesHolder(
+ suspendedResources, suspendedSynchronizations, name, readOnly,
+ isolationLevel, wasActive);
+ }
+ catch (RuntimeException | Error ex) {
+ doResumeSynchronization(suspendedSynchronizations);
+ throw ex;
+ }
+ }
+ else if (transaction != null) {
+ Object suspendedResources = doSuspend(transaction);
+ return new SuspendedResourcesHolder(suspendedResources);
+ }
+ else {
+ return null;
+ }
+}
+
+```
+
+`suspend(...)` ·½·¨ÖÐ×îÖØÒªµÄ¾ÍÊÇ¹ÒÆðÊÂÎñµÄ²Ù×÷ÁË£¬Ò²¾ÍÊÇ `doSuspend(transaction)`£¬¸Ã·½·¨ λÓÚ `` ÖУ¬Ö±½Ó¿´´úÂ룺
+
+```
+protected Object doSuspend(Object transaction) {
+ DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
+ txObject.setConnectionHolder(null);
+ // ½â³ý°ó¶¨
+ return TransactionSynchronizationManager.unbindResource(obtainDataSource());
+}
+
+```
+
+¼ÌÐø½øÈë `TransactionSynchronizationManager.unbindResource` ·½·¨£º
+
+```
+/**
+ * ½â³ý°ó¶¨²Ù×÷
+ */
+public static Object unbindResource(Object key) throws IllegalStateException {
+ Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
+ // ¼ÌÐøµ÷ÓÃ
+ Object value = doUnbindResource(actualKey);
+ if (value == null) {
+ throw new IllegalStateException(...);
+ }
+ return value;
+}
+
+/**
+ * ½â³ý°ó¶¨²Ù×÷
+ */
+private static Object doUnbindResource(Object actualKey) {
+ Map map = resources.get();
+ if (map == null) {
+ return null;
+ }
+ // ÒÆ³ý×ÊÔ´
+ Object value = map.remove(actualKey);
+ if (map.isEmpty()) {
+ resources.remove();
+ }
+ if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
+ value = null;
+ }
+ return value;
+}
+
+```
+
+ÔÚ¿ªÆôÊÂÎñʱ£¬Êǽ«Êý¾ÝÔ´ÓëÁ¬½Ó°ó¶¨µ½µ±Ç°Ị̈߳¬¹ÒÆðʱ £¬Êǽ«Êý¾ÝÔ´ÓëÁ¬½Ó½â³ýÓ뵱ǰÏ̵߳İ󶨹ØÏµ¡£
+
+### 3. `createAndHoldSavepoint(...)`£º´´½¨±£´æµã
+
+±£´æµãµÄ´´½¨ÔÚ `AbstractTransactionStatus#createAndHoldSavepoint` ·½·¨Öд¦Àí£¬´úÂëÈçÏ£º
+
+```
+ // ±£´æµã
+ private Object savepoint;
+
+ // ´´½¨±£´æµã
+ public void createAndHoldSavepoint() throws TransactionException {
+ setSavepoint(getSavepointManager().createSavepoint());
+ }
+
+ protected void setSavepoint(@Nullable Object savepoint) {
+ this.savepoint = savepoint;
+ }
+
+```
+
+àÅ£¬¿´À´Õâ¸ö·½·¨ÀïÖ»ÊÇ×öÁË`±£´æµã`µÄ±£´æ£¨Ò²¾ÍÊǸ³Öµ¸ø `AbstractTransactionStatus` µÄ³ÉÔ±±äÁ¿£©£¬ÒªÕæÕýÁ˽Ᵽ´æµãµÄ´´½¨£¬»¹µÃ¿´ `getSavepointManager().createSavepoint()`£¬½øÈëµ½ `JdbcTransactionObjectSupport#createSavepoint`£º
+
+```
+public Object createSavepoint() throws TransactionException {
+ ConnectionHolder conHolder = getConnectionHolderForSavepoint();
+ try {
+ if (!conHolder.supportsSavepoints()) {
+ throw new NestedTransactionNotSupportedException(...);
+ }
+ if (conHolder.isRollbackOnly()) {
+ throw new CannotCreateTransactionException(...);
+ }
+ // ´´½¨±£´æµã
+ return conHolder.createSavepoint();
+ }
+ catch (SQLException ex) {
+ throw new CannotCreateTransactionException("Could not create JDBC savepoint", ex);
+ }
+}
+
+```
+
+·¢ÏÖ×îºóµ÷ÓõÄÊÇ `ConnectionHolder#createSavepoint` ·½·¨£¬ÔÀ´±£´æµãÊÇÔÚ `ConnectionHolder` Öд´½¨µÄ°¡£¡¼ÌÐø£º
+
+```
+// ±£´æµãÃû³ÆÇ°×º
+public static final String SAVEPOINT_NAME_PREFIX = "SAVEPOINT_";
+
+// ±£´æµãÊýÁ¿
+private int savepointCounter = 0;
+
+public Savepoint createSavepoint() throws SQLException {
+ this.savepointCounter++;
+ // ÕâÀï´´½¨±£´æµã£¬µ÷ÓõÄÊÇ java.sql.Connection#setSavepoint(java.lang.String) ·½·¨
+ return getConnection().setSavepoint(SAVEPOINT_NAME_PREFIX + this.savepointCounter);
+}
+
+```
+
+±£´æµãÃû³ÆÇ°×ºÎª `SAVEPOINT_`£¬Ã¿´´½¨Ò»¸ö±£´æµã£¬`savepointCounter` µÄ¼ÆÊýÆ÷¾Í¼Ó 1£¬×îÖÕ±£´æµãµÄÃû³ÆÎª `SAVEPOINT_1`¡¢`SAVEPOINT_2`¡¢...
+
+´´½¨±£´æµã×îÖÕµ÷Óõķ½·¨ÊÇ `java.sql.Connection#setSavepoint(java.lang.String)`£¬ÒÀÈ»ÊÇ jdk ÌṩµÄ·½·¨£¬·ÖÎöµ½ÕâÀÎÒÃǻᷢÏÖÊÂÎñµÄ´ó²¿·Ö²Ù×÷¶¼ÊÇ spring ¶Ô jdk ·½·¨µÄ·â×°¡£
+
+ºÃÁË£¬±¾ÎĵķÖÎö¾ÍÏȵ½ÁË£¬¹ØÓÚÊÂÎñµÄÌá½»¡¢»Ø¹ö¡¢»Ø¹öµ½±£´æµã¡¢»Ö¸´¹ÒÆðµÄÊÂÎñµÈ£¬ÏÂÆªÎÄÕ¼ÌÐø·ÖÎö¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4947826](https://my.oschina.net/funcy/blog/4947826) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\345\205\255\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 04.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\345\205\255\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 04.md"
new file mode 100644
index 0000000..415c012
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\345\205\255\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 04.md"
@@ -0,0 +1,433 @@
+±¾ÎÄÊÇ¡¶ÊÂÎñµÄ¸ôÀë¼¶±ðÓë´«²¥·½Ê½µÄ´¦Àí¡··ÖÎöµÄµÚ 4 ƪ£¬½ÓÉÏÎÄ£¬ÎÒÃǼÌÐø¡£
+
+#### 3.6 Ö´ÐоßÌåµÄÒµÎñ
+
+Õâ¿é´úÂëÈçÏ£º
+
+```
+retVal = invocation.proceedWithInvocation();
+
+```
+
+ÕâÀï×îÖÕ»áµ÷Óõ½ÒµÎñ·½·¨ `UserService#insert`£¬±¾ÎIJ¢²»»á̽¾¿ÕâÆäÖÐÊÇÈçºÎÒ»²½²½µ÷ÓùýÈ¥µÄ£¬ÒªÁ˽âµ÷Óùý³ÌµÄС»ï°é¿ÉÒԲο¼ aop Ïà¹Ø²Ù×÷£º
+
+* [spring aop Ö® jdk ¶¯Ì¬´úÀí](https://my.oschina.net/funcy/blog/4696654)
+* [spring aop Ö® cglib ´úÀí](https://my.oschina.net/funcy/blog/4696655)
+
+#### 3.7 Òì³£»Ø¹ö
+
+´¦ÀíÒì³£µÄ·½·¨Îª `TransactionAspectSupport#completeTransactionAfterThrowing`£¬´úÂëÈçÏ£º
+
+```
+protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
+ if (txInfo != null && txInfo.getTransactionStatus() != null) {
+ // Òì³£·ûºÏ²Å»Ø¹ö
+ if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
+ try {
+ txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
+ }
+ catch (...) {
+ ...
+ }
+ }
+ else {
+ try {
+ // Òì³£²»·ûºÏ£¬¼´Ê¹Ö´Ðгö´íÒ²»áÌá½»
+ txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
+ }
+ catch (...) {
+ ...
+ }
+ }
+ }
+}
+
+```
+
+´ÓÕâ¸ö·½·¨À´¿´£¬³öÏÖÁËÒì³£²¢²»»áÖ±½Ó½øÐлعöµÄ£¬¶øÊÇÏÈÒªÅжÏÒì³£ÀàÐÍ£¬¶ÔÓÚÐèÒª»Ø¹öµÄÒì³£²Å»Ø¹ö¡£
+
+##### Åжϵ±Ç°Òì³£ÊÇ·ñÒª»Ø¹ö
+
+ÅжÏÒì³£ÊÇ·ñ·ûºÏµÄ·½·¨Îª `RuleBasedTransactionAttribute#rollbackOn`£º
+
+```
+public boolean rollbackOn(Throwable ex) {
+ RollbackRuleAttribute winner = null;
+ int deepest = Integer.MAX_VALUE;
+ if (this.rollbackRules != null) {
+ for (RollbackRuleAttribute rule : this.rollbackRules) {
+ // »ñÈ¡Òì³£µÄÉî¶È
+ int depth = rule.getDepth(ex);
+ // Éî¶ÈÂú×ãÌõ¼þ£¬±íʾµ±Ç°Òì³£ÐèÒª»Ø¹ö
+ if (depth >= 0 && depth < deepest) {
+ deepest = depth;
+ winner = rule;
+ }
+ }
+ }
+ if (winner == null) {
+ return super.rollbackOn(ex);
+ }
+ return !(winner instanceof NoRollbackRuleAttribute);
+}
+
+```
+
+»ñÈ¡Ê÷ÉîµÄ·½·¨Îª `RollbackRuleAttribute#getDepth(Throwable)`£¬´úÂëÈçÏ£º
+
+```
+public int getDepth(Throwable ex) {
+ return getDepth(ex.getClass(), 0);
+}
+
+private int getDepth(Class> exceptionClass, int depth) {
+ if (exceptionClass.getName().contains(this.exceptionName)) {
+ // Found it!
+ return depth;
+ }
+ // If we've gone as far as we can go and haven't found it...
+ if (exceptionClass == Throwable.class) {
+ return -1;
+ }
+ // µÝ¹é»ñÈ¡
+ return getDepth(exceptionClass.getSuperclass(), depth + 1);
+}
+
+```
+
+Õâ¸öʵÏֺܼòµ¥£¬¾ÍÊǵݹé»ñÈ¡ `exception` µÄ¸¸À࣬ÕÒµ½Á˾ͷµ»ØµÝ¹éµÄ´ÎÊý£¬Èç¹û×îÖÕÕÒµ½µÄÊÇ `Throwable`£¬¾Í·µ»Ø - 1.
+
+Ö®ËùÒÔʹÓÃÊ÷ÉîÀ´ÅжÏÊÇ·ñÐèÒª»Ø¹ö£¬ÔÒòÊÇÉèÖûعöµÄÒ쳣ʱ£¬¿ÉÒÔÉèÖÃÒì³£Ãû³Æ£º
+
+```
+public @interface Transactional {
+ ...
+
+ // ×¢ÒâÕâ¸öÀàÐÍÊÇ×Ö·û´®
+ String[] rollbackForClassName() default {};
+}
+
+```
+
+Òò´Ë²»ÄÜʹÓà `ex instanceof Exception` µÄ·½Ê½À´ÅжÏÄÜ·ñ»Ø¹ö¡£
+
+`RuleBasedTransactionAttribute#rollbackOn` ÖÐµÄ `RollbackRuleAttribute` Óë `NoRollbackRuleAttribute` ÓÖÊÇɶĨ£¿ËüÃÇ `rollbackFor` Óë `noRollbackFor` µÄ°ü×°À࣬ÔÚ `SpringTransactionAnnotationParser#parseTransactionAnnotation(AnnotationAttributes)` ·½·¨ÖÐÉèÖ㬴úÂëÈçÏ£º
+
+```
+protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
+ RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
+ ...
+ // ´¦Àí»Ø¹öÒì³£
+ List rollbackRules = new ArrayList<>();
+ for (Class> rbRule : attributes.getClassArray("rollbackFor")) {
+ rollbackRules.add(new RollbackRuleAttribute(rbRule));
+ }
+ for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
+ rollbackRules.add(new RollbackRuleAttribute(rbRule));
+ }
+ // ´¦Àí²»»Ø¹öÒì³£
+ for (Class> rbRule : attributes.getClassArray("noRollbackFor")) {
+ rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
+ }
+ for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
+ rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
+ }
+ // ´¦Àí¹æÔò
+ rbta.setRollbackRules(rollbackRules);
+ return rbta;
+}
+
+```
+
+##### »Ø¹ö²Ù×÷
+
+»Ø¹ö²Ù×÷ÔÚ `AbstractPlatformTransactionManager#rollback` ·½·¨Öд¦Àí£¬³ýÁËÊý¾Ý¿âµÄ»Ø¹ö²Ù×÷Í⣬Õâ¸ö·½·¨»¹´¦ÀíÁËһЩ»Øµ÷´¦Àí£¬ÕâÀïÎÒÃǾͲ»·ÖÎöÁË£¬Ö±½Ó¿´¹Ø¼üµÄ»Ø¹ö´úÂë¡£ÔÚÇ°ÃæµÄ·ÖÎöÊÂÎñµÄ´«²¥ÀàÐÍʱ£¬´ó¶à´«²¥ÀàÐÍÊǻعöÊÂÎñ£¬²»¹ý `PROPAGATION_NESTED` ÀýÍ⣬ËüÊǻعöµ½±£´æµã£¬ÕâÀïÎÒÃÇ·Ö±ðÀ´¿´¿´¹Ø¼ü´úÂ룺
+
+1. ÊÂÎñ»Ø¹ö
+
+ ´¦ÀíÊÂÎñ»Ø¹öµÄ·½·¨Îª `DataSourceTransactionManager#doRollback`£¬×îÖÕµ÷ÓõÄÊÇ `java.sql.Connection` µÄ·½·¨£º
+
+ ```
+ protected void doRollback(DefaultTransactionStatus status) {
+ DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
+ // »ñÈ¡Á¬½Ó£¬Connection Ϊ java.sql.Connection
+ Connection con = txObject.getConnectionHolder().getConnection();
+ try {
+ con.rollback();
+ }
+ catch (SQLException ex) {
+ throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
+ }
+ }
+
+ ```
+
+2. »Ø¹öµ½±£´æµã ´¦Àí»Ø¹öµ½±£´æµãµÄ²Ù×÷ÔÚ `AbstractTransactionStatus#rollbackToHeldSavepoint` ·½·¨ÖУº
+
+ ```
+ public void rollbackToHeldSavepoint() throws TransactionException {
+ Object savepoint = getSavepoint();
+ if (savepoint == null) {
+ throw new TransactionUsageException(...);
+ }
+ // »Ø¹öµ½±£´æµã
+ getSavepointManager().rollbackToSavepoint(savepoint);
+ // Êͷű£´æµã
+ getSavepointManager().releaseSavepoint(savepoint);
+ // ½«±£´æµãÖÃΪnull
+ setSavepoint(null);
+ }
+
+ ```
+
+ Õâ¸ö·½·¨Ö÷ÒªÓÐÁ½¸ö²Ù×÷£º»Ø¹öµ½±£´æµãÓëÊͷű£´æµã¡£
+
+ »Ø¹öµ½±£´æµãµÄ²Ù×÷ÔÚ `JdbcTransactionObjectSupport#rollbackToSavepoint` ·½·¨£º
+
+ ```
+ public void rollbackToSavepoint(Object savepoint) throws TransactionException {
+ ConnectionHolder conHolder = getConnectionHolderForSavepoint();
+ try {
+ conHolder.getConnection().rollback((Savepoint) savepoint);
+ conHolder.resetRollbackOnly();
+ }
+ catch (Throwable ex) {
+ throw new TransactionSystemException("Could not roll back to JDBC savepoint", ex);
+ }
+ }
+
+ ```
+
+ Êͷű£´æµãµÄ²Ù×÷ÔÚ `JdbcTransactionObjectSupport#releaseSavepoint` ·½·¨£º
+
+ ```
+ public void releaseSavepoint(Object savepoint) throws TransactionException {
+ ConnectionHolder conHolder = getConnectionHolderForSavepoint();
+ try {
+ conHolder.getConnection().releaseSavepoint((Savepoint) savepoint);
+ }
+ catch (Throwable ex) {
+ logger.debug("Could not explicitly release JDBC savepoint", ex);
+ }
+ }
+
+ ```
+
+ ×îÖÕ¶¼Êǵ÷Óà `java.sql.Connection` ÌṩµÄ·½·¨À´Íê³É²Ù×÷¡£
+
+##### Ìá½»²Ù×÷
+
+ÔÙÀ´¿´¿´Ìá½»²Ù×÷£¬´¦ÀíÌá½»²Ù×÷µÄ´úÂëΪ
+
+```
+txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
+
+```
+
+ÎÒÃǸú½øÕâ¸ö·½·¨£¬Ò»Ö±¸úµ½ `AbstractPlatformTransactionManager#processCommit`£º
+
+```
+private void processCommit(DefaultTransactionStatus status) throws TransactionException {
+ try {
+ ...
+
+ try {
+ if (status.hasSavepoint()) {
+ ...
+ unexpectedRollback = status.isGlobalRollbackOnly();
+ // 1\. Êͷű£´æµã
+ status.releaseHeldSavepoint();
+ }
+ else if (status.isNewTransaction()) {
+ ...
+ unexpectedRollback = status.isGlobalRollbackOnly();
+ // 2\. ´¦ÀíÌá½»²Ù×÷
+ doCommit(status);
+ }
+ else if (isFailEarlyOnGlobalRollbackOnly()) {
+ ...
+ }
+
+ ...
+ }
+ catch (...) {
+ ...
+ }
+ }
+ finally {
+ // 3\. ´¦ÀíÍê³É²Ù×÷£¬ÔÚÕâÀï»á»Ö¸´¹ÒÆðµÄÊÂÎñ(»Ö¸´Êý¾Ý¿âÁ¬½Ó)
+ cleanupAfterCompletion(status);
+ }
+}
+
+```
+
+ÒÔÉÏ·½·¨Ê¡ÂÔÁË´óÁ¿´úÂ룬´ó¶àÊÇÓë `TransactionSynchronization` »Øµ÷Ïà¹ØµÄ£¬ÎÒÃǾۼ¯Ö÷Òª²Ù×÷£º
+
+1. Êͷű£´æµã£ºÕâ¸ö²Ù×÷ÔÚÉÏÃæÒѾ·ÖÎö¹ýÁË£¬ÕâÀï¾Í²»ÔÙ·ÖÎöÁË
+2. ´¦ÀíÌá½»²Ù×÷£ºÌá½»ÔÚÕâÀï½øÐУ¬Ò»»á·ÖÎö£¬×îºóÎÒÃǻᷢÏÖËüÊǵ÷ÓÃÁË `java.sql.Connection` ÌṩµÄ·½·¨
+3. ´¦ÀíÍê³É²Ù×÷£ºÕâ¸ö²Ù×÷±È½ÏÖØÒª£¬ÖØÖÃÁ¬½ÓµÄÐÅÏ¢¡¢»Ö¸´¹ÒÆðÊÂÎñÁ¬½Ó¾ÍÊÇÔÚÕâÀï½øÐеÄ
+
+ÎÒÃÇÏÈÀ´¿´Ìá½»²Ù×÷£¬Ö±½Ó½øÈë×îÖÕ´úÂ룺`DataSourceTransactionManager#doCommit`
+
+```
+protected void doCommit(DefaultTransactionStatus status) {
+ DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
+ // »ñÈ¡Á¬½Ó£¬Connection Ϊ java.sql.Connection
+ Connection con = txObject.getConnectionHolder().getConnection();
+ try {
+ // Ìá½»ÊÂÎñ
+ con.commit();
+ }
+ catch (SQLException ex) {
+ throw new TransactionSystemException("Could not commit JDBC transaction", ex);
+ }
+}
+
+```
+
+×îÖÕÒ²Êǵ÷Óà `java.sql.Connection` ÌṩµÄ·½·¨¡£
+
+ÔÙÀ´¿´ÏÂÍê³É²Ù×÷µÄ´¦Àí£¬½øÈë `AbstractPlatformTransactionManager#cleanupAfterCompletion` ·½·¨£º
+
+```
+private void cleanupAfterCompletion(DefaultTransactionStatus status) {
+ status.setCompleted();
+ if (status.isNewSynchronization()) {
+ TransactionSynchronizationManager.clear();
+ }
+ if (status.isNewTransaction()) {
+ // ÕâÀï»áÖØÖÃÁ¬½Ó£¬Èç¹ûÊÇÐÂÁ¬½Ó£¬ÔÚÕâÀï»á¹Ø±ÕÁ¬½Ó
+ doCleanupAfterCompletion(status.getTransaction());
+ }
+ // Èç¹ûÓÐ¹ÒÆðµÄÊÂÎñ£¬ÔÚÕâÀï½øÐлָ´
+ if (status.getSuspendedResources() != null) {
+ Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
+ // »Ö¸´¹ÒÆðµÄÊÂÎñ
+ resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
+ }
+}
+
+```
+
+ÎÒÃÇÏÈÀ´¿´ `DataSourceTransactionManager#doCleanupAfterCompletion` ·½·¨:
+
+```
+protected void doCleanupAfterCompletion(Object transaction) {
+ DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
+
+ // ÒÆ³ýÊý¾ÝÔ´ÓëÁ¬½ÓµÄ°ó¶¨¹ØÏµ
+ if (txObject.isNewConnectionHolder()) {
+ TransactionSynchronizationManager.unbindResource(obtainDataSource());
+ }
+
+ // ÖØÖÃÁ¬½Ó£¬¾ÍÊǽ«Á¬½ÓÐÅÏ¢»Ö¸´µ½Ö´ÐÐÊÂÎñǰµÄ״̬
+ Connection con = txObject.getConnectionHolder().getConnection();
+ try {
+ if (txObject.isMustRestoreAutoCommit()) {
+ con.setAutoCommit(true);
+ }
+ DataSourceUtils.resetConnectionAfterTransaction(
+ con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
+ }
+ catch (Throwable ex) {
+ logger.debug("Could not reset JDBC Connection after transaction", ex);
+ }
+ // Èç¹ûÊÇÐÂÁ¬½Ó£¬ÓÃÍê¾ÍÔÚÕâÀï¹Ø±ÕÁ¬½Ó
+ if (txObject.isNewConnectionHolder()) {
+ // ×îÖÕµ÷ÓõÄÊÇ java.sql.Connection#close
+ DataSourceUtils.releaseConnection(con, this.dataSource);
+ }
+
+ txObject.getConnectionHolder().clear();
+}
+
+```
+
+ÔÙÀ´¿´¿´ÊÂÎñµÄ»Ö¸´²Ù×÷£¬Ò²¾ÍÊÇ `resume(...)` ·½·¨£¬¸ú½øÕâ¸ö·½·¨ºó£¬·¢ÏÖ×îÖÕµ÷ÓõÄÊÇ `DataSourceTransactionManager#doResume` ·½·¨£¬´úÂëÈçÏ£º
+
+```
+@Override
+protected void doResume(@Nullable Object transaction, Object suspendedResources) {
+ // ½«Êý¾ÝÔ´¡¢¹ÒÆðµÄÊý¾Ý¿âÁ¬½ÓÓ뵱ǰḬ̈߳ó¶¨
+ TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);
+}
+
+```
+
+´¦ÀíÍêÕâÒ»²½ºó£¬´ËʱµÄÊý¾ÝÔ´¾ÍÊÇ֮ǰ¹ÒÆðµÄÊý¾ÝÔ´ÁË¡£
+
+#### 3.8 ÖØÖÃÊÂÎñÐÅÏ¢
+
+ÔÚijЩ´«²¥·½Ê½Ï£¬±ÈÈç `PROPAGATION_REQUIRES_NEW`£¬ÎÒÃÇÐèÒª¹ÒÆðµ±Ç°ÊÂÎñ£¬È»ºó´´½¨ÐµÄÊÂÎñ£¬ÔÚÐÂÊÂÎñÖ´ÐÐÍê³Éºó£¬ÐèÒª»Ö¸´ÔÀ´µÄÊÂÎñ£¬ÕâÀïµÄÖØÖÃÊÂÎñÐÅÏ¢¾ÍÊǽ«µ±Ç°ÊÂÎñÐÅÏ¢»Ö¸´Îª¹ÒÆðµÄÊÂÎñµÄÐÅÏ¢£¨Ö»Êǻָ´ÁËÊÂÎñÐÅÏ¢£¬¹ÒÆðµÄÊý¾Ý¿âÁ¬½Ó²»ÊÇÔÚÕâÀï»Ö¸´£©£º
+
+```
+public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
+
+ // ´æ·Åµ±Ç°Ê¹ÓõÄÊÂÎïÐÅÏ¢
+ private static final ThreadLocal transactionInfoHolder =
+ new NamedThreadLocal<>("Current aspect-driven transaction");
+
+ // ÖØÖÃΪ¾ÉµÄÊÂÎñÐÅÏ¢
+ protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
+ if (txInfo != null) {
+ txInfo.restoreThreadLocalStatus();
+ }
+ }
+
+ /**
+ * TransactionInfo: ±£´æÊÂÎñÐÅÏ¢
+ */
+ protected static final class TransactionInfo {
+
+ // µ±Ç°µÄÊÂÎñ״̬¶ÔÏó
+ @Nullable
+ private TransactionStatus transactionStatus;
+
+ // ¾ÉµÄÊÂÎñÐÅÏ¢£¨Ò²¾ÍÊÇ¹ÒÆðµÄÊÂÎñÐÅÏ¢£©
+ @Nullable
+ private TransactionInfo oldTransactionInfo;
+
+ ...
+
+ private void restoreThreadLocalStatus() {
+ // ÉèÖÃΪ¾ÉµÄÊÂÎñÐÅÏ¢
+ transactionInfoHolder.set(this.oldTransactionInfo);
+ }
+
+ ...
+ }
+
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬`TransactionInfo` ¶Ô»»³ÖÓÐÉÏÒ»¸öÊÂÎñµÄÐÅÏ¢£¨`oldTransactionInfo` µÄ³ÉÔ±±äÁ¿£©£¬ÖØÖûØÉÏÒ»¸öÊÂÎñÐÅϢʱ£¬Ö»ÊǼòµ¥µØ½« `oldTransactionInfo` ÉèÖõ½ÃûΪ `transactionInfoHolder` µÄ `ThreadLocal` Àï¡£
+
+#### 3.9 Ìá½»ÊÂÎñ
+
+´¦ÀíÊÂÎñÌá½»µÄ´úÂëΪ `TransactionAspectSupport#commitTransactionAfterReturning`£¬´úÂëÈçÏ£º
+
+```
+protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
+ // ÅжÏÏÂÊÂÎñµÄ״̬
+ if (txInfo != null && txInfo.getTransactionStatus() != null) {
+ // ´¦ÀíÌá½»²Ù×÷£¬ÕâÇ°ÃæÒѾ·ÖÎö¹ýÁË
+ txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
+ }
+}
+
+```
+
+Ôڸ÷½·¨ÖУ¬ÎÒÃÇÓÖ¿´µ½ÁËÕâÐдúÂ룺
+
+```
+txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
+
+```
+
+Õâ¸öÒѾÔÚÓÉ**Òì³£ÒýÆðµÄÊÂÎñÌá½»**ÖзÖÎö¹ýÁË£¬¾Í²»ÔÙ·ÖÎöÁË¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4947800](https://my.oschina.net/funcy/blog/4947800) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\345\233\233\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 02.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\345\233\233\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 02.md"
new file mode 100644
index 0000000..eba0726
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\344\272\213\345\212\241/spring \344\272\213\345\212\241\357\274\210\345\233\233\357\274\211\357\274\232\344\272\213\345\212\241\347\232\204\351\232\224\347\246\273\347\272\247\345\210\253\344\270\216\344\274\240\346\222\255\346\226\271\345\274\217\347\232\204\345\244\204\347\220\206 02.md"
@@ -0,0 +1,580 @@
+±¾ÎÄÊÇ¡¶ÊÂÎñµÄ¸ôÀë¼¶±ðÓë´«²¥·½Ê½µÄ´¦Àí¡··ÖÎöµÄµÚ 2 ƪ£¬½ÓÉÏÎÄ£¬ÎÒÃǼÌÐø¡£
+
+#### 3.5 »ñÈ¡ÊÂÎñÐÅÏ¢
+
+ÊÂÎñµÄÐÅÏ¢»áÔÚ `TransactionAspectSupport#createTransactionIfNecessary` ·½·¨ÖлñÈ¡£¬Õâ¸ö·½·¨·Ç³£ÖØÒª£¬Ç°Ãæ½éÉܸôÀë¼¶±ð¡¢´«²¥·½Ê½¶¼»áÔÚÕâ¸ö·½·¨Àï´¦Àí¡£¸Ã·½·¨´úÂëÈçÏ£º
+
+```
+protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
+ @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
+ // Èç¹ûδָ¶¨Ãû³Æ£¬Ôò½«·½·¨Ãûµ±×öÊÂÎñÃû³Æ
+ if (txAttr != null && txAttr.getName() == null) {
+ txAttr = new DelegatingTransactionAttribute(txAttr) {
+ @Override
+ public String getName() {
+ return joinpointIdentification;
+ }
+ };
+ }
+
+ TransactionStatus status = null;
+ if (txAttr != null) {
+ if (tm != null) {
+ // »ñÈ¡ÊÂÎñ״̬£¬Èç¹ûµ±Ç°Ã»ÓÐÊÂÎñ£¬¿ÉÄܻᴴ½¨ÊÂÎñ
+ status = tm.getTransaction(txAttr);
+ }
+ }
+ // ×¼±¸ÊÂÎñÐÅÏ¢£¬¾ÍÊǽ«Ç°ÃæµÃµ½µÄÐÅÏ¢·â×°³É TransactionInfo
+ return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
+}
+
+```
+
+Õâ¸ö·½·¨Ö÷ÒªÊÇÁ½¸ö²Ù×÷£º
+
+1. »ñÈ¡ÊÂÎñ״̬
+2. ×¼±¸ÊÂÎñÐÅÏ¢
+
+ÏÈÀ´¿´Ï»ñÈ¡ÊÂÎñ״̬µÄÁ÷³Ì£¬·½·¨Îª `AbstractPlatformTransactionManager#getTransaction`£º
+
+```
+public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
+ throws TransactionException {
+
+ TransactionDefinition def = (definition != null ?
+ definition : TransactionDefinition.withDefaults());
+
+ // »ñÈ¡ÊÂÎñ¶ÔÏó
+ Object transaction = doGetTransaction();
+ boolean debugEnabled = logger.isDebugEnabled();
+
+ // ÊÇ·ñ´æÔÚÊÂÎñ£¬´æÔÚÔò·µ»Ø
+ if (isExistingTransaction(transaction)) {
+ return handleExistingTransaction(def, transaction, debugEnabled);
+ }
+ // ÔËÐе½ÁËÕâÀ±íÃ÷µ±Ç°Ã»ÓÐÊÂÎñ
+
+ // ¼ì²é³¬Ê±Ê±¼äµÄÉèÖÃÊÇ·ñºÏÀí
+ if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
+ throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
+ }
+
+ // PROPAGATION_MANDATORY£º±ØÐëÔÚÊÂÎñÖÐÔËÐУ¬ÕâÀïûÓÐÊÂÎñ£¬Ö±½ÓÅ×Òì³£
+ // No existing transaction found -> check propagation behavior to find out how to proceed.
+ if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
+ throw new IllegalTransactionStateException(...);
+ }
+ // ¹ÒÆðµ±Ç°ÊÂÎñ£¬´´½¨ÐÂÊÂÎñ
+ else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
+ def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
+ def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
+ // suspend(...) ´«Èënull£ºÈç¹ûÓÐͬ²½ÊÂÎñ£¬Ôò¹ÒÆðͬ²½ÊÂÎñ£¬·ñÔòʲôҲ²»×ö
+ SuspendedResourcesHolder suspendedResources = suspend(null);
+ try {
+ boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
+ // ´´½¨ÊÂÎñ¶ÔÏó
+ DefaultTransactionStatus status = newTransactionStatus(
+ def, transaction, true, newSynchronization, debugEnabled, suspendedResources);
+ // Æô¶¯ÊÂÎñ
+ doBegin(transaction, def);
+ // ÉèÖà TransactionSynchronizationManager µÄÊôÐÔ
+ prepareSynchronization(status, def);
+ return status;
+ }
+ catch (RuntimeException | Error ex) {
+ resume(null, suspendedResources);
+ throw ex;
+ }
+ }
+ else {
+ boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
+ return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
+ }
+}
+
+```
+
+Õâ¸ö·½·¨Óе㳤£¬ÎÒÃÇÂýÂý·ÖÎö¡£
+
+##### 1. `doGetTransaction(...)`£º»ñÈ¡ÊÂÎñ¶ÔÏó
+
+»ñÈ¡ÊÂÎñ¶ÔÏóµÄ·½·¨Îª `DataSourceTransactionManager#doGetTransaction`£º
+
+```
+protected Object doGetTransaction() {
+ DataSourceTransactionObject txObject = new DataSourceTransactionObject();
+ txObject.setSavepointAllowed(isNestedTransactionAllowed());
+ // »ñÈ¡Á¬½ÓÐÅÏ¢£¬obtainDataSource()£º»ñÈ¡Êý¾ÝÔ´
+ ConnectionHolder conHolder =
+ (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
+ txObject.setConnectionHolder(conHolder, false);
+ return txObject;
+}
+
+```
+
+ÕâÀïÓÐÁ½¸ö²Ù×÷£º
+
+1. »ñÈ¡Êý¾ÝÔ´
+2. »ñÈ¡ `ConnectionHolder`
+
+ÎÒÃÇÏÈÀ´¿´¿´Êý¾ÝÔ´ÊÇÈçºÎ»ñÈ¡µÄ£º
+
+```
+public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
+ implements ResourceTransactionManager, InitializingBean {
+
+ @Nullable
+ private DataSource dataSource;
+
+ /**
+ * ¹¹Ôì·½·¨´«ÈëÁËÊý¾ÝÔ´
+ */
+ public DataSourceTransactionManager(DataSource dataSource) {
+ this();
+ setDataSource(dataSource);
+ afterPropertiesSet();
+ }
+
+ /**
+ * ÉèÖÃÊý¾ÝÔ´
+ */
+ public void setDataSource(@Nullable DataSource dataSource) {
+ if (dataSource instanceof TransactionAwareDataSourceProxy) {
+ this.dataSource = ((TransactionAwareDataSourceProxy) dataSource)
+ .getTargetDataSource();
+ }
+ else {
+ this.dataSource = dataSource;
+ }
+ }
+
+ @Nullable
+ public DataSource getDataSource() {
+ return this.dataSource;
+ }
+
+ /**
+ * »ñÈ¡Êý¾ÝÔ´
+ */
+ protected DataSource obtainDataSource() {
+ DataSource dataSource = getDataSource();
+ Assert.state(dataSource != null, "No DataSource set");
+ return dataSource;
+ }
+
+ ...
+}
+
+```
+
+`obtainDataSource()` ʵ¼ÊÉÏÊǵ÷ÓÃÁË `getDataSource()` ·½·¨£¬·µ»ØµÄÊÇ `dataSource` ³ÉÔ±±äÁ¿£¬¶ø `dataSource` ÓÖÊÇÔÚ `DataSourceTransactionManager` µÄ¹¹Ôì·½·¨Àï´«ÈëµÄ£¬Òò´Ë£¬µÃµ½µÄ½áÂÛÊÇ£¬ÕâÀï»ñÈ¡µÄÊý¾ÝÔ´¾ÍÊÇÎÒÃÇÔÚÉèÖà `DataSourceTransactionManager` ʱ´«ÈëµÄ£º
+
+```
+@Configuration
+public class TxDemo03Config {
+
+ /**
+ * Éú³ÉÊý¾ÝÔ´
+ * @return
+ * @throws Exception
+ */
+ @Bean
+ public DataSource dataSource() throws Exception {
+ Driver driver = new com.mysql.jdbc.Driver();
+ String url = "jdbc:mysql://localhost:3306/test";
+ String username = "root";
+ String password = "123";
+ return new SimpleDriverDataSource(driver, url, username, password);
+ }
+
+ /**
+ * ÊÂÎñ¹ÜÀíÆ÷
+ * @param dataSource
+ * @return
+ */
+ @Bean
+ public DataSourceTransactionManager transactionManager(DataSource dataSource) {
+ return new DataSourceTransactionManager(dataSource);
+ }
+
+ ...
+
+}
+
+```
+
+¶øÕâ¸öÊý¾ÝÔ´£¬ÕýÊÇ `SimpleDriverDataSource`.
+
+ÎÒÃÇÔÙÀ´¿´¿´ `ConnectionHolder` µÄ»ñÈ¡£¬¸Ã·½·¨Îª `TransactionSynchronizationManager#getResource` £¬´úÂëÈçÏ£º
+
+```
+// ÓÃ ThreadLocal À´´æ·Å ConnectionHolder ÐÅÏ¢
+private static final ThreadLocal> resources =
+ new NamedThreadLocal<>("Transactional resources");
+
+/**
+ * »ñÈ¡ ConnectionHolder
+ */
+public static Object getResource(Object key) {
+ // °ü×°Ï´«ÈëµÄ key
+ Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
+ // ÔÚÕâÀï»ñÈ¡Á¬½ÓÐÅÏ¢
+ Object value = doGetResource(actualKey);
+ return value;
+}
+
+/**
+ * ¾ßÌåµÄ»ñÈ¡²Ù×÷
+ */
+private static Object doGetResource(Object actualKey) {
+ // ´ÓThreadLocalÖлñÈ¡
+ Map map = resources.get();
+ if (map == null) {
+ return null;
+ }
+ Object value = map.get(actualKey);
+ if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
+ map.remove(actualKey);
+ if (map.isEmpty()) {
+ resources.remove();
+ }
+ value = null;
+ }
+ return value;
+}
+
+```
+
+´Ó´úÂëÀ´¿´£¬`TransactionSynchronizationManager` ³ÖÓÐÒ»¸ö `ThreadLocal` µÄʵÀý£¬ÆäÖдæ·ÅÁËÒ»¸ö `Map`£¬¸Ã `Map` µÄ `key` Ϊ `datasource`£¬`value` Ϊ `ConnectionHolder`.
+
+ÄÇôÕâ¸ö `ConnectionHolder` ÊÇÊ²Ã´ÄØ£¿¿ÉÒÔ¼òµ¥µØ½«ÆäÀí½âΪ `Connection`(Êý¾Ý¿âÁ¬½Ó) µÄ°ü×°À࣬ÆäÖÐ×îÖØÒªµÄÊôÐÔ¾ÍÊÇ `Connection` ÁË£º
+
+
+
+ºÃÁË£¬µ½ÕâÀï¾Í°Ñ `doGetTransaction(xxx)` ·½·¨·ÖÎöÍêÁË£¬ÔÙÀ´¿´¿´Õâ¸ö·½·¨·µ»ØµÄ½á¹û£º
+
+
+
+##### 2. `isExistingTransaction(...)`£ºÊÇ·ñ´æÔÚÊÂÎñ
+
+»ñÈ¡µ½ÊÂÎñ¶ÔÏó `DataSourceTransactionObject` ºó£¬½ÓÏÂÀ´¾ÍÊÇÅжÏÊÇ·ñ´æÔÚÊÂÎñÁË£¬ÅжϷ½·¨ÔÚ `DataSourceTransactionManager#isExistingTransaction`£¬´úÂëÈçÏ£º
+
+```
+protected boolean isExistingTransaction(Object transaction) {
+ DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
+ return (txObject.hasConnectionHolder()
+ && txObject.getConnectionHolder().isTransactionActive());
+}
+
+```
+
+`ConnectionHolder` ÖÐÓÐÒ»¸ö³ÉÔ±±äÁ¿ `transactionActive`£¬Ëü±íÃ÷µ±Ç° `ConnectionHolder` µÄÊÂÎñÊÇ·ñ´¦ÓÚ¼¤»î״̬£¬`isExistingTransaction(...)` ·½·¨Ö÷ÒªÊǸù¾ÝËüÀ´Åжϵ±Ç°ÊÂÎñ¶ÔÏóÊÇ·ñ´æÔÚÊÂÎñµÄ¡£
+
+##### 3\. ´¦ÀíÒÑ´æÔÚµÄÊÂÎñ£º`handleExistingTransaction(...)`
+
+ÕâÀïÎÒÃÇÀ´¿´¿´Èç¹ûµ±Ç°´æÔÚÊÂÎñ£¬spring ÊÇÔõô´¦ÀíµÄ£¬´¦ÀíÒÑ´æÔÚÊÂÎñµÄ·½·¨Îª `AbstractPlatformTransactionManager#handleExistingTransaction`£¬´úÂëÈçÏ£º
+
+```
+private TransactionStatus handleExistingTransaction(TransactionDefinition definition,
+ Object transaction, boolean debugEnabled) throws TransactionException {
+ // µ±´«²¥·½Ê½Îª¡¾²»Ê¹ÓÃÊÂÎñ¡¿Ê±£¬Å׳öÒì³£
+ if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
+ throw new IllegalTransactionStateException(
+ "Existing transaction found for transaction marked with propagation 'never'");
+ }
+ // µ±´«²¥·½Ê½Îª¡¾²»Ö§³ÖÊÂÎñ¡¿Ê±£¬¹ÒÆðµ±Ç°ÊÂÎñ£¬È»ºóÔÚÎÞÊÂÎñµÄ״̬ÖÐÔËÐÐ
+ if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
+ // 1\. suspend()£º¹ÒÆðÊÂÎñ²Ù×÷
+ Object suspendedResources = suspend(transaction);
+ boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
+ return prepareTransactionStatus(
+ definition, null, false, newSynchronization, debugEnabled, suspendedResources);
+ }
+
+ // µ±´«²¥·½Ê½Îª¡¾ÔÚеÄÊÂÎñÖÐÔËÐС¿Ê±£¬¹ÒÆðµ±Ç°ÊÂÎñ£¬È»ºóÆô¶¯ÐµÄÊÂÎñ
+ if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
+ // ¹ÒÆðÊÂÎñ²Ù×÷
+ SuspendedResourcesHolder suspendedResources = suspend(transaction);
+ try {
+ boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
+ DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true,
+ newSynchronization, debugEnabled, suspendedResources);
+ // 2\. doBegin()£ºÆô¶¯ÐµÄÊÂÎñ
+ doBegin(transaction, definition);
+ prepareSynchronization(status, definition);
+ return status;
+ }
+ catch (RuntimeException | Error beginEx) {
+ resumeAfterBeginException(transaction, suspendedResources, beginEx);
+ throw beginEx;
+ }
+ }
+
+ // µ±´«²¥·½Ê½Îª¡¾Ç¶Ì×Ö´ÐС¿Ê±£¬ ÉèÖÃÊÂÎñµÄ±£´æµã
+ // ´æÔÚÊÂÎñ£¬½«¸ÃÊÂÎñ±ê×¢±£´æµã£¬ÐγÉǶÌ×ÊÂÎñ¡£
+ // ǶÌ×ÊÂÎñÖеÄ×ÓÊÂÎñ³öÏÖÒì³£²»»áÓ°Ïìµ½¸¸ÊÂÎñ±£´æµã֮ǰµÄ²Ù×÷¡£
+ if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
+ if (!isNestedTransactionAllowed()) {
+ throw new NestedTransactionNotSupportedException(...);
+ }
+ // 3\. createAndHoldSavepoint(...)£º´´½¨±£´æµã£¬»Ø¹öʱֻ»Ø¹öµ½¸Ã±£´æµã
+ if (useSavepointForNestedTransaction()) {
+ DefaultTransactionStatus status = prepareTransactionStatus(definition, transaction,
+ false, false, debugEnabled, null);
+ status.createAndHoldSavepoint();
+ return status;
+ }
+ else {
+ boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
+ DefaultTransactionStatus status = newTransactionStatus(
+ definition, transaction, true, newSynchronization, debugEnabled, null);
+ // Èç¹û²»Ö§³Ö±£´æµã£¬¾ÍÆô¶¯ÐµÄÊÂÎñ
+ doBegin(transaction, definition);
+ prepareSynchronization(status, definition);
+ return status;
+ }
+ }
+ if (isValidateExistingTransaction()) {
+ // ´¦ÀíÑéÖ¤²Ù×÷£¬²»×÷·ÖÎö
+ ...
+ }
+ boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
+ return prepareTransactionStatus(definition, transaction, false,
+ newSynchronization, debugEnabled, null);
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬Õâ¸ö·½·¨Àï¾Í´¦ÀíÁËÊÂÎñµÄ¸ôÀë¼¶±ðµÄÂß¼£¬Ïà¹ØµÄ´úÂëÒѾ×÷ÁË×¢ÊÍ£¬ÕâÀï¾Í²»¶à˵ÁË£¬²»¹ýÕâÀïÓм¸¸ö·½·¨ÐèÒªÌØ±ðÌá³ö£º
+
+1. `suspend()`£º¹ÒÆðÊÂÎñ²Ù×÷
+2. `doBegin()`£ºÆô¶¯ÐµÄÊÂÎñ
+3. `createAndHoldSavepoint(...)`£º´´½¨±£´æµã£¬»Ø¹öʱֻ»Ø¹öµ½¸Ã±£´æµã
+
+Õ⼸¸ö²Ù×÷°üº¬ÁËÊÂÎñ´¦Àí²Ù×÷£¬ºóÃæÎÒÃÇÔÙͳһ·ÖÎö¡£
+
+##### 4\. ¼ÌÐø `AbstractPlatformTransactionManager#getTransaction`
+
+ÈÃÎÒÃÇÔٻص½ `AbstractPlatformTransactionManager#getTransaction` ·½·¨£¬¼ÌÐøÊ£ÏµÄÁ÷³Ì£º
+
+```
+public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
+ throws TransactionException {
+
+ // Ç°ÃæÒѾ·ÖÎö¹ýÁË£¬Ê¡ÂÔ
+ ...
+
+ // ÔËÐе½ÁËÕâÀ±íÃ÷µ±Ç°Ã»ÓÐÊÂÎñ
+
+ // ¼ì²é³¬Ê±Ê±¼äµÄÉèÖÃÊÇ·ñºÏÀí
+ if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
+ throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
+ }
+
+ // PROPAGATION_MANDATORY£º±ØÐëÔÚÊÂÎñÖÐÔËÐУ¬ÕâÀïûÓÐÊÂÎñ£¬Ö±½ÓÅ×Òì³£
+ if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
+ throw new IllegalTransactionStateException(...);
+ }
+ // ¹ÒÆðµ±Ç°ÊÂÎñ£¬´´½¨ÐÂÊÂÎñ
+ else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
+ def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
+ def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
+ // suspend(...) ´«Èënull£ºÈç¹ûÓÐͬ²½ÊÂÎñ£¬Ôò¹ÒÆðͬ²½ÊÂÎñ£¬·ñÔòʲôҲ²»×ö
+ SuspendedResourcesHolder suspendedResources = suspend(null);
+ try {
+ boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
+ // ´´½¨ÊÂÎñ¶ÔÏó
+ DefaultTransactionStatus status = newTransactionStatus(
+ def, transaction, true, newSynchronization, debugEnabled, suspendedResources);
+ // Æô¶¯ÊÂÎñ
+ doBegin(transaction, def);
+ // ÉèÖà TransactionSynchronizationManager µÄÊôÐÔ
+ prepareSynchronization(status, def);
+ return status;
+ }
+ catch (RuntimeException | Error ex) {
+ resume(null, suspendedResources);
+ throw ex;
+ }
+ }
+ else {
+ boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
+ return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
+ }
+}
+
+```
+
+`handleExistingTransaction(...)` ·½·¨µÄ¹¦ÄÜÊÇ**µ±ÊÂÎñ´æÔÚʱ£¬ÄÇЩ¸ö´«²¥ÀàÐÍÒªÔõô´¦Àí**£¬`getTransaction(...)` ·½·¨Óàϲ¿·ÖµÄ¹¦ÄÜÊÇ£¬**µ±ÊÂÎñ´æÔÚʱ£¬ÄÇЩ¸ö´«²¥ÀàÐÍÓÖÒªÔõô´¦Àí**¡£¿ÉÒÔ¿´µ½£¬ÕâÀïÃæÒÀÈ»»¹ÊÇÓÐ `suspend(...)`¡¢`doBegin(...)` µÈ·½·¨£¬ÕâЩ¸ö·½·¨ÎÒÃÇÒ»»áҲͳһ·ÖÎö¡£
+
+##### 5\. ×¼±¸·µ»Ø½á¹û£º`prepareTransactionStatus(...)`
+
+`handleExistingTransaction(...)` ·½·¨Óë `getTransaction(...)` ·½·¨ÔÚ´¦Àí·µ»Ø½á¹ûʱ£¬¶¼Ê¹ÓÃÁË `prepareTransactionStatus(...)` ·½·¨£º
+
+```
+// `handleExistingTransaction(...)`·½·¨
+return prepareTransactionStatus(definition, transaction, false,
+ newSynchronization, debugEnabled, null);
+
+// `getTransaction(...)`·½·¨
+return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
+
+```
+
+ÎÒÃÇÀ´·ÖÎöÏÂÕâ¸ö·½·¨ÊÇ×öÁËɶ£¬½øÈë `AbstractPlatformTransactionManager#prepareTransactionStatus`£º
+
+```
+protected final DefaultTransactionStatus prepareTransactionStatus(
+ TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
+ boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
+
+ // ´´½¨ÁËÒ»¸ö DefaultTransactionStatus ¶ÔÏó
+ DefaultTransactionStatus status = newTransactionStatus(
+ definition, transaction, newTransaction, newSynchronization, debug, suspendedResources);
+ // ×¼±¸ Synchronization
+ prepareSynchronization(status, definition);
+ return status;
+}
+
+/**
+ *´´½¨Ò»¸ö TransactionStatus ʵÀý
+ */
+protected DefaultTransactionStatus newTransactionStatus(
+ TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
+ boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
+
+ boolean actualNewSynchronization = newSynchronization &&
+ !TransactionSynchronizationManager.isSynchronizationActive();
+ // µ÷Óà DefaultTransactionStatus µÄ¹¹Ôì·½·¨
+ return new DefaultTransactionStatus(
+ transaction, newTransaction, actualNewSynchronization,
+ definition.isReadOnly(), debug, suspendedResources);
+}
+
+```
+
+ËùÒÔÕâ¸ö·½·¨Ö÷Òª¾ÍÊÇΪÁË´´½¨ `DefaultTransactionStatus` ¶ÔÏó£¡ÎÒÃÇÀ´¿´ÏÂÕâÒ»²½µÄÔËÐнá¹û£º
+
+
+
+##### 6\. ×¼±¸ÊÂÎñÐÅÏ¢£º`TransactionAspectSupport#prepareTransactionInfo`
+
+»Øµ½ `TransactionAspectSupport#createTransactionIfNecessary` ·½·¨£º
+
+```
+protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
+ @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
+ ...
+ TransactionStatus status = null;
+ if (txAttr != null) {
+ if (tm != null) {
+ // »ñÈ¡ÊÂÎñ״̬£¬Èç¹ûµ±Ç°Ã»ÓÐÊÂÎñ£¬¿ÉÄܻᴴ½¨ÊÂÎñ
+ status = tm.getTransaction(txAttr);
+ }
+ }
+ // ×¼±¸ÊÂÎñÐÅÏ¢£¬¾ÍÊǽ«Ç°ÃæµÃµ½µÄÐÅÏ¢·â×°³É TransactionInfo
+ return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
+}
+
+```
+
+Ç°Ãæ·ÖÎöÁËÄÇô¶à£¬Ö»Êǵõ½ÁË `TransactionStatus`£¬ÎÒÃÇÔÙ½ÓÔÙÀ÷£¬¼ÌÐø·ÖÎö×¼±¸ÊÂÎñÐÅÏ¢µÄ·½·¨ `prepareTransactionInfo(...)`£º
+
+```
+protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
+ @Nullable TransactionAttribute txAttr, String joinpointIdentification,
+ @Nullable TransactionStatus status) {
+ TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
+
+ if (txAttr != null) {
+ txInfo.newTransactionStatus(status);
+ }
+
+ // Ê¡ÂÔlogµÄ´òÓ¡
+ ...
+
+ // ÓëḬ̈߳ó¶¨
+ txInfo.bindToThread();
+ return txInfo;
+}
+
+```
+
+àÅ£¬Í¬ `prepareTransactionStatus(...)` ÀàËÆ£¬Õâ¸ö·½·¨Ò²ÊÇ´´½¨ÁËÒ»¸ö `TransactionInfo` ¶ÔÏ󣬲¢ÇÒ½« `TransactionInfo` Ó뵱ǰḬ̈߳󶨣¬°ó¶¨µÄ´úÂëÈçÏ£º
+
+```
+public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
+
+ // ´æ·Åµ±Ç°Ê¹ÓõÄÊÂÎïÐÅÏ¢
+ private static final ThreadLocal transactionInfoHolder =
+ new NamedThreadLocal<>("Current aspect-driven transaction");
+
+ // ÖØÖÃΪ¾ÉµÄÊÂÎñÐÅÏ¢
+ protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
+ if (txInfo != null) {
+ txInfo.restoreThreadLocalStatus();
+ }
+ }
+
+ /**
+ * TransactionInfo: ±£´æÊÂÎñÐÅÏ¢
+ */
+ protected static final class TransactionInfo {
+
+ // µ±Ç°µÄÊÂÎñ״̬¶ÔÏó
+ @Nullable
+ private TransactionStatus transactionStatus;
+
+ // ¾ÉµÄÊÂÎñÐÅÏ¢£¨Ò²¾ÍÊÇ¹ÒÆðµÄÊÂÎñÐÅÏ¢£©
+ @Nullable
+ private TransactionInfo oldTransactionInfo;
+
+ /**
+ * ½«ÊÂÎñÐÅÏ¢°ó¶¨µ½µ±Ç°Ïß³Ì
+ */
+ private void bindToThread() {
+ // Äõ½¾ÉµÄÊÂÎñÐÅÏ¢
+ this.oldTransactionInfo = transactionInfoHolder.get();
+ // ÉèÖóÉ×îеÄÊÂÎñÐÅÏ¢
+ transactionInfoHolder.set(this);
+ }
+
+ /**
+ * ÊÂÎñÍê³Éºó£¬»á½«¾ÉµÄÊÂÎñÐÅÏ¢°ó¶¨µ½µ±Ç°Ïß³Ì
+ */
+ private void restoreThreadLocalStatus() {
+ // ÉèÖÃΪ¾ÉµÄÊÂÎñÐÅÏ¢
+ transactionInfoHolder.set(this.oldTransactionInfo);
+ }
+
+ ...
+ }
+
+}
+
+```
+
+`TransactionAspectSupport` ÖÐÓÐÒ»¸ö `ThreadLocal`£¬ÓÃÀ´´æ·Åµ±Ç°µÄ `TransactionInfo` ¶ÔÏ󣬽øÐÐḬ̈߳ó¶¨Ê±£¬»áÏÈÄõ½¾ÉµÄÊÂÎñÐÅÏ¢£¬±£´æÔÚ `TransactionInfo` µÄ³ÉÔ±±äÁ¿ `oldTransactionInfo` ÖУ¬È»ºó½«Ð嵀 `TransactionInfo` ·ÅÈë `ThreadLocal` ÖУ»µ±ÊÂÎñÖ´ÐÐÍê³Éºó£¬»á´Ó `TransactionInfo` µÄ³ÉÔ±±äÁ¿ `oldTransactionInfo` ÖÐÄõ½¾ÉµÄÊÂÎñÐÅÏ¢£¬ÔÙ½«¾ÉµÄÊÂÎñÐÅÏ¢·ÅÈë `ThreadLocal` ÖУ¬Õâ¾ÍÍê³ÉÁËÊÂÎñ "¾É - Р- ¾É" µÄÇл».
+
+ÕâÒ»²½µÃµ½µÄ `TransactionInfo` ÈçÏ£º
+
+
+
+¶ÔÓÚ `TransactionInfo` µÄ½á¹¹£¬ÕâÀï×÷һЩ˵Ã÷£º
+
+* ÀàÐÍÊÇ `TransactionAspectSupport.TransactionInfo`£¬ÊÇ `TransactionAspectSupport` µÄÒ»¸öÄÚ²¿À࣬·â×°ÁËÊÂÎñµÄһЩÐÅÏ¢
+* `transactionManager`: ÊÂÎñ¹ÜÀíÆ÷£¬¾ÍÊÇÎÒÃÇÉèÖÃµÄ `DataSourceTransactionManager`
+* `transactionAttribute`: ÊÂÎñÊôÐÔÖµ£¬ÓÃÀ´±£´æ `@Transactional` ×¢½âµÄÊôÐÔÖµ
+* `joinpointIdentification`: ·½·¨µÄÈ«ÏÞ¶¨Ãû£¨¸ñʽΪ£º"°üÃû¡£ÀàÐÍ¡£·½·¨Ãû"£©
+* `transactionStatus`: ´ÓÃû³ÆÉÏ¿´£¬ÊǼǼÊÂÎñµÄ״̬£¬Êµ¼ÊÕâ¸ö¶ÔÏó²»½ö¼Ç¼ÁËÊÂÎñµÄ״̬£¬°üÀ¨µÄÖØ´ó¹¦ÄÜÈçÏ£º
+ * `complete`: ÊÂÎñµÄÍê³É״̬
+ * `connectionHolder`: µ±Ç°³ÖÓеÄÊý¾Ý¿âÁ¬½Ó
+ * `suspendedResources`: ¹ÒÆðµÄÊý¾Ý¿âÁ¬½Ó£¬µ±ÐèÒª»Ö¸´¹ÒÆðµÄÊÂÎñʱ£¬¿ÉÒÔÄܹý¸Ã¶ÔÏóÄõ½¹ÒÆðµÄÊý¾Ý¿âÁ¬½Ó
+* `oldTransactionInfo`: ÉÏÒ»¸öÊÂÎñ£¨Ò²¾ÍÊÇ¹ÒÆðµÄÊÂÎñ£©µÄÐÅÏ¢£¬Ö´ÐÐÍ굱ǰÊÂÎñºó£¬»á»Ö¸´µ½ÉÏÒ»¸öÊÂÎñµÄÖ´ÐÐ
+
+Ò»²»Ð¡ÐÄÓÖдÁËÕâô³¤ÁË£¬±¾ÎľÍÏÈ·ÖÎöµ½ÕâÀïÁË£¬`suspend(...)`¡¢`doBegin(...)` µÈ·½·¨ÏÂÆªÔÙ·ÖÎö°É¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4947799](https://my.oschina.net/funcy/blog/4947799) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\357\274\232\345\220\257\345\212\250\346\265\201\347\250\213\346\246\202\350\247\210.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\357\274\232\345\220\257\345\212\250\346\265\201\347\250\213\346\246\202\350\247\210.md"
new file mode 100644
index 0000000..841ee00
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\200\357\274\211\357\274\232\345\220\257\345\212\250\346\265\201\347\250\213\346\246\202\350\247\210.md"
@@ -0,0 +1,230 @@
+在å‰�é�¢çš„æ–‡ç« ä¸ï¼Œæˆ‘们æˆ�功的编译了 spring æº�ç �,也构建了第一个 spring 测试 demo,接下æ�¥æˆ‘们就基于[第一个 spring æº�ç �调试 demo](https://my.oschina.net/funcy/blog/4533250 "第一个springæº�ç �调试demo") ä¸çš„代ç �,æ�¥å¯¹ spring æº�ç �进行æº�ç �分æž�。
+
+### 1\. spring �动�程概览
+
+在å‰�é�¢ demo çš„ `main()` 方法ä¸ï¼Œæœ‰è¿™ä¹ˆä¸€è¡Œï¼š
+
+```
+ApplicationContext context =
+ new AnnotationConfigApplicationContext("org.springframework.learn.demo01");
+
+```
+
+è¿™çŸçŸçš„一行就是 spring 的整个å�¯åЍæµ�程了。上é�¢çš„代ç �ä¸ï¼Œå£°æ˜Žäº†ä¸€ä¸ª `ApplicationContext` 类型的对象 `context`,å�³è¾¹ä½¿ç”¨å…¶å�ç±» `AnnotationConfigApplicationContext` å®žä¾‹åŒ–ï¼Œå¹¶åœ¨æž„é€ æ–¹æ³•ä¸ä¼ 入了包å�� `org.springframework.learn.demo01`,这个包å��就表明了接下æ�¥è¦�扫æ��哪些包。
+
+> 这里我们接触到了 spring 的第一个组件:`ApplicationContext`,关于 `ApplicationContext` 的分æž�,å�¯ä»¥å�‚è€ƒæˆ‘çš„æ–‡ç« [spring 组件(一):ApplicationContext](https://my.oschina.net/funcy/blog/4597456 "spring组件(一):ApplicationContext")。
+
+进入到 `AnnotationConfigApplicationContext`,代ç �如下:
+
+> AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)
+
+```
+public AnnotationConfigApplicationContext(String... basePackages) {
+ // 1\. è°ƒç”¨æ— å�‚æž„é€ å‡½æ•°ï¼Œä¼šå…ˆè°ƒç”¨çˆ¶ç±»GenericApplicationContextçš„æž„é€ å‡½æ•°
+ // 2\. çˆ¶ç±»çš„æž„é€ å‡½æ•°é‡Œé�¢å°±æ˜¯åˆ�始化DefaultListableBeanFactory,并且赋值给beanFactory
+ // 3\. æœ¬ç±»çš„æž„é€ å‡½æ•°é‡Œé�¢ï¼Œåˆ�始化了一个读å�–器:AnnotatedBeanDefinitionReader read,
+ // 一个扫�器ClassPathBeanDefinitionScanner scanner
+ // 4\. 这个scanner,就是下� scan(basePackages) 调用的对象
+ this();
+
+ //å¯¹ä¼ å…¥çš„åŒ…è¿›è¡Œæ‰«æ��,扫æ��完æˆ�å�Žï¼Œä¼šå¾—到一个 BeanDefinition 的集å�ˆ
+ scan(basePackages);
+
+ //�动spring,在这里完�spring容器的�始化�作,
+ //包括bean的实例化ã€�属性注入,将beanä¿�å˜åˆ°spring容器ä¸ç‰
+ refresh();
+}
+
+```
+
+这个类就三行,相关æ“�作都已在代ç �䏿³¨é‡Šäº†ï¼Œè¿™é‡Œç¨�å¾®å†�总结下,这段代ç �主è¦�å�šäº†ä¸‰ä»¶äº‹ï¼š
+
+1. è°ƒç”¨æ— å�‚æž„é€ ï¼Œè¿›è¡Œå±žæ€§åˆ�始化
+2. 进行包扫�,得到 BeanDefinition
+3. �用 spring 容器。
+
+接ç�€ï¼Œæˆ‘们å†�æ�¥çœ‹çœ‹ spring å�¯åЍæµ�程ä¸ï¼Œå�šäº†å“ªäº›äº‹ï¼š
+
+> AbstractApplicationContext#refresh
+
+```
+public void refresh() throws BeansException, IllegalStateException {
+ // 使用synchronized是为了��refresh() 还没结�,�次�起�动或者销�容器引起的冲�
+ synchronized (this.startupShutdownMonitor) {
+ // å�šä¸€äº›å‡†å¤‡å·¥ä½œï¼Œè®°å½•容器的å�¯åŠ¨æ—¶é—´ã€�æ ‡è®°â€œå·²å�¯åЍâ€�状æ€�ã€�检查环境å�˜é‡�ç‰
+ prepareRefresh();
+
+ // �始化BeanFactory容器�注册BeanDefinition, 最终获得了DefaultListableBeanFactory
+ ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
+
+ // 还是一些准备工作:
+ // 1\. è®¾ç½®äº†ä¸€ä¸ªç±»åŠ è½½å™¨
+ // 2\. 设置了bean表达�解�器
+ // 3\. æ·»åŠ äº†å±žæ€§ç¼–è¾‘å™¨çš„æ”¯æŒ�
+ // 4\. æ·»åŠ äº†ä¸€ä¸ªå�Žç½®å¤„ç�†å™¨ï¼šApplicationContextAwareProcessor
+ // 5\. 设置了一些忽略自动装�的接�
+ // 6\. 设置了一些�许自动装�的接�,并且进行了赋值�作
+ // 7\. 在容器ä¸è¿˜æ²¡æœ‰XXçš„bean的时候,帮我们注册beanName为XXçš„singleton bean
+ prepareBeanFactory(beanFactory);
+
+ try {
+ // Spring的一个扩展点. 如果有Bean实现了BeanFactoryPostProcessor接�,
+ // 那么在容器�始化以�,Spring 会负责调用里�的 postProcessBeanFactory 方法。
+ // 具体的å�ç±»å�¯ä»¥åœ¨è¿™æ¥çš„æ—¶å€™æ·»åŠ ç‰¹æ®Šçš„ BeanFactoryPostProcessor 的实现类,æ�¥å�šäº›äº‹
+ postProcessBeanFactory(beanFactory);
+
+ // 调用BeanFactoryPostProcessor�个实现类的postProcessBeanFactory(factory) 方法
+ invokeBeanFactoryPostProcessors(beanFactory);
+
+ // 扩展点,注册 BeanPostProcessor 的实现类,注��是BeanFactoryPostProcessor
+ registerBeanPostProcessors(beanFactory);
+
+ // åˆ�始化当å‰� ApplicationContext çš„ MessageSource,用在国际化æ“�作ä¸
+ initMessageSource();
+
+ // 这个方法主è¦�为åˆ�始化当å‰� ApplicationContext 的事件广æ’器
+ initApplicationEventMulticaster();
+
+ // 这也是spring的一个扩展点
+ onRefresh();
+
+ // Check for listener beans and register them.
+ // 注册事件监�器
+ registerListeners();
+
+ // �始化所有的 singleton beans
+ finishBeanFactoryInitialization(beanFactory);
+
+ // 完��动,
+ finishRefresh();
+ }
+
+ catch (BeansException ex) {
+ if (logger.isWarnEnabled()) {
+ logger.warn("Exception encountered during context initialization - " +
+ "cancelling refresh attempt: " + ex);
+ }
+
+ // Destroy already created singletons to avoid dangling resources.
+ // 销�已��始化的的Bean
+ destroyBeans();
+
+ // Reset 'active' flag.
+ // �置 'active' 状�
+ cancelRefresh(ex);
+
+ // Propagate exception to caller.
+ throw ex;
+ }
+
+ finally {
+ // Reset common introspection caches in Spring's core, since we
+ // might not ever need metadata for singleton beans anymore...
+ // 清除缓å˜
+ resetCommonCaches();
+ }
+ }
+}
+
+```
+
+这个方法虽然代ç �ä¸�多,但包å�«äº† spring bean 的整个创建过程,æ¯�个方法å�šäº†äº›ä»€ä¹ˆï¼Œåœ¨ä»£ç �ä¸éƒ½æœ‰æ³¨é‡Šï¼Œè¿™é‡Œå°±ä¸�赘述了。
+
+实际上,`refresh()` 涵盖了 spring 整个创建 bean çš„æµ�程,在å�Žé�¢çš„æ–‡ç« ä¸ï¼Œæˆ‘们也将é‡�点展开这里é�¢çš„æ–¹æ³•æ�¥åˆ†æž�,在现阶段å�ªéœ€è¦�大致了解这些方法å�šäº†ä»€ä¹ˆäº‹å�³å�¯ã€‚
+
+整个�程总结如下:
+
+
+
+### 2\. spring å�¯åŠ¨ä¸ `beanFactory` çš„å�˜åŒ–
+
+本文ä¸çš„æº�ç �解读就到这里了,接下æ�¥æˆ‘们æ�¥çœ‹çœ‹ï¼Œspring å�¯åŠ¨ä¸ `beanFactory` 有些什么å�˜åŒ–。
+
+> `beanFactory` 是 spring çš„é‡�è¦�组件之一,直译为 spring bean 工厂,是 spring 生产 bean 与ä¿�å˜ bean 的地方,关于 `beanFactory` 的详细分æž�,å�¯ä»¥æŸ¥çœ‹ [spring BeanFactory 分æž�](https://my.oschina.net/funcy/blog/4597529 "spring BeanFactory分æž�")。
+
+我们将æ–点打在 `AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)` çš„ `this()` 方法上,然å�Žè¿�行 demo01 çš„ `main()` 方法:
+
+
+
+æ¤æ—¶çš„å�˜é‡�ä¸ï¼Œå¹¶æ²¡æœ‰ `beanFactory`ï¼Œæˆ‘ä»¬è‡ªå·±æ·»åŠ `beanFactory` 到调度窗å�£çš„å�˜é‡�列表ä¸ï¼š
+
+
+
+è¿™æ ·å°±èƒ½çœ‹åˆ°å¯¹åº”çš„å€¼äº†ï¼š
+
+
+
+å�¯ä»¥çœ‹åˆ°ï¼Œæ¤æ—¶çš„ `beanFactory` 为 null,表明 `beanFactory` 并未实例化,我们继ç»è¿�行:
+
+
+
+当�行完 `this()` �,�现 `beanFactory` 已�有值了,类型为 `DefaultListableBeanFactory`。但是,在查看 `beanFactory` 对象时,�现 `beanFactory` 的属性太多了,我们应该�点关注啥呢?
+
+
+
+我们这部分主è¦�关注 spring bean çš„åˆ›å»ºï¼Œå› æ¤å�ªéœ€è¦�关注 `beanFactory` 的两个属性就å�¯ä»¥äº†ï¼š
+
+* beanDefinitionMapï¼šå˜æ”¾ beanDefinition çš„ map.
+* singletonObjectsï¼šå˜æ”¾ spring bean çš„ map,spring bean 创建å�Žéƒ½å˜æ”¾åœ¨è¿™é‡Œï¼Œä¹Ÿå�³ç›´è§‚上ç�†è§£çš„ `spring 容器`.
+
+> `BeanDefinition` 是 spring ��组件之一,为‘spring bean 的�述’,简��说,就是说明了一个 spring bean 应该如何创建。关于 `BeanDefinition` 的详细分�,�以查看 [spring BeanDefinition 分�](https://my.oschina.net/funcy/blog/4597536)。
+
+æˆ‘ä»¬æ‰‹åŠ¨æ·»åŠ å�˜é‡�,如下:
+
+
+
+å�¯ä»¥çœ‹åˆ°ï¼Œæ¤æ—¶çš„ `beanDefinitionMap` ä¸å·²ç»�有 4 个对象了,显然是在 `this()` æ–¹æ³•ä¸æ·»åŠ çš„ï¼Œå…³äºŽè¿™å�—我们å�Žé�¢ä¼šåˆ†æž�。
+
+接��行,�现 `beanDefinitionMap` �多了两个:
+
+
+
+这里的 `beanObj1` 与 `beanObj2` 就是我们自己的类了,由æ¤å�¯ä»¥åˆ¤æ–出 **spring 就是在 `AnnotationConfigApplicationContext#scan` 方法ä¸å¯¹åŒ…进行扫æ��çš„**。
+
+接下æ�¥ï¼Œä»£ç �执行进入 `AbstractApplicationContext#refresh` 方法,我们一行行è¿�行下去,å�‘现è¿�行到 `prepareBeanFactory(beanFactory);` 时,`singletonObjects` ä¸ç¬¬ä¸€æ¬¡å‡ºçŽ°äº†å¯¹è±¡ï¼š
+
+
+
+å�¯ä»¥çœ‹åˆ°ï¼Œè¿™é‡Œå‡ºçŽ°äº† 3 个类,基本都跟系统ã€�环境相关,如 `environment` 是 spring 当å‰�使用的环境 (`profile`),`systemProperties` 当å‰�系统的属性(æ“�作系统ã€�æ“�作系统版本ç‰ï¼‰ã€‚
+
+ç»§ç»å¾€ä¸‹è¿�行,å�‘现代ç �è¿�行到 `invokeBeanFactoryPostProcessors(beanFactory)` 时,å�ˆå¤šäº† 4 个类:
+
+
+
+å…³äºŽè¿™å‡ ä¸ªç±»çš„ä½œç”¨ï¼Œæˆ‘ä»¬å�Žé�¢çš„æ–‡ç« ä¸ä¼šåˆ†æž�,这里先ä¸�必管。继ç»å¾€ä¸‹è¿�行,å�‘现在 `registerBeanPostProcessors(beanFactory);` ä¸ï¼Œå�ˆå¤šäº†ä¸€ä¸ªå¯¹è±¡ï¼š
+
+```
+org.springframework.context.annotation.internalAutowiredAnnotationProcessor
+
+```
+
+这里我们�旧�用管这个对象,接��行下去,�以看到在�行 `initMessageSource()` 时,�多了一个对象:
+
+```
+messageSource -> {DelegatingMessageSource@1847} "Empty MessageSource"
+
+```
+
+显然,这个对象是用æ�¥å¤„ç�†å›½é™…化问题的,ä¸�过由于 demo01 ä¸å¹¶æ²¡æœ‰ç”¨åˆ°å›½é™…化,所以这里显示 `Empty MessageSource`。继ç»è¿�行,å�‘现è¿�行到 `initApplicationEventMulticaster();` 时,å�ˆå¤šäº†ä¸€ä¸ªå¯¹è±¡ï¼š
+
+```
+applicationEventMulticaster -> {SimpleApplicationEventMulticaster@1869}
+
+```
+
+显然,这个对象是用æ�¥å¤„ç�† `ApplicationContext` 的广æ’事件的,我们的 demo ä¸å¹¶æ²¡æœ‰ç”¨åˆ°ï¼Œæš‚æ—¶ä¸�å¿…ç�†ä¼šã€‚ç»§ç»ä¸‹åŽ»ï¼Œå�‘现在è¿�行完 `finishBeanFactoryInitialization(beanFactory);`,`singletonObjects` ä¸ç»ˆäºŽå‡ºçŽ°äº†æˆ‘ä»¬æœŸå¾…çš„å¯¹è±¡ï¼š
+
+
+
+ç”±æ¤å�¯è§�,对象就是在该方法ä¸åˆ›å»ºçš„。
+
+### 总结
+
+1. spring 包的�述:`AnnotationConfigApplicationContext#scan`
+2. spring bean 的创建:`AbstractApplicationContext#finishBeanFactoryInitialization`
+
+本文主è¦�是了解 spring å�¯åЍæµ�程,从整体上把æ�¡ spring å�¯åŠ¨è¿‡ç¨‹ä¸çš„ beanFactory çš„å�˜åŒ–。本文æ„�在了解 spring 的整体å�¯åЍæµ�程,å�Žç»çš„分æž�ä¸ï¼Œæˆ‘们将对这些æµ�程进行展开分æž�。
+
+* * *
+
+_本文原文链接:[https://my.oschina.net/funcy/blog/4597493](https://my.oschina.net/funcy/blog/4597493) ,é™�于作者个人水平,文ä¸éš¾å…�有错误之处,欢迎指æ£ï¼�原创ä¸�易,商业转载请è�”系作者获得授æ�ƒï¼Œé�žå•†ä¸šè½¬è½½è¯·æ³¨æ˜Žå‡ºå¤„。_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\203\357\274\211\357\274\232\345\233\275\351\231\205\345\214\226\344\270\216\344\272\213\344\273\266\345\244\204\347\220\206.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\203\357\274\211\357\274\232\345\233\275\351\231\205\345\214\226\344\270\216\344\272\213\344\273\266\345\244\204\347\220\206.md"
new file mode 100644
index 0000000..4f97b54
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\203\357\274\211\357\274\232\345\233\275\351\231\205\345\214\226\344\270\216\344\272\213\344\273\266\345\244\204\347\220\206.md"
@@ -0,0 +1,166 @@
+
+
+½ÓÉÏÎÄ£¬ÎÒÃǼÌÐø·ÖÎö spring µÄÆô¶¯Á÷³Ì¡£
+
+### 7\. ¹ú¼Ê»¯: `initMessageSource()`
+
+Õâ¸ö·½·¨ÊÇÓÃÀ´³õʼ»¯ `MessageSource` µÄ£¬ÄÚÈÝÈçÏ£º
+
+```
+public abstract class AbstractApplicationContext extends DefaultResourceLoader
+ implements ConfigurableApplicationContext {
+
+ ...
+
+ /**
+ * ³õʼ»¯ MessageSource
+ */
+ protected void initMessageSource() {
+ ConfigurableListableBeanFactory beanFactory = getBeanFactory();
+ // Èç¹ûbeanFactoryÖдæÔÚMessageSource£¬ÉèÖÃÆä ParentMessageSource
+ if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
+ this.messageSource = beanFactory.getBean(
+ MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
+ if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
+ HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
+ if (hms.getParentMessageSource() == null) {
+ // ÉèÖÃParentMessageSource
+ hms.setParentMessageSource(getInternalParentMessageSource());
+ }
+ }
+ }
+ // Èç¹ûbeanFactoryÖв»´æÔÚMessageSource£¬¾Í ´´½¨-ÉèÖÃ-×¢²á
+ else {
+ DelegatingMessageSource dms = new DelegatingMessageSource();
+ dms.setParentMessageSource(getInternalParentMessageSource());
+ this.messageSource = dms;
+ // ÉèÖÃParentMessageSource
+ beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
+ }
+ }
+
+ /**
+ * ·µ»Ø¸¸ÈÝÆ÷µÄ messageSource
+ */
+ @Nullable
+ protected MessageSource getInternalParentMessageSource() {
+ return (getParent() instanceof AbstractApplicationContext ?
+ ((AbstractApplicationContext) getParent()).messageSource : getParent());
+ }
+
+ ...
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬Õû¸ö·½·¨Ö÷ÒªÊDzÙ×÷ `MessageSource`£¬Ö÷ÒªÂ߼Ϊ£ºÈç¹ûÒѾ´æÔÚ `MessageSource` ÁË£¬¾ÍÉèÖÃһЩÊôÐÔ£»·ñÔò¾Í´´½¨ `MessageSource`£¬²¢ÉèÖÃЩ ÊôÐÔ£¬×îºó×¢²áµ½ `beanFactory` ÖС£
+
+¹ØÓÚ `MessageSource` µÄ¾ßÌå×÷Ó㬱¾ÎľͲ»Õ¹¿ªÁË¡£
+
+### 8\. ³õʼ»¯Ê¼þ¹ã²¥Æ÷£º`initApplicationEventMulticaster()`
+
+`AbstractApplicationContext#initApplicationEventMulticaster` ´úÂëÈçÏ£º
+
+```
+protected void initApplicationEventMulticaster() {
+ ConfigurableListableBeanFactory beanFactory = getBeanFactory();
+ // Èç¹ûÓû§ÅäÖÃÁË×Ô¶¨Òåʼþ¹ã²¥Æ÷£¬¾ÍʹÓÃÓû§µÄ
+ if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
+ this.applicationEventMulticaster =
+ beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
+ ApplicationEventMulticaster.class);
+ }
+ else {
+ // Óû§Ã»ÓÐÅäÖù㲥Æ÷£¬¾ÍʹÓÃĬÈϵÄʼþ¹ã²¥Æ÷
+ this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
+ beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
+ this.applicationEventMulticaster);
+ }
+}
+
+```
+
+Õâ¿éÂß¼Ò²ºÜ¼òµ¥£¬Èç¹ûÒÑ´æÔÚʼþ¹ã²¥Æ÷£¬¾ÍʹÓÃÒÑ´æÔڵ쬷ñÔò¾Í´´½¨Ò»¸ö¡£¹ØÓÚ `ApplicationEventMulticaster`£¬Ö÷Òª¾ÍÊÇÓÃÀ´¹ã²¥Ê¼þµÄ£¬¸ü¶à¹ØÓÚʼþµÄÄÚÈÝ£¬¿ÉÒԲο¼ [spring Ì½ÃØÖ® spring ʼþ»úÖÆ](https://my.oschina.net/funcy/blog/4713339).
+
+### 9\. À©Õ¹µã£ºonRefresh ()
+
+`AbstractApplicationContext#onRefresh` ÊÇ spring ÌṩµÄÒ»¸öÀ©Õ¹µã£¬·½·¨²¢ÎÞÄÚÈÝ£º
+
+```
+protected void onRefresh() throws BeansException {
+
+}
+
+```
+
+Èç¹ûÐèÒª´¦ÀíÌØ¶¨µÄ²Ù×÷£¬¿ÉÒÔÔÚ×ÓÀàÖÐʵÏÖ¡£
+
+µ±Ç°Ê¹ÓÃµÄ `ApplicationContext` ÊÇ `AnnotationConfigApplicationContext`£¬²¢ÎÞ `onRefresh()` ·½·¨£¬¾Í²»¹ý¶à·ÖÎöÁË¡£
+
+### 10\. ×¢²áʼþ¼àÌýÆ÷£ºregisterListeners ()
+
+`AbstractApplicationContext#registerListeners` Ïà¹Ø´úÂëÈçÏ£º
+
+> AbstractApplicationContext
+
+```
+/** ÕâÀï¾ÍÊÇÓÃÀ´´æ·Å¼àÌýÆ÷µÄ */
+private final Set> applicationListeners = new LinkedHashSet<>();
+
+/** ·µ»Øµ±Ç°ËùÓеļàÌýÆ÷ */
+public Collection> getApplicationListeners() {
+ return this.applicationListeners;
+}
+
+/**
+ * Ìí¼Ó¼àÌýÆ÷
+ */
+public void addApplicationListener(ApplicationListener> listener) {
+ Assert.notNull(listener, "ApplicationListener must not be null");
+ if (this.applicationEventMulticaster != null) {
+ this.applicationEventMulticaster.addApplicationListener(listener);
+ }
+ this.applicationListeners.add(listener);
+}
+
+/**
+ * ×¢²á¼àÌýÆ÷
+ */
+protected void registerListeners() {
+ // ÏÈÌí¼ÓÊÖ¶¯setµÄһЩ¼àÌýÆ÷
+ // getApplicationListeners() »ñÈ¡µÄ¼àÌýÆ÷»ù±¾ÊÇͨ¹ýµ÷Óà addApplicationListener(...) Ìí¼ÓµÄ
+ for (ApplicationListener> listener : getApplicationListeners()) {
+ getApplicationEventMulticaster().addApplicationListener(listener);
+ }
+ // »ñȡȡµ½¼àÌýÆ÷µÄÃû³Æ£¬ÉèÖõ½¹ã²¥Æ÷
+ // ´Ëʱ»ñÈ¡µÄ¼àÌýÆ÷ÊÇ´Ó beanFactory ÖлñÈ¡µÄ£¬¼´ÊÇspringͨ¹ý°üɨÃèµÃµ½µÄ
+ String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
+ for (String listenerBeanName : listenerBeanNames) {
+ getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
+ }
+ // Èç¹û´æÔÚÔçÆÚÓ¦ÓÃʼþ£¬¹ã²¥
+ Set earlyEventsToProcess = this.earlyApplicationEvents;
+ this.earlyApplicationEvents = null;
+ if (earlyEventsToProcess != null) {
+ for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
+ // ¹ã²¥ÔçÆÚʼþ
+ getApplicationEventMulticaster().multicastEvent(earlyEvent);
+ }
+ }
+}
+
+```
+
+Õâ¸ö·½·¨µÄÁ÷³Ì´óÖÂÈçÏ£º
+
+1. Ìí¼Ó `AbstractApplicationContext#applicationListeners` ÖеļàÌýÆ÷µ½ `ApplicationEventMulticaster` ÖÐ
+2. ´Ó `beanFactory` »ñÈ¡¼àÌýÆ÷µÄ `beanName`£¬Ìí¼Óµ½ `ApplicationEventMulticaster` ÖÐ
+3. Èç¹ûÓÐÔçÆÚʼþ£¬¾Í½øÐй㲥
+
+¹ØÓÚ spring µÄʼþ£¬±¾ÎIJ¢²»´òËãÕ¹¿ª£¬Èç¹ûÏëÁ˽â¸ü¶à£¬¿É²Î¿¼ [spring Ì½ÃØÖ® spring ʼþ»úÖÆ](https://my.oschina.net/funcy/blog/4713339).
+
+±¾ÎĵķÖÎö¾Íµ½ÕâÀïÁË¡£
+
+* * *
+
+_±¾ÎÄÔÎÄÁ´½Ó£º[https://my.oschina.net/funcy/blog/4892120](https://my.oschina.net/funcy/blog/4892120) £¬ÏÞÓÚ×÷Õ߸öÈËˮƽ£¬ÎÄÖÐÄÑÃâÓдíÎóÖ®´¦£¬»¶ÓÖ¸Õý£¡Ô´´²»Ò×£¬ÉÌÒµ×ªÔØÇëÁªÏµ×÷Õß»ñµÃÊÚȨ£¬·ÇÉÌÒµ×ªÔØÇë×¢Ã÷³ö´¦¡£_
\ No newline at end of file
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\211\357\274\211\357\274\232\345\214\205\347\232\204\346\211\253\346\217\217\346\265\201\347\250\213.md" "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\211\357\274\211\357\274\232\345\214\205\347\232\204\346\211\253\346\217\217\346\265\201\347\250\213.md"
new file mode 100644
index 0000000..f7c7a4d
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring\346\272\220\347\240\201\345\210\206\346\236\220/Spring\345\220\257\345\212\250\346\265\201\347\250\213/spring \345\220\257\345\212\250\346\265\201\347\250\213\357\274\210\344\270\211\357\274\211\357\274\232\345\214\205\347\232\204\346\211\253\346\217\217\346\265\201\347\250\213.md"
@@ -0,0 +1,800 @@
+
+
+ÔÚ [applicationContext µÄ´´½¨](https://my.oschina.net/funcy/blog/4608767)ÖУ¬ÎÒÃÇ·ÖÎöÁË `applicationContext` µÄ´´½¨¹ý³Ì£¬ÔÚ±¾ÎÄÖУ¬ÎÒÃǽ«·ÖÎö spring ÊÇÈçºÎ½øÐаüɨÃèµÄ¡£
+
+ÒÀ¾ÉÊÇ `AnnotationConfigApplicationContext` µÄ¹¹Ôì·½·¨£º
+
+```
+public AnnotationConfigApplicationContext(String... basePackages) {
+ this();
+ //¶Ô´«ÈëµÄ°ü½øÐÐɨÃ裬ɨÃèÍê³Éºó£¬»áµÃµ½Ò»¸ö BeanDefinition µÄ¼¯ºÏ
+ scan(basePackages);
+ refresh();
+}
+
+```
+
+Õâ´ÎÎÒÃǽ«Ä¿¹â·ÅÔÚ `scan(basePackages);` ÉÏ£¬½øÈë¸Ã·½·¨£º
+
+> AnnotationConfigApplicationContext#scan
+
+```
+public void scan(String... basePackages) {
+ Assert.notEmpty(basePackages, "At least one base package must be specified");
+ // ÕâÀïµÄscanner¶ÔÏó¾ÍÊÇÔÚthis()Öд´½¨µÄ
+ this.scanner.scan(basePackages);
+}
+
+```
+
+Õâ¸ö·½·¨¹Ø¼ü´úÂëÊÇ `this.scanner.scan(basePackages);`£¬Õâ¸ö `scanner` ¾ÍÊÇÔÚ `this()` Öд´½¨µÄ¶ÔÏó£º
+
+```
+public AnnotationConfigApplicationContext() {
+ this.reader = new AnnotatedBeanDefinitionReader(this);
+ // scanner ¾ÍÊÇÔÚÕâÀï´´½¨µÄ
+ this.scanner = new ClassPathBeanDefinitionScanner(this);
+}
+
+```
+
+¼ÌÐø×·×Ù£¬ÕâÀïÎÒÃǶԲ»ÖØÒªµÄ·½·¨½ö¸ø³öµ÷ÓÃÁ´£¬ÖØµã¹Ø×¢É¨Ãè°üµÄ¹ý³Ì£º
+
+```
+AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)
+ |-AnnotationConfigApplicationContext#scan
+ |-ClassPathBeanDefinitionScanner#scan
+ |-ClassPathBeanDefinitionScanner#doScan
+
+```
+
+`ClassPathBeanDefinitionScanner#doScan` ´úÂëÈçÏ£º
+
+```
+protected Set doScan(String... basePackages) {
+ Assert.notEmpty(basePackages, "At least one base package must be specified");
+ Set beanDefinitions = new LinkedHashSet<>();
+ //±éÀúÐèҪɨÃèµÄ°ü·¾¶
+ for (String basePackage : basePackages) {
+ //»ñÈ¡ËùÓзûºÏÌõ¼þµÄBeanDefinition
+ Set candidates = findCandidateComponents(basePackage);
+ for (BeanDefinition candidate : candidates) {
+ //°ó¶¨BeanDefinitionÓëScope
+ ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
+ candidate.setScope(scopeMetadata.getScopeName());
+ //²é¿´ÊÇ·ñÅäÖÃÀàÊÇ·ñÖ¸¶¨beanµÄÃû³Æ£¬Èçûָ¶¨ÔòʹÓÃÀàÃûÊ××ÖĸСд
+ String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
+ //ÏÂÃæÁ½¸öifÊÇ´¦Àílazy¡¢Autowire¡¢DependencyOn¡¢initMethod¡¢enforceInitMethod¡¢destroyMethod¡¢
+ // enforceDestroyMethod¡¢Primary¡¢Role¡¢DescriptionÕâЩÂß¼µÄ
+ if (candidate instanceof AbstractBeanDefinition) {
+ postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
+ }
+ if (candidate instanceof AnnotatedBeanDefinition) {
+ AnnotationConfigUtils.processCommonDefinitionAnnotations(
+ (AnnotatedBeanDefinition) candidate);
+ }
+ //¼ì²ébeanÊÇ·ñ´æÔÚ
+ if (checkCandidate(beanName, candidate)) {
+ //ÓÖ°ü×°ÁËÒ»²ã
+ BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
+ //¼ì²éscopeÊÇ·ñ´´½¨£¬Èçδ´´½¨Ôò½øÐд´½¨
+ definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(
+ scopeMetadata, definitionHolder, this.registry);
+ beanDefinitions.add(definitionHolder);
+ //×¢²á beanDefinition
+ registerBeanDefinition(definitionHolder, this.registry);
+ }
+ }
+ }
+ return beanDefinitions;
+}
+
+```
+
+Õâ¶Î´úÂëÍê³ÉµÄ¹¦ÄܺÜÃ÷ÁË£¬´óÌåÉÏ×öÁËÒÔϼ¸¼þÊ£º
+
+1. ¸ù¾Ý°ü·¾¶£¬µÃµ½·ûºÏÌõ¼þµÄ BeanDefinition
+2. ±éÀú BeanDefinition£¬½øÒ»²½·á¸» beanDefinition ÐÅÏ¢
+3. ½« BeanDefinition Ìí¼Óµ½ beanFactory
+
+> BeanDefinition Ò²ÊÇ spring µÄÖØÒª×é¼þÖ®Ò»£¬¹ØÓÚ BeanDefinition µÄ·ÖÎö£¬¿É²Î¿¼ [spring ×é¼þÖ® BeanDefinition](https://my.oschina.net/funcy/blog/4597536 "spring×é¼þÖ®BeanDefinition")¡£
+
+½ÓÏÂÀ´ÎÒÃÇÖ÷Òª·ÖÎöÕâÈý¸öµÄ²Ù×÷¡£
+
+### 1\. ¸ù¾Ý°ü·¾¶µÃµ½ BeanDefinition
+
+ÕâÒ»²½Ö÷Òª·¢ÉúÔÚ `Set candidates = findCandidateComponents(basePackage);`£¬ÎÒÃǸú½øÈ¥¿´¿´´úÂëµÄÖ´ÐУ¬ÕâÀïÒÀ¾É¶Ô²»ÖØÒª´úÂë¸ø³öµ÷ÓÃÁ´£¬¸Ã·½·¨µÄµ÷ÓÃÈçÏ£º
+
+```
+AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)
+ |-AnnotationConfigApplicationContext#scan
+ |-ClassPathBeanDefinitionScanner#scan
+ |-ClassPathBeanDefinitionScanner#doScan
+ |-ClassPathScanningCandidateComponentProvider#findCandidateComponents
+ |-ClassPathScanningCandidateComponentProvider#scanCandidateComponents
+
+```
+
+×îÖÕµ÷Óõ½ÁË `ClassPathScanningCandidateComponentProvider#scanCandidateComponents`£¬´úÂëÈçÏ (ÓÐɾ¼õ)£º
+
+```
+private Set scanCandidateComponents(String basePackage) {
+ Set candidates = new LinkedHashSet<>();
+ //×éװɨÃè·¾¶£¨×é×°Íê³ÉºóÊÇÕâÖÖ¸ñʽ£ºclasspath*:org/springframework/learn/demo01/**/*.class£©
+ String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
+ resolveBasePackage(basePackage) + '/' + this.resourcePattern;
+ //¸ù¾Ý·¾¶»ñÈ¡×ÊÔ´¶ÔÏ󣬼´É¨Ãè³ö¸Ã·¾¶ÏµĵÄËùÓÐclassÎļþ£¬µÃµ½ Resource
+ Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
+ for (Resource resource : resources) {
+ if (resource.isReadable()) {
+ //¸ù¾Ý×ÊÔ´¶ÔÏó»ñÈ¡×ÊÔ´¶ÔÏóµÄMetadataReader
+ MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
+ // ÕâÀï×öÁËÁ½¼þÊ£º
+ // 1\. ÊÇ·ñÐèÒª³õʼ»¯Îªspring bean£¬¼´ÊÇ·ñÓÐ @Component¡¢@ServiceµÈ×¢½â
+ // 2\. ²é¿´ÅäÖÃÀàÊÇ·ñÓÐ@ConditionalһϵÁеÄ×¢½â£¬È»ºóÊÇ·ñÂú×ã×¢²áBeanµÄÌõ¼þ
+ if (isCandidateComponent(metadataReader)) {
+ ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
+ sbd.setResource(resource);
+ sbd.setSource(resource);
+ if (isCandidateComponent(sbd)) {
+ candidates.add(sbd);
+ }
+ }
+ }
+ }
+ return candidates;
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬ÒÔÉÏ´úÂë×öÁËÈý¼þÊ£º
+
+1. ¸ù¾Ý´«ÈëµÄ basePackage µÃµ½É¨Ãè·¾¶
+2. ¸ù¾ÝɨÃè·¾¶µÃµ½¸Ã·¾¶ÏµÄËùÓÐ class Îļþ¶ÔÓ¦µÄ Resource
+3. ½« Resource ת»¯Îª beanDefinition
+
+½ÓÏÂÀ´ÎÒÃǾÍÒÔÉÏ´úÂë½øÐзÖÎö¡£
+
+#### 1.1 ¸ù¾Ý basePackage µÃµ½°üɨÃè·¾¶
+
+ÕâÒ»²½Ã»É¶ºÃ·ÖÎö£¬¾ÍÊÇÒ»¸ö×Ö·û´®µÄÆ´½ÓÓëÌæ»»£¬½«´«ÈëµÄ `org.springframework.learn.demo01` ת»»Îª `classpath*:org/springframework/learn/demo01/**/*.class`£¬Ïà¹Ø´úÂë¾ÍÒ»ÐУº
+
+```
+String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
+ resolveBasePackage(basePackage) + '/' + this.resourcePattern;
+
+```
+
+#### 1.2 ɨÃè°ü·¾¶
+
+µÃµ½°üɨÃè·¾¶ºó£¬½ÓÏÂÀ´¾ÍÊǽøÐÐɨÃèÁË¡£spring ÔÚɨÃèʱ£¬»á°ÑɨÃè·¾¶ÏµÄËùÓÐ class ÎļþɨÃè³öÀ´£¬È»ºó·â×°³É `Resource`£¬´úÂëÈçÏÂ
+
+```
+Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
+
+```
+
+¸ú½ø´úÂ룬ͬÑùµØ£¬ÎÒÃǶԲ»ÖØÒªµÄ·½·¨£¬ÒÀ¾ÉÖ»¸ø³ö·½·¨µ÷Óãº
+
+```
+AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)
+ |-AnnotationConfigApplicationContext#scan
+ |-ClassPathBeanDefinitionScanner#scan
+ |-ClassPathBeanDefinitionScanner#doScan
+ |-ClassPathScanningCandidateComponentProvider#findCandidateComponents
+ |-ClassPathScanningCandidateComponentProvider#scanCandidateComponents
+ |- GenericApplicationContext#getResources
+ |-AbstractApplicationContext#getResources
+ |-PathMatchingResourcePatternResolver#getResources
+ |-PathMatchingResourcePatternResolver#findPathMatchingResources
+
+```
+
+ÎÒÃǽ«´úÂë¾Û¼¯ÓÚ `PathMatchingResourcePatternResolver#findPathMatchingResources`:
+
+```
+protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
+ // ´«ÈëµÄ locationPattern ÊÇ classpath*:org/springframework/learn/demo01/**/*.class
+ // rootDirPath ÊÇ classpath*:org/springframework/learn/demo01/
+ String rootDirPath = determineRootDir(locationPattern);
+
+ // subPattern ÊÇ **/*.class
+ String subPattern = locationPattern.substring(rootDirPath.length());
+
+ // ÕâÀï·µ»ØµÄ Resource ÊÇ rootDirPath µÄ¾ø¶Ô·¾¶(ÓÃurl±íʾ)
+ // URL [file:/xxx/spring-learn/build/classes/java/main/org/springframework/learn/demo01/]
+ Resource[] rootDirResources = getResources(rootDirPath);
+
+ Set result = new LinkedHashSet<>(16);
+ for (Resource rootDirResource : rootDirResources) {
+ rootDirResource = resolveRootDirResource(rootDirResource);
+ URL rootDirUrl = rootDirResource.getURL();
+ if (equinoxResolveMethod != null && rootDirUrl.getProtocol().startsWith("bundle")) {
+ URL resolvedUrl = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirUrl);
+ if (resolvedUrl != null) {
+ rootDirUrl = resolvedUrl;
+ }
+ rootDirResource = new UrlResource(rootDirUrl);
+ }
+ // ´¦Àí vfs ×ÊÔ´²éÕÒ
+ if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
+ result.addAll(VfsResourceMatchingDelegate
+ .findMatchingResources(rootDirUrl, subPattern, getPathMatcher()));
+ }
+ // ´¦Àíjar°üÎļþ²éÕÒ
+ else if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) {
+ result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern));
+ }
+ // ´¦ÀíÎļþ·¾¶ÏµÄÎļþ²éÕÒ
+ else {
+ result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
+ }
+ }
+ return result.toArray(new Resource[0]);
+}
+
+```
+
+ͨ¹ý·ÖÎö£¬·¢ÏÖ¸ÃÀàµÄ´¦Àí¹ý³ÌÈçÏ£º
+
+1. ͨ¹ý´«ÈëµÄ locationPattern µÃµ½¸Ã pattern Ï嵀 url ¾ø¶Ô·¾¶£¬·âװΪ Resource
+2. ±éÀú·µ»ØµÄ·¾¶£¬²éÕÒ class Îļþ£¬·âװΪ Resource
+
+ÎÒÃÇÀ´¿´¿´ spring ÊÇÈçºÎ½« pattrn ת»»Îª url ·¾¶µÄ£¬ÎÒÃǸú½ø´úÂ룺
+
+```
+|-PathMatchingResourcePatternResolver#getResources
+ |-PathMatchingResourcePatternResolver#findAllClassPathResources
+ |-PathMatchingResourcePatternResolver#doFindAllClassPathResources
+
+```
+
+×îÖÕ´úÂëµ½ÁË `PathMatchingResourcePatternResolver#doFindAllClassPathResources`:
+
+```
+protected Set doFindAllClassPathResources(String path) throws IOException {
+ Set result = new LinkedHashSet<>(16);
+ ClassLoader cl = getClassLoader();
+ // path¶ÔÓ¦µÄurl
+ Enumeration resourceUrls = (cl != null ? cl.getResources(path) :
+ ClassLoader.getSystemResources(path));
+ while (resourceUrls.hasMoreElements()) {
+ URL url = resourceUrls.nextElement();
+ // ½«urlת»»ÎªResource£¬²¢Ìí¼Óµ½½á¹ûÖÐ
+ result.add(convertClassLoaderURL(url));
+ }
+ if ("".equals(path)) {
+ addAllClassLoaderJarRoots(cl, result);
+ }
+ return result;
+}
+
+// ½«urlת»»ÎªResource
+protected Resource convertClassLoaderURL(URL url) {
+ return new UrlResource(url);
+}
+
+```
+
+´Ëʱ´«ÈëµÄ `path` Ϊ `org/springframework/learn/demo01/`£¬´Ó´úÂë¿ÉÖª£¬×îÖÕµ÷ÓÃÁË java µÄ `ClassLoader` ·½·¨À´»ñÈ¡ path ¶ÔÓ¦µÄ url£¬È»ºó½« url ת»»Îª `Resource` Ìí¼Óµ½½á¹û¼¯Öв¢·µ»Ø¡£
+
+Äõ½ÀàµÄ¾ø¶Ô·¾¶Ö®ºó£¬½ÓϾÍÊǶÔ·¾¶½øÐбéÀú£¬Äõ½ class ÎļþÁË¡£ÈÃÎÒÃÇÔٻص½ `PathMatchingResourcePatternResolver#findPathMatchingResources`£¬spring ɨÃèʱ£¬»á¸ù¾Ý´«ÈëµÄ url ÀàÐÍ£¬¹²É¨Ãè 3 ¸öµØ·½£º
+
+1. vfs
+2. jar °ü
+3. Îļþ·¾¶
+
+`vfs` ×¢ÊÍÉÏ˵ÊÇ "URL protocol for a general JBoss VFS resource"£¬¼´Í¨Óà JBoss VFS ×ÊÔ´µÄ URL ÐÒ飬ÕâÀï²»É¡£Èç¹ûÏîÄ¿ÖÐÒýÈëÁË jar °üÇÒÐèҪɨÃè jar ÖеÄ·¾¶£¬¾Í»áʹÓà jar °üɨÃ跽ʽ½øÐÐ class Îļþ²éÕÒ£¬ÓÉÓÚµ÷ÊÔʱ£¬`demo01` ÊÇʹÓÃÎļþ·½Ê½É¨ÃèµÄ£¬ÕâÀï¾ÍÖØµã·ÖÎöÎļþɨÃ跽ʽ£¬ÖÁÓÚ jar ÊÇÈçºÎɨÃèµÄ£¬ÓÐÐËȤµÄС»ï°é¿É×ÔÐÐÑо¿Ï¡£
+
+ÎÒÃǸú½ø `findPathMatchingResources` ·½·¨£º
+
+```
+|-PathMatchingResourcePatternResolver#findPathMatchingResources
+ |-PathMatchingResourcePatternResolver#doFindPathMatchingFileResources
+ |-PathMatchingResourcePatternResolver#doFindMatchingFileSystemResources
+
+```
+
+```
+protected Set doFindMatchingFileSystemResources(File rootDir,
+ String subPattern) throws IOException {
+ // ÕâÀï½øÐÐÎļþ²éÕÒ
+ Set matchingFiles = retrieveMatchingFiles(rootDir, subPattern);
+ Set result = new LinkedHashSet<>(matchingFiles.size());
+ for (File file : matchingFiles) {
+ result.add(new FileSystemResource(file));
+ }
+ return result;
+}
+
+```
+
+ÔÚ `PathMatchingResourcePatternResolver#doFindMatchingFileSystemResources` ÖУ¬spring ½«É¨Ãèµ½µÄ File ת»»Îª `FileSystemResource` ±£´æ£¬ÕâÊÇÎÒÃÇÓöµ½µÄµÚ¶þ¸ö `Resource` ÀàÐÍÁË (Ç°ÃæÎª `UrlResource`£¬ÕâÀïΪ `FileSystemResource`).
+
+½ÓÏÂÎÒÃÇÖØµã¹Ø×¢ `Set matchingFiles = retrieveMatchingFiles(rootDir, subPattern);`£¬¿´¿´ spring ÊÇÈçºÎÍê³ÉÎļþ²éÕҵģº
+
+```
+|-PathMatchingResourcePatternResolver#findPathMatchingResources
+ |-PathMatchingResourcePatternResolver#doFindPathMatchingFileResources
+ |-PathMatchingResourcePatternResolver#doFindMatchingFileSystemResources
+ |-PathMatchingResourcePatternResolver#retrieveMatchingFiles
+ |-PathMatchingResourcePatternResolver#doRetrieveMatchingFiles
+
+```
+
+```
+protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set result)
+ throws IOException {
+ for (File content : listDirectory(dir)) {
+ String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/");
+ if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) {
+ if (!content.canRead()) {
+ }
+ else {
+ // Èç¹ûÊÇÎļþ¼Ð£¬µÝ¹éµ÷ÓÃ
+ doRetrieveMatchingFiles(fullPattern, content, result);
+ }
+ }
+ // Èç¹ûÊÇÎļþÇÒÎļþ·¾¶
+ if (getPathMatcher().match(fullPattern, currPath)) {
+ result.add(content);
+ }
+ }
+}
+
+```
+
+ÒÔÉÏ´úÂë±È½Ï¼òµ¥£¬ÓëÎÒÃÇÆ½³£±éÀúÎļþµÄ·½Ê½ÊÇÒ»ÑùµÄ¡£
+
+ÖµµÃÒ»ÌáµÄÊÇ£¬`getPathMatcher().match(fullPattern, currPath)` ×îÖÕµ÷Óõ½µÄÊÇ `AntPathMatcher#doMatch`£¬ÕâÊÇÒ»¸ö ant ·ç¸ñµÄ·¾¶Æ¥ÅäÑéÖ¤£¬¼´Â·¾¶ÖдøÓÐ `*`£¬Èç´«ÈëµÄ pattern ÊÇ `/xxx/spring-framework/spring-learn/build/classes/java/main/org/springframework/learn/demo01/**/*.class`£¬±íʾƥÅä `/xxx/spring-framework/spring-learn/build/classes/java/main/org/springframework/learn/demo01/` ¼°Æä×ÓÎļþ¼ÐÏÂËùÓÐÒÔ`.class` Îļþ½áβµÄÎļþ£¬µ±Ç°´«ÈëµÄ path ÊÇ `/xxx/spring-framework/spring-learn/build/classes/java/main/org/springframework/learn/demo01/BeanObj2.class`£¬ÏÔȻƥÅä¡£¹ØÓÚ `AntPathMatcher#doMatch` ·½·¨ÊÇÈçºÎ½øÐÐÆ¥ÅäµÄ£¬ÕâÀï¾Í²»½øÐÐÕ¹¿ªÁË¡£
+
+¾¹ýÁËÒÔÉϲ½Ö裬ÎÒÃÇÖÕÓڵõ½ÁË class Îļþ¶ÔÓ¦µÄ Resource ÁË.
+
+#### 1.3 ½« Resource ת»¯Îª BeanDefinition
+
+½« Resource ת»¯Îª BeanDefinition£¬´úÂëÊÇ
+
+> ClassPathScanningCandidateComponentProvider#scanCandidateComponents
+
+```
+// ´Ó resource µÃµ½ MetadataReader
+MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
+
+// ÕâÀï×öÁËÁ½¼þÊ£º
+// 1\. ÊÇ·ñÐèÒª³õʼ»¯Îªspring bean£¬¼´ÊÇ·ñÓÐ @Component¡¢@ServiceµÈ×¢½â
+// 2\. ²é¿´ÅäÖÃÀàÊÇ·ñÓÐ@ConditionalһϵÁеÄ×¢½â£¬È»ºóÊÇ·ñÂú×ã×¢²áBeanµÄÌõ¼þ
+if (isCandidateComponent(metadataReader)) {
+ // ½« metadataReader ת»»Îª ScannedGenericBeanDefinition£¬ÕâÒ²ÊÇBeanDefinition¼Ò×åÖеÄÒ»Ô±
+ ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
+ ...
+}
+
+```
+
+##### 1\. ´Ó Resource µÃµ½ MetadataReader
+
+ÎÒÃÇ×·×ÙÏ `MetadataReader` µÄ»ñÈ¡£º
+
+```
+|-ClassPathScanningCandidateComponentProvider#scanCandidateComponents
+ |-CachingMetadataReaderFactory#getMetadataReader
+ |-SimpleMetadataReaderFactory#getMetadataReader(Resource)
+ |-SimpleMetadataReader#SimpleMetadataReader
+
+```
+
+´úÂë×îÖÕÔËÐе½ÁË `SimpleMetadataReader` µÄ¹¹Ôì·½·¨:
+
+```
+SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
+ SimpleAnnotationMetadataReadingVisitor visitor
+ = new SimpleAnnotationMetadataReadingVisitor(classLoader);
+ // ÕâÀï·¢ÉúÁËclassÎļþµÄ¶ÁÈ¡Óë½âÎö
+ getClassReader(resource).accept(visitor, PARSING_OPTIONS);
+ this.resource = resource;
+ this.annotationMetadata = visitor.getMetadata();
+}
+
+```
+
+ÔÙ½øÒ»²½×·×Ù£¬·¢ÏÖ class ÎļþµÄ¶ÁÈ¡Óë½âÎö·¢ÉúÔÚ `ClassReader` Àࣺ
+
+
+
+Õâ¸öÀàʹÓà asm À´¶ÁÈ¡ class Îļþ£¬´úÂë±È½Ï¸´ÔÓ£¬¾Í²»ÉÁË¡£
+
+Ò»Ö±ÒÔÀ´£¬ÎÒ¶¼ÒÔΪ spring ÊÇͨ¹ý·´ÉäÀ´»ñÈ¡ÀàÐÅÏ¢µÄ£¬µ½ÕâÀï²ÅÖªµÀ£¬**ÔÀ´ spring ÊÇͨ¹ý asm Ö±½Ó¶ÁÈ¡ class ÎļþÀ´»ñÈ¡ÀàµÄÐÅÏ¢µÄ** ¡£
+
+×îºóÎÒÃÇÀ´¿´Ïµõ½µÄ `MetadataReader` µÄ½á¹û£º
+
+
+
+ÕâÀïÖØµã¹Ø×¢ `annotations` ÊôÐÔ£¬ÀïÃæÓÐÒ»¸ö `annotations` ºÍ `mappings`£¬`annotations` ÄÚÈÝΪ `@Service`£¬`mappings` ÊÇÒ»¸öÊý×飬ÄÚÈÝΪ
+
+```
+0-@Service
+1-@Component
+2-@Index
+
+```
+
+
+
+
+
+
+
+`annotations` ±¾È˲²âÊÇ `BeanObj1` ÉϵÄ×¢½â£º
+
+
+
+ÖÁÓÚ `mappings` ÊÇɶ£¬ÎÒ²»ºÃ²Â²â£¬²»¹ýÒ²¿ÉÒÔ´Ó×¢½âÖз¢ÏÖһЩ¶ËÄߣº
+
+
+
+
+
+`@Service` ÉÏÓÐ `@Component` ×¢½â£¬`@Component` ÉÏÓÐ `@Indexed`£¬¶øÕâÈýÕß¶¼³öÏÖÔÚÁË `mappings` ÖУ¬Õâ¿´×ÅÏñÊÇרÃÅÓÃÀ´±£´æÄÃ×¢½âÖ®ÉϵÄ×¢½âµÄ£¿²»¾À½áÕâ¸öÁË£¬ÔÝÇҾ͵±×÷ÊÇÕ⹦Äܰɣ¡**×¢Ò⣺`mappings` ÀïÃæµÄÄÚÈݺÜÖØÒª£¬ºóÃæ»áÓÃÀ´£¡**
+
+##### 2. `isCandidateComponent(MetadataReader)`£ºÅжÏÊÇ·ñÐèҪʵÀý»¯Îª spring bean
+
+ÔÚÉÏÒ»²½ÖУ¬ÎÒÃǵõ½ÁË basePackage ÏÂ**ËùÓÐÀà**µÄ `MetadataReader` ÃèÊöÎļþ£¬×¢ÒâÕâÀïÊÇ**ËùÓÐÀà**£¬µ«ÕâЩÀàÊDz»ÊǶ¼Òª×ª³É `spring bean`£¬Íйܵ½ spring ÈÝÆ÷ÄØ£¿Õâ¾ÍÊÇ `isCandidateComponent(MetadataReader)` µÄ¹¦ÄÜÁË¡£·Ï»°ÉÙ˵£¬ÉÏ´úÂ룺
+
+```
+protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
+ // Ê¡ÂÔ²¿·Ö´úÂë
+ for (TypeFilter tf : this.includeFilters) {
+ // ÕâÀïÅжÏÊÇ·ñÐèÒªÍйܵ½springÈÝÆ÷
+ if (tf.match(metadataReader, getMetadataReaderFactory())) {
+ // ÅжÏÊÇ·ñÓÐ@ConditionalһϵÁеÄ×¢½â
+ return isConditionMatch(metadataReader);
+ }
+ }
+ return false;
+}
+
+```
+
+Õâ¶ÎÖ÷ÒªÊÇ×öÁËÁ½¸öÅжϣº
+
+* ÊÇ·ñÐèҪΪ spring bean
+* ÊÇ·ñÓÐ `@Conditional` µÈһϵÁеÄ×¢½â
+
+ÕâÀïÎÒÃÇÏÈÀ´¿´µÚÒ»¸öÅжϡ£
+
+ÔÚ spring ÖУ¬±êÃ÷ spring bean µÄ×¢½âÓкܶ࣬Ïñ `@Component`¡¢`@Repository`¡¢`@Service`¡¢`@Controller`¡¢`@Configuration`£¬ÉõÖÁÊÇÄã×Ô¼ºÐ´µÄ×¢½âÀֻ࣬ҪÉÏÃæ±êÁËÕâЩע½â£¬Ïñ
+
+```
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+// Ìí¼Ó @Component »ò @Service »ò @Repository µÈÆäÖÐÖ®Ò»
+@Component
+public @interface MySpringBean {
+ ...
+}
+
+```
+
+¶¼Äܱ» spring ʶ±ð¡£Èç¹ûÊÇ spring ÌṩµÄ×¢½â£¨`@Component`¡¢`@Repository` µÈ£©£¬ÔÚÅжÏÊDz»ÊÇ spring bean ʱ£¬Ö»ÐèÒª×öÀàËÆ
+
+```
+if(annotation == Component.class || annotation == Repository.class) {
+ ...
+}
+
+```
+
+µÄÅжϾÍÐÐÁË¡£µ«¶ÔÓÚ×Ô¶¨ÒåµÄ×¢½â `@MySpringBean`£¬spring ÊÇÔõô֪µÀÕâÊÇ spring bean ÄØ£¿ÔÚÎÒÃǶ¨Òå `@MySpringBean` ʱ£¬Ò»¶¨ÒªÔÚÀàÉÏÌí¼Ó `@Component` »ò `@Service` »ò `@Repository` µÈÆäÖÐÖ®Ò»²ÅÄܱ» spring ʶ±ð£¬ÕâÆäÖÐÓÐʲôÐþ»úÄØ£¿ÎÒÃǸú½ø´úÂë `AbstractTypeHierarchyTraversingFilter#match(MetadataReader, MetadataReaderFactory)`£¬ÕâÀïÎÒÃǶԲ»ÖØÒªµÄ´úÂëÒÀ¾ÉÖ»¸ø³öµ÷ÓÃÁ´£º
+
+```
+|-ClassPathScanningCandidateComponentProvider#isCandidateComponent(MetadataReader)
+ |-AbstractTypeHierarchyTraversingFilter#match(MetadataReader, MetadataReaderFactory)
+ |-AnnotationTypeFilter#matchSelf
+
+```
+
+´úÂë×îÖÕµ½ÁË `AnnotationTypeFilter#matchSelf`:
+
+```
+@Override
+protected boolean matchSelf(MetadataReader metadataReader) {
+ AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
+ // ÕâÀïµÄannotationType¾ÍÊÇ @Component
+ return metadata.hasAnnotation(this.annotationType.getName()) ||
+ (this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
+}
+
+```
+
+¹Ø¼ü¾ÍÔÚÕâÁË£º
+
+```
+metadata.hasAnnotation(this.annotationType.getName())
+Óë
+this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName())
+
+```
+
+ÎÒÃÇÏÈ¿´ `metadata.hasAnnotation(this.annotationType.getName())` µÄ±È½Ï£º
+
+```
+// AnnotationMetadata#hasAnnotation
+default boolean hasAnnotation(String annotationName) {
+ return getAnnotations().isDirectlyPresent(annotationName);
+}
+
+```
+
+ÕâÀïµÄ `getAnnotations()` µÃµ½µÄ½á¹ûÊÇ
+
+
+
+mappings ÀïµÄÄÚÈÝÊÇ
+
+```
+0-@Service
+1-@Component
+2-@Index
+
+```
+
+ÕâÆäʵ¾ÍÊÇÎÒÃÇÇ°ÃæµÃµ½µÄ `MetadataReader` ÀïµÄÄÚÈÝ£¡
+
+ÔÙ×·×ÙÏÂÈ¥£¬·¢ÏÖ `isDirectlyPresent` ¾ÍÊÇÅÐ¶Ï `annotations` Óë `mappings` ÀïÓÐûÓгöÏÖ `@Component`:
+
+```
+private boolean isPresent(Object requiredType, boolean directOnly) {
+ // ÅÐ¶Ï annotations ÀïÓÐûÓгöÏÖ @Component
+ for (MergedAnnotation> annotation : this.annotations) {
+ Class extends Annotation> type = annotation.getType();
+ if (type == requiredType || type.getName().equals(requiredType)) {
+ return true;
+ }
+ }
+ if (!directOnly) {
+ // ÅÐ¶Ï mappings ÀïÓÐûÓгöÏÖ @Component
+ for (AnnotationTypeMappings mappings : this.mappings) {
+ for (int i = 1; i < mappings.size(); i++) {
+ AnnotationTypeMapping mapping = mappings.get(i);
+ if (isMappingForType(mapping, requiredType)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+```
+
+½Ó×ÅÎÒÃÇÔÙÀ´¿´ `this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName())`£¬²é¿´µ÷Óãº
+
+```
+|-AnnotationTypeFilter#matchSelf
+ |-AnnotationMetadata#hasMetaAnnotation
+ |-MergedAnnotationsCollection#get(String, Predicate)
+ |-MergedAnnotationsCollection#get(String, Predicate, MergedAnnotationSelector)
+ |-MergedAnnotationsCollection#find
+
+```
+
+×îÖյIJéÕÒ·½·¨ÔÚ `MergedAnnotationsCollection#find`:
+
+```
+private MergedAnnotation find(Object requiredType,
+ @Nullable Predicate super MergedAnnotation > predicate,
+ @Nullable MergedAnnotationSelector selector) {
+
+ MergedAnnotation result = null;
+ for (int i = 0; i < this.annotations.length; i++) {
+ MergedAnnotation> root = this.annotations[i];
+ AnnotationTypeMappings mappings = this.mappings[i];
+ // mappings ±éÀú mappings
+ for (int mappingIndex = 0; mappingIndex < mappings.size(); mappingIndex++) {
+ AnnotationTypeMapping mapping = mappings.get(mappingIndex);
+ if (!isMappingForType(mapping, requiredType)) {
+ continue;
+ }
+ // µ½ÕâÀ¾ÍÊÇÕÒµ½ÁË @Component ×¢½â
+ MergedAnnotation candidate = (mappingIndex == 0
+ ? (MergedAnnotation ) root
+ : TypeMappedAnnotation.createIfPossible(mapping, root, IntrospectionFailureLogger.INFO));
+ if (candidate != null && (predicate == null || predicate.test(candidate))) {
+ if (selector.isBestCandidate(candidate)) {
+ return candidate;
+ }
+ result = (result != null ? selector.select(result, candidate) : candidate);
+ }
+ }
+ }
+ return result;
+}
+
+```
+
+¿ÉÒÔ¿´µ½£¬²éÕÒ·½Ê½¸úÉÏÃæµÄ `metadata.hasAnnotation(this.annotationType.getName())` ¸ß¶ÈÏàËÆ¡£
+
+ÒÔÉϾÍÊÇ spring ÓÃÀ´ÅжÏÊÇ·ñ°üº¬ `@Service`¡¢`@Component` µÈ×¢½âµÄÂß¼ÁË¡£
+
+ÔÚ `java` ÖУ¬×¢½âÊDz»Äܼ̳еģ¬Èç
+
+```
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Base {
+
+}
+
+@Target({ElementType.TYPE, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Child extends Base {
+
+}
+
+```
+
+ÒÔÉÏÓï·¨ÔÚ java Öв»±»ÔÊÐíµÄ£¬spring ¾ÍÊDzÉÓÃÕâ½âÎö`×¢½âµÄ×¢½â`µÄ·½Ê½£¬ÊµÏÖÁËÀàËÆÓڼ̳еŦÄÜ¡£
+
+½Ó×ÅÎÒÃÇÔÙÀ´¿´ `ClassPathScanningCandidateComponentProvider#isConditionMatch` ·½·¨¡£Êµ¼ÊÉÏ£¬Õâ¸ö·½·¨ÊÇÓÃÀ´ÅжÏÀàÊÇ·ñº¬ÓÐ `@Conditional` ×¢½âµÄ£¬Âú×ãÌõ¼þÔò»áʶ±ðΪ spring bean£¬´úÂë×îÖÕµ÷Óõ½ÁË `ConditionEvaluator#shouldSkip(AnnotatedTypeMetadata, ConfigurationCondition.ConfigurationPhase)`:
+
+```
+public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
+ // Ê¡ÂÔÁËһЩ´úÂë
+
+ // µÃµ½ condition ¶ÔÏó
+ List