diff --git a/JdkLearn/src/main/java/com/learnjava/concurent/ThreadPoolExecutorDemo.java b/JdkLearn/src/main/java/com/learnjava/concurent/ThreadPoolExecutorDemo.java new file mode 100644 index 0000000..5d5b5fc --- /dev/null +++ b/JdkLearn/src/main/java/com/learnjava/concurent/ThreadPoolExecutorDemo.java @@ -0,0 +1,48 @@ +package com.learnjava.concurent; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @Description + * @Author luohaiyang + * @Date 2022/4/24 + */ +public class ThreadPoolExecutorDemo { + + public static void main(String[] args) { + testThreadPoolExecutorBinaryCalc(); + } + + + /** + * 验证ThreadPoolExecutor中的二进制位运算操作 + */ + private static void testThreadPoolExecutorBinaryCalc() { +// System.out.println(ctl.get()); +// System.out.println(Integer.toBinaryString(ctlOf(RUNNING, 0))); +// System.out.println(Integer.toBinaryString(RUNNING)); + // 修改线程状态-STOP + System.out.println(Integer.toBinaryString(~runStateOf(ctlOf(STOP, 10)))); + // 修改线程状态-TERMINATED +// System.out.println(runStateOf(3)); +// System.out.println(Integer.toBinaryString(~CAPACITY)); + } + + private static final int COUNT_BITS = Integer.SIZE - 3; + + private static final int CAPACITY = (1 << COUNT_BITS) - 1; + + private static final int RUNNING = -1 << COUNT_BITS; + private static final int SHUTDOWN = 0 << COUNT_BITS; + private static final int STOP = 1 << COUNT_BITS; + private static final int TIDYING = 2 << COUNT_BITS; + private static final int TERMINATED = 3 << COUNT_BITS; + + private static AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); + + private static int runStateOf(int c) { return c & ~CAPACITY; } + + private static int workerCountOf(int c) { return c & CAPACITY; } + + private static int ctlOf(int rs, int wc) { return rs | wc; } +} diff --git a/README.md b/README.md index 7181972..fae4153 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,8 @@ SpringCloud源码 - [一篇文章快速深入学习ThreadLocal](https://github.com/coderbruis/JavaSourceLearning/blob/master/note/JDK/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%BF%AB%E9%80%9F%E6%B7%B1%E5%85%A5%E5%AD%A6%E4%B9%A0ThreadLocal.md) - [深入学习Java volatile关键字](https://github.com/coderbruis/JavaSourceLearning/blob/master/note/JDK/%E6%B7%B1%E5%85%A5%E5%AD%A6%E4%B9%A0Java%20volatile%E5%85%B3%E9%94%AE%E5%AD%97.md) - [深入学习Thread底层原理](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/JDK/%E6%B7%B1%E5%85%A5%E5%AD%A6%E4%B9%A0Thread%E5%BA%95%E5%B1%82%E6%BA%90%E7%A0%81.md) + - [深入学习JDK1.7、8 HashMap扩容原理]() + - [开源项目里那些看不懂的位运算分析](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/JDK/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E9%87%8C%E9%82%A3%E4%BA%9B%E7%9C%8B%E4%B8%8D%E6%87%82%E7%9A%84%E4%BD%8D%E8%BF%90%E7%AE%97%E5%88%86%E6%9E%90.md) - Spring源码学习 - Spring版本:5.2.1.RELEASE @@ -135,6 +137,7 @@ SpringCloud源码 - Netty底层源码解析-FastThreadLocal原理分析 - Netty底层源码解析-内存分配原理分析 - Netty底层源码解析-RocketMQ底层使用到的Netty + - [Netty底层的优化总结]() - [实战+原理效果更佳!强烈推荐闪电侠大佬实战课:《Netty 入门与实战:仿写微信 IM 即时通讯系统》](https://juejin.cn/book/6844733738119593991) Netty实战课相关点位于:Spring-Netty,com/bruis/learnnetty/im包下,有需要的读者可前往查看。 diff --git a/Spring-Netty/src/main/java/com/bruis/learnnetty/im/console/ConsoleCommandManager.java b/Spring-Netty/src/main/java/com/bruis/learnnetty/im/console/ConsoleCommandManager.java index d4759d0..8bf69f6 100644 --- a/Spring-Netty/src/main/java/com/bruis/learnnetty/im/console/ConsoleCommandManager.java +++ b/Spring-Netty/src/main/java/com/bruis/learnnetty/im/console/ConsoleCommandManager.java @@ -19,7 +19,7 @@ public class ConsoleCommandManager implements ConsoleCommand { public ConsoleCommandManager() { consoleCommandMap = new HashMap<>(); consoleCommandMap.put("sendToUser", new SendToUserConsoleCommand()); - consoleCommandMap.put("logout", new LoginConsoleCommand()); + consoleCommandMap.put("logout", new LogoutConsoleCommand()); consoleCommandMap.put("createGroup", new CreateGroupConsoleCommand()); consoleCommandMap.put("joinGroup", new JoinGroupConsoleCommand()); consoleCommandMap.put("quitGroup", new QuitGroupConsoleCommand()); diff --git a/Spring-Netty/src/main/java/com/bruis/learnnetty/im/console/LoginConsoleCommand.java b/Spring-Netty/src/main/java/com/bruis/learnnetty/im/console/LoginConsoleCommand.java index 105cf58..3e632ca 100644 --- a/Spring-Netty/src/main/java/com/bruis/learnnetty/im/console/LoginConsoleCommand.java +++ b/Spring-Netty/src/main/java/com/bruis/learnnetty/im/console/LoginConsoleCommand.java @@ -17,7 +17,11 @@ public void exec(Scanner scanner, Channel channel) { LoginRequestPacket loginRequestPacket = new LoginRequestPacket(); System.out.print("输入用户名登录: "); - loginRequestPacket.setUserName(scanner.nextLine()); + String userIdStr; // 在退出登录logout之后 这里会读取到最后一个回车符 用户名就是空字符串会导致无法退出登录 + while ((userIdStr = scanner.nextLine()).isEmpty()) { + System.out.println("用户名异常, 请重新输入"); + } + loginRequestPacket.setUserName(userIdStr); loginRequestPacket.setPassword("pwd"); // 发送登录数据包 diff --git "a/note/Dubbo/Dubbo\345\272\225\345\261\202\346\272\220\347\240\201\345\255\246\344\271\240\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224 Dubbo\347\232\204SPI\346\234\272\345\210\266\357\274\210\344\270\213\357\274\211.md" "b/note/Dubbo/Dubbo\345\272\225\345\261\202\346\272\220\347\240\201\345\255\246\344\271\240\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224 Dubbo\347\232\204SPI\346\234\272\345\210\266\357\274\210\344\270\213\357\274\211.md" index d99cbec..8bd2172 100644 --- "a/note/Dubbo/Dubbo\345\272\225\345\261\202\346\272\220\347\240\201\345\255\246\344\271\240\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224 Dubbo\347\232\204SPI\346\234\272\345\210\266\357\274\210\344\270\213\357\274\211.md" +++ "b/note/Dubbo/Dubbo\345\272\225\345\261\202\346\272\220\347\240\201\345\255\246\344\271\240\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224 Dubbo\347\232\204SPI\346\234\272\345\210\266\357\274\210\344\270\213\357\274\211.md" @@ -51,8 +51,9 @@ SimpleExt ext = ExtensionLoader.getExtensionLoader(SimpleExt.class).getDefaultEx } return loader; } -```Java -getExtensionLoader方法首先回去判断EXTENSION_LOADERS缓存中是否已经缓存了该类型的扩展点加载器,如果没有则new一个该类型的ExtensionLoader并添加进EXTENSION_LOADERS中。但需要注意的是ExtensionLoader的构造方法 +``` + +getExtensionLoader方法首先会去判断EXTENSION_LOADERS缓存中是否已经缓存了该类型的扩展点加载器,如果没有则new一个该类型的ExtensionLoader并添加进EXTENSION_LOADERS中。但需要注意的是ExtensionLoader的构造方法 中,是会先创建默认的ExtensionFactory类型的ExtensionLoader对象,然后调用getAdaptiveExtension()方法创建适配类型的扩展点实现类。 ```Java @@ -112,7 +113,7 @@ getExtensionLoader方法首先回去判断EXTENSION_LOADERS缓存中是否已经 loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages()); } - // 这里只会返回非Adaptive和非Wrapper类型的扩展点实现类Class,因为Adaptive会被缓存到cachedAdaptiveClasses缓存中,儿Wrapper类型的类会被缓存到cachedWrapperClasses缓存中。 + // 这里只会返回非Adaptive和非Wrapper类型的扩展点实现类Class,因为Adaptive会被缓存到cachedAdaptiveClasses缓存中,而Wrapper类型的类会被缓存到cachedWrapperClasses缓存中。 return extensionClasses; } @@ -267,10 +268,10 @@ public class AdaptiveExtensionFactory implements ExtensionFactory { } ``` -① 中逻辑是这样的,调用ExtensionLoader#getSupportedExtensions()回去加载ExtensionFactory所有的扩展点实现类,并返回一个扩展点名称作为Key,扩展点实现类Class对象为Value的Map集合, +① 中逻辑是这样的,调用ExtensionLoader#getSupportedExtensions()会去加载ExtensionFactory所有的扩展点实现类,并返回一个扩展点名称作为Key,扩展点实现类Class对象为Value的Map集合, 在上面的SPI配置文件中已经展示出来了,所以这里获取到的是spi。 -// 有人可能会问,上面的SPI配置文件不是还有一个adaptive吗?为什么没加载进来呢?这是因为getSupportedExtension()中实际是调用getExtensionClasses()方法去获取Map集合,而其底层是去从cachedClasses缓存中 +有人可能会问,上面的SPI配置文件不是还有一个adaptive吗?为什么没加载进来呢?这是因为getSupportedExtension()中实际是调用getExtensionClasses()方法去获取Map集合,而其底层是去从cachedClasses缓存中 获取,而adaptive扩展点实现类是缓存在了cachedAdaptiveClass中的。 @@ -385,4 +386,6 @@ public class SimpleExt$Adaptive implements org.apache.dubbo.common.extension.ext ### 3. @Activate注解 +TODO + diff --git "a/note/JDK/\345\274\200\346\272\220\351\241\271\347\233\256\351\207\214\351\202\243\344\272\233\347\234\213\344\270\215\346\207\202\347\232\204\344\275\215\350\277\220\347\256\227\345\210\206\346\236\220.md" "b/note/JDK/\345\274\200\346\272\220\351\241\271\347\233\256\351\207\214\351\202\243\344\272\233\347\234\213\344\270\215\346\207\202\347\232\204\344\275\215\350\277\220\347\256\227\345\210\206\346\236\220.md" new file mode 100644 index 0000000..cec5185 --- /dev/null +++ "b/note/JDK/\345\274\200\346\272\220\351\241\271\347\233\256\351\207\214\351\202\243\344\272\233\347\234\213\344\270\215\346\207\202\347\232\204\344\275\215\350\277\220\347\256\227\345\210\206\346\236\220.md" @@ -0,0 +1,96 @@ +相信看过几个流行框架源码的小伙伴,或多或少都见到过底层代码运用的位运算,不知道有多少是能够一眼看懂了的,一眼看懂了的都是“真大佬”。如果看不懂的话就老老实实的通过二进制分析来看下这些二进制算法的作用。 + +## 1. JDK1.8 HashMap里运用到的为运算 + +## 2. Netty里运用的位运算 + +## 3. JDK ThreadPoolExecutor里的位运算 + +```java +public class ThreadPoolExecutor extends AbstractExecutorService { + + // ... 其他代码省略 + + private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); + private static final int COUNT_BITS = Integer.SIZE - 3; + private static final int CAPACITY = (1 << COUNT_BITS) - 1; + + private static final int RUNNING = -1 << COUNT_BITS; + private static final int SHUTDOWN = 0 << COUNT_BITS; + private static final int STOP = 1 << COUNT_BITS; + private static final int TIDYING = 2 << COUNT_BITS; + private static final int TERMINATED = 3 << COUNT_BITS; + + private static int runStateOf(int c) { return c & ~CAPACITY; } + private static int workerCountOf(int c) { return c & CAPACITY; } + private static int ctlOf(int rs, int wc) { return rs | wc; } + + private static boolean runStateLessThan(int c, int s) { + return c < s; + } + + private static boolean runStateAtLeast(int c, int s) { + return c >= s; + } + + private static boolean isRunning(int c) { + return c < SHUTDOWN; + } + + // ... 其他代码省略 +} +``` +首先看下ctlOf()方法,入参是int rs和int wc,这里rs其实是线程池里线程的状态,而wc表示的时线程数,基于这两个点我们进行位运算分析。 + +首先看先成变量: +```java +private static final int COUNT_BITS = Integer.SIZE - 3; +private static final int RUNNING = -1 << COUNT_BITS; +``` +Integer.SIZE = 32,所以COUNT_BITS = 29,这里RUNNING就是-1的二进制位左移29位,得到的结果就是(提示:-1的二进制是: 1111 1111 1111 1111 ... 三十二位全是1) +``` +1110 0000 0000 0000 0000 0000 0000 0000 +``` +这就是RUNNING的二进制值。 +同理我们可以分别得到SHUTDOWN、STOP、TIDYING、TERMINATED的二进制值 +``` +0000 0000 0000 0000 0000 0000 0000 0000 // SHUTDOWN +0010 0000 0000 0000 0000 0000 0000 0000 // STOP +0100 0000 0000 0000 0000 0000 0000 0000 // TIDYING +0110 0000 0000 0000 0000 0000 0000 0000 // TERMINATED +``` +这里其实已经可以看出作者的用意了,就是让高3位作为线程池的状态,低29位用来表示线程数量。对于 +```java +private static int ctlOf(int rs, int wc) { return rs | wc; } +// 位运算“或”,遇1得1,否则为0 +``` +所以ctlOf就表示将rs代表的线程状态和wc代表的线程数计算在同一个32位二进制中,互相不影响。 +所以如下: +```java +private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); +// 1110 0000 0000 0000 0000 0000 0000 0000 +``` +接着,再来分析下另外两个方法:runStateOf()、workerCountOf(),这两个方法都喝CAPACITY有关,先看下CAPACITY属性 +```java +private static final int CAPACITY = (1 << COUNT_BITS) - 1; +// 1 << 29 => 0010 0000 0000 0000 0000 0000 0000 0000 +// 1 << 29 - 1 => 0001 1111 1111 1111 1111 1111 1111 1111 + + +private static int runStateOf(int c) { return c & ~CAPACITY; } +// ~CAPACITY => 1110 0000 0000 0000 0000 0000 0000 0000 +// 运算“与”表示11得1,否则为0,所以 c & ~CAPACITY实际上就只能操作高三位, +// 也就是只能计算线程状态,并且~CAPACITY表示的是RUNNING时的状态 + + +private static int workerCountOf(int c) { return c & CAPACITY; } +// CAPACITY => 0001 1111 1111 1111 1111 1111 1111 1111 +// 所以 c & CAPACITY 就表示只能操作低29位,所以workerCountOf就只能操作线程数 +``` +这里需要注意的是,runStateOf()和workerCountOf()传入的数字都是需要由:ctlOf()计算返回的,否则计算会出错。 + +线程池位运算相关验证代码于,读者可自行测试以加强理解。 +[ThreadPoolExecutorDemo](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/JdkLearn/src/main/java/com/learnjava/concurent/ThreadPoolExecutorDemo.java) + + +未完待续... \ No newline at end of file diff --git "a/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240Java volatile\345\205\263\351\224\256\345\255\227.md" "b/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240Java volatile\345\205\263\351\224\256\345\255\227.md" index 79f3bfd..015b838 100644 --- "a/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240Java volatile\345\205\263\351\224\256\345\255\227.md" +++ "b/note/JDK/\346\267\261\345\205\245\345\255\246\344\271\240Java volatile\345\205\263\351\224\256\345\255\227.md" @@ -51,7 +51,7 @@ Lock引起的将当前处理器缓存该变量的数据写回到系统内存中 每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是否过期,当处理器发现自己缓存行对于数据的内存地址被修改了,就会将当前缓存行设置为无效。当处理器对这个数据进行修改操作时,会重新从系统内存中读取该数据到处理器缓存中。 -[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bTawJOHf-1596181331575)(https://note.youdao.com/yws/api/personal/file/AA87E3ABBEDB4A37B69D8E75B5ED12C1?method=download&shareKey=f9788b07ab72368f3613b2744614eecf)] +![volatile-01](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/JDK/volatile-01.png) 为了实现volatile的内存语义,编译期在生成字节码时会对使用volatile关键字修饰的变量进行处理,在字节码文件里对应位置生成一个Lock前缀指令,Lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成。 @@ -96,7 +96,7 @@ d = 4; //语句五 **volatile内存语义的底层实现原理——内存屏障** 为了实现volatile的内存语义,编译期在生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序。下图看看JMM针对编译期指定的volatile重排序的规则表: -[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nUC08aj9-1596181331578)(https://note.youdao.com/yws/api/personal/file/2DB4A9DDE8D243E680668BEDA1EA931D?method=download&shareKey=03684bd761521c57dfea00548eadeb15)] +![volatile-04](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/JDK/volatile-04.png) 就上面的图标,是什么含义呢? 举例来说, @@ -117,12 +117,12 @@ volatile读之后的操作不会被编译器重排序到volatile读之前。 2. 在每个volatile写操作后插入StoreLoad屏障 3. 在每个volatile读前面插入一个LoadLoad屏障 4. 在每个volatile读后面插入一个LoadStore屏障 - -[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z1N3KBZj-1596181331583)(https://note.youdao.com/yws/api/personal/file/E11087F8FD5B4673ABD8C58F6F8DA232?method=download&shareKey=cf78d935c04cb11b039399e1d4825b74)] + +![volatile-02](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/JDK/volatile-02.png) - StoreStore屏障可以保证在volatile写之前,所有的普通写操作已经对所有处理器可见,StoreStore屏障保障了在volatile写之前所有的普通写操作已经刷新到主存。 - StoreLoad屏障避免volatile写与下面有可能出现的volatile读/写操作重排。因为编译器无法准确判断一个volatile写后面是否需要插入一个StoreLoad屏障(写之后直接就return了,这时其实没必要加StoreLoad屏障),为了能实现volatile的正确内存语意,JVM采取了保守的策略。在每个volatile写之后或每个volatile读之前加上一个StoreLoad屏障,而大多数场景是一个线程写volatile变量多个线程去读volatile变量,同一时刻读的线程数量其实远大于写的线程数量。选择在volatile写后面加入StoreLoad屏障将大大提升执行效率(上面已经说了StoreLoad屏障的开销是很大的)。 -[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pRcUS5Mm-1596181331589)(https://note.youdao.com/yws/api/personal/file/2A92B2D468A345F6A55C75249A89845A?method=download&shareKey=ac99a6bcd169bf4bcda8b0fbd33e0003)] +![volatile-03](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/JDK/volatile-03.png) - LoadLoad屏障保证了volatile读不会与下面的普通读发生重排 - LoadStore屏障保证了volatile读不回与下面的普通写发生重排。 diff --git "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\212\357\274\211.md" "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\212\357\274\211.md" index 436b444..248f495 100644 --- "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\212\357\274\211.md" +++ "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\212\357\274\211.md" @@ -28,7 +28,7 @@ ApplicationContext bf = new ClassPathXmlApplicationContext("applicationContext.x ### DefaultListableBeanFactory DefaultListableBeanFactory是整个bean加载的核心部分,是Spring注册及加载bean的默认实现。下面看看DefaultListableBeanFactory的层次结构图。 -![图片1](https://note.youdao.com/yws/api/personal/file/A91C9C5BB33B48A4B501435C157FFD99?method=download&shareKey=2b9a7ef7fd42d051fec83fe3f5eef7a8) +![spring-01](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-01.png) 从上往下开始介绍各个类以及接口的作用: - AliasRegistry(接口):alias指的是bean的别名,而aliasRegistry定义了对alias的增删改查等操作。 - SimpleAliasRegistry(类):主要使用map作为alias的缓存,并对接口AliasRegistry进行实现。 @@ -48,7 +48,7 @@ DefaultListableBeanFactory是整个bean加载的核心部分,是Spring注册 ### XmlBeanDefinitionReader XML配置文件的读取是Spring中最重要的功能,因为Spring的大部分功能都是以配置作为切入点的,XmlBeanDefinitionReader实现了对资源文件的读取、解析以及注册。先看一下XmlBeanDefinitionReader的层次结构图。 -![图片2](https://note.youdao.com/yws/api/personal/file/477FF4A409A94CBB8CF9A05A16D8F7D4?method=download&shareKey=de7d24b623d4c5bb7e65bb440438e271) +![spring-02](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-02.png) - EnvironmentCapable(接口):定义获取Environment方法,Environment代表了配置文件。 - BeanDefinitionReader(接口):主要定义资源文件读取并转换为BeanDefinition的各个功能。 @@ -96,7 +96,7 @@ Person{name='Bruis', age=23} ** 前方高能 ** -![图片3](https://note.youdao.com/yws/api/personal/file/219238FD61C146C99E137E303D52EA66?method=download&shareKey=d5e5aaa1e9fa782eeb056b89119c3565) +![spring-03](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-03.jpg) 通过在断点debug,跟踪程序运行。 @@ -146,7 +146,7 @@ public void setConfigLocations(String... locations) { 下面我们来重点看看refresh()过程。 -![Image](https://note.youdao.com/yws/api/personal/file/76AE8FEDAFF54B6881C336B056AC5B0A?method=download&shareKey=430f5263180efd8467df6e6434456f3d) +![spring-04](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-04.jpg) 1. AbstractApplicationContext.class ```Java @@ -239,8 +239,8 @@ protected final void refreshBeanFactory() throws BeansException { } ``` 这里先看看上面代码的loadBeanDefinitions()方法运行完后的结果 -![图片](https://note.youdao.com/yws/api/personal/file/59FBCD3CC1B54136A05309EA6B88FEB3?method=download&shareKey=80bdcfcbde0362b73eb633390c5b1042) -![图片](https://note.youdao.com/yws/api/personal/file/E258907852284A6F93A2C305319EBB64?method=download&shareKey=7e1dba96d3b53ca9b6af017552f8fd31) +![spring-05](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-05.png) +![spring-06](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-06.png) 从图中可以知道,loadBeanDefinitions()方法运行完后,在beanFactory变量里面存放着一个ConcurrentHashMap变量,用于存放着person这个KV键值对,Key为person,Value为一个ArrayList的变量,里面存放着person的两个属性:age、name。 那么,person的属性是怎么被封装到beanFactory里面的呢?请看下面的源码解析。 @@ -409,7 +409,7 @@ protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) 下面,继续深入registerBeanDefinitions方法。 -![图片](https://note.youdao.com/yws/api/personal/file/861658D89B0D4B48A7ED56B554CF3028?method=download&shareKey=c3bc974e751495bac74d9ac9ec56cb75) +![spring-07](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-07.jpg) 1. XmlBeanDefinitionReader.class ```Java @@ -636,8 +636,8 @@ public void parsePropertyElement(Element ele, BeanDefinition bd) { } ``` -![Images](https://note.youdao.com/yws/api/personal/file/75CAC9D21AD64BAB89B0D25C8BBE7598?method=download&shareKey=89e73cf46fe18b1b85aecf8d58006f8e) -![Images](https://note.youdao.com/yws/api/personal/file/CF65BB80EB934EBEBA49466CFAB261A0?method=download&shareKey=8b9f0078cf5a3171dfd69d00d9ba55f6) +![spring-08](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-08.png) +![spring-09](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-09.png) 然后,就会一路返回到refresh()方法里的加载bean定义信息的方法——loadBeanDefinitions(),此时beanFactory里面就会存在一个带有KV对的ConcurrentHashMap,而这个beanFactory会存放在Spring容器里面。 ```Java @@ -648,8 +648,8 @@ customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); ``` 再看看DefaultListableBeanFactory里面的内容 -![Images](https://note.youdao.com/yws/api/personal/file/59FBCD3CC1B54136A05309EA6B88FEB3?method=download&shareKey=80bdcfcbde0362b73eb633390c5b1042) -![Images](https://note.youdao.com/yws/api/personal/file/E258907852284A6F93A2C305319EBB64?method=download&shareKey=7e1dba96d3b53ca9b6af017552f8fd31) +![spring-10](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-10.png) +![spring-11](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-11.png) 上面的过程,就已经完成了Spring容器的初始化过程,相信读者也已经对Spring容器的初始化有了一个大致的了解。下面总结一下Spring容器的初始化: - 第一个过程是Resource定位过程。这个Resource定位过程指的是BeanDefinition的资源定位,它由ResourceLoader通过统一的Resource接口来完成,这个Resource对各种形式的BeanDefinition的使用都提供了统一接口。这个定位过程类似于容器寻找数据的过程,就像使用水桶装水先要把水找到一样。 @@ -670,7 +670,7 @@ bean的创建和初始化过程是在refresh方法里的invokeBeanFactoryPostPro - 当容器关闭时,调用Bean的销毁方法 下面先看看创建bean和初始化bean的时序图。 -![Images](https://note.youdao.com/yws/api/personal/file/8B415614A97D45B481925159264C344F?method=download&shareKey=1083828cfcea581b0aa5cae56e3f3090) +![spring-12](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-12.jpg) 1. AbstractApplicationContext.class ```Java @@ -967,7 +967,7 @@ public Object getSingleton(String beanName, ObjectFactory singletonFactory) { ``` 无图无真相: -![Images](https://note.youdao.com/yws/api/personal/file/4C30C0DA143E422FBD27E50AE71AC179?method=download&shareKey=2f4dff65df0e9761ede47d26782dd977) +![spring-13](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-13.png) 5. AbstractAutowireCapableBeanFactory.class ```Java diff --git "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\213\357\274\211.md" "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\213\357\274\211.md" index 7f8691e..89fdf81 100644 --- "a/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\213\357\274\211.md" +++ "b/note/Spring/\346\267\261\345\205\245Spring\346\272\220\347\240\201\347\263\273\345\210\227\357\274\210\344\272\214\357\274\211\342\200\224\342\200\224\346\267\261\345\205\245Spring\345\256\271\345\231\250\357\274\214\351\200\232\350\277\207\346\272\220\347\240\201\351\230\205\350\257\273\345\222\214\346\227\266\345\272\217\345\233\276\346\235\245\345\275\273\345\272\225\345\274\204\346\207\202Spring\345\256\271\345\231\250\357\274\210\344\270\213\357\274\211.md" @@ -79,7 +79,7 @@ SpringIOC容器是如何在Web环境中被加载并起作用的?SpringIOC容 IOC容器的启动过程就是建立Spring上下文的过程,该上下文是与ServletContext相伴而生的,同时也是IOC容器在Web应用环境中的具体表现之一。由ContextLoaderListener启动的上下文为根上下文。在根上下文的基础上,还有一个与Web MVC相关的上下文应用来保存控制器(DispatcherServlet)需要的MVC对象,**作为根上下文的子上下文**,构成一个层次化的上下文体系,这个与Web MVC相关的上下文——WebApplicationContext。在Web容器中启动Spring应用程序时,首先建立根上下文,然后建立这个上下文体系,这个上下文体系的建立是由ContextLoader来完成的。简单点说,ContextLoaderListener的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。 先看看Web程序启动到SpringIOC容器创建和初始化的整个过程。 -![image](https://note.youdao.com/yws/api/personal/file/9755412D703C4DE287B26AF2396E57BD?method=download&shareKey=52783ceb34f405ad47140c22da34275e) +![spring-14](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-14.jpg) 结合着时序图,再去调试源码,思路会清晰很多。 @@ -272,7 +272,7 @@ protected Class determineContextClass(ServletContext servletContext) { ``` 下面看看默认的IOC容器是什么。有图有真相: -![image](https://note.youdao.com/yws/api/personal/file/AB1007BC2A7549D7898417D6231AE4E3?method=download&shareKey=e851d344aedd461f319dba3b8e2c6fe8) +![spring-15](https://github.com/coderbruis/JavaSourceCodeLearning/blob/master/note/images/spring/spring-15.jpg) ```Java protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { diff --git a/note/images/JDK/volatile-01.png b/note/images/JDK/volatile-01.png new file mode 100644 index 0000000..61eb672 Binary files /dev/null and b/note/images/JDK/volatile-01.png differ diff --git a/note/images/JDK/volatile-02.png b/note/images/JDK/volatile-02.png new file mode 100644 index 0000000..a288136 Binary files /dev/null and b/note/images/JDK/volatile-02.png differ diff --git a/note/images/JDK/volatile-03.png b/note/images/JDK/volatile-03.png new file mode 100644 index 0000000..7ace8b9 Binary files /dev/null and b/note/images/JDK/volatile-03.png differ diff --git a/note/images/JDK/volatile-04.png b/note/images/JDK/volatile-04.png new file mode 100644 index 0000000..44b287a Binary files /dev/null and b/note/images/JDK/volatile-04.png differ diff --git a/note/images/spring/spring-01.png b/note/images/spring/spring-01.png new file mode 100644 index 0000000..26d87c9 Binary files /dev/null and b/note/images/spring/spring-01.png differ diff --git a/note/images/spring/spring-02.png b/note/images/spring/spring-02.png new file mode 100644 index 0000000..e309335 Binary files /dev/null and b/note/images/spring/spring-02.png differ diff --git a/note/images/spring/spring-03.jpg b/note/images/spring/spring-03.jpg new file mode 100644 index 0000000..83952d4 Binary files /dev/null and b/note/images/spring/spring-03.jpg differ diff --git a/note/images/spring/spring-04.jpg b/note/images/spring/spring-04.jpg new file mode 100644 index 0000000..654d4ec Binary files /dev/null and b/note/images/spring/spring-04.jpg differ diff --git a/note/images/spring/spring-05.png b/note/images/spring/spring-05.png new file mode 100644 index 0000000..6191186 Binary files /dev/null and b/note/images/spring/spring-05.png differ diff --git a/note/images/spring/spring-06.png b/note/images/spring/spring-06.png new file mode 100644 index 0000000..f6912dc Binary files /dev/null and b/note/images/spring/spring-06.png differ diff --git a/note/images/spring/spring-07.jpg b/note/images/spring/spring-07.jpg new file mode 100644 index 0000000..cf74eaf Binary files /dev/null and b/note/images/spring/spring-07.jpg differ diff --git a/note/images/spring/spring-08.png b/note/images/spring/spring-08.png new file mode 100644 index 0000000..4f12e5f Binary files /dev/null and b/note/images/spring/spring-08.png differ diff --git a/note/images/spring/spring-09.png b/note/images/spring/spring-09.png new file mode 100644 index 0000000..baff012 Binary files /dev/null and b/note/images/spring/spring-09.png differ diff --git a/note/images/spring/spring-10.png b/note/images/spring/spring-10.png new file mode 100644 index 0000000..6191186 Binary files /dev/null and b/note/images/spring/spring-10.png differ diff --git a/note/images/spring/spring-11.png b/note/images/spring/spring-11.png new file mode 100644 index 0000000..f6912dc Binary files /dev/null and b/note/images/spring/spring-11.png differ diff --git a/note/images/spring/spring-12.jpg b/note/images/spring/spring-12.jpg new file mode 100644 index 0000000..ee53f53 Binary files /dev/null and b/note/images/spring/spring-12.jpg differ diff --git a/note/images/spring/spring-13.png b/note/images/spring/spring-13.png new file mode 100644 index 0000000..5f32cb1 Binary files /dev/null and b/note/images/spring/spring-13.png differ diff --git a/note/images/spring/spring-14.jpg b/note/images/spring/spring-14.jpg new file mode 100644 index 0000000..fe86220 Binary files /dev/null and b/note/images/spring/spring-14.jpg differ diff --git a/note/images/spring/spring-15.png b/note/images/spring/spring-15.png new file mode 100644 index 0000000..1309372 Binary files /dev/null and b/note/images/spring/spring-15.png differ