One, foreword
This article mainly introduces how to quickly use SpringFlux framework to develop WEB sites based on SpringBoot.
In addition to Spring MVC Stack (Servlet Stack), Spring Flux Stack (Reactive Stack) is introduced in Spring 5.0. To meet the needs of different applications and development teams.
Developers are always looking for runtimes, programming frameworks, and architectures that best fit their applications. For example, some use cases are best suited to a stack based on a synchronous blocking IO architecture, while others may be better suited to an asynchronous, non-blocking stack based on Reactive Streams responsive programming principles.
There will be a series of in-depth articles on SpringFlux’s responsive programming principles and their representative implementation of ProjectReactor. It is hoped that through this series of articles, readers can gradually understand the principles and implementation of responsive programming in the process of using SpringFlux. Thus, the project can form its own judgment criteria for choosing SpringMVC or SpringWebFlux.
Second, get started quickly
1. Create a project
Start start.spring. IO to initialize a Spring WebFlux project. The left column is Project Metadata, with your group name (let’s use Net.yesData) and Artifact name (demo by default); The next column is Dependencies. We type in “Reactive Web” and select “Reacive Web” from the drop-down box. The “Selected Dependencies” below will show the “Reactive Web” that we Selected. Then click “Generate Project” and the browser will download the created Spring Boot Project. Use your favorite IDE (Eclipse, IntelliJ IDEA, etc.).
2. Add a Controller
If you are familiar with Spring MVC, you are no stranger to the @Controller annotation. It doesn’t matter if you’re not familiar with it. I’ll give you a brief introduction. Spring WebFlux has two characteristics, one is Functional and the other is annotation-based. Functional programming is not a great way to get started, so let’s start with annotations. Similar to the Spring MVC model, the Spring WebFlux model also uses the @Controller annotation, as well as the @RestController annotation.
After opening the project with the IDE, append a class: SampleController and add the following code:
@RestController
@RequestMapping("/")
public class SampleController {
@GetMapping("/hello")
public String hello(){
return "hello";
}
}Copy the code
After the operation, use the browser visit: http://localhost:8080/hello, will see the words “hello” on the browser.
How about that? It’s easy.
3. Add a WebFilter
Try adding a Filter. Under the Spring WebFlux framework, adding a Filter is done by implementing the WebFilter interface.
@Component public class FirstWebFilter implements WebFilter { @Override public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) { serverWebExchange.getAttributes().put("User", "jerry"); return webFilterChain.filter(serverWebExchange); }}Copy the code
3. Learn more about the process of Spring WebFlux startup by SpringBoot
For developers who are already familiar with the Spring MVC framework, getting started quickly isn’t enough. We must understand the mechanism and principles behind it to have a sense of knowing ourselves and the enemy. Let’s take a look at SpringBoot to start Spring WebFlux. Developers who are not familiar with the Spring MVC framework may want to take a look at this chapter for better use of the Spring WebFlux framework.
1. Preparation
You’ll need to go to Gitubgithub.com/spring-proj… Download the source code for Spring WebFlux for subsequent analysis.
2, @ EnableWebFlux
Recall that in creating a project with start.spring. IO, one of the annotations to the DemoApplication startup class is @enableWebFlux. SpringBoot uses this annotation to start Spring WebFlux.
@EnableWebFlux @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}Copy the code
Look again at EnableWebFlux definition (can be found in SpringWebFlux source code), as follows, we noticed that it introduces DelegatingWebFluxConfiguration class. It seems that the secret hiding DelegatingWebFluxConfiguration class?
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebFluxConfiguration.class)
public @interface EnableWebFlux {
}Copy the code
Open DelegatingWebFluxConfiguration. Java file (can be found in SpringWebFlux source code), then you we find that it is the parent of the WebFluxConfigurationSupport class. Let’s take a look at the parent class first.
@Configuration
public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport {
......
}Copy the code
The following is the parent class WebFluxConfigurationSupport implementation code snippets. We are aware of it to the Spring Bean container, injected two Bean: webHandler and requestMappingHandlerMapping (actually also injected with several other beans, but we only pay attention to the two).
The Bean named “webHandler” is of type DispatcherHandler, which, as the name implies, dispatches requests to individual processing units. The type of the Bean is called “requestMappingHandlerMapping” requestMappingHandlerMapping, its fundamental is to realize the HandlerMapping interface. HandlerMapping is used to map requests to handlers, such as a request path to a Controller.
The DispatcherHandler and HandlerMapping are further covered in the following sections.
public class WebFluxConfigurationSupport implements ApplicationContextAware { @Bean public DispatcherHandler webHandler() { return new DispatcherHandler(); } @Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); mapping.setOrder(0); mapping.setContentTypeResolver(webFluxContentTypeResolver()); mapping.setCorsConfigurations(getCorsConfigurations()); PathMatchConfigurer configurer = getPathMatchConfigurer(); Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch(); if (useTrailingSlashMatch ! = null) { mapping.setUseTrailingSlashMatch(useTrailingSlashMatch); } Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch(); if (useCaseSensitiveMatch ! = null) { mapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch); } Map<String, Predicate<Class<? >>> pathPrefixes = configurer.getPathPrefixes(); if (pathPrefixes ! = null) { mapping.setPathPrefixes(pathPrefixes); } return mapping; }}Copy the code
2, DispatcherHandler
The DispatcherHandler registers itself as a Bean in Spring’s Bean container, which, together with WebFilter, WebExceptionHandler, etc., forms a processing chain.
The DispatcherHandler will find the components it needs from the Spring Configuration, which are in the following three categories:
public class DispatcherHandler implements WebHandler, ApplicationContextAware { ... private List<HandlerMapping> handlerMappings; private List<HandlerAdapter> handlerAdapters; private List<HandlerResultHandler> resultHandlers; . }Copy the code
-
HandlerMapping
- Map Request to Handler
- HandlerMapping default implementation is RequestMappingHandlerMapping for @ RequestMapping the tag method; RouterFunctionMapping is used to route functional endpoints. SimpleUrlHandlerMapping is used to explicitly register URL schema with WebHandler
-
HandlerAdaptor
- Help DispatcherHandler call the Handler mapped by Request
- The main purpose of HandlerAdaptor is to free the DispatcherHandler from the details of calling specific handlers
-
HandlerResultHandler
- Process the result of Handler and terminate the Response
- The return result of calling the specific Handler is wrapped in the HandlerResult, which is handled by the HandlerResultHandler. Such as ResponseBodyResultHandler handle @ ResponseBody marking methods return values
The schematic diagram is as follows:
DispatcherHandler
|
|-->HandlerMapping
|-->HandlerAdaptor
|-->HandlerResultHandlerCopy the code
The core methods of DispatcherHandler are:
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return Mono.error(HANDLER_NOT_FOUND_EXCEPTION);
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION))
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}Copy the code
This method describes how a DispatcherHandler handles requests
- Use HandlerMapping to find the specific Handler for the Request. The code snippet is
concatMap(mapping -> mapping.getHandler(exchange))Copy the code
- This particular Handler is executed through the HandlerAdaptor, and the code snippet is
flatMap(handler -> invokeHandler(exchange, handler))Copy the code
- The result returned by the Handler is processed by the HandlerResultHandler. The code snippet is
flatMap(result -> handleResult(exchange, result))Copy the code
You might be wondering, where is Request in this method? ServerWebExchange Exchange, and other articles about ServerWebExchange.
3, HandlerMapping
The first step in the DispatcherHandler routine is to use HandlerMapping. There are three kinds of common HandlerMapping: RequestMappingHandlerMapping, RouterFunctionMapping, SimpleUrlHandlerMapping
RequestMappingHandlerMapping is the default, whether still remember DispatcherHandler has released a Bean named “RequestMappingHandlerMapping”? It assumes the relationship between the mapping Request and the Annotation-based Handler.
Because we are used to using the @ Controller and @ RestController, @ RequestMapping annotations to develop WEB project, so it is depend on the RequestMappingHandlerMapping. We can talk about RequestMappingHandlerMapping the next.
3-1, the RequestMappingHandlerMapping class hierarchy
1 layer: AbstractHandlerMapping implements HandlerMapping, Ordered, BeanNameAware
^
|Copy the code
Layer 2: AbstractHandlerMethodMapping implements InitializingBean
^
|Copy the code
Three layers: RequestMappingInfoHandlerMapping
^
|Copy the code
Four layers: the RequestMappingHandlerMapping implements EmbeddedValueResolverAware
3-2. Handler is available for scanning
Notice that layer 2 implements the InitializingBean interface, and classes that implement that interface have the opportunity to call the BeanFactory after all of its properties have been set
void afterPropertiesSet()Copy the code
Method to notify it. Let’s look at the layer 2 implementation of this method.
@Override public void afterPropertiesSet() { initHandlerMethods(); // Total includes detected mappings + explicit registrations via registerMapping.. . }Copy the code
For reasons of length, we won’t go into what is called in the method here
initHandlerMethods();Copy the code
In fact, it’s the @requestMapping and its variants that scan all @Controller annotated classes for methods that will eventually process the Request and cache it for further execution.
3-3. Cooperate with DispatcherHandler
MappingHandler is called by DispatcherHandler
Mono<Object> getHandler(ServerWebExchange exchange)Copy the code
Method to select the specific Handler to handle the request.
Four,
The Spring WebFlux model is very simple to use, especially for developers familiar with the Spring MVC model, with seamless switching. When the Spring Boot framework is used, annotations such as @Controller, @restController, and @RequestMapping are used to implement the Request Handler.
Original: www.yesdata.net/2018/11/20/…