>,即每个Entry对象都有一个ThreadLocal的弱引用(作为key),这是为了防止内存泄露。一旦线程结束,key变为一个不可达的对象,这个Entry就可以被GC了。
177 |
178 | 接下来我们来看ThreadLocalMap 的set方法的实现:
179 | ```
180 | private void set(ThreadLocal key, Object value) {
181 |
182 | // We don't use a fast path as with get() because it is at
183 | // least as common to use set() to create new entries as
184 | // it is to replace existing ones, in which case, a fast
185 | // path would fail more often than not.
186 |
187 | Entry[] tab = table;
188 | int len = tab.length;
189 | int i = key.threadLocalHashCode & (len-1);
190 |
191 | for (Entry e = tab[i];
192 | e != null;
193 | e = tab[i = nextIndex(i, len)]) {
194 | ThreadLocal k = e.get();
195 |
196 | if (k == key) {
197 | e.value = value;
198 | return;
199 | }
200 |
201 | if (k == null) {
202 | replaceStaleEntry(key, value, i);
203 | return;
204 | }
205 | }
206 |
207 | tab[i] = new Entry(key, value);
208 | int sz = ++size;
209 | if (!cleanSomeSlots(i, sz) && sz >= threshold)
210 | rehash();
211 | }
212 | ```
213 |
214 | ThreadLocal 的get方法会调用 ThreadLocalMap 的 getEntry(ThreadLocal key) ,其源码如下:
215 | ```
216 | private Entry getEntry(ThreadLocal key) {
217 | int i = key.threadLocalHashCode & (table.length - 1);
218 | Entry e = table[i];
219 | if (e != null && e.get() == key)
220 | return e;
221 | else
222 | return getEntryAfterMiss(key, i, e);
223 | }
224 |
225 | private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) {
226 | Entry[] tab = table;
227 | int len = tab.length;
228 |
229 | while (e != null) {
230 | ThreadLocal k = e.get();
231 | if (k == key)
232 | return e;
233 | if (k == null)
234 | expungeStaleEntry(i);
235 | else
236 | i = nextIndex(i, len);
237 | e = tab[i];
238 | }
239 | return null;
240 | }
241 | ```
242 |
243 | ### 参考资料
244 | [并发编程 | ThreadLocal源码深入分析](http://www.sczyh30.com/posts/Java/java-concurrent-threadlocal/)
245 |
--------------------------------------------------------------------------------
/contents/Linux/README.md:
--------------------------------------------------------------------------------
1 | # Netty
2 | Netty.
3 |
--------------------------------------------------------------------------------
/contents/MQ/README.md:
--------------------------------------------------------------------------------
1 | # Netty
2 | Netty.
3 |
--------------------------------------------------------------------------------
/contents/Microservices/Hystrix_Isolation.md:
--------------------------------------------------------------------------------
1 | Hystrix熔断器支持的隔离策略目前有两种方式:信号量模式和线程池模式。
2 | 但信号量并不支持超时,当被调服务发生问题时,有少部分用户会长时间无法得到响应。
3 | 另外,使用线程池模式无法传递Header,我估计是由于线程切换,参数传递过程中被去掉了。
4 |
5 | ### 信号量和线程池对比
6 | | 策略 | 是否有线程切换 | 是否支持异步 | 是否支持超时 | 是否支持熔断 | 开销大小 | 是否支持限流|
7 | | --- | --- | --- |--- | --- |--- | --- |
8 | | 信号量 | 否 | 否 | 否 | 是 | 小 | 是 |
9 | | 线程池 | 是 | 是 | 是 | 是 | 大 | 是 |
10 |
11 |
12 | ### 信号量
13 | 信号量的使用示意图如下图所示,当n个并发请求去调用一个目标服务接口时,都要获取一个信号量才能真正去调用目标服务接口,但信号量有限,默认是10个,可以使用maxConcurrentRequests参数配置,如果并发请求数多于信号量个数,就有线程需要进入队列排队,但排队队列也有上限,默认是 5,如果排队队列也满,则必定有请求线程会走fallback流程,从而达到限流和防止雪崩的目的。
14 |
15 | 信号量模式从始至终都只有请求线程自身,是同步调用模式,不支持超时调用,不支持直接熔断,由于没有线程的切换,开销非常小。
16 |
17 | ### 线程池
18 | 线程池的使用示意图如下图所示,当n个请求线程并发对某个接口请求调用时,会先从hystrix管理的线程池里面获得一个线程,然后将参数传递给这个线程去执行真正调用。线程池的大小有限,默认是10个线程,可以使用maxConcurrentRequests参数配置,如果并发请求数多于线程池线程个数,就有线程需要进入队列排队,但排队队列也有上限,默认是 5,如果排队队列也满,则必定有请求线程会走fallback流程。
19 |
20 | 线程池模式可以支持异步调用,支持超时调用,支持直接熔断,存在线程切换,开销大。
21 |
--------------------------------------------------------------------------------
/contents/Microservices/MSA.md:
--------------------------------------------------------------------------------
1 | ## 微服务架构
2 |
3 | ### 什么是微服务?
4 | 微服务就是一些协同工作的小而自治的服务。具有两个特点:1:很小,专注于做好一件事;2.自治性,独立部署,服务会暴露出API。
5 |
6 | ### 微服务架构的好处
7 | 首先,通过分解巨大单体式应用为多个服务方法解决了复杂性问题。在功能不变的情况下,应用被分解为多个可管理的分支或服务。每个服务都有一个用RPC-或者消息驱动API定义清楚的边界。微服务架构模式给采用单体式编码方式很难实现的功能提供了模块化的解决方案,由此,单个服务很容易开发、理解和维护。
8 |
9 | 第二,这种架构使得每个服务都可以有专门开发团队来开发。开发者可以自由选择开发技术,提供API服务。当然,许多公司试图避免混乱,只提供某些技术选择。然后,这种自由意味着开发者不需要被迫使用某项目开始时采用的过时技术,他们可以选择现在的技术。甚至于,因为服务都是相对简单,即使用现在技术重写以前代码也不是很困难的事情。
10 |
11 | 第三,微服务架构模式是每个微服务独立的部署。开发者不再需要协调其它服务部署对本服务的影响。这种改变可以加快部署速度。UI团队可以采用AB测试,快速的部署变化。微服务架构模式使得持续化部署成为可能。
12 |
13 | 最后,微服务架构模式使得每个服务独立扩展。你可以根据每个服务的规模来部署满足需求的规模。甚至于,你可以使用更适合于服务资源需求的硬件。比如,你可以在EC2 Compute Optimized instances上部署CPU敏感的服务,而在EC2 memory-optimized instances上部署内存数据库。
14 |
15 | ### 微服务架构的不足
16 | Fred Brooks在30年前写道,“there are no silver bullets”,像任何其它科技一样,微服务架构也有不足。其中一个跟他的名字类似,『微服务』强调了服务大小,实际上,有一些开发者鼓吹建立稍微大一些的,10-100 LOC服务组。尽管小服务更乐于被采用,但是不要忘了这只是终端的选择而不是最终的目的。微服务的目的是有效的拆分应用,实现敏捷开发和部署。
17 |
18 | 主要不足体现在 部署、测试、监控。
19 |
20 | ### 参考
21 | [微服务实战(一):微服务架构的优势与不足](http://www.dockone.io/article/394)
22 |
--------------------------------------------------------------------------------
/contents/Microservices/Short_url.md:
--------------------------------------------------------------------------------
1 | ## short_url/shorten
2 | 将一个或多个长链接转换成短链接
3 |
4 | ## 实现
5 | [短网址(short URL)系统的原理及其实现](https://segmentfault.com/a/1190000012088345)
6 | [短址(short URL)原理及其实现](https://blog.csdn.net/beiyeqingteng/article/details/7706010)
7 |
--------------------------------------------------------------------------------
/contents/MyBatis/README.md:
--------------------------------------------------------------------------------
1 | # Netty
2 | Netty.
3 |
--------------------------------------------------------------------------------
/contents/MySQL/README.md:
--------------------------------------------------------------------------------
1 | # MySQL
2 |
3 | ## 列
4 | ### 1. 增加列
5 | ```
6 | ALTER TABLE `tb_user` ADD COLUMN `address` VARCHAR(40) NOT NULL DEFAULT '' COMMENT '用户住址';
7 | ```
8 |
9 | ### 2. 删除列
10 | ```
11 | ALTER TABLE 表名 drop column 列名;
12 | ```
13 |
14 | ### 3. 修改字段长度
15 | ```
16 | ALTER TABLE `tb_user` MODIFY COLUMN `single_code` VARCHAR(40);
17 | ```
18 |
19 | ## 索引
20 | ### 1.普通索引
21 | ```
22 | ALTER TABLE `t_user` ADD KEY INX_biz_id(`loan_id`, `lender_id`, `sub_account_id`, `buy_type`, `phase`);
23 | ```
24 |
25 | ### 2.唯一索引
26 | ```
27 | ALTER TABLE `t_user` ADD UNIQUE KEY INX_biz_id(`loan_id`, `lender_id`, `sub_account_id`, `buy_type`, `phase`);
28 | ```
29 |
30 | ### 2.删除索引
31 | ```
32 | alter table 表名 drop index 索引名 ;
33 | ```
34 |
35 |
36 | ## 有用的脚本
37 | ### 1.根据多个字段查找重复数据
38 | ```
39 | select * from (select lender_id, loan_id,sub_account_id, buy_type, phase, concat(lender_id, loan_id, sub_account_id, buy_type, phase) as col_t from calendar_repay_1 order by id desc) tmp group by col_t having count(col_t)>1;
40 | ```
41 |
--------------------------------------------------------------------------------
/contents/Netty/README.md:
--------------------------------------------------------------------------------
1 | # Netty
2 | ## Netty实战
3 | * [蚂蚁通信框架实践](https://mp.weixin.qq.com/s?__biz=MzI3MzEzMDI1OQ==&mid=2651819829&idx=1&sn=5c6dbee399fe564fd73a59e1dc6cf1af&chksm=f0dcd949c7ab505fd08a330167e10b87926cbf729b507ca666c9509e52e81e670f7dfd25ce10&mpshare=1&scene=1&srcid=0404YUfqF8az2kYBYfvo0Pl0#rd)
4 | * [京东到家基于netty与websocket的实践](https://mp.weixin.qq.com/s?__biz=MzAwMzg1ODMwNw==&mid=2653791831&idx=1&sn=77b436914cf21f09e3bfea193fa25b3b&chksm=80edccbbb79a45ad2aaf85a0f8a88b18415185884bf7f335e00b3e80e68d9198ae31958c9399&scene=0#rd)
5 |
--------------------------------------------------------------------------------
/contents/Others/README.md:
--------------------------------------------------------------------------------
1 | # My blog
2 | [CSDN](http://blog.csdn.net/top_code?viewmode=list)
3 |
4 | [简书](http://www.jianshu.com/u/215e5a237558)
5 |
--------------------------------------------------------------------------------
/contents/Redis/README.md:
--------------------------------------------------------------------------------
1 | # Netty
2 | Netty.
3 |
--------------------------------------------------------------------------------
/contents/Redis/Redis_Hash_Datastructure.md:
--------------------------------------------------------------------------------
1 | ## 介绍
2 | Redis hash是一个string类型的field和value的映射表.一个key可对应多个field,一个field对应一个value。
3 | 将一个对象存储为hash类型,较于每个字段都存储成string类型更能节省内存。新建一个hash对象时开始是用zipmap(又称为small hash)来存储的。
4 | 这个zipmap其实并不是hash table,但是zipmap相比正常的hash实现可以节省不少hash本身需要的一些元数据存储开销。
5 | 尽管zipmap的添加,删除,查找都是O(n),但是由于一般对象的field数量都不太多。
6 | 所以使用zipmap也是很快的,也就是说添加删除平均还是O(1)。如果field或者value的大小超出一定限制后,Redis会在内部自动将zipmap替换成正常的hash实现。
7 |
8 | ## 操作
9 | ### 1. hset
10 | ```
11 | HSET key field value
12 | ```
13 | 将哈希表key中的域field的值设为value。如果key不存在,一个新的哈希表被创建并进行hset操作。如果域field已经存在于哈希表中,旧值将被覆盖。
14 |
15 | ### 2. hget
16 | ```
17 | HGET key field
18 | ```
19 | 返回哈希表key中指定的field的值。
20 |
21 | ### 3. hsetnx
22 | ```
23 | HSETNX key field value
24 | ```
25 | 将哈希表key中的域field的值设置为value,当且仅当域field不存在。若域field已经存在,该操作无效。如果key不存在,一个新哈希表被创建并执行hsetnx命令。
26 |
27 | ### 4. hmset
28 | ```
29 | HMSET key field value [field value ...]
30 | ```
31 | 同时将多个field - value(域-值)对设置到哈希表key中。此命令会覆盖哈希表中已存在的域。如果key不存在,一个空哈希表被创建并执行hmset操作。
32 |
33 | ```
34 | redis> MSET key1 "Hello" key2 "World"
35 | "OK"
36 | redis> GET key1
37 | "Hello"
38 | redis> GET key2
39 | "World"
40 | redis>
41 | ```
42 |
43 | ### 5. hmget
44 | ```
45 | HMGET key field [field ...]
46 | ```
47 | 返回哈希表key中,一个或多个给定域的值。如果给定的域不存在于哈希表,那么返回一个nil值。因为不存在的key被当作一个空哈希表来处理,所以对一个不存在的key进行hmget操作将返回一个只带有nil值的表。
48 |
49 | ### 6. hgetall
50 | ```
51 | HGETALL key
52 | ```
53 |
54 | 返回哈希表key中,所有的域和值。在返回值里,紧跟每个域名(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。
55 |
56 | ### 7. hdel
57 | ```
58 | HDEL key field [field ...]
59 | ```
60 | 删除哈希表key中的一个或多个指定域,不存在的域将被忽略。
61 |
62 | ### 8. hlen
63 | ```
64 | HLEN key
65 | ```
66 | 返回哈希表key对应的field的数量。
67 |
68 | ### 9. hexists
69 | ```
70 | HEXISTS key field
71 | ```
72 | 查看哈希表key中,给定域field是否存在。
73 |
74 | ### 10. hkeys
75 | ```
76 | HKEYS key
77 | ```
78 | 获得哈希表中key对应的所有field。
79 |
80 | ### 11. hvals
81 | ```
82 | HVALS key
83 | ```
84 | 获得哈希表中key对应的所有values。
85 |
86 | ### 12. hincrby
87 | ```
88 | redis> HSET myhash field 5
89 | (integer) 1
90 | redis> HINCRBY myhash field 1
91 | (integer) 6
92 | redis> HINCRBY myhash field -1
93 | (integer) 5
94 | redis> HINCRBY myhash field -10
95 | (integer) -5
96 | redis>
97 | ```
98 | 为哈希表key中的域field的值加上增量increment。增量也可以为负数,相当于对给定域进行减法操作。如果key不存在,一个新的哈希表被创建并执行hincrby命令。如果域field不存在,那么在执行命令前,域的值被初始化为0。对一个储存字符串值的域field执行hincrby命令将造成一个错误。本操作的值限制在64位(bit)有符号数字表示之内。
99 |
100 |
--------------------------------------------------------------------------------
/contents/Redis/Redis_List_Datastructure.md:
--------------------------------------------------------------------------------
1 | ## 简介
2 | Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
3 | 一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
4 |
5 | ## 操作
6 |
--------------------------------------------------------------------------------
/contents/Redis/Redis_Set_Datastructure.md:
--------------------------------------------------------------------------------
1 | ## Redis 集合(Set)
2 | Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
3 | Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
4 | 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
5 |
6 | ## 操作
7 |
--------------------------------------------------------------------------------
/contents/Redis/Redis_Sorted_Set_Datastructure.md:
--------------------------------------------------------------------------------
1 | ## Redis 有序集合(sorted set)
2 | Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
3 | 不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
4 | 有序集合的成员是唯一的,但分数(score)却可以重复。
5 | 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
6 |
7 | ## 操作
8 |
--------------------------------------------------------------------------------
/contents/Security/README.md:
--------------------------------------------------------------------------------
1 | # blog
2 | My blog.
3 |
--------------------------------------------------------------------------------
/contents/Spring Boot/README.md:
--------------------------------------------------------------------------------
1 | # Spring Boot
2 | Spring Boot Tech Blog.
3 |
--------------------------------------------------------------------------------
/contents/Spring Boot/Spring-Boot-Custom-Your-Starter.md:
--------------------------------------------------------------------------------
1 | SpringBoot最大的特点就是提供了很多默认的配置,Spring4.x提供了基于条件来配置Bean的能力,SpringBoot就是通过这一原理来实现的。
2 |
3 | ## 创建自己的Spring Boot Starter
4 | 如果你想要自己创建一个starter,那么基本上包含以下几步:
5 | 1. 创建一个starter项目,关于项目的命名你可以参考[这里](https://docs.spring.io/spring-boot/docs/1.5.12.RELEASE/reference/htmlsingle/#boot-features-custom-starter-naming)
6 | 2. 创建一个ConfigurationProperties用于保存你的配置信息(如果你的项目不使用配置信息则可以跳过这一步,不过这种情况非常少见)
7 | 3. 创建一个AutoConfiguration,引用定义好的配置信息;在AutoConfiguration中实现所有starter应该完成的操作,并且把这个类加入spring.factories配置文件中进行声明
8 | 4. 打包项目,之后在一个SpringBoot项目中引入该项目依赖,然后就可以使用该starter了
9 |
10 | Spring 官方 Starter通常命名为spring-boot-starter-{name}如 spring-boot-starter-web, Spring官方建议非官方Starter命名应遵循{name}-spring-boot-starter的格式。
11 |
12 | ```
13 | package com.alibaba.druid.spring.boot.autoconfigure;
14 |
15 | import javax.sql.DataSource;
16 |
17 | import com.alibaba.druid.pool.DruidDataSource;
18 | import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
19 | import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidFilterConfiguration;
20 | import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidSpringAopConfiguration;
21 | import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidStatViewServletConfiguration;
22 | import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidWebStatFilterConfiguration;
23 |
24 | import org.slf4j.Logger;
25 | import org.slf4j.LoggerFactory;
26 | import org.springframework.boot.autoconfigure.AutoConfigureBefore;
27 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
28 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
29 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
30 | import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
31 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
32 | import org.springframework.context.annotation.Bean;
33 | import org.springframework.context.annotation.Configuration;
34 | import org.springframework.context.annotation.Import;
35 | /**
36 | * @author lihengming [89921218@qq.com]
37 | */
38 | @Configuration
39 | @ConditionalOnClass(DruidDataSource.class)
40 | @AutoConfigureBefore(DataSourceAutoConfiguration.class)
41 | @EnableConfigurationProperties({DruidStatProperties.class, DataSourceProperties.class})
42 | @Import({DruidSpringAopConfiguration.class,
43 | DruidStatViewServletConfiguration.class,
44 | DruidWebStatFilterConfiguration.class,
45 | DruidFilterConfiguration.class})
46 | public class DruidDataSourceAutoConfigure {
47 |
48 | private static final Logger LOGGER = LoggerFactory.getLogger(DruidDataSourceAutoConfigure.class);
49 |
50 | @Bean(initMethod = "init")
51 | @ConditionalOnMissingBean
52 | public DataSource dataSource() {
53 | LOGGER.info("Init DruidDataSource");
54 | return new DruidDataSourceWrapper();
55 | }
56 | }
57 | ```
58 | 我们首先讲一下源码中注解的作用:
59 | * @Configuration,被该注解注释的类会提供一个或则多个@Bean修饰的方法并且会被spring容器处理来生成bean definitions。
60 | * @Bean注解是必须修饰函数的,该函数可以提供一个bean。而且该函数的函数名必须和bean的名称一致,除了首字母不需要大写。
61 | * @ConditionalOnClass注解是条件判断的注解,表示对应的类在classpath目录下存在时,才会去解析对应的配置文件。
62 | * @EnableConfigurationProperties注解给出了该配置类所需要的配置信息类,也就是StorageServiceProperties类,这样spring容器才会去读取配置信息到StorageServiceProperties对象中。
63 | * @ConditionalOnMissingBean注解也是条件判断的注解,表示如果不存在对应的bean条件才成立,这里就表示如果已经有StorageService的bean了,那么就不再进行该bean的生成。这个注解十分重要,涉及到默认配置和用户自定义配置的原理。也就是说用户可以自定义一个StorageService的bean,这样的话,spring容器就不需要再初始化这个默认的bean了。
64 | * ConditionalOnProperty注解是条件判断的注解,表示如果配置文件中的响应配置项数值为true,才会对该bean进行初始化。
65 |
66 |
67 | ## 解决Spring Boot Parent依赖
68 |
69 |
70 | ## 参考资料
71 | * [Spring Boot custom-starter](https://docs.spring.io/spring-boot/docs/1.5.12.RELEASE/reference/htmlsingle/#boot-features-custom-starter-naming)
72 | * [dubbo-spring-boot-starter](https://github.com/alibaba/dubbo-spring-boot-starter)
73 | * [druid-spring-boot-starter](https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter)
74 | * [Condition annotations](https://docs.spring.io/spring-boot/docs/1.5.10.RELEASE/reference/htmlsingle/#boot-features-bean-conditions)
75 | [Spring Boot - parent pom when you already have a parent pom
76 | ](https://stackoverflow.com/questions/21317006/spring-boot-parent-pom-when-you-already-have-a-parent-pom/21318359#21318359)
77 |
--------------------------------------------------------------------------------
/contents/Spring Boot/SpringBoot-Theory-AutoConfigure.md:
--------------------------------------------------------------------------------
1 | ## Spring Boot核心原理-自动配置
2 | Spring Boot出现之后,得益于COC(“习惯优于配置”)这个理念,再也没有繁琐的配置(大多数流行第三方技术都被集成在内)。
3 | 那么背后实现的核心原理到底是什么呢? 其实是spring 4.x提供的基于条件配置bean的能力。
4 | Spring boot关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar中,主要包含了如下图所示的配置(并未截全):
5 |
--------------------------------------------------------------------------------
/contents/Spring Boot/Spring_Boot_Profile_Usage.md:
--------------------------------------------------------------------------------
1 | ## 前言
2 | 在Spring Boot的开发中,应用程序在不同的环境可能会有不同的配置,例如数据库连接、日志级别等,开发,测试,生产每个环境可能配置都不一致。
3 |
4 | 使用Spring Boot的Profile可以实现多场景下的配置切换,方便开发中进行测试和部署生产环境。
5 | 下面就大致介绍一下yml配置文件跟properties配置文件怎么使用profile配置不同环境的配置文件。
6 |
7 | ## 开发环境
8 | 开发环境如下:
9 | * JDK 1.8
10 | * Maven 3.x
11 | * Spring Boot 1.5.8
12 | * Intellij Idea 2017
13 |
14 | ## 实战
15 |
16 | ### 1. 使用yml文件
17 | 1.首先,我们先创建一个名为 application.yml的属性文件,如下:
18 | ```
19 | server:
20 | port: 8080
21 |
22 | my:
23 | name: demo
24 |
25 | spring:
26 | profiles:
27 | active: dev
28 |
29 | ---
30 | #development environment
31 | spring:
32 | profiles: dev
33 |
34 | server:
35 | port: 8160
36 |
37 | my:
38 | name: ricky
39 |
40 | ---
41 | #test environment
42 | spring:
43 | profiles: test
44 |
45 | server:
46 | port: 8180
47 |
48 | my:
49 | name: test
50 |
51 | ---
52 | #production environment
53 | spring:
54 | profiles: prod
55 |
56 | server:
57 | port: 8190
58 |
59 | my:
60 | name: prod
61 |
62 | ```
63 |
64 | application.yml文件分为四部分,使用```---``` 来作为分隔符,第一部分通用配置部分,表示三个环境都通用的属性,
65 | 后面三段分别为:开发,测试,生产,用spring.profiles指定了一个值(开发为dev,测试为test,生产为prod),这个值表示该段配置应该用在哪个profile里面。
66 |
67 | 如果我们是本地启动,在通用配置里面可以设置调用哪个环境的profil,也就是第一段的```spring.profiles.active=XXX```,
68 | 其中XXX是后面3段中spring.profiles对应的value,通过这个就可以控制本地启动调用哪个环境的配置文件,例如:
69 | ```
70 | spring:
71 | profiles:
72 | active: dev
73 | ```
74 |
75 | 加载的就是开发环境的属性,如果dev换成test,则会加载测试环境的属性,以此类推。
76 |
77 | **注意**
78 | 如果spring.profiles.active没有指定值,那么只会使用没有指定spring.profiles文件的值,也就是只会加载通用的配置。
79 |
80 | #### 打包发布
81 | 如果是部署到服务器的话,我们正常打成jar包,启动时通过
82 | ```--spring.profiles.active=xxx```来控制加载哪个环境的配置,完整命令如下:
83 | ```
84 | java -jar xxx.jar --spring.profiles.active=test 表示加载测试环境的配置
85 |
86 | java -jar xxx.jar --spring.profiles.active=prod 表示加载生产环境的配置
87 | ```
88 |
89 | #### 命令行参数
90 | 通过 ```java -jar app.jar --name="Spring" --server.port=9090``` 方式来传递参数。
91 |
92 | 参数用 ```--xxx=xxx```的形式传递。
93 |
94 | 可以使用的参数可以是我们自己定义的,也可以是Spring Boot中默认的参数。
95 |
96 | **注意:命令行参数在app.jar的后面**
97 |
98 | #### 使用多个yml配置文件进行配置属性文件
99 | 如果是使用多个yml来配置属性,通过与配置文件相同的明明规范,创建application-{profile}.yml文件,将于环境无关的属性,放置到application.yml文件里面,可以通过这种形式来配置多个环境的属性文件,在application.yml文件里面指定```spring.profiles.active=xxx```,来加载不同环境的配置,如果不指定,则默认只使用application.yml属性文件,不会加载其他的profiles的配置
100 |
101 |
102 | ### 2. 使用properties文件
103 | 如果使用application.properties进行多个环境的配置,原理跟使用多个yml配置文件一致,也是通过application-{profile}.properties来控制加载哪个环境的配置,将于环境无关的属性,放置到application.properties文件里面,通过```spring.profiles.active=xxx```,加载不同环境的配置,如果不指定,则默认加载application.properties的配置,不会加载带有profile的配置
104 |
105 |
106 | ### 3. Maven中的场景配置
107 | ```
108 |
109 |
110 |
111 | dev
112 |
113 | dev
114 |
115 |
116 | true
117 |
118 |
119 |
120 |
121 | test
122 |
123 | test
124 |
125 |
126 |
127 |
128 | prod
129 |
130 | prod
131 |
132 |
133 |
134 |
135 |
136 | ${project.artifactId}
137 |
138 |
139 | src/main/resources
140 | false
141 |
142 |
143 | src/main/resources.${build.profile.id}
144 | false
145 |
146 |
147 |
148 |
149 | org.springframework.boot
150 | spring-boot-maven-plugin
151 |
152 | exec
153 |
154 |
155 |
156 |
157 | ```
158 |
159 | ## 源码
160 | [spring-boot-profiles](https://github.com/TFrise/spring-boot-tutorials/tree/master/spring-boot-profiles)
161 |
162 | ## 参考文档
163 | [Spring Boot Reference Guide - Profiles](https://docs.spring.io/spring-boot/docs/1.5.8.RELEASE/reference/htmlsingle/#boot-features-profiles)
164 |
165 |
--------------------------------------------------------------------------------
/contents/Spring MVC/README.md:
--------------------------------------------------------------------------------
1 | # blog
2 | My blog.
3 |
--------------------------------------------------------------------------------
/contents/Spring/README.md:
--------------------------------------------------------------------------------
1 | # Spring
2 | Spring Tech Blog.
3 |
--------------------------------------------------------------------------------
/contents/Spring/Spring Framework-Introduction.md:
--------------------------------------------------------------------------------
1 |
2 | # Overview
3 | Spring Framework 的功能被组织成了 20 来个模块。这些模块分成 Core Container, Data Access/Integration, Web, AOP (Aspect Oriented Programming), Instrumentation, Messaging, 和 Test,如下图:
4 |
5 | Figure 2.1. Overview of the Spring Framework:
6 |
7 | 
8 |
--------------------------------------------------------------------------------
/contents/Spring/Spring4.x-Conditional-Annotation.md:
--------------------------------------------------------------------------------
1 | # Spring4.x新特性: 条件注解@Conditional
2 | @Conditional根据满足某一个特定条件创建一个特定的Bean。比如说,当某一个jar包在某一个类路径下的时候,自动配置一个或者多个Bean;或者只有某个Bean被创建才会创建另外一个Bean。总的来说,就是根据特定条件来控制Bean的创建行为,这样我们可以利用这个特性进行一些自动的配置。
3 | 在Spring Boot中大量的应用到条件注解,后面有机会我们会说到。
4 |
--------------------------------------------------------------------------------
/contents/Spring/Spring4.x-Java-Based-Configuration.md:
--------------------------------------------------------------------------------
1 | # Spring4.x新特性-基于Java配置
2 | 基于 Java 的配置选项,可以使你在不用配置 XML 的情况下编写大多数的 Spring。
3 |
4 | ## @Configuration 和 @Bean 注解
5 | 带有 @Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源。@Bean 注解告诉 Spring,一个带有 @Bean 的注解方法将返回一个对象,该对象应该被注册为在 Spring 应用程序上下文中的 bean。
6 |
7 | 最简单可行的 @Configuration 类如下所示:
8 | ```
9 | package com.mindflow.spring4;
10 |
11 | import org.springframework.context.annotation.*;
12 |
13 | @Configuration
14 | public class AppConfig {
15 | @Bean
16 | public Foo foo() {
17 | return new Foo(bar());
18 | }
19 | @Bean
20 | public Bar bar() {
21 | return new Bar();
22 | }
23 | }
24 | ```
25 |
26 | 上面的代码将等同于下面的 XML 配置:
27 | ```
28 |
29 |
30 |
31 |
32 | ```
33 |
34 | 在这里,带有 @Bean 注解的方法名称作为 bean 的 ID,它创建并返回实际的 bean。你的配置类可以声明多个 @Bean。一旦定义了配置类,你就可以使用 AnnotationConfigApplicationContext 来加载并把他们提供给 Spring 容器,如下所示:
35 | ```
36 | package com.mindflow.spring4;
37 |
38 | import org.springframework.context.ApplicationContext;
39 | import org.springframework.context.annotation.*;
40 |
41 | public class MainApp {
42 | public static void main(String[] args) {
43 | ApplicationContext ctx =
44 | new AnnotationConfigApplicationContext(AppConfig.class);
45 |
46 | Foo foo = ctx.getBean(Foo.class);
47 |
48 | foo.say("Hello World!");
49 | }
50 | }
51 | ```
52 |
53 | ## @Import 注解
54 | @Import 注解允许从另一个配置类中加载 @Bean 定义。就像 Spring 的 XML 文件中使用的元素帮助模块化配置一样,@Import注解允许从其它配置类中加载@Bean的配置。
55 |
56 | 考虑 ConfigA 类,如下所示:
57 | ```
58 | @Configuration
59 | public class ConfigA {
60 | @Bean
61 | public A a() {
62 | return new A();
63 | }
64 | }
65 | ```
66 | 你可以在另一个 Bean 声明中导入上述 Bean 声明,如下所示:
67 | ```
68 | @Configuration
69 | @Import(ConfigA.class)
70 | public class ConfigB {
71 | @Bean
72 | public B a() {
73 | return new A();
74 | }
75 | }
76 | ```
77 |
78 | 现在,当实例化上下文时,不需要同时指定 ConfigA.class 和 ConfigB.class,只有 ConfigB 类需要提供,如下所示:
79 | ```
80 | public static void main(String[] args) {
81 | ApplicationContext ctx =
82 | new AnnotationConfigApplicationContext(ConfigB.class);
83 | // now both beans A and B will be available...
84 | A a = ctx.getBean(A.class);
85 | B b = ctx.getBean(B.class);
86 | }
87 | ```
88 |
89 | ## AnnotationConfigApplicationContext
90 | AnnotationConfigApplicationContext可以使用无参构造方法来实例化,之后使用register()方法来配置。这个方法当编程式地构建AnnotationConfigApplicationContext时尤其有用:
91 | ```
92 | public static void main(String[] args) {
93 | AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
94 | ctx.register(AppConfig.class, OtherConfig.class);
95 | ctx.register(AdditionalConfig.class);
96 | ctx.refresh();
97 | MyService myService = ctx.getBean(MyService.class);
98 | myService.doStuff();
99 | }
100 | ```
101 |
102 | 要开启组件扫描,仅仅需要在你的@Configuration类上加上如下注解:
103 | ```
104 | @Configuration
105 | @ComponentScan(basePackages = "com.acme")
106 | public class AppConfig {
107 | ...
108 | }
109 | ```
110 |
111 | 有经验的 Spring 用户肯定会熟悉下面这个 Spring 的 context:命名空间中的常用 XML声明:
112 | ```
113 |
114 |
115 |
116 | ```
117 | 在上面的示例中,com.acme包会被扫描到,去查找任意@Component注解的类,那些类就会被注册为 Spring 容器中的 bean。AnnotationConfigApplicationContext 暴露出 scan(String ...)方法,允许相同的组件扫描功能:
118 | ```
119 | public static void main(String[] args) {
120 | AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
121 | ctx.scan("com.acme");
122 | ctx.refresh();
123 | MyService myService = ctx.getBean(MyService.class);
124 | }
125 | ```
126 |
127 |
128 | ## @Bean注解
129 | ### 生命周期回调
130 | @Bean 注解支持指定任意的初始化和销毁的回调方法,就像在 bean 元素中 Spring 的 XML 的初始化方法和销毁方法的属性:
131 | ```
132 | public class Foo {
133 | public void init() {
134 | // initialization logic
135 | }
136 | public void cleanup() {
137 | // destruction logic
138 | }
139 | }
140 |
141 | @Configuration
142 | public class AppConfig {
143 | @Bean(initMethod = "init", destroyMethod = "cleanup" )
144 | public Foo foo() {
145 | return new Foo();
146 | }
147 | }
148 | ```
149 |
150 | ### 指定 Bean 的范围
151 |
152 | 默认范围是单实例,但是你可以重写带有 @Scope 注解的该方法,如下所示:
153 | ```
154 | @Configuration
155 | public class AppConfig {
156 | @Bean
157 | @Scope("prototype")
158 | public Foo foo() {
159 | return new Foo();
160 | }
161 | }
162 | ```
163 |
164 | ### 指定bean的名称
165 | 默认地,配置类使用@Bean方法的名称来作为注册bean的名称。这个方法可以被重写,当然,使用的是name属性。
166 | ```
167 | @Configuration
168 | public class AppConfig {
169 |
170 | @Bean(name = "myFoo")
171 | public Foo foo() {
172 | return new Foo();
173 | }
174 | }
175 | ```
176 |
177 |
178 |
--------------------------------------------------------------------------------
/contents/Spring/Spring_Annotation_Scan.md:
--------------------------------------------------------------------------------
1 |
2 | 在使用Spring时,有时候有会有一些自定义Annotation的需求,比如一些Listener的回调函数。
3 |
4 | 例如,在配置中心的设计上,我们期望在配置发生变更时,client能收到通知,如下:
5 | ```
6 | @Service
7 | public class DemoService {
8 |
9 | @Value("${batch:100}")
10 | private int batch;
11 |
12 | @ConfigChangeListener
13 | private void onChange(ConfigChangeEvent changeEvent) {
14 | //update injected value of batch if it is changed in Apollo
15 | if (changeEvent.isChanged("batch")) {
16 | batch = config.getIntProperty("batch", 100);
17 | }
18 | }
19 | }
20 | ```
21 |
22 | 一开始的时候,我是在Spring的ContextRefreshedEvent事件里,通过context.getBeansWithAnnotation(Component.class) 来获取到所有的bean,然后再检查method是否有@MyListener的annotation。
23 |
24 | 后来发现这个方法有缺陷,当有一些spring bean的@Scope设置为session/request时,创建bean会失败。
25 |
26 | 参考:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-scopes
27 |
28 | ## BeanPostProcessor接口
29 | 后来看了下spring jms里的@JmsListener的实现,发现实现BeanPostProcessor接口才是最合理的办法。
30 | ```
31 | public interface BeanPostProcessor {
32 |
33 | /**
34 | * Apply this BeanPostProcessor to the given new bean instance before any bean
35 | * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
36 | * or a custom init-method). The bean will already be populated with property values.
37 | * The returned bean instance may be a wrapper around the original.
38 | * @param bean the new bean instance
39 | * @param beanName the name of the bean
40 | * @return the bean instance to use, either the original or a wrapped one;
41 | * if {@code null}, no subsequent BeanPostProcessors will be invoked
42 | * @throws org.springframework.beans.BeansException in case of errors
43 | * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
44 | */
45 | Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
46 |
47 | /**
48 | * Apply this BeanPostProcessor to the given new bean instance after any bean
49 | * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
50 | * or a custom init-method). The bean will already be populated with property values.
51 | * The returned bean instance may be a wrapper around the original.
52 | * In case of a FactoryBean, this callback will be invoked for both the FactoryBean
53 | * instance and the objects created by the FactoryBean (as of Spring 2.0). The
54 | * post-processor can decide whether to apply to either the FactoryBean or created
55 | * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
56 | *
This callback will also be invoked after a short-circuiting triggered by a
57 | * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
58 | * in contrast to all other BeanPostProcessor callbacks.
59 | * @param bean the new bean instance
60 | * @param beanName the name of the bean
61 | * @return the bean instance to use, either the original or a wrapped one;
62 | * if {@code null}, no subsequent BeanPostProcessors will be invoked
63 | * @throws org.springframework.beans.BeansException in case of errors
64 | * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
65 | * @see org.springframework.beans.factory.FactoryBean
66 | */
67 | Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
68 |
69 | }
70 | ```
71 | 所有的bean在创建完之后,都会回调postProcessAfterInitialization函数,这时就可以确定bean是已经创建好的了。
72 |
73 | 所以扫描自定义的annotation的代码大概是这个样子的:
74 | ```
75 | public class ConfigChangeListenerProcessor implements BeanPostProcessor {
76 |
77 | @Override
78 | public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
79 | return bean;
80 | }
81 |
82 | @Override
83 | public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
84 | Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass());
85 | if (methods != null) {
86 | for (Method method : methods) {
87 | ConfigChangeListener listener = AnnotationUtils.findAnnotation(method, ConfigChangeListener.class);
88 | // process
89 | }
90 | }
91 | return bean;
92 | }
93 | }
94 | ```
95 |
--------------------------------------------------------------------------------
/contents/Spring/Spring_Bean_Lifecycle.md:
--------------------------------------------------------------------------------
1 | ## Spring Bean生命周期详解
2 | 在Spring中 Bean 可谓是一个核心的元素,当我们结合Spring进行编程的时候也离不开Bean,面对这样重要的一个角色,了解其生命周期和该生命周期所涉及的环节对我们更加熟练灵活地使用Bean是很有Bean必要的,下面我们就来详细分析下Bean的生命周期吧。
3 | 此处,可以借鉴Java EE中Servlet的生命周期,实例化、初始init、接收请求service、销毁destroy。
4 |
5 | ### Spring Bean的生命周期概述
6 | 1. 实例化BeanFactoryPostProcessor接口实现类;
7 | 2. 执行BeanFactoryPostProcessor的postProcessBeanFactory方法;
8 | 3. 实例化BeanPostProcessor接口实现类;
9 | 4. 实例化InstantiationAwareBeanPostProcessor接口实现类;
10 | 5. 执行InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法;
11 | 6. 执行Bean的构造方法;
12 | 7. 执行InstantiationAwareBeanPostProcessor的postProcessPropertyValues方法;
13 | 8. 为Bean注入属性;
14 | 9. 调用BeanNameAware接口的setBeanName方法;
15 | 10. 调用BeanFactoryAware接口的setBeanFactory()方法;
16 | 11. 调用ApplicationContextAware接口的setApplicationContext(ApplicationContext)方法;
17 | 12. 执行BeanPostProcessor接口的postProcessBeforeInitialization方法;
18 | 13. 执行InitializingBean接口的afterPropertiesSet方法;
19 | 14. 调用的init-method属性指定的初始化方法;
20 | 15. 执行BeanPostProcessor接口的postProcessAfterInitialization方法;
21 | 16. 执行InstantiationAwareBeanPostProcessor接口的postProcessAfterInstantiation方法;
22 | 17. 容器初始化成功,执行业务代码后,下面开始销毁容器;
23 |
24 | 18. 调用DisposableBean接口的destroy方法;
25 | 19. 调用中的destroy-method指定的销毁方法。
26 |
27 | ### Spring Bean生命周期流程图
28 |
29 |
--------------------------------------------------------------------------------
/contents/Spring/Spring_IOC_Analysis_Part1.md:
--------------------------------------------------------------------------------
1 | ## Spring IOC源码分析
2 |
3 | 首先,看一个简单示例:
4 | ```
5 | import org.springframework.context.support.ClassPathXmlApplicationContext;
6 |
7 | /**
8 | * ${DESCRIPTION}
9 | *
10 | * @author Ricky Fung
11 | * @create 2018-04-15 12:07
12 | */
13 | public class SpringApp {
14 |
15 | public static void main(String[] args) throws InterruptedException {
16 |
17 | ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
18 |
19 | ExampleBean exampleBean = (ExampleBean) context.getBean("exampleBean");
20 | System.out.println(exampleBean);
21 | }
22 | }
23 | ```
24 |
25 | applicationContext.xml
26 | ```
27 |
28 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | ```
41 |
42 | 接下来,我们分析一下```org.springframework.context.support.ClassPathXmlApplicationContext```。
43 |
44 | ### ClassPathXmlApplicationContext
45 | ClassPathXmlApplicationContext继承层次关系如下:
46 | 
47 |
48 | 1. 构造方法
49 | ```
50 | public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
51 |
52 | /**
53 | * Create a new ClassPathXmlApplicationContext, loading the definitions
54 | * from the given XML file and automatically refreshing the context.
55 | * @param configLocation resource location
56 | * @throws BeansException if context creation failed
57 | */
58 | public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
59 | this(new String[] {configLocation}, true, null);
60 | }
61 |
62 | /**
63 | * Create a new ClassPathXmlApplicationContext with the given parent,
64 | * loading the definitions from the given XML files.
65 | * @param configLocations array of resource locations
66 | * @param refresh whether to automatically refresh the context,
67 | * loading all bean definitions and creating all singletons.
68 | * Alternatively, call refresh manually after further configuring the context.
69 | * @param parent the parent context
70 | * @throws BeansException if context creation failed
71 | * @see #refresh()
72 | */
73 | public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
74 | throws BeansException {
75 |
76 | super(parent);
77 | setConfigLocations(configLocations);
78 | if (refresh) {
79 | refresh();
80 | }
81 | }
82 | }
83 | ```
84 |
85 | refresh方法继承自```org.springframework.context.support.AbstractApplicationContext```类,如下:
86 | ```
87 | @Override
88 | public void refresh() throws BeansException, IllegalStateException {
89 | synchronized (this.startupShutdownMonitor) {
90 | // Prepare this context for refreshing.
91 | prepareRefresh();
92 |
93 | // Tell the subclass to refresh the internal bean factory.
94 | ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
95 |
96 | // Prepare the bean factory for use in this context.
97 | prepareBeanFactory(beanFactory);
98 |
99 | try {
100 | // Allows post-processing of the bean factory in context subclasses.
101 | postProcessBeanFactory(beanFactory);
102 |
103 | // Invoke factory processors registered as beans in the context.
104 | invokeBeanFactoryPostProcessors(beanFactory);
105 |
106 | // Register bean processors that intercept bean creation.
107 | registerBeanPostProcessors(beanFactory);
108 |
109 | // Initialize message source for this context.
110 | initMessageSource();
111 |
112 | // Initialize event multicaster for this context.
113 | initApplicationEventMulticaster();
114 |
115 | // Initialize other special beans in specific context subclasses.
116 | onRefresh();
117 |
118 | // Check for listener beans and register them.
119 | registerListeners();
120 |
121 | // Instantiate all remaining (non-lazy-init) singletons.
122 | finishBeanFactoryInitialization(beanFactory);
123 |
124 | // Last step: publish corresponding event.
125 | finishRefresh();
126 | }
127 |
128 | catch (BeansException ex) {
129 | if (logger.isWarnEnabled()) {
130 | logger.warn("Exception encountered during context initialization - " +
131 | "cancelling refresh attempt: " + ex);
132 | }
133 |
134 | // Destroy already created singletons to avoid dangling resources.
135 | destroyBeans();
136 |
137 | // Reset 'active' flag.
138 | cancelRefresh(ex);
139 |
140 | // Propagate exception to caller.
141 | throw ex;
142 | }
143 |
144 | finally {
145 | // Reset common introspection caches in Spring's core, since we
146 | // might not ever need metadata for singleton beans anymore...
147 | resetCommonCaches();
148 | }
149 | }
150 | }
151 | ```
152 |
153 | obtainFreshBeanFactory()方法如下:
154 | ```
155 | /**
156 | * Tell the subclass to refresh the internal bean factory.
157 | * @return the fresh BeanFactory instance
158 | * @see #refreshBeanFactory()
159 | * @see #getBeanFactory()
160 | */
161 | protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
162 | refreshBeanFactory();
163 | ConfigurableListableBeanFactory beanFactory = getBeanFactory();
164 | if (logger.isDebugEnabled()) {
165 | logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
166 | }
167 | return beanFactory;
168 | }
169 | ```
170 | 这里的 refreshBeanFactory()和getBeanFactory()方法实现在```org.springframework.context.support.AbstractRefreshableApplicationContext```类中,如下:
171 |
172 | ```
173 | /**
174 | * This implementation performs an actual refresh of this context's underlying
175 | * bean factory, shutting down the previous bean factory (if any) and
176 | * initializing a fresh bean factory for the next phase of the context's lifecycle.
177 | */
178 | @Override
179 | protected final void refreshBeanFactory() throws BeansException {
180 | if (hasBeanFactory()) {
181 | destroyBeans();
182 | closeBeanFactory();
183 | }
184 | try {
185 | DefaultListableBeanFactory beanFactory = createBeanFactory();
186 | beanFactory.setSerializationId(getId());
187 | customizeBeanFactory(beanFactory);
188 | loadBeanDefinitions(beanFactory);
189 | synchronized (this.beanFactoryMonitor) {
190 | this.beanFactory = beanFactory;
191 | }
192 | }
193 | catch (IOException ex) {
194 | throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
195 | }
196 | }
197 |
198 | /**
199 | * Determine whether this context currently holds a bean factory,
200 | * i.e. has been refreshed at least once and not been closed yet.
201 | */
202 | protected final boolean hasBeanFactory() {
203 | synchronized (this.beanFactoryMonitor) {
204 | return (this.beanFactory != null);
205 | }
206 | }
207 |
208 | protected DefaultListableBeanFactory createBeanFactory() {
209 | return new DefaultListableBeanFactory(getInternalParentBeanFactory());
210 | }
211 |
212 | @Override
213 | public final ConfigurableListableBeanFactory getBeanFactory() {
214 | synchronized (this.beanFactoryMonitor) {
215 | if (this.beanFactory == null) {
216 | throw new IllegalStateException("BeanFactory not initialized or already closed - " +
217 | "call 'refresh' before accessing beans via the ApplicationContext");
218 | }
219 | return this.beanFactory;
220 | }
221 | }
222 | ```
223 |
224 | 通过createBeanFactory方法,可以我们知道创建的BeanFactory实例是```org.springframework.beans.factory.support.DefaultListableBeanFactory```,DefaultListableBeanFactory类的继承层次关系如下图:
225 | 
226 |
227 |
228 |
229 |
--------------------------------------------------------------------------------
/contents/Spring/Spring_Transaction_Analysis.md:
--------------------------------------------------------------------------------
1 | Spring @Transactional 实现原理分析
2 |
3 |
4 | ## 参考
5 | [Spring @Transactional explained](https://doanduyhai.wordpress.com/2011/11/20/spring-transactional-explained/)
6 |
--------------------------------------------------------------------------------
/contents/Tools/Atom_Markdown_Config.md:
--------------------------------------------------------------------------------
1 | 为了让中文显示起来跟好看,我使用微软雅黑作为中文字体,Monaco作为英文字体,具体配置如下:
2 |
3 | 下面这些是和Markdown编辑相关的包:
4 | * language-markdown: Markdown语法支持
5 | * markdown-image-paste: 使用Ctrl-V将图片插入到Markdown文档中
6 | * markdown-preview-plus:对markdown-preview的强化,更好的预览Markdown文档
7 | * markdown-scroll-sync: 同步显示Markdown源文件和预览文件
8 | * markdown-table-editor: 让Markdown编辑表格更轻松
9 | * markdown-themeable-pdf: 为Markdown生成的PDF文件使用自定义主题。
10 | * markdown-writer: 更好的使用Markdown写作
11 | * pdf-view: 基于PDF.js的PDF预览,和markdown-themeable-pdf结合起来,可以在Atom里面直接查看生成的PDF文件
12 |
13 | ## 修改页眉
14 | ~/.atom/markdown-themeable-pdf/header.js: PDF文件页眉,我的设置如下(页眉中只显示文件名称)
15 | ```
16 | module.exports = function (info) {
17 | return {
18 | height: '2cm',
19 | contents: '' + info.fileInfo.name + '
'
20 | };
21 | };
22 | ```
23 |
24 | ## 修改页脚
25 | ~/.atom/markdown-themeable-pdf/footer.js: PDF文件页脚,我的设置如下(页脚中显示页码信息,Copyright,时间戳和作者名)。
26 | ```
27 | module.exports = function (info) {
28 | var dateFormat = function () {
29 | var d = new Date();
30 | var mm = d.getMonth() + 1;
31 | var dd = d.getDate();
32 | var yy = d.getFullYear();
33 | var myDateString = yy + '-' + mm + '-' + dd;
34 | return myDateString;
35 | };
36 | return {
37 | height: '1cm',
38 | contents: 'Page {{page}}/{{pages}}
© Copyright ' + dateFormat() + ' by K.X
'
39 | };
40 | };
41 | ```
42 |
43 | ## 导出字体
44 | ~/.atom/markdown-themeable-pdf/styles: PDF文本字体。和Atom一样,我使用微软雅黑作为中文字体,Monaco作为英文字体。
45 | ```
46 | * {
47 | font-family: Monaco, Microsoft YaHei UI;
48 | }
49 | ```
50 |
51 |
52 |
--------------------------------------------------------------------------------
/contents/Tools/Mac_Env_Config.md:
--------------------------------------------------------------------------------
1 | # 在 macOS High Sierra 10.13 搭建Java开发环境
2 |
3 | ## 安装 iTerm2
4 | 推荐 [iTerm2](https://www.iterm2.com),iTerm2 功能强大,可以替代系统默认的命令行终端。下载解压后,将 iTerm2 直接拖入"应用程序"目录。
5 |
6 | ## 安装 Xcode
7 | [Xcode](https://itunes.apple.com/cn/app/xcode/id497799835) 是苹果出品的包含一系列工具及库的开发套件。通过 AppStore 安装最新版本的 Xcode(9.0)。我们一般不会用 Xcode 来开发后端项目。但这一步也是必须的,因为 Xcode 会附带安装一些如 Git 等必要的软件。
8 |
9 | ## 安装 Command Line Tools for Xcode
10 | 这一步会帮你安装许多常见的基于 Unix 的工具。Xcode 命令行工具作为 Xcode 的一部分,包含了 GCC 编译器。在命令行中执行以下命令即可安装:
11 | ```
12 | # 安装 Xcode Command Line Tools
13 | $ xcode-select --install
14 | ```
15 |
16 | 当 Xcode 和 Xcode Command Line Tools 安装完成后,你需要启动 Xcode,并点击同意接受许可协议,然后关闭 Xcode 就可以了。这一步骤也是必须的,否则 Xcode 包含的一系列开发工具都将不可用。
17 |
18 | ## 安装 Homebrew
19 | [Homebrew](https://brew.sh/index_zh-cn.html) 作为 macOS 不可或缺的套件管理器,用来安装、升级以及卸载常用的软件。在命令行中执行以下命令即可安装:
20 | ```
21 | $ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
22 | ```
23 | 安装后可以修改 Homebrew 源,国外源一直不是很给力,这里我们将 Homebrew 的 git 远程仓库改为中国科学技术大学开源软件镜像:
24 |
25 | ## 安装一些必要的工具包
26 | ```
27 | brew install wget
28 | brew install autoconf
29 | brew install openssl
30 | ```
31 |
32 | ## Java环境配置
33 | ### JDK
34 | JDK在Mac系统中,其实有两个路径:一个是默认的,一个是用户自己下载安装的JDK。
35 |
36 | 想查看默认使用的是哪个JDK,只需在终端中输入whereis java就能看到路径,然后用ls -l则能看到真实路径,命令如下:
37 | ```
38 | $ whereis java
39 | /usr/bin/java
40 | $ ls -l /usr/bin/java
41 |
42 | ```
43 | 如果是从Oracle下载的idk,且想要更新的话,则首先需要修改jdk的环境变量。oracle下载的,默认会安装在:/Library/Java/JavaVirtualMachines/ 目录下。
44 |
45 | #### 1. 下载JDK 安装包
46 | [点此](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 下载JDK 安装包。下载成功后直接点击安装包进行安装。
47 |
48 | 打开Mac自带终端Terminal,进入当前用户主目录:
49 | ```
50 | $ cd ~
51 | ```
52 | 默认用户目录则不需要
53 |
54 | #### 2. 创建.bash_profile文件
55 | 如果你是第一次配置环境变量,可以使用
56 | ```
57 | $ touch .bash_profile
58 | ```
59 | 创建一个.bash_profile的隐藏配置文件,如果是已存在的配置文件,则使用
60 | ```
61 | $ open -e .bash_profile
62 | ```
63 |
64 | #### 3. 打开.bash_profile文件
65 | 输入jdk下面的命令,注意根据自己的目录进行调整JAVA_HOME的值,我安装的JDK1.8路径:/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home
66 |
67 | 完整配置如下:
68 | ```
69 | JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home
70 | PATH=$JAVA_HOME/bin:$PATH:.
71 | CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:.
72 | export JAVA_HOME
73 | export CLASSPATH
74 | export PATH
75 | ```
76 | #### 4. 重新加载.bash_profile
77 | 使用"source .bash_profile"使配置生效,如下:
78 | ```
79 | $ source .bash_profile
80 | ```
81 |
82 | #### 5.验证
83 | 输入如下命令:
84 | ```
85 | $ java -version
86 | ```
87 | 或者:
88 | ```
89 | $ echo $JAVA_HOME
90 | ```
91 |
92 | ### Maven
93 | #### 1. 下载Maven
94 | [点此](http://maven.apache.org/download.cgi)下载Maven安装包。
95 |
96 | #### 2. 解压缩
97 | 解压上一步下载的gz文件,命令如下:
98 | ```
99 | $ tar xzvf apache-maven-3.5.3-bin.tar.gz
100 | ```
101 |
102 | #### 3. 添加环境变量
103 |
104 | 添加bin到环境变量中,需要编辑 ```.bash_profile```文件,命令如下:
105 | ```
106 | $ vi .bash_profile
107 | ```
108 |
109 | 添加内容如下:
110 | ```
111 | MAVEN_HOME=/Users/ricky/Data/Software/Maven/apache-maven-3.5.3
112 | PATH=$PATH:$MAVEN_HOME/bin
113 |
114 | export MAVEN_HOME
115 | export PATH
116 | ```
117 | 保存并退出。
118 |
119 | #### 4. 重新加载.bash_profile
120 | 使用"source .bash_profile"使配置生效,如下:
121 | ```
122 | $ source .bash_profile
123 | ```
124 |
125 | #### 5.验证
126 | 输入如下命令:
127 | ```
128 | $ mvn -v
129 | ```
130 | 或者:
131 | ```
132 | $ echo $MAVEN_HOME
133 | ```
134 |
135 | #### setting.xml
136 | Maven的配置文件settings.xml存在于两个地方:
137 | * 安装的地方:${M2_HOME}/conf/settings.xml
138 | * 用户的目录:${user.home}/.m2/settings.xml
139 |
140 | 前者又被叫做全局配置,对操作系统的所有使用者生效;后者被称为用户配置,只对当前操作系统的使用者生效。如果两者都存在,它们的内容将被合并,并且用户范围的settings.xml会覆盖全局的settings.xml。
141 |
142 | Windows位置在C:\Users\{你的用户名}\.m2\settings.xml,Mac位置在/Users/{你的用户名}/.m2/settings.xml。
143 |
144 | ### IntelliJ IDEA
145 | #### 1. 下载
146 | [点此](https://www.jetbrains.com/idea/download/) 下载IntelliJ IDEA安装包。
147 |
148 | #### 2. 激活方式
149 | 激活方式如下:
150 | * 通过License Server:http://idea.iteblog.com/key.php[已被封杀]
151 | * 通过License Server:http://idea.toocruel.net[已被封杀]
152 |
153 | #### 3. 启动JVM参数调优
154 |
155 | #### 4. 模板配置
156 | ```
157 | /**
158 | * @author Ricky Fung
159 | * @version 1.0
160 | * @since ${YEAR}-${MONTH}-${DAY} ${HOUR}:${MINUTE}
161 | */
162 | ```
163 |
164 | ## Git
165 | ### 1. 下载Git
166 | [点此](https://git-scm.com/)下载Git安装包。
167 |
168 | ### 2. 初次运行 Git 前的配置
169 | Git 提供了一个叫做 git config 的工具(译注:实际是 git-config 命令,只不过可以通过 git 加一个名字来呼叫此命令。),专门用来配置或读取相应的工作环境变量。而正是由这些环境变量,决定了 Git 在各个环节的具体工作方式和行为。这些变量可以存放在以下三个不同的地方:
170 |
171 | * ```/etc/gitconfig``` 文件:系统中对所有用户都普遍适用的配置。若使用 git config 时用 --system 选项,读写的就是这个文件。
172 | * ```~/.gitconfig``` 文件:用户目录下的配置文件只适用于该用户。若使用 git config 时用 --global 选项,读写的就是这个文件。
173 | * 当前项目的 Git 目录中的配置文件(也就是工作目录中的 .git/config 文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以 .git/config 里的配置会覆盖 /etc/gitconfig 中的同名变量。
174 |
175 | #### 用户信息
176 | 第一个要配置的是你个人的用户名称和电子邮件地址。这两条配置很重要,每次 Git 提交时都会引用这两条信息,说明是谁提交了更新,所以会随更新内容一起被永久纳入历史记录:
177 | ```
178 | $ git config --global user.name "John Doe"
179 | $ git config --global user.email johndoe@example.com
180 | ```
181 |
182 | #### 查看配置信息
183 | 要检查已有的配置信息,可以使用 git config --list 命令:
184 | ```
185 | $ git config --list
186 | user.name=Scott Chacon
187 | user.email=schacon@gmail.com
188 | color.status=auto
189 | color.branch=auto
190 | color.interactive=auto
191 | color.diff=auto
192 | ...
193 | ```
194 |
195 | ### 3. 生成 ssh 密钥
196 | #### 1.查看ssh密钥
197 | 查看是否已经有了ssh密钥,命令如下:
198 | ```
199 | $ cd ~/.ssh
200 | ```
201 | 如果没有密钥则不会有此文件夹,有则备份删除。
202 |
203 | #### 2.生成密钥
204 | 生成ssh密钥,命令如下:
205 | ```
206 | $ ssh-keygen -t rsa -C “example@example.com”
207 | ```
208 | 按3次回车,密码为空。
209 |
210 | #### 3 .添加ssh密钥
211 | 在gitlab/github个人中心```SSH keys```添加ssh密钥,这要添加的是“id_rsa.pub”里面的公钥。
212 |
213 |
214 | ## 安装MySQL
215 | 一、安装MySQL
216 | ```
217 | $ brew install mysql
218 | ```
219 | 二、启动mysql服务
220 | ```
221 | $ mysql.server start
222 | ```
223 | 三、初始化mysql配置
224 | ```
225 | $ mysql_secure_installation
226 | ```
227 |
228 | 其他命令:
229 | ```
230 | # 获取 service 列表
231 | brew services list
232 | # 重启 mysql 服务
233 | brew services restart mysql
234 | # 停止 mysql 服务
235 | brew services stop mysql
236 | ```
237 |
238 | ### 常见问题
239 | 解决 Authentication plugin ‘caching_sha2_password’ cannot be loaded 的方法,可以往你的连接工具、或者程序应用显示指定身份验证方式,或者直接改为以前的版本方式:
240 | 你可以使用如下方式:
241 | ```
242 | ALTER USER root@localhost IDENTIFIED WITH mysql_native_password BY ‘root2018’;
243 | ```
244 |
245 | 修改root的密码改为root2018。
246 |
--------------------------------------------------------------------------------
/contents/Tools/Mac_Useful_Skills.md:
--------------------------------------------------------------------------------
1 | # Mac 使用技巧
2 |
3 | ## Mac OS X MySQL客户端工具
4 | * [Sequel Pro](http://www.sequelpro.com/)
5 | * Navicat Premium
6 | * [MySQL workbench](http://www.sequelpro.com/)
7 |
8 | ## Mac OS 画图工具
9 | * [draw.io](https://www.draw.io/)
10 |
--------------------------------------------------------------------------------
/docs/image/Http/README.md:
--------------------------------------------------------------------------------
1 | ## HTTP
2 |
--------------------------------------------------------------------------------
/docs/image/Http/htt2_binary_frame.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Http/htt2_binary_frame.jpg
--------------------------------------------------------------------------------
/docs/image/Http/http2_multiplexing.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Http/http2_multiplexing.jpg
--------------------------------------------------------------------------------
/docs/image/Http/http_request.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Http/http_request.png
--------------------------------------------------------------------------------
/docs/image/Http/http_response.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Http/http_response.png
--------------------------------------------------------------------------------
/docs/image/Http/tcp_3_handshake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Http/tcp_3_handshake.png
--------------------------------------------------------------------------------
/docs/image/Http/tcp_4_bye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Http/tcp_4_bye.png
--------------------------------------------------------------------------------
/docs/image/Hystrix/HystrixRollingNumber_bucket.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Hystrix/HystrixRollingNumber_bucket.png
--------------------------------------------------------------------------------
/docs/image/Hystrix/HystrixRollingNumber_window.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Hystrix/HystrixRollingNumber_window.png
--------------------------------------------------------------------------------
/docs/image/Hystrix/README.md:
--------------------------------------------------------------------------------
1 | ## Hystrix
2 |
--------------------------------------------------------------------------------
/docs/image/Interview/README.md:
--------------------------------------------------------------------------------
1 | # Interview
2 |
--------------------------------------------------------------------------------
/docs/image/Interview/System_Archtecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Interview/System_Archtecture.png
--------------------------------------------------------------------------------
/docs/image/JAVA_HOME.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/JAVA_HOME.png
--------------------------------------------------------------------------------
/docs/image/JDK_Source/HashMap_jdk8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/JDK_Source/HashMap_jdk8.jpg
--------------------------------------------------------------------------------
/docs/image/JDK_Source/LinkedList_jdk8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/JDK_Source/LinkedList_jdk8.png
--------------------------------------------------------------------------------
/docs/image/JDK_Source/README.md:
--------------------------------------------------------------------------------
1 | ## JDK源码
2 |
--------------------------------------------------------------------------------
/docs/image/JDK_Source/concurrenthashmap_jdk7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/JDK_Source/concurrenthashmap_jdk7.png
--------------------------------------------------------------------------------
/docs/image/JDK_Source/concurrenthashmap_jdk8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/JDK_Source/concurrenthashmap_jdk8.png
--------------------------------------------------------------------------------
/docs/image/JVM/Jvm_Area.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/JVM/Jvm_Area.jpg
--------------------------------------------------------------------------------
/docs/image/JVM/Jvm_GC_Root.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/JVM/Jvm_GC_Root.png
--------------------------------------------------------------------------------
/docs/image/JVM/Jvm_collector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/JVM/Jvm_collector.png
--------------------------------------------------------------------------------
/docs/image/JVM/Jvm_heap_area.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/JVM/Jvm_heap_area.png
--------------------------------------------------------------------------------
/docs/image/JVM/README.md:
--------------------------------------------------------------------------------
1 | # JVM
2 |
--------------------------------------------------------------------------------
/docs/image/RBAC/RBAC_extension.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/RBAC/RBAC_extension.jpg
--------------------------------------------------------------------------------
/docs/image/RBAC/RBAC_group.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/RBAC/RBAC_group.jpg
--------------------------------------------------------------------------------
/docs/image/RBAC/RBAC_permission_category.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/RBAC/RBAC_permission_category.jpg
--------------------------------------------------------------------------------
/docs/image/RBAC/RBAC_permission_model.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/RBAC/RBAC_permission_model.jpg
--------------------------------------------------------------------------------
/docs/image/Redis/README.md:
--------------------------------------------------------------------------------
1 | ## Redis
2 |
--------------------------------------------------------------------------------
/docs/image/Redis/redis_ds2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Redis/redis_ds2.jpg
--------------------------------------------------------------------------------
/docs/image/Redis/redis_ds_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Redis/redis_ds_1.jpg
--------------------------------------------------------------------------------
/docs/image/Spring-Framework-overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Spring-Framework-overview.png
--------------------------------------------------------------------------------
/docs/image/Spring/AspectJAwareAdvisorAutoProxyCreator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Spring/AspectJAwareAdvisorAutoProxyCreator.png
--------------------------------------------------------------------------------
/docs/image/Spring/ClassPathXmlApplicationContext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Spring/ClassPathXmlApplicationContext.png
--------------------------------------------------------------------------------
/docs/image/Spring/DefaultListableBeanFactory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/Spring/DefaultListableBeanFactory.png
--------------------------------------------------------------------------------
/docs/image/Spring/README.md:
--------------------------------------------------------------------------------
1 | ## Spring
2 |
--------------------------------------------------------------------------------
/docs/image/alipay/README.md:
--------------------------------------------------------------------------------
1 | # 支付宝双十一
2 |
--------------------------------------------------------------------------------
/docs/image/cap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/cap.png
--------------------------------------------------------------------------------
/docs/image/cpu_cache.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/cpu_cache.png
--------------------------------------------------------------------------------
/docs/image/gbf40/README.md:
--------------------------------------------------------------------------------
1 | ## 高并发系统设计40问
2 | 高并发系统设计40问
3 |
--------------------------------------------------------------------------------
/docs/image/gbf40/gbf40_danti.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/gbf40/gbf40_danti.jpg
--------------------------------------------------------------------------------
/docs/image/gbf40/gbf40_msa.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/gbf40/gbf40_msa.jpg
--------------------------------------------------------------------------------
/docs/image/git_flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/git_flow.png
--------------------------------------------------------------------------------
/docs/image/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/logo.jpg
--------------------------------------------------------------------------------
/docs/image/maven_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/maven_home.png
--------------------------------------------------------------------------------
/docs/image/tas_list_alipay.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/tas_list_alipay.jpeg
--------------------------------------------------------------------------------
/docs/image/task_list_iqj.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/task_list_iqj.jpeg
--------------------------------------------------------------------------------
/docs/image/zfb_zqhb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/docs/image/zfb_zqhb.jpg
--------------------------------------------------------------------------------
/font/README.md:
--------------------------------------------------------------------------------
1 | # 中文字体库
2 |
3 | 可以从 https://www.wfonts.com/ 网站下载字体。
4 |
--------------------------------------------------------------------------------
/font/fangsong.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/font/fangsong.zip
--------------------------------------------------------------------------------
/font/kaiti.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TFdream/blog/b127bc2533d953adcc8f366ab9fb4033fa8e20d8/font/kaiti.zip
--------------------------------------------------------------------------------
/ppt/README.md:
--------------------------------------------------------------------------------
1 | #PPT
2 | PPT
3 |
--------------------------------------------------------------------------------