Spring5框架学习笔记(三)

Spring5框架学习笔记(三)


Spring5框架新功能
  1. 整个Spring5框架代码基于java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除
  2. Spring5框架自带了通用的日志封装
    1. Spring5已移除Log4jConfigListener,官方建议是用Log4j2
  3. Spring5框架核心容器支持@Nullable注解
    1. @Nullable注解可以使用在方法上面,属性上面,参数上面,表示方法返回值可以为空,属性值可以为空,参数值可以为空
  4. Spring5核心容器支持函数式风格GenericApplicationContext
  5. Spring5支持整合Junit5
//整合Junit4
@RunWith(SpringJUnit4ClassRunner.class)  //单元测试框架
@ContextConfiguration(classes = TxConfig.class)  //加载配置文件
public class JTest4 {

    @Autowired
    private UserService userService;

    @Test
    public void test(){
        userService.accountMoney();
    }
}
Spring框架新功能(webflux)
  1. WebFlux介绍
    1. Spring5添加的新模块,用于web开发,功能与spirngMVC类似,Webflux使用当前一种比较流行响应式编程出现的框架
    2. Webflux是一种异步非阻塞的框架,异步非阻塞的框架在Servlet3.1以后才支持,核心是基于Reactor的相关API实现的
    3. 什么是异步非阻塞?
      异步和同步,阻塞和非阻塞
      同步和异步针对的是调用者,调用者发起请求,如果等着对方回应之后才去做其他事情就是同步,如果发起请求之后不等着对方回应就去做其他事情就是异步
      阻塞和非阻塞针对的是被调用者,被调用者收到请求之后,做完请求任务之后才给出反馈就是阻塞,收到请求之后马上给出反馈然后再去做事情就是非阻塞。
    4. Webflux特点
      1. 非阻塞是式:在有限资源下,提高系统吞吐量和伸缩性,以Reactor为基础实现响应式编程
      2. 函数式编程:Spring5框架基于java8,webflux使用java8函数式编程方式实现路由请求
    5. webflux和springMVC的区别
      1. 两个框架都可以使用注解方式,都运行在Tomcat容器中
      2. springMVC采用命令式编程,webflux采用异步响应式编程
    6. 什么是响应式编程?
      响应式编程是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。
    7. 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, arg)->{
            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都可以发出三种数据信号:元素值,错误信号,完成信号。错误信号和完成信号都代表终止信号,终止信号用于告诉订阅者数据流结束了。错误信号终止数据流同时把错误信息传递给订阅者。
public class TestReactor {

    public static void main(String[] args) {
        Flux.just(1,2,3,4);
        Mono.just(1);

        Integer[] array = {1,2,3,4};
        Flux.fromArray(array);

        List<Integer> list = Arrays.asList(1,2,3,4);
        Flux.fromIterable(list);

        Stream<Integer> stream = list.stream();
        Flux.fromStream(stream);
    }
}
  1. 三种信号特点
    1. 错误信号和完成信号都是终止信号,不能共存
    2. 如果没有发送任何元素值,而是直接发送错误或完成信号,表示是空
    3. 如果没有错误信号,没有完成信号,表示是无限数据流
  2. 调用just或者其他方法只是声明数据流,数据流并没有发出,只有订阅之后才会触发数据流。
Flux.just(1,2,3,4).subscribe(System.out::println);
Mono.just(1).subscribe(System.out::println);
  1. 操作符
    1. 对数据流进行一道道操作,成为操作符,比如工厂流水线
    2. map: 元素映射为新的元素
    3. flatMap:元素映射为流,把每个元素转换成流,把转换之后的多个流合并成一个大的流
SpringWebflux执行流程和核心API
  1. SpringWebflux基于Reactor,默认容器是Netty,Netty是高性能,NIO框架,异步非阻塞框架
  2. SpringWebflux执行过程与springMVC相似
    1. SpringWebflux核心控制器DispatchHandler,实现接口WebHandler
public Mono<Void> handle(ServerWebExchange exchange) {
        if (this.handlerMappings == null) {
            return this.createNotFoundError();
        } else {
            return CorsUtils.isPreFlightRequest(exchange.getRequest()) ? this.handlePreFlight(exchange) : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
                return mapping.getHandler(exchange);
            }).next().switchIfEmpty(this.createNotFoundError()).flatMap((handler) -> {
                return this.invokeHandler(exchange, handler);
            }).flatMap((result) -> {
                return this.handleResult(exchange, result);
            });
        }
    }
  1. SpringWebflux里面DispatcherHandler负责请求的处理,HandlerMapping:请求查询到处理的方法,HandlerAdapter:真正负责请求处理,HandlerResultHandler:响应结果处理
  2. SpringWebflux实现函数式编程,两个接口:RouterFunction(路由处理)和HandlerFunction(处理函数)
  3. SpringWebflux(基于注解编程模型)
@Repository
public class UserServiceImpl implements UserService {

    private final Map<Integer, User> users = new HashMap<>();

    public UserServiceImpl(){
        this.users.put(1, new User("张三", "nan", 20));
        this.users.put(2, new User("李四", "nv", 25));
        this.users.put(3, new User("王五", "nv", 22));
    }

    @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 -> {
            int id = this.users.size();
            users.put(id, person);
        }).thenEmpty(Mono.empty());
    }
}
  1. SpringMVC方式实现,同步阻塞的方式,基于SpringMVC+Servlet+Tomcat;SpringWebflux方式实现,异步非阻塞方式,基于SpringWebflux+Reactor+Netty
  2. SpringWebflux(基于函数式编程模型)
    1. 在使用函数式编程模型操作时,需要自己初始化服务器
    2. 基于函数式编程模型,有两个核心接口:RouterFunction(实现路由功能,请求转发给对应的handler)和HandlerFunction(处理请求生成响应的函数)。核心任务定义两个函数式接口的实现并且启动需要的服务器。
    3. SpringWebflux请求和响应不再是ServletRequest和ServletResponse,而是ServerRequest和ServerResponse
public class UserHandler {

    private final UserService userService;

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

    public Mono<ServerResponse> getUserById(ServerRequest request){
        int id = Integer.parseInt(request.pathVariable("id"));
        //空值处理
        Mono<ServerResponse> notFound = ServerResponse.notFound().build();
        Mono<User> userMono = this.userService.getUserById(id);
        //把userMono进行转换返回
        //使用reactorc操作符flatMap
       return userMono.
               flatMap(person -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).bodyValue(person))
               .switchIfEmpty(notFound);
    }

    public Mono<ServerResponse> getAllUsers(ServerRequest request){
        Flux<User> users = this.userService.getAllUser();
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(users, User.class);
    }

    public Mono<ServerResponse> saveUser(ServerRequest request){
        Mono<User> userMono = request.bodyToMono(User.class);
        return ServerResponse.ok().build(this.userService.saveUserInfo(userMono));
    }
}

//最终调用
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();
    }

    //创建router路由
    public RouterFunction<ServerResponse> routingFunction(){
        UserService userService = new UserServiceImpl();
        UserHandler userHandler = new UserHandler(userService);
        return RouterFunctions.route().GET("/user/{id}", userHandler::getUserById)
                .GET("/users", userHandler::getAllUsers)
                .POST("saveuser", userHandler::saveUser)
                .build();
    }

    //创建服务器完成适配
    public void createReactorServer(){
        RouterFunction<ServerResponse> router = routingFunction();
        HttpHandler httpHandler = RouterFunctions.toHttpHandler(router);
        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
        HttpServer httpServer = HttpServer.create();
        httpServer.handle(adapter).bindNow();
    }
}
//webclient调用方式
public class Client {
    public static void main(String[] args) {
        WebClient client = WebClient.create("http://127.0.0.1:57815");
        String id = "1";
        User block = client.get().uri("/user/{id}", id).accept(MediaType.APPLICATION_JSON).retrieve().bodyToMono(User.class)
                .block();
        System.out.println(block.getName());

        //查询所有
        Flux<User> userFlux = client.get().uri("/users").accept(MediaType.APPLICATION_JSON).retrieve().bodyToFlux(User.class);
        userFlux.map(user -> user.getName()).buffer().doOnNext(System.out::println).blockFirst();
    }
}
循环依赖问题
  1. spring只能解决scope为singleton,通过set注入的循环依赖
  2. 通过构造注入或者scope为prototype的循环依赖无法解决,抛出BeanCurrentlyInCreationException异常
  3. 只有单例的bean会通过三级缓存提前暴露来解决循环依赖的问题,而非单例的bean,每次从容器中获取都是一个新的对象,都会重新创建,所以非单例的bean是没有缓存的,不会将其放到三级缓中
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    private static final int SUPPRESSED_EXCEPTIONS_LIMIT = 100;
    //第一级缓存(也叫单例池),singletonObjects: 存放已经经历了完整生命周期的bean对象
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
    //第三级缓存: singletonFactories,存放可以生成bean的工厂
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
    //第二级缓存: earlySingletonObjects,存放早期暴露出来的bean对象,bean的生命周期未走完(属性还未填充),就把这个bean存入该缓存中,也就是实例化但未初始化的bean放入该缓存中
    private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
    private final Set<String> registeredSingletons = new LinkedHashSet(256);
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16));
    private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap(16));

//三级缓存中的ObjectFactory
@FunctionalInterface
public interface ObjectFactory<T> {
    T getObject() throws BeansException;
}

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值