springboot2 已经发布,其中最亮眼的非webflux响应式编程莫属了!响应式的weblfux可以支持高吞吐量,意味着使用相同的资源可以处理更加多的请求,毫无疑问将会成为未来技术的趋势,是必学的技术!很多人都看过相关的入门教程,但看完之后总觉得很迷糊,知其然不知道其所以然,包括我本人也有相同的疑惑。后面在研究和学习中发现,是我的学习路径不对,很多基本概念不熟悉,之前公司主打的jdk版本还是1.6/1.7,直接跳到运行在jdk8上的webflux,跨度太大,迷惑是在所难免的!
在这里我个人推荐的学习途径如下:先学习jdk8的lambda表达式和stream流编程,了解函数式编程的知识点和思想,接着学习jdk9的响应式流flux,理解响应式流概念,理解背压和实现机制。这2者学好之后,很容易理解webflux的基石reactor,再学习webflux就水到渠成了!
这里我记录了自己的学习之路,列出了每一块的学习重点,除了API的知识点学习之外,更加重要的了解底层运行机制和实现原理。对于我个人来说,学习技术如果不了解原理,知识点需要死记硬背,而了解了底层机制之后,不但不需要死记硬背,还可以把自己的技术点连成面融会贯通,很容易举一反三,知识点也不会忘记,也能和别人扯扯技术的底层实现了。
下面只讲解重点/高级知识和底层原理,入门教程请自行搜索学习
lambda表达式
lambda表达式中的this
lambda表达式最终会返回一个实现了指定接口的实例,看上去和内部匿名类很像,但有一个最大的区别就是代码里面的this,内部匿名类this指向的就是匿名类,而lambda表达式里面的this指向的当前类。
package jdk8.lambda;
/**
* lambda表达式的this
*
* @author 晓风轻
*
*/
public class ThisDemo {
private String name = "ThisDemo";
public void test() {
// 匿名类实现
new Thread(new Runnable() {
private String name = "Runnable";
@Override
public void run() {
System.out.println("这里的this指向匿名类:" + this.name);
}
}).start();
// lambda实现
new Thread(() -> {
System.out.println("这里的this指向当前的ThisDemo类:" + this.name);
}).start();
}
public static void main(String[] args) {
ThisDemo demo = new ThisDemo();
demo.test();
}
}
输出
这里的this指向匿名类:Runnable
这里的this指向当前的ThisDemo类:ThisDemo
实现原理
lambda表达式里面,会把lambda表达式在本类中生成一个以lambda$+数字的方法。关键点:该方法不一定是static的方法,是static还是非static,取决于lambda表达式里面是否引用了this。这就是为什么lambda表达式里面的this指向的是本地,因为他在本类里面创建了一个方法,然后把lambda表达式里面的代码放进去。
// lambda实现
// 下面会自动生成lambda$0方法,由于使用了this,所以是非static方法
new Thread(() -> {
System.out.println("这里的this指向当前的ThisDemo类:" + this.name);
}).start();
// lambda实现
// 下面会自动生成lambda$1方法,由于使用了this,所以是static方法
new Thread(() -> {
System.out.println("这里没有引用this,生成的lambda1方法是static的");
}).start();
上面代码会自动生成2个lambda$方法
使用javap -s -p 类名, 可以看出一个是static,一个是非staic的
这就是为什么lambda表达式里面的this指向当前类的底层机制!因为代码就是在本类的一个方法里面执行的。
额外说一句,自动生成的方法是否带参数取决于lambda是否有参数,例子中表达式没有参数(箭头左边是空的),所以自动生成的也没有。
实例方法的方法引用
方法引用有多种,静态方法的方法引用很好理解,但实例对象的方法引用一开始确实让我有点费解,这和静态方法引用由啥区别?看上去很像啊。
class DemoClass {
/**
* 这里是一个静态方法
*/
public static int staticMethod(int i) {
return i * 2;
}
/**
* 这里是一个实例方法
*/
public int normalMethod(int i) {
System.out.println("实例方法可以访问this:" + this);
return i * 3;
}
}
public class MethodRefrenceDemo {
public static void main(String[] args) {
// 静态方法的方法引用
IntUnaryOperator methodRefrence1 = DemoClass::staticMethod;
System.out.println(methodRefrence1.applyAsInt(111));
DemoClass demo = new DemoClass();
// 实例方法的方法引用
IntUnaryOperator methodRefrence2 = demo::normalMethod;
System.out.println(methodRefrence2.applyAsInt(111));
}
}
这里牵涉到不同的语言里面对this的实现方法。我们知道静态方法和实例方法的区别是实例方法有this,静态方法没有。java里面是怎么样实现this的呢?
java里面在默认把this作为参数,放到实例方法的第一个参数。
就是说:
/**
* 这里是一个实例方法
*/
public int normalMethod(int i) {
System.out.println("实例方法可以访问this:" + this);
return i * 2;
}
编译之后和下面这样的代码编译之后是一样的!
/**
* 这里是一个实例方法
*/
public int normalMethod(DemoClass this,int i) {
System.out.println("实例方法可以访问this:" + this);
return i * 2;
}
如何证明?
第1个证据,看反编译里面的本地变量表。
静态方法:
而实例方法
第2个证据,下面这样的代码能正确执行。
class DemoCl2{
/**
* 这里是一个实例方法, 代码上2个参数
* 而我们调用的时候只有一个参数
*/
public int normalMethod(DemoClass2 this,int i) {
return i * 2;
}
}
public