浅析 SpringMVC 中返回对象的循环引用问题
问题发现
@RestController、@ResponseBody 等注解是我们在写 Web 应用时打交道最多的注解了,我们经常有这样的需求:返回一个对象给前端,SpringMVC 帮助我们序列化成 JSON 对象。而今天我要分享的话题也不是什么高深的内容,可能大家多多少少也都遇到过,那就是返回对象中存在循环引用时的问题,分享我的一些思考。
该问题非常简单容易复现,直接上代码。
准备两个循环引用的对象:
1 |
|
@RestController、@ResponseBody 等注解是我们在写 Web 应用时打交道最多的注解了,我们经常有这样的需求:返回一个对象给前端,SpringMVC 帮助我们序列化成 JSON 对象。而今天我要分享的话题也不是什么高深的内容,可能大家多多少少也都遇到过,那就是返回对象中存在循环引用时的问题,分享我的一些思考。
该问题非常简单容易复现,直接上代码。
准备两个循环引用的对象:
1 |
|
一年一度的 HW 行动开始了,最近也是被各种安全漏洞搞的特别闹心,一周能收到几十封安全团队扫描出来的漏洞邮件,这其中有一类漏洞很容易被人忽视,但影响面却极广,危害也极大,我说出它的名字你应该也不会感到陌生,正是 Spring Boot Actuator
。
写这篇文章前,我跟我的朋友做了一个小调查,问他们对 Spring Boot Actuator
的了解,结果惊人的一致,大家都知道 Spring Boot 提供了 spring-boot-starter-actuator
的自动配置,但却很少有人真正用到它相关的特性。在继续往下面看这篇文章时,大家也可以先思考下几个问题:
spring-boot-starter-actuator
依赖吗?spring-boot-starter-actuator
的有关功能吗?spring-boot-starter-actuator
的安全风险和正确配置方式吗?很久没有写关于 Spring 的文章了,最近在系统梳理 Dubbo 代码的过程中发现了 XML schema 这个被遗漏的知识点。由于工作中使用 SpringBoot 比较多的原因,几乎很少接触 XML,此文可以算做是亡羊补牢,另一方面,也为后续的 Dubbo 源码解析做个铺垫。
XML schema 扩展机制是啥?这并不是一块很大的知识点,翻阅一下 Spring 的文档,我甚至没找到一个贯穿上下文的词来描述这个功能,XML Schema Authoring
是文档中对应的标题,简单来说:
去年我曾经写过几篇和 Spring Session 相关的文章,从一个未接触过 Spring Session 的初学者视角介绍了 Spring Session 如何上手,如果你未接触过 Spring Session,推荐先阅读下「从零开始学习 Spring Session」系列(https://www.cnkirito.moe/categories/Spring-Session/) Spring Session 主要解决了分布式场景下 Session 的共享问题,本文将从 Spring Session 的源码出发,来讨论一些 Session 设计的细节。
上一篇文章《浅析 Spring 中的事件驱动机制》简单介绍了 Spring 对事件的支持。Event 的整个生命周期,从 publisher 发出,经过 applicationContext 容器通知到 EventListener,都是发生在单个 Spring 容器中,而在分布式场景下,有些时候一个事件的产生,可能需要被多个实例响应,本文主要介绍分布式场景下的事件驱动机制,由于使用了 Redis,ActiveMQ,也可以换一个名词来理解:分布式下的发布订阅模式。
在日常项目开发中,我们或多或少的发现一些包一些类位于 java 或 javax 中,他们主要提供抽象类,接口,提供了一种规范,如 JPA,JSR,JNDI,JTA,JMS,他们是由 java 指定的标准规范,一流企业做标准、二流企业做品牌、三流企业做产品,虽然有点调侃的意味,但也可以见得它的重要意义。而 JMS 就是 java 在消息服务上指定的标准
The Java Message Service (JMS) API is a messaging standard that allows application components based on the Java Platform Enterprise Edition (Java EE) to create, send, receive, and read messages. It enables distributed communication that is loosely coupled, reliable, and asynchronous.
JMS(JAVA Message Service,java 消息服务)API 是一个消息服务的标准或者说是规范,允许应用程序组件基于 JavaEE 平台创建、发送、接收和读取消息。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。
消息中间件有非常多的实现,如 ActiveMQ,RabbitMQ,RocketMQ,而他们同一遵循的接口规范,便是 JMS。在下文中即将出现的 ConnectionFactory,Destination,Connection,Session,MessageListener,Topic,Queue 等等名词,都是 JMS 核心的接口,由于本文的初衷并不是讲解 MQ&JMS,所以这些机制暂且跳过。
在上一个项目中,我们对接了外网的 http 接口,而安全性的保障则是交给 OAuth2 来完成,作为 OAuth2 的客户端,我们需要获取服务端返回的 token,而 token 接口的获取次数每个月是有限制的,于是我们选择使用 Redis 来保存,定时刷新。由于每次发起请求时都要携带 token,为了更高的性能减少一次 redis io,我们在 TokenService 中使用了本地变量缓存 token。于是形成如下的 token 获取机制:
这个图并不复杂,只是为了方便描述需求:首先去本地变量中加载 token,若 token==null,则去 Redis 加载,若 Redis 未命中(token 过期了),则最终调用外部的 http 接口获取实时的 token,同时存入 redis 中和本地变量中。
这个需求设计到这样一个问题:大多数情况下是单个实例中发现 redis 中的 token 为空,而它需要同时获取最新 token,并通知其他的实例也去加载最新的 token,这个时候事件广播就可以派上用场了。
由于 token 缓存在了 Redis 中,我们首先介绍 Redis 的发布订阅机制。
今天来简单地聊聊事件驱动,其实写这篇文章挺令我挺苦恼的,因为事件驱动这个名词,我没有找到很好的定性解释,担心自己的表述有误,而说到事件驱动可能立刻联想到如此众多的概念:观察者模式,发布订阅模式,消息队列 MQ,消息驱动,事件,EventSourcing… 为了不产生歧义,笔者把自己所了解的这些模棱两可的概念都列了出来,再开始今天的分享。
上一篇文章中,我们使用 Redis 集成了 Spring Session。大多数的配置都是 Spring Boot 帮我们自动配置的,这一节我们介绍一点 Spring Session 较为高级的特性。
上一篇文章介绍了一些 Session 和 Cookie 的基础知识,这篇文章开始正式介绍 Spring Session 是如何对传统的 Session 进行改造的。官网这么介绍 Spring Session:
Spring Session provides an API and implementations for managing a user’s session information. It also provides transparent integration with:
HttpSession
alive when receiving WebSocket messages其具体的特性非常之多,具体的内容可以从文档中了解到,笔者做一点自己的总结,Spring Session 的特性包括但不限于以下:
介绍完特性,下面开始一步步集成 Spring Session
Session 和 Cookie 这两个概念,在学习 java web 开发之初,大多数人就已经接触过了。最近在研究跨域单点登录的实现时,发现对于 Session 和 Cookie 的了解,并不是很深入,所以打算写两篇文章记录一下自己的理解。在我们的应用集成 Spring Session 之前,先补充一点 Session 和 Cookie 的关键知识。
由于 http 协议是无状态的协议,为了能够记住请求的状态,于是引入了 Session 和 Cookie 的机制。我们应该有一个很明确的概念,那就是 Session 是存在于服务器端的,在单体式应用中,他是由 tomcat 管理的,存在于 tomcat 的内存中,当我们为了解决分布式场景中的 session 共享问题时,引入了 redis,其共享内存,以及支持 key 自动过期的特性,非常契合 session 的特性,我们在企业开发中最常用的也就是这种模式。但是只要你愿意,也可以选择存储在 JDBC,Mongo 中,这些,spring 都提供了默认的实现,在大多数情况下,我们只需要引入配置即可。而 Cookie 则是存在于客户端,更方便理解的说法,可以说存在于浏览器。Cookie 并不常用,至少在我不长的 web 开发生涯中,并没有什么场景需要我过多的关注 Cookie。http 协议允许从服务器返回 Response 时携带一些 Cookie,并且同一个域下对 Cookie 的数量有所限制,之前说过 Session 的持久化依赖于服务端的策略,而 Cookie 的持久化则是依赖于本地文件。虽然说 Cookie 并不常用,但是有一类特殊的 Cookie 却是我们需要额外关注的,那便是与 Session 相关的 sessionId,他是真正维系客户端和服务端的桥梁。
spring,restful,前后端分离这些关键词都是大家耳熟能详的关键词了,一般 spring 常常需要与前端、第三方使用 JSON,XML 等形式进行交互,你也一定不会对 @RequestBody 和 @ResponseBody 这两个注解感到陌生。
Update your browser to view this website correctly.&npsb;Update my browser now