Java Web 入门导论 (未完待续...)

Java Web 入门导论 (未完待续...)

适合新手入门Java Web技术栈,减少茫然和弯路。知其然,更知其所以然.... 

持续更新 j-days

简言之:2条线,不迷茫

  • 线索1 -- 沿着数据的流向,思考每个环节存在的需求和问题,以及java如何解决,如java实现http协议接受客户端的请求是java web服务的前提
  • 线索2 -- 终极目标:业务至上【解放web开发者(从低级、重复劳动),专注于业务】,即旧技术/方案存在的问题,以及新技术/方案如何解决和优化,不断将开发者从繁琐、重复的底层劳动中解放出来,从而更多的关注业务 -- Spring及Boot成为java事实规范的主要原因

以下按照数据流的方向、各主要环节概论

1、【起点(服务的前提)】 -- 问题:如何建立通信链路,使用哪种"官方语言",即网络协议

  • IP协议蔟(先 服务定位):根据IP+port确定网络中唯一的服务端(服务器+监听端口的服务程序);
  • TCP协议族(再 建立连接):通过握手建立服务端和客户端间稳定的单工/双工连接;
  • 核心目标 - 通信:
    • Client-Server 丰富通信 - HTTP协议:C-S架构关注丰富的表现层(json、xml、甚至是文件)(超文本),构建多样的WWW网络服务和站点;
    • Server-Server 高效通信 - RPC协议:服务端之间通信往往是业务数据的交互,特征是:频率高、数据小,更关注载荷(体/头 比例)效率和性能,不关注丰富度,典型如dubbo、thrift

2、【I/O(服务进程(用户态) <---> 系统(硬件)级 间数据流转)】

客户端通过上述链路、协议将数据输送到服务端的网卡缓冲区以后,关注操作系统(OS)如何将网卡接收到的请求数据(读缓冲区)(内核态)传递给服务进程的内存空间(用户(即进程)态)【请求读取】,反之【响应输出】

核心:关注操作系统IO机制的升级路线(语言层(无论是Java、Python、NodeJS还是Go...)只是封装了系统调用)

  • BIO阻塞IO(❌Web服务基本废弃):

    • read/write 

      系统调用(用户态 <-> 内核态) 同步阻塞,每个线程指定处理一个连接(1000连接=1000线程,线程栈(1M左右)*1000,内存直接溢出OOM,且线程切换(上下文的保存和恢复)的成本成为主要矛盾⚠️)

    • InputStream/OutputStream 

      java sdk的输入/输出抽象接口,可以看做对read/write的包装和IO的抽象,提供对象化的IO Api

  • NIO/2 非阻塞(主流✅):

    • selector/epoll 

      多路复用,代替旧版阻塞式read/write等待,单线程(Acceptor线程)可以监听万级连接上的IO事件,并分发给处理(工作者)线程池。(对应于【1主-多从】Reactor响应式线程模型,可参阅Netty线程模型相关)

    • Buffer+Channel 

      代替直接InputStream/OutputStream,提升性能,增强功能

      • 通过Buffer将随机读写转化为批量顺序读写 【提升性能】
      • 通过Channel提供读写双工的增强API,读写只发生在Channel+Buffer上,不再直接系统调用(read/write),不阻塞(不用内核态 <-> 用户态状态)【增强功能】
  • AIO异步IO(非主流 ⚠️ 系统支持不成熟): 

    依赖于操作系统的async_io机制 

3、服务(核心): 根据请求执行一系列业务逻辑后返回处理结果(响应输出),

关注2大责任链

  • 1、servlet规范与容器(Tomcat为例)【传统⚠️】

    servlet规范是Java对于服务的抽象(Java接口编程的典型),制定了标准服务端程序的服务流程、功能组件,和容器规范(如果没有规范,便无法成为行业标准,也得不到大公司/大牛的加入和支持,因此接口思想是Java最重要的编程思想,重抽象(接口/规范设计),多实现(择优而胜))

    • 2大组件:
      • Filter - 组成前置和后置的责任链,用于执行服务前置的预处理(如权限验证)和服务后置的后处理(如服务耗时统计)
      • Servlet - 真正的服务组件,核心方法service用于扩展、根据不同的请求,分发执行不同的业务逻辑
    • 容器(常见Tomcat):

      Servlet容器规范的实现,负责Servlet的实例化和生命周期管理,并提供连接管理、协议解析(如http)等基础支持,让开发者只关注扩展Servlet、实现自己的业务,并不需重复的底层劳动

    • 问题: Servlet#service 太过底层和原始,参数的解析、验证、路由的分发以及响应的包装等需要开发者手动处理,繁重而冗余⚠️

  • 2、Spring MVC责任链【主流✅】

    鉴于传统Servlet机制的问题,以核心DispathServlet全权代理所有请求,解决了参数解析、绑定、验证和自动路由、响应封装等大部分底层、重复劳动,并通过注解(声明式编程)和动态代理机制(动态编程)让任何类和方法都具备"服务Service"的能力,而不再局限于继承重量级的类Servle,开发者真正实现了【业务至上】

    • 2大组件:
      • Interceptor:类似于Servlet中Filter,前置/后置责任链
      • Controller:服务的集合,内部的每个方法都可以声明为服务(HandlerMethod,类似于Servlet#service),但只关心当前的请求参数和业务逻辑
    • 分层隔离原则

      即虽然Servlet规范中的Filter/Servlet和Spring MVC中Interceptor/Controller具备相似的能力,但业务层不应轻易跨过Spring MVC去使用Servlet机制,会打破分层隔离的原则,引起代码逻辑的混乱,且没有额外的好处。

4、Spring/Boot(事实规范 -- 助力Java Web起飞)

提升Java开发的效率和逼格,Java Web编程的事实规范

  • Spring(实例管理工厂/容器)

    改变传统的手动创建游离实例、管理生命周期、依赖层层传递(尤其是嵌套较深)等问题,将组件实例的创建、管理、相互依赖委托给Spring工厂(即IoC,控制/依赖反转),降低了手动管理的重复劳动,更基于容器提供了AOP等高级编程的支持(集中的好处是可以管理,并提供高级功能),以此进一步提高自动化水平(如boot的自动化配置,事务的自动化代理)

    • 反转(也可以理解为委托(给Spring))

      可以理解为根据依赖关系(先)Spring自动创建被依赖的实例、并建立依赖关系,而常规(正常、手动)情况下,是先创建被依赖的实例,再手动设置依赖关系(后)

    • 产生原因 -- 2个基本事实:

      • 1、功能性组件多是无状态的单例模式(无状态服务原则),无需手动冗余创建、管理(需要自动化、透明化)
      • 2、组件间需要相互组合才能实现更复杂的业务功能(依赖,组合模式)
  • Spring Boot(开发脚手架/启动器)

    基于【约定大于配置】的思想,在Spring容器支持条件化配置的基础上,对常用的web组件进行约定的配置(各种starter包,如spring mvc starter,spring data starter...so on)

    • 基本事实:在使用某个组件时(如Tomcat容器),大部分的场景下(90%)都会使用默认或通用的配置,每次都进行重复的配置或拷贝是不明智的,因此需要进一步解放出来 --> 【专注业务,别做低级劳动】
  • 总论:

    通过Sping以及Boot,让Java开发具备了脚本语言开发(脚手架)开箱即用的敏捷开发能力,解决了大部分的低级劳动,进一步解放开发者,如只要引入starter-web依赖,tomcat、mvc等无需任何额外配置,开箱即跑,6到飞起(做过传统java web开发的应该对web.xml重复、繁重的配置深有体会)

5、Java并发编程(前后端开发的主要区别)

上千/万用户的并发请求反应到服务器便是并发的处理请求(串行处理是不可取的,IO很慢,第50-1000等待的用户就跑了),就必须保证并发的安全性,因此并发安全和编程是Java web开发的重要(首要)命题。

  • 并发手段:多线程与线程池(主流,但非唯一)
  • 并发安全
    • 并发安全的手段:synchronized,lock,cas、volatile等;
    • 并发安全的对象/字段:AtomicInteger原子系列
    • 并发安全的集合(容器):ConcurrentHashMap系列

6、业务模型和存储

业务的本质是业务模型和服务设计,并最终持久化业务,以形成业务数据。3大存储,不同侧重

  • MySQL

    事务性性存储是大部分业务(尤其是核心业务)必不可少的,关注(业务)模型间的关联和事务

    • 基本事实

      一个业务要么成功,要么失败,不应该处于半成功、半失败的错误中间态 ==> 事务(业务)一致性

      备注: 如果db层没有提供这个机制,就要业务侧去额外实现和保证(无疑是重复、冗余而低级的劳动)

  • Redis

    K-V键值存储,关注查询瓶颈的热数据,提升服务体验(非必须,但更友好)

  • ES

    侧重关键词的检索,弥补MySQL文本检索的劣势,通过倒排索引(以关键字搜索文档,而非(遍历、逐个)文档搜索是否包含关键字),加速文本搜索

..................... 未完,待续 ...........................................

最后

  • 项目实践 * 时间,不断深化Java及各技术栈,将理论转化为能力
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值