diff --git a/ReadMe.md b/ReadMe.md
index dc53ae6..84572da 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -29,227 +29,333 @@
+ +# 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) + +## 集合类 + +* [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/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) + +## 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) + +## Java网络编程 + +* [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全家桶 + +## 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源码剖析:初探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) + +### AOP +* [AnnotationAwareAspectJAutoProxyCreator 分析(上)](docs/Spring全家桶/Spring源码分析/SpringAOP/AnnotationAwareAspectJAutoProxyCreator分析(上).md) +* [AnnotationAwareAspectJAutoProxyCreator 分析(下)](docs/Spring全家桶/Spring源码分析/SpringAOP/AnnotationAwareAspectJAutoProxyCreator分析(下).md) +* [AOP示例demo及@EnableAspectJAutoProxy](docs/Spring全家桶/Spring源码分析/SpringAOP/AOP示例demo及@EnableAspectJAutoProxy.md) +* [SpringAop(四):jdk 动态代理](docs/Spring全家桶/Spring源码分析/SpringAOP/SpringAop(四):jdk动态代理.md) +* [SpringAop(五):cglib 代理](docs/Spring全家桶/Spring源码分析/SpringAOP/SpringAop(五):cglib代理.md) +* [SpringAop(六):aop 总结](docs/Spring全家桶/Spring源码分析/SpringAOP/SpringAop(六):aop总结.md) + +### 事务 +* [spring 事务(一):认识事务组件](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(一):认识事务组件.md) +* [spring 事务(二):事务的执行流程](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(二):事务的执行流程.md) +* [spring 事务(三):事务的隔离级别与传播方式的处理](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(三):事务的隔离级别与传播方式的处理01.md) +* [spring 事务(四):事务的隔离级别与传播方式的处理](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(四):事务的隔离级别与传播方式的处理02.md) +* [spring 事务(五):事务的隔离级别与传播方式的处理](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(五):事务的隔离级别与传播方式的处理03.md) +* [spring 事务(六):事务的隔离级别与传播方式的处理](docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(六):事务的隔离级别与传播方式的处理04.md) + +### 启动流程 +* [spring启动流程(一):启动流程概览](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(一):启动流程概览.md) +* [spring启动流程(二):ApplicationContext 的创建](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(二):ApplicationContext的创建.md) +* [spring启动流程(三):包的扫描流程](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(三):包的扫描流程.md) +* [spring启动流程(四):启动前的准备工作](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(四):启动前的准备工作.md) +* [spring启动流程(五):执行 BeanFactoryPostProcessor](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(五):执行BeanFactoryPostProcessor.md) +* [spring启动流程(六):注册 BeanPostProcessor](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(六):注册BeanPostProcessor.md) +* [spring启动流程(七):国际化与事件处理](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(七):国际化与事件处理.md) +* [spring启动流程(八):完成 BeanFactory 的初始化](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(八):完成BeanFactory的初始化.md) +* [spring启动流程(九):单例 bean 的创建](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(九):单例bean的创建.md) +* [spring启动流程(十):启动完成的处理](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(十):启动完成的处理.md) +* [spring启动流程(十一):启动流程总结](docs/Spring全家桶/Spring源码分析/Spring启动流程/Spring启动流程(十一):启动流程总结.md) + +### 组件分析 +* [spring 组件之 ApplicationContext](docs/Spring全家桶/Spring源码分析/Spring组件分析/Spring组件之ApplicationContext.md) +* [spring 组件之 BeanDefinition](docs/Spring全家桶/Spring源码分析/Spring组件分析/Spring组件之BeanDefinition.md) +* [Spring 组件之 BeanFactory](docs/Spring全家桶/Spring源码分析/Spring组件分析/Spring组件之BeanFactory.md) +* [spring 组件之 BeanFactoryPostProcessor](docs/Spring全家桶/Spring源码分析/Spring组件分析/Spring组件之BeanFactoryPostProcessor.md) +* [spring 组件之 BeanPostProcessor](docs/Spring全家桶/Spring源码分析/Spring组件分析/Spring组件之BeanPostProcessor.md) + +### 重要机制探秘 + +* [ConfigurationClassPostProcessor(一):处理 @ComponentScan 注解](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/ConfigurationClassPostProcessor(一):处理@ComponentScan注解.md) +* [ConfigurationClassPostProcessor(三):处理 @Import 注解](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/ConfigurationClassPostProcessor(三):处理@Import注解.md) +* [ConfigurationClassPostProcessor(二):处理 @Bean 注解](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/ConfigurationClassPostProcessor(二):处理@Bean注解.md) +* [ConfigurationClassPostProcessor(四):处理 @Conditional 注解](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/ConfigurationClassPostProcessor(四):处理@Conditional注解.md) +* [Spring 探秘之 AOP 的执行顺序](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/Spring探秘之AOP的执行顺序.md) +* [Spring 探秘之 Spring 事件机制](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/Spring探秘之Spring事件机制.md) +* [spring 探秘之循环依赖的解决(一):理论基石](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/Spring探秘之循环依赖的解决(一):理论基石.md) +* [spring 探秘之循环依赖的解决(二):源码分析](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/Spring探秘之循环依赖的解决(二):源码分析.md) +* [spring 探秘之监听器注解 @EventListener](docs/Spring全家桶/Spring源码分析/Spring重要机制探秘/spring探秘之监听器注解@EventListener.md) +* [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) +* [DispatcherServlet 初始化流程 ](docs/Spring全家桶/SpringMVC源码分析/DispatcherServlet初始化流程.md) +* [RequestMapping 初始化流程 ](docs/Spring全家桶/SpringMVC源码分析/RequestMapping初始化流程.md) +* [Spring 容器启动 Tomcat ](docs/Spring全家桶/SpringMVC源码分析/Spring容器启动Tomcat.md) +* [SpringMVC demo 与@EnableWebMvc 注解 ](docs/Spring全家桶/SpringMVC源码分析/SpringMVC的Demo与@EnableWebMvc注解.md) +* [SpringMVC 整体源码结构总结 ](docs/Spring全家桶/SpringMVC源码分析/SpringMVC整体源码结构总结.md) +* [请求执行流程(一)之获取 Handler ](docs/Spring全家桶/SpringMVC源码分析/请求执行流程(一)之获取Handler.md) +* [请求执行流程(二)之执行 Handler 方法 ](docs/Spring全家桶/SpringMVC源码分析/请求执行流程(二)之执行Handler方法.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源码分析 +* [@SpringBootApplication 注解](docs/Spring全家桶/SpringBoot源码解析/@SpringBootApplication注解.md) +* [springboot web应用(一):servlet 组件的注册流程](docs/Spring全家桶/SpringBoot源码解析/SpringBootWeb应用(一):servlet组件的注册流程.md) +* [springboot web应用(二):WebMvc 装配过程](docs/Spring全家桶/SpringBoot源码解析/SpringBootWeb应用(二):WebMvc装配过程.md) + +* [SpringBoot 启动流程(一):准备 SpringApplication](docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(一):准备SpringApplication.md) +* [SpringBoot 启动流程(二):准备运行环境](docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(二):准备运行环境.md) +* [SpringBoot 启动流程(三):准备IOC容器](docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(三):准备IOC容器.md) +* [springboot 启动流程(四):启动IOC容器](docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(四):启动IOC容器.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 自动装配(三):自动装配顺序](docs/Spring全家桶/SpringBoot源码解析/SpringBoot自动装配(三):自动装配顺序.md) + +## SpringCloud +* [SpringCloud概述](docs/Spring全家桶/SpringCloud/SpringCloud概述.md) +* [Spring Cloud Config](docs/Spring全家桶/SpringCloud/SpringCloudConfig.md) +* [Spring Cloud Consul](docs/Spring全家桶/SpringCloud/SpringCloudConsul.md) +* [Spring Cloud Eureka](docs/Spring全家桶/SpringCloud/SpringCloudEureka.md) +* [Spring Cloud Gateway](docs/Spring全家桶/SpringCloud/SpringCloudGateway.md) +* [Spring Cloud Hystrix](docs/Spring全家桶/SpringCloud/SpringCloudHystrix.md) +* [Spring Cloud LoadBalancer](docs/Spring全家桶/SpringCloud/SpringCloudLoadBalancer.md) +* [Spring Cloud OpenFeign](docs/Spring全家桶/SpringCloud/SpringCloudOpenFeign.md) +* [Spring Cloud Ribbon](docs/Spring全家桶/SpringCloud/SpringCloudRibbon.md) +* [Spring Cloud Sleuth](docs/Spring全家桶/SpringCloud/SpringCloudSleuth.md) +* [Spring Cloud Zuul](docs/Spring全家桶/SpringCloud/SpringCloudZuul.md) + +## SpringCloud 源码分析 +* [Spring Cloud Config源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudConfig源码分析.md) +* [Spring Cloud Eureka源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudEureka源码分析.md) +* [Spring Cloud Gateway源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudGateway源码分析.md) +* [Spring Cloud Hystrix源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudHystrix源码分析.md) +* [Spring Cloud LoadBalancer源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudLoadBalancer源码分析.md) +* [Spring Cloud OpenFeign源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudOpenFeign源码分析.md) +* [Spring Cloud Ribbon源码分析](docs/Spring全家桶/SpringCloud源码分析/SpringCloudRibbon源码分析.md) + +## SpringCloud Alibaba +* [SpringCloud Alibaba概览](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibaba概览.md) +* [SpringCloud Alibaba nacos](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibabaNacos.md) +* [SpringCloud Alibaba RocketMQ](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibabaRocketMQ.md) +* [SpringCloud Alibaba sentinel](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibabaSentinel.md) +* [SpringCloud Alibaba skywalking](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibabaSkywalking.md) +* [SpringCloud Alibaba seata](docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibabaSeata.md) + +## SpringCloud Alibaba源码分析 +* [Spring Cloud Seata源码分析](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudSeata源码分析.md) +* [Spring Cloud Sentinel源码分析](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudSentinel源码分析.md) +* [SpringCloudAlibaba nacos源码分析:概览](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudAlibabaNacos源码分析:概览.md) +* [SpringCloudAlibaba nacos源码分析:服务发现](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudAlibabaNacos源码分析:服务发现.md) +* [SpringCloudAlibaba nacos源码分析:服务注册](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudAlibabaNacos源码分析:服务注册.md) +* [SpringCloudAlibaba nacos源码分析:配置中心](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudAlibabaNacos源码分析:配置中心.md) +* [Spring Cloud RocketMQ源码分析](docs/Spring全家桶/SpringCloudAlibaba源码分析/SpringCloudRocketMQ源码分析.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) + + +# 计算机基础 + +## 计算机网络 todo -### 操作系统 +## 操作系统 todo -#### Linux相关 +## Linux相关 todo -### 数据结构与算法 +## 数据结构与算法 todo -#### 数据结构 +## 数据结构 todo -#### 算法 +## 算法 todo -## 数据库 +# 数据库 todo -### MySQL +## MySQL * [Mysql原理与实践总结](docs/database/Mysql原理与实践总结.md) * [重新学习Mysql数据库:无废话MySQL入门](docs/database/重新学习MySQL数据库:无废话MySQL入门.md) * [重新学习Mysql数据库:『浅入浅出』MySQL和InnoDB](docs/database/重新学习MySQL数据库:『浅入浅出』MySQL和InnoDB.md) @@ -266,9 +372,9 @@ todo * [重新学习Mysql数据库:Mysql主从复制,读写分离,分表分库策略与实践](docs/database/重新学习MySQL数据库:Mysql主从复制,读写分离,分表分库策略与实践.md) -## 缓存 +# 缓存 -### Redis +## Redis * [Redis原理与实践总结](docs/cache/Redis原理与实践总结.md) * [探索Redis设计与实现开篇:什么是Redis](docs/cache/探索Redis设计与实现开篇:什么是Redis.md) * [探索Redis设计与实现:Redis的基础数据结构概览](docs/cache/探索Redis设计与实现:Redis的基础数据结构概览.md) @@ -287,27 +393,46 @@ todo * [探索Redis设计与实现:Redis事务浅析与ACID特性介绍](docs/cache/探索Redis设计与实现:Redis事务浅析与ACID特性介绍.md) * [探索Redis设计与实现:Redis分布式锁进化史 ](docs/cache/探索Redis设计与实现:Redis分布式锁进化史.md ) -## 消息队列 - -### 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) - -## 分布式 -### 理论 +# 消息队列 + +## Kafka +* [消息队列kafka详解:Kafka快速上手(Java版)](docs/mq/kafka/消息队列kafka详解:Kafka快速上手(Java版).md) +* [消息队列kafka详解:Kafka一条消息存到broker的过程](docs/mq/kafka/消息队列kafka详解:Kafka一条消息存到broker的过程.md) +* [消息队列kafka详解:消息队列kafka详解:Kafka介绍](docs/mq/kafka/消息队列kafka详解:Kafka介绍.md) +* [消息队列kafka详解:Kafka原理分析总结篇](docs/mq/kafka/消息队列kafka详解:Kafka原理分析总结篇.md) +* [消息队列kafka详解:Kafka常见命令及配置总结](docs/mq/kafka/消息队列kafka详解:Kafka常见命令及配置总结.md) +* [消息队列kafka详解:Kafka架构介绍](docs/mq/kafka/消息队列kafka详解:Kafka架构介绍.md) +* [消息队列kafka详解:Kafka的集群工作原理](docs/mq/kafka/消息队列kafka详解:Kafka的集群工作原理.md) +* [消息队列kafka详解:Kafka重要知识点+面试题大全](docs/mq/kafka/消息队列kafka详解:Kafka重要知识点+面试题大全.md) +* [消息队列kafka详解:如何实现延迟队列](docs/mq/kafka/消息队列kafka详解:如何实现延迟队列.md) +* [消息队列kafka详解:如何实现死信队列](docs/mq/kafka/消息队列kafka详解:如何实现死信队列.md) + +## RocketMQ +* [RocketMQ系列:事务消息(最终一致性)](docs/mq/RocketMQ/RocketMQ系列:事务消息(最终一致性).md) +* [RocketMQ系列:基本概念](docs/mq/RocketMQ/RocketMQ系列:基本概念.md) +* [RocketMQ系列:广播与延迟消息](docs/mq/RocketMQ/RocketMQ系列:广播与延迟消息.md) +* [RocketMQ系列:批量发送与过滤](docs/mq/RocketMQ/RocketMQ系列:批量发送与过滤.md) +* [RocketMQ系列:消息的生产与消费](docs/mq/RocketMQ/RocketMQ系列:消息的生产与消费.md) +* [RocketMQ系列:环境搭建](docs/mq/RocketMQ/RocketMQ系列:环境搭建.md) +* [RocketMQ系列:顺序消费](docs/mq/RocketMQ/RocketMQ系列:顺序消费.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) + +# 分布式 +## 分布式理论 * [分布式系统理论基础:一致性PC和PC ](docs/distributed/basic/分布式系统理论基础:一致性PC和PC.md) * [分布式系统理论基础:CAP ](docs/distributed/basic/分布式系统理论基础:CAP.md) * [分布式系统理论基础:时间时钟和事件顺序](docs/distributed/basic/分布式系统理论基础:时间时钟和事件顺序.md) @@ -316,22 +441,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,31 +462,31 @@ todo * [搞懂分布式技术:使用RocketMQ事务消息解决分布式事务 ](docs/distributed/practice/搞懂分布式技术:使用RocketMQ事务消息解决分布式事务.md ) * [搞懂分布式技术:消息队列因何而生](docs/distributed/practice/搞懂分布式技术:消息队列因何而生.md) * [搞懂分布式技术:浅谈分布式消息技术Kafka](docs/distributed/practice/搞懂分布式技术:浅谈分布式消息技术Kafka.md ) +* [分布式技术实践总结](docs/distributed/分布式理论总结.md) -* [分布式理论总结](docs/distributed/分布式技术实践总结.md) -## 面试指南 +# 面试指南 todo -### 校招指南 +## 校招指南 todo -### 面经 +## 面经 todo -## 工具 +# 工具 todo -## 资料 +# 资料 todo -### 书单 +## 书单 todo -## 待办 +# 待办 springboot和springcloud -## 微信公众号 +# 微信公众号 -### Java技术江湖 +## Java技术江湖 如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号【Java技术江湖】  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 99% 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" index 9a1cdad..60b89e6 100644 --- "a/docs/java/jvm/JVM\346\200\273\347\273\223.md" +++ "b/docs/Java/JVM/JVM\346\200\273\347\273\223.md" @@ -1,4 +1,4 @@ -# Table of Contents +# 目录 * [JVM介绍和源码](#jvm介绍和源码) * [JVM内存模型](#jvm内存模型) 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 98% 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" index 341f675..ceda305 100644 --- "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" @@ -1,4 +1,23 @@ # 目录 + +* [核心概念(Core Concepts)](#核心概念core-concepts) + * [Latency(延迟)](#latency延迟) + * [Throughput(吞吐量)](#throughput吞吐量) + * [Capacity(系统容量)](#capacity系统容量) +* [相关示例](#相关示例) + * [Tuning for Latency(调优延迟指标)](#tuning-for-latency调优延迟指标) + * [Tuning for Throughput(吞吐量调优)](#tuning-for-throughput吞吐量调优) + * [Tuning for Capacity(调优系统容量)](#tuning-for-capacity调优系统容量) + * [6\. GC 调优(工具篇) - GC参考手册](#6-gc-调优工具篇---gc参考手册) + * [JMX API](#jmx-api) + * [JVisualVM](#jvisualvm) + * [jstat](#jstat) + * [GC日志(GC logs)](#gc日志gc-logs) + * [GCViewer](#gcviewer) + * [分析器(Profilers)](#分析器profilers) + * [hprof](#hprof) + * [Java VisualVM](#java-visualvm) + * [AProf](#aprof) * [参考文章](#参考文章) @@ -18,8 +37,6 @@ -## 5\. GC 调优(基础篇) - GC参考手册 - > **说明**: > > **Capacity**: 性能,能力,系统容量; 文中翻译为”**系统容量**“; 意为硬件配置。 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 99% 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" index b48b79b..6c1b066 100644 --- "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" @@ -1,7 +1,7 @@ # 目录 * [打破双亲委派模型](#打破双亲委派模型) * [JNDI](#jndi) - * [[JNDI 的理解](https://yq.aliyun.com/go/articleRenderRedirect?url=https%3A%2F%2Fwww.cnblogs.com%2Fzhchoutai%2Fp%2F7389089.html)](#[jndi-的理解]httpsyqaliyuncomgoarticlerenderredirecturlhttps3a2f2fwwwcnblogscom2fzhchoutai2fp2f7389089html) + * [JNDI 的理解](#[jndi-的理解]) * [OSGI](#osgi) * [1.如何正确的理解和认识OSGI技术?](#1如何正确的理解和认识osgi技术?) * [Tomcat类加载器以及应用间class隔离与共享](#tomcat类加载器以及应用间class隔离与共享) 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 99% 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" index 65e4869..8048fb5 100644 --- "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" @@ -14,7 +14,7 @@ * [垃圾回收中实例的终结](#垃圾回收中实例的终结) * [对象什么时候符合垃圾回收的条件?](#对象什么时候符合垃圾回收的条件?) * [GC Scope 示例程序](#gc-scope-示例程序) - * [[JVM GC算法](https://www.cnblogs.com/wupeixuan/p/8670341.html)](#[jvm-gc算法]httpswwwcnblogscomwupeixuanp8670341html) + * [JVM GC算法](#JVM GC算法) * [JVM垃圾判定算法](#jvm垃圾判定算法) * [引用计数算法(Reference Counting)](#引用计数算法reference-counting) * [可达性分析算法(根搜索算法)](#可达性分析算法(根搜索算法)) 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 98% 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" index 987466f..caac027 100644 --- "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" @@ -1,24 +1,21 @@ +# 目录 + * [JVM优化的必要性](#jvm优化的必要性) + * [JVM调优原则](#jvm调优原则) + * [JVM运行参数设置](#jvm运行参数设置) + * [JVM性能调优工具](#jvm性能调优工具) + * [常用调优策略](#常用调优策略) + * [六、JVM调优实例](#六、jvm调优实例) + * [七、一个具体的实战案例分析](#七、一个具体的实战案例分析) + * [参考资料](#参考资料) + * [参考文章](#参考文章) - - -**目录** - -一. JVM优化的必要性 - -二. JVM调优原则 -三. JVM运行参数设置 -四. JVM性能调优工具 -五. 常用调优策略 - -六. JVM调优实例 - -七. 一个具体的实战案例分析 + -### JVM优化的必要性 +## JVM优化的必要性 **1.1: 项目上线后,什么原因使得我们需要进行jvm调优** @@ -58,7 +55,7 @@ Jvm堆内存不能设置太大,否则会导致寻址垃圾的时间过长, * 系统吞吐量与响应性能不高或下降。 -### JVM调优原则 +## JVM调优原则  @@ -254,13 +251,13 @@ TLAB空间一般不会太大,当大对象无法在TLAB分配时,则会直接 -### 四.JVM性能调优工具 +## JVM性能调优工具 这个篇幅在这里就不过多介绍了,可以参照: 深入理解JVM虚拟机——Java虚拟机的监控及诊断工具大全 -### 五.常用调优策略 +## 常用调优策略 这里还是要提一下,及时确定要进行JVM调优,也不要陷入“知见障”,进行分析之后,发现可以通过优化程序提升性能,仍然首选优化程序。 @@ -410,7 +407,7 @@ CPU多核,关注用户停顿时间,JDK1.8及以上,JVM可用内存6G以上 > XX:MaxDirectMemorySize -### 六、JVM调优实例 +## 六、JVM调优实例 整理的一些JVM调优实例: @@ -533,7 +530,7 @@ CPU多核,关注用户停顿时间,JDK1.8及以上,JVM可用内存6G以上 系统对外提供各种账号鉴权服务,使用时发现系统经常服务不可用,通过 Zabbix 的监控平台监控发现系统频繁发生长时间 Full GC,且触发时老年代的堆内存通常并没有占满,发现原来是业务代码中调用了 -### 七、一个具体的实战案例分析 +## 七、一个具体的实战案例分析 **7.1 典型调优参数设置** 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 96% 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" index 0a1c3ac..58b8166 100644 --- "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" @@ -1,5 +1,5 @@ # 目录 - * [[java编译期优化](https://www.cnblogs.com/LeonNew/p/6187411.html)](#[java编译期优化]httpswwwcnblogscomleonnewp6187411html) + * [java编译期优化](#[java编译期优化]) * [早期(编译期)优化](#早期(编译期)优化) * [泛型与类型擦除](#泛型与类型擦除) * [自动装箱、拆箱与遍历循环](#自动装箱、拆箱与遍历循环) @@ -41,7 +41,7 @@ java语言的编译期其实是一段不确定的操作过程,因为它可以 2.后端编译:把字节码转变为机器码 3.静态提前编译:直接把*.java文件编译成本地机器代码 从JDK1.3开始,虚拟机设计团队就把对性能的优化集中到了后端的即时编译中,这样可以让那些不是由Javac产生的Class文件(如JRuby、Groovy等语言的Class文件)也能享受到编译期优化所带来的好处 -**Java中即时编译在运行期的优化过程对于程序运行来说更重要,而前端编译期在编译期的优化过程对于程序编码来说关系更加密切 ** +**Java中即时编译在运行期的优化过程对于程序运行来说更重要,而前端编译期在编译期的优化过程对于程序编码来说关系更加密切** ### 早期(编译期)优化 @@ -102,7 +102,7 @@ public static void main(String[] args) { ##### 解释器与编译器 -Java程序最初是通过解释器进行解释执行的,当程序需要迅速启动和执行时,解释器可以首先发挥作用,省去编译时间,立即执行;当程序运行后,随着时间的推移,编译期逐渐发挥作用,把越来越多的代码编译成本地代码,获得更高的执行效率。**解释执行节约内存,编译执行提升效率。** 同时,解释器可以作为编译器激进优化时的一个“逃生门”,让编译器根据概率选择一些大多数时候都能提升运行速度的优化手段,当激进优化的假设不成立,则通过逆优化退回到解释状态继续执行。 +Java程序最初是通过解释器进行解释执行的,当程序需要迅速启动和执行时,解释器可以首先发挥作用,省去编译时间,立即执行;当程序运行后,随着时间的推移,编译期逐渐发挥作用,把越来越多的代码编译成本地代码,获得更高的执行效率。**解释执行节约内存,编译执行提升效率。**同时,解释器可以作为编译器激进优化时的一个“逃生门”,让编译器根据概率选择一些大多数时候都能提升运行速度的优化手段,当激进优化的假设不成立,则通过逆优化退回到解释状态继续执行。 HotSpot虚拟机中内置了两个即时编译器,分别称为Client Compiler(C1编译器)和Server Compiler(C2编译器),默认采用解释器与其中一个编译器直接配合的方式工作,使用哪个编译器取决于虚拟机运行的模式,也可以自己去指定。若强制虚拟机运行与“解释模式”,编译器完全不介入工作,若强制虚拟机运行于“编译模式”,则优先采用编译方式执行程序,解释器仍然要在编译无法进行的情况下介入执行过程。  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 99% 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" index 08cc449..cca62d4 100644 --- "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" @@ -32,7 +32,7 @@ ## 一、背景 -Java的内存回收不需要程序员负责,JVM会在必要时启动Java GC完成垃圾回收。Java以便我们控制对象的生存周期,提供给了我们四种引用方式,引用强度从强到弱分别为:强引用、软引用、弱引用、虚引用。 +Java的内存回收不需要程序员负责,JVM会在必要时启动Java GC完成垃圾回收。Java以便我们控制对象的生存周期,提供给了我们四种引用方式,引用强度从强到弱分别为:强引用、软引用、弱引用、虚引用。 ## 二、简介 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 99% 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" index aace19c..435e587 100644 --- "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" @@ -403,8 +403,8 @@ public class TheClass { 你可以像这样来访问变量的注解: ``` -Field field = ... //获取方法对象 -
Annotation[] annotations = field.getDeclaredAnnotations();
+Field field = ... //获取方法对象目录
+Annotation[] annotations = field.getDeclaredAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
@@ -418,8 +418,8 @@ for(Annotation annotation : annotations){
你可以像这样访问指定的变量注解:
```
-Field field = ...//获取方法对象
-
+Field field = ...//获取方法对象目录
+
Annotation annotation = field.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
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 98%
rename from "docs/java/basic/javac\345\222\214javap.md"
rename to "docs/Java/basic/javac\345\222\214javap.md"
index 5f85010..f797af7 100644
--- "a/docs/java/basic/javac\345\222\214javap.md"
+++ "b/docs/Java/basic/javac\345\222\214javap.md"
@@ -18,14 +18,7 @@
* [-encoding](#-encoding)
* [-verbose](#-verbose)
* [其他命令](#其他命令)
- * [使用javac构建项目](#使用javac构建项目)
- * [](#)
-* [java文件列表目录](#java文件列表目录)
- * [放入列表文件中](#放入列表文件中)
- * [生成bin目录](#生成bin目录)
- * [列表](#列表)
- * [通过-cp指定所有的引用jar包,将src下的所有java文件进行编译](#通过-cp指定所有的引用jar包,将src下的所有java文件进行编译)
- * [通过-cp指定所有的引用jar包,指定入口函数运行](#通过-cp指定所有的引用jar包,指定入口函数运行)
+ * [使用javac构建项目](#使用javac构建项目)
* [javap 的使用](#javap-的使用)
* [参考文章](#参考文章)
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 98%
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"
index 2e51bc0..7ebb784 100644
--- "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"
@@ -38,7 +38,7 @@
## Java中的构造方法
### 构造方法简介
-构造方法是类的一种特殊方法,用来初始化类的一个新的对象。[Java](http://c.biancheng.net/java/) 中的每个类都有一个默认的构造方法,它必须具有和类名相同的名称,而且没有返回类型。构造方法的默认返回类型就是对象类型本身,并且构造方法不能被 static、final、synchronized、abstract 和 native 修饰。
+构造方法是类的一种特殊方法,用来初始化类的一个新的对象。[Java](http://c.biancheng.net/java/)中的每个类都有一个默认的构造方法,它必须具有和类名相同的名称,而且没有返回类型。构造方法的默认返回类型就是对象类型本身,并且构造方法不能被 static、final、synchronized、abstract 和 native 修饰。
提示:构造方法用于初始化一个新对象,所以用 static 修饰没有意义;构造方法不能被子类继承,所以用 final 和 abstract 修饰没有意义;多个线程不会同时创建内存地址相同的同一个对象,所以用 synchronized 修饰没有必要。
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 98%
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"
index e40b5d0..35e3ada 100644
--- "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"
@@ -80,7 +80,7 @@ Java 给多线程编程提供了内置的支持。 一条线程指的是进程
* **新建状态:**
- 使用 **new** 关键字和 **Thread** 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 **start()** 这个线程。
+ 使用**new**关键字和**Thread**类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序**start()**这个线程。
* **就绪状态:**
@@ -88,7 +88,7 @@ Java 给多线程编程提供了内置的支持。 一条线程指的是进程
* **运行状态:**
- 如果就绪状态的线程获取 CPU 资源,就可以执行 **run()**,此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
+ 如果就绪状态的线程获取 CPU 资源,就可以执行**run()**,此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
* **阻塞状态:**
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 99%
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"
index 8a672ed..57e5237 100644
--- "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"
@@ -3,9 +3,8 @@
* [多线程中的“回调”](#多线程中的回调)
* [Java回调机制实战](#java回调机制实战)
* [实例一 : 同步调用](#实例一-:-同步调用)
- * [1.1 同步调用代码](#11-同步调用代码)
- * [实例二:由浅入深](#实例二:由浅入深)
- * [实例三:Tom做题](#实例三:tom做题)
+ * [实例二:由浅入深](#实例二:由浅入深)
+ * [实例三:Tom做题](#实例三:tom做题)
* [参考文章](#参考文章)
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 99%
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"
index c89b6ae..95169c6 100644
--- "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"
@@ -6,12 +6,12 @@
* [fail-fast示例](#fail-fast示例)
* [fail-fast产生原因](#fail-fast产生原因)
* [fail-fast解决办法](#fail-fast解决办法)
-* [Comparable 和 Comparator](#comparable-和-comparator)
- * [Comparable](#comparable)
- * [Comparator](#comparator)
- * [Java8中使用lambda实现比较器](#java8中使用lambda实现比较器)
- * [总结](#总结)
- * [参考文章](#参考文章)
+ * [Comparable 和 Comparator](#comparable-和-comparator)
+ * [Comparable](#comparable)
+ * [Comparator](#comparator)
+ * [Java8中使用lambda实现比较器](#java8中使用lambda实现比较器)
+ * [总结](#总结)
+ * [参考文章](#参考文章)
本文参考 cmsblogs.com/p=1185
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 98%
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"
index e228969..ed04968 100644
--- "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"
@@ -13,9 +13,8 @@
* [初始容量和扩容](#初始容量和扩容)
* [线程安全](#线程安全-1)
* [Stack](#stack)
-* [Stack](#stack-1)
- * [三个集合类之间的区别](#三个集合类之间的区别)
- * [参考文章](#参考文章)
+ * [三个集合类之间的区别](#三个集合类之间的区别)
+ * [参考文章](#参考文章)
本文参考多篇优质技术博客,参考文章请在文末查看
@@ -464,11 +463,11 @@ vector大部分方法都使用了synchronized修饰符,所以他是线层安
# Stack
- 如果我们去查jdk的文档,我们会发现stack是在java.util这个包里。它对应的一个大致的类关系图如下:
+ 如果我们去查jdk的文档,我们会发现stack是在java.util这个包里。它对应的一个大致的类关系图如下:

- 通过继承Vector类,Stack类可以很容易的实现他本身的功能。因为大部分的功能在Vector里面已经提供支持了。
+ 通过继承Vector类,Stack类可以很容易的实现他本身的功能。因为大部分的功能在Vector里面已经提供支持了。
在Java中Stack类表示后进先出(LIFO)的对象堆栈。栈是一种非常常见的数据结构,它采用典型的先进后出的操作方式完成的。
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 99%
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"
index 7cacaae..eb10601 100644
--- "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"
@@ -8,8 +8,8 @@
* [5\. 唤醒后检查中断状态](#5-唤醒后检查中断状态)
* [6\. 获取独占锁](#6-获取独占锁)
* [7\. 处理中断状态](#7-处理中断状态)
- * [* 带超时机制的 await](#-带超时机制的-await)
- * [* 不抛出 InterruptedException 的 await](#-不抛出-interruptedexception-的-await)
+ * [带超时机制的 await](#-带超时机制的-await)
+ * [不抛出 InterruptedException 的 await](#-不抛出-interruptedexception-的-await)
* [AbstractQueuedSynchronizer 独占锁的取消排队](#abstractqueuedsynchronizer-独占锁的取消排队)
* [再说 java 线程中断和 InterruptedException 异常](#再说-java-线程中断和-interruptedexception-异常)
* [线程中断](#线程中断)
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 92%
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"
index ca072a2..74fa6a0 100644
--- "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"
@@ -27,7 +27,7 @@ Fork/Join框架是Java7提供的一个用于并行执行任务的框架, 是
## 简介
-通常,使用Java来开发一个简单的并发应用程序时,会创建一些**Runnable**对象,然后创建对应的**Thread** 对象来控制程序中这些线程的创建、执行以及线程的状态。自从Java 5开始引入了**Executor**和**ExecutorService**接口以及实现这两个接口的类(比如**ThreadPoolExecutor**)之后,使得Java在并发支持上得到了进一步的提升。
+通常,使用Java来开发一个简单的并发应用程序时,会创建一些**Runnable**对象,然后创建对应的**Thread**对象来控制程序中这些线程的创建、执行以及线程的状态。自从Java 5开始引入了**Executor**和**ExecutorService**接口以及实现这两个接口的类(比如**ThreadPoolExecutor**)之后,使得Java在并发支持上得到了进一步的提升。
**执行器框架(Executor Framework)**将任务的创建和执行进行了分离,通过这个框架,只需要实现**Runnable**接口的对象和使用**Executor**对象,然后将**Runnable**对象发送给执行器。执行器再负责运行这些任务所需要的线程,包括线程的创建,线程的管理以及线程的结束。
@@ -37,7 +37,7 @@ Fork/Join框架是Java7提供的一个用于并行执行任务的框架, 是

-没有固定的公式来决定问题的**参考大小(Reference Size)**,从而决定一个任务是需要进行拆分或不需要拆分,拆分与否仍是依赖于任务本身的特性。可以使用在任务中将要处理的元素的数目和任务执行所需要的时间来决定参考大小。测试不同的参考大小来决定解决问题最好的一个方案,将**ForkJoinPool**类看作一个特殊的 **Executor** 执行器类型。这个框架基于以下两种操作。
+没有固定的公式来决定问题的**参考大小(Reference Size)**,从而决定一个任务是需要进行拆分或不需要拆分,拆分与否仍是依赖于任务本身的特性。可以使用在任务中将要处理的元素的数目和任务执行所需要的时间来决定参考大小。测试不同的参考大小来决定解决问题最好的一个方案,将**ForkJoinPool**类看作一个特殊的**Executor**执行器类型。这个框架基于以下两种操作。
* **分解(Fork)**操作:当需要将一个任务拆分成更小的多个任务时,在框架中执行这些任务;
* **合并(Join)**操作:当一个主任务等待其创建的多个子任务的完成执行。
@@ -46,7 +46,7 @@ Fork/Join框架是Java7提供的一个用于并行执行任务的框架, 是
为了达到这个目标,通过**Fork/Join框架**执行的任务有以下限制。
-* 任务只能使用**fork()**和**join()** 操作当作同步机制。如果使用其他的同步机制,工作者线程就不能执行其他任务,当然这些任务是在同步操作里时。比如,如果在**Fork/Join 框架**中将一个任务休眠,正在执行这个任务的工作者线程在休眠期内不能执行另一个任务。
+* 任务只能使用**fork()**和**join()**操作当作同步机制。如果使用其他的同步机制,工作者线程就不能执行其他任务,当然这些任务是在同步操作里时。比如,如果在**Fork/Join 框架**中将一个任务休眠,正在执行这个任务的工作者线程在休眠期内不能执行另一个任务。
* 任务不能执行I/O操作,比如文件数据的读取与写入。
* 任务不能抛出非运行时异常(Checked Exception),必须在代码中处理掉这些异常。
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 96%
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"
index 2d825d4..c9a13f8 100644
--- "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"
@@ -1,3 +1,12 @@
+# 目录
+
+ * [一、properly constructed / this对象逸出](#一、properly-constructed--this对象逸出)
+ * [二、对象的安全发布](#二、对象的安全发布)
+ * [三、 final 关键字的内存语义](#三、-final-关键字的内存语义)
+ * [四、HotSpot VM中对final内存语义的实现](#四、hotspot-vm中对final内存语义的实现)
+* [参考文献](#参考文献)
+
+
**本文转载自互联网,侵删**
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
@@ -215,4 +224,4 @@ JSR 133 (Java Memory Model) FAQ
Java Concurrency in Practice
The JSR-133 Cookbook for Compiler Writers
-Intel® 64 and IA-32 ArchitecturesvSoftware Developer’s Manual Volume 3A: System Programming Guide, Part 1
\ No newline at end of file
+Intel® 64 and IA-32 ArchitecturesvSoftware Developer’s Manual Volume 3A: System Programming Guide, Part 1
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 99%
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"
index 6314e77..dff6cc3 100644
--- "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"
@@ -345,7 +345,7 @@ public V put(K key, V value) {
第一层皮很简单,根据 hash 值很快就能找到相应的 Segment,之后就是 Segment 内部的 put 操作了。
-Segment 内部是由 **数组+链表** 组成的。
+Segment 内部是由**数组+链表**组成的。
```
final V put(K key, int hash, V value, boolean onlyIfAbsent) {
@@ -640,11 +640,11 @@ public V get(Object key) {
## Java8 HashMap
-Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由 **数组+链表+红黑树** 组成。
+Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑树,所以其由**数组+链表+红黑树**组成。
-根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 **O(n)**。
+根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为**O(n)**。
-为了降低这部分的开销,在 Java8 中,当链表中的元素达到了 8 个时,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 **O(logN)**。
+为了降低这部分的开销,在 Java8 中,当链表中的元素达到了 8 个时,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为**O(logN)**。
来一张图简单示意一下吧:
@@ -654,7 +654,7 @@ Java8 对 HashMap 进行了一些修改,最大的不同就是利用了红黑
下面,我们还是用代码来介绍吧,个人感觉,Java8 的源码可读性要差一些,不过精简一些。
-Java7 中使用 Entry 来代表每个 HashMap 中的数据节点,Java8 中使用 **Node**,基本没有区别,都是 key,value,hash 和 next 这四个属性,不过,Node 只能用于链表的情况,红黑树的情况需要使用 **TreeNode**。
+Java7 中使用 Entry 来代表每个 HashMap 中的数据节点,Java8 中使用**Node**,基本没有区别,都是 key,value,hash 和 next 这四个属性,不过,Node 只能用于链表的情况,红黑树的情况需要使用**TreeNode**。
我们根据数组元素中,第一个节点数据类型是 Node 还是 TreeNode 来判断该位置下是链表还是红黑树的。
@@ -1145,7 +1145,7 @@ private final void tryPresize(int size) {
这个方法的核心在于 sizeCtl 值的操作,首先将其设置为一个负数,然后执行 transfer(tab, null),再下一个循环将 sizeCtl 加 1,并执行 transfer(tab, nt),之后可能是继续 sizeCtl 加 1,并执行 transfer(tab, nt)。
-所以,可能的操作就是执行 **1 次 transfer(tab, null) + 多次 transfer(tab, nt)**,这里怎么结束循环的需要看完 transfer 源码才清楚。
+所以,可能的操作就是执行**1 次 transfer(tab, null) + 多次 transfer(tab, nt)**,这里怎么结束循环的需要看完 transfer 源码才清楚。
#### 数据迁移:transfer
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 95%
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"
index 50c20d6..a357d88 100644
--- "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"
@@ -91,7 +91,7 @@ ReentrantReadWriteLock 分为读锁和写锁两个实例,读锁是共享锁,
很清楚了,ReadLock 和 WriteLock 中的方法都是通过 Sync 这个类来实现的。Sync 是 AQS 的子类,然后再派生了公平模式和不公平模式。
-从它们调用的 Sync 方法,我们可以看到: **ReadLock 使用了共享模式,WriteLock 使用了独占模式**。
+从它们调用的 Sync 方法,我们可以看到:**ReadLock 使用了共享模式,WriteLock 使用了独占模式**。
等等,**同一个 AQS 实例怎么可以同时使用共享模式和独占模式**???
@@ -99,7 +99,7 @@ ReentrantReadWriteLock 分为读锁和写锁两个实例,读锁是共享锁,

-AQS 的精髓在于内部的属性 **state**:
+AQS 的精髓在于内部的属性**state**:
1. 对于独占模式来说,通常就是 0 代表可获取锁,1 代表锁被别人获取了,重入例外
2. 而共享模式下,每个线程都可以对 state 进行加减操作
@@ -168,9 +168,9 @@ abstract static class Sync extends AbstractQueuedSynchronizer {
1. state 的高 16 位代表读锁的获取次数,包括重入次数,获取到读锁一次加 1,释放掉读锁一次减 1
2. state 的低 16 位代表写锁的获取次数,因为写锁是独占锁,同时只能被一个线程获得,所以它代表重入次数
-3. 每个线程都需要维护自己的 HoldCounter,记录该线程获取的读锁次数,这样才能知道到底是不是读锁重入,用 ThreadLocal 属性 **readHolds** 维护
-4. **cachedHoldCounter** 有什么用?其实没什么用,但能提示性能。将最后一次获取读锁的线程的 HoldCounter 缓存到这里,这样比使用 ThreadLocal 性能要好一些,因为 ThreadLocal 内部是基于 map 来查询的。但是 cachedHoldCounter 这一个属性毕竟只能缓存一个线程,所以它要起提升性能作用的依据就是:通常读锁的获取紧随着就是该读锁的释放。我这里可能表达不太好,但是大家应该是懂的吧。
-5. **firstReader** 和 **firstReaderHoldCount** 有什么用?其实也没什么用,但是它也能提示性能。将"第一个"获取读锁的线程记录在 firstReader 属性中,这里的**第一个**不是全局的概念,等这个 firstReader 当前代表的线程释放掉读锁以后,会有后来的线程占用这个属性的。**firstReader 和 firstReaderHoldCount 使得在读锁不产生竞争的情况下,记录读锁重入次数非常方便快速**
+3. 每个线程都需要维护自己的 HoldCounter,记录该线程获取的读锁次数,这样才能知道到底是不是读锁重入,用 ThreadLocal 属性**readHolds**维护
+4. **cachedHoldCounter**有什么用?其实没什么用,但能提示性能。将最后一次获取读锁的线程的 HoldCounter 缓存到这里,这样比使用 ThreadLocal 性能要好一些,因为 ThreadLocal 内部是基于 map 来查询的。但是 cachedHoldCounter 这一个属性毕竟只能缓存一个线程,所以它要起提升性能作用的依据就是:通常读锁的获取紧随着就是该读锁的释放。我这里可能表达不太好,但是大家应该是懂的吧。
+5. **firstReader**和**firstReaderHoldCount**有什么用?其实也没什么用,但是它也能提示性能。将"第一个"获取读锁的线程记录在 firstReader 属性中,这里的**第一个**不是全局的概念,等这个 firstReader 当前代表的线程释放掉读锁以后,会有后来的线程占用这个属性的。**firstReader 和 firstReaderHoldCount 使得在读锁不产生竞争的情况下,记录读锁重入次数非常方便快速**
6. 如果一个线程使用了 firstReader,那么它就不需要占用 cachedHoldCounter
7. 个人认为,读写锁源码中最让初学者头疼的就是这几个用于提升性能的属性了,使得大家看得云里雾里的。主要是因为 ThreadLocal 内部是通过一个 ThreadLocalMap 来操作的,会增加检索时间。而很多场景下,执行 unlock 的线程往往就是刚刚最后一次执行 lock 的线程,中间可能没有其他线程进行 lock。还有就是很多不怎么会发生读锁竞争的场景。
@@ -498,7 +498,7 @@ protected final boolean tryAcquire(int acquires) {
}
```
-下面看一眼 **writerShouldBlock()** 的判定,然后你再回去看一篇写锁获取过程。
+下面看一眼**writerShouldBlock()**的判定,然后你再回去看一篇写锁获取过程。
```
static final class NonfairSync extends Sync {
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 99%
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"
index 0abdbe8..60a9c3e 100644
--- "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"
@@ -9,7 +9,6 @@
* [volatile写-读的内存语义](#volatile写-读的内存语义)
* [volatile内存语义的实现](#volatile内存语义的实现)
* [JSR-133为什么要增强volatile的内存语义](#jsr-133为什么要增强volatile的内存语义)
- * [](#)
* [引言](#引言)
* [术语定义](#术语定义)
* [3 处理器如何实现原子操作](#3-处理器如何实现原子操作)
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 98%
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"
index 0856914..a9aad6e 100644
--- "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"
@@ -176,7 +176,7 @@ Java 语言在遵循内存模型的基础上推出了 JMM 规范,目的是解
我们知道,Java程序是需要运行在Java虚拟机上面的,**Java内存模型(Java Memory Model ,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能保证效果一致的机制及规范。**
-提到Java内存模型,一般指的是JDK 5 开始使用的新的内存模型,主要由[JSR-133: JavaTM Memory Model and Thread Specification](http://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf) 描述。感兴趣的可以参看下这份PDF文档([http://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf](http://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf))
+提到Java内存模型,一般指的是JDK 5 开始使用的新的内存模型,主要由[JSR-133: JavaTM Memory Model and Thread Specification](http://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf)描述。感兴趣的可以参看下这份PDF文档([http://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf](http://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf))
Java内存模型规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程中是用到的变量的主内存副本拷贝,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量的传递均需要自己的工作内存和主存之间进行数据同步进行。
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 98%
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"
index b318132..aa025c9 100644
--- "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"
@@ -92,7 +92,7 @@ public interface Executor {
}
```
-我们可以看到 Executor 接口非常简单,就一个 `void execute(Runnable command)` 方法,代表提交一个任务。为了让大家理解 java 线程池的整个设计方案,我会按照 Doug Lea 的设计思路来多说一些相关的东西。
+我们可以看到 Executor 接口非常简单,就一个`void execute(Runnable command)`方法,代表提交一个任务。为了让大家理解 java 线程池的整个设计方案,我会按照 Doug Lea 的设计思路来多说一些相关的东西。
我们经常这样启动一个线程:
@@ -171,7 +171,7 @@ class SerialExecutor implements Executor {
}
```
-当然了,Executor 这个接口只有提交任务的功能,太简单了,我们想要更丰富的功能,比如我们想知道执行结果、我们想知道当前线程池有多少个线程活着、已经完成了多少任务等等,这些都是这个接口的不足的地方。接下来我们要介绍的是继承自 `Executor` 接口的 `ExecutorService` 接口,这个接口提供了比较丰富的功能,也是我们最常使用到的接口。
+当然了,Executor 这个接口只有提交任务的功能,太简单了,我们想要更丰富的功能,比如我们想知道执行结果、我们想知道当前线程池有多少个线程活着、已经完成了多少任务等等,这些都是这个接口的不足的地方。接下来我们要介绍的是继承自`Executor`接口的`ExecutorService`接口,这个接口提供了比较丰富的功能,也是我们最常使用到的接口。
## ExecutorService
@@ -277,13 +277,13 @@ public interface Callable {
在这里,就不展开说 FutureTask 类了,因为本文篇幅本来就够大了,这里我们需要知道怎么用就行了。
-下面,我们来看看 `ExecutorService` 的抽象实现 `AbstractExecutorService` 。
+下面,我们来看看`ExecutorService`的抽象实现`AbstractExecutorService`。
## AbstractExecutorService
AbstractExecutorService 抽象类派生自 ExecutorService 接口,然后在其基础上实现了几个实用的方法,这些方法提供给子类进行调用。
-这个抽象类实现了 invokeAny 方法和 invokeAll 方法,这里的两个 newTaskFor 方法也比较有用,用于将任务包装成 FutureTask。定义于最上层接口 Executor中的 `void execute(Runnable command)` 由于不需要获取结果,不会进行 FutureTask 的包装。
+这个抽象类实现了 invokeAny 方法和 invokeAll 方法,这里的两个 newTaskFor 方法也比较有用,用于将任务包装成 FutureTask。定义于最上层接口 Executor中的`void execute(Runnable command)`由于不需要获取结果,不会进行 FutureTask 的包装。
> 需要获取结果(FutureTask),用 submit 方法,不需要获取结果,可以用 execute 方法。
@@ -600,7 +600,7 @@ public Future submit(Callable task) {
当然,上图没有考虑队列是否有界,提交任务时队列满了怎么办?什么情况下会创建新的线程?提交任务时线程池满了怎么办?空闲线程怎么关掉?这些问题下面我们会一一解决。
-我们经常会使用 `Executors` 这个工具类来快速构造一个线程池,对于初学者而言,这种工具类是很有用的,开发者不需要关注太多的细节,只要知道自己需要一个线程池,仅仅提供必需的参数就可以了,其他参数都采用作者提供的默认值。
+我们经常会使用`Executors`这个工具类来快速构造一个线程池,对于初学者而言,这种工具类是很有用的,开发者不需要关注太多的细节,只要知道自己需要一个线程池,仅仅提供必需的参数就可以了,其他参数都采用作者提供的默认值。
```
public static ExecutorService newFixedThreadPool(int nThreads) {
@@ -659,7 +659,7 @@ public static ExecutorService newCachedThreadPool() {
* keepAliveTime
- > 空闲线程的保活时间,如果某线程的空闲时间超过这个值都没有任务给它做,那么可以被关闭了。注意这个值并不会对所有线程起作用,如果线程池中的线程数少于等于核心线程数 corePoolSize,那么这些线程不会因为空闲太长时间而被关闭,当然,也可以通过调用 `allowCoreThreadTimeOut(true)`使核心线程数内的线程也可以被回收。
+ > 空闲线程的保活时间,如果某线程的空闲时间超过这个值都没有任务给它做,那么可以被关闭了。注意这个值并不会对所有线程起作用,如果线程池中的线程数少于等于核心线程数 corePoolSize,那么这些线程不会因为空闲太长时间而被关闭,当然,也可以通过调用`allowCoreThreadTimeOut(true)`使核心线程数内的线程也可以被回收。
* threadFactory
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 99%
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"
index f5ab376..98f3e38 100644
--- "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"
@@ -9,7 +9,6 @@
* [Lock类](#lock类)
* [AQS](#aqs)
* [锁Lock和Conditon](#锁lock和conditon)
- * [](#)
* [并发工具类](#并发工具类)
* [原子数据类型](#原子数据类型)
* [同步容器](#同步容器)
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 76%
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"
index dc643c3..ab7b901 100644
--- "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"
@@ -1,3 +1,34 @@
+# 目录
+
+ * [**一,结构型模式**](#一,结构型模式)
+ * [**1,适配器模式**](#1,适配器模式)
+ * [**2,桥接模式**](#2,桥接模式)
+ * [**3,组合模式**](#3,组合模式)
+ * [**4,装饰者模式**](#4,装饰者模式)
+ * [**5,门面模式**](#5,门面模式)
+ * [**6,享元模式**](#6,享元模式)
+ * [**7,代理模式**](#7,代理模式)
+ * [**二,创建模式**](#二,创建模式)
+ * [**1,抽象工厂模式**](#1,抽象工厂模式)
+ * [**2,建造模式(Builder)**](#2,建造模式builder)
+ * [**3,工厂方法**](#3,工厂方法)
+ * [**4,原型模式**](#4,原型模式)
+ * [**5,单例模式**](#5,单例模式)
+ * [**三,行为模式**](#三,行为模式)
+ * [**1,责任链模式**](#1,责任链模式)
+ * [**2,命令模式**](#2,命令模式)
+ * [**3,解释器模式**](#3,解释器模式)
+ * [**4,迭代器模式**](#4,迭代器模式)
+ * [**5,中介者模式**](#5,中介者模式)
+ * [**6,备忘录模式**](#6,备忘录模式)
+ * [**7,空对象模式**](#7,空对象模式)
+ * [**8,观察者模式**](#8,观察者模式)
+ * [**9,状态模式**](#9,状态模式)
+ * [**10,策略模式**](#10,策略模式)
+ * [**11,模板方法模式**](#11,模板方法模式)
+ * [**12,访问者模式**](#12,访问者模式)
+
+
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
@@ -12,9 +43,9 @@
本文转自https://www.cnblogs.com/LinkinPark/p/5233075.html
-**一,结构型模式**
+## **一,结构型模式**
-**1,适配器模式**
+### **1,适配器模式**
**用来把一个接口转化成另一个接口**
@@ -30,7 +61,7 @@
>
> **javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal()**
-**2,桥接模式**
+### **2,桥接模式**
**这个模式将抽象和抽象操作的实现进行了解耦,这样使得抽象和实现可以独立地变化**
@@ -38,7 +69,7 @@
>
> **JDBC**
-**3,组合模式**
+### **3,组合模式**
**使得客户端看来单个对象和对象的组合是同等的。换句话说,某个类型的方法同时也接受自身类型作为参数**
@@ -52,7 +83,7 @@
>
> **java.util.Set#addAll(Collection)**
-**4,装饰者模式**
+### **4,装饰者模式**
**动态的给一个对象附加额外的功能,这也是子类的一种替代方式。可以看到,在创建一个类型的时候,同时也传入同一类型的对象。这在JDK里随处可见,你会发现它无处不在,所以下面这个列表只是一小部分**
@@ -64,9 +95,9 @@
>
> **java.util.zip.ZipOutputStream(OutputStream)**
>
-> **java.util.Collections#checked**
+> **java.util.Collections#checked**
-**5,门面模式**
+### **5,门面模式**
**给一组组件,接口,抽象,或者子系统提供一个简单的接口**
@@ -74,7 +105,7 @@
>
> **javax.faces.webapp.FacesServlet**
-**6,享元模式**
+### **6,享元模式**
**使用缓存来加速大量小对象的访问时间**
@@ -86,7 +117,7 @@
>
> **java.lang.Character#valueOf(char)**
-**7,代理模式**
+### **7,代理模式**
**代理模式是用一个简单的对象来代替一个复杂的或者创建耗时的对象。**
@@ -94,11 +125,11 @@
>
> **RMI**
-** **
+****
-**二,创建模式**
+## **二,创建模式**
-**1,抽象工厂模式**
+### **1,抽象工厂模式**
**抽象工厂模式提供了一个协议来生成一系列的相关或者独立的对象,而不用指定具体对象的类型。它使得应用程序能够和使用的框架的具体实现进行解耦。这在JDK或者许多框架比如Spring中都随处可见。它们也很容易识别,一个创建新对象的方法,返回的却是接口或者抽象类的,就是抽象工厂模式了**
@@ -118,7 +149,7 @@
>
> **javax.xml.transform.TransformerFactory#newInstance()**
-**2,建造模式(Builder)**
+### **2,建造模式(Builder)**
**定义了一个新的类来构建另一个类的实例,以简化复杂对象的创建。建造模式通常也使用方法链接来实现**
@@ -130,7 +161,7 @@
>
> **javax.swing.GroupLayout.Group#addComponent()**
-**3,工厂方法**
+### **3,工厂方法**
**就是一个返回具体对象的方法**
@@ -148,7 +179,7 @@
>
> **java.lang.Class#forName()**
-**4,原型模式**
+### **4,原型模式**
**使得类的实例能够生成自身的拷贝。如果创建一个对象的实例非常复杂且耗时时,就可以使用这种模式,而不重新创建一个新的实例,你可以拷贝一个对象并直接修改它**
@@ -156,7 +187,7 @@
>
> **java.lang.Cloneable**
-**5,单例模式**
+### **5,单例模式**
**用来确保类只有一个实例。Joshua Bloch在Effetive Java中建议到,还有一种方法就是使用枚举**
@@ -168,11 +199,11 @@
>
> **java.awt.Desktop#getDesktop()**
-** **
+****
-**三,行为模式**
+## **三,行为模式**
-**1,责任链模式**
+### **1,责任链模式**
**通过把请求从一个对象传递到链条中下一个对象的方式,直到请求被处理完毕,以实现对象间的解耦**
@@ -180,7 +211,7 @@
>
> **javax.servlet.Filter#doFilter()**
-**2,命令模式**
+### **2,命令模式**
**将操作封装到对象内,以便存储,传递和返回**
@@ -188,7 +219,7 @@
>
> **javax.swing.Action**
-**3,解释器模式**
+### **3,解释器模式**
**这个模式通常定义了一个语言的语法,然后解析相应语法的语句**
@@ -198,7 +229,7 @@
>
> **java.text.Format**
-**4,迭代器模式**
+### **4,迭代器模式**
**提供一个一致的方法来顺序访问集合中的对象,这个方法与底层的集合的具体实现无关**
@@ -206,7 +237,7 @@
>
> **java.util.Enumeration**
-**5,中介者模式**
+### **5,中介者模式**
**通过使用一个中间对象来进行消息分发以及减少类之间的直接依赖**
@@ -218,7 +249,7 @@
>
> **java.lang.reflect.Method#invoke()**
-**6,备忘录模式**
+### **6,备忘录模式**
**生成对象状态的一个快照,以便对象可以恢复原始状态而不用暴露自身的内容。Date对象通过自身内部的一个long值来实现备忘录模式**
@@ -226,7 +257,7 @@
>
> **java.io.Serializable**
-**7,空对象模式**
+### **7,空对象模式**
**这个模式通过一个无意义的对象来代替没有对象这个状态。它使得你不用额外对空对象进行处理**
@@ -236,7 +267,7 @@
>
> **java.util.Collections#emptySet()**
-**8,观察者模式**
+### **8,观察者模式**
**它使得一个对象可以灵活的将消息发送给感兴趣的对象**
@@ -248,7 +279,7 @@
>
> **javax.faces.event.PhaseListener**
-**9,状态模式**
+### **9,状态模式**
**通过改变对象内部的状态,使得你可以在运行时动态改变一个对象的行为**
@@ -256,7 +287,7 @@
>
> **javax.faces.lifecycle.LifeCycle#execute()**
-**10,策略模式**
+### **10,策略模式**
**使用这个模式来将一组算法封装成一系列对象。通过传递这些对象可以灵活的改变程序的功能**
@@ -266,7 +297,7 @@
>
> **javax.servlet.Filter#doFilter()**
-**11,模板方法模式**
+### **11,模板方法模式**
**让子类可以重写方法的一部分,而不是整个重写,你可以控制子类需要重写那些操作**
@@ -278,7 +309,7 @@
>
> **java.util.AbstractList#indexOf()**
-**12,访问者模式**
+### **12,访问者模式**
**提供一个方便的可维护的方式来操作一组对象。它使得你在不改变操作的对象前提下,可以修改或者扩展对象的行为**
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 97%
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"
index 634e1c6..15c003a 100644
--- "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"
@@ -1,3 +1,17 @@
+# 目录
+
+* [目录](#目录)
+ * [Java IO](#java-io)
+ * [Socket编程](#socket编程)
+ * [客户端,服务端的线程模型](#客户端,服务端的线程模型)
+ * [IO模型](#io模型)
+ * [NIO](#nio)
+ * [AIO](#aio)
+ * [Tomcat中的NIO模型](#tomcat中的nio模型)
+ * [Tomcat的container](#tomcat的container)
+ * [netty](#netty)
+
+
# 目录
* [Java IO](#java-io)
* [Socket编程](#socket编程)
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 93%
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"
index 8bdf054..deca42f 100644
--- "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"
@@ -1,3 +1,21 @@
+# 目录
+
+* [目录](#目录)
+ * [IO模型介绍](#io模型介绍)
+ * [阻塞 I/O(blocking IO)](#阻塞-io(blocking-io))
+ * [非阻塞 I/O(nonblocking IO)](#非阻塞-io(nonblocking-io))
+ * [I/O 多路复用( IO multiplexing)](#io-多路复用(-io-multiplexing))
+ * [异步 I/O(asynchronous IO)](#异步-io(asynchronous-io))
+ * [阻塞IO,非阻塞IO 与 同步IO, 异步IO的区别和联系](#阻塞io非阻塞io-与-同步io-异步io的区别和联系)
+ * [IO模型的形象举例](#io模型的形象举例)
+ * [Select/Poll/Epoll 轮询机制](#selectpollepoll-轮询机制)
+ * [Java网络编程模型](#java网络编程模型)
+ * [BIO](#bio)
+ * [NIO](#nio)
+ * [AIO](#aio)
+ * [对比](#对比)
+
+
# 目录
* [IO模型介绍](#io模型介绍)
* [阻塞 I/O(blocking IO)](#阻塞-io(blocking-io))
@@ -90,7 +108,7 @@ asynchronous IO
**_当一个read操作发生时,它会经历两个阶段:_**
-* 等待数据准备,比如accept(), recv()等待数据 `(Waiting for the data to be ready)`
+* 等待数据准备,比如accept(), recv()等待数据`(Waiting for the data to be ready)`
* 将数据从内核拷贝到进程中, 比如 accept()接受到请求,recv()接收连接发送的数据后需要复制到内核,再从内核复制到进程用户空间`(Copying the data from the kernel to the process)`
**_对于socket流而言,数据的流向经历两个阶段:_**
@@ -206,7 +224,7 @@ linux下的asynchronous IO其实用得很少。先看一下它的流程:
同步IO VS 异步IO:
概念:
-同步与异步同步和异步关注的是___消息通信机制 ___(synchronous communication/ asynchronous communication)所谓同步,就是在发出一个_调用_时,在没有得到结果之前,该_调用_就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由_调用者_主动等待这个_调用_的结果。而异步则是相反,_调用_在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在_调用_发出后,_被调用者_通过状态、通知来通知调用者,或通过回调函数处理这个调用。
+同步与异步同步和异步关注的是___消息通信机制___(synchronous communication/ asynchronous communication)所谓同步,就是在发出一个_调用_时,在没有得到结果之前,该_调用_就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由_调用者_主动等待这个_调用_的结果。而异步则是相反,_调用_在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在_调用_发出后,_被调用者_通过状态、通知来通知调用者,或通过回调函数处理这个调用。
典型的异步编程模型比如Node.js举个通俗的例子:你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。
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 97%
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"
index 32a6684..04f25ab 100644
--- "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"
@@ -1,3 +1,13 @@
+# 目录
+
+ * [当前环境](#当前环境)
+ * [处理 socket 输入输出流](#处理-socket-输入输出流)
+ * [结果展示](#结果展示)
+ * [请求模型优化](#请求模型优化)
+ * [补充1:TCP客户端与服务端](#补充1:tcp客户端与服务端)
+ * [补充2:UDP客户端和服务端](#补充2:udp客户端和服务端)
+
+
本文转自:https://github.com/jasonGeng88/blog
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
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 98%
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"
index 65d0917..47e6d17 100644
--- "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"
@@ -1,3 +1,13 @@
+# 目录
+
+ * [当前环境](#当前环境)
+ * [代码地址](#代码地址)
+ * [知识点](#知识点)
+ * [获取 socket 连接](#获取-socket-连接)
+ * [完整示例](#完整示例)
+ * [处理连接就绪事件](#处理连接就绪事件)
+
+
本文转载自:[https://github.com/jasonGeng88/blog](https://github.com/jasonGeng88/blog)
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
@@ -474,4 +484,4 @@ public class NioNonBlockingHttpClient {
````

-本文从 nio 的阻塞方式讲起,介绍了阻塞 I/O 与非阻塞 I/O 的区别,以及在 nio 下是如何一步步构建一个 IO 多路复用的模型的客户端。文中需要理解的内容比较多,如果有理解错误的地方,欢迎指正~
\ No newline at end of file
+本文从 nio 的阻塞方式讲起,介绍了阻塞 I/O 与非阻塞 I/O 的区别,以及在 nio 下是如何一步步构建一个 IO 多路复用的模型的客户端。文中需要理解的内容比较多,如果有理解错误的地方,欢迎指正~
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 94%
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"
index 4ec65bc..35be566 100644
--- "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"
@@ -1,3 +1,18 @@
+# 目录
+
+* [目录](#目录)
+ * [阻塞模式 IO](#阻塞模式-io)
+ * [非阻塞 IO](#非阻塞-io)
+ * [NIO.2 异步 IO](#nio2-异步-io)
+ * [1、返回 Future 实例](#1、返回-future-实例)
+ * [2、提供 CompletionHandler 回调函数](#2、提供-completionhandler-回调函数)
+ * [AsynchronousFileChannel](#asynchronousfilechannel)
+ * [AsynchronousServerSocketChannel](#asynchronousserversocketchannel)
+ * [AsynchronousSocketChannel](#asynchronoussocketchannel)
+ * [Asynchronous Channel Groups](#asynchronous-channel-groups)
+ * [小结](#小结)
+
+
# 目录
* [阻塞模式 IO](#阻塞模式-io)
* [非阻塞 IO](#非阻塞-io)
@@ -32,7 +47,7 @@
上一篇文章介绍了 Java NIO 中 Buffer、Channel 和 Selector 的基本操作,主要是一些接口操作,比较简单。
-本文将介绍**非阻塞 IO** 和**异步 IO**,也就是大家耳熟能详的 NIO 和 AIO。很多初学者可能分不清楚异步和非阻塞的区别,只是在各种场合能听到**异步非阻塞**这个词。
+本文将介绍**非阻塞 IO**和**异步 IO**,也就是大家耳熟能详的 NIO 和 AIO。很多初学者可能分不清楚异步和非阻塞的区别,只是在各种场合能听到**异步非阻塞**这个词。
本文会先介绍并演示阻塞模式,然后引入非阻塞模式来对阻塞模式进行优化,最后再介绍 JDK7 引入的异步 IO,由于网上关于异步 IO 的介绍相对较少,所以这部分内容我会介绍得具体一些。
@@ -160,7 +175,7 @@ select 和 poll 都有一个共同的问题,那就是**它们都只会告诉
**epoll**:2002 年随 Linux 内核 2.5.44 发布,epoll 能直接返回具体的准备好的通道,时间复杂度 O(1)。
-除了 Linux 中的 epoll,2000 年 FreeBSD 出现了 **Kqueue**,还有就是,Solaris 中有 **/dev/poll**。
+除了 Linux 中的 epoll,2000 年 FreeBSD 出现了**Kqueue**,还有就是,Solaris 中有**/dev/poll**。
> 前面说了那么多实现,但是没有出现 Windows,Windows 平台的非阻塞 IO 使用 select,我们也不必觉得 Windows 很落后,在 Windows 中 IOCP 提供的异步 IO 是比较强大的。
@@ -239,13 +254,13 @@ More New IO,或称 NIO.2,随 JDK 1.7 发布,包括了引入异步 IO 接
**在 Unix/Linux 等系统中,JDK 使用了并发包中的线程池来管理任务**,具体可以查看 AsynchronousChannelGroup 的源码。
-在 Windows 操作系统中,提供了一个叫做 [I/O Completion Ports](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365198.aspx) 的方案,通常简称为 **IOCP**,操作系统负责管理线程池,其性能非常优异,所以**在 Windows 中 JDK 直接采用了 IOCP 的支持**,使用系统支持,把更多的操作信息暴露给操作系统,也使得操作系统能够对我们的 IO 进行一定程度的优化。
+在 Windows 操作系统中,提供了一个叫做[I/O Completion Ports](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365198.aspx)的方案,通常简称为**IOCP**,操作系统负责管理线程池,其性能非常优异,所以**在 Windows 中 JDK 直接采用了 IOCP 的支持**,使用系统支持,把更多的操作信息暴露给操作系统,也使得操作系统能够对我们的 IO 进行一定程度的优化。
> 在 Linux 中其实也是有异步 IO 系统实现的,但是限制比较多,性能也一般,所以 JDK 采用了自建线程池的方式。
本文还是以实用为主,想要了解更多信息请自行查找其他资料,下面对 Java 异步 IO 进行实践性的介绍。
-总共有三个类需要我们关注,分别是 **AsynchronousSocketChannel**,**AsynchronousServerSocketChannel** 和 **AsynchronousFileChannel**,只不过是在之前介绍的 FileChannel、SocketChannel 和 ServerSocketChannel 的类名上加了个前缀 **Asynchronous**。
+总共有三个类需要我们关注,分别是**AsynchronousSocketChannel**,**AsynchronousServerSocketChannel**和**AsynchronousFileChannel**,只不过是在之前介绍的 FileChannel、SocketChannel 和 ServerSocketChannel 的类名上加了个前缀**Asynchronous**。
Java 异步 IO 提供了两种使用方式,分别是返回 Future 实例和使用回调函数。
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 97%
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"
index 8a4ec27..41852cd 100644
--- "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"
@@ -1,3 +1,14 @@
+# 目录
+
+ * [为什么要 I/O 多路复用](#为什么要-io-多路复用)
+ * [select](#select)
+ * [poll](#poll)
+ * [epoll](#epoll)
+ * [epoll_create 用来创建一个 epoll 描述符:](#epoll_create-用来创建一个-epoll-描述符:)
+ * [epoll_ctl 用来增/删/改内核中的事件表:](#epoll_ctl-用来增删改内核中的事件表:)
+ * [epoll_wait 用来等待事件](#epoll_wait-用来等待事件)
+
+
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
> https://github.com/h2pl/Java-Tutorial
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 99%
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"
index 2a3740d..7404a6e 100644
--- "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"
@@ -1,3 +1,17 @@
+# 目录
+
+* [目录](#目录)
+ * [前言](#前言)
+ * [源码环境准备](#源码环境准备)
+ * [endpoint](#endpoint)
+ * [init 过程分析](#init-过程分析)
+ * [start 过程分析](#start-过程分析)
+ * [Acceptor](#acceptor)
+ * [Poller](#poller)
+ * [processKey](#processkey)
+ * [总结](#总结)
+
+
# 目录
* [前言](#前言)
* [源码环境准备](#源码环境准备)
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 98%
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"
index e21ceef..f2d39e8 100644
--- "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"
@@ -1,3 +1,23 @@
+# 目录
+
+* [目录](#目录)
+ * [Netty概述](#netty概述)
+ * [Netty简介](#netty简介)
+ * [Netty都有哪些组件?](#netty都有哪些组件?)
+ * [Netty是如何处理连接请求和业务逻辑的呢?](#netty是如何处理连接请求和业务逻辑的呢?)
+ * [如何配置一个Netty应用?](#如何配置一个netty应用?)
+ * [Netty是如何处理数据的?](#netty是如何处理数据的?)
+ * [如何处理我们的业务逻辑?](#如何处理我们的业务逻辑?)
+ * [ByteBuf](#bytebuf)
+ * [Channel](#channel)
+ * [ChannelHandler](#channelhandler)
+ * [ChannelPipeline](#channelpipeline)
+ * [EventLoop](#eventloop)
+ * [Bootstrap](#bootstrap)
+ * [Echo示例](#echo示例)
+ * [参考文献](#参考文献)
+
+
# 目录
* [Netty概述](#netty概述)
* [etty简介](#etty简介)
@@ -169,7 +189,7 @@ Encoders和Decoders
因为我们在网络传输时只能传输字节流,因此,在发送数据之前,我们必须把我们的message型转换为bytes,与之对应,我们在接收数据后,必须把接收到的bytes再转换成message。我们把bytes to message这个过程称作Decode(解码成我们可以理解的),把message to bytes这个过程成为Encode。
-Netty中提供了很多现成的编码/解码器,我们一般从他们的名字中便可知道他们的用途,如**ByteToMessageDecoder**、**MessageToByteEncoder**,如专门用来处理Google Protobuf协议的**ProtobufEncoder**、 **ProtobufDecoder**。
+Netty中提供了很多现成的编码/解码器,我们一般从他们的名字中便可知道他们的用途,如**ByteToMessageDecoder**、**MessageToByteEncoder**,如专门用来处理Google Protobuf协议的**ProtobufEncoder**、**ProtobufDecoder**。
我们前面说过,具体是哪种Handler就要看它们继承的是InboundAdapter还是OutboundAdapter,对于**Decoders**,很容易便可以知道它是继承自**ChannelInboundHandlerAdapter**或 ChannelInboundHandler,因为解码的意思是把ChannelPipeline**传入的bytes解码成我们可以理解的message**(即Java Object),而ChannelInboundHandler正是处理Inbound Event,而Inbound Event中传入的正是字节流。Decoder会覆盖其中的“ChannelRead()”方法,在这个方法中来调用具体的decode方法解码传递过来的字节流,然后通过调用ChannelHandlerContext.fireChannelRead(decodedMessage)方法把编码好的Message传递给下一个Handler。与之类似,Encoder就不必多少了。
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 96%
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"
index 020f65f..5d47624 100644
--- "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"
@@ -1,3 +1,22 @@
+# 目录
+
+* [目录](#目录)
+ * [Buffer](#buffer)
+ * [position、limit、capacity](#position、limit、capacity)
+ * [初始化 Buffer](#初始化-buffer)
+ * [填充 Buffer](#填充-buffer)
+ * [提取 Buffer 中的值](#提取-buffer-中的值)
+ * [mark() & reset()](#mark--reset)
+ * [rewind() & clear() & compact()](#rewind--clear--compact)
+ * [Channel](#channel)
+ * [FileChannel](#filechannel)
+ * [SocketChannel](#socketchannel)
+ * [ServerSocketChannel](#serversocketchannel)
+ * [DatagramChannel](#datagramchannel)
+ * [Selector](#selector)
+ * [小结](#小结)
+
+
# 目录
* [Buffer](#buffer)
* [position、limit、capacity](#position、limit、capacity)
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 95%
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"
index f50c0df..8256703 100644
--- "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"
@@ -1,3 +1,30 @@
+# 目录
+
+* [目录](#目录)
+* [mmap基础概念](#mmap基础概念)
+* [mmap内存映射原理](#mmap内存映射原理)
+* [mmap和常规文件操作的区别](#mmap和常规文件操作的区别)
+* [mmap优点总结](#mmap优点总结)
+* [mmap使用细节](#mmap使用细节)
+ * [堆外内存](#堆外内存)
+ * [在讲解DirectByteBuffer之前,需要先简单了解两个知识点](#在讲解directbytebuffer之前,需要先简单了解两个知识点)
+ * [java引用类型,因为DirectByteBuffer是通过虚引用(Phantom Reference)来实现堆外内存的释放的。](#java引用类型,因为directbytebuffer是通过虚引用phantom-reference来实现堆外内存的释放的。)
+ * [关于linux的内核态和用户态](#关于linux的内核态和用户态)
+ * [DirectByteBuffer ———— 直接缓冲](#directbytebuffer--直接缓冲)
+ * [DirectByteBuffer堆外内存的创建和回收的源码解读](#directbytebuffer堆外内存的创建和回收的源码解读)
+ * [堆外内存分配](#堆外内存分配)
+ * [Bits.reserveMemory(size, cap) 方法](#bitsreservememorysize-cap-方法)
+ * [堆外内存回收](#堆外内存回收)
+ * [通过配置参数的方式来回收堆外内存](#通过配置参数的方式来回收堆外内存)
+ * [堆外内存那些事](#堆外内存那些事)
+ * [使用堆外内存的原因](#使用堆外内存的原因)
+ * [什么情况下使用堆外内存](#什么情况下使用堆外内存)
+ * [堆外内存 VS 内存池](#堆外内存-vs-内存池)
+ * [堆外内存的特点](#堆外内存的特点)
+ * [堆外内存的一些问题](#堆外内存的一些问题)
+ * [参考文章](#参考文章)
+
+
# 目录
* [mmap基础概念](#mmap基础概念)
* [mmap内存映射原理](#mmap内存映射原理)
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 97%
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"
index 02dc4e4..550f7ab 100644
--- "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"
@@ -1,3 +1,22 @@
+# 目录
+
+* [目录](#目录)
+ * [概述](#概述)
+ * [Selector的中的重要属性](#selector的中的重要属性)
+ * [Selector 源码解析](#selector-源码解析)
+ * [1、Selector的构建](#1、selector的构建)
+ * [接下来看下 selector.open():](#接下来看下-selectoropen:)
+ * [EPollSelectorImpl](#epollselectorimpl)
+ * [EPollArrayWrapper](#epollarraywrapper)
+ * [ServerSocketChannel的构建](#serversocketchannel的构建)
+ * [将ServerSocketChannel注册到Selector](#将serversocketchannel注册到selector)
+ * [EPollSelectorImpl. implRegister](#epollselectorimpl-implregister)
+ * [Selection操作](#selection操作)
+ * [epoll原理](#epoll原理)
+ * [后记](#后记)
+ * [参考文章](#参考文章)
+
+
# 目录
* [概述](#概述)
* [Selector的中的重要属性](#selector的中的重要属性)
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 95%
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"
index ad909d5..65f5206 100644
--- "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"
@@ -1,3 +1,16 @@
+# 目录
+
+* [目录](#目录)
+ * [一、I/O复用模型解读](#一、io复用模型解读)
+ * [二、TOMCAT对IO模型的支持](#二、tomcat对io模型的支持)
+ * [三、TOMCAT中NIO的配置与使用](#三、tomcat中nio的配置与使用)
+ * [四、NioEndpoint组件关系图解读](#四、nioendpoint组件关系图解读)
+ * [五、NioEndpoint执行序列图](#五、nioendpoint执行序列图)
+ * [六、NioEndpoint源码解读](#六、nioendpoint源码解读)
+ * [七、关于性能](#七、关于性能)
+ * [八、总结](#八、总结)
+
+
# 目录
* [一、I/O复用模型解读](#一、io复用模型解读)
* [二、TOMCAT对IO模型的支持](#二、tomcat对io模型的支持)
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 99%
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"
index e9ff30d..76dfece 100644
--- "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"
@@ -5,9 +5,6 @@
* [相关类](#相关类)
* [扩展](#扩展)
* [参考文章](#参考文章)
-* [微信公众号](#微信公众号)
- * [个人公众号:程序员黄小斜](#个人公众号:程序员黄小斜)
- * [技术公众号:Java技术江湖](#技术公众号:java技术江湖)
本文转载自互联网,侵删
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 98%
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"
index 77b8926..bc23655 100644
--- "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"
@@ -18,9 +18,6 @@
* [3.会话工厂与会话](#3会话工厂与会话)
* [4.运行流程](#4运行流程)
* [测试工程搭建](#测试工程搭建)
- * [微信公众号](#微信公众号-1)
- * [个人公众号:程序员黄小斜](#个人公众号:程序员黄小斜)
- * [技术公众号:Java技术江湖](#技术公众号:java技术江湖)
本文转载自互联网,侵删
@@ -252,7 +249,7 @@ Mybatis通过执行器与Mappered Statement的结合实现与数据库的交互
## 测试工程搭建
-1. 新建maven工程
+1.新建maven工程

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 98%
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"
index fa1490e..5937ec0 100644
--- "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"
@@ -1,3 +1,9 @@
+# 目录
+
+ * [连接器(Connector)](#连接器(connector))
+ * [容器(Container)](#容器(container))
+
+
本文转载自互联网,侵删
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
@@ -187,4 +193,4 @@ Container[] conHosts = engine.findChildren();
定位 Servlet 的流程图:
-
\ No newline at end of file
+
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 96%
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"
index d04ef0d..d6cfa8c 100644
--- "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"
@@ -9,8 +9,6 @@
* [maven目录](#maven目录)
* [Maven常用命令说明](#maven常用命令说明)
* [Maven使用](#maven使用)
- * [[](http://tengj.top/2018/01/01/maven/#%E4%BE%9D%E8%B5%96%E7%9A%84%E9%85%8D%E7%BD%AE "依赖的配置")依赖的配置](#[]httptengjtop20180101mavene4be9de8b596e79a84e9858de7bdae-依赖的配置依赖的配置)
- * [[](http://tengj.top/2018/01/01/maven/#%E4%BE%9D%E8%B5%96%E8%8C%83%E5%9B%B4 "依赖范围")依赖范围](#[]httptengjtop20180101mavene4be9de8b596e88c83e59bb4-依赖范围依赖范围)
* [传递性依赖](#传递性依赖)
* [依赖范围](#依赖范围)
* [Maven和Gradle的比较](#maven和gradle的比较)
@@ -90,7 +88,7 @@ Maven不仅是构建工具,还是一个依赖管理工具和项目管理工具
[](http://upload-images.jianshu.io/upload_images/5811881-7482108a7ff71031.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "image.png")
-三:最后设置一下环境变量,将Maven安装配置到操作系统环境中,主要就是配置M2_HOME 和PATH两项,如图
+三:最后设置一下环境变量,将Maven安装配置到操作系统环境中,主要就是配置M2_HOME和PATH两项,如图
[](http://upload-images.jianshu.io/upload_images/5811881-ffdf167e64415703.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "image.png")
都搞定后,验证一下,打开doc输入 mvn -v如何得到下面信息就说明配置成功了
@@ -187,7 +185,7 @@ name元素生命了一个对于用户更为友好的项目名称,虽然这不
依赖范围就是用来控制依赖和三种classpath(编译classpath,测试classpath、运行classpath)的关系,Maven有如下几种依赖范围:
* compile:编译依赖范围。如果没有指定,就会默认使用该依赖范围。使用此依赖范围的Maven依赖,对于编译、测试、运行三种classpath都有效。典型的例子是spring-code,在编译、测试和运行的时候都需要使用该依赖。
-* test: 测试依赖范围。使用次依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将无法使用此依赖。典型的例子是Jnuit,它只有在编译测试代码及运行测试的时候才需要。
+* test:测试依赖范围。使用次依赖范围的Maven依赖,只对于测试classpath有效,在编译主代码或者运行项目的使用时将无法使用此依赖。典型的例子是Jnuit,它只有在编译测试代码及运行测试的时候才需要。
* provided:已提供依赖范围。使用此依赖范围的Maven依赖,对于编译和测试classpath有效,但在运行时候无效。典型的例子是servlet-api,编译和测试项目的时候需要该依赖,但在运行项目的时候,由于容器以及提供,就不需要Maven重复地引入一遍。
* runtime:运行时依赖范围。使用此依赖范围的Maven依赖,对于测试和运行classpath有效,但在编译主代码时无效。典型的例子是JDBC驱动实现,项目主代码的编译只需要JDK提供的JDBC接口,只有在执行测试或者运行项目的时候才需要实现上述接口的具体JDBC驱动。
* system:系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围完全一致,但是,使用system范围的依赖时必须通过systemPath元素显示地指定依赖文件的路径。由于此类依赖不是通过Maven仓库解析的,而且往往与本机系统绑定,可能构成构建的不可移植,因此应该谨慎使用。systemPath元素可以引用环境变量,如:
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 99%
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"
index 0732005..ee6dffc 100644
--- "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"
@@ -16,9 +16,6 @@
* [5.1 示例一:简单的 JUnit 3.X 测试](#51-示例一:简单的-junit-3x-测试)
* [6 个人建议](#6-个人建议)
* [8 大单元测试框架](#8-大单元测试框架)
-* [微信公众号](#微信公众号)
- * [个人公众号:程序员黄小斜](#个人公众号:程序员黄小斜)
- * [技术公众号:Java技术江湖](#技术公众号:java技术江湖)
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 94%
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"
index 8384ba1..e98f6e8 100644
--- "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"
@@ -15,9 +15,6 @@
* [Spring Boot 支持 JSP](#spring-boot-支持-jsp)
* [集成 MyBatis](#集成-mybatis)
* [springMVC和springboot的区别](#springmvc和springboot的区别)
-* [微信公众号](#微信公众号)
- * [个人公众号:程序员黄小斜](#个人公众号:程序员黄小斜)
- * [技术公众号:Java技术江湖](#技术公众号:java技术江湖)
本文转载自互联网,侵删
@@ -120,7 +117,7 @@ public class HelloController {
@RequestMapping("/hello") public String hello() { return "Hello Spring Boot!"; }}
```
-* **@RestController 注解:** 该注解是 @Controller 和 @ResponseBody 注解的合体版
+* **@RestController 注解:**该注解是 @Controller 和 @ResponseBody 注解的合体版
#### 第三步:利用 IDEA 启动 Spring Boot
@@ -163,7 +160,7 @@ public class HelloController {
org.springframework.boot spring-boot-maven-plugin
```
-我们可以看到一个比较陌生一些的标签 `` ,这个标签是在配置 Spring Boot 的父级依赖:
+我们可以看到一个比较陌生一些的标签``,这个标签是在配置 Spring Boot 的父级依赖:
```
@@ -176,12 +173,12 @@ public class HelloController {
#### 应用入口类
-Spring Boot 项目通常有一个名为 *Application 的入口类,入口类里有一个 main 方法, **这个 main 方法其实就是一个标准的 Javay 应用的入口方法。**
+Spring Boot 项目通常有一个名为 *Application 的入口类,入口类里有一个 main 方法,**这个 main 方法其实就是一个标准的 Javay 应用的入口方法。**
-**@SpringBootApplication** 是 Spring Boot 的核心注解,它是一个组合注解,该注解组合了:**@Configuration、@EnableAutoConfiguration、@ComponentScan;** 若不是用 @SpringBootApplication 注解也可以使用这三个注解代替。
+**@SpringBootApplication**是 Spring Boot 的核心注解,它是一个组合注解,该注解组合了:**@Configuration、@EnableAutoConfiguration、@ComponentScan;**若不是用 @SpringBootApplication 注解也可以使用这三个注解代替。
* 其中,**@EnableAutoConfiguration 让 Spring Boot 根据类路径中的 jar 包依赖为当前项目进行自动配置**,例如,添加了 spring-boot-starter-web 依赖,会自动添加 Tomcat 和 Spring MVC 的依赖,那么 Spring Boot 会对 Tomcat 和 Spring MVC 进行自动配置。
-* **Spring Boot 还会自动扫描 @SpringBootApplication 所在类的同级包以及下级包里的 Bean** ,所以入口类建议就配置在 grounpID + arctifactID 组合的包名下(这里为 cn.wmyskxz.springboot 包)
+* **Spring Boot 还会自动扫描 @SpringBootApplication 所在类的同级包以及下级包里的 Bean**,所以入口类建议就配置在 grounpID + arctifactID 组合的包名下(这里为 cn.wmyskxz.springboot 包)
#### Spring Boot 的配置文件
@@ -209,7 +206,7 @@ Spring Boot 的全局配置文件的作用是对一些默认配置的配置值

-* **注意:** 我们并没有在 yml 文件中注明属性的类型,而是在使用的时候定义的。
+* **注意:**我们并没有在 yml 文件中注明属性的类型,而是在使用的时候定义的。
你也可以在配置文件中使用当前配置:
@@ -219,7 +216,7 @@ Spring Boot 的全局配置文件的作用是对一些默认配置的配置值

-* **问题:** 这样写配置文件繁琐而且可能会造成类的臃肿,因为有许许多多的 @Value 注解。
+* **问题:**这样写配置文件繁琐而且可能会造成类的臃肿,因为有许许多多的 @Value 注解。
> * 封装配置信息
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 97%
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"
index 1b37c95..7556dc4 100644
--- "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"
@@ -1,5 +1,4 @@
# 目录
-
* [引言](#引言)
* [工作原理原型图](#工作原理原型图)
* [工作原理解析](#工作原理解析)
@@ -8,9 +7,6 @@
* [MyBatis的配置](#mybatis的配置)
* [MyBatis的主要成员](#mybatis的主要成员)
* [参考文章](#参考文章)
-* [微信公众号](#微信公众号)
- * [个人公众号:程序员黄小斜](#个人公众号:程序员黄小斜)
- * [技术公众号:Java技术江湖](#技术公众号:java技术江湖)
本系列文章将整理到我在GitHub上的《Java面试指南》仓库,更多精彩内容请到我的仓库里查看
diff --git "a/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" "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"
new file mode 100644
index 0000000..26e828a
--- /dev/null
+++ "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"
@@ -0,0 +1,621 @@
+# Spring ܵ AOP
+
+## Spring ܵ AOP
+
+Spring ܵһؼ**ı**(AOP)ܡıҪѳֽɲͬIJֳΪνĹע㡣һӦóĶĹܱΪ**йע**Щйעڸ϶Ӧóҵиָĺܺõӣ־¼ơʽȫԺͻȡ
+
+ OOP УؼԪģ࣬ AOP еԪģ档עӦóϣAOP ӰĶжԺйעAOP DZԵĴ Perl.NETJava ԡ
+
+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 ܹʱ֣
+
+* һʽǸȤĸִС
+
+* һǩһƺIJDzɵģʵӦǿյġ
+
+ʾжһΪ 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\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" "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"
new file mode 100644
index 0000000..c4de431
--- /dev/null
+++ "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"
@@ -0,0 +1,183 @@
+### ע
+
+SpringܵĺĹ
+
+* SpringΪеJavaЩJavaΪBean
+* SpringBean֮ϵSpringʹһֱΪ"ע"ķʽBean֮ϵ
+
+ʹע룬ΪBeanעֵͨעBeanáעһĽʽBeanļ֯һ𣬶Ӳķʽһ
+
+#### ע
+
+Rod Johnsonǵһ߶ļJavaʵЭϵˣַʽһ֣ƷתInverse of ControlIoCMartine FowlerΪַʽһƣע루Dependency Injection˲ע룬ǿƷת京ȫͬijJavaߣҪһJavaķʱڴͳģʽͨ
+
+1. ԭʼ: ****Ȼٵñķ
+2. ģʽ: ҵĹȻ****ͨȥȡٵñķ
+
+ע****֣Ȼᵼµ뱻ʵӲϣdzĿάʹ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Ҫ£ٿBeanBeanSpring˵ҪľǸļBeanʵBeanʵķ"ע"νIoCıʡ
+
+#### Bean
+
+ͨSpringһBeanʵʱBeanʵʵΪBeanָضSpring֧
+
+1. singleton: ģʽSpring IoCУsingletonBeanֻһʵ
+2. prototype: ÿͨgetBean()ȡprototypeBeanʱһµBeanʵ
+3. request: һHTTPrequestBeanֻһʵζţͬһHTTPڣÿBeanõͬһʵֻWebӦʹSpringʱЧ
+4. session bean ĶΪ HTTP Ự ֻweb-aware Spring ApplicationContextЧ
+5. global session: ÿȫֵHTTP SessionӦһBeanʵڵ͵£ʹportlet contextʱЧֻͬWebӦЧ
+
+ָBeanSpringĬʹsingletonprototypeBeanĴٴ۱ȽϴsingletonBeanʵһɹͿظʹáˣӦþ⽫Beanóprototype
+
+### ʹԶװעBean
+
+SpringԶװBeanBean֮ϵʹrefʽָBeanSpringXMLļݣijֹΪBeanע뱻Bean
+SpringԶװͨ` `Ԫص`default-autowire`ָԶļеBeanãҲͨ` `Ԫص`autowire`ָֻԸBeaná
+
+`autowire``default-autowire`Խֵ
+
+* `no`: ʹԶװ䡣BeanͨrefԪض塣ĬãڽϴIJвıãʽúܹõϵ
+* `byName`: setterԶװ䡣SpringȫBeanҳidsetterȥsetǰСдĸͬBeanע롣ûҵƥBeanʵSpringκע롣
+* `byType`: setterβԶװ䡣SpringеȫBeanһBeansetterβƥ䣬ԶעBeanҵBean׳һ쳣ûҵBeanʲôᷢsetterᱻá
+* `constructor`: byTypeƣԶƥ乹IJǡҵһ빹ƥBean׳һ쳣
+* `autodetect`: SpringBeanڲṹоʹconstructorbyTypeԡҵһĬϵĹ캯ôͻӦbyTypeԡ
+
+**һBeanʹԶװʹrefʽָʱʽָԶװڴ͵ӦãʹԶװ䡣ȻʹԶװɼļĹϵԺԡϵװԴļͣBeanBean֮Ͻ͵Σڸ߲ν**
+
+
+
+## Bean3ַʽ
+
+### ʹùBeanʵ
+
+ʹùBeanʵùע룬SpringײBeanʵҪBeanṩĹ
+
+ĬϵĹBeanʵSpringBeanʵִĬϳʼеĻ͵ֵʼΪ0falseе͵ֵʼΪnull
+
+### ʹþ̬Bean
+
+ʹþ̬BeanʵʱclassҲָʱclassԲָBeanʵʵ࣬Ǿ̬࣬Spring֪ͨĸBeanʵ
+
+֮⣬Ҫʹfactory-methodָ̬Springþ̬һBeanʵһָBeanʵSpringĴͨBeanʵȫһ̬Ҫʹ` `Ԫָ̬IJ
+
+### ʵBean
+
+ʵ뾲ֻ̬һͬþֻ̬ʹù༴ɣʵҪʵʹʵʱBeanʵ` `Ԫclassԣʵʹ`factory-bean`ָʵ
+ʵBean` `ԪʱҪָԣ
+
+* factory-bean: ԵֵΪBeanid
+* factory-method: ָʵĹ
+
+ʵʱҪʹ` `Ԫȷֵ
+
+## ЭͬBean
+
+singletonBeanprototypeBeanʱͬԭΪSpringʼʱԤʼе`singleton Bean``singleton Bean``prototype Bean`Springڳʼ`singleton Bean`֮ǰȴ`prototypeBean`ȻŴ`singleton Bean`ォ`prototype Bean`ע`singleton Bean`
+ͬķ֣
+
+* ע: singletonBeanÿҪprototypeBeanʱµBeanʵɱ֤ÿע`prototype Bean`ʵµʵ
+* ÷ע: עͨʹlookupע룬ʹlookupעSpringдBeanij巽زBeanĽҵBeanͨһ`non-singleton Bean`SpringͨʹJDK̬cglibĿͻ˵Ķ룬ӶʵҪ
+
+õڶַʹ÷ע롣Ϊʹlookupע룬Ҫ
+
+1. BeanʵඨΪ࣬һȡBean
+2. ` `Ԫ` `ԪSpringΪBeanʵʵָij
+
+**_ע⣺_**
+
+> Springʱ̬ǿķʽʵ` `ԪָijĿʵֹӿڣSpringJDK̬ʵָó࣬Ϊ֮ʵֳĿûʵֹӿڣSpringcglibʵָó࣬Ϊ֮ʵֳSpring4.0spring-core-xxx.jarѾcglib⡣
+
+## ֺ
+
+Springṩֳõĺ
+
+* Bean: ֺBeanкBeanжǿ
+* : ֺIoCкǿܡ
+
+### Bean
+
+BeanһBeanBeanṩidԣҪеBeanִкΪеĿBeanɴȣBeanΪBeanBeanBeanʵɹ֮BeanʵнһǿBeanʵ`BeanPostProcessor`ӿڣͬʱʵָýӿڵ
+
+1. `Object postProcessBeforeInitialization(Object bean, String name) throws BeansException`: ÷ĵһϵͳкBeanʵڶǸBeanid
+2. `Object postProcessAfterinitialization(Object bean, String name) throws BeansException`: ÷ĵһϵͳкBeanʵڶǸBeanid
+
+һעBeanBeanͻԶÿ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淶AnnotationSpringֱӽǣڶSpringBeanΪǶηκԡǰεķʱBeanijʼεķʱBean֮ǰķ
+
+### Spring4.0ǿԶװ;ȷװ
+
+Springṩ`@Autowired`עָԶװ䣬`@Autowired`setterͨʵȡʹ`@Autowired`עsetterʱĬϲbyTypeԶװԡֲ£Զװ͵ĺѡBeanʵжʱͿ쳣Ϊʵ־ȷԶװ䣬Springṩ`@Qualifier`ע⣬ͨʹ`@Qualifier`BeanidִԶװ䡣
+
+# ο
+
+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\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" "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"
new file mode 100644
index 0000000..69bfc96
--- /dev/null
+++ "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"
@@ -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 ϣ WebSphereJBossTomcat ȣͿʹ 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`ԷDzJDBCˣͨ£ǻʵһ`JdbcTemplate`˼壬Ҫʹ[Templateģʽ](https://www.liaoxuefeng.com/wiki/1252599548343744/1281319636041762)
+
+дʾ߲ԴʱǿƼʹ[HSQLDB](http://hsqldb.org/)ݿ⣬һJavaдĹϵݿ⣬ڴģʽļģʽУֻһjardzʺʾ߲Դ롣
+
+ʵʹΪȴ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ԴĹʼݿдһBeanSpringʱԶһ`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Զͷ:
+ // ڲֶPreparedStatementResultSettry(...)ͷ:
+ 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ȻκλConnectionIJ
+
+ٿ`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) {
+ // SQLRowMapperʵ:
+ 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()`IJȻSQLSQLԼ`RowMapper`ʵֱʹSpringṩ`BeanPropertyRowMapper`ݿĽṹǡúJavaBeanһ£ô`BeanPropertyRowMapper`ͿֱӰһм¼תΪJavaBean
+
+ִеIJDzѯDz롢ºɾôҪʹ`update()`
+
+```
+public void updateUser(User user) {
+ // SQLSQLظµ:
+ 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`ʵJDBCJavaת
+
+ܽһ`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Ĺ̾ORMObject-Relational MappingORMȿѼ¼תJavaҲJavaתΪм¼
+
+ʹ`JdbcTemplate``RowMapper`ԿԭʼORMҪʵָԶORMѡORMܣ[Hibernate](https://hibernate.org/)
+
+SpringмHibernate
+
+HibernateΪORMܣ`JdbcTemplate`HibernateȻҪJDBCԣҪJDBCӳأԼHibernateMavenУǼ
+
+* 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ʹõݿHSQLDBHibernateʹһHQLIJѯ䣬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ʱҪʹû͵ԣʹðװͣLongInteger
+
+Ƶģٶһ`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áͨSpringHibernateʱҲҪ`hibernate.cfg.xml`ļһ仰ܽ
+
+ʹSpringHibernateJPAע⣬κζXMLá
+
+`User``Book`ORMJava Bean֮ͨΪEntity Bean
+
+`user`ɾIJ顣ΪʹHibernateˣҪģʵǶ`User`JavaBeanСɾIJ顱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дĴַǸָIJѯ`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мHibernateHibernateǵһ㷺ʹõORMܣǺܶС黹˵JPAJava Persistence APIɶ
+
+JPA֮ǰҪעJavaEE1999ͷˣServletJMSƽ̨ͬJavaڷdzڱУҸѽӿڶˣȻԻؼҸɻȥʵֽӿڣûͿڲͬijṩIJƷѡлΪûдʱֻҪýӿڣҪþĵײʵ֣JDBC
+
+JPAJavaEEһORMʵʵHibernateûɶ𣬵ûʹJPAôõľ`jakarta.persistence``org.hibernate`ĵΪJPAֻǽӿڣԣҪѡһʵֲƷJDBCӿںMySQLһ
+
+ʹJPAʱҲȫѡHibernateΪײʵ֣ҲѡJPAṩ[EclipseLink](https://www.eclipse.org/eclipselink/)SpringJPAļɣ֧ѡHibernateEclipseLinkΪʵ֡Ȼ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ӿھ൱ͨJPAHibernate
+
+Ȼ`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;
+}
+
+```
+
+ǻعһJDBCHibernateJPAṩĽӿڣʵϣǵĹϵ£
+
+| JDBC | Hibernate | JPA |
+| --- | --- | --- |
+| DataSource | SessionFactory | EntityManagerFactory |
+| Connection | Session | EntityManager |
+
+`SessionFactory``EntityManagerFactory`൱`DataSource``Session``EntityManager`൱`Connection`ÿҪݿʱҪȡµ`Session``EntityManager`ٹرա
+
+ǣע`UserService`עIJ`EntityManagerFactory``EntityManager`ұע`@PersistenceContext`ѵʹJPA̲߳ͬһ`EntityManager`
+
+ʵעIJ`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 {
+ ...
+}
+
+```
+
+ݿɾĵIJԷֱʹ`persist()``remove()``merge()`ΪEntity Beanʹ÷dzﲻٶ
+
+#### MyBatis
+
+: 2022/11/16 21:07 / Ķ: 601258
+
+* * *
+
+
+
+ʹHibernateJPAݿʱORMɵҪǰResultSetÿһбJava Bean߰Java BeanԶתINSERTUPDATEIJУӶʵ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;
+ }
+
+ /**
+ * ȡUserAddress:
+ */
+ 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);
+ }
+}
+
+```
+
+ΪʵIJѯUserProxy뱣HibernateĵǰSessionǣύSessionԶرգʱٻȡ`getAddress()`ݿ⣬ȡIJһµݡˣORMAttached/Detached״̬ʾǰJava BeanSessionķΧڣSessionһ롱ܶѧȷ״̬仯߽磬ͻɴ`PersistentObjectException`쳣ʽ״̬ʹͨJava Beanڱøӡ
+
+⣬HibernateJPAΪʵּݶݿ⣬ʹHQLJPQLѯһתضݿSQLлݿ⣬һԶתܿ⣬SQLŻ鷳
+
+ORMͨṩ˻棬һΪһͶ档һָһSessionΧڵĻ棬龰ǸѯʱβѯԷͬһʵ
+
+```
+User user1 = session.load(User.class, 123);
+User user2 = session.load(User.class, 123);
+
+```
+
+ָSessionĻ棬һĬϹرգҪֶá漫ݵIJһԣԭSQLdzᵼĸ¡磺
+
+```
+// ߳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ṩJdbcTemplateORMȣҪм
+
+1. ѯҪֶṩMapperʵԱResultSetÿһбΪJava
+2. ɾIJIJбҪֶ룬UserʵΪ[user.id, user.name, user.email]бȽ鷳
+
+JdbcTemplateȷԣÿζȡһݿǻ棬ִеSQLȫȷģȱǴȽϷ`INSERT INTO users VALUES (?,?,?)`Ǹӡ
+
+ԣȫԶORMHibernateдȫ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() { ... }
+}
+
+```
+
+ٻعһHibernateJPA`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_timecreatedAt:
+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);
+
+```
+
+IJ`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СDzXML÷ʽҪ˽ͯЬĶ[ٷĵ](https://mybatis.org/mybatis-3/zh/configuration.html)
+
+ʹMyBatisSQLҪȫдŵִеSQLԼдSQLSQLŻdzҲԱд⸴ӵ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\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" "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"
new file mode 100644
index 0000000..de8dba7
--- /dev/null
+++ "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"
@@ -0,0 +1,713 @@
+# 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.xspring-boot-starter-web Զ hibernate-validator spring-boot 汾 2.3.xҪֶ
+
+
+
+```
+
+ org.hibernate.validator
+ hibernate-validator-parent
+ 6.2.5.Final
+
+
+```
+
+
+
+ web ˵ΪֹǷҵӰ죬 Controller һҪУģ£Ϊʽ
+
+* POSTPUT ʹ 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` עIJԼ`@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)IJУʵԭ
+
+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\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" "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"
new file mode 100644
index 0000000..99987fa
--- /dev/null
+++ "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"
@@ -0,0 +1,849 @@
+
+
+
+
+ڰøٵĴ롢дϵͳ Spring Boot ȻΪ Java Ӧÿʵ Spring Boot ṩڶУ**Զ**ǶһԣSpring Boot һΪԱԶɿ伴á߱ijһܵ 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_ ijʼ`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`ȥȡֵ
+
+
+
+ߣԳСͷ
+ӣ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\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" "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"
new file mode 100644
index 0000000..98c55c3
--- /dev/null
+++ "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"
@@ -0,0 +1,270 @@
+
+
+
+
+# Spring е¼
+
+
+
+2022-05-16 15:29
+
+
+
+
+
+
+
+
+
+## Spring е¼
+
+Ѿ½ Spring ĺ **ApplicationContext** beans ڡ beans ʱApplicationContext ijЩ͵¼磬ʱ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ȻIJһ Spring Ӧó
+
+| | |
+| --- | --- |
+| 1 | һΪ SpringExample ĿڴĿ **src** ļдһ com.tutorialspoint |
+| 2 | ʹ Add External JARs ѡ Spring ⣬ͼ Spring Hello World Example ½ڡ |
+| 3 | com.tutorialspoint д Java HelloWorldCStartEventHandlerCStopEventHandler 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\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" "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"
new file mode 100644
index 0000000..09874af
--- /dev/null
+++ "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"
@@ -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 ݸλ·ԴIJԣ
+
+| ǰ | | ˵ |
+| --- | --- | --- |
+| `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` ӿԴ 磬Ǽijģ壬ضԴȡûĽɫ ԴǾ̬ģȫ `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\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" "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"
new file mode 100644
index 0000000..4515cad
--- /dev/null
+++ "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"
@@ -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 ԪϢͨý飨 XMLProeprties ȣ BeanDefinition
+* IoC ԪϢͨý飨 XMLProeprties ȣ IoC ΪעAOP
+* ⲿãͨԴ ProeprtiesYAML ȣ PropertySource
+* Spring Profileͨⲿãṩ֧
+
+**Extensible XML authoring ȱ**
+
+* ߸ӶȣԱҪϤ XML Schemaspring.handlersspring.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\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" "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"
new file mode 100644
index 0000000..c247c82
--- /dev/null
+++ "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"
@@ -0,0 +1,292 @@
+# 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 аĽӿڣPlatformTransactionManagerTransactionDefinition TransactionStatus
+
+ JAR ĺ jar ij zip ʽѹѹѹļе \org\springframework\transaction Ŀ¼Ŀ¼еļͼ 1 ʾ
+
+
+ͼ 1 Ľӿ
+
+ͼ 1 УעļDZڽҪĺĽӿڡĽӿڵüṩķ¡
+
+#### 1\. PlatformTransactionManager
+
+PlatformTransactionManager ӿ Spring ṩƽ̨ڹýӿṩ¡
+
+* TransactionStatus getTransactionTransactionDefinition definitionڻȡ״̬Ϣ
+* void commitTransactionStatus statusύ
+* void rollbackTransactionStatus statusڻع
+
+ĿУSpring xml õϸϢװ TransactionDefinition УȻͨ getTransaction() ״̬TransactionStatusһIJ
+
+#### 2\. TransactionDefinition
+
+TransactionDefinition ӿ壨ĶṩϢȡķа¡
+
+* String getName()ȡơ
+* int getIsolationLevel()ȡĸ뼶
+* int getPropagationBehavior()ȡĴΪ
+* int getTimeout()ȡijʱʱ䡣
+* boolean isReadOnly()ȡǷֻ
+
+УĴΪָͬһУͬǰʹõΪ 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 γǶ |
+
+УΪԿǷҪԼδ
+
+ͨ£ݵIJѯıԭݣԲҪݵӡĺɾȲûָĴΪ Spring3 ĬϵĴΪ required
+
+#### 3\. TransactionStatus
+
+TransactionStatus ӿ״̬ijһʱ״̬Ϣа 2 ʾ
+
+ 2 IJ
+| | ˵ |
+| --- | --- |
+| 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() ֱڱʾտ
+
+#### 2DAOӿʵ
+
+Ŀ 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 ӿڣת˵ķʵ֣ݲIJͬ DAO Ӧķ
+
+#### 6\. Spring ļ
+
+Ŀ src Ŀ¼´ Spirng ļ applicationContext.xml༭ʾ
+````
+
+
+ ````
+У ǵĵ 613 14 дֱ AOP ռ 4250 дʹ ֪ͨݡ
+
+ 5258 дʹ Ƕ棬е 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 IJѯпԿ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 IJѯпԿеݲûз仯ڳִй׳쳣ύתʧܡɴ˿֪Spring Чˡ
+
+
+ͼ 5 ѯ
+
+# SpringʽAnnotationעⷽʽʵ֣
+
+ [Spring](http://www.voidme.com/spring) Уʹû XML ķʽʵʽ⣬ͨ Annotation עķʽʵʽ
+
+ʹ Annotation ķʽdzֻҪĿ£¡
+
+#### 1 Spring עʾ
+````
+
+````
+#### 2Ҫʹҵ߷ע @Transactional @Transactional IJ @Transactional IJͼ 1 ʾ
+
+
+ͼ 1 @Transactionalб
+
+ͨġ [SpringXMLʵ](http://www.voidme.com/spring/spring-transaction-management-by-xml)̳ת˵İʹ Annotation עķʽʵ Spring ʽ
+
+#### 1\. ע
+
+ Spring ļ applicationContext.xmlĺʾ
+
+
+````
+
+
+
+ ````
+````
+пԿԭļȣֻ֣Ӳע
+
+Ҫעǣѧϰ AOP עⷽʽʱҪļпעָɨЩµע⣬ûпעΪڵ 3335 ֶ 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\345\205\250\345\256\266\346\241\266/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"
new file mode 100644
index 0000000..931264e
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\345\220\210\351\233\206.md"
@@ -0,0 +1,22 @@
+# Spring
+
+
+# SpringԴ
+
+# SpringMVC
+
+# SpringMVC Դ
+
+# SpringBoot
+## springbootǰ
+## springbootĻʹ
+## springbootijע
+## springbootĺ
+## springbootĻԭ
+## springbootԴ
+
+# SpringBoot Դ
+
+# SpringCloud
+# SpringCloud Դ
+
diff --git "a/docs/Spring\345\205\250\345\256\266\346\241\266/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"
new file mode 100644
index 0000000..35623db
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/Spring/Spring\345\256\271\345\231\250\344\270\216IOC.md"
@@ -0,0 +1,157 @@
+IoC Inversion of Control ļдΪƷתһżһ˼룬һҪ̷ָܹƳϡij
+
+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 ֮ǻҪ˽һdzҪĸע롣
+
+ע루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 һIJƷ 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.javą¡
+
+ 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.javą¡
+
+ 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\345\205\250\345\256\266\346\241\266/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"
new file mode 100644
index 0000000..c5b2238
--- /dev/null
+++ "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"
@@ -0,0 +1,724 @@
+# Springע
+## 1
+
+Ƕ֪SpringĵԾIOC+AOPIOCԭʵһSpringSpring 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 IJĬֵΪ 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();
+}
+````
+һַdzbeanʽΪܶ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
+dzټ÷֪һ¾
+
+### 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 IJ
+
+@Lookup ڣ
+
+ԭ bean עԼbean Provider
+
+ɾӵһԭ Spring beanôǼ⣺
+
+ǵĵ Spring bean ηЩԭ Spring bean
+
+ڣProvider ϶һַʽ @Lookup ijЩͨá
+
+ҪעǣspringĬʹõĵbeanҪעԭbeanDzҪĶ
+
+ȣǴһԭ 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 õbeanunqualifiedעϱѡ
+
+````
+@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
+
+ͨӦ˵beanscopeĬ϶ǵģʵspring beanֶֶ֧÷ΧŲͬڡ
+
+ʹ@Scope @Component @Bean ķΧ ǵԭ͡ỰglobalSession һЩԶ巶Χ
+
+ӦöֵΪ
+````
+singleton
+prototype
+request
+session
+application
+websocket
+````
+
+
+````
+@Component
+@Scope("prototype")
+class Engine {}
+````
+ǿһЩrequestsessionwebsocketbeanͨӦǺصģô洢ûϢ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ʱdzá
+
+Լ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\345\205\250\345\256\266\346\241\266/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"
new file mode 100644
index 0000000..e9a041f
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/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 ĵ뷢չ
+
+ڵ J2EEJava EE ƽ̨Ƴ EJB ΪĵĿʽֿʽʵʵĿдֱˣʹøӡӷסǿڳֲѶȴȡ
+
+Rod Johnson 2004 ij顶Expert One-on-One J2EE Development without EJBУ EJB ӷĽṹһķͷֱԸӼķʽ滻
+
+ⱾУRod Johnson ͨһ 3 дĸչʾڲʹ EJB ¹һչ Java ӦóУRod Johnson длṹ룬аõ Java ӿں࣬ ApplicationContextBeanFactory ȡЩĸΪ 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 нܡ
+
+### SpringSpring ջ
+
+ϵ Spring ָ Spring Framework Ϊĵ Spring ջ
+
+ʮķչSpring ѾһӦÿܣչΪһɶͬĿģ飩ɵij켼 Spring FrameworkSpring MVCSpringBootSpring CloudSpring DataSpring 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 ˼ٷװεиӵúʵԭΪԱṩһײάķֲʽϵͳ߰ |
+
+### SpringSpring 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 MVCStruts2 ȿܵϣ
+* ҵṩ˹ͼ¼־Ĺܣ
+* ڳ־ò㻹 MyBatisHibernate JdbcTemplate ȼݿзʡ
+
+ֵ Spring һȫĽЩѾнϺýSpring ظ顣
+
+ϿSpring ܸ Java ԱߵɶȣҵijҲṩõĽڿԴܵ˹㷺Ļӭұֹ˾Ϊ Java Ŀѡܡ
+
+## Spring Framework ص
+
+Spring ܾ¼ص㡣
+
+### ****
+
+Spring һԽжĴϵά Spring
+
+### **㼯ɸ**
+
+Spring ųĿԴܣڲṩ˶Ըܣ Struts2HibernateMyBatis ȣֱ֧֡
+
+### ** Java EE API ʹѶ**
+
+Spring Java EE зdzõһЩ APIJDBCJavaMailԶ̵õȣṩ˷װʹЩ API ӦõѶȴ͡
+
+### **IJ**
+
+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
+
+
+ͼ1Springܹͼ
+
+ͼа Spring ܵģ飬ЩģһҵӦÿڿпԸѡԵʹҪģ顣ֱЩģýмܡ
+
+## 1\. Data Access/Integrationݷʣɣ
+
+ݷʣɲ JDBCORMOXMJMS Transactions ģ飬¡
+
+* JDBC ģ飺ṩһ JBDC ģ壬ʹЩģͳ߳ JDBC 뻹бƣܵ Spring ĺô
+* ORM ģ飺ṩеġ-ϵӳ켯ɵ API JPAJDOHibernate MyBatis ȡһʹ Spring
+* OXM ģ飺ṩһ֧ Object /XML ӳijʵ֣ JAXBCastorXMLBeansJiBX XStream Java ӳ XML ݣ߽XML ӳ Java
+* JMS ģ飺ָ Java Ϣṩһ ϢߡϢߡģڸӼʹ JMSJMS Ӧó֮䣬ֲʽϵͳзϢ첽ͨš
+* Transactions ģ飺ֱ֧̺ʽ
+
+## 2\. Web ģ
+
+Spring Web WebServletWebSocket 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 ContainerSpring ĺ
+
+Spring ĺģ齨Ļ Beans ģ顢Core ģ顢Context ģ SpEL ʽģɣûЩҲ AOPWeb ϲĹܡ¡
+
+* Beans ģ飺ṩ˿ܵĻ֣Ʒתע롣
+* Core ģ飺װ Spring ܵĵײ㲿֣ԴʡתһЩùࡣ
+* Context ģ飺 Core Beans ģĻ֮ϣ Beans ģ鹦ܲԴ֤ʻJava EE ֧֡ڡ¼ȡApplicationContext ӿģĽ㡣
+* SpEL ģ飺ṩǿıʽַ֧֣֧ʺֵãַ֧ʼ顢֧㣬ִ֧ Spring ȡ BeanҲ֧бͶӰѡһбۺϵȡ
+
+## 4\. AOPAspectsInstrumentation Messaging
+
+ Core Container ֮ AOPAspects ģ飬£
+
+* AOP ģ飺ṩʵ֣ṩ־¼ȨơͳƵͨùܺҵļ̬ܶİЩӵҪĴУ˾ְҵͨùܵϡ
+* Aspects ģ飺ṩ AspectJ ļɣһǿҳ̣AOPܡ
+* Instrumentation ģ飺ṩߵֺ֧ʵ֣ضӦ÷ʹá
+* messaging ģ飺Spring 4.0 ԺϢSpring-messagingģ飬ģṩ˶ϢϵṹЭ֧֡
+
+## 5\. Test ģ
+
+Test ģ飺Spring ֧ Junit TestNG ԿܣһṩһЩ Spring IJԹܣڲ Web ʱģ Http Ĺܡ
\ No newline at end of file
diff --git "a/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" "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"
new file mode 100644
index 0000000..b40a369
--- /dev/null
+++ "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"
@@ -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.javaEclipse IDE ̨ʾϢ¡
+ message : Hello World!
+
+ˣǾͳɹ˵һ Spring Ӧó
\ No newline at end of file
diff --git "a/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" "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"
new file mode 100644
index 0000000..c3bce06
--- /dev/null
+++ "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"
@@ -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ʹõijʼ 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\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" "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"
new file mode 100644
index 0000000..009576d
--- /dev/null
+++ "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"
@@ -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 LoggingCommons LoggingLog4JSLF4Jⶼȷ
+
+
+
+
+
+| | кܶ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ģʽʱһЩļ¼ǶʽHibernateSpring 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 BootSpring `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 HookJVM˳ʱ־ϵͳ Ӧó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Բ
+
+
+
+Log4j2Spring `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\345\205\250\345\256\266\346\241\266/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"
new file mode 100644
index 0000000..c699974
--- /dev/null
+++ "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"
@@ -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(Ӧ)
+
+springbeanʹõxmlļһbeanspringbootУΪãspringṩ@Configurationһע
+
+൱ڰѸΪspringxmlļе
+
+@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 ϡ
+
+ڽIJУǽֻÿĻ ˽Ϣƪ¡
+
+### 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Ҳṩʲôʽˣֱûдһжtruefalse
+
+ڸӵǿԴһԶࡣ Ǹ Spring Զ @Conditional һʹã
+
+````
+@Conditional(HibernateCondition.class)
+Properties ditionalProperties() {
+//...
+}
+````
+
+## 5 ܽ
+ڱУǸԶù̲ΪԶԶ bean ṩ
\ No newline at end of file
diff --git "a/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" "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"
new file mode 100644
index 0000000..e22fa00
--- /dev/null
+++ "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"
@@ -0,0 +1,302 @@
+
+
+
+
+# Spring Boot Tomcat
+
+ݽվѸѧϰʼǡܽоղء֤ȷԣʹöķ뱾վأ
+
+
+
+
+
+
+
+
+
+ͨʹSpring BootӦóԴһwarļԲWebСڱУѧϰδWARļTomcat WebвSpring BootӦó
+
+## Spring Boot Servletʼ
+
+ͳIJʽʹ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";
+ }
+}
+
+```
+
+## Ӧó
+
+ڣʹMavenGradleһWARļԲTomcatУԴӦóʾ
+
+Mavenʹ`mvn package`Ӧó ȻWARļĿĿ¼ҵĻͼʾ -
+
+
+
+Gradleʹ`gradle clean build`Ӧó ȻWARļ`build/libs`Ŀ¼ҵ۲˴ĻͼԱõ -
+
+
+
+## Tomcat
+
+ڣTomcatwebappsĿ¼²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\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/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"
new file mode 100644
index 0000000..e0eeb3e
--- /dev/null
+++ "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"
@@ -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ִ һָƶijĻеװá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)ÿĶ˵㣬[ͨHTTPJMXǣʹǿԶ̷ʣ](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ĻServletWebӦó |
+| `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 MVCSpring WebFluxJerseyʹ¶Ķ˵㡣
+
+
+
+
+| ID | ˵ |
+| --- | --- |
+| `heapdump` | һdumpļ HotSpot JVMϣһ `HPROF` ʽļ OpenJ9 JVMϣһ `PHD` ʽļ |
+| `logfile` | ־ļݣ `logging.file.name` `logging.file.path` ѱã ֧ʹHTTP `Range` ͷ־ļIJݡ |
+| `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˵ͨHTTPJMX¶ġ ڶ˵ܰϢӦϸǺʱ¶ǡ
+
+
+
+
+
+ҪıЩ˵㱻¶ʹض `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) |
+| --- | --- |
+
+
+
+
+
+| | ڶ˵㱩¶ʱʵʩԼIJԣעһ `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 Securityclasspathϣû `SecurityFilterChain` beanô `/health` ִ֮actuatorSpring BootԶ֤ȫ 㶨һԶ `SecurityFilterChain` beanSpring 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 BootSpring SecurityĬֵCSRFĬ± ζʹĬϰȫʱҪ `POST`shutdownloggers˵㣩`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 ˵ijý壨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 MVCSpring WebFluxActuatorWeb˵֧
+
+
+
+
+
+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` ע͵ķԶͨJMXWebӦóҲͨHTTP ͨʹJerseySpring MVCSpring WebFlux˵ͨHTTP¶ JerseySpring MVCãʹSpring MVC
+
+
+
+
+
+ӱ¶һһԶ
+
+
+
+
+
+
+
+Java
+
+Kotlin
+
+
+
+
+
+```
+@ReadOperation
+public CustomData getData() {
+ return new CustomData("test", 5);
+}
+
+```
+
+
+
+
+
+
+
+Ҳͨʹ `@JmxEndpoint` `@WebEndpoint` дضĶ˵㡣 Щ˵㱻ǸԵļϡ 磬`@WebEndpoint` ֻͨHTTP¶ͨJMX
+
+
+
+
+
+ͨʹ `@EndpointWebExtension` `@EndpointJmxExtension` дضļչ ЩעṩضIJǿеĶ˵㡣
+
+
+
+
+
+ҪWebܵضܣʵservletSpring `@Controller` `@RestController` ˵㣬DzͨJMXʹòͬWebʱá
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.input)2.7.1\.
+
+
+
+˵ϵIJͨ롣 ͨwebʱЩֵURLIJѯJSON塣 ͨJMXʱӳ䵽MBeanIJС Ĭ£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` Եĵһ |
+| --- | --- |
+
+
+
+
+
+| | Ϊӳ䵽IJʵֶ˵JavaӦ `-parameters` 룬ʵֶ˵KotlinӦ `-java-parameters` 롣 ʹSpring BootGradleʹMaven `spring-boot-starter-parent`⽫Զ |
+| --- | --- |
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.input.conversion)ת
+
+
+
+бҪݸ˵IJԶתΪ͡ ڵò֮ǰͨJMXHTTPյ뱻תΪͣʹ `ApplicationConversionService` ʵԼκ `Converter` `GenericConverter` Bean `@EndpointConverter`
+
+
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.web)2.7.2\. ԶWEB˵
+
+
+
+ `@Endpoint``@WebEndpoint` `@EndpointWebExtension` ԶʹJerseySpring MVCSpring WebFluxͨHTTP JerseySpring 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` עһһ· IJΪһ·ӵ·νС ڵö˵ʱñֵᱻ 벶ʣ·Ԫأһ `@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` һֵӦ״̬200OK ûзһֵӦ״̬204No Content
+
+
+
+
+
+һڵʱûIJ߲ܱתΪͣͲᱻãӦ״̬400Bad Request
+
+
+
+
+
+
+
+##### [](https://springdoc.cn/spring-boot/actuator.html#actuator.endpoints.implementing-custom.web.range-requests)WEB˵ Range
+
+
+
+ʹHTTP rangeһHTTPԴһ֡ ʹSpring MVCSpring Web Fluxʱ `org.springframework.core.io.Resource` IJԶַ֧Χ
+
+
+
+
+
+| | ʹ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 MVCSpring WebFluxĶ˵㡣 ͨʹSpring MVCSpring WebFluxıעӳ䣬 `@RequestMapping` `@GetMapping`˵ID·ǰ ˵ṩSpringWebܸļɣȴ˿ֲԡ Ӧѡ `@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мij `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)IJ֡ |
+| --- | --- |
+
+
+
+
+
+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 stateunready](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`Ӧóڴڲ״̬ʵʵ̽루¶״̬֮ ʵʵ̽루¶˸״̬֮кܴ ӦóڵIJͬΣ̽ʹá
+
+
+
+
+
+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` ļãͻᷢ
+
+
+
+
+
+| | MavenGradleɸļ "[ɹϢ](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` ˵㷢IJϵͳϢϸڼ [`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 MVCSpring WebFluxJersey JerseySpring 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\. ƹ˿
+
+
+
+ڻƵIJ˵ͨʹĬϵ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\. ManagementSSL
+
+
+
+ΪʹԶ˿ʱҲͨʹø `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)
+
+
+
+
+
+| | JDBCR2DBCĿɹ۲ԣ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) ҵDynatraceMicrometerָĵ`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ԶOneAgentDynatrace 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 OperatorKubernetesʱעԶӲԱȡĶ˵URIAPIơ
+
+
+
+
+
+ĬΪ `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ȡ˵URLIJѡͬ
+
+
+
+
+
+* 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ԪʵOneAgentDynatraceԱУöԪݣ磬̻Podḻָꡣ
+
+* Ĭάȡָӵеļֵԡ Micrometerָ˾ͬıǩǽĬdimension
+
+* ʹDynatrace Summary instrumentijЩ£Micrometer Dynatraceעָ걻ܾ Micrometer 1.9.xУͨDynatraceضժҪ⡣ Ϊ `false` ʹMicrometerص1.9.x֮ǰĬΪ ֻڴMicrometer 1.8.xǨƵ1.9.xʱʱſʹá
+
+
+
+
+
+ԲָURIAPIƣʾ £ʹԶõĶ˵㡣
+
+
+
+
+
+
+
+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ơ豸IDURI
+
+
+
+
+
+
+
+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
+
+```
+
+
+
+
+
+
+
+v1APIָ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) ҵΪMicrometerDynatrace 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 IDhttps://micrometer.io/docs/registry/graphite#_hierarchical_name_mapping[ӳ䵽 flat hierarchical name]
+
+
+
+
+
+| | ҪΪ붨 `GraphiteMeterRegistry` ṩԼ `HierarchicalNameMapper` Լ壬ṩһԶõ `GraphiteConfig` `Clock` BeanJavaKotlin```@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` BeanJavaKotlin```@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÷ģclasspathJava 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 Pushgatewayclasspathϣ `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עеؽָͨUDPStatsD 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\. ־¼ָ
+
+
+
+ԶLogbackLog4J2¼ ϸ `log4j2.events.` `logback.events.` meter¹
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.supported.tasks)7.3.5\. ִк͵ָ
+
+
+
+Զʹпõ `ThreadPoolTaskExecutor` `ThreadPoolTaskScheduler` BeanֻܱҪײ `ThreadPoolExecutor` á ָexecutorǣexecutorBeanơ
+
+
+
+
+
+
+
+#### [](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` Ϊǰ
+
+
+
+
+
+DZDZĻָ꼯
+
+
+
+
+
+ҲʹöġԻָꡣ
+
+
+
+
+
+֧»⡣
+
+
+
+
+
+* Cache2k
+
+* Caffeine
+
+* Hazelcast
+
+* κμݵJCacheJSR-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ʾеǰġеġĺС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` beanSpring 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` עᡣ
+
+
+
+
+
+ΪӳشIJָꡣ
+
+
+
+
+
+* `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` ͷDZID `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` κξ̬ ЩʹõDzSpringȫע |
+| --- | --- |
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.metrics.customizing.common-tags)7.5.1\. ǩTag
+
+
+
+ͨñǩһڶлά꣬ʵջȡ ñǩDZԽãʾ
+
+
+
+
+
+
+
+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` ͷDZ
+
+
+
+
+
+
+
+Properties
+
+Yaml
+
+
+
+
+
+```
+management.metrics.enable.example.remote=false
+
+```
+
+
+
+
+
+
+
+per-meterĶơ
+
+
+
+Table 1\. Per-meter customizations
+| Property | ˵ |
+| --- | --- |
+| `management.metrics.enable` | ǷܾضIDMeter ܵ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б ͨṩΪѡ鿴ijضDZϢ磬`/actuator/metrics/jvm.memory.max`
+
+
+
+
+
+| | ʹõӦʹõһ£ļϵͳо淶֡ 仰˵ `jvm.memory.max` PrometheusʾΪ `jvm_memory_max`ΪȻӦʹ `jvm.memory.max` Ϊѡ `metrics` ˵мDZ |
+| --- | --- |
+
+
+
+
+
+ҲURLĩβ `tag=KEY:VALUE` ѯԶDZά??磬`/actuator/metrics/jvm.memory.max?tag=area:nonheap`
+
+
+
+
+
+| | IJֵDZƥDZκӦõıǩͳ _ܺ_ ǰУص `Value` ͳǶѵ Code CacheCompressed 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 observationmetric
+
+
+
+
+
+
+
+
+
+
+
+## [](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` - ZipkintraceҪġ
+
+
+
+
+
+
+
+#### [](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` - WavefronttraceҪġ
+
+
+
+
+
+
+
+#### [](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 MVCSpring WebFluxҲҪʹ `io.zipkin.reporter2:zipkin-sender-urlconnection` |
+| --- | --- |
+
+
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/actuator.html#actuator.micrometer-tracing.tracer-implementations.brave-wavefront)8.3.4\. ʹWavefrontOpenZipkin Brave
+
+
+
+* `io.micrometer:micrometer-tracing-bridge-brave` - ӲMicrometer Observation APIBraveıҪ
+
+* `io.micrometer:micrometer-tracing-reporter-wavefront` - WavefronttraceҪġ
+
+
+
+
+
+
+
+
+
+### [](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\345\205\250\345\256\266\346\241\266/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"
new file mode 100644
index 0000000..0318193
--- /dev/null
+++ "b/docs/Spring\345\205\250\345\256\266\346\241\266/SpringBoot/SpringBoot\347\232\204Starter\346\234\272\345\210\266.md"
@@ -0,0 +1,262 @@
+starterSpringBootеһ·ЧĽĿ̵ĸӳ̶ȣڼŷdzõЧתһƬ£ϸspring boot staterʲôʲô
+
+Spring Boot StarterSpringBootбһָ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ʹõݿJDBCjar
+2. jpa
+3. xxx.xmlһЩϢ
+4. ĵֱ
+
+Ҫעǣ**_ÿ½һҪõjpaĿʱҪظһ_**ҲڵһԼĿʱGoogleԼһ˰ʱ˸ֵ֮jpaˡЩо˻OneNoteνĿĹ̸¼IJԼҪõļݣһٴjpaĿʱͲҪٴȥGoogleˣֻҪűʼٰ֮еļcopy&pasteͿˡ
+
+IJҲ㲻Уʵûstarter֮ǰôɵģм⣺
+
+1. ̱ȽϷһӳĿ
+2. ͣcopy&paste[Dont repeat yourself](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)
+3. ڵһõʱ߱ȽСףҪѵʱ
+
+### ʹSpring Boot StarterЧ
+
+starterҪĿľΪ˽Щ⡣
+
+starterstarterõ˿Լȥ鷳ҪעDzͬstarterΪ˽ͬڲʵֿܻкܴIJ죬jpastarterRedisstarterʵ־ͲһΪstarterısynthesizeһijҲеDockerΪǶһװIJ֪DockerΪ˽ʲôģҲDockerstarterһȡ
+
+starterʵ֣Ȼͬstarterʵв죬ǻ϶ʹõͬݣConfigurationPropertiesAutoConfigurationΪSpring BootšԼáһʹConfigurationPropertiesǵãЩöһĬֵûдԭʼõ£ĬֵͻЧںܶǷdzõġ֮⣬starterConfigurationPropertiesʹеԱۼһļУһresourcesĿ¼µapplication.propertiesǾSpringĿXML
+
+starter
+
+
+
+starterjarԼֶõʱjarûʲôͬǿΪstarterʵǰһЩòԼѼû˰ûȥ˷ĹڡԼá£ConfigurationPropertiesûνòΪ?`application.properties`?ļĴڣʹҪԶãеҲֻҪһļнУʹdz㡣
+
+˽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ӦֻҪmavenstarterSpringBootԶɨ赽ҪصϢӦĬástarterǰ˸ĴҪøϢšSpringBootԶͨclasspath·µҪBeanעIOCSpringBootṩճҵӦзֳ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.jsonspring-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"
+ }
+ ]
+}
+ƴ
+```
+
+##
+
+ҵͼmaveninstallװ 
+
+Ȼ½һĿвԣĿ̾Ͳˡ
+
+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
+* @ConditionalOnMissingBeanbeanʱ,ʵǰBean
+* @ConditionalOnPropertyļ㶨bean
+* @ConditionalOnBeanbeanʱ,ʵǰBean
+* @ConditionalOnClass ·ϴڣʵǰBean
+* @ConditionalOnMissingClass ·ϲڣʵǰBean
+
+
+
+ߣ
+ӣhttps://juejin.cn/post/7127468724046528525
+Դϡ
+ȨСҵתϵȨҵתע
+
diff --git "a/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" "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"
new file mode 100644
index 0000000..c524bd5
--- /dev/null
+++ "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"
@@ -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 ִͿܣӦûһָõķ⡣
+
+Ϊ֤뷨ȷģ200210дһ顶 Expert One-on-One J2EE ˵ʱ Java ҵӦóָ Java EE EJB дڵһЩҪȱݡⱾУһͨ Java עĸĽ
+
+Уչʾڲʹ EJB ¹չλԤϵͳΪ˹Ӧóд˳ 30,000 еĻṹ룬ĿеĸΪ com.interface21ԴΪ interface21Ҳ Spring ǰ
+
+˭أǴ Rod Johnson ͼ, Rod Johnson Ϥѧ˼ѧλͬʱѧλ˳Ծڻص֮ǰѧIJʿѧλ 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 Ŀз20144£Spring Boot 1.0.0
+
+Spring Boot ֮ܵԴijע½һЩ˺ҵʹ 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 ٷҲdz Spring Boot ĺչѾ Spring Boot Ϊ˾Ŀƹ㣬ŵ˹ϵһλã˺ Spring Boot ijչҲá
+
+#
+
+
+
+springspringbootĻ
+
+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ṩspringbeaná
+
+5ṩصԣءָ㡢ȹܣspringbootṩǿ̬ﲻspringbootԼҲһЩⲿ̬
+
+6ڴɣҲҪxmlļ֤springbootĿȣԼüļǽҪapplication.propertiesлòҲspringbootҵ̬ɵĶclassļ
+
+# SpringĹϵ
+
+
+
+## SpringFrameworkʲô⣿
+
+SpringJavaҵ棨Java Enterprise EditionJEEҲJ2EEƷ迪EnterpriseJavaBeanEJBSpringΪҵJavaṩһԼķͨע̣üJavaPlain Old Java ObjectPOJOʵEJBĹܡ
+
+1.ʹSpringIOC,֮ϵSpring,֮,ǸרעӦ
+
+2.ṩڶ,,WSȡ
+
+3.ܺõ֧AOP,̡
+
+4.Ŀṩ˺ܺõļ֧,Hibernate,Struts2,JPA
+
+5.Spring DIƽҵ滻ĸԡ
+
+6.Springڵ,Ⱦ͡
+
+7.Springĸ߶ȿɿ,ǿSpring,߿ѡSpringֻȫ
+
+## SpringFrameworkûнʲô⣿
+
+ȻSpringģȴġһʼSpringXMLãǺܶXMLáSpring 2.5˻עɨ裬˴ӦóʽXMLáSpring 3.0˻JavaãһͰȫĿع÷ʽԴXML
+
+Щö˿ʱġΪ˼Springúͽҵ֮Ҫ˼άлԱдüռ˱дӦóʱ䡣пһSpringʵãͬʱҪĻرҲ١
+
+֮⣬ĿҲһʱ顣ڻʱҪҪЩ꣬һҪ֮ϵ꣬һѡİ汾֮IJͻ谭ĿĿȡ
+
+## SpringBootSpringȱ
+
+SpringBootSpringȱеĸƺŻԼõ˼룬ÿԱҵ֮˼άлȫĵͶ뵽ҵĴдУӶ˿Чʣһ̶Ŀڡ
+
+ʹSpringܽпĹУҪúܶSpringܰspring-corespring-beanspring-contextȣЩͨظӵģҪܶʹüظã翪ע⡢־ȡSpring BootЩҪIJṩĬãȻЩĬǿĵģٴSpringӦ
+
+# SpringMVCĹϵ
+
+
+
+Spring BootSpring BootʹͿʼSpringӦóס ˺ܶ롣 Ļ˺ܶิԣ˿ԱԿֲɿSpringӦó
+
+Spring MVCSpring MVCڹWebӦóWeb MVCܡ ڸֹܵļ һHTTPWebӦóܡ
+
+
+
+Spring BootSpring MVCڲͬĿĶڡ Spring BootSpring MVC֮Ҫ
+
+
+
+| Spring Boot | Spring MVC |
+| --- | --- |
+| Spring BootʹúĬֵSpringӦó | Spring MVCSpring»ģͼWebܡ |
+| ṩĬSpringֵ֧Ŀܡ | ṩڹWebӦóļܡ |
+| ֶá | Ҫֶйá |
+| Ҫ | DZġ |
+| 룬װһԪС | ֱָÿ |
+| ˿ʱ䲢ʡ | ʵͬĿҪʱ䡣 |
+
+# SpringCloudĹϵ
+
+Spring BootSpringijԱһȫµĿܣĿǾܼͿٵĿSpringӦóáΪ߿ݵʹSpringؿṩ˱ĿܣֻΪܵʹҲṩ˺ܺõĽּܡ
+
+
+
+
+ͼߵĻspringbootڹӦãҲdz˵
+
+springcloudڷҲǴЭspringbootӦó
+
+springcloudаڶصAPISpringcloud GatewayConfig Serever·Circuit BreakerעService RegisttySleuth
+
+# ʹSpringboot8ԭ
+
+## Ŀ
+
+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 ΪǶʽ TomcatJetty Undertow ṩ伴õ֧֡ ԱͲصڴͳӦ÷в Web Ӧó ͨʵԽһַ ʵյõһκ JAR һе JAR ļ ʱJAR 㹻ĿΪӦó
+
+ǶʽȤʱ Spring Boot Ӧó JAR תΪ WARDzͳ
+
+## 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 ġ
+
+磬ԶɵIJԽǷȷء
+
+````
+@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 Ӧódz ⣬ͨIJ轫Щ 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/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" "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"
new file mode 100644
index 0000000..247e419
--- /dev/null
+++ "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"
@@ -0,0 +1,108 @@
+# ٹSpringBootӦ
+
+̳springboot㹻ȨҲ㹻
+
+## һ hello world
+
+һġHello WorldκӵĶ˵㡣Ը֣ԸѺõķʽӦ
+
+## Ҫ
+
+1һֵIDE,ѡ IntelliJ IDEASpring ToolsVisual Studio Code Eclipse ȵȡ
+
+2JDKڰ汾Ļ8-17Dzѡ
+
+3ȻﻹҪmavenpomҲҪmavenmavenideaԴˡǻڽIJֽнܣҪЩ
+
+## һһµ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()`ּڻȡһΪnameStringȻ˲еĵ`"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
+
+```
+
+ӦûῴһЩ˷dzƵ
+
+
+иǣ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\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" "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"
new file mode 100644
index 0000000..46c6771
--- /dev/null
+++ "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"
@@ -0,0 +1,2989 @@
+## 1.SpringBootùı
+
+ΪʵֿٴͿĿSpringbootܴspringbootĿԽĿֱӴjarУԼװTomcatһַݵIJʽ
+
+Ŀķʽһjar𣬼ļ͵jarͻ
+
+һĿйУҪĶļĻҪ´
+
+ĿҪͬһ̨ʱԵjarͬĵĿjar100Mܾռ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ⲿļģͼ
+
+
+@PropertySourcevalueֵһclasspathconfigĿ¼µԴļڶǸspring.profiles.path̬ȡĿ¼spring.profiles.pathںļԶһֵļͳһļ·ignoreResourceNotFound=true趨ǰһ·ûҵļݵڶ·ȥҡ
+
+ǻֱӸ·FileSystemResourceȥһļʵͼ
+
+
+ԭƣںļԶͳһĿ¼·ļ
+
+logback־ļطʽ£
+
+
+һʵַ˼·
+
+```
+ - springbootļﶨһspring.profiles.pathֵָļͳһõĿ¼ļҲǷ
+
+ - ļļĵطҲӦûȡspring.profiles.path̬ظ·µļ
+
+ - Pom.xmlļĴģ飬ļųǴjarDzļģοĵڵ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.xmlbuildģͿͨ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ͬĿ¼½configlibļУֱļ͵ȥṹͼ*.shΪԼдĿshellű
+
+
+
+configڵspringbootļapplication-demo1.propertiesļ
+
+spring.profiles.pathijɵǰļڵĿ¼Ϊ/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 ʹһdzر `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.propertiesYAML
+
+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` ˵ȷһΪʲôһضֵʱdzáʹ˵ֵ "[](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` Ὣκѡ `--` ͷIJ `--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` УservletijʼԴ滷ϵͳԣ֮һ |
+| --- | --- |
+
+
+
+
+
+#### [](https://springdoc.cn/spring-boot/features.html#features.external-config.files.optional-prefix)2.3.1\. ѡλ(Optional Locations)
+
+
+
+Ĭ£ָλòʱSpring Boot׳һ `ConfigDataLocationNotFoundException` Ӧó
+
+
+
+
+
+ָһλã㲻Ǵڣʹ `optional:` ǰ `spring.config.locationspring.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` λͬضļڷضļ ָ˼ļʤIJԡ 磬ļ `prod,live` `spring.profiles.active` ָģ`application-prod.properties` еֵԱ `application-live.properties` еֵǡ
+
+
+
+
+
+| | ʤIJ[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 PropertiesYAML [](https://springdoc.cn/spring-boot/features.html#features.external-config.files.configtree) jarṩ֧֣ҪDZļ 磬ⲿ洢ConsulApache ZooKeeperNetflix ArchaiusNacos֧ԼλãʵԼüأ `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Ӧóʱ㾭Ҫȡƽ̨ṩֵ ڴĿIJټȱ㣬رֵ 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 swarmsecretķȨʱ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ûΪֵṩκ֧֣ṩHookmSpring `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/) JSONijֲָݵķʽ ֻҪclasspath [SnakeYAML](https://github.com/snakeyaml/snakeyaml) ⣬`SpringApplication` ͻԶ֧YAMLΪpropertiesƷ
+
+
+
+
+
+| | ʹ StarterSnakeYAML `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` עֵã磬ע ԲIntegerLongUUIDStringʾ
+
+
+
+
+
+
+
+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ֵģã |
+| --- | --- |
+
+
+
+
+
+| | һĬϵι캯gettersetterͨDZģΪͨJava Beans property descriptorJavaʡʵֵģSpring MVCһ £ʡsetter* Map, ֻҪDZʼҪһgetterһҪһsetterΪǿԱͻ䡣 * Collectionarray ͨͨYAMLʹõŷֵָԣʡ ںһ£һsetterDZġ ǽΪһsetter ʼһϣȷDzɱģǰӣ * ǶPOJOԱʼǰе `Security` ֶΣͲҪsetter ðͨʹĬϹ캯ʱʵҪһsetter ЩʹProject LombokԶgettersetter ȷLombokΪκضĹ캯ΪԶʵֻDZJava 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...
+
+ }
+
+}
+
+```
+
+
+
+
+
+
+
+УΨһġ캯ĴζӦʹøù캯а ζŰҵһϣIJĹ캯 ж캯ʹ `@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` ȻʹùעBeanBean `@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` BeanBeanͬķʽעǣʾ
+
+
+
+
+
+
+
+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` һBeanBeanע `@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` Ϊmapkey бѾ `key3` ɾΪûбŰ
+
+
+
+
+
+ֵʱ `.` ļҪ `[]` ֵöٺ `java.lang` еͣ `Object` `a.b=c` `Map` е `.` һ `{"a.b"="c"}` EntryMap κͣ `key` `.` Ҫʹŷš 磬 `a.b=c` `Map` һ `{"a"={"b"="c"}` entryMap `[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` beanBeanΪ `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
+
+
+
+durationSpring 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` ʾ13죩
+
+
+
+
+
+֧мĵλʽ
+
+
+
+
+
+* `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\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" "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"
new file mode 100644
index 0000000..477370a
--- /dev/null
+++ "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"
@@ -0,0 +1,345 @@
+# SpringBoot - Ȳdevtools
+
+> SpringBootУÿдĶҪٵԣܱȽϷʱ䣻SpringBootŶԴṩspring-boot-devtoolsdevtoolsͼԵЧʡ@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ȣӦõһPSspring-boot-devtoolsṩķҲҪģֶֻʵԶضѡ
+
+ϸϣҪȲȼ, JavaĿԣ
+
+* **Ȳ**
+
+ * ڷʱ²Ŀ
+ * ֱ¼Ӧãַʽͷڴ棬ȼظӸɾףͬʱҲʱ䡣
+* **ȼ**
+
+ * ʱ¼classӶӦá
+ * ȼصʵԭҪ[javaػ](/md/java/jvm/java-jvm-classload.html)ʵַʽԸΪʱһ̨̣߳ʱļļʱ仯ʱˣ롣
+ * ԱȷƣʱȡϢ̬ͨĵıΪ ȼʱͨ¼ظıϢֱӸıΪ
+
+### [#](#ʲôliveload) ʲôLiveLoad
+
+LiveLoadṩͻԶظµĹߣΪLiveLoadLiveload֣ 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
+
+°汾IDEAFile->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չ֧ChromeFirefoxSafariԴ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һClassLoaderrestart 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.includeincludeԪӦñߵĿԼ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ҪģSpringJAR
+
+* **Ĭ£ᱻ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.ioProgram 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-propertiesfalseapplication.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ǿͨRebuildCtrl + 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\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" "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"
new file mode 100644
index 0000000..e225d74
--- /dev/null
+++ "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"
@@ -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ṩߵýӿڵĹܡ
+
+?ȱ㣺
+
+* ܴʱܰ㴦е顣ֻṩһߵԣ洢IJʹPostmanYAPIִ֧ûĹܡ
+* ҪѭһЩ淶淶ġ˵ܻ᷵һjsonݣݿһMapʽģôǴʱܱעMapʽķݵÿֶε˵һʵĻǿͨעֶμ˵Ҳ˵swaggerƼʹGETʽύݵʱʹBodyƼʹqueryheader·Ȼֻߵԡ
+* ûнӿĵ¹Ȼһӿڸ֮ܲľɰĽӿϢ㡰ܡ뿴ɰĽӿϢЩҶȸ·ʱܻľɰĽӿڡôʱֻɺȥûעˣԿԿǽӿĵµʱע;ɰģȻд°ġȻͨӿĵԱȡ
+* ȻJavaʵвģͣpo,dto,voȣģ͵ΪһЩһû¼ʱֻҪusername,passwordȨʱҪȨޱϢʹUserʵĻĵоͻԶ˶ϢҪģʵ࣬¼ʱһLoginFormҪû-ȨϢʱʹUserࡣȻˣswagger֮ʹžͻôˡ
+
+?ȱдеܻ࣬swaggerеʵҪǹ淶⣬淶ʱֻĴ淶ԣͼʼˣǰʲôӿڵIJʹһ࣬swaggerҪֿijֲĴ淶ԡ
+
+?ע´ʾSpring BootԲο[swagger-demo](https://github.com/alprogor/swagger-demo)
+
+* * *
+
+# swagger
+
+?ȽswaggerҲϽôʹãġٽ⡣
+
+## 1.
+
+?ע⣬ǰѾspring bootweb
+
+ƴ
+
+```
+
+ io.springfox
+ springfox-swagger2
+ 2.9.2
+
+
+ io.springfox
+ springfox-swagger-ui
+ 2.9.2
+
+
+```
+
+## 2.Swagger:
+
+ҪʹswaggerDZswaggerãҪһ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 uiDzʾģеĻͻʾ
+
+
+## ӿ
+
+ʹ`@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ʽʱʹjsonform-dataȷʽݣʱʹ·url(?ȻPOSTMANֵ֧)ӿڴݵjsonform-dataʽģʹPOSTʽá
+
+### һʵࡣ
+
+ʱҪʹ`@ApiModel`עʵ࣬ȻڽӿжΪʵ༴ɣ
+
+* @ApiModel
+ *
+ * valueʵ
+ * descriptionʵ˵
+* @ApiModelPropertyֶε塣
+ *
+ * valueֶ˵
+ * exampleʾExample ValueĬֵãֶΪstringʱʱʾĬֵΪ"".
+ * nameµֶɵֶ
+ * allowableValuesֵ÷Χ`{1,2,3}`ֻȡֵ`[1,5]`ȡ15ֵ`(1,5)`15ֵ15ʹ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ԶװGETDzҪʹform-datajsonȷʽݲʹPostmanԽӿڣswagger߲Dz֧**
+ڷʵʹ`@ApiImplicitParams``@ApiImplicitParam`
+`@ApiImplicitParams`ڷͷϣ`@ApiImplicitParam``@ApiImplicitParams`棬һ`@ApiImplicitParam`Ӧһ
+`@ApiImplicitParam`
+
+* name֣Ҳֶε,ӿڵӦ**ӦҲɣԿ**
+* value
+* requiredעǷ
+* paramTypepath,query,body,form,headerȷʽڶڷʵʱõֻpath,query,headerbodyformDzõġbodyڶɢֻjsonĽӿ`form-data`,`x-www-form-urlencoded`ʱܲʹswaggerҳAPIԣں潲BootstrapUIswaggerǿеԣBootstrapUIswaggerָ֧`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`ԤbootstarpSwagger UI档
+
+## ŵ
+
+1.?ÿһ
+
+2.˵ˣBootstrapUIswaggerָ֧`form-data``x-www-form-urlencoded`
+
+
+3.ָ֧ƵAPIĵ͵ȫAPIĵ
+
+
+
+
+* * *
+
+# Spring Securityע
+
+Spring BootSpring SecuritySwaggerʱҪص·ͷе·עǷ¼·
+
+ƴ
+
+```
+.antMatchers("/swagger**/**").permitAll()
+.antMatchers("/webjars/**").permitAll()
+.antMatchers("/v2/**").permitAll()
+.antMatchers("/doc.html").permitAll() // bootstarpSwagger 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`עһͷ磺
+
+ƴ
+
+```
+ // ҪIJDZõҪ,Ȩ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 securityshiroˣﲻ
+
+2.DzʽпԷʣʽйرSwaggerԶãͲswaggerҳˡʹ`@Profile({"dev","test"})`עֻdevtestSwaggerԶá
+ȻSpring Bootļĵǰprofile`spring.profiles.active=release`֮ʱ`http://localhost:8080/swagger-ui.html`
+
+* * *
+
+
+
+ߣ[progor](https://www.cnblogs.com/progor/)
+Ϊԭתע
+
diff --git "a/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" "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"
new file mode 100644
index 0000000..813fabe
--- /dev/null
+++ "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"
@@ -0,0 +1,1112 @@
+# Springע
+## 1
+
+Ƕ֪SpringĵԾIOC+AOPIOCԭʵһSpringSpring 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 IJĬֵΪ 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();
+}
+````
+һַdzbeanʽΪܶ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
+dzټ÷֪һ¾
+
+### 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 IJ
+
+@Lookup ڣ
+
+ԭ bean עԼbean Provider
+
+ɾӵһԭ Spring beanôǼ⣺
+
+ǵĵ Spring bean ηЩԭ Spring bean
+
+ڣProvider ϶һַʽ @Lookup ijЩͨá
+
+ҪעǣspringĬʹõĵbeanҪעԭbeanDzҪĶ
+
+ȣǴһԭ 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 õbeanunqualifiedעϱѡ
+
+````
+@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
+
+ͨӦ˵beanscopeĬ϶ǵģʵspring beanֶֶ֧÷ΧŲͬڡ
+
+ʹ@Scope @Component @Bean ķΧ ǵԭ͡ỰglobalSession һЩԶ巶Χ
+
+ӦöֵΪ
+````
+singleton
+prototype
+request
+session
+application
+websocket
+````
+
+
+````
+@Component
+@Scope("prototype")
+class Engine {}
+````
+ǿһЩrequestsessionwebsocketbeanͨӦǺصģô洢ûϢ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ʱdzá
+
+Լ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 IJͬ壬HTTP ѷֱΪGETPOSTPUTDELETE 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) {
+// ...
+}
+````
+⣬ǿͨIJΪ 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
+ڽIJУǽ 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 Ӧ ڽIJУǽġ
+
+### 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(Ӧ)
+
+springbeanʹõxmlļһbeanspringbootУΪãspringṩ@Configurationһע
+
+൱ڰѸΪspringxmlļе
+
+@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 ϡ
+
+ڽIJУǽֻÿĻ ˽Ϣƪ¡
+
+### 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Ҳṩʲôʽˣֱûдһжtruefalse
+
+ڸӵǿԴһԶࡣ Ǹ Spring Զ @Conditional һʹã
+
+````
+@Conditional(HibernateCondition.class)
+Properties ditionalProperties() {
+//...
+}
+````
+
+## 5 ܽ
+ڱУǸԶù̲ΪԶԶ bean ṩ
+
+# ο
+https://www.baeldung.com/spring-annotations
diff --git "a/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" "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"
new file mode 100644
index 0000000..fc25a2c
--- /dev/null
+++ "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"
@@ -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/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\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 96%
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\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"
index 8564da9..96260af 100644
--- "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\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"
@@ -8,7 +8,6 @@
* [2.3、@Import](#23、import)
* [2.4、@Conditional](#24、conditional)
* [2.5、@ConfigurationProperties与@EnableConfigurationProperties](#25、configurationproperties与enableconfigurationproperties)
- * [](#)
* [三、削铁如泥:SpringFactoriesLoader详解](#三、削铁如泥:springfactoriesloader详解)
* [四、另一件武器:Spring容器的事件监听机制](#四、另一件武器:spring容器的事件监听机制)
* [Spring容器内的事件监听机制](#spring容器内的事件监听机制)
@@ -17,9 +16,6 @@
* [6.1 SpringApplication初始化](#61-springapplication初始化)
* [6.2 Spring Boot启动流程](#62-spring-boot启动流程)
* [参考文章](#参考文章)
-* [微信公众号](#微信公众号)
- * [个人公众号:黄小斜](#个人公众号:黄小斜)
- * [技术公众号:Java技术江湖](#技术公众号:java技术江湖)
本文转自互联网,侵删
@@ -806,30 +802,3 @@ public void initialize(ConfigurableApplicationContext context) {
[5][spring boot实战:自动配置原理分析](https://link.jianshu.com/?t=http%3A%2F%2Fblog.csdn.net%2Fliaokailin%2Farticle%2Fdetails%2F49559951):[http://blog.csdn.net/liaokailin/article/details/49559951](https://link.jianshu.com/?t=http%3A%2F%2Fblog.csdn.net%2Fliaokailin%2Farticle%2Fdetails%2F49559951)
[6][spring boot实战:Spring boot Bean加载源码分析](https://link.jianshu.com/?t=http%3A%2F%2Fblog.csdn.net%2Fliaokailin%2Farticle%2Fdetails%2F49107209):[http://blog.csdn.net/liaokailin/article/details/49107209](https://link.jianshu.com/?t=http%3A%2F%2Fblog.csdn.net%2Fliaokailin%2Farticle%2Fdetails%2F49107209)
-
-
-## 微信公众号
-
-### 个人公众号:黄小斜
-
-黄小斜是跨考软件工程的 985 硕士,自学 Java 两年,拿到了 BAT 等近十家大厂 offer,从技术小白成长为阿里工程师。
-
-作者专注于 JAVA 后端技术栈,热衷于分享程序员干货、学习经验、求职心得和程序人生,目前黄小斜的CSDN博客有百万+访问量,知乎粉丝2W+,全网已有10W+读者。
-
-黄小斜是一个斜杠青年,坚持学习和写作,相信终身学习的力量,希望和更多的程序员交朋友,一起进步和成长!
-
-**原创电子书:**
-关注公众号【黄小斜】后回复【原创电子书】即可领取我原创的电子书《菜鸟程序员修炼手册:从技术小白到阿里巴巴Java工程师》
-
-**程序员3T技术学习资源:** 一些程序员学习技术的资源大礼包,关注公众号后,后台回复关键字 **“资料”** 即可免费无套路获取。
-**考研复习资料:** 计算机考研大礼包,都是我自己考研复习时用的一些复习资料,包括公共课和专业的复习视频,这里也推荐给大家,关注公众号后,后台回复关键字 **“考研”** 即可免费获取。
-
-
-
-### 技术公众号:Java技术江湖
-
-如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号【Java技术江湖】一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM、SpringBoot、MySQL、分布式、中间件、集群、Linux、网络、多线程,偶尔讲点Docker、ELK,同时也分享技术干货和学习经验,致力于Java全栈开发!
-
-**Java工程师必备学习资源:** 一些Java工程师常用学习资源,关注公众号后,后台回复关键字 **“Java”** 即可免费无套路获取。
-
-
\ 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 {};
+
+ /**
+ * ɨclassclassڵİᱻɨ裬 @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