1,整合日志框架
2,@Nullable 注解
3,函数式风格 GenericApplicationContext
4,整合 JUnit5
5,Webflux
- 5.1,SpringWebflux 介绍
- 5.2,响应式编程
- 5.3,Webflux执行流程和核心API
- 5.4,基于注解编程模型
- 5.5,基于函数式编程模型
- 整个 Spring5 框架的代码基于 Java8,运行时兼容 JDK9,许多不建议使用的类和方法在代码库中删除
- Spring 5.0 框架自带了通用的日志封装
1,Spring5 已经移除 Log4jConfigListener,官方建议使用 Log4j2
2,Spring5 框架整合 Log4j2步骤:
(1)引入jar包
(2)创建 log4j2.xml 配置文件
(3)创建测试类
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 注解
- @Nullable 注解可以使用在方法上面,属性上面,参数上面,表示方法返回可以为空,属性值可以为空,参数值可以为空,分别如下所示:
@Nullable String getId(); @Nullable private String bookName; public函数式风格 GenericApplicationContextvoid registerBean(@Nullable String beanName, Class beanClass, @Nullable Supplier supplier, BeanDefinitionCustomizer... customizers) { this.reader.registerBean(beanClass, beanName, supplier, customizers); }
@Test public void testGenericApplicationContext(){ //1,创建GenericApplicationContext对象 GenericApplicationContext context = new GenericApplicationContext(); //2,调用context的方法对象注册 context.refresh(); context.registerBean("user",User.class, () -> new User()); //3,获取在spring注册的对象 User user = (User)context.getBean("user"); System.out.println(user); }整合 JUnit5
- 整合 JUnit4
1,引入 Spring 相关针对测试依赖
2, 创建测试类,使用注解方式完成
@RunWith(SpringJUnit4ClassRunner.class)//单元测试框架 @ContextConfiguration("classpath:user.xml")//加载配置文件 public class TestUser { @Autowired private UserService userService; @Test public void testUser(){ userService.addUser(); }
- 整合 JUnit5
1,引入 JUnit5 的 jar 包
2, 创建测试类,使用注解完成 / 使用复合注解
@ExtendWith(SpringExtension.class) @ContextConfiguration("classpath:bean1.xml") //@SpringJUnitConfig(locations = "classpath:bean1.xml") //复合注解 public class TestUser { @Autowired private UserController userService; @Test public void testUser(){ userService.addUser(); } }SpringWebflux 1,SpringWebflux 介绍
-
是 Spring5 添加新的模块,用于 web 开发的,功能和 SpringMVC 类似的,Webflux 使用当前一种比较流程响应式编程出现的框架。
-
使用传统 web 框架,比如 SpringMVC,这些基于 Servlet 容器,Webflux 是一种异步非阻塞的框架,异步非阻塞的框架在 Servlet3.1 以后才支持,核心是基于 Reactor 的相关 API 实现的。
-
异步和同步针对调用者,调用者发送请求,如果等着对方回应之后才去做其他事情就是同步,如果发送请求之后不等着对方回应就去做其他事情就是异步
-
阻塞和非阻塞针对被调用者,被调用者受到请求之后,做完请求任务之后才给出反馈就是阻塞,受到请求之后马上给出反馈然后再去做事情就是非阻塞
-
Webflux 特点:
(1)非阻塞式:在有限资源下,提高系统吞吐量和伸缩性,以 Reactor 为基础实现响应式编程
(2) 函数式编程:Spring5 框架基于 java8,Webflux 使用 Java8 函数式编程方式实现路由请求
-
什么是响应式编程?
响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。
-
Java8 及其之前版本 提供的观察者模式两个类 Observer 和 Observable
public class ObserverDemo extends Observable { public static void main(String[] args) { ObserverDemo observer = new ObserverDemo(); observer.addObserver((o ,arg) ->{ System.out.println("发生变化"); }); observer.addObserver((o, org) ->{ System.out.println("手动被观察者通知,准备改变"); }); observer.setChanged();//数据变化 observer.notifyObservers();//通知 } }
-
Reactor实现
(1)响应式编程 *** 作中,Reactor是满足Reactive规范框架
(2)Reactor有两个核心类,Mono和Flux,这两个类实现接口Publisher,提供丰富 *** 作符。Flux对象实现发布者,返回N个元素;Mono实现发布者,返回0或者1个元素
(3)Flux和Mono都是数据流的发布者,使用 Flux 和 Mono 都可以发出三种数据信号:元素值,错误信号,完成信号,错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了,错误信号终止数据流同时把错误信息传递给订阅者
(4)代码演示 Flux 和 Mono
public static void main(String[] args) { //just方法直接声明 Flux.just(1,2,3,4); Mono.just(1); //其他的方法 Integer[] array = {1,2,3,4}; Flux.fromArray(array); Listlist = Arrays.asList(array); Flux.fromIterable(list); Stream stream = list.stream(); Flux.fromStream(stream); }
(5)三种信号特点:
- 错误信号和完成信号都是终止信号,不能共存的
- 如果没有发送任何元素值,而是直接发送错误或者完成信号,表示是空数据流
- 如果没有错误信号,没有完成信号,表示是无限数据流
(6)调用 just 或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触发数据流,不订阅什么都不会发生的
Flux.just(1,2,3,4).subscribe(System.out::print); Mono.just(1).subscribe(System.out::print);
(7) *** 作符
- 对数据流进行一道道 *** 作,成为 *** 作符,比如工厂流水线
- map 元素映射为新元素
- flatMap 元素映射为流,把每个元素转换流,把转换之后多个流合并大的流
- SpringWebflux基于Reactor,默认使用容器是Netty,Netty是高性能的NIO框架,异步非阻塞的框架
(1)Netty
- BIO
- NIO
(2)SpringWebflux 执行过程和 SpringMVC 相似的
- SpringWebflux 核心控制器 DispatchHandler,实现接口 WebHandler
- 接口 WebHandler 有一个方法handle
(3)SpringWebflux 里面 DispatcherHandler,负责请求的处理
- HandlerMapping:请求查询到处理的方法
- HandlerAdapter:真正负责请求处理
- HandlerResultHandler:响应结果处理
(4)SpringWebflux 实现函数式编程,两个接口:RouterFunction(路由处理)和 HandlerFunction(处理函数)
4,基于注解编程模型-
SpringWebflux 实现方式有两种:注解编程模型和函数式编程模型
-
使用注解编程模型方式,和之前 SpringMVC 使用相似的,只需要把相关依赖配置到项目中,SpringBoot 自动配置相关运行容器,默认情况下使用 Netty 服务器
-
代码如下:
(1)创建springboot工程,引入WebFlux依赖 spring-boot-starter-webflux
(2)配置启动端口号:server.port = 8088
(3)创建包和相关类
//实体类 public class User { private String name; private String gender; private Integer age; } //用户 *** 作接口 public interface UserService { //根据 id 查询用户 MonogetUserById(int id); //查询所有用户 Flux getAllUser(); //添加用户 Mono saveUserInfo(Mono user); } //接口实现类 @Repository public class UserServiceImpl implements UserService { //创建 map 集合存储数据 private final Map 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 getUserById(int id) { return Mono.justOrEmpty(this.users.get(id)); } @Override public Flux getAllUser() { return Flux.fromIterable(this.users.values()); } @Override public Mono saveUserInfo(Mono userMono) { return userMono.doOnNext(person -> { //向 map 集合里面放值 int id = users.size()+1; users.put(id,person); }).thenEmpty(Mono.empty()); } @RestController public class controller { //注入 service @Autowired private UserService userService; //id 查询 @GetMapping("/user/{id}") public Mono geetUserId(@PathVariable int id) { return userService.getUserById(id); } //查询所有 @GetMapping("/user") public Flux getUsers() { return userService.getAllUser(); } //添加 @PostMapping("/saveuser") public Mono saveUser(@RequestBody User user) { Mono userMono = Mono.just(user); return userService.saveUserInfo(userMono); } }
-
说明:
SpringMVC 方式实现,同步阻塞的方式,基于 SpringMVC+Servlet+Tomcat
SpringWebflux 方式实现,异步非阻塞 方式,基于 SpringWebflux+Reactor+Netty
(1)在使用函数式编程模型 *** 作时候,需要自己初始化服务器
(2)基于函数式编程模型时候,有两个核心接口:RouterFunction(实现路由功能,请求转发给对应的 handler)和 HandlerFunction(处理请求生成响应的函数)。核心任务定义两个函数式接口的实现并且启动需要的服务器。
( 3 ) SpringWebflux 请 求 和 响 应 不 再 是 ServletRequest 和 ServletResponse ,而是ServerRequest 和 ServerResponse
- 代码示例如下:
//创建 Handler(具体实现方法) public class UserHandler { private final UserService userService; public UserHandler(UserService userService){ this.userService = userService; } //根据id查询 public MonogetUserById(ServerRequest request){ //获取id值 int userId = Integer.valueOf(request.pathVariable("id")); //空值处理 Mono notFound = ServerResponse.notFound().build(); //调用service方法得到数据 Mono userMono = this.userService.getUserById(userId); //把userMono进行转换返回,使用Reactor *** 作符FlatMap return userMono.flatMap(person -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON) .body(fromObject(person))) .switchIfEmpty(notFound); } //查询所有 public Mono getAllUsers(ServerRequest request) { //调用 service 得到结果 Flux users = this.userService.getAllUser(); return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(users,User.class); } //添加 public Mono saveUser(ServerRequest request) { //得到 user 对象 Mono userMono = request.bodyToMono(User.class); return ServerResponse.ok().build(this.userService.saveUserInfo(userMono)); } } //初始化服务器,编写 Router public class Server { //创建Router路由 public RouterFunction routerFunction(){ //创建 handler 对象 UserService userService = new UserServiceImpl(); UserHandler handler = new UserHandler(userService); //设置路由 return RouterFunctions.route( GET("/users/{id}").and(accept(APPLICATION_JSON)), handler::getUserById) .andRoute(GET("/users").and(accept(APPLICATION_JSON)), handler::getAllUsers); } //创建服务器完成适配 public void createReactorServer(){ //路由和 handler 适配 RouterFunction route = routerFunction(); HttpHandler httpHandler = toHttpHandler(route); ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler); //创建服务器 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(); } } } //使用 WebClient 调用 public class Client { public static void main(String[] args) { //调用服务器地址 WebClient webClient = WebClient.create("http://127.0.0.1:63739"); //根据 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); //查询所有 Flux results = webClient.get().uri("/users").accept(MediaType.APPLICATION_JSON).retrieve().bodyToFlux(User.class); results.map(stu -> stu.getName()).buffer().doOnNext(System.out::println).blockFirst(); } }
下一章,(1)SpringMVC————概述,程序的编写,RestFul风格和数据处理及跳转
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)