Java spring 5 new features functional web framework detailed introduction

New features of Java spring 5 functional web framework

give an example

Let's start with some excerpts from the sample application. The following is the response information base that exposes the person object. It is very similar to the traditional non response information base, except that it returns flux < person > and the traditional return list < person >, and returns person where mono < person > is returned. Mono < void > is used as completion ID: indicates when saving is completed.

Here's how we expose the repository with the new functional web framework:

Next, we will introduce how to run, for example, in reactor netty:

The last thing to do is try:

There are more introductions below, let's dig deeper!

Core components

I will introduce the framework by thoroughly explaining the core components: handlerfunction, routerfunction, and filterfunction. These three interfaces, as well as all other types described in this article, can be found at org springframework. web. reactive. Found in function package.

HandlerFunction

The starting point of this new framework is handlerfunction < T >, basically function < request, response < T > >, in which request and response are newly defined and invariable. The interface is friendly to provide jdk-8 DSL to the bottom HTTP message. It is a convenient build tool for building response entities, which is very similar to that seen in responseentity. The annotation corresponding to handlerfunction is a method with @ requestmapping.

The following is an example of a simple "Hello world" processing function, which returns a response message with 200 status and a body of string:

As we can see in the above example, the handler functions respond completely by building on reactor: they accept flux, mono, or any other corresponding stream publisher as the response type.

It should be noted that the handlerfunction itself has no side effects because it returns a response instead of treating it as a parameter (see servlet. Service (ServletRequest, servletresponse), which is essentially biconsumer < ServletRequest, servletresponse >). There are many advantages without side effects: easy to test, write and optimize.

RouterFunction

The incoming request is routed to the handler with routerfunction < T > (i.e. function < request, optional < handlerfunction < T > >) route to the processing function, if it matches; otherwise, an empty result will be returned. The routing method is similar to the @ requestmapping annotation. However, there is another significant difference: when annotation is used, the routing will be limited to the range that the annotation value can express, so it is difficult to handle the coverage of these methods; when When using the routing method, the code is there and can be easily overwritten or replaced.

The following is an example of a routing function with an embedded processing function. It looks a little verbose, but don't worry: we'll find a way to make it shorter.

Generally, you do not need to write a complete routing method, but statically introduce routerfunctions Route(), so that the routing method can be created with the request predicate (i.e. predicate < request >) and the handler function. If the judgement is successful, the processing method will be returned, otherwise the null result will be returned. The following is an example of rewriting the above with the route method:

You can (statically) import requestpredictions. * to access commonly used predicates, matching based on path, HTTP method, content type, etc. with it, we can make helloworloute simpler:

Combinatorial function

Two routing functions can form a new routing function and route to any processing function: if the first function does not match, the second function will be executed. You can call routerfunction And(), combine two routing functions like this:

If the path matches / Hello world, the above will respond with "Hello world". If the path matches / the answer, it will also return "42". If both do not match, an empty optional is returned. Note that the combined routing functions execute in turn, so it makes sense to put generic functions before specific functions.

You can also combine the required predicates by calling and or. It works like this: for and, if two given predicates match, the result predicate matches, and if one of the two predicates matches, or matches. For example:

In fact, most of the predicates found in requestpredictions are composed! For example, requestpredictions Get (string) is requestpredictions Method (httpmethod) and requestpredictions Path (string). Therefore, we can rewrite the above code as:

Method reference

By the way: so far, we have written all the handler functions as inline lambda expressions. Although this works well in demonstrations and short examples, it has to be said that there is a tendency to lead to "confusion" because you have to mix two concerns: Request Routing and request processing. So let's see if we can make things simpler. First, we create a class containing processing code:

Note that both methods have a flag that is compatible with the handler. This allows us to use method references:

FilterFunction

The path mapped by the routing function can be mapped by calling routerfunction Filter (filterfunction < T, R >), where filterfunction < T, R > is essentially bifunction < request, handlerfunction < T >, response < R > >. The handler parameter of the function represents the next item in the whole chain: This is a typical handlerfunction, but if multiple filters are attached, it can also be another filterfunction. Let's add a log filter to the route:

Note that it is optional whether or not to call the next handler. This is useful in security and caching scenarios (such as calling next only when the user has sufficient permissions).

Since route is an infinite routing function, we know what type of response information the next handler will return. That's why we ended up using response End and the reason for responding to body with object. In the handler class, both methods return response < string >, so it should be possible to have a string response body. We can use routerfunction Andsame() instead of and(). This combination method requires that the parameter routing function be of the same type. For example, we can make all responses capitalized:

Using annotations, similar functions can be implemented with @ controlleradvice and / or servletFilter.

Running server

All this is good, but one thing I forgot: how can we run these functions in an actual HTTP server? The answer is undoubtedly by calling another function. You can use routerfunctions Tohttphandler() converts the routing function to HttpHandler. HttpHandler is a response abstraction introduced into spring 5.0 M1: it allows you to run on a variety of response runtimes: reactor netty, rxnetty, servlet 3.1 +, and undertow. In this example, we have shown how to run route in reactor netty. For tomcat, it looks like this:

It is important to note that the above code does not depend on the spring application context. Like the jdbctemplate and other spring utility classes, using the application context is optional: you can connect handlers and routing functions in the context, but it is not necessary.

Also note that you can also convert the routing function to handlermapping so that it can run in dispatcherhandler (you may need responsive @ controllers).

conclusion

Let me conclude with a brief summary:

In order to give you a more comprehensive understanding, I have created a simple example project using functional web framework. Download address

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>