栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring 第七讲:Spring5 框架新功能

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring 第七讲:Spring5 框架新功能

一、Spring5 框架新功能 1、版本兼容

整个 Spring5 框架的代码基于 Java8,运行时兼容 JDK9,许多不建议使用的类和方法在代码库中删除。

2、日志封装

Spring5 框架自带了通用的日志封装

(1) Spring5 已经移除了 Log4jConfigListener,官方建议使用 Log4j2
(2) Spring5 框架整合 Log4j2

① 引入 log4j2 、 slf4j

    
    
        org.slf4j
        slf4j-api
        1.7.30
    

    
        org.apache.logging.log4j
        log4j-slf4j-impl
        2.14.1
    

    
        org.apache.logging.log4j
        log4j-api
        2.14.1
    
    
        org.apache.logging.log4j
        log4j-core
        2.14.1
    

② 创建 log4j2.xml 配置文件





    
    
        
        
            
            
        
    
    
    
    
        
            
        
    

③ 测试类

public class UserLog {

    private static final Logger log = LoggerFactory.getLogger(UserLog.class);

    public static void main(String[] args) {
        log.info("hello log4j2");
        log.info("hello log4j2");
    }
}

④ 结果

19:25:32.010 [main] INFO  UserLog - hello log4j2
19:25:32.012 [main] INFO  UserLog - hello log4j2
3、@Nullable 注解

Spring5 框架核心容器支持 @Nullable 注解

使用范围作用
方法上面表示方法返回值可以为空
属性上面表示属性值可以为空
参数上面表示参数值可以为空
4、函数式风格创建对象

Spring5 核心容器支持函数式风格创建对象 GenericApplicationContext

     //函数式风格
    @org.junit.Test
    public void testGenericApplicationContext(){
        //1.创建GenericApplicationContext对象
        GenericApplicationContext context = new GenericApplicationContext();
        //2.调用context的方法进行对象注册
        context.refresh();
        context.registerBean("user1",User.class,() -> new User());
        //3.获取在Spring注册的对象
        User user = (User) context.getBean("user1");
        System.out.println(user);
    }
5、测试方面的改进

Sping5 支持整合 JUnit5
(1)整合 JUnit4
① 引入 Spring 相关针对测试依赖。
② 创建测试类,使用注解方式完成。

@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架
@ContextConfiguration("classpath:bean1.xml") //加载配置文件
public class Test {

    @Autowired
    private UserService userService;

    @org.junit.Test
    public void JUnit4test(){
        userService.accountMoney(); //可替代以下testAccount()方法
    }

    @org.junit.Test
    public void testAccount(){ //testAccount()方法
        ApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();
    }
}

(2)整合 JUnit5
① 引入 Spring 相关针对测试依赖。
② 创建测试类,使用注解方式完成。

@ExtendWith(SpringExtension.class)
@Configuration("classpath:bean1.xml")
public class Test {

    @Autowired
    private UserService userService;

    @org.junit.Test
    public void JUnit5test(){
        userService.accountMoney(); //可替代以下testAccount()方法
    }

    @org.junit.Test
    public void testAccount(){
        ApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();
    }
}

③ @SprinJunitConfig(location="classpath:bean1.cml")
可以替代上面 :
@ExtendWith(SpringExtension.class)
@Configuration("classpath:bean1.xml")

6、SpringWebflux 6.1 SpringWebflux 介绍

(1)是 Spring5 添加新的模块,用于 web 开发的,功能和 SpringMVC 类似的,SpringWebflux 是当前一种比较流行的响应式编程框架。
(2)使用传统的 web 框架,比如 SpringMVC,这些基于 Servlet 容器,Webflux 是一种异步非阻塞的框架,在 Servlet 3.1 以后版本才支持。核心是基于 Reactor 的相关 API 实现的。

  • 异步和同步:针对调用者,调用者发送请求,如果等着对方回应之后才去做其他事情就是同步;如果发送之后不等对方回应就去做其他事情就是异步。
  • 阻塞和非阻塞:被调用者收到请求后,做完请求任务之后才给出反馈就是阻塞;收到请求之后马上给出反馈然后再去做事情就是非阻塞。

上面都是针对对象不一样

(4)Webflux 特点:
① 异步非阻塞:在有限的资源下,提高系统的吞吐量和伸缩性,以 Reactor 为基础实现响应式编程。
② 函数式编程:Spring5 框架基于 Java8,Webflux 使用 Java8 函数时编程方式实现路由请求。

(5)比较 SpringMVC

① 两个框架都可以使用注解方式,都运行在 Tomcat 等容器中。
② SpringMVC 采用命令式编程,Webflux采用异步响应式编程。

6.2 响应式编程

(1)什么是响应式编程?
响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。

类似于 EXCEL 的计算公式 A1=B1+C1,A1 的值依赖 B1 和 C1。

(2)Java8 及其之前版本
提供的观察者模式两个类 Observer 和 Observable(在 Java9 之后被 Flow 类取代)
① 创建 SringBoot 项目,版本 2.2.1.RELEASE
② 观察者例子

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,arg)->{
            System.out.println("被观察者通知,准备改变");
        });
        //监控数据是否发生变化
        observer.setChanged();
        //通知
        observer.notifyObservers();
    }
}

③ 结果

收到观察者通知,准备改变
发生了变化
6.3 响应式编程(Reactor 实现)

(1)响应式编程操作中,Reactor 是满足 Reactive 规范框架

(2)Reactor 有两个核心类,Mono 和 Flux,这两个类实现接口 Publisher,提供丰富操作符。
Flux 对象实现发布者,返回 N 个元素;
Mono 对象实现发布者,返回 0 或者 1 个元素。

(3)Flux 和 Mono 都是数据流的发布者,使用 Flux 和 Mono 都可以发出三种数据信号:元素值,错误信号,完成信号。
错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了。
错误信号终止数据流同时把错误信息传递给订阅者。

(4)三种信号特点
① 错误信号和完成信号都是终止信号,不能共存的。
② 如果没有发送任何元素值,而是直接发送错误或者完成信号,表示空数据流。
③ 如果没有错误信号,没有完成信号,表示是无限数据流。

(5)编程实现
① 引入 reactor-core 依赖

        
            io.projectreactor
            reactor-core
            3.1.5.RELEASE
        

② 编程代码

public class TestReactor {

    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); //数组方式

        List list = Arrays.asList(array);
        Flux.fromIterable(list); //集合方式

        Stream stream = list.stream();
        Flux.fromStream(stream); //流的方法
    }
}

(6)调用 just 或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅 subscribe 之后才会触发数据流,不订阅什么都不会发生。

public class TestReactor {

    public static void main(String[] args) {
        //just方法直接声明
        Flux.just(1,2,3,4).subscribe(System.out::print);
        Mono.just(1).subscribe(System.out::print);
    }
}

(7)操作符
① 对数据流进行一道道操作,称为操作符,比如工厂流水线。

操作符解释说明
map元素映射为新元素
flatMap元素映射为流

map:

flatMap :
把每个元素转化为流,把转换之后多个流合并成大流。

6.4 SpringWebflux 执行流程和核心 API

SpringWebflux 基于 Reactor,默认容器是 Netty,Netty 是高性能,NIO 框架,高性能异步非阻塞的框架。
(1)Netty
BIO 阻塞
NIO 非阻塞

(2)SpringWebflux 执行过程和 SpringMVC 相似的。
① SpringWebflux 核心控制器 DispatcherHandler,实现接口 WebHandler。
② 接口 WebHandler 有一个方法 handle。

(3)SpringWebflux 里面 DispatcherHandler,负责请求的处理
① HandlerMapping:请求查询到处理的方法。
② HandlerAdapter:真正负责请求处理。
③ HandlerResultHandler:响应结果处理。

(4)SpringWebflux 实现函数式编程,两个接口: RouteFunction(路由处理) 和 HandlerFunction(处理函数)

6.5 SpringWebflux(基于注解编程模型)

SpringWebflux 实现方式有两种:注解编程模型和函数式编程模型。
使用注解编程模型方式,和 SpringMVC 使用相似的,只需要把相关依赖配置到项目中,SpringBoot 自动配置相关运行容器,默认情况下使用 Netty 服务器。
(1)实现步骤
① 创建 SpringBoot 项目,引入 Webflux 依赖。

        
            org.springframework.boot
            spring-boot-starter-webflux
        

② 设置端口号 8081

server.port=8081

③ 创建包和相关类

User

public class User {
    private String name;
    private String gender;
    private Integer age;

    public User(String name, String genderr, Integer age) {
        this.name = name;
        this.gender = genderr;
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setGender(String genderr) {
        this.gender = genderr;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public String getGender() {
        return gender;
    }

    public Integer getAge() {
        return age;
    }
}

UserService

//用户操作接口
public interface UserService {
    //根据id查询用户(一个用Mono)
    Mono getUserById(int id);
    
    //查询所有用户(多个用Flux)
    Flux getAllUser();
    
    //添加用户
    Mono saveUserInfo(Mono user);
}

UserServiceImpl

@Service
public class UserServiceImpl implements UserService{

    //创建map集合存储数据
    private final Map users = new HashMap<>();
    
    public UserServiceImpl(){
        this.users.put(1,new User("Jack","m",20));
        this.users.put(2,new User("Lucy","f",21));
        this.users.put(2,new User("Lily","f",22));
    }
    
    //根据id查询
    @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());
    }
}

④ 结果
输入 url:http://localhost:8080/user/1

⑤ 说明
SpringMVC 方式实现,同步阻塞的方式,基于 SpringMVC+Servlet+Tomcat
SpringWebflux 方式实现,异步非阻塞方式,基于 SpringWebflux+Reactor+Netty

6.6 SpringWebflux(基于函数式编程模型)

(1)在使用函数式编程模型操作时候,需要自己初始化服务器。
(2)基于函数式编程模型时候,有两个核心接口:RouteFunction(实现路由功能,请求转发给对应的 handler) 和 HandlerFunction(处理请求生成响应的函数)。核心任务定义两个函数式接口的实现并且启动需要的服务器。
(3)SpringWebflux 请求和响应不再是 ServletRequest 和 ServletResponse,而是 ServerRequest 和 ServerResponse。
(4)实现步骤
① 创建 Handler (具体实现方法)

public class UserHandler {

    private final UserService userService;

    public UserHandler(UserService userService){
        this.userService = userService;
    }

    //根据id查询
    public Mono getUserById(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(){
        //调用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 {
    
    public static void main(String[] args) throws IOException {
        Server server = new Server();
        server.createReactorServer();
        System.out.println("enter to exit");
        System.in.read();
    }
    
    //1.创建Router路由
    public RouterFunction routingFunction(){
        //创建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);
    }

    //3.创建服务器完成适配
    public void createReactorServer(){
        //路由和handle适配
        RouterFunction route = routingFunction();
        HttpHandler httpHandler = toHttpHandler(route);
        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);

        //创建服务器
        HttpServer httpServer = HttpServer.create();
        httpServer.handle(adapter).bindNow();
    }
}

(5)使用 WebClient 调用

public class Client {

    public static void main(String[] args) {
        //调用服务器地址
        WebClient webClient = WebClient.create("http://127.0.0.1:4619");

        //根据id查询
        String id= "1";
        User userresult = webClient.get().uri("/users/{id}", id).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class).block();
        System.out.println(userresult.getName());

        //查询所有
        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();
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/682503.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号