Tom哥 пре 2 година
родитељ
комит
4cdcaa2c4e
100 измењених фајлова са 828 додато и 3474 уклоњено
  1. BIN
      1.jpg
  2. 3 187
      README.md
  3. 0 31
      basic-knowledge/HashMap的扩容机制.md
  4. 0 199
      basic-knowledge/Log4j.md
  5. 0 271
      basic-knowledge/NIO.md
  6. 0 73
      basic-knowledge/ThreadLocal.md
  7. 0 237
      basic-knowledge/concurrent-class.md
  8. 0 15
      basic-knowledge/ibatis.md
  9. BIN
      basic-knowledge/img/.DS_Store
  10. BIN
      basic-knowledge/img/1.jpg
  11. BIN
      basic-knowledge/img/10.jpg
  12. BIN
      basic-knowledge/img/11.png
  13. BIN
      basic-knowledge/img/12.png
  14. BIN
      basic-knowledge/img/13.png
  15. BIN
      basic-knowledge/img/15.png
  16. BIN
      basic-knowledge/img/16.png
  17. BIN
      basic-knowledge/img/17.png
  18. BIN
      basic-knowledge/img/18.png
  19. BIN
      basic-knowledge/img/19.png
  20. BIN
      basic-knowledge/img/2.jpg
  21. BIN
      basic-knowledge/img/20.png
  22. BIN
      basic-knowledge/img/20191226162717.gif
  23. BIN
      basic-knowledge/img/21.png
  24. BIN
      basic-knowledge/img/22.png
  25. BIN
      basic-knowledge/img/23.png
  26. BIN
      basic-knowledge/img/24.png
  27. BIN
      basic-knowledge/img/27.png
  28. BIN
      basic-knowledge/img/3.png
  29. BIN
      basic-knowledge/img/30.png
  30. BIN
      basic-knowledge/img/31.jpeg
  31. BIN
      basic-knowledge/img/4.png
  32. BIN
      basic-knowledge/img/5.png
  33. BIN
      basic-knowledge/img/6.png
  34. BIN
      basic-knowledge/img/7.png
  35. BIN
      basic-knowledge/img/8.png
  36. BIN
      basic-knowledge/img/9.png
  37. BIN
      basic-knowledge/img/Snip20160626_24.png
  38. BIN
      basic-knowledge/img/Snip20160628_32.png
  39. BIN
      basic-knowledge/img/Snip20160630_46.png
  40. BIN
      basic-knowledge/img/Snip20160701_52.png
  41. BIN
      basic-knowledge/img/Snip20160731_1.png
  42. BIN
      basic-knowledge/img/Snip20160822_89.png
  43. BIN
      basic-knowledge/img/Snip20160822_90.png
  44. BIN
      basic-knowledge/img/Snip20160822_91.png
  45. BIN
      basic-knowledge/img/Snip20160822_92.png
  46. BIN
      basic-knowledge/img/Snip20160822_93.png
  47. BIN
      basic-knowledge/img/WechatIMG469.jpeg
  48. BIN
      basic-knowledge/img/java/1.png
  49. BIN
      basic-knowledge/img/java/2.png
  50. BIN
      basic-knowledge/img/java/3.png
  51. BIN
      basic-knowledge/img/qrcode_for_gh_4461eb8b8689_258.jpg
  52. 0 33
      basic-knowledge/java-class-reference.md
  53. 0 7
      basic-knowledge/java-exception.md
  54. 0 16
      basic-knowledge/java-gc.md
  55. 0 8
      basic-knowledge/java-io.md
  56. 0 95
      basic-knowledge/java-lock.md
  57. 0 80
      basic-knowledge/java-random.md
  58. 0 128
      basic-knowledge/java.md
  59. 0 213
      basic-knowledge/java8-stream.md
  60. 0 86
      basic-knowledge/java修饰词.md
  61. 0 57
      basic-knowledge/java的线程状态.md
  62. 0 45
      basic-knowledge/jvm-param.md
  63. 0 38
      basic-knowledge/jvm内存结构.md
  64. 0 86
      basic-knowledge/regex.md
  65. 0 37
      basic-knowledge/spring.md
  66. 0 131
      basic-knowledge/springboo-note.md
  67. 0 25
      basic-knowledge/springboot-hot-reload.md
  68. 0 314
      basic-knowledge/springboot-javaConfig.md
  69. 0 41
      basic-knowledge/springboot-unit.md
  70. 0 45
      basic-knowledge/springboot.md
  71. 0 57
      basic-knowledge/springcloud.md
  72. 0 56
      basic-knowledge/各种坑.md
  73. 0 95
      basic-knowledge/常用java类.md
  74. 0 4
      basic-knowledge/常用jdk命令.md
  75. 0 87
      basic-knowledge/常用的设计模式.md
  76. 0 211
      basic-knowledge/类加载器.md
  77. 0 47
      data-base/DAO层接口性能监控.md
  78. 0 33
      data-base/bigint类型.md
  79. 0 80
      data-base/database-connection-pool.md
  80. 0 97
      data-base/id-generate.md
  81. BIN
      data-base/img/1.png
  82. BIN
      data-base/img/2.png
  83. BIN
      data-base/img/3.png
  84. BIN
      data-base/img/4.png
  85. 0 16
      data-base/other.md
  86. 0 28
      data-base/sql-optimize.md
  87. 0 33
      data-base/transaction.md
  88. 0 116
      data-base/分布式事务.md
  89. 0 16
      data-base/分库分表.md
  90. 0 0
      docs/.DS_Store
  91. 259 0
      docs/.vuepress/components/LockArticle.vue
  92. 111 0
      docs/.vuepress/components/PayArticle.vue
  93. 239 0
      docs/.vuepress/config.js
  94. 15 0
      docs/.vuepress/enhanceApp.js
  95. 0 0
      docs/.vuepress/public/CNAME
  96. 201 0
      docs/.vuepress/public/LICENSE
  97. BIN
      docs/.vuepress/public/assets/images/sys/beian.png
  98. BIN
      docs/.vuepress/public/assets/images/sys/full.png
  99. BIN
      docs/.vuepress/public/assets/images/sys/next2.png
  100. BIN
      docs/.vuepress/public/assets/images/sys/pre2.png

+ 3 - 187
README.md

@@ -1,192 +1,8 @@
-## 技术心得
+# technology-talk | 程序员编码指南
 
----
+> 你好,我是Tom哥
 
-### 前言
-
-有人认为编程是一门技术活,要有一定的天赋,非天资聪慧者不能及也。
-
-其实不然,笔者计算机专业出身,对于技术这碗饭有一些心得体会,大多数人成为某领域顶级专家可能会有些难度,但应对日常工作,**成长为资深研发工程师、技术专家、甚至成为小团队的Team Leader,并不难**
-
-**多读书、多看报,多研究开源框架源码,比如:github.com,这里汇集了全球工程师的智慧!**
-
-言归正传,本文会列举工作中常用的一些技术,以及如何锻炼提升自己的架构能力。
-
-由于每块技术市场上基本都有对应的网络资料或书籍,所以本文只是少篇幅列举工作中用到的核心知识点,抛砖引玉,属于进阶型,不适用初学者。
-
-
-### 基础知识
-* 	[java](basic-knowledge/java.md)
-*  	[spring](basic-knowledge/spring.md)
-*  	[spring boot](basic-knowledge/springboot.md)
-*  	[spring cloud](basic-knowledge/springcloud.md)
-*	[ibatis](basic-knowledge/ibatis.md)
-*	[设计模式](basic-knowledge/常用的设计模式.md)
-*	[Log日志](basic-knowledge/Log4j.md)
-
-
-### 数据库
-目前使用最多还是mysql,虽然单机性能比不上oracle,但免费开源,单机成本低且借助于分布式集群,可以有强大的输出能力。
-
-*	[连接池](data-base/database-connection-pool.md)
-* 	[事务](data-base/transaction.md)
-* 	[分库分表](data-base/分库分表.md)
-* 	[全局表 ID生成器](data-base/id-generate.md)
-* 	[读写分离](http://blog.csdn.net/itomge/article/details/6909240)
-* 	[SQL调优](data-base/sql-optimize.md)
-* 	[其它](data-base/other.md)
-
-
-### web容器/协议/网络
-
-* [负载均衡](web/load-balance.md)
-* 服务器
-	* [Nginx](web/Nginx.md)
-	* [Tomcat](web/tomcat.md)
-* 协议
-	* [HTTP 协议](web/http.md)
-	* [TCP 协议](web/tcp.md)
-* [CDN](web/CDN.md)
-* [其它](web/other.md)
-
-
-### 常用三方工具包
-
-* [Google Guava](open-source-framework/Goole-Guava.md)
-* [fastJson](open-source-framework/fastJson.md)
-* [log4J](http://blog.csdn.net/itomge/article/details/17913607)
-* [commons-codec](open-source-framework/commons-codec.md)
-* [commons-lang3](open-source-framework/commons-lang3.md)
-* [commons-io](open-source-framework/commons-io.md)
-* [Quartz](open-source-framework/Quartz.md)
-* [HttpClient](open-source-framework/HttpClient.md)
-* [okhttp](open-source-framework/okhttp.md)
-* [Javassist](open-source-framework/Javassist.md)
-* [lombok](open-source-framework/lombok.md)
-
-
-### 中间件
-
-*	RPC框架
-	* [dubbo](middle-software/dubbo.md)
-	* [dubbox](https://www.oschina.net/p/dubbox)
-	* [motan](https://github.com/weibocom/motan)
-	* [Thrift](https://github.com/apache/thrift)
-	* [RPC框架性能比较](middle-software/rpc-compare.md)
-
-*   MQ消息
-	* [ActiveMQ](https://github.com/apache/activemq)
-	* [RabbitMQ](middle-software/RabbitMQ.md)
-	* [Kafka](middle-software/kafka.md)
-	* [RocketMQ](middle-software/RocketMQ.md)	
-	* [MQ框架性能比较](middle-software/mq-compare.md)
-
-*   分布式缓存
-	* [redis](open-source-framework/redis.md)
-	* [memcache](http://blog.csdn.net/itomge/article/details/8035197)
-
-*   本地缓存
-	* [Guava](middle-software/guava.md)
-	* [Ehcache](middle-software/ehcache.md)
-	 	
-*   搜索
-	* [Elasticsearch](middle-software/elasticsearch.md)
-
-*   分布式数据框架
-	* [cobar](middle-software/cobar.md)
-	* [Mycat](middle-software/mycat.md)
-	* [tsharding](middle-software/tsharding.md)
-	* [tddl](https://github.com/alibaba/tb_tddl)
-	* [sharding-jdbc](middle-software/sharding-jdbc.md)
-	* [dbsplit](https://gitee.com/robertleepeak/dbsplit)
-
-*	分布式协调服务
-	* [zookeeper](middle-software/zookeeper.md)
-		
-*   配置管理
-
-	* [super-diamond](other/super-diamond源码分析.md)
-	* [disconf](https://www.oschina.net/p/disconf)
-	* [apollo](middle-software/apollo.md)
-
-*   分布式文件系统
-	* [FastDFS](middle-software/FastDFS.md)
-
-*   分布式任务调度框架
-
-	* [Elastic-Job](https://github.com/elasticjob/elastic-job)
-	* [详解当当网的分布式作业框架elastic-job](http://www.infoq.com/cn/articles/dangdang-distributed-work-framework-elastic-job)
-	* [TBSchedule](http://blog.csdn.net/taosir_zhang/article/details/50728362)
-	* [xxl-job](https://github.com/xuxueli/xxl-job)
-
-*   大数据
-	* [Hbase](middle-software/Hbase.md)
-	* [Spark](middle-software/Spark.md)
-	* [Hadoop](middle-software/Hadoop.md)
-	* [Hive](middle-software/Hive.md)
-	* [other框架](middle-software/big-data.md)	
-
-*  其它
-	* [数据库binlog的增量订阅&消费组件](https://github.com/alibaba/canal)
-	* [数据库同步系统](https://github.com/alibaba/otter)
-	* [TCC-Transaction](middle-software/TCC-Transaction.md)
-	* [Netty](middle-software/Netty.md)
-	* [OpenResty](middle-software/openresty.md)
-
-### 系统架构 
-
-* [架构经验](system-architecture/architecture-experience.md)
-* [经典案例](system-architecture/architecture-good-case.md)
-* [通用技术方案选型](system-architecture/technology-selection.md)
-* [编码前3000问](system-architecture/编码前3000问.md)
-* [软硬件性能](system-architecture/software-performance.md)
-* [技术大纲](system-architecture/knowledge-outline.md)
-
-
-### 项目管理
-
-* [论需求调研的重要性](project-management/论需求调研的重要性.md)
-* [项目管理](project-management/project-management.md)
-* [代码管理](project-management/code.md)
-* [测试相关](project-management/test.md)
-
-
-### 运维
-
-*	[快速排查线上问题](ops/online-question.md)
-*	[linux常用命令](ops/linux-commands.md)
-*	[本地代码调试](ops/本地代码调试.md)
-* 	[Docker](ops/docker.md)
-
-### 个人成长
-
-*   [学习网站](other/study.md)
-*   [Tom哥的读书单](other/book.md)
-*   [个人成长与职业规划](other/person.md)
-*   [程序员素养](other/programer.md)
-
-
-### 其它
-
-*	[常用软件工具](other/tool.md)
-*	[一致性hash算法](other/一致性hash.md)
-*   面试
-	* [java面试题](other/java-interview.md)
-	* [大数据面试题](other/bigdata-interview.md)
-*	[回车与换行的区别](other/回车与换行的区别.md)
-*   [github上fork项目后,如何同步更新后面提交](http://blog.csdn.net/qq1332479771/article/details/56087333)
-* 	[其它](other/other.md)
-
-
-### 写在最后
-
-
-作者 **Tom哥**,计算机研究生,**阿里 P7 技术专家**,拿过 百度、华为、中兴、腾讯 等6家大厂offer,出过**专利**。
-
-多次参加**淘宝双11**大促活动,架构经验丰富。作为团队负责人,面试过 **500多**位候选人,如果你想去**一线大厂**,关注下方公众号回复「 **大厂** 」,领取大厂面试资料,成为offer收割机
-
-
-<img src="https://raw.githubusercontent.com/aalansehaiyang/technology-talk/master/1.jpg" width=400>
+🚜 **上最快的车、唠最狠的嗑,爬最高的坡、拿最贵的Offer!** 
 
 
 

+ 0 - 31
basic-knowledge/HashMap的扩容机制.md

@@ -1,31 +0,0 @@
-## HashMap的扩容机制
-
----
-
-######简介
-
-单纯的kv键值对结构,可以接受null键和null值,速度比较快,非线程安全。
-
-
-#####HashMap的数据结构
-
-HashMap实际上是一个“链表的数组”的数据结构,每个元素存放链表头结点的数组,即数组和链表的结合体。
-
-![image](img/Snip20160731_1.png)
-
-Entry就是数组中的元素,每个 Map.Entry 其实就是一个key-value对,它持有指向下一个元素的引用,这就构成了链表。
-
-
-
-#####工作原理:
-
-
-1.put
-
-当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。
-
-
-
-HashMap基于hashing原理,我们通过put()方法储存,当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,然后找到bucket位置来储存值对象。
-
-当获取对象时,同上找到对应的bucket,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。

+ 0 - 199
basic-knowledge/Log4j.md

@@ -1,199 +0,0 @@
-## java日志
-
----
-
-#### 一、Log4
-
-Log4j是Apache的一个开源项目,它允许开发者以任意间隔输出日志信息.。主要分为两部分:一是appender,是输出日志的方式;二是logger,是具体日志输出器
-
-**1.Appender**
-
-  其中,Log4j提供的appender有以下几种:
-  
-
-* org.apache.log4j.ConsoleAppender(输出到控制台)
-* org.apache.log4j.FileAppender(输出到文件)
-* org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
-* org.apache.log4j.RollingFileAppender(文件到达指定大小的时候产生一个新的文件)
-* org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
-
-例如:
-
-```
-<appender name=" ConsoleAppenderA"class="org.apache.log4j.ConsoleAppender">
-        <param name="target" value="System.out"/>
-        <layout class="org.apache.log4j.PatternLayout">
-            <param name="ConversionPattern"value="%-5p %x %c{2} -%m%n"/>
-        </layout>
-</appender>
-
-<appender name="BUSINESSERRORAPPENDER" class="com.alibaba.common.logging.spi.log4j.DailyRollingFileAppender">
-        <param name="file" value="${luna_loggingRoot}/usr/common/business-error.log"/>
-        <param name="append" value="true"/>
-        <param name="encoding" value="GBK"/>
-        <layout class="org.apache.log4j.PatternLayout">
-            <param name="ConversionPattern" value="%d %-5p %c{2} - %m%n"/>
-        </layout>
-    </appender>
-    
-     <appender name="cacheFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
-        <File>${LOG_HOME}/redis-cache.log</File>
-        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
-            <fileNamePattern>${LOG_HOME}/redis-cache-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
-            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
-                <maxFileSize>100MB</maxFileSize>
-            </timeBasedFileNamingAndTriggeringPolicy>
-        </rollingPolicy>
-        <encoder>
-            <Pattern>%date{ISO8601} %-5level [%thread] %logger{32} - %message%n</Pattern>
-        </encoder>
-    </appender>
-```
-
-**其中,Log4j提供的layout有以下几种:**
-
-* org.apache.log4j.HTMLLayout(以HTML表格形式布局)
-* org.apache.log4j.PatternLayout(可以灵活地指定布局模式)
-* org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串)
-* org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)
-
-
-
-**格式化日志信息Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下:**
-
-* %m 输出代码中指定的消息
-* %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL
-* %r 输出自应用启动到输出该log信息耗费的毫秒数
-* %c 输出所属的类目,通常就是所在类的全名
-* %t 输出产生该日志事件的线程名
-* %n 输出一个回车换行符,Windows平台为“rn”,Unix平台为“n”
-* %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyyy MMM ddHH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921
-* %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。
-
-**2.Logger**
-
-Log4j中有一个根日志器
-
-```
-<root>
-   <level value="$luna_loggingLevel"/>
-   <appender-ref ref="PROJECT"/>
-   <appender-ref ref="EXCEPTION_LOG"/>
-</root>
-```
-
-
-默认时系统中其他所有非根logger都会继承根日志器,logger如果有level属性就会覆盖继承日志器(比如根日志器)的level属性。而appender会叠加,即本logger的配置的appender加上继承日志器上的appender。
-
-```
-<logger name="com.alibaba.service.VelocityService">
-        <level value="INFO"/>
-        <appender-ref ref="ConsoleAppenderA"/>
-</logger>
-```
-
-根据继承原则得到这个logger的level是INFO,appender是ConsoleAppenderA、PROJECT、EXCEPTION_LOG。
-也可以使logger不继承其他logger,使用additivity="false"
-
-```
-<logger name="com.alibaba.china.pylon.enhancedmit.domain.Handler" additivity="false">
-	    <level value="info"/>
-	    <appender-ref ref="enhancedMITAppender"/>
-</logger>
-```
-
-其中,level 是日志记录的优先级,分为OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者自定义的级别。
-
-Log4j常用的四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关。**比如在这里定义了INFO级别,只有等于及高于这个级别的才会处理,而DEBUG级别的日志信息将不会被打印出来。**
-
-ALL:打印所有的日志,OFF:关闭所有的日志输出。 
-appender-ref属性即使用logger引用之前配置过的appender。
-
-
-**在程序中怎么创建logger,并调用呢?**
-
-```
-Logger logger =Logger.getLogger(VelocityService.class.getName()); 
-或
-Logger logger =LogFactory.getLog(VelocityService.class);
-logger.debug("Justtesting a log message with priority set to DEBUG");
-logger.info("Just testinga log message with priority set to INFO");
-logger.warn("Just testinga log message with priority set to WARN");
-logger.error("Justtesting a log message with priority set to ERROR");
-logger.fatal("Justtesting a log message with priority set to FATAL");
-```
- 
-另外,logger对name的前缀默认也有继承性,例:
-
-```
-<logger name="com.alibaba.service" additivity="false">
-     <level value="INFO"/>
-     <appender-ref ref="ConsoleAppenderA"/>
-</logger>
-
-<logger name="com.alibaba.service.VelocityService">
-    <level value="INFO"/>
-    <appender-ref ref="FileAppenderA"/>
- </logger>
- ````
- 
-根据继承原则名为com.alibaba.service.VelocityService的logger的appender是FileAppenderA和ConsoleAppenderA,level的为INFO。
-
-
-#### 二、SLF4J
-
-Log4J (Simple Logging Facade for Java)使用普遍,但是框架较重,引入了很多无用的包,相比SLF4J就灵活很多。SLF4J很好地解耦了API和实现,例如,你可以强制使用SLF4J的API,而保持生产环境中用了几年的旧的Log4J.properties文件。
-
-例如:
-
-```
-Logger.debug("Hello " + name);
-```
-
-由于字符串拼接的问题(注:上述语句会先拼接字符串,再根据当前级别是否低于debug决定是否输出本条日志,即使不输出日志,字符串拼接操作也会执行),许多公司强制使用下面的语句,这样只有当前处于DEBUG级别时才会执行字符串拼接:
-
-```
-if (logger.isDebugEnabled()) {
-    LOGGER.debug(“Hello ” + name);
-}
-```
-
-它避免了字符串拼接问题,但有点太繁琐了是不是?相对地,SLF4J提供下面这样简单的语法:
-
-```
-LOGGER.debug("Hello {}", name);
-```
-
-它的形式类似第一条示例,而又没有字符串拼接问题,也不像第二条那样繁琐。
-
-**pom依赖:**
-
-```
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>jcl-over-slf4j</artifactId>
-            <version>1.7.7</version>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>log4j-over-slf4j</artifactId>
-            <version>1.7.7</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-core</artifactId>
-            <version>1.1.2</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-classic</artifactId>
-            <version>1.1.2</version>
-        </dependency>
-```
-
-**参考资料:**
-
-
-http://ifeve.com/java-slf4j-think/
-
-https://www.slf4j.org/

+ 0 - 271
basic-knowledge/NIO.md

@@ -1,271 +0,0 @@
-## NIO
-
----
-
-#### 简介:
-NIO 是java 1.4引入的新特性。是对原来的standard IO的扩展。
-
-Standard IO是对字节流的读写,在进行IO之前,首先创建一个流对象,流对象进行读写操作都是按字节
-,一个字节一个字节的来读或写。而NIO把IO抽象成块,类似磁盘的读写,每次IO操作的单位都是一个块,块被读入内存之后就是一个byte[],NIO一次可以读或写多个字节。
-
-
-#####NIO的几大组件:
-
-#####1.Selector
-
-多路复用选择器,基于“事件驱动”,其核心就是通过Selector来轮询注册在其上的Channel,当发现某个或多个Channel处于就绪状态后,从阻塞状态返回就绪的Channel的SelectionKey集合,进行I/O操作。
-
-* 创建多路复用器并启动线程
-
-```
- Selector selector=Selector.open();
- new Thread(new ReactorTask()).start();
- 
-```
-
-* 创建Channel
-
-```
-// 打开ServerSocketChannel,用于监听客户端的连接
-ServerSocketChannel ssc=ServerSocketChannel.open();
-//设置连接为非阻塞模式
-ssc.configureBlocking(false);
-//绑定监听端口
-ServerSocket ss=ssc.socket();
-ss.bind(new InetSocketAddress(InetAdderss.getByName("ip"),port));
-//将ServerSocketChannel注册到多路复用器Selector上,监听ACCEPT事件
-ssc.register(selector,SelectionKey.OP_ACCEPT);
-
-```
-* 等待客户端的连接
-
-```
- while (true) {
-            // selector.select是阻塞的,一直等到有客户端连接过来才返回,然后会检查发生的是哪一种事件,然后根据不同的事件做不同的操作
-            selector.select();
-            Set<SelectionKey> selectionKeys = selector.selectedKeys();
-            Iterator<SelectionKey> it = selectionKeys.iterator();
-            while (it.hasNext()) {
-                SelectionKey key = it.next();
-                if (key.isAcceptable()) {
-                    // 处理新接入的请求消息
-                    ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
-                    SocketChannel sc = ssc.accept();
-                    sc.configureBlocking(false);
-                    // 注册读事件
-                    sc.register(selector, SelectionKey.OP_READ);
-                }
-                if (key.isReadable()) {
-                    // 处理读请求
-                    SocketChannel sc = (SocketChannel) key.channel();
-                    ByteBuffer readBuffer = ByteBuffer.allocate(1024);
-                    int readBytes = sc.read(readBuffer);
-                    if (readBytes > 0) {
-                        readBuffer.flip();
-                        byte[] bytes = new byte[readBuffer.remaining()];
-                        readBuffer.get(bytes);
-                        System.out.println(new String(bytes, "UTF-8"));
-                    }
-                }
-
-            }
-        }
-
-```
-
-
-#####2.Channel
-Channel是NIO对IO抽象的一个新概念,NIO在进行IO时需要创建一个Channel对象,是双向的,不象Standard IO分为输入流和输出流
-
-#####3.Buffer
-
-Buffer和Channel都是一起使用的,每次都是从一个Channel中读出一个Buffer或者把一个Buffer写入到一个Channel中
-
-```
-                    // 处理读请求
-                    SocketChannel sc = (SocketChannel) key.channel();
-                    ByteBuffer readBuffer = ByteBuffer.allocate(1024);
-                    int readBytes = sc.read(readBuffer);
-                    if (readBytes > 0) {
-                        readBuffer.flip();
-                        byte[] bytes = new byte[readBuffer.remaining()];
-                        readBuffer.get(bytes);
-                        System.out.println(new String(bytes, "UTF-8"));
-                    }
-                    
-```
-
-Buffer有3个重要的属性
-
-* position 正整数,指向Buffer中下一个要读取或写入的字节位置
-* limit 正整数,指向Buffer中的某个位置,在IO时只读写下标小于limit的字节内容
-* capacity  正整数,Buffer所能容纳的最大字节数
-
-0 <= position <= limit <= capacity
-
-初始状态:
-![image](img/Snip20160822_89.png)
-
-从Channel中读入5个字到ByteBuffer
-![image](img/Snip20160822_90.png)
-
-flip(),准备写入或输出
-
-```
-public final Buffer flip() {
-        limit = position;
-        position = 0;
-        mark = -1;
-        return this;
-    }
-```
-![image](img/Snip20160822_91.png)
-
-输出内容后,position就移动到跟limit相同的位置上
-![image](img/Snip20160822_92.png)
-
-ByteBuffer如果要重复利用,需要清理,position和limit回到初始状态时的位置,然后可以接着用这个Buffer来读写数据,不需要再New 新的Buffer
-
-```
-    public final Buffer clear() {
-        position = 0;
-        limit = capacity;
-        mark = -1;
-        return this;
-    }
-```
-![image](img/Snip20160822_93.png)
-
-
-#### 比较好的基于NIO的开源框架(Netty)
-
-**优点:**
-
-* api简单,开发门槛低
-* 功能强大,内置了多种编码、解码功能
-* 与其它业界主流的NIO框架对比,netty的综合性能最优
-* 社区活跃,使用广泛,经历过很多商业应用项目的考验
-* 定制能力强,可以对框架进行灵活的扩展
-
-
-```
-<dependency>
-     <groupId>org.jboss.netty</groupId>
-     <artifactId>netty</artifactId>
-     <version>3.2.5.Final</version>
-</dependency>
-```
-
-**例子:**
-
-* 服务端。接收客户端请求并将内容打印出来,同时发送一个消息收到回执。
-
-```
-public class NettyServer {
-
-    private static int HEADER_LENGTH = 4;
-
-    public void bind(int port) throws Exception {
-
-        ServerBootstrap b = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),
-                                                                                  Executors.newCachedThreadPool()));
-
-        // 构造对应的pipeline
-        b.setPipelineFactory(new ChannelPipelineFactory() {
-
-            public ChannelPipeline getPipeline() throws Exception {
-                ChannelPipeline pipelines = Channels.pipeline();
-                pipelines.addLast(MessageHandler.class.getName(), new MessageHandler());
-                return pipelines;
-            }
-        });
-        // 监听端口号
-        b.bind(new InetSocketAddress(port));
-    }
-
-    // 处理消息
-    static class MessageHandler extends SimpleChannelHandler {
-
-        public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
-            // 接收客户端请求
-            ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
-            String message = new String(buffer.readBytes(buffer.readableBytes()).array(), "UTF-8");
-            System.out.println("<服务端>收到内容=" + message);
-
-            // 给客户端发送回执
-            byte[] body = "服务端已收到".getBytes();
-            byte[] header = ByteBuffer.allocate(HEADER_LENGTH).order(ByteOrder.BIG_ENDIAN).putInt(body.length).array();
-            Channels.write(ctx.getChannel(), ChannelBuffers.wrappedBuffer(header, body));
-            System.out.println("<服务端>发送回执,time=" + System.currentTimeMillis());
-
-        }
-    }
-
-    public static void main(String[] args) {
-        try {
-            new NettyServer().bind(1088);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        ;
-    }
-}
-```
-
-* 客户端。向服务端发送一个请求,然后打印服务端响应的内容。
-
-```
-public class NettyClient {
-
-    private final ByteBuffer readHeader  = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
-    private final ByteBuffer writeHeader = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN);
-    private SocketChannel    channel;
-
-    public void sendMessage(byte[] body) throws Exception {
-        // 创建客户端通道
-        channel = SocketChannel.open();
-        channel.socket().setSoTimeout(60000);
-        channel.connect(new InetSocketAddress(AddressUtils.getHostIp(), 1088));
-
-        // 客户端发请求
-        writeWithHeader(channel, body);
-
-        // 接收服务端响应的信息
-        readHeader.clear();
-        read(channel, readHeader);
-        int bodyLen = readHeader.getInt(0);
-        ByteBuffer bodyBuf = ByteBuffer.allocate(bodyLen).order(ByteOrder.BIG_ENDIAN);
-        read(channel, bodyBuf);
-        System.out.println("<客户端>收到响应内容:" + new String(bodyBuf.array(), "UTF-8") + ",长度:" + bodyLen);
-    }
-
-    private void writeWithHeader(SocketChannel channel, byte[] body) throws IOException {
-        writeHeader.clear();
-        writeHeader.putInt(body.length);
-        writeHeader.flip();
-        // channel.write(writeHeader);
-        channel.write(ByteBuffer.wrap(body));
-    }
-
-    private void read(SocketChannel channel, ByteBuffer buffer) throws IOException {
-        while (buffer.hasRemaining()) {
-            int r = channel.read(buffer);
-            if (r == -1) {
-                throw new IOException("end of stream when reading header");
-            }
-        }
-    }
-
-    public static void main(String[] args) {
-        String body = "客户发的测试请求!";
-        try {
-            new NettyClient().sendMessage(body.getBytes());
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-}
-
-```
-
-

+ 0 - 73
basic-knowledge/ThreadLocal.md

@@ -1,73 +0,0 @@
-## ThreadLocal原理机制
-
----
-
-
-* [Java多线程之隔离技术ThreadLocal源码详解](https://mp.weixin.qq.com/s/mo3-y-45_ao54b5T7ez7iA)
-
----
-
-**简介:**
-
-ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制。
- 
-ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
-
-**常用方法:**
-
-* get
-
-```
-T get()
-
-```
-
-返回此线程局部变量的当前线程副本中的值,如果这是线程第一次调用该方法,则创建并初始化此副本。
-
-```
-源代码:
-
- public T get() {
-        Thread t = Thread.currentThread();
-        ThreadLocalMap map = getMap(t);
-        if (map != null) {
-            ThreadLocalMap.Entry e = map.getEntry(this);
-            if (e != null) {
-                @SuppressWarnings("unchecked")
-                T result = (T)e.value;
-                return result;
-            }
-        }
-        return setInitialValue();
-    }
-```
-
-* set
-
-```
-void set(T value)
-```
-将此线程局部变量的当前线程副本中的值设置为指定值。
-
-```
-源代码:
-
- public void set(T value) {
-        Thread t = Thread.currentThread();
-        ThreadLocalMap map = getMap(t);
-        if (map != null)
-            map.set(this, value);
-        else
-            createMap(t, value);
-    }
-```
-
-
-* remove
-
-```
-void remove()
-```
-有助于减少线程局部变量的存储需求。
-
-

+ 0 - 237
basic-knowledge/concurrent-class.md

@@ -1,237 +0,0 @@
-### jdk并发包里常用的类
-
----
-
-#### 资料
-
-* [并发编程 :Concurrent 用户指南 ( 上 )](https://mp.weixin.qq.com/s/sF1xZY9ZrLVOXvTD4jiHRA)
-* [并发编程 :Concurrent 用户指南 ( 中 )](https://mp.weixin.qq.com/s/BrI7y7gKaBTDdtLm15ezzw)
-* [并发编程 :Concurrent 用户指南 ( 下 )](https://mp.weixin.qq.com/s/XxTazsHStb7BwjUxKflpdA)
-
----
-
-
-* ConcurrentHashMap
-
-	是线程安全的。
-	
-	Put方法,首先是对key.hashCode进行hash操作,得到hash值。然后获取对应的segment对象,接着调用Segment对象的put方法完成当前操作。当调用put方法时,首先lock操作,完成操作后再释放锁。
-	
-	http://ifeve.com/concurrenthashmap/
-
-![image](img/17.png)
-
-* Semaphore
-
-	可以控制某资源同时被访问的个数。例如连接池中通常要控制创建连接的个数。
-	
-	tryAcquire方法,获得锁<br>
-	release方法,释放锁
-
-* CountdownLatch
-
-	闭锁,确保一个服务不会开始,直到它依赖的其他服务都已近开始,它允许一个或多个线程,等待一个事件集的发生。
-	通过减计数的方式,控制多个线程同时开始某个动作。当计数为0时,await后的代码才会被执行。
-提供await()和countDown()两个方法。
-
-* CyclicBarrier
-
-	cyclicBarrier中的await方法会对count值减1,并阻塞当前线程(java.util.concurrent.locks.Condition.await()),如果count==0时先执行CyclicBarrier内部的Runnable任务(java.lang.Runnable.run()),然后唤醒所有阻塞的线程(java.util.concurrent.locks.Condition.signalAll()),count恢复初始值(可以进入下一轮循环)。
-	
-	与CountdownLatch不同的是,它可以循环重用。
-	
-```
-import java.util.concurrent.CyclicBarrier;
-
-public class TestCyclicBarrier {
-
-    private static final int THREAD_NUM = 5;
-
-    public static class WorkerThread implements Runnable {
-
-        CyclicBarrier barrier;
-
-        public WorkerThread(CyclicBarrier b){
-            this.barrier = b;
-        }
-
-        @Override
-        public void run() {
-            try {
-                System.out.println("Worker's waiting");
-                // 线程在这里等待,直到所有线程都到达barrier。
-                barrier.await();
-                System.out.println("ID:" + Thread.currentThread().getId() + " Working");
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-
-    }
-
-    public static void main(String[] args) {
-        CyclicBarrier cb = new CyclicBarrier(THREAD_NUM, new Runnable() {
-
-            // 当所有线程到达barrier时执行
-            @Override
-            public void run() {
-                System.out.println("Inside Barrier");
-            }
-        });
-
-        for (int i = 0; i < 10; i++) {
-            new Thread(new WorkerThread(cb)).start();
-        }
-    }
-
-}
-```
-结果:
-
-```
-Worker's waiting
-Worker's waiting
-Worker's waiting
-Worker's waiting
-Worker's waiting
-Inside Barrier
-ID:13 Working
-ID:9 Working
-ID:12 Working
-ID:11 Working
-ID:10 Working
-Worker's waiting
-Worker's waiting
-Worker's waiting
-Worker's waiting
-Worker's waiting
-Inside Barrier
-ID:18 Working
-ID:14 Working
-ID:16 Working
-ID:15 Working
-ID:17 Working
-
-```
-
-
-* AtomicInteger
-
-	原子操作,线程安全。之前如果多线程累计计数,需要通过锁控制。
-IncrementAndGet方法,关键是调用了compareAndSwap方法,是native方法,基于cpu的CAS原语来实现的。简单原理是由cpu比较内存位置上的值是否为当前值,如果是换成新值,否则返回false
-
-* ThreadPoolExecutor
-
-	提供线程池服务,ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler)
-
-```
-corePoolSize: 线程池维护线程的最少数量
-maximumPoolSize:线程池维护线程的最大数量
-keepAliveTime: 线程池维护线程所允许的空闲时间
-unit: 线程池维护线程所允许的空闲时间的单位
-workQueue: 线程池所使用的缓冲队列
-handler: 线程池对拒绝任务的处理策略
-```
-```
-block queue有以下几种实现:
-1. ArrayBlockingQueue:有界的数组队列
-2. LinkedBlockingQueue:可支持有界、无界的队列,使用链表实现
-3. PriorityBlockingQueue:优先队列,可对任务排序
-4. SynchronousQueue:队列长度为1的队列,和Array有点区别就是:client 线程提交到 block queue会是一个阻塞过程,直到有一个消费线程连接上来poll task
-
-RejectExecutionHandler是针对任务无法处理时的一些自我保护处理:
-1.	Reject 直接抛出Reject exception
-2.	Discard 直接忽略该runnable,不建议使用
-3.	DiscardOldest 丢弃最早入队列的任务
-4.	CallerRuns 直接让原先的client thread做为消费线程,象同步调用方式一样,自己来执行。
-
-```
-
- ![image](img/Snip20160701_52.png)
-
-
-**如何确定最大线程数?**
-
-确定线程数首先需要考虑到系统可用的处理器核心数:
-
-Runtime.getRuntime().availableProcessors();
-应用程序最小线程数应该等于可用的处理器核数。
-
-如果所有的任务都是计算密集型的,则创建处理器可用核心数这么多个线程就可以了,这样已经充分利用了处理器,也就是让它以最大火力不停进行计算。创建更多的线程对于程序性能反而是不利的,因为多个线程间频繁进行上下文切换对于程序性能损耗较大。
-
-如果任务都是IO密集型的,那我们就需要创建比处理器核心数大几倍数量的线程。为何?当一个任务执行IO操作时,线程将被阻塞,于是处理器可以立即进行上下文切换以便处理其他就绪线程。如果我们只有处理器核心数那么多个线程的话,即使有待执行的任务也无法调度处理了。
-
-因此,线程数与我们每个任务处于阻塞状态的时间比例相关。加入任务有50%时间处于阻塞状态,那程序所需线程数是处理器核心数的两倍。我们可以计算出程序所需的线程数,公式如下:
-
-线程数=CPU可用核心数/(1 - 阻塞系数),其中阻塞系数在在0到1范围内。
-
-计算密集型程序的阻塞系数为0,IO密集型程序的阻塞系数接近1。
-确定阻塞系数,我们可以先试着猜测,或者采用一些性能分析工具或java.lang.management API 来确定线程花在系统IO上的时间与CPU密集任务所耗的时间比值。
-         
-         
-* Executors
-	
-	工具类,提供大量管理线程执行器的工厂方法。
-
-	newFixedThreadPool(int) ,创建固定大小的线程池
-
-	newSingleThreadPool(),创建大小为1的线程池,同一时刻执行的task只有一个,其它的都放在阻塞队列中。
-
-	newScheduledThreadPool(int),适用于一些需要定时或延迟的任务。与Timer的区别:
-Timer是单线程,一旦一个task执行慢,将会影响其它任务。另外如果抛出异常,其它任务也不再执行。
-ScheduledThreadPoolExecutor可执行callable的task,执行完毕后得到执行结果。任务队列是基于DelayedWorkQueue实现,将有新task加入时,会按执行时间排序。
-
-* FutureTask
-
-	用于异步获取执行结果或取消执行任务。通过传入Callable给FutureTask,直接调用run方法执行,之后可以通过FutureTask的get异步方法获得执行结果。FutureTask即使多次调用了run方法,它只会执行一次Callable任务,当然也可以通过cancel来取消执行。
-《分布式java应用》P158
-
-* ArrayBlockingQueue
-
-	基于数组、先进先出、线程安全的集合
-
-
-* CopyOnWriteArrayList
-
-	线程安全,读操作时无锁的ArrayList。每次新增一个对象时,会将创建一个新的数组(长度+1),将之前的数组中的内容复制到新的数组中,并将新增的对象放入数组末尾。最后做引用切换。
-	
-* CopyOnWriteArraySet
-
-	与上面的类似,无非在add时,会调用addIfAbsent,由于每次add时都要进行数组遍历,因此性能会略低于CopyOnWriteArrayList
-
-* ReentrantLock
-
-	单锁。控制并发的,和synchronized达到的效果是一致的。
-Lock方法,借助于CAS机制来控制锁。
-Unlock方法,释放锁
-
-* ReentrantReadWriteLock
-
-	与ReentrantLock没有任何继承关系,提供了读锁和写锁,在读多写少的场景中大幅度提升性能。
-	
-	持有读锁时,不能直接调用写锁的lock方法<br>
-	持有写锁时,其他线程的读或写都会被阻塞。
-	
-	ReentrantReadWriteLock  lock=new ReentrantReadWriteLock();
-WriteLock  writeLock=lock.writeLock();
-ReadLock   readLock=lock.readLock();
-《分布式java应用》P165
-
-* 如何避免死锁
-
-	1.制定锁的顺序,来避免死锁(先A后B,避免A->B和B->A同时存在);
-	
-	2.尝试使用定时锁(lock.tryLock(timeout))
-	
-	3.在持有锁的方法中进行其他方法的调用,尽量使用开放调用(当调用方法不需要持有锁时,叫做开放调用)
-	
-	4.减少锁的持有时间、减小锁代码块的粒度。
-
-
-
-
-#### 汇总
-
-![image](img/Snip20160628_32.png)
-
-

+ 0 - 15
basic-knowledge/ibatis.md

@@ -1,15 +0,0 @@
-## ibatis
-
----
-
-### 附录
-
-* [MyBatis 动态 SQL 底层原理分析](http://mp.weixin.qq.com/s/BLY1HZUtmYA_w1_MZfcYRQ)
-* [基于mybatis读写分离插件](https://mp.weixin.qq.com/s/O8DfUjIw18WehILOWsR8ug)
-
-
-####简介
-
-ibatis已经不再维护,现在基本采用myibatis
-
-

BIN
basic-knowledge/img/.DS_Store


BIN
basic-knowledge/img/1.jpg


BIN
basic-knowledge/img/10.jpg


BIN
basic-knowledge/img/11.png


BIN
basic-knowledge/img/12.png


BIN
basic-knowledge/img/13.png


BIN
basic-knowledge/img/15.png


BIN
basic-knowledge/img/16.png


BIN
basic-knowledge/img/17.png


BIN
basic-knowledge/img/18.png


BIN
basic-knowledge/img/19.png


BIN
basic-knowledge/img/2.jpg


BIN
basic-knowledge/img/20.png


BIN
basic-knowledge/img/20191226162717.gif


BIN
basic-knowledge/img/21.png


BIN
basic-knowledge/img/22.png


BIN
basic-knowledge/img/23.png


BIN
basic-knowledge/img/24.png


BIN
basic-knowledge/img/27.png


BIN
basic-knowledge/img/3.png


BIN
basic-knowledge/img/30.png


BIN
basic-knowledge/img/31.jpeg


BIN
basic-knowledge/img/4.png


BIN
basic-knowledge/img/5.png


BIN
basic-knowledge/img/6.png


BIN
basic-knowledge/img/7.png


BIN
basic-knowledge/img/8.png


BIN
basic-knowledge/img/9.png


BIN
basic-knowledge/img/Snip20160626_24.png


BIN
basic-knowledge/img/Snip20160628_32.png


BIN
basic-knowledge/img/Snip20160630_46.png


BIN
basic-knowledge/img/Snip20160701_52.png


BIN
basic-knowledge/img/Snip20160731_1.png


BIN
basic-knowledge/img/Snip20160822_89.png


BIN
basic-knowledge/img/Snip20160822_90.png


BIN
basic-knowledge/img/Snip20160822_91.png


BIN
basic-knowledge/img/Snip20160822_92.png


BIN
basic-knowledge/img/Snip20160822_93.png


BIN
basic-knowledge/img/WechatIMG469.jpeg


BIN
basic-knowledge/img/java/1.png


BIN
basic-knowledge/img/java/2.png


BIN
basic-knowledge/img/java/3.png


BIN
basic-knowledge/img/qrcode_for_gh_4461eb8b8689_258.jpg


+ 0 - 33
basic-knowledge/java-class-reference.md

@@ -1,33 +0,0 @@
-## 强引用、软引用、弱引用、幻象引用
----
-
-* 强引用
-
-常见的普通对象引用,只要还有强引用指向一个对象,就表示这个对象还“活着”,垃圾回收不会回收这种对象。对于一个普通对象,如果没有其他引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为null,就可以被垃圾收集了。
-
-* 软引用
-
-SoftReference,相对强引用弱一些,可以让对象豁免一些垃圾收集,只有当JVM 认为内存不足时,才会去试图回收软引用指向的对象。
-
-JVM会确保在抛出OutofMemoryError之前,清理软引用指向的对象。这样保证了使用缓存的同时,不会耗尽内存。
-
-* 弱引用
-
-并不能使对象豁免垃圾收集,仅仅是提供一种访问在弱引用状态下对象的途经。
-
-如果试图获取时对象还在,就使用它,否则重新实例化,它同样是很多缓存实现的选择。
-
-* 幻象引用
-
-也叫虚引用,你不能通过它访问对象。仅仅提供了对象被finalize以后,做某些事情的机制,比如 Post-Mortem清理机制
-
-
-对象可达性状态流转图:
-
-![image](img/31.jpeg)
-
-
-所有引用类型,都是抽象类 java.lang.ref.Reference的子类,提供了get()方法。
-
-**除了幻象引用(get返回null),如果对象没有被销毁,都可以通过get()方法获取原有对象,我们可以将访问到的对象,重新指向强引用,也就是人为的改变对象的可达性状态。**
-

+ 0 - 7
basic-knowledge/java-exception.md

@@ -1,7 +0,0 @@
-##  Exception
-
----
-
-图中红色部分为受检查异常。它们必须被捕获,或者在函数中声明为抛出该异常。
-
-![image](img/22.png)

+ 0 - 16
basic-knowledge/java-gc.md

@@ -1,16 +0,0 @@
-##  垃圾回收
-
----
-
-
-* [GC算法 垃圾收集器](https://mp.weixin.qq.com/s/olNXcRAT3PTK-hV_ehtmtw)
-* [Java GC 分析](https://mp.weixin.qq.com/s/S3PcA2KIzCVB2hJmsbVzyQ)
-* [Java应用频繁FullGC分析](https://yq.aliyun.com/articles/94557?spm=5176.100239.blogcont217385.73.SaQb9l)
-
-* GC日志
-
-	* [快速解读GC日志](https://blog.csdn.net/renfufei/article/details/49230943)
-	* [CMS垃圾回收器详解](https://blog.csdn.net/zqz_zqz/article/details/70568819)
-	
-
-	

+ 0 - 8
basic-knowledge/java-io.md

@@ -1,8 +0,0 @@
-## IO 相关
----
-
-### BIO
-
-### NIO
-
-### AIO

+ 0 - 95
basic-knowledge/java-lock.md

@@ -1,95 +0,0 @@
-## 锁
----
-
-并发 (Concurrency):一个处理器“同时”处理多个任务
-并行 (Parallelism):多个处理器 “同时”处理多个任务
-
-#### 常见锁类型:
-
-1.互斥锁(Mutex)
-
-* 同步块 synchronized block
-
-* 对象锁 object.lock()
-
-* 可重入锁
-
-可重入锁,也叫做递归锁,指的是同一线程外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。ReentrantLock 和synchronized 都是 可重入锁。
-
-在lock函数内,应验证线程是否为已经获得锁的线程。当unlock()第一次调用时,实际上不应释放锁。(采用计数进行统计)
-
-可重入锁最大的特点是避免死锁。
-
-```
-public class Test implements Runnable{
-
-	public synchronized void get(){
-		System.out.println(Thread.currentThread().getId());
-		set();
-	}
-
-	public synchronized void set(){
-		System.out.println(Thread.currentThread().getId());
-	}
-
-	@Override
-	public void run() {
-		get();
-	}
-	public static void main(String[] args) {
-		Test ss=new Test();
-		new Thread(ss).start();
-		new Thread(ss).start();
-		new Thread(ss).start();
-	}
-}
-
-返回结果:
-
-9
-9
-11
-11
-10
-10
-
-```
-
-```
-public class Test implements Runnable {
-	ReentrantLock lock = new ReentrantLock();
-
-	public void get() {
-		lock.lock();
-		System.out.println(Thread.currentThread().getId());
-		set();
-		lock.unlock();
-	}
-
-	public void set() {
-		lock.lock();
-		System.out.println(Thread.currentThread().getId());
-		lock.unlock();
-	}
-
-	@Override
-	public void run() {
-		get();
-	}
-
-	public static void main(String[] args) {
-		Test ss = new Test();
-		new Thread(ss).start();
-		new Thread(ss).start();
-		new Thread(ss).start();
-	}
-}
-```
-
-2.信号量(Semaphore)
-
-* 公平和非公平
-
-3.乐观锁(CAS)
-
-* ABA问题:无锁堆栈实现

+ 0 - 80
basic-knowledge/java-random.md

@@ -1,80 +0,0 @@
-```
-import java.nio.charset.Charset;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.ReentrantLock;
-
-import com.google.common.hash.HashFunction;
-import com.google.common.hash.Hashing;
-
-/**
- * 用于生成随机token
- * 
- * @author onlyone
- */
-public class RandomService {
-
-    private ReentrantLock lock           = new ReentrantLock();
-    private AtomicLong    resetCounter   = new AtomicLong(0);
-    private HashFunction  sha1           = Hashing.sha1();
-
-    private int           resetThreshold = 10000;
-    private Charset       encoding       = Charset.forName("UTF-8");
-
-    private SecureRandom  random;
-
-    public RandomService(){
-        this.resetSecureRandom();
-    }
-
-    private void resetSecureRandom() {
-        this.lock.lock();
-        try {
-            this.random = SecureRandom.getInstance("NativePRNGNonBlocking");
-            // this.random = SecureRandom.getInstanceStrong(); // for windows
-            this.random.generateSeed(32);
-        } catch (NoSuchAlgorithmException e) {
-        } finally {
-            this.lock.unlock();
-        }
-    }
-
-    public String getToken() {
-        if (this.resetCounter.incrementAndGet() > this.resetThreshold) {
-            this.resetSecureRandom();
-            this.resetCounter.set(0);
-        }
-        byte[] bytes = new byte[32];
-        this.random.nextBytes(bytes);
-        byte[] seedBytes = UUID.randomUUID().toString().getBytes(this.encoding);
-        byte[] seeds = new byte[seedBytes.length + bytes.length];
-        System.arraycopy(bytes, 0, seeds, 0, bytes.length);
-        System.arraycopy(seedBytes, 0, seeds, bytes.length - 1, seedBytes.length);
-        return this.sha1.hashBytes(bytes).toString();
-    }
-
-    public static void main(String[] args) {
-
-        RandomService randomService = new RandomService();
-        List<String> list = new ArrayList<String>(200000);
-        List<String> repetition = new ArrayList<String>();
-        for (int i = 0; i < 200000; i++) {
-            String t = randomService.getToken();
-            if (list.contains(t)) {
-                repetition.add(t);
-            } else {
-                list.add(t);
-            }
-            System.out.println(t);
-            System.out.println("i=" + i + ", 重复列表" + repetition + ",list size=" + list.size());
-        }
-
-    }
-}
-
-
-```

+ 0 - 128
basic-knowledge/java.md

@@ -1,128 +0,0 @@
-## java相关
-
----
-
-### 一、基础
-
-
-* 基本语法
-
-	基本数据类型;运算符;表达式;选择与循环语句;类与对象(普通类、抽象类、接口、枚举、Annotation、内部类);继承与实现;异常;package与jar包;序列化与反序列化;正则表达式;重载与覆盖;
-* 数组
-
-	一维数组;二维数组。。。
-* 集合
-	
-	Collection接口;Set相关;List相关;Map相关
-* 线程
-
-	Thread;Runnable;Callable;线程状态;优先级;
-* IO
-
-	File类;字节流(InputStream、OutputStream);字符流(Reader、Writer);转换流(OutputStreamWriter、InputStreamReader);压缩流;
-
-* 网络
-	
-	TCP编程;UDP编程
-* 泛型
-* 反射
-
-	提供api方法取得类的结构;调用类的方法;动态代理
-
-#####  源码分析
-
-* List
-	* [ArrayList](https://mp.weixin.qq.com/s/g1E3GQU1JJzpAxV4zwRKgg) 
-	* [LinkedList](https://mp.weixin.qq.com/s/oA0D1BjzBi7z0Xuvt4O-PQ) 
-	* [CopyOnWriteArrayList](https://mp.weixin.qq.com/s/riVaKy4IR2uRGZzKMLVtAQ)
-* Map
-	* [HashMap](https://mp.weixin.qq.com/s/SyKckwLfV2ypJOzTFA7R_g)
-	* [LinkedHashMap](https://mp.weixin.qq.com/s/m2XfI2A2jJqFLAI_iNZI-g)
-	* [ConcurrentHashMap(上)](https://mp.weixin.qq.com/s/1GJ4Vd2iHgyvjMFLv7sO2A)
-	* [ConcurrentHashMap(下)](https://mp.weixin.qq.com/s/rPa30_MslGTz56UTxE0WAA)
-	* ConcurrentHashMap,Java 7为实现并行访问,引入了Segment这一结构,实现了分段锁,理论上最大并发度与Segment个数相等。Java 8为进一步提高并发性,摒弃了分段锁的方案,而是直接使用一个大的数组。同时为了提高哈希碰撞下的寻址性能,Java 8在链表长度超过一定阈值(8)时将链表(寻址时间复杂度为O(N))转换为红黑树(寻址时间复杂度为O(long(N))),[原文链接](http://www.jasongj.com/java/concurrenthashmap/)
-
-
-### 二、进阶
-
-* 	[java关键字](java修饰词.md)
-* 	[正则表达式](regex.md)
-* 	[常见锁](java-lock.md)
-* 	[常用java类库](常用java类.md)
-*	[java的System.getProperty()方法使用](http://blog.csdn.net/itomge/article/details/9098207)
-* 	[java8函数编程(lambda表达式)](java8-stream.md)
-* 	[java的线程状态](java的线程状态.md)
-* 	[ThreadLocal原理机制](ThreadLocal.md)
-* 	[HashMap的扩容机制](HashMap的扩容机制.md)
-* 	[Exception](java-exception.md)
-* 	[各种坑](各种坑.md)
-* 	[IO类型](java-io.md)
-
-* ###### NIO
-	* 	[NIO](NIO.md)
-	* 	[深度解读 Tomcat 中的 NIO 模型](https://mp.weixin.qq.com/s/Nk7gcwsgBhgMWTRkgAFpRA)
-	* [epoll 浅析以及 nio 中的 Selector](https://mp.weixin.qq.com/s/RmONdyXuJZa8WyJCu2j7WA)
-	* [Linux IO模式及 select、poll、epoll详解](https://segmentfault.com/a/1190000003063859)
-
-* ###### 多线程
-	* [Java 多线程知识汇总(1)](https://mp.weixin.qq.com/s/D3TIYMaCSGtY5Dv38vMHpA)
-	* [Java 多线程知识汇总(2)](https://mp.weixin.qq.com/s/e9avHfZtfiQ4v3fhVHIcAA)
-	* [Java 多线程知识汇总(3)](https://mp.weixin.qq.com/s/s6UvYe1CP8zigR7E6mK9Og)
-
-* ###### java并发包
-	* 	[jdk并发包里常用的类](concurrent-class.md)
-	*	[Java 并发源码合集](https://mp.weixin.qq.com/s/K8y6wMNDLwsmU7EFRx7Dsw)
-	*	[CyclicBarrier](https://mp.weixin.qq.com/s/Y9IcHAwa4VkJN02_U1fDWg)
-	* 	[CountDownLatch](https://mp.weixin.qq.com/s/UA8hoHiJj5vzb2-c08lpDA)
-	* 	[Semaphore](https://mp.weixin.qq.com/s/i_-seey2Du-99SyLSC9OiQ)
-	
-
-
-* ###### 示例
-	* [JAVA集合框架中的常用集合及其特点、适用场景、实现原理简介](https://mp.weixin.qq.com/s/FRF-c2t_Un1Krw29yuxyaw)
-
-* ###### netty	
-	* [Netty 长连接服务](https://www.dozer.cc/2014/12/netty-long-connection.html)
-
-
-### 三、JVM虚拟机
-
-*  	[内存模型](jvm内存结构.md)
-* 	[类加载](类加载器.md)
-*  	[GC垃圾回收](java-gc.md)
-* 	[强引用、软引用、弱引用、幻象引用](java-class-reference.md)
-* ###### JVM 调优
-	*   [jvm参数](jvm-param.md)
-	*  	[jvm自带命令](https://mp.weixin.qq.com/s/QNr8somjodyvU9dRAQG2oA)
-	* 	[如何优化Java GC](https://mp.weixin.qq.com/s/ydkEkh_Uc1paftJLKIsm0w)
-	* 	[大型跨境电商 JVM 调优经历](https://mp.weixin.qq.com/s/bOarreWhQJmS6VTZfFcsZw)
-	*   [Jvm知识汇总](https://mp.weixin.qq.com/s/4c9K5eYMFGVV2WyKaYXVBA)
-	*   [海量连接服务端jvm参数调优杂记](https://mp.weixin.qq.com/s/jt_BCAo8krxPAhLhhLdIrg)
-* ###### JVM 调优工具
-	* 	[XXFox](http://xxfox.perfma.com/)
-
-### 四、前沿
-
-*   [Java 的版本历史与特性](https://mp.weixin.qq.com/s/wcF14v11QaS21UFczqGbVg)
-*   [JavaEE 7 正式发布](http://www.iteye.com/news/27980)
-*   [Java 8-从持久代到metaspace](https://mp.weixin.qq.com/s/w_Uqi5PBkWCqh7qHq6XaKw)
-*   [Java 8的新特性—终极版](https://mp.weixin.qq.com/s/CWNIRk9xGu2XSbrWELTKNg)
-* 	[Java 9 中的新特性](https://mp.weixin.qq.com/s/YalBtZ_dZayMec8aprk6Xw)
-* 	[Java 10正式发布,带来了这些新特性](https://mp.weixin.qq.com/s/UX_tP95fTR99B53DYgHNJQ)
-
-### 五、其它
-* 	[随机数生成 --- NativePRNGNonBlocking ](http://hongjiang.info/java8-nativeprng-blocking/)
-* 	[随机token 生成代码](java-random.md)
-* 	[HashMap扩容、散列碰撞](https://yq.aliyun.com/articles/225660?spm=5176.100238.spm-cont-list.1.LYRwKV)
-* 	[一台Java服务器跑多少个线程](https://mp.weixin.qq.com/s/lQkPltX3yS3bGb9EbxHGAg)
-* 	[【死磕Java并发】—- 深入分析CAS](https://mp.weixin.qq.com/s/--AMdl0GZQkY1MWIWQ-HHA)
-* 	[深入探索 Java 热部署](https://www.ibm.com/developerworks/cn/java/j-lo-hotdeploy/index.html)
-* 	signal 信号
-	* [jvm与系统信号(2)](http://hongjiang.info/jvm-and-signals-2/)
-	* [kill 命令详解 系统信号](https://www.cnblogs.com/MYSQLZOUQI/p/5258898.html)
-	* [Linux系统下如何优雅地关闭Java进程方法](http://www.kgc.cn/bbs/post/90262.shtml)
-	* [signal信号捕捉](https://blog.csdn.net/aa4790139/article/details/8584931)
-	* drools-demo 代码示例,java工程优雅关闭(kill pid , 默认信号 15)
-* 
-	
-	

+ 0 - 213
basic-knowledge/java8-stream.md

@@ -1,213 +0,0 @@
-## java8函数编程(lambda表达式)
----
-
-### 简介
-
-面向对象编程是对数据进行抽象;函数式编程是对行为进行抽象。
-
-核心思想:使用不可变值和函数,函数对一个值进行处理,映射成另一个值。
-
-对核心类库的改进主要包括集合类的API和新引入的流Stream。流使程序员可以站在更高的抽象层次上对集合进行操作。
-
-### 示例
-
-* [Lambda 表达式的 10 个示例](https://mp.weixin.qq.com/s/Xhr9aNEMr0fIUWh27mH1pw)
-* [learn-java8](https://github.com/biezhi/learn-java8)
-* [java8-tutorial](https://github.com/aalansehaiyang/java8-tutorial)
-* [一文让你明白lambda用法与源码分析](https://mp.weixin.qq.com/s/9mgD2aV6gML57RAPIEbZeQ)
-
-### 分类
-
-##### 1.惰性求值方法
-
-```
-lists.stream().filter(f -> f.getName().equals("p1"))
-```
-如上示例,这行代码并未做什么实际性的工作,filter只是**描述**了Stream,**没有产生新的集合**。
-
-如果是多个条件组合,可以通过代码块{}
-
-##### 2.及早求值方法
-
-```
-List<Persion> list2 = lists.stream().filter(f -> f.getName().equals("p1")).collect(Collectors.toList());
-```
-如上示例,collect最终会从Stream产生新值,拥有终止操作。
-
-
-理想方式是形成一个惰性求值的链,最后用一个及早求值的操作返回想要的结果。与建造者模式相似,建造者模式先是使用一系列操作设置属性和配置,最后调用build方法,创建对象。
-
-
-### 常用方法
-
-##### 1.collect(Collectors.toList())
-Stream流生成一个List列表
-
-Collectors.toSet() ,生成set集合。
-
-```
-Collectors.toMap(MemberModel::getUid, Function.identity())
-
-Function.identity() 表示遍历的对象
-```
-
-Collectors里提供了很多方法,比如字符串拼接。
-
-##### 2.map
-将一种类型转换成另外一种类型
-
-#### 3.filter
-对Stream流中的元素过滤。
-
-true:保留;false:扔掉。
-
-##### 4.flatMap
-将多个Stream连接成一个Stream
-
-```
- List<Integer> result= Stream.of(Arrays.asList(1,3),Arrays.asList(5,6)).flatMap(a->a.stream()).collect(Collectors.toList());
- ```
- 结果: [1, 3, 5, 6]
- 
-##### 5.distinct
-去重
-##### 6.count
-计总数
-##### 7.min,max
-最小值,最大值
-
-```
-List<Persion> lists = new ArrayList<Persion>();
-lists.add(new Persion(1L, "p1"));
-lists.add(new Persion(2L, "p2"));
-lists.add(new Persion(3L, "p3"));
-lists.add(new Persion(4L, "p4"));
-Persion a = lists.stream().max(Comparator.comparing(t -> t.getId())).get();
-System.out.println(a.getId());
-```
-如果比较器涉及多个条件,比较复杂,可以定制
-
-```
-
- Persion a = lists.stream().min(new Comparator<Persion>() {
-
-      @Override
-      public int compare(Persion o1, Persion o2) {
-           if (o1.getId() > o2.getId()) return -1;
-           if (o1.getId() < o2.getId()) return 1;
-           return 0;
-       }
- }).get();
- ```
-
-### 代码调试
-
-可以使用peek方法,peek方法可只包含一个空的方法体,只要能设置断点即可,但有些IDE不允许空,可以如下文示例,简单写一个打印逻辑。
-
-注意,调试完后要删掉。
-
-```
-List<Persion> lists = new ArrayList<Persion>();
-lists.add(new Persion(1L, "p1"));
-lists.add(new Persion(2L, "p2"));
-lists.add(new Persion(3L, "p3"));
-lists.add(new Persion(4L, "p4"));
-System.out.println(lists);
-
-List<Persion> list2 = lists.stream()
-				 .filter(f -> f.getName().startsWith("p"))
-                .peek(t -> {
-                    System.out.println(t.getName());
-                })
-                .collect(Collectors.toList());
-                
-System.out.println(list2);
-```
-
-
-
-### 一些例子
-
-* 集合--》取元素的一个属性--》去重---》组装成List--》返回
-
-```
-List<LikeDO> likeDOs=new ArrayList<LikeDO>();
- //add一系列元素 
- //得到收藏贴子的tid列表
-List<Long> likeTidList = likeDOs.stream().map(LikeDO::getTid)
-                .distinct().collect(Collectors.toList());
- 
- ```
- 
- * 集合--》按表达式过滤--》遍历、每个元系处理--》放入预先定义的集合中
- 
- ```
- 
-  Map<String, StkProduct> newStockName2Product = Maps.newConcurrentMap();
-        stockProducts.stream().filter(stkProduct -> stkProduct.enabled).forEach(stkProduct -> {
-            String newName = BCConvert.bj2qj(StringUtils.replace(stkProduct.name, " ", ""));
-            newStockName2Product.put(newName, stkProduct);
-        });
-  ```
-  
- ```
- 
- Set<String> qjStockNames;
- qjStockNames.stream().filter(name -> !acAutomaton.getKey2link().containsKey(name)).forEach(name -> {
-            String value = "";
-            StkProduct stkProduct = stockNameQj2Product.get(name);
-            if (stkProduct != null) {
-                value = stkProduct.name;
-            }
-            acAutomaton.getKey2link().put(name, value);
-        });
- ```
- 
-* 集合--》map
- 
-```
-List<ImageModel> imageModelList = null;
-Map<Long, String> imagesMap = null;
-imagesMap = imageModelList.stream().collect(Collectors.toMap(ImageModel::getAid, o -> IMAGE_ADDRESS_PREFIX + o.getUrl()));
-              
-             
-
-Map<String, String> kvMap = postDetailCacheList.stream().collect(Collectors.toMap((detailCache) ->
-                getBbsSimplePostKey(detailCache.getTid()), JSON::toJSONString));
-
-
-Map<Long, Long> pidToTid;
-List<String> pidKeyList = pidToTid.entrySet().stream().map((o) -> getKeyBbsReplyPid(o.getValue(), o.getKey())).collect(Collectors.toList());
-
-```
- 
- * DO模型---》Model模型
- 
- ```
- List<AdDO> adDOList;
- adDOList.stream().map(adDo -> convertAdModel(adDo))
-                .collect(Collectors.toList());
- 
- ```
- 
- * phones 是一个List\<String>,将相同的元素分组、归类
- 
- ```
-List<String> phones=new ArrayList<String>();
-        phones.add("a");
-        phones.add("b");
-        phones.add("a");
-        phones.add("a");
-        phones.add("c");
-        phones.add("b");
-        Map<String, List<String>> phoneClassify = phones.stream().collect(Collectors.groupingBy(item -> item));
-        System.out.println(phoneClassify);
-        
-返回结果:
-{a=[a, a, a], b=[b, b], c=[c]}
- ```
-  
-### 参考资料
-
-* [http://blog.csdn.net/renfufei/article/details/24600507](http://blog.csdn.net/renfufei/article/details/24600507)
-* [http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html](http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/Lambda-QuickStart/index.html)

+ 0 - 86
basic-knowledge/java修饰词.md

@@ -1,86 +0,0 @@
-## java修饰词
-
----
-
-#### 1.volatile介绍
-
-
-volatile是java最轻量级的同步机制。
-
-**特性:**
-
-*	可见性。变量读写直接操作主存而不是CPU Cache。当一个线程修改了volatile修饰的变量后,无论是否加锁,其它线程都可以立即看到最新的修改。
-*	禁止指令重排序优化。
-*	保证变量可见性,但无法保证原子性。也就是说非线程安全
-
-##### java内存模型:
-
-![image](img/16.png)
-
-[深入分析volatile的实现原理](https://mp.weixin.qq.com/s/mcR8_FHHGA2zb0aW1N02ag?from=groupmessage&isappinstalled=0)
-
-#### 2.synchronized介绍
-
-线程安全,锁区域内容一次只允许一个线程执行,通过锁机制控制。
-
-```
-     一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
-
-     二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
-
-     三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
-```
-
-
-* 同步方法
-
-```
-public synchronized void method(int i);  
-```
-
-每个类实例对应一把锁,类的两个实例没有这个限制。类实例中所有的synchronized方法共用这一把锁,锁的范围有点大。
-
-
-* 同步块
-
-相比上面的同步方法,锁的范围可缩小。
-
-
-```
-synchronized(syncObject) {  
-//允许访问控制的代码  
-}  
-```
-
-其中的代码执行前必须获得对象 syncObject 锁,可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。
-
-#### 3.final介绍
-
-如果修饰变量标识为常量,运行过程中会将值直接替换到变量这个占位符中(避免根据内存地址再次查找这层消耗);如果修改方法,方法不允许被覆盖;修饰类,类不允许被继承。
-
-基础类型,如String,不允许修改。
-
-集合,如Map、List,引用地址不允许改,但可以put、get等操作。
-
-java8编译会检查,如果是修改常量,会编译失败。
-
-![image](img/Snip20160626_24.png)
-
-
-#### 4.static
-
-* 声明属性
-
-	为全局属性,放在全局数据区,只分配一次
-* 声明方法
-
-	类方法,可以由类名称直接调用
-	
-* 声明类
-	
-#### 5.transient
-	
-如果一个对象中的某个属性不希望被序列化,则可以使用transient关键字进行声明。
-
-
-	

+ 0 - 57
basic-knowledge/java的线程状态.md

@@ -1,57 +0,0 @@
-## java的线程状态
-
----
-
-** 线程有5种状态**
-
-1. new,创建线程,尚未启动
-2. Runable,此状态的线程有可能正在执行,也有可能正在等待cpu为它分配时间片
-3. waiting,处于此状态的线程不会被分配时间片,必须要等待被其他线程显式的唤醒,notify或notify all
-4. timed waiting ,处于此状态的线程不会被分配时间片,不过无须等待其它线程显式的唤醒,在一定时间后会由系统自动唤醒
-5. blocked,线程被阻塞了,必须要等待获取锁
-6. terminated,线程已执行结束,如一个线程的run()函数执行完毕后线程就进入死亡状态
-
-
-**影响的命令:**
-
-*	run、start
-
-	需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由Java的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void。
-	
-* 	wait
-
-	当前线程暂停执行并释放对象锁标志,让其他线程可以进入Synchronized数据块,当前线程被放入对象等待池中
-	
-*	notify
-
-	唤醒一个线程
-	
-* 	notifyAll
-
-	唤醒所有线程
-	
-* 	sleep
-
-	休眠一段时间后,会自动唤醒。但它并不释放对象锁。也就是如果有Synchronized同步块,其他线程仍然不能访问共享数据。注意该方法要捕获异常
-	
-* 	join
-
-	当前线程停下来等待,直至另一个调用join方法的线程终止,线程在被激活后不一定马上就运行,而是进入到可运行线程的队列中
-	
-*	yield
-
-	停止当前线程,让同等优先权的线程运行。如果没有同等优先权的线程,那么yield()方法将不会起作用
-
-*	daemon
-
-
-
-
-操会作系统维护一个ready queue(就绪线程队列),某一时刻cpu只为ready queue中位于队列头部的线程服务。 
-
-
-![image](img/Snip20160630_46.png)
-
-**参考资料:**
-
-http://www.jianshu.com/p/c9f847101fae

+ 0 - 45
basic-knowledge/jvm-param.md

@@ -1,45 +0,0 @@
-## jvm参数---性能调优
-
----
-
-#### 一、jvm参数
-
-*	-Xms 
-
-堆最小值

*	-Xmx
-
堆最大堆值。-Xms与-Xmx 的单位默认字节都是以k、m做单位的。
-
通常这两个配置参数相等,避免每次空间不足,动态扩容带来的影响。
-
*	-Xmn 
-
新生代大小

*	-Xss 

每个线程池的堆栈大小。在jdk5以上的版本,每个线程堆栈大小为1m,jdk5以前的版本是每个线程池大小为256k。一般在相同物理内存下,如果减少-xss值会产生更大的线程数,但不同的操作系统对进程内线程数是有限制的,是不能无限生成。

*	-XX:NewRatio 
-
设置新生代与老年代比值,-XX:NewRatio=4 表示新生代与老年代所占比例为1:4 ,新生代占比整个堆的五分之一。如果设置了-Xmn的情况下,该参数是不需要在设置的。

*	-XX:PermSize
-
设置持久代初始值,默认是物理内存的六十四分之一

*	-XX:MaxPermSize 

设置持久代最大值,默认是物理内存的四分之一

*	-XX:MaxTenuringThreshold

新生代中对象存活次数,默认15。(若对象在eden区,经历一次MinorGC后还活着,则被移动到Survior区,年龄加1。以后,对象每次经历MinorGC,年龄都加1。达到阀值,则移入老年代)

*	-XX:SurvivorRatio 

Eden区与Subrvivor区大小的比值,如果设置为8,两个Subrvivor区与一个Eden区的比值为2:8,一个Survivor区占整个新生代的十分之一

*	-XX:+UseFastAccessorMethods 

原始类型快速优化

*	-XX:+AggressiveOpts

编译速度加快

*	-XX:PretenureSizeThreshold

对象超过多大值时直接在老年代中分配



```
-说明:
整个堆大小的计算公式:JVM 堆大小 = 年轻代大小+年老代大小+持久代大小。
增大新生代大小就会减少对应的年老代大小,设置-Xmn值对系统性能影响较大,所以如果设置新生代大小的调整,则需要严格的测试调整。而新生代是用来存放新创建的对象,大小是随着堆大小增大和减少而有相应的变化,默认值是保持堆大小的十五分之一,-Xmn参数就是设置新生代的大小,也可以通过-XX:NewRatio来设置新生代与年老代的比例,java 官方推荐配置为3:8。
-
新生代的特点就是内存中的对象更新速度快,在短时间内容易产生大量的无用对象,如果在这个参数时就需要考虑垃圾回收器设置参数也需要调整。推荐使用:复制清除算法和并行收集器进行垃圾回收,而新生代的垃圾回收叫做初级回收。

```
-

```
StackOverflowError和OutOfMemoryException。当线程中的请求的栈的深度大于最大可用深度,就会抛出前者;若内存空间不够,无法创建新的线程,则会抛出后者。栈的大小直接决定了函数的调用最大深度,栈越大,函数嵌套可调用次数就越多。
-
```
-
**经验:**
-
1. Xmn用于设置新生代的大小。过小会增加Minor GC频率,过大会减小老年代的大小。一般设为整个堆空间的1/4或1/3.
-
2. XX:SurvivorRatio用于设置新生代中survivor空间(from/to)和eden空间的大小比例;
XX:TargetSurvivorRatio表示,当经历Minor GC后,survivor空间占有量(百分比)超过它的时候,就会压缩进入老年代(当然,如果survivor空间不够,则直接进入老年代)。默认值为50%。

3. 为了性能考虑,一开始尽量将新生代对象留在新生代,避免新生的大对象直接进入老年代。因为新生对象大部分都是短期的,这就造成了老年代的内存浪费,并且回收代价也高(Full GC发生在老年代和方法区Perm).
-
4. 当Xms=Xmx,可以使得堆相对稳定,避免不停震荡
-
5. 一般来说,MaxPermSize设为64MB可以满足绝大多数的应用了。若依然出现方法区溢出,则可以设为128MB。若128MB还不能满足需求,那么就应该考虑程序优化了,减少**动态类**的产生。


#### 二、垃圾回收
-

**垃圾回收算法:**
-
*	引用计数法:会有循环引用的问题,古老的方法;
*	Mark-Sweep:标记清除。根可达判断,最大的问题是空间碎片(清除垃圾之后剩下不连续的内存空间);
-*	Copying:复制算法。对于短命对象来说有用,否则需要复制大量的对象,效率低。**如Java的新生代堆空间中就是使用了它(survivor空间的from和to区);**
*	Mark-Compact:标记整理。对于老年对象来说有用,无需复制,不会产生内存碎片

**GC考虑的指标**
-
*	吞吐量:应用耗时和实际耗时的比值;
*	停顿时间:垃圾回收的时候,由于Stop the World,应用程序的所有线程会挂起,造成应用停顿。
-
-```
吞吐量和停顿时间是互斥的。
-对于后端服务(比如后台计算任务),吞吐量优先考虑(并行垃圾回收);
-对于前端应用,RT响应时间优先考虑,减少垃圾收集时的停顿时间,适用场景是Web系统(并发垃圾回收)
```

**回收器的JVM参数**
-
*	-XX:+UseSerialGC

串行垃圾回收,现在基本很少使用。
-
*	-XX:+UseParNewGC
-
-新生代使用并行,老年代使用串行;

*	-XX:+UseConcMarkSweepGC
-
新生代使用并行,老年代使用CMS(一般都是使用这种方式),CMS是Concurrent Mark Sweep的缩写,并发标记清除,一看就是老年代的算法,所以,它可以作为老年代的垃圾回收器。CMS不是独占式的,它关注停顿时间
-
*	-XX:ParallelGCThreads
-
指定并行的垃圾回收线程的数量,最好等于CPU数量
-
*	-XX:+DisableExplicitGC
-
禁用System.gc(),因为它会触发Full GC,这是很浪费性能的,JVM会在需要GC的时候自己触发GC。

*	-XX:CMSFullGCsBeforeCompaction 

在多少次GC后进行内存压缩,这个是因为并行收集器不对内存空间进行压缩的,所以运行一段时间后会产生很多碎片,使得运行效率降低。

*	-XX:+CMSParallelRemarkEnabled

降低标记停顿

*	-XX:+UseCMSCompactAtFullCollection 

在每一次Full GC时对老年代区域碎片整理,因为CMS是不会移动内存的,因此会非常容易出现碎片导致内存不够用的

*	-XX:+UseCmsInitiatingOccupancyOnly 

使用手动触发或者自定义触发cms 收集,同时也会禁止hostspot 自行触发CMS GC

*	-XX:CMSInitiatingOccupancyFraction 

使用CMS作为垃圾回收,使用70%后开始CMS收集

*	-XX:CMSInitiatingPermOccupancyFraction 

设置perm gen使用达到多少%比时触发垃圾回收,默认是92%

*	-XX:+CMSIncrementalMode 

设置为增量模式

*	-XX:+CmsClassUnloadingEnabled 

CMS是不会默认对永久代进行垃圾回收的,设置此参数则是开启

*	-XX:+PrintGCDetails

开启详细GC日志模式,日志的格式是和所使用的算法有关

*	-XX:+PrintGCDateStamps

将时间和日期也加入到GC日志中


**配置参考:**
-

![image](img/13.png)
-
-**前同事分享的一个不错案例:**
-
![image](img/15.png)

+ 0 - 38
basic-knowledge/jvm内存结构.md

@@ -1,38 +0,0 @@
-## jvm内存结构
-
----
-
-* [JVM内存结构](https://mp.weixin.qq.com/s/li3ISdodGu2EK_Fo_4NJPA)
-* [java8 去除永久代增加元数据区Metaspace](https://www.cnblogs.com/paddix/p/5309550.html)
-
----
-
-#### 虚拟机运行时的数据区
-
-![image](img/1.jpg)
-
-a)程序计数器(program counter register),一块较小的内存空间,可以看作当前线程所执行的字节码的行号指示器。由于java虚拟机是采用多线程,通过线程切换获得时间片得到cpu的控制权。为了线程切换后能恢复到正确的执行位置。
-
-b)虚拟机栈,调用一个方法时会创建一个栈帧,用于存储局部变量、对象引用、方法返回值,每一个方法从调用到执行完成,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。通过 -Xss控制大小,如果线程请求的栈深度大于虚拟机所允许的深度,会抛出StatckOverflowError。
-通过递归死锁会引发这种问题。
-
-c)本地方法栈,与虚拟机栈相似,主要是针对native方法服务。
-
-d)堆(heap),所有线程共享,通过new操作产生对象,存放对象实例,分为年轻代(eden、两个survivor)和年老代,通过-Xmx和-Xms控制大小,如果内存不足会抛OutOfMemoryError。通过GC释放
-
-e)方法区:主要是类信息、常量、静态变量,也叫持久代,通过-XXMaxPerSize控制大小,当方法区无法满足内存分配需求时也会抛出OutOfMemoryError。特别注意动态代理子类,在运行期会创建很多新的子类,导致空间不足。
-
-![image](img/2.jpg)
-
-
-* Young GC 
-
-	Eden Space 满了 ;Survivor Space 满了
-
-* Full GC
-
-	老年代满了;持久代满了
-	
-```
-jstat –gcutil  进程ID  刷新时间(可以实时监控jvm 的gc情况)
-```

+ 0 - 86
basic-knowledge/regex.md

@@ -1,86 +0,0 @@
-## 正则表达式
-
----
-
-在Sun的Java JDK 1.40版本中,Java自带了支持正则表达式的包,主要是放在java.util.regex包下面。
-
-```
- Pattern p_script = Pattern.compile("正则表达式", Pattern.CASE_INSENSITIVE);
- Matcher m_script = p_script.matcher(content);
- while (m_script.find()) {
-           // 找到匹配内容,进行后续事情
-            String strAid = m_script.group(1);
-            。。。。
- }
-```
-**Matcher类的常用方法:**
-
-* matches():返回整个目标字符串与Pattern是否匹配
-
-* find():返回与Pattern匹配的下一个子串
-
-* group():返回上一次与Pattern匹配的子串中的内容。group是针对()来说的,group(0)就是指的整个串,group(1) 指的是第一个括号里的东西,group(2)指的第二个括号里的东西
-
-* start():返回上一次与Pattern匹配的子串在目标字符串中的开始位置。
-
-* end():返回上一次与Pattern匹配的子串在目标字符串中的结束位置加1。
-
-**正则表达式语法**
-
-|元字符|描述|
-|--|--|
-| \ | 将下一个字符标记符、或一个向后引用、或一个八进制转义符。例如,“\\n”匹配\n。“\n”匹配换行符。序列“\\”匹配“\”而“\(”则匹配“(”。即相当于多种编程语言中都有的“转义字符”的概念。|
-|^ | 匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。|
-|$ | 匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。|
-| * | 匹配前面的子表达式任意次。例如,zo*能匹配“z”,“zo”以及“zoo”。*等价于{0,}|
-|+ |匹配前面的子表达式一次或多次(大于等于1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。|
-|?|匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”中的“do”。?等价于{0,1}。|
-|{n} |n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。
-|{n,} |n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。|
-|{n,m} |m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。|
-| x\|y |匹配x或y。例如,“z|food”能匹配“z”或“food”或"zood"(此处请谨慎)。“(z|f)ood”则匹配“zood”或“food”。|
-| [xyz] |字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。
-| [^xyz]  |负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“plin”。
-| [a-z] | 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。|
-| [^a-z]  | 负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。|
-| . | 可以匹配任何字符|
-| \d | 匹配一个数字字符。等价于[0-9] |
-| \D | 匹配一个非数字字符。等价于[^0-9] |
-| \s | 匹配所有的空白字符,包括空格、制表符、换页符、换行符、回车符 等等。等价于[ \f\n\r\t\v]。 |
-| \S |匹配所有的非空白字符|
-
-更多内容参考:http://www.cnblogs.com/lzq198754/p/5780340.html
-
-**常用正则表达式**
-
-|规则	|正则表达式语法  |
-|--|--|
-|一个或多个汉字|	^[\u0391-\uFFE5]+$ 
-|邮政编码	 | ^[1-9]\d{5}$ 
-|QQ号码	 | ^[1-9]\d{4,10}$ 
-|用户名(字母开头 + 数字/字母/下划线)|	^[A-Za-z][A-Za-z1-9_-]+$
-|手机号码	 | ^1[3|4|5|8][0-9]\d{8}$ 
-|URL|	^((http|https)://)?([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$ 
-|18位身份证号 |	^(\d{6})(18|19|20)?(\d{2})([01]\d)([0123]\d)(\d{3})(\d|X|x)?$
-|邮箱| ^[a-zA-Z_]{1,}[0-9]{0,}@(([a-zA-z0-9]-*){1,}\.){1,3}[a-zA-z\-]{1,}$ 
-
-
-
-### 示例
-
-```
-示例:
-\\[img(\\=(\\d+)\\,(\\d+))?\\](((http\\:|https\\:)?\\/\\/[a-zA-Z|\\.|0-9]*\\/)?[a-zA-Z|\\/|0-9]*\\.[a-zA-Z]*)\\[\\/img\\]
-
-[img=225,165]http://bbsimg.wacdn.com/forum/201702/07/120732h4p5yw6wk4bwyk5q.jpg[/img]火炉上一分钟如一小时那
-
-
-group(0)=[img=225,165]http://bbsimg.wacdn.com/forum/201702/07/120732h4p5yw6wk4bwyk5q.jpg[/img]
-group(1)==225,165
-group(2)=225
-group(3)=165
-group(4)=http://bbsimg.wacdn.com/forum/201702/07/120732h4p5yw6wk4bwyk5q.jpg
-group(5)=http://bbsimg.wacdn.com/
-group(6)=http:
-
-```

+ 0 - 37
basic-knowledge/spring.md

@@ -1,37 +0,0 @@
-## spring
-
----
-
-### 附录
-
-* [源码](https://github.com/spring-projects/spring-framework)
-
-* [定时任务(复杂的场景还是要借助Quartz框架)](https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html) 
-
-
----
-
-
-
-#### 简介
-
-一个应用非常广泛的java开源框架。主要分为两大块:IOC和AOP。
-
-
-`无论是技术类书籍或者网上资料、学习手册,非常多,此处就不详细列举`
-
-#### 文档
-
-* 事务
-	* [深入理解 Spring 事务原理](http://www.codeceo.com/article/spring-transactions.html)
-	* [Spring事务传播性与隔离性](https://mp.weixin.qq.com/s/u4NLJ3I2vkeZHWBpgHsdEA)
-
-* annotation 重试配置
-	* [Spring重试支持Spring Retry](http://blog.csdn.net/jiesa/article/details/76549381)
-	* [https://stackoverflow.com/questions/38212471/springboot-retryable-not-retrying](https://stackoverflow.com/questions/38212471/springboot-retryable-not-retrying)
-
-*  框架配置
-	* [Spring、Spring MVC、MyBatis 整合文件配置详解](https://mp.weixin.qq.com/s/8-XvEOA4WzrZwytOXpHHyw)
-	
-*  其它
-	* [利用StopWatch监控Java代码运行时间和分析性能](https://jingyan.baidu.com/article/11c17a2c353e20f446e39d38.html)

+ 0 - 131
basic-knowledge/springboo-note.md

@@ -1,131 +0,0 @@
-## spring boot 笔记
----
-
-#### 框架---模块---体系---生态
-
-#### 简介
-
-springboot是基于spring+java+web容器,微服务框架的杰出代表。微服务其实就是将服务粒度做小,使之可以独立承担对外服务的的职责。
-
-##### 特征
-* 遵循“约定胜于配置”的原则,使用spring boot只需要很少的配置,大部分时候可以使用默认配置
-* 项目快速搭建,可以配置整合第三方框架
-* 可完全不使用xml配置,借助java config
-* 内嵌Servlet(如 Tomcat)容器,可以jar包运行
-* 运行中的应用状态监控
-
-**微服务优势:**
-
-*	独立性。每个微服务都是一个独立的项目。可以独立对外提供服务,可以将研发人力资源很好的分摊,避免人力资源密集带来的沟通、协作成本。(低耦合原则)
-*	稳定性。任何一个微服务的失败都将只影响自己或少量其他微服务,不会影响整个服务运行体系。
-
-SpringApplication将一个典型的spring应用启动的流程“模板化”,默认模板化后执行流程就可以满足需求了,如果有特殊需求,SpringApplication在合适的流程节点开放了一系列不同类型的扩展点,我们可以通过这些扩展点对SpringBoot程序的启动和关闭过程进行扩展。
-
-```
-
-@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class,
-                                  DataSourceTransactionManagerAutoConfiguration.class })
-public class Main extends WebMvcConfigurationSupport {
-
-public static void main(String[] args) {
-        SpringApplication app = new SpringApplication(Main.class, "classpath*:/spring/*.xml");
-        app.setShowBanner(false);
-        app.run(args);
-    }
-}
-```
-
-**执行流程:**
-
-1.如果我们使用的是SpringApplication的静态run方法,首先需要创建一个SpringApplication对象实例。
-
-a)使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitialize
-
-b)使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener
-
-c)设置main方法的定义类
-
-2.开始执行run方法的逻辑,首先遍历执行所有通过SpringFactoriesLoader加载到的SpringApplicationRunListener,调用它们的started()方法,告诉这些SpringApplicationRunListener,SpringBoot应用要开始执行了。
-
-3.创建并配置当前SpringBoot应用将要使用的Environment
-
-4.遍历并调用所有的SpringApplicationRunListener的environmentPrepared()方法,告诉它们,Springboot应用使用的Environment准备好了
-
-5.确定SpringBoot应用创建什么类型的ApplicationContext,并创建完成,然后根据条件决定是否使用自定义的ShutdownHook,是否使用自定义的BeanNameGenerator,是否使用自定义的ResourceLoader,然后将准备好的Environment设置给创建好的ApplicationContext使用
-
-6.ApplicationContext创建完成,SpringApplication调用之前加载的ApplicationContextInitialize的initialize方法对创建好的ApplicationContext进行进一步的处理
-
-7.遍历所有SpringApplicationRunListener的contextPrepared()方法,通知它们,SpringBoot应用使用的ApplicationContext准备好了
-
-8.将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的Ioc容器配置加载到已经你准备完毕的ApplicationContext
-
-9.遍历所有的SpringApplicationRunListener的contextLoader()方法,告知ApplicationContext已装载完毕
-
-10.调用ApplicationContext的refresh()方法,完成Ioc容器可用的最后一道工序
-
-11.查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们
-
-12.遍历所有的SpringApplicationRunListener的finished()方法,告知,“初始化完成”
-
----
-
-##### spring boot提供了很多“开箱即用”的依赖模块,以"spring-boot-starter-"开头,以解决不同场景问题。
-
-1.SpringBoot应用将自动使用logback作为应用日志框架,
-
-```
-<dependency>
-    <groupId>org.springframework.boot</groupId>
-    <artifactId>spring-boot-starter-logging</artifactId>
-</dependency>
-```
-
-2.得到一个直接可执行的web应用,当前项目下直接运行mvn spring-boot:run 就可以直接启动一个嵌入tomcat服务请求的web应用。
-
-默认访问地址:http://localhost:8080
-
-```
-<dependency>
-    <groupId>org.springframework.boot</groupId>
-    <artifactId>spring-boot-starter-web</artifactId>
-</dependency>
-```
-如果想使用其它容器,可引入spring-boot-starter-jetty
-
-另外可以修改server.port使用自己指定的端口
-
-3.访问数据库依赖此模块。
-
-```
-<dependency>
-    <groupId>org.springframework.boot</groupId>
-    <artifactId>spring-boot-starter-jdbc</artifactId>
-</dependency>
-```
-
-
-4.负责web应用安全,配合spring-boot-starter-web使用
-
-
-```
-<dependency>
-    <groupId>org.springframework.boot</groupId>
-    <artifactId>spring-boot-starter-security</artifactId>
-</dependency>
-```
-
-
-5.监控,了解应用的运行状态
-
-
-```
-<dependency>
-    <groupId>org.springframework.boot</groupId>
-    <artifactId>spring-boot-starter-actuator</artifactId>
-</dependency>
-```
-
-上面只是介绍一些常用的组件,sping社区还有很多其它优秀的组件,可以根据自己的业务情况研究自取。
-
-
-

+ 0 - 25
basic-knowledge/springboot-hot-reload.md

@@ -1,25 +0,0 @@
-## spring boot 热部署
----
-
-
-![image](img/18.png)
-
-
-右键---》Run As---》Run Configurations---》在Arguments的tab里面设置VM参数如下
-
-```
--javaagent:/Users/onlyone/M2/org/springframework/springloaded/1.2.6.RELEASE/springloaded-1.2.6.RELEASE.jar  -noverify
-```
-
-![image](img/19.png)
-
-
-** 即可支持在编码过程中代码热部署!!! **
-
-![image](img/20.png)
-
-** 另外支持 debug 模式!!! Dubug As --》Java Application  **
-
-其它方式可参考:
-
-http://blog.csdn.net/l1028386804/article/details/69940574

+ 0 - 314
basic-knowledge/springboot-javaConfig.md

@@ -1,314 +0,0 @@
-## springboot-javaConfig
----
-
-* @SpringBootApplication
-
-```
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-@Inherited
-@Configuration
-@EnableAutoConfiguration
-@ComponentScan
-public @interface SpringBootApplication {
-
-	/**
-	 * Exclude specific auto-configuration classes such that they will never be applied.
-	 * @return the classes to exclude
-	 */
-	Class<?>[] exclude() default {};
-
-}
-```
-定义在main方法入口类处,用于启动sping boot应用项目
-
-* @EnableAutoConfiguration
-
-让spring boot根据类路径中的jar包依赖当前项目进行自动配置
-
-在src/main/resources的META-INF/spring.factories
-
-```
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
-org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
-
-若有多个自动配置,用“,”隔开
-```
-
-* @ImportResource
-
-加载xml配置,一般是放在启动main类上
-
-```
-@ImportResource("classpath*:/spring/*.xml")  单个
-
-@ImportResource({"classpath*:/spring/1.xml","classpath*:/spring/2.xml"})   多个
-
-```
-
-* @Value
-
-application.properties定义属性,直接使用@Value注入即可
-
-```
-public class A{
-	 @Value("${push.start:0}")    如果缺失,默认值为0
-     private Long  id;
-}
-```
-
-* @ConfigurationProperties(prefix="person")
-
-可以新建一个properties文件,ConfigurationProperties的属性prefix指定properties的配置的前缀,通过location指定properties文件的位置
-
-```
-@ConfigurationProperties(prefix="person")
-public class PersonProperties {
-	
-	private String name ;
-	private int age;
-}
-```
-
-* @EnableConfigurationProperties
-
-用 @EnableConfigurationProperties注解使 @ConfigurationProperties生效,并从IOC容器中获取bean。
-
-https://blog.csdn.net/u010502101/article/details/78758330
-
-
-* @RestController
-
-组合@Controller和@ResponseBody,当你开发一个和页面交互数据的控制时,比如bbs-web的api接口需要此注解
-
-* @RequestMapping("/api2/copper")
-
-用来映射web请求(访问路径和参数)、处理类和方法,可以注解在类或方法上。注解在方法上的路径会继承注解在类上的路径。
-
-produces属性:定制返回的response的媒体类型和字符集,或需返回值是json对象
-
-```
-@RequestMapping(value="/api2/copper",produces="application/json;charset=UTF-8",method = RequestMethod.POST)
-```
-
-* @RequestParam 
-
-获取request请求的参数值
-
-```
- public List<CopperVO> getOpList(HttpServletRequest request,
-                                    @RequestParam(value = "pageIndex", required = false) Integer pageIndex,
-                                    @RequestParam(value = "pageSize", required = false) Integer pageSize) {
- 
-  }
-```
-
-* @ResponseBody
-
-支持将返回值放在response体内,而不是返回一个页面。比如Ajax接口,可以用此注解返回数据而不是页面。此注解可以放置在返回值前或方法前。
-
-```
-另一个玩法,可以不用@ResponseBody。
-继承FastJsonHttpMessageConverter类并对writeInternal方法扩展,在spring响应结果时,再次拦截、加工结果
-// stringResult:json返回结果
-//HttpOutputMessage outputMessage
-
- byte[] payload = stringResult.getBytes();
- outputMessage.getHeaders().setContentType(META_TYPE);
- outputMessage.getHeaders().setContentLength(payload.length);
- outputMessage.getBody().write(payload);
- outputMessage.getBody().flush();
-```
-
-* @Bean(name="bean的名字",initMethod="初始化时调用方法名字",destroyMethod="close")
-
-定义在方法上,在容器内初始化一个bean实例类。
-
-```
-@Bean(destroyMethod="close")
-@ConditionalOnMissingBean
-public PersonService registryService() {
-		return new PersonService();
-	}
-```
-
-* @Service  用于标注业务层组件
-
-* @Controller用于标注控制层组件(如struts中的action)
-
-* @Repository用于标注数据访问组件,即DAO组件
-
-* @Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
-
-* @PostConstruct
-
-spring容器初始化时,要执行该方法
-
-
-```
-@PostConstruct  
-public void init() {   
-}   
-```
-
-* @PathVariable  用来获得请求url中的动态参数
-
-```
-@Controller  
-public class TestController {  
-
-     @RequestMapping(value="/user/{userId}/roles/{roleId}",method = RequestMethod.GET)  
-     public String getLogin(@PathVariable("userId") String userId,  
-         @PathVariable("roleId") String roleId){
-           
-         System.out.println("User Id : " + userId);  
-         System.out.println("Role Id : " + roleId);  
-         return "hello";  
-     
-     }  
-}
-```
-
-* @ComponentScan  注解会告知Spring扫描指定的包来初始化Spring 
-
-```
-@ComponentScan(basePackages = "com.bbs.xx")
-```
-
-* @EnableZuulProxy
-
-路由网关的主要目的是为了让所有的微服务对外只有一个接口,我们只需访问一个网关地址,即可由网关将所有的请求代理到不同的服务中。Spring Cloud是通过Zuul来实现的,支持自动路由映射到在Eureka Server上注册的服务。Spring Cloud提供了注解@EnableZuulProxy来启用路由代理。
-
-* Autowired
-
-在默认情况下使用 @Autowired 注释进行自动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个。当找不到一个匹配的 Bean 时,Spring 容器将抛出 BeanCreationException 异常,并指出必须至少拥有一个匹配的 Bean。
-
-当不能确定 Spring 容器中一定拥有某个类的 Bean 时,可以在需要自动注入该类 Bean 的地方可以使用 @Autowired(required = false),这等于告诉 Spring:在找不到匹配 Bean 时也不报错
-
-[@Autowired注解注入map、list与@Qualifier](https://blog.csdn.net/ethunsex/article/details/66475792)
-
-
-* @Configuration
-
-```
-@Configuration("name")//表示这是一个配置信息类,可以给这个配置类也起一个名称
-@ComponentScan("spring4")//类似于xml中的<context:component-scan base-package="spring4"/>
-public class Config {
-
-    @Autowired//自动注入,如果容器中有多个符合的bean时,需要进一步明确
-    @Qualifier("compent")//进一步指明注入bean名称为compent的bean
-    private Compent compent;
-
-    @Bean//类似于xml中的<bean id="newbean" class="spring4.Compent"/>
-    public Compent newbean(){
-        return new Compent();
-    }   
-}
-
-```
-* @Import(Config1.class)
-
-导入Config1配置类里实例化的bean
-
-```
-@Configuration
-public class CDConfig {
-
-    @Bean   // 将SgtPeppers注册为 SpringContext中的bean
-    public CompactDisc compactDisc() {
-        return new CompactDisc();  // CompactDisc类型的
-    }
-}
-
-
-
-@Configuration
-@Import(CDConfig.class)  //导入CDConfig的配置
-public class CDPlayerConfig {
-
-    @Bean(name = "cDPlayer")
-    public CDPlayer cdPlayer(CompactDisc compactDisc) {  
-         // 这里会注入CompactDisc类型的bean
-         // 这里注入的这个bean是CDConfig.class中的CompactDisc类型的那个bean
-        return new CDPlayer(compactDisc);
-    }
-}
-```
-
-* @Order
-
-@Order(1),值越小优先级超高,越先运行
-
-* @ConditionalOnExpression
-
-```
-@Configuration
-@ConditionalOnExpression("${enabled:false}")
-public class BigpipeConfiguration {
-    @Bean
-    public OrderMessageMonitor orderMessageMonitor(ConfigContext configContext) {
-        return new OrderMessageMonitor(configContext);
-    }
-}
-```
-
-开关为true的时候才实例化bean,后面是默认值
-
-* ConditionalOnWebApplication
-
-当前项目是WEB项目的条件下
-
-https://www.jianshu.com/p/23f504713b94
-
-
-* @ConditionalOnProperty
-
-这个注解能够控制某个 @Configuration 是否生效。具体操作是通过其两个属性name以及havingValue来实现的,其中name用来从application.properties中读取某个属性值,如果该值为空,则返回false;如果值不为空,则将该值与havingValue指定的值进行比较,如果一样则返回true;否则返回false。如果返回值为false,则该configuration不生效;为true则生效。
-
-https://blog.csdn.net/dalangzhonghangxing/article/details/78420057
-
-* @ConditionalOnClass
-
-该注解的参数对应的类在class path中,否则不解析该注解修饰的配置类
-
-```
-@Configuration
-@ConditionalOnClass({Gson.class})
-public class GsonAutoConfiguration {
-    public GsonAutoConfiguration() {
-    }
-
-    @Bean
-    @ConditionalOnMissingBean
-    public Gson gson() {
-        return new Gson();
-    }
-}
-
-```
-
-* ConditionalOnBean
-
-
-```
-@Configuration
-@ConditionalOnBean({LoadBalancerClient.class})
-@EnableConfigurationProperties({LoadBalancerRetryProperties.class})
-public class LoadBalancerAutoConfiguration {
-。。。
-
-}
-```
-只有 LoadBalancerClient类创建的bean对象在容器中存在时,才会执行LoadBalancerAutoConfiguration中的配置类
-
-
-* @ConditionalOnMisssingClass({ApplicationManager.class})
-
-如果存在它修饰的类的bean,则不需要再创建这个bean;
-
-
-* @ConditionOnMissingBean(name = "example")
-
-表示如果name为“example”的bean存在,该注解修饰的代码块不执行。

+ 0 - 41
basic-knowledge/springboot-unit.md

@@ -1,41 +0,0 @@
-## eclipse中如何跑spring boot的单元测试
----
-
-
-1、首先引入对应的pom依赖
-
-```
-<dependency>
-   <groupId>org.springframework.boot</groupId>
-   <artifactId>spring-boot-configuration-processor</artifactId>
-   <optional>true</optional>
-</dependency>
-```
-
-```
-@RunWith(SpringJUnit4ClassRunner.class)
-@ContextConfiguration(locations = {"classpath*:spring/bbs*.xml"})
-public class AbstractTest {
-
-}
-
-public class AdServiceTest extends AbstractTest {
-
-    @Autowired
-    AdService adService;
-
-    @Test
-    public void test() {
-        AdParam adParam = new AdParam();
-        adParam.setAdPositionId(16005);
-        adParam.setNum(20);
-        List<AdModel> adModels = adService.queryAdList(adParam);
-        System.out.println(JSON.toJSONString(adModels));
-    }
-}
-
-```
-
-**参考资料:**
-
-http://412887952-qq-com.iteye.com/blog/2307104

+ 0 - 45
basic-knowledge/springboot.md

@@ -1,45 +0,0 @@
-## spring boot
-
----
-
-### 一、手册
-
-
-* [源码](https://github.com/spring-projects/spring-boot)
-* [spring boot 笔记](springboo-note.md)
-* [SpringBoot 组件接入示例](https://github.com/aalansehaiyang/SpringBoot-Learning)
-* [java autoConfig配置](springboot-javaConfig.md)
-* [代码热部署](springboot-hot-reload.md)
-* [eclipse中如何跑spring boot的单元测试](springboot-unit.md)
-* [异步调用Async](https://blog.csdn.net/v2sking/article/details/72795742)
-
-
-#### 接口扩展
-
-* [ApplicationListener](https://my.oschina.net/spinachgit/blog/1635218?nocache=1522203306031)
-* [ApplicationObjectSupport](https://blog.csdn.net/huangbo_embed/article/details/50342669)
-* [FactoryBean]()
-* [InitializingBean]()
-* 拦截器
-	* [HandlerInterceptor、WebMvcConfigurerAdapter](https://blog.csdn.net/qq_27905183/article/details/79079762)
-	* [ClientHttpRequestInterceptor、RestTemplate](https://www.jianshu.com/p/deb5e5efb724)
-* AOP
-	* [@Around增强处理简单示例](https://www.cnblogs.com/ssslinppp/p/5845659.html)
-
-### 二、资料集
-
-* [Spring Boot 系列文章](http://www.ityouknow.com/spring-boot.html)
-* [【github】awesome-spring-boot,收集各种Spring Boot 学习资源 ](https://github.com/ityouknow/awesome-spring-boot) 
-* [基于spring Boot 的开源软件](https://mp.weixin.qq.com/s/iwYVhvNgfi0VTkl2tqMbNw)
-* 系列
-	* [springboot-learning-example](https://github.com/JeffLi1993/springboot-learning-example)
-	* [Spring Boot 简书](http://www.jianshu.com/collection/f0cf6eae1754)
-	* [Spring干货汇总](https://mp.weixin.qq.com/s/VFHmOIp-H4lgh4gQE-cj5A)
-	* 《SpringBoot揭秘--快速构建微服务体系》
-* [给你一份SpringBoot知识清单](https://mp.weixin.qq.com/s/weh1bwsxBXQC1sbBo7_nwQ)
-
-### 三、前沿
-
-* [Spring Boot 2.0正式发布,新特性解读](https://mp.weixin.qq.com/s/lsJU_XFmI3dPpkWndrsAuw)
-* [Spring Boot 2.0权威发布](https://mp.weixin.qq.com/s/aSzZYsYux9iRHJOcbpvSWg)
-* [Spring Boot 2.1.0 权威发布](https://mp.weixin.qq.com/s/7Fck8qYDZiYqsHE7qjbV1Q)

+ 0 - 57
basic-knowledge/springcloud.md

@@ -1,57 +0,0 @@
-## Spring Cloud
-
----
-
-几大模块:服务发现(Eureka),断路器(Hystrix),智能路由(Zuul),客户端负载均衡(Ribbon)
-
-spring --> spring boot --> spring cloud
-
-### 一、手册
-
-* [源码](https://github.com/spring-cloud/spring-cloud-netflix)
-* [中文社区](http://bbs.springcloud.com.cn/)
-* [源码分析](http://www.jianshu.com/u/6a622d516e32)
-* [推荐博客](http://www.ityouknow.com/springcloud/2016/12/30/springcloud-collect.html)
-* [Spring Cloud 构建微服务示例](https://github.com/aalansehaiyang/SpringCloud-Learning)
-* [spring Cloud 核心组件](https://github.com/ityouknow/spring-cloud-examples)
-
-	* [注册中心 Eureka](http://www.ityouknow.com/springcloud/2017/05/10/springcloud-eureka.html)
-		* 生产中我们可能需要三台或者大于三台的注册中心来保证服务的稳定性,配置的原理其实都一样,将注册中心分别指向其它的注册中心。
-		* 不同的服务器之间通过异步模式互相复制各自的状态。
-	* [服务注册与发现](http://blog.didispace.com/springcloud6/)
-		* client初始时为java提供的,如果是Node.js、Net等语言,也有其对应的client,按规范将接口的自定义协议注册到注册中心即可。
-		* 客户端向注册中心注册自身提供的服务,并周期性地发送心跳来更新它的服务租约。当服务关闭时,向Eureka Server取消租约。
-	* [熔断器 Hystrix](http://www.ityouknow.com/springcloud/2017/05/16/springcloud-hystrix.html)
-		* 容错管理组件。帮助服务依赖中出现延迟或故障时,提供强大的容错能力。
-	* [服务网关 Zuul](https://mp.weixin.qq.com/s/5PQ9iyPfYCEcJ5W7q0T2oQ)
-		* 通过一个API网关根据请求的url,路由到相应的服务
-		* [服务网关zuul初级篇](http://www.ityouknow.com/springcloud/2017/06/01/gateway-service-zuul.html)
-		* [Netflix正式开源其API网关Zuul 2](https://mp.weixin.qq.com/s/wh_7duo4God8_9awPJBJbQ)
-	* [客户端负载均衡 Ribbon](http://blog.didispace.com/spring-cloud-starter-dalston-2-2/)
-		* 通过在客户端中配置ribbonServerList来设置服务端列表去轮询访问以达到均衡负载的作用。
-	* [客户端负载均衡 Feign](http://blog.didispace.com/spring-cloud-starter-dalston-2-3/)	
-		* Feign是基于Ribbon实现的,所以它自带了客户端负载均衡功能,也可以通过Ribbon的IRule进行策略扩展。
-		* 创建接口并用注解来配置它即可完成对Web服务接口的绑定。它具备可插拔的注解支持,包括Feign注解、JAX-RS注解。它也支持可插拔的编码器和解码器。Spring Cloud Feign还扩展了对Spring MVC注解的支持,同时还整合了Ribbon和Eureka来提供均衡负载的HTTP客户端实现。
-	* config
-		* 分布式配置管理
-		* [Spring Cloud Config采用数据库存储配置内容](https://mp.weixin.qq.com/s/cQ7iSBv9YZZMH95Zot7JLg)
-* 配置参数
-	* [SpringCloud Eureka参数配置项详解](http://www.cnblogs.com/chry/p/7992885.html)
-
-### 二、博客
-
-* [【github】SpringCloud-Learning](https://github.com/dyc87112/SpringCloud-Learning)
-* [【github】SpringBoot-Learning](https://github.com/dyc87112/SpringBoot-Learning)
-* [【github】SpringCloudLearning](https://github.com/forezp/SpringCloudLearning)
-* [【CSDN】史上最简单的 Spring Cloud 教程](https://blog.csdn.net/column/details/15197.html)	
-* [【文档】SpringCloud.cc](https://springcloud.cc/spring-cloud-dalston.html)
-* [【github】SpringCloud-Learning](https://github.com/aalansehaiyang/SpringCloud-Learning)
-
-
-### 三、闲谈
-
-* [Spring Cloud在国内中小型公司能用起来吗?](https://mp.weixin.qq.com/s/vnWXpH5pv-FAzLZfbgTGvg)
-
-#### 四、坑
-
-* [注册中心备份节点 unavailable-replicas问题](http://www.ccblog.cn/95.htm)

+ 0 - 56
basic-knowledge/各种坑.md

@@ -1,56 +0,0 @@
-## 各种坑
-
----
-
-#### 1. SimpleDateFormat 不是线程安全的
-
-使用过程不要定义为静态全局变量。
-
-**正确使用:**
-
-```
-    /**
-     * 时间是否是今天
-     */
-    public static boolean isToday(Long second) {
-        if (second == null) {
-            return false;
-        }
-        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
-        String today = sf.format(System.currentTimeMillis());
-        String compare = sf.format(new Date(second * 1000L));
-        return StringUtils.equals(today, compare);
-    }
-    
-```
-
-
-#### 2.cache模型里面字段数据范围
-通常预发环境和线上环境会共用一套cache,如何避免两套环境间的数据干扰。
-
-```
-写入:DO --> cacheModel
-读出:cacheModel --> DO
-查询接口:DO --> ServiceModel
-```
-#### 3.字符串不变性
-
-下面这张图展示了这段代码做了什么
-
-```
-String s = "abcd";
-s = s.concat("ef");
-```
-
-![image](img/21.png)
-
-#### 4.HashCode被设计用来提高性能。
-
-equals()方法与hashCode()方法的区别在于:
-
-如果两个对象相等(equal),那么他们一定有相同的哈希值。
-如果两个对象的哈希值相同,但他们未必相等(equal)。
-
-注:== 表示两对象内存地址相同
-
-#### 5.

+ 0 - 95
basic-knowledge/常用java类.md

@@ -1,95 +0,0 @@
-## 常用java类库
-
----
-
-#### 1.Runtime类
-
-* jvm虚拟机注册一个勾子,当虚拟机要关闭时,会执行预先注册的线程任务。
-
-```
-Runtime.getRuntime().addShutdownHook(new Thread() {
-
-            public void run() {
-                try {
-                    logger.info("## stop the canal client");
-                    clientTest.stop();
-                } catch (Throwable e) {
-                    logger.warn("##something goes wrong when stopping canal:\n{}", ExceptionUtils.getFullStackTrace(e));
-                } finally {
-                    logger.info("## canal client is down.");
-                }
-            }
-
-        });
- ```
- 
- [ShutdownHook - java中优雅地停止服务](https://mp.weixin.qq.com/s/z5bfW8OJOYMK-fzSzDOkdg)
- 
- * 获取JVM的内存空间信息
- 
-####2. 字符串操作
-
-* StringBuffer 线程安全
-
-* StringBuilder 非线程安全,适用于单线程,速度快
-
-####3. 日期操作
-
-* Date
-* Calendar
-* DateFormat
-* SimpleDateFormat
-
-####4.Math类
-
-数学操作相关,提供一系列的数学操作方法。比如:求平方根,两数的最大值,两数的最小值,四舍五入,2的3次方,绝对值,三角函数等等
-
-####5. Random类
-
-可以指定一个随机数的范围,然后任意产生此范围的数字。
-
-####6. DecimalFormat
-
-Format的一个子类,可以根据用户自定义格式来格式化数字
-
-```
-DecimalFormat df=new DecimalFormat("###,###.###");
-df.format(1234232.1456);
-
-结果
-1,234,232.146
-
-```
-
-####7. BigInteger
-
-大整数类。如果在操作时一个整型数据超过了整数的最大长度Long,可以使用此类。
-
-提供了一系列方法,用于基本运算。
-
-####8. BigDecimal
-
-float和double无法做到准确的精度计数,如果需要精确的计算结果,可以使用此类。
-
-注:通常涉及到钱的计算,比如交易订单各种折扣、优惠混合运算,最好使用此类。
-
-
-####9. Arrays
-
-数组元素的查找、数组内容的填充、排序等
-
-####10. Comparable接口
-
-比较器,排序时使用。
-
-```
-public interface Comparable<T> {
-   public int compareTo(T o);
-} 
- ```
- 
-与Arrays.sort(Object[] a)方法或者Collections.sort(List<T> list)方法组合使用。
- 
-另一种用法:
-
-java.util.Collections.sort(List<T>, Comparator<? super T>)

+ 0 - 4
basic-knowledge/常用jdk命令.md

@@ -1,4 +0,0 @@
-## 常用jdk命令
-
----
-

+ 0 - 87
basic-knowledge/常用的设计模式.md

@@ -1,87 +0,0 @@
-## 常用的设计模式
----
-
-###	单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点
-
```
-public class SingletonClass{
-    private static SingletonClass instance=null;
-    public static SingletonClass getInstance(){
-        if(instance==null){
-            synchronized(SingletonClass.class){
-                if(instance==null){
-                    instance=new SingletonClass();
-                }
-            }
-        }
-        return instance;
-    }
-}
-```
[如何实现一个正确的单例模式](https://mp.weixin.qq.com/s/2ARZEkUZWKN0fxHfkayYHA)
-
[漫画:什么是单例模式?(整合版)](https://mp.weixin.qq.com/s/1fQkkdtzYh_OikbYJnmZWg)

### 工厂模式
-
-**类图:**
-
![image](img/10.jpg)

###  装饰模式
装饰者模式,在保持原有功能不变的情况下将一个类重新装饰,使其具有更强大的功能,用一句成语形容“锦上添花”。
-
**类结构:**
-
-![image](img/3.png)

 
Component:抽象组件,定义了一组抽象的接口,指定了被装饰的组件都有哪些功能。
-

ComponentImpl:抽象组件实现类,完成了基本的功能实现。

Decorator:装饰器角色,持有Component的实例引用,有点递归的感觉。

伪代码:
-
```
Component c=new ComponentImpl();
Decorator d1=new Decorator();
d1.setComponent(c);
Decorator d2=new Decorator();
d2.setComponent(d1);
Decorator d3=new Decorator();
d3.setComponent(d2);
Decorator d4=new Decorator();
d4.setComponent(d3);
d4.methodA();
-
```
装饰者模式和适配器模式有点类似,都是包装(wrapper)了一个类,但目地却不相同。适配器模式是将一个接口转换成另一个接口,从而达成匹配。而装饰者模式并没有改变原来的接口,而是改变原有对象的处理方法,借助递归提升性能。
### 适配器模式
-

适配器模式就是一个类的接口不能被客户端接受,需要转换为另一种接口,从而使两个不匹配的接口能在一起工作。
-
**类结构**
-
![image](img/4.png)
 
Adaptee:源接口,需要适配的接口
-
Target:目标接口,暴露出去的接口
-
Adapter:适配器,将源接口适配成目标接口
-
举个现实例子:
-
Adaptee就是相机中的内存卡片,Target就是电脑,而Adapter则是USB读卡器。
-
**适用场景:**
-
比如查物流信息,由于物流公司的系统都是各自独立,在编程语言和交互方式上有很大差异,需要针对不同的物流公司做单独适配,同时结合不同公司的系统性能,配置不同的响应超时时间
-
-![image](img/5.png)

 
### 观察者模式
-

观察者模式通常也叫发布—订阅模式,或者事件监听模式,定义一对多的依赖关系,让多个观察者对象同时监听一个主题对象,如果这个主题对象的状态发生变化时,会通知所有的观察者对象。
异步消息(MQ、activeMQ)都是基于这种模式

**类结构图:**
-
-![image](img/6.png)
 
* Subject:主题类,将所有的观察者对象保存在一个List集合中,并提供增、删的方法,以及状态变化后的通知方法。
* Observer:观察者的抽象接口,提供了一个抽象的动作方法,具体的业务由子类来实现
* ConcreteObserver:具体的观察者,负责实现自己的业务动作
* ConcreteSubject:具体的主题类,在内部状态发生变化时,给所有登记过的观察者发出通知。

**优点:**
-
* 解耦,将耦合的双方都依赖于抽象类,而不是依赖于具体。从而使得各自的变化不会影响另一边的变化。
* Observer采用的是抽象类,这样的好处是可以将多个子类相同的代码逻辑抽取出来,放到抽象类中

### 责任链模式
-
责任链模式就是很多对象由每个对象对其下家的引用串连起来形成一条链,请求在这条链上传递,直到最终处理完。就象一根水管一样,水从一端流入,会经过一系列的阀门,最终从另一端流出。如果有一个阀门关着,水都流不出来。
-
**链上的节点可以控制,根据是否执行分为两种情况:**
-
-* 找到对应的点,执行,跳出。如:for循环的break
* 所有的节点都执行一遍,上个节点的返回结果作为下个节点的入参
-
http://blog.csdn.net/itomge/article/details/20792567
-

###	策略模式
-
策略模式通常是指完成某个操作可能会有多种方法,适用于多种场合。我们需要把每个操作方法当做一个实现策略,调用者可根据需要(特定的规则)选择合适的策略
-

**结构类图:**
-
![image](img/7.png)
 
* Context:使用不同的策略环境,根据自身的条件选择不同的策略实现类来完成所需要的操作。他持有一个策略实例的引用
* Strategy:抽象策略,定义每个策略都要实现的方法
* Realize1,Realize2:负责实现抽象策略中定义的策略方法。
-
```
例子:
 @Override
    @Enhancement({ @Capability(type = CapabilityTypeEnum.INVOCATION_STATS) })
    public void sendGoods(SendGoodsParam param) throws ServiceException {
        if (null == param || null == param.getId()) {
            this.throwInvalidError(ErrorCodeEnum.NULL_PARAM, null, param);
        }
        TradeFlowService t = createTradeFlowServiceByOrderId(param.getId());
        t.sendGoods(param);
    }
-```
createTradeFlowServiceByOrderId方法会根据”订单号的长短“选择具体的子策略
-
* 长订单号:tpTradeFlowService
* 短订单号:unifyTradeFlowService

彼此子策略实现互不干扰,有效达到隔离效果。

### 合成模式
-
可以控制某资源同时被访问的个数。例如连接池中通常要控制创建连接的个数。
-
tryAcquire方法,获得锁
-
release方法,释放锁
-
### 模板模式
-
应用场景很多,尤其是在框架设计中,提供了一个方便的开发程序的模板,你只要实现模板中的一些接口或方法就能完成一个复杂的任务。
-
**结构类图:**

![image](img/8.png) 

* AbstractTemplate:定义一个完整的框架,方法的调用顺序已经确定,但会定义一些抽象的方法留给子类去实现
* SubTemplate:实现抽象模板中定义的抽象方法,从而形成一个完整的流程逻辑
-
```
public TradeFlowActionResult execute(TradeFlowActionParam param, Map context) throws ServiceException {
        try {    // 业务逻辑校验
            this.validateBusinessLogic(param, context);
        } catch (ServiceException ex) {
            sendGoodsLog.info("SendGoodsAction->validateBusinessLogic got exception. param is " + param, ex);
            throw ex;
        } catch (RuntimeException ex) {
            sendGoodsLog.info("SendGoodsAction->validateBusinessLogic got runtime exception. param is " + param, ex);
            throw ex;
        }
        try {
            // 卖家发货业务逻辑
            this.sendGoods(param, context);
        } catch (ServiceException ex) {
            sendGoodsLog.info("SendGoodsAction->sendGoods got exception. param is " + param, ex);
            throw ex;
        } catch (RuntimeException ex) {
            sendGoodsLog.info("SendGoodsAction->sendGoods got runtime exception. param is " + param, ex);
            throw ex;
        }
        try {
            // 补充业务(结果不影响核心业务)
            this.addition(param, context);
        } catch (ServiceException ex) {
            sendGoodsLog.info("SendGoodsAction->addition got exception. param is " + param, ex);
            throw ex;
        } catch (RuntimeException ex) {
            sendGoodsLog.info("SendGoodsAction->addition got runtime exception. param is " + param, ex);
            throw ex;
        }
        // 处理结果
        return null;
    }
-```
-上面提到的三个抽象方法(业务逻辑校验、卖家发货业务逻辑、补充业务)都是在子类中实现的
-
即控制了主流程结构,又不失灵活性,可以让使用者在其基础上定制开发。

#### 代理模式
-
代理模式,为其它对象提供一种代理以控制对这个对象的访问。
-
**类结构图:**
-
![image](img/9.png)
 
* Subject:接口类,定义了一些需要代理的接口方法
* RealSubject:具体的实现类
* ProxySubject:代理类,保存一个Subject引用,可以注入一个具体的子类比如RealSubject。
-
代理模式其实就是在操作对象时引入一定程度的间接性。这种间接性,可以增加很多附加操作。比如权限控制,参数校验等等
-
```
public class ProxyPersonManager implements PersonManager {
    // 接口引用
    PersonManager realPersonManager = new RealPersonManager();
    @Override
    public double getSalary(String name, String operateName) {
        // 1. 增加一些的权限判断。比如操作人是否有查询某人工资的权限
        // 2. 具体类的调用
        return realPersonManager.getSalary(name, operateName);
    }
}
-
```

#### RBAC
-
基于角色的权限访问控制。
-
用户---》用户的身份(店铺、达人)--》对应的权限集合
-
每个权限都拆分原子的,采用并集的形式。另外增加个性化权限表,专属用户有专门的权限。


#### 事件溯源Event Sourcing
-

几乎所有数据库都支持高可用性集群,大多数数据库对系统一致性模型提供一个易于理解的方式,保证强一致性模型的安全方式是维持数据库事务操作的有序日志,理论上理由非常简单,一个事务日志是一系列数据更新操作的动作有序记录集合,当其他节点从主节点获得这个事务日志时,能够按照这种有序动作集合重新播放这些操作,从而更新自己所在节点的数据库状态,当这个事务日志完成后,次节点的状态最终会和主节点状态一致,
-
-
-Event sourcing事件溯源是借鉴数据库事务日志的一种数据持久方式,在事务日志中记录导致状态变化的一系列领域事件。通过持久化记录改变状态的事件,通过重新播放获得状态改变的历史。 事件回放可以返回系统到任何状态。
-
-https://www.jdon.com/event.html

#### Sidecar模式
-

Sidecar主张以额外的容器来扩展或增强主容器,而这个额外的容器被称为Sidecar容器。也可以理解为插件。
-
-主要是用来改造已有服务。我们知道,要在一个架构中实施一些架构变更时,需要业务方一起过来进行一些改造。然而业务方的事情比较多,像架构上的变更会低优先级处理,这就导致架构变更的 " 政治复杂度 " 太大。而通过 Sidecar 的方式,我们可以适配应用服务,成为应用服务进出请求的代理。这样,我们就可以干很多对于业务方完全透明的事情了。

https://blog.csdn.net/ZYQDuron/article/details/80757232
-
-https://www.cnblogs.com/waterlufei/p/7145746.html
-


+ 0 - 211
basic-knowledge/类加载器.md

@@ -1,211 +0,0 @@
-## 类加载器
-
----
-
-#### 什么是类的加载
-
-类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放入方法区,并在堆区创建一个 java.lang.Class对象,用来描述类在方法区内的数据结构(比如,类的name、全局变量、构造器和方法等)。类加载的最终产物是位于堆区中的 Class对象, Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。允许用户根据这些元信息对象间接调用Class对象的功能,即“反射”机制。
-
-
-![image](img/java/1.png)
-
-类加载器并不需要等到某个类被“首次主动使用”时再加载它,JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了.class文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误(LinkageError错误)如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误
-
-
-
-#### 类的生命周期
-
-![image](img/java/2.png)
-
-其中类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。
-
-##### 1、加载
-
-在加载阶段,虚拟机需要完成以下三件事情:
-
-* 通过一个类的全限定名来获取其定义的二进制字节流。
-* 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
-* 在Java堆中生成一个代表这个类的 java.lang.Class对象,作为对方法区中这些数据的访问入口。
-
-相对于类加载的其他阶段而言,加载阶段(准确地说,是加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,因为开发人员既可以使用系统提供的类加载器来完成加载,也可以自定义自己的类加载器来完成加载。
-
-加载阶段完成后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区之中,而且在Java堆中也创建一个 java.lang.Class类的对象,这样便可以通过该对象访问方法区中的数据。
-
-##### 2、连接
-
-##### 2.1 验证 
-
-**确保被加载的类的正确性。**
-
-验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证阶段大致会完成4个阶段的检验动作:
-
-* 文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以 0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。
-* 元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了 java.lang.Object之外。
-* 字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。
-* 符号引用验证:确保解析动作能正确执行。
-
-验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用 -Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。
-
-##### 2.2 准备
-
-**为类的 静态变量分配内存,并将其初始化为默认值。**
-
-准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。对于该阶段有以下几点需要注意:
-
-* 这时候进行内存分配的仅包括类变量(static),而不包括实例变量,实例变量会在对象实例化时随着对象一块分配在Java堆中。
-* 这里所设置的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。
-
-假设一个类变量的定义为:` public static int value=3;`
-
-那么变量value在准备阶段过后的初始值为0,而不是3,因为这时候尚未开始执行任何Java方法,而把value赋值为3的 public static 指令是在程序编译后,存放于类构造器 \<clinit>()方法中,所以把value赋值为3的动作将在`初始化阶段`才会执行。
-
-
-* 如果类字段的字段属性表中存在 ConstantValue属性,即同时被final和static修饰,那么在准备阶段变量value就会被初始化为ConstValue属性所指定的值。
-
-假设上面的类变量value被定义为: `public static final int value=3;`
-
-编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据 ConstantValue的设置将value赋值为3。我们可以理解为static final常量在编译期就将其结果放入了调用它的类的常量池中
-
-##### 2.3 解析
-
-**把类中的符号引用转换为直接引用**
-
-解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。符号引用就是一组符号来描述目标,可以是任何字面量。
-
-直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。
-
-##### 3、初始化
-
-初始化,为类的静态变量赋予正确的初始值,有两种方式:
-
-* 声明类变量是指定初始值
-* 使用静态代码块为类变量指定初始值
-
-
-JVM初始化步骤
-
-* 假如这个类还没有被加载和连接,则程序先加载并连接该类
-* 假如该类的直接父类还没有被初始化,则先初始化其直接父类
-* 假如类中有初始化语句,则系统依次执行这些初始化语句
-
-类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:
-
-* 创建类的实例,也就是new的方式
-* 访问某个类或接口的静态变量,或者对该静态变量赋值
-* 调用类的静态方法
-* 反射(如 Class.forName(“com.shengsiyuan.Test”))
-* 初始化某个类的子类,则其父类也会被初始化
-* Java虚拟机启动时被标明为启动类的类( Java Test),直接使用 java.exe命令来运行某个主类
-
-##### 4、使用阶段
-
-
-##### 5、结束生命周期
-
-在如下几种情况下,Java虚拟机将结束生命周期
-
-* 执行了 System.exit()方法
-* 程序正常执行结束
-* 程序在执行过程中遇到了异常或错误而异常终止
-* 由于操作系统出现错误而导致Java虚拟机进程终止
-
-#### 类加载器
-
-类的装载器有三个:根装载器(用C++编写),负责装载JRE的核心类库。ExtClassLoader扩展类加载器,负责加载ext目录下的jar包。AppClassLoader系统类装载器,负责装载Classpath路径下的类包。这三个类装载器存在父子层级关系,根装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器。一般来说,Java 应用的类都是由AppClassLoader来完成加载的。可以通过 ClassLoader.getSystemClassLoader() 来获取它。一般来说,开发人员编写的类加载器的父类加载器是 应用类加载器  Application ClassLoader  
-
-除了系统提供的类加载器以外,开发人员可以通过继承 java.lang.ClassLoader 类的方式实现自己的类加载器,以满足一些特殊的需求。
-
-除了根类加载器之外,所有的类加载器都有一个父类加载器。可以通过 getParent()方法得到。**不同的类加载器为相同名字的类创建了额外的名称空间,所以相同名称的类才可以并存在 Java 虚拟机中,只需要用不同的类加载器来加载它们即可。**不同类加载器加载的类之间是不兼容的(相当于两个不同的类型),这就相当于在 Java 虚拟机内部创建了一个个相互隔离的 Java 类空间。这种技术在许多框架中都被用到,如OSGI等。
-
-jvm启动时,会启动jre/rt.jar里的类加载器:bootstrap classloader,用来加载java核心api;然后启动扩展类加载器ExtClassLoader加载扩展类,并加载用户程序加载器AppClassLoader,并指定ExtClassLoader为他的父类;
-
-
-![image](img/12.png)
-
-CommonClassLoader、CatalinaClassLoader和SharedClassLoader与具体部署的Web应用无关,而WebappClassLoader则对应Web应用,每个Web应用都会有独立的类加载器,从而实现类的隔离。当类被加载时,会先检查在内存中是否已经被加载,如果是,则不再加载,如果没有,再由AppClassLoader来加载,先从jar包里找,没有再从classpath里找;如果自定义loader类,就会存在命名空间的情况,不同的加载器加载同一个类时,产生的实例其实是不同的。
-
-#### JVM类加载机制
-
-* **全盘负责**,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
-* **父类委托**,先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
-* **缓存机制**,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效
-
-#### 双亲委派模式
-
-双亲委派模型的工作流程是:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把请求委托给父加载器去完成,依次向上,因此,所有的类加载请求最终都应该被传递到顶层的启动类加载器中,只有当父加载器在它的搜索范围中没有找到所需的类时,即无法完成该加载,子加载器才会尝试自己去加载该类。这也就可以解释为什么无法加载一个自定义的java.lang.String类!!!
-
-双亲委派机制:
-
-```
-1、当 AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。
-2、当 ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。
-3、如果 BootStrapClassLoader加载失败(例如在 $JAVA_HOME/jre/lib里未查找到该class),会使用 ExtClassLoader来尝试加载;
-4、若ExtClassLoader也加载失败,则会使用 AppClassLoader来加载,如果 AppClassLoader也加载失败,则会报出异常 ClassNotFoundException。
-```
-
-ClassLoader源码分析:
-
-```
-protected synchronized Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException{
- // 首先判断该类型是否已经被加载
- Class c = findLoadedClass(name);
- if (c == null) {
- 	//如果没有被加载,就委托给父类加载或者委派给启动类加载器加载
-     try {
-  		if (parent != null) {
-     	 	 //如果存在父类加载器,就委派给父类加载器加载,false表示加载的类不会初始化
-     		 c = parent.loadClass(name, false);
-  		} else {
-     		//如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方法native 			// Class findBootstrapClass(String name)
-      		c = findBootstrapClass0(name);
-  		}
-     } catch (ClassNotFoundException e) {
-         // 如果父类加载器和启动类加载器都不能完成加载任务,才调用自身的加载功能
-         c = findClass(name);
-     }
- }
- if (resolve) {
-     resolveClass(c);
- }
- return c;
-}
-```
-
-双亲委派模型意义:
-
-* 系统类防止内存中出现多份同样的字节码
-* 保证Java程序安全稳定运行
-
-
-#### 类的完整标识是(classLoader,package,className)
-
-#### Class.forName()和ClassLoader.loadClass()区别
-
-类加载有三种方式:
-
-* java命令行启动应用时候由JVM初始化加载
-* 通过Class.forName()方法动态加载
-* 通过ClassLoader.loadClass()方法动态加载
- 
-```
-Class<?> loadClass(String name) 
-
-Class<?> loadClass(String name, boolean resolve) 
-```
-
-我们看到上面两个方法声明,第二个方法的第二个参数用于设置加载类的时候是否链接该类(上文中装载类文件的第二步),true链接,否则就不链接。Class类的forName方法则相反,使用forName加载时会将Class进行解析和初始化。
-
-例如:JDBC DRIVER的加载,我们在加载JDBC驱动的时候都是使用的forName而非是ClassLoader的loadClass方法呢?我们知道,JDBC驱动是通过DriverManager,必须在DriverManager中注册,如果驱动类没有被初始化,则不能注册到DriverManager中,因此必须使用forName而不是用LoadClass。 
-
-#### 自定义类加载器
-
-通常情况下,我们都是直接使用系统类加载器。但是,有的时候,我们也需要自定义类加载器。比如应用是通过网络来传输 Java类的字节码,为保证安全性,这些字节码经过了加密处理,这时系统类加载器就无法对其进行加载,这样则需要自定义类加载器来实现。自定义类加载器一般都是继承 ClassLoader类,并重写 findClass 方法
-
-#### 参考资料:
-
-https://mp.weixin.qq.com/s/rLooaTOU_NQTJdn28KAUFw
-
-
-
-

+ 0 - 47
data-base/DAO层接口性能监控.md

@@ -1,47 +0,0 @@
-## DAO层接口性能监控
-
----
-
-####简介:
-
-笼统来讲讲,任何系统都可以抽象为数据+算法。而数据库作为数据的存储系统,其响应快慢直接影响着系统的整体性能。
-
-目前很多大公司内部都有一些定制的监控系统,可以多维度采集数据,生成各种报表。
-
-不过这样的系统维护成本比较高,甚至要专门的技术人员维护。如果是创业公司,可能不具备这种条件,不过我们可以通过一些简单方法,也能达到同样的效果。
-
-比如通过Spring AOP机制,统计dao方法的调用时间,超过一定阈值,会打印到日志中。后面可以接入邮件系统,每天统计慢sql,了解系统的健康状况,**及时优化各种潜在的风险。**
-
-**代码示例:**
-
-```
-@Aspect
-@Component
-public class DaoRTLogAspect {
-
-    private static final Logger logger = LoggerFactory.getLogger("daoRTLog");
-
-    @Pointcut("execution(public * com.onlyone.bbs.dal.dao..*.*(..))")
-    public void daoLog() {
-    }
-
-    @Around("daoLog()")
-    public Object profile(ProceedingJoinPoint pjp) throws Throwable {
-        String method = pjp.getSignature().toString();
-        Long _startTime = System.currentTimeMillis();
-        try {
-            return pjp.proceed();
-        } finally {
-            Long _wasteTime = System.currentTimeMillis() - _startTime;
-            if (_wasteTime > 50) {
-                StringBuilder sb = new StringBuilder();
-                sb.append("method=").append(method).append(",wasteTime=").append(_wasteTime);
-                logger.info(sb.toString());
-            }
-        }
-    }
-
-}
-
-
-```

+ 0 - 33
data-base/bigint类型.md

@@ -1,33 +0,0 @@
-## mysql中bigint、int、mediumint、smallint 和 tinyint的取值范围
-
----
-
-##### 引言
-
-社区这边的业务就遇到过这个坑,由于是用的开源框架,很多表id的字段用的mediumint类型,随着业务增长,数据量暴增,结果有一天超过id的上限,结果insert db就报错了,影响部分业务功能。
-
-##### 整型数值
-
-整型的每一种都分有无符号(unsigned)和有符号(signed)两种类型,在默认情况下声明的整型变量都是有符号的类型,如果需声明无符号类型的话就需要在类型前加上unsigned。
-
-* bigint
-
-	从 -2^63 (-9223372036854775808) 到 2^63-1 (9223372036854775807) 的整型数据(所有数字),无符号的范围是0到18446744073709551615,共 8 个字节。
-
-*	int
-
-	一个正常大小整数。有符号的范围是-2^31 (-2,147,483,648) 到 2^31 - 1 (2,147,483,647) 的整型数据(所有数字),无符号的范围是0到4294967295。共 4 个字节。
-int 的 SQL-92 同义词为 integer。
-
-*	mediumint
-	
-	一个中等大小整数,有符号的范围是-8388608到8388607,无符号的范围是0到16777215,  [0,2^24-1]。 大小为3个字节。
-	
-*	smallint
-
-	一个小整数。有符号的范围是-2^15 (-32,768) 到 2^15 - 1 (32,767) 的整型数据,无符号的范围是0到65535。大小为 2 个字节。MySQL提供的功能已经绰绰有余,而且由于MySQL是开放源码软件,因此可以大大降低总体拥有成本。
-	
-*	tinyint
-
-	有符号的范围是-128 - 127, 无符号的范围是 从 0 到 255 的整型数据。大小为 1 字节。[0,2^8-1]
-

+ 0 - 80
data-base/database-connection-pool.md

@@ -1,80 +0,0 @@
-## 数据库连接池
-
----
-
-### SQL生命周期:
-
-1. 应用服务器与数据库服务器建立一个连接
-2. 数据库进程拿到请求sql
-3. 解析并生成执行计划,执行
-4. 读取数据到内存并进行逻辑处理
-5. 通过步骤一的连接,发送结果到客户端
-6. 关掉连接,释放资源
-
-
-其中的连接在里面发挥着重大作用,但频繁的创建和销毁,非常浪费系统资源。由于数据库更适合长连接,也就有个连接池,能对连接复用,维护连接对象、分配、管理、释放,也可以避免创建大量的连接对DB引发的各种问题;另外通过请求排队,也缓解对DB的冲击。
-
-
-
-连接池在初始化时创建MIN个连接。如果有业务请求,而此时没有空闲的管道,如果没有达到MAX连接数,无需等待,会申请创建一个新的连接。如果已经达到MAX,只能排队等待,等待的时间取决于block-timeout,如果超过等待时间没有拿到连接,抛拿不到连接的异常。
-
-		
-
-### 推荐开源框架:
-
-Druid首先是一个数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser。
-
-[https://mp.weixin.qq.com/s/SRB0yruUIdmG9z8lXnJ-Ag](https://mp.weixin.qq.com/s/SRB0yruUIdmG9z8lXnJ-Ag)
-
-**附加功能**:
-
-* 监控,比如打印每一条sql详情,统计慢sql
-* 统计,sql调用次数、时间等
-* 安全,比如防御SQL注入攻击,数据库密码加密等
-* 支持spring boot
-
-```
-<dependency>
-    <groupId>com.alibaba</groupId>
-    <artifactId>druid</artifactId>
-    <version>1.0.9</version>
-</dependency>
-````
-
-```
- <bean id="bbsShardingDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"
-          p:url="${jdbc.bbs.sharding.url}"
-          p:username="${jdbc.bbs.sharding.username}"
-          p:password="${jdbc.bbs.sharding.password}"
-          p:initialSize="1"
-          p:minIdle="1"
-          p:maxActive="20"
-          p:maxWait="60000"
-          p:timeBetweenEvictionRunsMillis="60000"
-          p:minEvictableIdleTimeMillis="300000"
-          p:validationQuery="SELECT 'x'"
-          p:testWhileIdle="true"
-          p:testOnBorrow="false"
-          p:testOnReturn="false"
-          p:poolPreparedStatements="false"
-          p:maxPoolPreparedStatementPerConnectionSize="20"
-          p:connectionProperties="config.decrypt=true"
-          p:filters="stat,config">
-    </bean>
-
-```
-
-
-
-接口文档注释:
-
-http://tool.oschina.net/apidocs/apidoc?api=druid0.26
-
-
-### 其它
-
-* [数据库连接池极简教程](https://mp.weixin.qq.com/s/tLysIX9KChNioJ-fMMimxw)
-
-* [阿里巴巴开源项目 Druid 负责人温少访谈](http://www.iteye.com/magazines/90)
-
-

+ 0 - 97
data-base/id-generate.md

@@ -1,97 +0,0 @@
-## id生成器
-
----
-
-### 资料
-
-* [分布式ID生成器](https://mp.weixin.qq.com/s/qO84jWhQ5O2mPafsHrh2bA)
-* [通用的ID产生器--Vesta](https://gitee.com/robertleepeak/vesta-id-generator)
-* [twitter的全局唯一ID生成器---snowflake](https://github.com/twitter/snowflake)
-
----
-如果单表,可以借助于mysql自带的id生成器每次自增+1的方式来生成主键id。
-
-如果分库分表,需要提前在外部生成id,然后将记录插入到对应的分表中。
-
-
-**其实原理很简单,只需实现一个id批量生成查询器即可,大概步骤:**
-
-a)本地引入一个client二方包,当有记录要插入数据库表时,调用nextId方法生成一个id,由于是提前分配的,大多数情况下从本地cache取,如果分配完了,需要从服务器再次申请。
-
-
-```
- private final ConcurrentHashMap<CacheKey, CachedRange> cache = new ConcurrentHashMap<CacheKey, CachedRange>();
- 
- CacheKey:业务场景
- CachedRange:当前批次可用的id区间范围
- ```
- 
- ```
-  public long nextId(String app, String key) {
-        synchronized (this){
-            CacheKey cacheKey = new CacheKey(app, key);
-            CachedRange cachedRange = this.cache.get(cacheKey);
-            if (cachedRange == null || cachedRange.range.getEnd() < cachedRange.pos) {
-                IDRange range = this.service.getNextRange(app, key, this.size);
-                cachedRange = new CachedRange(range, range.getStart()) ;
-            }
-            long pos = cachedRange.pos;
-            cachedRange.pos += 1;
-            this.cache.put(cacheKey, cachedRange);
-            return pos;
-        }
-    }
-    
-size:表示一次获取id的区间长度
-    
-```
-
-b)初始化时或者分配的区间段用完,此时需要从远程服务器申请
-
-
-```
-获取一个可用的IDRange, 结果为闭区间[a, b]
-
-public IDRange getNextRange(String app, String key, int size) {
-
-        synchronized (this) {
-            IDRange result = new IDRange();
-            IDRange range = this.get4Update(app, key, size * this.PRE_ALOCATE_BATCH_NUM);
-            result.setApp(app);
-            result.setKey(key);
-            result.setStart(range.getStart());
-            result.setEnd(range.getEnd());
-
-            this.logger.info("return range: {}", result);
-            return result;
-        }
-    }
-```
-
-```
-// 数据库查询
-
- @Transactional(value="crtTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
-    public IDRange get4Update(String app, String key, int size) {
-        Map<String, String> params = new HashMap<String, String>();
-        params.put("app", app);
-        params.put("key", key);
-        SqlSession sqlSession = this.commonSqlSessionTemplate.getSqlSessionFactory()
-                .openSession();
-        UniversalId universalId = sqlSession.selectOne("select4Update", params);
-        if (universalId == null) {
-            return null;
-        }
-
-        IDRange range = new IDRange();
-        range.setApp(app);
-        range.setKey(key);
-        range.setStart(universalId.getValue() + 1);
-        range.setEnd(universalId.getValue() + size - 1);
-
-        universalId.setValue(universalId.getValue() + size);
-        sqlSession.update("updateValue", universalId);
-        return range;
-    }
-```
-

BIN
data-base/img/1.png


BIN
data-base/img/2.png


BIN
data-base/img/3.png


BIN
data-base/img/4.png


+ 0 - 16
data-base/other.md

@@ -1,16 +0,0 @@
-## 其它
-
----
-
-### 基础
-
-* 	[mysql中bigint、int、mediumint、smallint 和 tinyint的取值范围](bigint类型.md)
-* 	[mysql中int长度的意义](http://blog.csdn.net/qmhball/article/details/51544484)
-* 	[DAO层接口性能监控](DAO层接口性能监控.md)
-* 	[MySQL主从复制详解与实践](http://blog.csdn.net/wangyuanjun008/article/details/79420131)
-
-
-### 业界动态
-
-* 	[NoSQL 没毛病,为什么 MySQL 还是“王”:8 篇值得回顾的技术热文](https://mp.weixin.qq.com/s/g0eqJpZoHDh-c2XdKJkFXw)
-* 	[阿里下一代数据库技术:把数据库装入容器不再是神话](https://mp.weixin.qq.com/s/AIZQ5-F5AngdIESNCXngWw)

+ 0 - 28
data-base/sql-optimize.md

@@ -1,28 +0,0 @@
-## 调优
-
----
-
-### 一、SQL技巧
-
-* insert ignore 
-
-insert ignore 与insert into的区别就是insert ignore 会忽略数据库中已经存在的数据,如果数据库没有数据,就插入新的数据,如果有数据的话就跳过这条数据。这样就可以保留数据库中已经存在数据,达到在间隙中插入数据的目的。
-
-* replace into
-
-replace into 跟 insert 功能类似,不同点在于:replace into 首先尝试插入数据到表中, 1. 如果发现表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插入新的数据。 2. 否则,直接插入新数据。
-
-* ON DUPLICATE KEY UPDATE
-
-批量插入数据 。自动解决索引冲突。
-
-http://blog.csdn.net/u010003835/article/details/54381080
-
-### 二、数据库调优
-
-* [MySQL 大表优化方案](https://mp.weixin.qq.com/s/BMQC2oJlhLoeBDtveXgHpw)
-
-单表优化(字段、索引、查询SQL、引擎、系统参数),读写分离,缓存,表分区,垂直拆分,水平拆分
-
-
-* 

+ 0 - 33
data-base/transaction.md

@@ -1,33 +0,0 @@
-## 事务
-
----
-
-### 事务特性
-
-原子性、一致性、隔离性、持久性,这四个属性通常称为ACID特性。
-
-* 原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
-* 一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
-* 隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
-* 持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
-
-
-### 分布式事务
-
-* [分布式事务](分布式事务.md)
-* [分布式系统常见的事务处理机制](https://mp.weixin.qq.com/s/ja0VRPkfHL9dtOP_PxwxKw)
-* [微服务架构下处理分布式事务的典型方案](https://mp.weixin.qq.com/s/RKwvfKXIHrrkuCqOGZ4CPw)
-* [解决分布式系统事务一致性的几种方案对比](https://mp.weixin.qq.com/s/kzmTKKH-t6tpJ97fa6TYPg)
-* [多库多事务降低数据不一致概率](https://mp.weixin.qq.com/s/FvB-hOBT13SMfZko5iagAg)
-* [蚂蚁技术专家:一篇文章带你学习分布式事务](https://mp.weixin.qq.com/s/abjDjGGz5RUoCNCdnoxOjQ)
-
-#### 开源框架
-
-* [tcc-transaction是TCC型事务java实现](https://github.com/changmingxie/tcc-transaction)
-* [TCC分布式事务的实现原理](https://mp.weixin.qq.com/s/K0PCZmdXyJYwyuEPW8bvFg)
-* [分布式事务 TCC-Transaction 源码分析 —— Dubbo 支持](https://mp.weixin.qq.com/s/WRH8C3MYSFghFopBKmshJw)
-* [分布式事务 TCC-Transaction 源码分析 —— 项目实战](https://mp.weixin.qq.com/s/vPr4yMUzurtVkW3BGXit5g)
-* [GTS来了!阿里微服务架构下的分布式事务解决方案](https://mp.weixin.qq.com/s/bUtu2nTs0bybnTvk-iLt6Q)
-* [Atomikos](https://yq.aliyun.com/articles/39054)
-* [微服务架构下分布式事务解决方案 —— 阿里GTS](https://mp.weixin.qq.com/s/BWrGw5dkRfR7gws2XY8vHQ)
-* [ByteJTA是一个兼容JTA规范的基于XA/2PC的分布式事务管理器](https://github.com/liuyangming/ByteJTA)

+ 0 - 116
data-base/分布式事务.md

@@ -1,116 +0,0 @@
-## 分布式事务
-
----
-
-
-分布式事务场景如何设计系统架构及解决数据一致性问题,个人理解最终方案把握以下原则就可以了,那就是:大事务=小事务(原子事务)+异步(消息通知),**解决分布式事务的最好办法其实就是不考虑分布式事务,将一个大的业务进行拆分,整个大的业务流程,转化成若干个小的业务流程,然后通过设计补偿流程从而考虑最终一致性。**
-
-
-#### What’s 事务
-
-事务(Transaction)及其ACID属性
-
-事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个属性,通常简称为事务的ACID属性:
-
-  * 原子性(Atomicity):事务是一个原子操作单元,其对数据的修改,要么全都执行,要么全都不执行。
-  * 一致性(Consistent):在事务开始和完成时,数据都必须保持一致状态。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性;事务结束时,所有的内部数据结构(如B树索引或双向链表)也都必须是正确的。
-  * 隔离性(Isoation):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
-  * 持久性(Durabe):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。
-
-#### 典型场景:银行转账业务
-例如:李雷账户中有500块钱,韩梅梅账户有200块钱,李雷要从自己的账户中转100块钱给韩梅梅,转账(事务)成功执行完成后应该是李雷账户减100变为400,韩梅梅账户加100变为300,不能出现其他情况,即在事务开始和结束时数据都必须保持一致状态(一致性),事务结束时所有的数据及结构都必须是正确的。并且同样的转账操作(同一流水,即一次转账操作)无论执行多少次结果都相同(幂等性)。
-
-#### 电商场景:流量充值业务
-再说我们做的一个项目:中国移动-流量充值能力中心,核心业务流程为:
-
-```
-  1. 用户进入流量充值商品购买页面,选择流量商品;
-  2. 购买流量充值商品,有库存限制则判断库存,生成流量购买订单;
-  3. 选择对应的支付方式(和包、银联、支付宝、微信)进行支付操作;
-  4. 支付成功后,近实时流量到账即可使用流量商品;
-```
-此业务流程看似不是很复杂对吧,不涉及到类似电商业务的实物购买,但是我认为其中的区别并不是很大,只是缺少电商中的物流发货流程,其他流程几乎是一样的,也有库存以及优惠折扣等业务存在。
-
-整个系统交互如下图:
-
-![image](img/1.png)
-
-
-#### 分布式事务
-上述两个场景的业务需求已经说完了,接着谈谈分布式事务,要说分布式事务那就先聊聊本地事务与分布式事务:
-
-Ps:相同点:首先都是要保证数据正确(即ACID),本地事务与分布式事务还可以对应为:刚性事务与柔性事务,在我个人理解刚性事务与柔性事务的最大区别就是:一个完整的事务操作是否可以在同一物理介质(例如:内存)上同时完成;柔性事务就是一个完整事务需要跨物理介质或跨物理节点(网络通讯),那么排它锁、共享锁等等就没有用武之地了(这里并不是指大事务拆小事务【本地事务】后),无法保证原子性(Atomicity)完成事务。个人理解分布式(柔性)事务本质意义上就是-伪事务,柔性事务其实就是根据不同的业务场景使用不同的方法实现最终一致性,因为可以根据业务的特性做部分取舍,在业务过程中可以容忍一定时间内的数据不一致。
-
-在知乎上面看过一篇文章,支付宝的柔性事务实现方式有四种分别针对不同的业务场景,如下图:
-
-![image](img/2.png)
-
-  1. 两阶段型
-  2. 补偿型
-  3. 异步确保型
-  4. 最大努力通知型
-
-回到我们流量交易中心的业务场景:
-
-通过Dubbo实现了微服务化,大致拆分如下:
-
-  1. 商品服务
-  2. 订单服务
-  3. 库存服务
-  4. 支付服务
-  5. 直充服务
-  6. 消息服务
-  7. 等其他服务
-
-#### 场景一:
-
-库存数量与订单数量一致性,采用补偿型+最大努力通知型,采用原因为不涉及跨机房和长事务(正常情况下库存与订单服务处理很快):
-
-  1. 用户下单先减库存,库存减成功后;
-  2. 调用下单服务:
-  3. 2-1. 下单成功,两事务均提交完成;
-  4. 2-2. 下单失败,库存回滚,两事务均失败,此处还有一个保障机制(最大努力通知型),就是如果调用库存服务异常,确定库存回滚失败了,则放入消息服务(延时消息队列)分阶段定时重试,努力重试保证库存服务正常后成功回滚。
-
-#### 场景二:
-
-订单信息、支付信息、充值信息三者之间的一致性,采用异步确保型的原因是,整个业务链路太长且跨不同的机房系统,网络延迟较高,业务方面恰好不需要非常高的实时性,所以采用小事务+异步通知,目前正常情况下用户从下单到完成支付到流量到账平均为1-5分钟左右:
-
-  1. 下单成功即订单服务创建订单成功并发送支付请求到支付网关系统(订单状态-待支付,超过1小时未支付则流转为超时未付撤销,此处用到了RocketMQ的延时消费恰好实现定时器业务场景)。
-  2. 返回支付页面,用户在支付交易系统完成支付业务流程,支付网关异步通知流量中心,流量中心接收到支付成功状态后修改订单状态-支付成功,并给支付网关返回成功结果(此处并发压力目前不大,暂时没有再进行异步解耦)。
-  3. 流量中心修改完订单状态后,调用消息服务将直充业务放入消息队列,对直充业务进行解耦(原因是直充需要调用31省移动CRM系统,此链路过长,且部分省CRM系统耗时非常大,每个省的处理能力不同,经常出现20秒以上的超时,因此要考虑部分超时较高的省份拖垮系统,进行业务的削峰填谷);
-  4. 3-1. 当直充成功时,修改订单状态-已完成;
-  5. 3-2. 当直充失败时(移动特性,例如:直充时正好用户销户或者停机了),修改订单状态为待退款,并调用支付网关系统的退款接口,退款成功后支付网关异步通知流量中心,流量中心修改订单状态为-退款成功;
-  6. 3-3. 当直充超时时,调用定时任务服务进行超时重试机制(第一次重试在10分钟后执行、第二次在30分钟后、第三次…..),直到最大超时重试次数后还得不到直充结果,订单状态会卡在支付成功状态,依赖T+1对账稽核流程保证最终一致性,订单状态根据对账结果流转为:已完成或待退款–>退款成功。
-
-#### 场景三:
-直充到账后的消息通知(APP消息推送或短信通知),采用最大努力通知型,这个业务场景比较简单,在直充成功后,订单状态流转为已完成,此时通过消息服务进行到账通知业务的解耦,调用消息服务失败的情况下,使用定时任务努力通知。
-
-#### 场景四:
-
-**对账稽核:**
-
-按照支付账期每日进行T+1对账,对账原则:以支付交易记录为准,对流量中心订单记录+支付网关交易记录+省CRM充值记录三方比对,将某些中间状态的订单(例如:支付成功、待退款)核对后将订单状态流转完结(已完成、退款成功)。
-
-**结算稽核:**
-
-对账成功后的数据定期进入结算流程,对支付网关周期内的支付金额与结算数据的金额进行核对,稽核成功后进行财务结算流程,将钱结算给省公司,并提供结算明细给省公司,供省公司与直充成本记录进行复核。
-Ps:以下是流量中心的部分架构设计,总体原则方向:微服务化
-
-**流量中心-架构设计**
-
-![image](img/3.png)
-
-
-架构设计思想:在系统初期设计时以及部分硬性环境约束下,我们根据业务拆分为多个子系统(微服务):商品服务、订单服务、库存服务、支付网关、统一接口平台、对账服务、结算服务、网关对接服务等,后续还会增加:账户服务、虚拟货币服务、卡券服务等等…。按照微服务的核心设计思想,所有服务完全独立、隔离,因此所有服务从上至下:请求接入(连接管理)、请求处理(计算服务)、数据存储(存储服务)进行拆分,接入与计算尽最大可能实现无状态,数据存储进行垂直+水平拆分,垂直拆分:商品库-mysql(读多写少,主从架构+读写分离)+redis(读多写少,集群方式)、订单库-mysql(读写均衡,多主多从+水平拆分)、库存专用库-redis(分布式+主备容灾)、外部交易系统-支付网关、外部办理系统-统一接口平台。
-
-Ps:此架构目前已支撑总交易额3.6亿,总订单4680万,日均交易额500万,日订单量50万,后续业务量持续增加的情况下按照微服务思想继续拆分,例如将订单服务再拆分为:下单服务、查单服务,直到根据业务需求与系统关系耦合性拆分到最细粒度为止。
-
-  1. 性能扩展:应用层计算服务(无状态应用)通过增加服务节点同比提升运算性能,配套质量(性能)监控服务dubbo monitor及整合Netflix的Hystrix熔断器对业务质量进行管理实现应用层的动态扩缩容。
-  2. 容量扩展:数据层存储服务(有状态应用)通过对数据水平拆分实现容量的无限扩容,Nosql类方案:Codis中间件;关系型数据库:Mycat数据库分库分表中间件。目前项目中采用twitter的snowflake唯一ID生成器(根据业务场景优化后)自己实现数据的水平拆分和路由规则。
-  3. 存储性能:Nosql:针对读多写少场景-使用淘宝的Tedis(多写随机读的特性提高性能),读写均衡使用-Codis;Mysql:读多写少场景使用一主多从架构(例如商品信息),读写均衡场景使用多主多从架构(例如订单信息)。
-
-
-**整体拆分原则如下图:**
-
-![image](img/4.png)
-

+ 0 - 16
data-base/分库分表.md

@@ -1,16 +0,0 @@
-## 分库分表
-
----
-
-**注意问题:**
-
-*	表操作尽量搞成单表形式,如果涉及join操作或表关联,需要在业务层做处理,而非sql解决
-*	分表键字段确定
-*	所有的sql语句都要包含分表字段
-*	如果类似于交易订单场景,需要从买家、卖家两个维度,可以分为读库、写库,如何保证两个库之间数据同步
-*	全局主键id如何获取
-
-
-**一些成熟的开源框架:**
-
-*	cobar

+ 0 - 0
basic-knowledge/.DS_Store → docs/.DS_Store


+ 259 - 0
docs/.vuepress/components/LockArticle.vue

@@ -0,0 +1,259 @@
+<template>
+    <div class="read-more-wrap"
+         style="display: none; position: absolute; bottom: 0px; z-index: 9999; width: 100%; margin-top: -100px; font-family: PingFangSC-Regular, sans-serif;">
+        <div id="read-more-mask"
+             style="position: relative; height: 200px; background: -webkit-gradient(linear, 0 0%, 0 100%, from(rgba(255, 255, 255, 0)), to(rgb(255, 255, 255)));"></div>
+        <a id="read-more-btn" target="_self"
+           style="position: absolute; left: 50%; top: 70%; bottom: 30px; transform: translate(-50%, -50%); width: 160px; height: 36px; line-height: 36px; font-size: 15px; text-align: center; border: 1px solid rgb(222, 104, 109); color: rgb(222, 104, 109); background: rgb(255, 255, 255); cursor: pointer; border-radius: 6px;">阅读全文</a>
+
+        <div id="btw-modal-wrap" style="display: none;">
+            <div id="btw-mask"
+                 style="position: fixed; top: 0px; right: 0px; bottom: 0px; left: 0px; opacity: 0.7; z-index: 999; background: rgb(0, 0, 0);"></div>
+            <div id="btw-modal"
+                 style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 300px; text-align: center; font-size: 13px; background: rgb(255, 255, 255); border-radius: 10px; z-index: 9999; font-family: PingFangSC-Regular, sans-serif;">
+            <span id="btw-modal-close-btn"
+                  style="position: absolute; top: 5px; right: 15px; line-height: 34px; font-size: 34px; cursor: pointer; opacity: 0.2; z-index: 9999; color: rgb(0, 0, 0); background: none; border: none; outline: none;">×</span>
+                <p id="btw-modal-header"
+                   style="margin-top: 40px; line-height: 1.8; font-size: 13px;">
+                    扫码或搜索:<span style="color: #E9405A; font-weight: bold;">微观技术</span>
+
+                    <br>发送:<span id="fustack-token" class="token"
+                                 style="color: #e9415a; font-weight: bold; font-size: 17px; margin-bottom: 45px;">290992</span>
+                    <br>即可<span style="color: #e9415a; font-weight: bold;">立即永久</span>解锁本站全部文章</p>
+                <img src="/images/personal/qrcode.jpg"
+                     style="width: 180px; margin-top: 10px; margin-bottom: 30px; border: 8px solid rgb(230, 230, 230);">
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+
+    export default {
+        name: 'LockArticle',
+        data() {
+            return {}
+        },
+        mounted: function () {
+            // 定时任务
+            setInterval(() => {
+                if (this.isLock()) {
+                    let $article = this.articleObj();
+                    this._detect($article, this);
+                }
+            }, 1500);
+
+            // 判断是否锁定文章
+            // if (this.isLock()) {
+            //     setTimeout(() => {
+            //         let $article = this.articleObj();
+            //         this._detect($article, this);
+            //
+            //         // 定时任务
+            //         setInterval(() => {
+            //             this._detect($article, this);
+            //         }, 5000);
+            //
+            //     }, 2000);
+            // }
+
+        },
+        methods: {
+            isLock() {
+                return "need" === this.$page.frontmatter.lock;
+            },
+            articleObj: function () {
+                let $article = $('.theme-default-content');
+                if ($article.length <= 0) return null;
+
+                // 文章的实际高度
+                let height = $article[0].clientHeight;
+
+                return {
+                    article: $article,
+                    height: height
+                }
+            },
+            _detect: function (articleObj, t) {
+                if (null == articleObj) return;
+
+                let res = this.getCookie("_unlock");
+                if ('success' === res) {
+                    return;
+                }
+
+                t.getToken().then(function (token) {
+                    $.ajax({
+                        url: 'https://api.offercome.cn/interfaces/BlogApi.php',
+                        type: "GET",
+                        dataType: "text",
+                        data: {
+                            token: token
+                        },
+                        success: function (data) {
+                            if (data === 'refuse') {
+                                t._lock(articleObj);
+                            } else {
+                                t._unlock(articleObj);
+                                t.setCookie("_unlock", "success", 7);
+                            }
+                        },
+                        error: function (data) {
+                            t._unlock(articleObj);
+                        }
+                    })
+                });
+            },
+            _lock: function (articleObj) {
+                let $article = articleObj.article;
+                let height = articleObj.height;
+                if ($article.length <= 0) return;
+
+                // 文章隐藏后的高度
+                let halfHeight = height * 0.3;
+
+                // 篇幅短一点的文章就不需要解锁了
+                if (this.os().isPc && halfHeight > 800) {
+
+                    // 获取口令
+                    this.getToken().then(function (token) {
+                        $('#fustack-token').text(token);
+
+                        // 判断是否已加锁
+                        if ($article.hasClass("lock")) {
+                            return;
+                        }
+
+                        // 设置文章可显示高度
+                        $article.css({"height": halfHeight + 'px'});
+                        $article.addClass('lock');
+
+                        // 添加引导解锁标签
+                        $article.remove("#read-more-wrap");
+
+                        let clone = $('.read-more-wrap').clone();
+                        clone.attr('id', 'read-more-wrap');
+                        clone.css('display', 'block');
+
+                        clone.find("#read-more-btn").click(function () {
+                            clone.find("#btw-modal-wrap").css('display', 'block');
+                        });
+
+                        clone.find("#btw-modal-close-btn").click(function () {
+                            clone.find("#btw-modal-wrap").css('display', 'none');
+                        });
+
+                        $article.append(clone);
+                    });
+
+                }
+            },
+            _unlock: function (articleObj) {
+
+                let $article = articleObj.article;
+
+                // 判断是否已加锁
+                if (!$article.hasClass("lock")) {
+                    return;
+                }
+
+                $article.css('height', 'initial');
+                $article.removeClass('lock');
+
+                $('#read-more-wrap').remove();
+
+            },
+            getToken: async function () {
+				// 浏览器 Cookie true 不限制
+				if(navigator.cookieEnabled){
+					let value = this.getCookie('BAEID');
+					if (!value) {
+						return await this.getFingerprintId();
+					}
+					return value.substring(value.length - 6).toUpperCase();
+				} else{
+					return await this.getFingerprintId();
+				}
+                // return await this.getFingerprintId();
+            },
+            getFingerprintId: function () {
+                // https://github.com/fingerprintjs/fingerprintjs
+               /* new Fingerprint2().get(function(result, components){
+                    let value = result.toUpperCase();
+                    let token = value.substring(value.length - 6).toUpperCase();
+                    // 设置token
+                    $('#fustack-token').text(token);
+                });
+                return $('#fustack-token').text();*/
+                return new Promise( resolve => {
+                    new Fingerprint2().get(function(result, components){
+                        let value = result.toUpperCase();
+                        let token = value.substring(value.length - 6).toUpperCase();
+                        resolve(token);
+                    });
+                })
+            },
+			getUUID: function () {
+                return 'xxxxxx'.replace(/[xy]/g, function (c) {
+                    let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
+                    return v.toString(16);
+                });
+            },
+            getCookie: function (name) {
+                let value = "; " + document.cookie;
+                let parts = value.split("; " + name + "=");
+                if (parts.length === 2)
+                    return parts.pop().split(";").shift();
+            },
+            setCookie: function (name, value, hours){
+                let exp = new Date();
+                exp.setTime(exp.getTime() + hours*60*60*1000);
+                // ;path=/ cookie全站有效
+                document.cookie = name + "="+ escape (value) + ";path=/;expires=" + exp.toGMTString();
+            },
+            os: function () {
+                let ua = navigator.userAgent,
+                    isWindowsPhone = /(?:Windows Phone)/.test(ua),
+                    isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone,
+                    isAndroid = /(?:Android)/.test(ua),
+                    isFireFox = /(?:Firefox)/.test(ua),
+                    isChrome = /(?:Chrome|CriOS)/.test(ua),
+                    isTablet = /(?:iPad|PlayBook)/.test(ua) || (isAndroid && !/(?:Mobile)/.test(ua)) || (isFireFox && /(?:Tablet)/.test(ua)),
+                    isPhone = /(?:iPhone)/.test(ua) && !isTablet,
+                    isPc = !isPhone && !isAndroid && !isSymbian;
+                return {
+                    isTablet: isTablet,
+                    isPhone: isPhone,
+                    isAndroid: isAndroid,
+                    isPc: isPc
+                }
+            }
+        }
+
+    }
+
+</script>
+
+<style lang="stylus">
+    #read-more-btn {
+        border: none !important;
+        text-decoration: none;
+        background: #3eaf7c !important;
+    }
+
+    #read-more-btn {
+        color: #fff !important;
+        transition: all .5s ease;
+    }
+
+    #read-more-btn:hover {
+        background: #de3636 !important;
+    }
+
+    .lock {
+        position: relative;
+        overflow: hidden;
+        padding-bottom: 30px;
+    }
+</style>
+

+ 111 - 0
docs/.vuepress/components/PayArticle.vue

@@ -0,0 +1,111 @@
+<template>
+    <div class="pay-read-more-wrap"
+         style="display: none; position: absolute; bottom: 0px; z-index: 9999; width: 100%; margin-top: -100px; font-family: PingFangSC-Regular, sans-serif;">
+        <div id="pay-read-more-mask"
+             style="position: relative; height: 200px; background: -webkit-gradient(linear, 0 0%, 0 100%, from(rgba(255, 255, 255, 0)), to(rgb(255, 255, 255)));"></div>
+        <a id="pay-read-more-btn" target="_blank"
+           style="position: absolute; left: 50%; top: 70%; bottom: 30px; transform: translate(-50%, -50%); width: 160px; height: 36px; line-height: 36px; font-size: 15px; text-align: center; border: 1px solid rgb(222, 104, 109); color: rgb(222, 104, 109); background: rgb(255, 255, 255); cursor: pointer; border-radius: 6px;">付费阅读</a>
+    </div>
+</template>
+
+<script>
+    export default {
+        name: 'PayArticle',
+        data() {
+            return {}
+        },
+        mounted: function () {
+
+            // 延迟执行
+            setTimeout(() => {
+                if (this.isPay()) {
+                    let $article = this.articleObj();
+                    this._detect($article, this);
+                }
+            }, 150);
+
+            // 定时任务
+            let interval = setInterval(() => {
+                if (this.isPay()) {
+                    let $article = this.articleObj();
+                    // if ($article && $article.article.hasClass("lock-pay")){
+                    //     clearInterval(interval);
+                    // }
+                    this._detect($article, this);
+                }
+            }, 1000);
+        },
+        methods: {
+            isPay() {
+                return this.$page.frontmatter.pay;
+            },
+            articleObj: function () {
+                let $article = $('.theme-default-content');
+                if ($article.length <= 0) return null;
+
+                // 文章的实际高度
+                let height = $article[0].clientHeight;
+
+                return {
+                    article: $article,
+                    height: height
+                }
+            },
+            _detect: function (articleObj, t) {
+                if (null == articleObj) return;
+
+                let $article = articleObj.article;
+                let height = articleObj.height;
+                if ($article.length <= 0) return;
+
+                // 文章隐藏后的高度
+                let halfHeight = height * 0.9;
+
+                // 判断是否已加锁
+                if ($article.hasClass("lock-pay")) {
+                    return;
+                }
+
+                // 设置文章可显示高度
+                $article.css({"height": halfHeight + 'px'});
+                $article.addClass('lock-pay');
+
+                // 删除原有标签
+                $article.remove("#pay-read-more-wrap");
+
+                // 添加加锁标签
+                let clone = $('.pay-read-more-wrap').clone();
+                clone.attr('id', 'pay-read-more-wrap');
+                clone.css('display', 'block');
+
+                // 按钮跳转付费
+                clone.find("#pay-read-more-btn").attr("href", this.$page.frontmatter.pay);
+
+                $article.append(clone);
+            }
+        }
+    }
+</script>
+
+<style lang="stylus">
+    #pay-read-more-btn {
+        border: none !important;
+        text-decoration: none;
+        background: #3eaf7c !important;
+    }
+
+    #pay-read-more-btn {
+        color: #fff !important;
+        transition: all .5s ease;
+    }
+
+    #pay-read-more-btn:hover {
+        background: #de3636 !important;
+    }
+
+    .lock-pay {
+        position: relative;
+        overflow: hidden;
+        padding-bottom: 30px;
+    }
+</style>

+ 239 - 0
docs/.vuepress/config.js

@@ -0,0 +1,239 @@
+module.exports = {
+    port: "8080",
+    dest: ".site",
+    base: "/",
+    // 是否开启默认预加载js
+    shouldPrefetch: (file, type) => {
+        return false;
+    },
+    // webpack 配置 https://vuepress.vuejs.org/zh/config/#chainwebpack
+    chainWebpack: config => {
+        if (process.env.NODE_ENV === 'production') {
+            const dateTime = new Date().getTime();
+
+            // 清除js版本号
+            config.output.filename('assets/js/cg-[name].js?v=' + dateTime).end();
+            config.output.chunkFilename('assets/js/cg-[name].js?v=' + dateTime).end();
+
+            // 清除css版本号
+            config.plugin('mini-css-extract-plugin').use(require('mini-css-extract-plugin'), [{
+                filename: 'assets/css/[name].css?v=' + dateTime,
+                chunkFilename: 'assets/css/[name].css?v=' + dateTime
+            }]).end();
+
+        }
+    },
+    markdown: {
+        lineNumbers: true,
+        externalLinks: {
+            target: '_blank', rel: 'noopener noreferrer'
+        }
+    },
+    locales: {
+        "/": {
+            lang: "zh-CN",
+            title: "offer 来了",
+            description: "汇总java生态圈常用技术框架、开源中间件,系统架构、数据库、大公司架构案例、常用三方类库、项目管理、线上问题排查、个人成长、思考等知识"
+        }
+    },
+    head: [
+        // ico
+        ["link", {rel: "icon", href: `/favicon.ico`}],
+        // meta
+        ["meta", {name: "robots", content: "all"}],
+        ["meta", {name: "author", content: "Tom哥"}],
+        ["meta", {"http-equiv": "Cache-Control", content: "no-cache, no-store, must-revalidate"}],
+        ["meta", {"http-equiv": "Pragma", content: "no-cache"}],
+        ["meta", {"http-equiv": "Expires", content: "0"}],
+        ["meta", {
+            name: "keywords",
+            content: "汇总java生态圈常用技术框架、开源中间件,系统架构、数据库、大公司架构案例、常用三方类库、项目管理、线上问题排查、个人成长、思考等知识"
+        }],
+        ["meta", {name: "apple-mobile-web-app-capable", content: "yes"}],
+        ['script',
+            {
+                charset: 'utf-8',
+                async: 'async',
+                // src: 'https://code.jquery.com/jquery-3.5.1.min.js',
+                src: '/js/jquery.min.js',
+            }],
+        ['script',
+            {
+                charset: 'utf-8',
+                async: 'async',
+                // src: 'https://code.jquery.com/jquery-3.5.1.min.js',
+                src: '/js/global.js',
+            }],
+        ['script',
+            {
+                charset: 'utf-8',
+                async: 'async',
+                src: '/js/fingerprint2.min.js',
+            }],
+        // ['script',
+        //     {
+        //         charset: 'utf-8',
+        //         async: 'async',
+        //         src: 'https://s9.cnzz.com/z_stat.php?id=1278232949&web_id=1278232949',
+        //     }],
+        // 添加百度统计
+        // ["script", {},
+        //     `
+        //       var _hmt = _hmt || [];
+        //       (function() {
+        //         var hm = document.createElement("script");
+        //         hm.src = "https://hm.baidu.com/hm.js?0b31b4c146bf7126aed5009e1a4a11c8";
+        //         var s = document.getElementsByTagName("script")[0];
+        //         s.parentNode.insertBefore(hm, s);
+        //       })();
+        //     `
+        // ]
+    ],
+    plugins: [
+        [
+            {globalUIComponents: ['LockArticle', 'PayArticle']}
+        ],
+        // ['@vssue/vuepress-plugin-vssue', {
+        //     platform: 'github-v3', //v3的platform是github,v4的是github-v4
+        //     // 其他的 Vssue 配置
+        //     owner: 'fuzhengwei', //github账户名
+        //     repo: 'CodeGuide', //github一个项目的名称
+        //     clientId: 'df8beab2190bec20352a',//注册的Client ID
+        //     clientSecret: '7eeeb4369d699c933f02a026ae8bb1e2a9c80e90',//注册的Client Secret
+        //     autoCreateIssue: true // 自动创建评论,默认是false,最好开启,这样首次进入页面的时候就不用去点击创建评论的按钮了。
+        // }
+        // ],
+        // ['@vuepress/back-to-top', true], replaced with inject page-sidebar
+        ['@vuepress/medium-zoom', {
+            selector: 'img:not(.nozoom)',
+            // See: https://github.com/francoischalifour/medium-zoom#options
+            options: {
+                margin: 16
+            }
+        }],
+        // https://v1.vuepress.vuejs.org/zh/plugin/official/plugin-pwa.html#%E9%80%89%E9%A1%B9
+        // ['@vuepress/pwa', {
+        //     serviceWorker: true,
+        //     updatePopup: {
+        //         '/': {
+        //             message: "发现新内容可用",
+        //             buttonText: "刷新"
+        //         },
+        //     }
+        // }],
+        // see: https://vuepress.github.io/zh/plugins/copyright/#%E5%AE%89%E8%A3%85
+        // ['copyright', {
+        //     noCopy: false, // 允许复制内容
+        //     minLength: 100, // 如果长度超过 100 个字符
+        //     authorName: "https://offercome.cn",
+        //     clipboardComponent: "请注明文章出处, [offer 来了](https://offercome.cn)"
+        // }],
+        // see: https://github.com/ekoeryanto/vuepress-plugin-sitemap
+        // ['sitemap', {
+        //     hostname: 'https://offercome.cn'
+        // }],
+        // see: https://github.com/IOriens/vuepress-plugin-baidu-autopush
+        ['vuepress-plugin-baidu-autopush', {}],
+        // see: https://github.com/znicholasbrown/vuepress-plugin-code-copy
+        ['vuepress-plugin-code-copy', {
+            align: 'bottom',
+            color: '#3eaf7c',
+            successText: '@Tom哥: 代码已经复制到剪贴板'
+        }],
+        // see: https://github.com/tolking/vuepress-plugin-img-lazy
+        ['img-lazy', {}],
+        ["vuepress-plugin-tags", {
+            type: 'default', // 标签预定义样式
+            color: '#42b983',  // 标签字体颜色
+            border: '1px solid #e2faef', // 标签边框颜色
+            backgroundColor: '#f0faf5', // 标签背景颜色
+            selector: '.page .content__default h1' // ^v1.0.1 你要将此标签渲染挂载到哪个元素后面?默认是第一个 H1 标签后面;
+        }],
+        // https://github.com/lorisleiva/vuepress-plugin-seo
+        ["seo", {
+            siteTitle: (_, $site) => $site.title,
+            title: $page => $page.title,
+            description: $page => $page.frontmatter.description,
+            author: (_, $site) => $site.themeConfig.author,
+            tags: $page => $page.frontmatter.tags,
+            // twitterCard: _ => 'summary_large_image',
+            type: $page => 'article',
+            url: (_, $site, path) => ($site.themeConfig.domain || '') + path,
+            image: ($page, $site) => $page.frontmatter.image && (($site.themeConfig.domain && !$page.frontmatter.image.startsWith('http') || '') + $page.frontmatter.image),
+            publishedAt: $page => $page.frontmatter.date && new Date($page.frontmatter.date),
+            modifiedAt: $page => $page.lastUpdated && new Date($page.lastUpdated),
+        }]
+    ],
+    themeConfig: {
+        docsRepo: "aalansehaiyang/technology-talk",
+        // 编辑文档的所在目录
+        docsDir: 'docs',
+        // 文档放在一个特定的分支下:
+        docsBranch: 'master',
+        //logo: "/logo.png",
+        editLinks: true,
+        sidebarDepth: 0,
+        //smoothScroll: true,
+        locales: {
+            "/": {
+                label: "简体中文",
+                selectText: "Languages",
+                editLinkText: "在 GitHub 上编辑此页",
+                lastUpdated: "上次更新",
+                nav: [
+                    {
+                        text: 'Java', link: ''
+                    },
+                    {
+                        text: 'Spring全家桶', link: ''
+                    },
+                    {
+                        text: '中间件',
+                        items: [
+                            {
+                                text: 'Redis',
+                                link: ''
+                            },
+                            {
+                                text: 'MySQL',
+                                link: ''
+                            }
+                        ]
+                    },
+
+                    {
+                        text: '关于',
+                        items: [
+                            {text: '关于自己', link: '/md/about/me/about-me.md'}
+                        ]
+                    }
+                ],
+                sidebar: {
+                    "/md/about/": genAbout()
+                }
+            }
+        }
+    }
+};
+
+
+// About page
+function genAbout() {
+    return [
+        {
+            title: "关于自己",
+            collapsable: false,
+            sidebarDepth: 0,
+            children: [
+                "me/about-me.md",
+                "me/me-2022.md",
+            ]
+        },
+        {
+            title: "关于学习",
+            collapsable: false,
+            sidebarDepth: 0,
+        }
+    ];
+}
+

+ 15 - 0
docs/.vuepress/enhanceApp.js

@@ -0,0 +1,15 @@
+export default ({router}) => {
+    /**
+     * 路由切换事件处理
+     */
+    router.beforeEach((to, from, next) => {
+        //触发百度的pv统计
+        if (typeof _hmt != "undefined") {
+            if (to.path) {
+                _hmt.push(["_trackPageview", to.fullPath]);
+            }
+        }
+        // continue
+        next();
+    });
+};

+ 0 - 0
system-architecture/cache-talk.md → docs/.vuepress/public/CNAME


+ 201 - 0
docs/.vuepress/public/LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

BIN
docs/.vuepress/public/assets/images/sys/beian.png


BIN
docs/.vuepress/public/assets/images/sys/full.png


BIN
docs/.vuepress/public/assets/images/sys/next2.png


BIN
docs/.vuepress/public/assets/images/sys/pre2.png


Неке датотеке нису приказане због велике количине промена