Spring 核心原理解析

用户头像
Chank
关注
发布于: 2020 年 07 月 07 日

Spring核心概念

IoC

IoC(Inversation of Control,控制反转)是实现SOLID原则中的依赖倒置原则(Dependency Inversion Principle)的一个思路,即将对象的初始化、对象的销毁等交给容器来管理。

使用IoC有如下好处:

  • 方便管理对象之间复杂的依赖关系

  • 便于进行单元测试,方便切换Mock组件

  • 便于进行AOP操作,对业务侵入性小

DI

DI(Dependency Injection,依赖注入)是实现控制反转的方法,即由容器动态的将对象的依赖注入到该对象中。

AOP

AOP(Aspect Oriented Programming,面向切面编程)是一种编程思想,旨在通过分离横切关注点来提高模块化,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发效率。主要的应用场景有:日志、安全、性能监控、异常处理等。

JavaBean

JavaBean是符合一定规范编写的Java类,便于封装重用。主要有如下规范:

  1. 提供默认的构造函数

  2. 对属性提供getter跟setter方法

  3. 实现Serializable接口

  4. 所有属性都应该为private

Spring Bean

Spring Bean是受Spring管理的对象,所有能受Spring容器管理的对象都可以称为Spring Bean。Spring Bean的限制比JavaBean少很多。

Spring运行时核心组件



Spring Core(spring-core)、Spring Beans(spring-beans)跟Spring Context(spring-context)是实现IoC的核心组件。

Spring Core

核心源码解析

Spring Core源码结构如下:

spring-core-5.2.6.RELEASE
+ META-INF
- org.springframework
+ asm
- cglib
+ beans
+ core
+ proxy
+ reflect
+ transform
+ util
+ core
+ lang
+ objenesis
+ util


asm:Java字节码处理框架,能够读写字节码,基于字节码层面对代码进行分析和转换。可以用来实现AOP等功能

cglib(Code Generation Library):可用来实现动态代理,动态生成要代理类的子类(对于final方法,无法进行代理);也可以用来实现AOP;底层使用字节码处理框架ASM;比使用Java反射效率更高;JDK动态代理是使用反射来调用委托类的方法,而CGLIB是通过生成FastClass的方法来调用委托类的方法(FastClass的机制是建立委托类方法的索引,通过索引来查找和调用实际的方法)。

core:提供的核心功能:

  1. annotation:读取注解、处理注解

  2. env:提供了两个核心能力:profiles(用于区分环境来实例化Bean,例如development环境或者production环境)跟properties(可以来自properties文件,JVM属性,系统环境变量等)

  3. convert:类型转换工具包;例如可以定义将一个字符串转换为一个实例对象(Converter<S, T>)

  4. io:对资源(Resource)的抽象,定义了获取资源等操作;主要包括ByteArrayResource、ClassPathResource、FileSystemResource、UrlResource等等

  5. Searializer:序列化反序列化工具包

  6. task:同步task跟异步task的核心接口定义跟工具包

  7. type:Class跟Method等的元数据定义(ClassMetadata,MethodMetadata)

lang:条件编译注解,提供注解给静态代码分析工具检查软件缺陷,也可以增强IDE提示,减少潜在Bug

objenesis:对象实例化工具,封装后提供缓存功能

util:工具包

CGLIB源码解析



可以看出,CGLIB依赖于ASM。CGLIB核心代码结构的说明如下:

  • beans:JavaBean相关的工具类

  • core:底层字节码操作等功能,大部分都和ASM有关

  • proxy:创建代理跟方法拦截器相关的功能

  • reflect:加快反射相关的功能,例如FastClass使用了索引来加快方法调用

  • transform:在运行期或者编译器转换类等相关功能

  • util:排序等相关功能

看一个CGLIB动态代理的例子加强理解:

package proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyDemo {
static class Original {
public void originalMethod(String s) {
System.out.println(s);
}
}
static class Handler implements MethodInterceptor {
private final Original original;
public Handler(Original original) {
this.original = original;
}
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("BEFORE");
method.invoke(original, args);
System.out.println("AFTER");
return null;
}
}
public static void main(String[] args){
Original original = new Original();
MethodInterceptor handler = new Handler(original);
Original f = (Original) Enhancer.create(Original.class, handler);
f.originalMethod("Hallo");
}
}

CGLIB生成的代码如下(由于太多,省略了一部分):

...
public class CglibProxyDemo$Original$$EnhancerByCGLIB$$12fc168f extends Original implements Factory {
...
public final void originalMethod(String var1) {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$originalMethod$0$Method, new Object[]{var1}, CGLIB$originalMethod$0$Proxy);
} else {
super.originalMethod(var1);
}
}
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
CglibProxyDemo$Original$$EnhancerByCGLIB$$12fc168f var1 = (CglibProxyDemo$Original$$EnhancerByCGLIB$$12fc168f)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
}
}
public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
String var10000 = var0.toString();
switch(var10000.hashCode()) {
case -508378822:
if (var10000.equals("clone()Ljava/lang/Object;")) {
return CGLIB$clone$4$Proxy;
}
break;
case -144856275:
if (var10000.equals("originalMethod(Ljava/lang/String;)V")) {
return CGLIB$originalMethod$0$Proxy;
}
break;
case 1826985398:
if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
return CGLIB$equals$1$Proxy;
}
break;
case 1913648695:
if (var10000.equals("toString()Ljava/lang/String;")) {
return CGLIB$toString$2$Proxy;
}
break;
case 1984935277:
if (var10000.equals("hashCode()I")) {
return CGLIB$hashCode$3$Proxy;
}
}
return null;
}
...
}

首先来看看Spring Core几个核心类之间的关系:



Enhancer:用于创建代理类,不是线程安全的,在调用静态方法 create 的时候内部会创建一个Enhancer实例,会负责指挥如何生成代理类

Callback:主要有以下Callback:

  • MethodInterceptor(由MethodInterceptorGenerator生成):实现被代理对象的逻辑植入

  • FixedValue(由FixedValueGenerator生成):只会调用 FixedValueloadObject 方法,不会再调用代理目标类的相应方法

  • InvocationHandler(由InvocationHandlerGenerator生成): invoke 方法传入了被代理的对象、调用的方法跟方法参数等,可以自定义实现

  • LazyLoader(由LazyLoaderGenerator生成):被代理的对象在第一次调用的时候才进行初始化

  • Dispatcher(由DispatcherGenerator生成):每次调用被拦截方法的时候都会调用一次 loadObject 方法

  • NoOp(由NoOpGenerator生成):声明一个单单例对象,该代理不对被代理类执行任何操作

再来看看上面 Enhancer.create 的一个简化的时序图:



filterConstructors:默认会filter所有private的Constructor

getMethods:会获取被代理类的所有方法并且过虑掉static、private跟final的方法

emitMethods:生成所有被代理类的方法,生成的方法里会调用Callback定义的行为

emitConstructors:生成代理类的构造方法

JDK Proxy vs CGLIB Proxy



  • JDK动态代理只能对实现了接口的类生成代理,不能针对类;而CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法

  • JDK使用了反射;CGLIB底层采用ASM字节码生成框架生成代理类

核心注解

@AliasFor:提供注解属性别名

@Order:1. 定义AspectJ Advice的执行顺序;2. 定义注入集合的元素的顺序。Spring 4.1后可以用@Priority代替

@NonNull:不允许为空

@NonNullApi:表示方法参数和返回值不为null

@NonNullFields:表示Field不为null

@Nullable:允许为空

Spring Beans

Spring Core源码结构如下:

spring-beans-5.2.6.RELEASE
+ META-INF
- org.springframework.beans
+ annotation
- factory
+ annotation
- config
BeanDefinition.java
+ groovy
+ parsing
+ serviceloader
- support
AbstractBeanFactory.java
...
+ wiring
+ xml
BeanFactory.java
...
+ propertyeditors
+ support
BeanInfoFactory.java
BeanWrapper.java
BeanWrapperImpl.java
BeanUtils.java
...


factory:JavaBean容器相关的实现代码

  • annotation:基于注解配置相关的类

  • config:JavaBean配置相关的类

  • parsing:JavaBean定义解析的基础类

  • serviceloader:Service Loader相关功能

  • support:Bean Factory的默认实现

  • BeanFactory :JavaBean容器,用来实例化、配置并管理Beans

propertyeditors:将string类型数据转为其它类型数据,例如 ClassEditor 传入Class Name可以返回一个 Class 对象

support:Spring Beans项目的支持包,主要有排序Beans等功能

BeanInfoFactory :生成BeanInfo的工厂类

BeanWrapper :提供分析跟操作JavaBeans的接口

BeanWrapperImplBeanWrapper 的实现

BeanUtils :JavaBean的静态工具类,用来实例化Bean、检查Bean属性跟复制Bean属性等

BeanDefinition :Bean的定义

Spring Beans几个核心类之间的关系:



Bean的作用域

Spring Bean的作用域一共有五类:

  • Singleton:在Spring Container中只有一个实例

  • Prototype:每次调用都会得到一个新的实例

  • Request:一个HTTP请求

  • Session:跟HTTP Session生命周期一样

  • Global Session:在一个全局的HTTP Session中

*Aware Interfaces:

实现*Aware相关接口能够感知到Spring容器所提供的资源自身的一些属性。主要有

  • BeanNameAware:获取在容器中Bean的名字

  • ApplicationContextAware:获取当前的ApplicationContext

  • BeanFactoryAware:获取当前的BeanFactory

  • ResourceLoaderAware:获取ResourceLoader

Bean的生命周期

BeanFactory会加载Bean的定义,然后用这个定义去配置跟创建Bean。Bean的生命周期主要分为初始化跟销毁阶段,在初始化阶段,下面的方法会被依次调用:

  • BeanNameAware.setBeanName

  • BeanClassLoaderAware.setBeanClassLoader

  • BeanFactoryAware.setBeanFactory

  • EnviromentAware.setEnviroment

  • EmbeddedValueResolverAware.setEmbeddedValueResolver

  • ResourceLoaderAware.setResourceLoader

  • ApplicationEventPublishAware.setApplicationEventPublisher

  • MessageSourceAware.setMessageSource

  • ApplicationContextAware.setApplicationContext

  • ServletContextAware.setServletContext

  • BeanPostProcessors.postProcessBeforeInitialization

  • InitializingBean.afterPropertiesSet

  • BeanPostProcessors.postProcessAfterInitialization

在销毁阶段,以下方法会被依次调用:

  • DestructionAwareBeanPostProcessors.postProcessBeforeDestruction

  • DisposableBean.destroy

  • 自定义的销毁方法

配置Bean的主要方式:

  • 基于XML配置

  • 基于注解配置

  • 基于Java类配置

注入Bean的方式:

  • 基于XML注入:ref属性、factory-method属性

  • 基于注解注入:@Autowired属性类构造函数setter接口

Bean Id vs Bean Name

在容器中,Bean Id跟Bean Name都能唯一地标识Bean

  • Bean只能有一个Id,但可以有多个Name

  • 我们可以不设置Id跟Name,这里Spring会使用类的全限定名来设置Id

  • 可以设置多个Name,此时如果不设置Id,那么会使用第一个用作标识符

核心注解

@Autowired:依赖注入,该注解能用在属性、Setters跟构造函数上,默认是单例;默认按类型来装配,当有多个匹配的时候会按属性名字来装配;可以用在属性,构造函数跟方法上

@Lookup:方法注入,Spring会生成一个代理对象,每次都能拿到一个新的Bean实例;即是Prototype作用域

@Configurable:说明该类有Bean的定义(@Bean)

@Qualifier:用来提示跟限制需要注入的Bean

@Value:配置属性默认值,可以支持从配置文件读取

Spring Context

Spring Context源码结构如下:

spring-context-5.2.6.RELEASE
+ META-INF
- org.springframework
+ cache
- context
+ annotation
+ config
+ event
+ expression
+ index
+ support
+ weaving
ApplicationContext.java
ApplicationContextAware.java
ApplicationEvent.java
ApplicationListener.java
ConfigurableApplicationContext.java
Lifecycle.java
LifecycleProcessor.java
...
+ instrument.classloading
+ scheduling
+ scripting
+ stereotype
+ validation
...


cache:通用缓存抽象,基于Spring AOP

context:Spring Context核心代码

annotation:Spring Context相关的一些注解

config:Spring Context相关配置

event:Spring Context相关事件

expression:解析expression

support:Spring Context核心实现

weaving:加载时织入

ApplicationContext:配置应用的核心接口,应用在运行时是只读的

ApplicationContextAware:实现 ApplicationContextAware 的对象可以获得 ApplicationContext 实例

ApplicationEvent:应用事件

ApplicationListener:应用事件监听器

ConfigurableApplicationContext:提供设置上下文ID,添加监听器,刷新容器等接口

Lifecycle:定义start/stop等生命周期接口

instrument.classloading:基于ClassLoader提供运行时织入的功能

scheduling:通用任务调度抽象

stereotype:标记分层系统的注解

validation:提供数据绑定跟校验相关功能

Spring Context几个核心类之间的关系:

Spring Context vs Spring BeanFactory

Spring Context继承自BeanFactory,但创建Bean只是Spring Context的其中一部分功能。Spring Context是整个Spring容器的核心,主要有以下功能:

  • 创建、销毁Bean

  • 加载资源文件

  • 发布应用程序事件

  • 解析消息,支持i18n等

获取Bean Definition的方式

  • 通过 @ComponentScan 指定Bean Definition的包路径

  • 通过 @Import 导入Bean Definition

  • 直接通过 Beanfactory.registerBeanDefinition 注册Bean Definition

  • 直接调用 AnnotationConfigRegistry.scan注册Bean Definition

Spring AOP vs AspectJ AOP

先看一下AOP的几个核心概念:

  • Aspect:切面,横跨多个类的关注点的模块化

  • Join Point:连接点,程序运行中的一个点;例如方法执行前或者处理异常

  • Advice:通知,切面在连接点处执行的动作

  • Pointcut:切入点,匹配连接点的断言

  • Introduction:引入,为类声明额外的方法和字段

  • Weaving:织入,将切面与目标类联系在一起从而创建目标对象



Spring AOP跟AspectJ AOP的不同之处有:

  • AspectJ AOP支持编译时、加载时跟运行时织入;Spring AOP只支持运行时织入

  • AspectJ AOP支持的Join Point比Spring AOP多得多;Spring AOP只支持方法执行Join Point,而AspectJ还有方法调用、对象初始化、赋值等等Join Point

核心注解

@Bean :标记该方法会生成一个由Spring容器管理的Bean,需要跟 @Configuration 一起使用,Spring会使用CGLIB代理该方法。

@ComponentScan :标记哪个包需要被Spring扫描并且装载入Bean容器

@ComponentScans:可以指定多个 @ComponentScan

@Conditional:只有在满足条件的情况下才装载该Bean

@Configuration:表明该类是Spring的配置类,会有多个 @Bean

@DependsOn:表明该Bean依赖于另外一个Bean,需要依赖的Bean先实例化

@Description:对Bean的描述,类似于注释

@EnableAspectJAutoProxy:启用AspectJ,支持AOP功能

@EnableLoadTimeWeaving:启用加载时织入(Load Time Weaving)

@Import:手动导入Bean到Spring容器,或者根据Bean配置导入Bean到Spring容器中

@ImportResource:导入Bean配置到Spring容器中

@Lazy:懒惰初始化Bean实例

@Primary:当有多个Bean满足注入条件时,标记该注解的会优先注入

@Profile:标记的Profile被激活时才会将Profile中对应的Bean加载到Spring容器中

@PropertySource:加载指定的属性配置文件

@PropertySources:加载多个 @PropertySource

@Scope:Bean的作用域,基本的作用域有:Singleton、Prototype

Caceh相关注解

@EnableCaching:开启注解配置缓存的功能

@Cacheable:缓存函数调用的结果,下次调用会从缓存获取

@CacheConfig:缓存配置

@CachePut:只缓存函数的结果,下次调用还是会重新执行函数

@CacheEvit:删除缓存

@Caching:定义多个@CacheEvit或者@CachePut

Scheduling相关注解

@EnableScheduling:开启任务调度的功能

@EnableAsync:开启异步任务调度的功能

@Scheduled:被注解的函数将会被Spring Scheduling调度执行,支持 cronfixedDelayfixedRate

@Schedules:定义多个@Scheduled

@Async:被注解的函数将会被异步执行

stereotype相关注解

@Component:泛指各种组件,通过配置component-scan类会自动注册到Spring容器

@Controller:Web Controller

@Repository:在DDD中定义的Repository

@Service:在DDD中定义的Service

@Bean vs @Component

Spring Boot

Spring Boot源码结构如下:

spring-boot-project
+ spring-boot
+ spring-boot-actuator
+ spring-boot-actuator-autoconfigure
+ spring-boot-autoconfigure
+ spring-boot-cli
+ spring-boot-dependencies
+ spring-boot-devtools
+ spring-boot-docs
+ spring-boot-parent
+ spring-boot-starters
+ spring-boot-test
+ spring-boot-test-autoconfigure
+ spring-boot-tools


spring-boot:Spring Boot 核心类

spring-boot-actuator:监控跟管理Spring应用

spring-boot-actuator-autoconfigure:自动配置Spring Actuator

spring-boot-autoconfigure:Spring Boot自动配置相关功能

spring-boot-cli:Spring Boot命令行工具(Command Line Interface)

spring-boot-dependencies:Spring Boot相关依赖

spring-boot-devtools:Spring Boot开发者工具

spring-boot-parent:Spring Boot的父项目

spring-boot-starters:包含一些常用的Starter

spring-boot-test:Spring Boot测试相关功能

spring-boot-test-autoconfigure:自动配置Spring Boot Test

spring-boot-tools:Spring Boot相关工具

常见Spring Boot问题

Spring Boot的优点

  • 能够创建独立的Spring应用程序

  • 能够方便地嵌入Tomcat、Jetty等,无须部署WAR文件

  • 配置Starter能够方便地集成需要的框架

  • 尽可能自动配置Spring

  • 提供生产就绪功能,如指标、健康检查和外部配置

Spring Boot 的自动装配原理是什么

Spring Boot自动装配是通过 @Configuration@Conditional 注解来工作的,即只有在满足条件时才创建并装载Bean到Spring Context。

如何自定义Spring Boot Starter

Spring Boot Starter是一个写好自动装配逻辑的JAR依赖,我们只要引用这个Starter,那么程序运行时需要的依赖库、配置属性等就会自动装配到我们的运行环境。Spring Boot在启动时会检查JAR包中是否存在META-INF/spring.factories文件,如果存在则会进一步读取其中的 EnableAutoConfiguration 配置项,该配置项包包含了JAR包中的自动装配类。

官方全名规范:spring-boot-starter-${module}

自定义全名规范:${module}-spring-boot-starter

自定义Spring Boot Starter步骤如下:

  1. 创建项目,添加spring-boot-autoconfigure依赖

  2. 定义Service服务类

  3. 定义配置类( @ConfigurationProperties ),用于封装 application.properties或application.y配置

  4. 创建自动化配置类,定义好加载条件( @Conditional

  5. 添加spring.factories

Spring Boot的启动流程

SpringApplication初始化:

  1. 推断应用的类型: REACTIVESERVLET 或者 NONE

  2. META-INF/spring.factories 加载 ApplicationContextInitializer

  3. META-INF/spring.factories 加载 ApplicationListener

  4. 推断并创建 main 方法所属的类

SpringApplication.run:

  1. META-INF/spring.factories 加载 SpringApplicationRunListener

  2. 创建并配置 Environment

  3. 根据推断的应用类型创建 SpringContext

  4. META-INF/spring.factories 加载 SpringBootExceptionReporter

  5. 准备 SpringContext,创建 BeanDefinitionLoader,加载Bean定义

  6. 刷新 SpringContext 创建Bean并装载入Spring容器

  7. 假如Spring容器里有 ApplicationRunner 或者 CommandLineRunner,那么就执行它们

SpringContext vs SpringApplication

SpringApplication是Spring Boot驱动Spring应用上下文的引导类,实质上是为Spring应用创建并初始化Spring上下文

核心注解

@SpringBootConfuguration:是 @Configuration的派生注解,作用与 @Configuration一样

@AutoConfigurationPackage:将添加该注解的类所在的Package及子Package下的所有组件扫描加载到Spring容器中去

@EnableAutoConfiguration:开启自动配置的功能,继承自 @AutoConfigurationPackage;将 META-INF/spring.factories里面配置的所有 EnableAutoConfiguration 的值加到容器里(必须满足一定的条件都会加载到容器里)

@SpringBootApplication:继承了 @SpringBootConfiguration@EnableAutoConfiguration@ComponentScan

@AutoConfigureAfter:在加载指定的类之后再加载当前类

@AutoConfigureBefore:在加载指定的类之前要先加载当前类

@AutoConfigureOrder:指定加载的顺序

@ImportAutoConfiguration:继承了 @Import,用于导入自动配置类

@ConditionalOnBean:Spring容器中存在该类型Bean时生效

@ConditionalOnClass:Classpath中存在该类时生效

@ConditionalOnExpression:满足该表达式时生效

@ConditionalOnJava:指定的Java版本存在时生效

@ConditionalOnJndi:指定的JNDI存在时生效

@ConditionalOnMissingBean:Spring容器中不存在该类型Bean时生效

@ConditionalOnMissingClass:Classpath中不存在该类时生效

@ConditionalOnNotWebApplication:不是Web应用环境下生效

@ConditionalOnProperty:设置该参数时生效

@ConditionalOnResource:指定的文件存在时生效

@ConditionalSingleCandidate:Spring容器中该类型Bean只有一个或@Primary的只有一个时生效

@ConditionalOnWarDeployment:使用WAR部署时生效

@ConditionalOnWebApplication:Web应用环境下生效

@ConfigurationProperties:Spring Boot外部配置,可以让使用者设置 .properties文件配置信息

Spring Actuate Endpoint

@Endpoint:构建HTTP REST API的请求路径

@ReadEndpoint:GET请求

@WriteOperator:POST请求

@DeleteOperator:DELETE请求

Spring Boot Test

@SpringBootTest:用来做集成测试,会启动一个内置服务并会初始化一个SpringContext

@LocalServerPort:通过 @SpringBootTest 可以随机监听一个端口,该注解可以将随机监听的端口注入进来

@WebMvcTest:用来测试Spring MVC

@WebFluxTest:用来测试WebFlux

@JdbcTest:用来测试JDBC

@DataRedisTest:用来测试Redis应用

@TestConfiguration:继承自 @Configuration ,用来配置Test相关的Bean

@TestComponent:继承自 @Component,用来配置Test相关的Bean

@MockBean:Mock一个Bean用来测试

@MockBeans:Mock多个Bean用来测试

@SpyBean:Spy一个Bean用来测试;

@SpyBeans:Spy多个Bean用来测试

Spring Reactive

Spring Reactive基于Project Reactor,首先来看看Project Reactor的主要特性。

Reactor实现了Reactive编程范式,Reactive是异步非阻塞编程,有以下特点:

  • 响应式的(Responsive)

  • 适应性强的(Resilient)

  • 弹性的(Elastic)

  • 消息驱动的(Message Driven)

响应式编程是一种关注于数据流(Data Streams)和变化传递(Propagation of Changes)的异步编程范式。在传统的编程范式中,一般通过迭代器(Iterator)模式来遍历并处理数据,采用的是拉的方式;而响应式编程采用的是发布者-订阅者模式,即推的方式。但在推送模式中,如果产生数据的速度过快,会使消息订阅者的处理速度无法跟上生产速度,因此,又引入了Backpressure的功能。所以实际上是一种推拉结合的模式。同时,Flux跟Mono还提供了 mapfilterflatMapzipreduce等函数式编程API

Mono:表示有0个或者1个元素

Flux:表示有0~N个元素

Reactive vs Callbacks vs Futures

  • Callbacks(回调)会导致”回调地狱“,让代码变得难以理解和维护

  • Futures对多个处理的组合不是很友善

  • Reactive就完美地解决了“回调地狱”跟多个处理的组合问题

如下图所求,在Spring中,有Reactive Stack跟Servlet Stack。



Reactive Stack示例:

@RequestMapping("/webflux")
@RestController
public class WebFluxTestController {
@GetMapping("/mono")
public Mono<Foobar> foobar() {
return Mono.just(new Foobar());
}
}


参考

Overview of Spring Framework

Spring源码剖析5:JDK和cglib动态代理原理详解

CGLib: The Missing Manual

Create Proxies Dynamically Using CGLIB Library

Creating a Proxy Object Using cglib

Spring Boot Redis: Ultimate Guide to Redis Cache with Spring Boot 2

Spring AOP in Spring Certification

Spring Core Technologies

Building a Reactive RESTful Web Service

Reactor Reference

The Reactive Manifesto



发布于: 2020 年 07 月 07 日 阅读数: 139
用户头像

Chank

关注

还未添加个人签名 2019.02.06 加入

邮箱:fangliquan@qq.com

评论

发布
暂无评论
Spring核心原理解析