Spring Boot与Spring Security:
使用JWT:
存储和管理令牌:
安全性:
日志和监控:
JWT登录流程:
JWT结构包括三部分:
头(Header):它通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法,如HMAC SHA256或RSA。
有效载荷(Payload):包含声明,这是关于实体(通常是用户)以及其他一些元数据的语句。这些声明被称为“claims”。
签名(Signature):为了获得签名部分,您必须获取编码的header,编码的payload,一个秘密,然后使用header中指定的算法进行签名。
摘要算法:JWT支持多种摘要算法,但最常见的算法是:
其中,HS256使用共享密钥(客户端和服务器都知道的),而RS256使用私钥/公钥对,只有服务器知道私钥。这使得RS256更适合于公开的、可扩展的环境,因为只有生成JWT的服务器才能验证和接受令牌。
添加iText库依赖:
pom.xml
中添加iText的依赖。不同版本的iText可能有所不同,所以要确保选择一个适合的版本。创建PDF文档:
Document
类来创建一个新的PDF文档。PdfWriter.getInstance()
方法将这个Document
对象与一个文件输出流关联起来。开始编写内容:
document.open()
document.add()
方法添加内容。iText提供了多种元素,如Paragraph
, Chapter
, Section
, List
, PdfPTable
等,你可以根据需要加入。格式化内容:
BaseFont
和Font
类来创建和应用不同的字体和样式。创建表格:
PdfPTable
类来创建表格。添加图片或公司标志:
Image
类来添加图片到文档。页眉和页脚:
HeaderFooter
类或事件处理来添加页眉和页脚。这样可以为每一页自动添加页码、日期、公司标志等信息。完成文档:
document.close()
来关闭并保存文档。提供给用户:
图中服务端启动时将自己的服务节点信息注册到注册中心,客户端调用远程方法时会订阅注册中心中的可用服务节点信息,拿到可用服务节点之后远程调用方法,当注册中心中的可用服务节点发生变化时会通知客户端,避免客户端继续调用已经失效的节点。那客户端是如何调用远程方法的呢,来看一下远程调用示意图:
客户端(Client):发起RPC请求的部分。客户端包含代表远程过程的存根(stub),它提供与本地过程相同的接口。
服务器(Server):接受RPC请求并执行服务的部分。服务器同样包含一个存根,负责接受请求、解码参数、执行请求并返回结果。
传输层:RPC需要一种通信方式来在客户端和服务器之间传输数据。这通常通过网络完成,例如使用TCP/IP或UDP。
消息格式/序列化:由于网络传输层通常只能传输字节流,RPC需要将数据(如过程参数和返回值)转换为这种格式。这个转换过程叫做序列化(将数据转换为字节流)和反序列化(将字节流转回原始数据)。
请求与响应:客户端发起的是请求,服务器返回的是响应。每个请求都与一个响应匹配。
服务注册与发现:在某些RPC系统中(如gRPC、Apache Thrift等),服务器可以注册其提供的服务,并且客户端可以发现这些服务。这可以使得客户端和服务器的连接更加动态和灵活。
错误处理:如果远程调用中发生错误(如网络问题、服务不可用等),RPC框架应该能够捕获并处理这些错误。
身份验证和授权:为了确保只有合法的客户端可以访问服务,RPC系统可能会包含身份验证和授权机制。
负载均衡:在多个服务器实例中,RPC系统可能会提供负载均衡功能,使得客户端的请求可以均匀地分配到不同的服务器。
(1)选择CP还是AP取决于你的系统需求:
(2)ZooKeeper 是一个CP系统。当网络分区发生时,为了维护一致性,ZooKeeper可能会牺牲可用性。这意味着在某些情况下,ZooKeeper可能不会响应客户端的请求,以确保数据的一致性。
(1)在RPC(远程过程调用)中,序列化的主要作用是将数据或对象转化为可传输的格式,使其能够在网络上进行传输,从而实现不同节点或服务之间的通信。
具体作用如下:
数据交换:通过序列化,客户端可以将请求参数转化为字节流,在网络上发送到服务器;服务器接收到字节流后,再通过反序列化恢复为原始的请求参数。
保证数据完整性:序列化过程中可以将数据结构完整地转化为字节流,确保数据在传输过程中不丢失任何信息。
兼容性:有些序列化协议(如Protocol Buffers, Avro等)提供了版本控制和兼容性管理,使得数据格式可以随着时间演进而不影响已有的客户端和服务器之间的通信。
(2)Serializable的原理
Serializable
是Java中的一个标记性接口,用于指示一个类的对象可以被序列化。当一个类实现了Serializable
接口时,Java的对象序列化机制可以将其转换为字节流,反之也可以从字节流中重构对象。
服务掉线分为主动下线和心跳检测。
比如服务由于发版时,在重启之前先主动通知注册中心:我要重启了,有流量进来先不要分给我,让别的机器服务,等我重启成功后在放流量进来,或者是在管理后台手动直接摘掉机器,这个是主动下线。
增加 Netty 心跳机制 : 保证客户端和服务端的连接不被断掉,避免重连。
心跳检测是处理服务非正常下线(如断电断网)的情况,这个时候如果注册中心不知道该服务已经掉线,一旦被其调用就会带来问题。为了避免出现这样的情况,注册中心增加一个心跳检测功能,它会对服务提供者(Provider)进行心跳检测,比如每隔 30s 发送一个心跳,如果三次心跳结果都没有返回值,就认为该服务已下线,赶紧更新 Consumer 的服务列表,告诉 Consumer 调用别的机器
首先注册中心挂掉也要分两种情况,如果数据库挂了,ZK 还是能用的,因为 ZK 会缓存注册机列表在缓存里。其次 ZK 本身就是一个集群的,一台机器挂了,ZK 会选举出集群中的其他机器作为 Master 继续提供服务,如果整个集群都挂了也没问题,因为调用者本地会缓存注册中心获取的服务列表。省略和注册中心的交互,Consumer 和 Provider 采用直连方式,这些策略都是可配置的。
在 Netty 中,RPC 框架的实现是基于 Netty 的异步通信机制的。RPC 框架中,客户端与服务端的异步通信是通过 Channel 和 EventLoop 实现的。Channel 是一个连接到网络套接字的组件,而 EventLoop 是处理 Channel 事件的线程。在 Netty 中,每个 Channel 都有一个与之相关联的 EventLoop,它会处理所有的 I/O 事件和请求。
具体步骤如下:
(1)ZooKeeper的特点有以下几点
(2)ZooKeeper的选举机制是基于Paxos算法。当集群中的Leader节点挂掉时,ZooKeeper会自动进行Leader选举。选举过程分为两个阶段:选举和投票。选举阶段是为了选出一个唯一的Leader,投票阶段是为了让其他节点知道谁是Leader。在选举过程中,每个节点都可以成为候选人,然后通过投票来决定哪个候选人成为Leader。
当出现网络分区或者节点故障时,就会出现选举问题。如果出现网络分区,那么可能会出现多个Leader,这时需要手动干预解决。如果出现节点故障,那么ZooKeeper会自动进行Leader选举。
ZooKeeper是CP系统。它保证了数据的一致性和分区容错性,但不保证可用性。因此,在网络分区或者节点故障时,可能会导致部分客户端无法访问。
ZooKeeper分布式锁的实现方式是:首先需要创建一个父节点,尽量是持久节点(PERSISTENT类型),然后每个要获得锁的线程,都在这个节点下创建个临时顺序节点。当一个线程需要获得锁时,它会在父节点下创建一个临时顺序节点,然后获取父节点下所有子节点的列表,判断自己创建的节点是否是最小的那个。如果是,则表示该线程获得了锁;否则,该线程就需要监听比自己小的那个节点的删除事件,当该节点被删除时,该线程再次判断自己创建的节点是否是最小的那个。如果是,则表示该线程获得了锁。
客户端调用远程服务的时候进行负载均衡 :调用服务的时候,从很多服务地址中根据相应的负载均衡算法选取一个服务地址。
(1)RandomLoadBalance:根据权重随机选择(对加权随机算法的实现)。这是Dubbo默认采用的一种负载均衡策略。
(2)LeastActiveLoadBalance:最小活跃数负载均衡。
Dubbo 就认为谁的活跃数越少,谁的处理速度就越快,性能也越好,这样的话,我就优先把请求给活跃数少的服务提供者处理。
(3)ConsistentHashLoadBalance:一致性Hash负载均衡策略。
ConsistentHashLoadBalance
中没有权重的概念,具体是哪个服务提供者处理请求是由你的请求的参数决定的,也就是说相同参数的请求总是发到同一个服务提供者。另外,Dubbo 为了避免数据倾斜问题(节点不够分散,大量请求落到同一节点),还引入了虚拟节点的概念。通过虚拟节点可以让节点更加分散,有效均衡各个节点的请求量。
(4)RoundRobinLoadBalance:加权轮询负载均衡。
轮询就是把请求依次分配给每个服务提供者。加权轮询就是在轮询的基础上,让更多的请求落到权重更大的服务提供者上。
RPC(远程过程调用,Remote Procedure Call)是一种计算机通信协议,它允许程序在一个地址空间中请求服务,而不需要明确提供该服务的详细知识。在分布式系统和微服务架构中,RPC经常被用作通信机制。学习RPC的原因有很多:
分布式系统设计:随着业务规模的增长,很多企业都会从单体应用转向分布式系统。在分布式系统中,不同的服务或组件可能部署在不同的机器或数据中心上。RPC为这些服务或组件之间提供了一种快速、高效的通信方式。
微服务架构:微服务是近年来非常热门的软件架构模式,每个服务通常负责执行单一的、小的功能。这些服务之间需要通过某种方式进行通信,而RPC是其中之一。
性能和优化:与其他通信机制相比,如HTTP RESTful API,RPC通常能提供更好的性能和更少的开销。学习如何优化RPC可以帮助你构建更高效的系统。
多语言支持:很多RPC框架,如gRPC,支持多种编程语言,这意味着你可以在不同的语言中编写服务,然后使用RPC进行交互。
跨平台通信:RPC允许不同的系统、应用或设备之间进行通信,这为构建跨平台应用提供了可能性。
抽象和封装:RPC隐藏了网络通信的复杂性,开发者只需像调用本地函数一样调用远程函数,而不需要关心底层的网络细节。
拓展知识和技能:作为软件工程师,了解不同的技术和方法可以帮助你在面对各种问题时更具备选择权和判断力。
一面问的多态特性,运行时多态怎么实现的
Sring拥有两大特性:IoC和AOP。IoC,英文全称Inversion of Control,意为控制反转(或者叫依赖注入)。AOP,英文全称Aspect-Oriented Programming,意为面向切面编程。
Spring核心容器的主要组件是Bean工厂(BeanFactory),Bean工厂使用控制反转(IoC)模式来降低程序代码之间的耦合度,并提供了面向切面编程(AOP)的实现。
Spring AOP中动态代理的两种实现方式分别是JDK动态代理和CGLIB动态代理。 JDK动态代理是通过反射机制来实现的, CGLIB动态代理则是通过继承目标类来实现的,它不要求目标类实现接口,代理类继承了目标类并在代理类中重写了目标类的方法。
singleton(单例):这是默认的作用域。在Spring IoC容器的上下文中,每个Bean定义对应的实例只有一个。无论多少次请求该Bean,都会返回该容器中的同一个Bean实例。它确保Bean在Spring上下文中是一个单例,但如果有多个Spring上下文,则每个上下文都会有一个Bean的实例。
prototype(原型):每次请求都将创建一个新的Bean实例。当你获取Bean时,Spring IoC容器都会返回一个新的实例,这意味着prototype作用域的Bean不会被重用。
request:这是一个Web-specific作用域,用于Web应用。每次HTTP请求都会产生一个新的Bean,该Bean仅在当前HTTP请求内有效。
session:这也是一个Web-specific作用域。在Web应用中,为每一个HTTP Session创建一个Bean实例。这意味着该Bean的状态会保持在整个用户会话中。
application:这是另一个Web-specific作用域。为每一个ServletContext创建一个Bean实例(通常是Web应用的全局作用域)。这个Bean对所有的HTTP Session是可见的。
websocket:在WebSocket生命周期内,为每个WebSocket创建一个Bean实例。
当你定义一个Bean时,你可以指定其作用域。如果没有明确指定,那么Bean的默认作用域是singleton。
地址解析:
建立TCP连接:
发送HTTP请求:
服务器处理请求并返回HTTP响应:
浏览器解析并渲染页面:
加载嵌套的资源:
执行JavaScript:
关闭连接:
(1)三次握手的步骤如下:
(2)四次挥手的步骤如下:
(3) 三次握手原因:
防止已失效的连接请求报文段突然传到了服务端:考虑一个场景,客户端发送了第一个连接请求,但是由于网络原因这个请求被延迟了,于是TCP又发送了一个连接请求。当网络好转时,两个连接请求几乎同时到达服务端,如果此时是两次握手,服务端就会建立两个连接,但客户端只建立了一个连接,这就造成了服务端资源的浪费。
更为可靠地确认双方的接收与发送能力:三次握手可以确保双方都有接收和发送消息的能力。两次握手无法保证这一点。
设定序列号:三次握手还可以使得双方都能为TCP连接初始的序列号达成一致