3. Functional style GenericApplicationContext
- 5.1 introduction to spring Webflux
- 5.2, responsive programming
- 5.3. Webflux execution process and core API
- 5.4, annotation based programming model
- 5.5, based on functional programming model
Integrated logging framework
- The code of the whole spring 5 framework is based on Java 8, and the runtime is compatible with JDK9. Many classes and methods that are not recommended are deleted from the code base
- Spring 5.0 framework comes with a general log encapsulation
1. Log4jConfigListener has been removed from spring 5. Log4j2 is officially recommended
2. Spring 5 framework integration Log4j2 steps:
(1) Import jar package
(2) Create log4j2.xml configuration file
<?xml version="1.0" encoding="UTF-8"?> <!--Log level and prioritization: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <!--Configuration hinder status Used to set log4j2 The internal information output can not be set, When set to trace When, you can see log4j2 Various internal detailed outputs--> <configuration status="INFO"> <!--Define all first appender--> <appenders> <!--Output log information to console--> <console name="Console" target="SYSTEM_OUT"> <!--Controls the format of log output--> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </console> </appenders> <!--Then define logger,Only definition logger And introduced appender,appender Will take effect--> <!--root: Used to specify the root log of the project, if not specified separately Logger,Will be used root As Default log output--> <loggers> <root level="info"> <appender-ref ref="Console"/> </root> </loggers> </configuration>
(3) Create test class
public class UserLog { private static final Logger log = LoggerFactory.getLogger(User.class); public static void main(String[] args) { log.info("info log4j"); log.warn("warn log4j"); } }
@Nullable annotation
- @Nullable annotations can be used on methods, properties and parameters, indicating that the method return can be null, the property value can be null and the parameter value can be null, as shown below:
@Nullable String getId(); @Nullable private String bookName; public <T> void registerBean(@Nullable String beanName, Class<T> beanClass, @Nullable Supplier<T> supplier, BeanDefinitionCustomizer... customizers) { this.reader.registerBean(beanClass, beanName, supplier, customizers); }
Functional style GenericApplicationContext
@Test public void testGenericApplicationContext(){ //1. Create a GenericApplicationContext object GenericApplicationContext context = new GenericApplicationContext(); //2. Call the method object registration of context context.refresh(); context.registerBean("user",User.class, () -> new User()); //3. Get the object registered in spring User user = (User)context.getBean("user"); System.out.println(user); }
Integrate JUnit 5
- Integrate JUnit 4
1. Introduce Spring related to test dependency
2. Create a test class and complete it by annotation
@RunWith(SpringJUnit4ClassRunner.class)//Unit test framework @ContextConfiguration("classpath:user.xml")//Load profile public class TestUser { @Autowired private UserService userService; @Test public void testUser(){ userService.addUser(); }
- Integrate JUnit 5
1. Introduce the jar package of JUnit 5
2. Create test classes and complete / use composite annotations with annotations
@ExtendWith(SpringExtension.class) @ContextConfiguration("classpath:bean1.xml") //@SpringJUnitConfig(locations = "classpath:bean1.xml") / / composite annotation public class TestUser { @Autowired private UserController userService; @Test public void testUser(){ userService.addUser(); } }
SpringWebflux
-
It is a new module added by spring 5 for web development. Its function is similar to that of spring MVC. Webflux uses a current framework that compares process responsive programming.
-
Traditional web frameworks, such as spring MVC, are based on Servlet containers. Webflux is an asynchronous and non blocking framework. The asynchronous and non blocking framework is only supported after Servlet 3.1. The core is implemented based on the relevant API of Reactor.
-
Asynchronous and synchronous are for the caller. If the caller sends a request and waits for the other party's response before doing other things, it is synchronous. If the caller does other things without waiting for the other party's response after sending a request, it is asynchronous
-
Blocking and non blocking are aimed at the callee. After receiving the request, the callee gives feedback only after completing the request task, which is blocking. After receiving the request, the callee gives feedback immediately and then does something is non blocking
-
Webflux features:
(1) Non blocking: under limited resources, improve system throughput and scalability, and realize responsive programming based on Reactor
(2) Functional programming: the spring 5 framework is based on Java 8, and Webflux uses Java 8 functional programming to route requests
-
What is responsive programming?
Responsive programming is a programming paradigm for data flow and change propagation. This means that static or dynamic data streams can be easily expressed in the programming language, and the relevant calculation model will automatically propagate the changed values through the data stream. A spreadsheet program is an example of responsive programming. Cells can contain literal values or formulas like "= B1+C1", and the values of cells containing formulas will change according to the values of other cells.
-
The Observer pattern provided by Java 8 and earlier versions includes two classes: Observer and Observable
public class ObserverDemo extends Observable { public static void main(String[] args) { ObserverDemo observer = new ObserverDemo(); observer.addObserver((o ,arg) ->{ System.out.println("undergo changes"); }); observer.addObserver((o, org) ->{ System.out.println("Manually notified by the observer, ready to change"); }); observer.setChanged();//Data change observer.notifyObservers();//notice } }
-
Reactor implementation
(1) In Reactive programming operations, Reactor is a framework that meets the Reactive specification
(2) Reactor has two core classes, mono and Flux. These two classes implement the interface Publisher and provide rich operators. The Flux object implements the Publisher and returns N elements; Mono implements the Publisher and returns 0 or 1 elements
(3) Both Flux and Mono are publishers of data streams. Using Flux and Mono, three data signals can be sent: element value, error signal and completion signal. Both error signal and completion signal represent termination signals. Termination signals are used to tell subscribers that the data stream is over. Error signals terminate the data stream and pass error information to subscribers
(4) Code demonstration Flux and Mono
/* Introduce dependency <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-core</artifactId> <version>3.1.5.RELEASE</version> </dependency> */ public static void main(String[] args) { //just method direct declaration Flux.just(1,2,3,4); Mono.just(1); //Other methods Integer[] array = {1,2,3,4}; Flux.fromArray(array); List<Integer> list = Arrays.asList(array); Flux.fromIterable(list); Stream<Integer> stream = list.stream(); Flux.fromStream(stream); }
(5) Three signal characteristics:
- Both error signal and completion signal are termination signals and cannot coexist
- If no element value is sent, but an error or completion signal is sent directly, it indicates an empty data stream
- If there is no error signal and no completion signal, it indicates an infinite data stream
(6) Calling just or other methods only declares the data flow. The data flow is not issued. The data flow will be triggered only after subscription. Nothing will happen without subscription
Flux.just(1,2,3,4).subscribe(System.out::print); Mono.just(1).subscribe(System.out::print);
(7) Operator
- The data stream is operated one after another to become an operator, such as a factory pipeline
- map element to new element
- flatMap elements are mapped into streams, each element is converted into a stream, and multiple streams after conversion are merged into a large stream
- Spring Webflux is based on Reactor. The default container is netty. Netty is a high-performance NIO framework and an asynchronous non blocking framework
(1)Netty
- BIO
- NIO
(2) The execution process of spring Webflux is similar to that of spring MVC
- The spring Webflux core controller DispatchHandler implements the interface WebHandler
- Interface WebHandler has a method handle
(3) DispatcherHandler in spring Webflux is responsible for processing requests
- HandlerMapping: the processing method of the request query
- HandlerAdapter: really responsible for request processing
- HandlerResultHandler: response result processing
(4) Spring Webflux implements functional programming with two interfaces: RouterFunction and handler function
-
Spring Webflux can be implemented in two ways: annotated programming model and functional programming model
-
Using the annotation programming model is similar to the previous spring MVC. You only need to configure the relevant dependencies into the project. SpringBoot automatically configures the relevant running containers. By default, the Netty server is used
-
The code is as follows:
(1) Create a springboot project, introduce WebFlux, and rely on spring boot starter weblux
(2) Configure startup port number: server.port = 8088
(3) Create packages and related classes
//Entity class public class User { private String name; private String gender; private Integer age; } //User operation interface public interface UserService { //Query user by id Mono<User> getUserById(int id); //Query all users Flux<User> getAllUser(); //Add user Mono<Void> saveUserInfo(Mono<User> user); } //Interface implementation class @Repository public class UserServiceImpl implements UserService { //Create a map collection to store data private final Map<Integer,User> users = new HashMap<>(); public UserServiceImpl() { this.users.put(1,new User("Tommey","nan",20)); this.users.put(2,new User("Hat","nv",30)); this.users.put(3,new User("Mary","nv",18)); } @Override public Mono<User> getUserById(int id) { return Mono.justOrEmpty(this.users.get(id)); } @Override public Flux<User> getAllUser() { return Flux.fromIterable(this.users.values()); } @Override public Mono<Void> saveUserInfo(Mono<User> userMono) { return userMono.doOnNext(person -> { //Put values into the map set int id = users.size()+1; users.put(id,person); }).thenEmpty(Mono.empty()); } @RestController public class controller { //Inject service @Autowired private UserService userService; //id query @GetMapping("/user/{id}") public Mono<User> geetUserId(@PathVariable int id) { return userService.getUserById(id); } //Query all @GetMapping("/user") public Flux<User> getUsers() { return userService.getAllUser(); } //add to @PostMapping("/saveuser") public Mono<Void> saveUser(@RequestBody User user) { Mono<User> userMono = Mono.just(user); return userService.saveUserInfo(userMono); } }
-
explain:
Spring MVC is implemented in the way of synchronous blocking, which is based on spring MVC + servlet + Tomcat
Implemented in spring Webflux, asynchronous and non blocking mode, based on spring Webflux + reactor + netty
(1) When operating with the functional programming model, you need to initialize the server yourself
(2) Based on the functional programming model, there are two core interfaces: RouterFunction (to realize the routing function and forward the request to the corresponding handler) and HandlerFunction (to process the request and generate the response). The core task defines the implementation of two functional interfaces and starts the required server.
(3) Spring Webflux requests and responses are no longer ServletRequest and ServletResponse, but ServerRequest and ServerResponse
- Code examples are as follows:
//Create Handler (specific implementation method) public class UserHandler { private final UserService userService; public UserHandler(UserService userService){ this.userService = userService; } //Query by id public Mono<ServerResponse> getUserById(ServerRequest request){ //Get id value int userId = Integer.valueOf(request.pathVariable("id")); //Null value processing Mono<ServerResponse> notFound = ServerResponse.notFound().build(); //Call the service method to get the data Mono<User> userMono = this.userService.getUserById(userId); //Convert userMono to return, and use the Reactor operator FlatMap return userMono.flatMap(person -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON) .body(fromObject(person))) .switchIfEmpty(notFound); } //Query all public Mono<ServerResponse> getAllUsers(ServerRequest request) { //Call the service to get the result Flux<User> users = this.userService.getAllUser(); return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(users,User.class); } //add to public Mono<ServerResponse> saveUser(ServerRequest request) { //Get user object Mono<User> userMono = request.bodyToMono(User.class); return ServerResponse.ok().build(this.userService.saveUserInfo(userMono)); } } //Initialize the server and write the Router public class Server { //Create Router route public RouterFunction<ServerResponse> routerFunction(){ //Create handler object UserService userService = new UserServiceImpl(); UserHandler handler = new UserHandler(userService); //Set route return RouterFunctions.route( GET("/users/{id}").and(accept(APPLICATION_JSON)), handler::getUserById) .andRoute(GET("/users").and(accept(APPLICATION_JSON)), handler::getAllUsers); } //Create server complete adaptation public void createReactorServer(){ //Routing and handler adaptation RouterFunction<ServerResponse> route = routerFunction(); HttpHandler httpHandler = toHttpHandler(route); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); //Create server HttpServer httpServer = HttpServer.create(); httpServer.handle(adapter).bindNow(); } public static void main(String[] args) { Server server = new Server(); server.createReactorServer(); System.out.println("enter to exit"); try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } } } //Using WebClient call public class Client { public static void main(String[] args) { //Call server address WebClient webClient = WebClient.create("http://127.0.0.1:63739"); //Query by id String id = "1"; User user = webClient.get().uri("/users/{id}", id).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class).block(); System.out.println(user); //Query all Flux<User> results = webClient.get().uri("/users").accept(MediaType.APPLICATION_JSON).retrieve().bodyToFlux(User.class); results.map(stu -> stu.getName()).buffer().doOnNext(System.out::println).blockFirst(); } }