如何实现API接口的幂等性
幂等性什么是幂等性在实际的开发项目中,一个对外暴露的接口往往会面临很多次请求。这就需要考虑到一个幂等性问题。
幂等的数学概念幂等是源于一种数学概念。其主要有两个定义
如果在一元运算中,x 为某集合中的任意数,如果满足 f(x) = f(f(x)) ,那么该 f 运算具有幂等性,比如绝对值运算 abs(a) = abs(abs(a)) 就是幂等性函数。
如果在二元运算中,x 为某集合中的任意数,如果满足 f(x,x) = x,前提是 f 运算的两个参数均为 x,那么我们称 f 运算也有幂等性,比如求大值函数 max(x,x) = x 就是幂等性函数。
幂等性在开发中的概念在数学中幂等的概念或许比较抽象,但是在开发中幂等性是极为重要的。简单来说,对于同一个系统,在同样条件下,一次请求和重复多次请求对资源的影响是一致的,就称该操作为幂等的。比如说如果有一个接口是幂等的,当传入相同条件时,其效果必须是相同的。
特别是对于现在分布式系统下的 RPC 或者 Restful 接口互相调用的情况下,很容易出现由于网络错误等等各种原因导致调用的时候出现异常而需要重 ...
SpringBoot 全局异常处理的几种常见姿势
异常处理方式的发展web.xml在还没有Spring的时候,开发使用的是原生的Servlet + tomcat容器。那个时候就提供了通用的异常的处理配置方式的:在web.xml里进行如下配置:
1234567891011<!-- 根据状态码 --><error-page> <error-code>500</error-code> <location>/500.jsp</location></error-page><!-- 根据异常类型 --><error-page> <exception-type>java.lang.RuntimeException</exception-type> <location>/500.jsp</location></error-page>
SpringMVCSpring MVC提供处理异常的方式主要分为两种:
实现HandlerExceptionResolver方式
@Exc ...
结合AOP和SpEL表达式实现日志切面
需求结合AOP技术和SpEL表达式实现一个简单的AOP切面
计算耗时,并打印日志
用户可以在注解中添加指定的字段名称,切面自动解析出值,放在日志里一起打印。
示例:在添加注解的时候,指定bizCode = "#msg",那么在方法被调用的时候,就会计算变量articleId在当前上下文中的值,并在日志中打印出来。
123456@MdcDot(bizCode = "#articleId")@RequestMapping("/hello")public String sayHello(String articleId) { System.out.println("Hello, World :" + articleId); return "success";}
测试效果如下:
实现定义注解MdcDot123456789101112import java.lang.annotation.Documented;import java.lang.annotat ...
Spring AOP在什么场景下会失效?
刚刚遇到了Spring AOP失效的问题,趁这个机会总结一下~
什么是Spring AOPSpring AOP是Spring框架中的一个重要组成部分,它提供了一种面向切面编程(Aspect-Oriented Programming, AOP)的实现方式。AOP的核心思想是将那些分布在多个对象或方法中的共同行为(即横切关注点)提取出来,形成一个独立的模块,称为“切面”(Aspect)。这样做的好处是可以增强的代码模块化,减少重复代码,提高系统的可维护性和可扩展性。
AOP基于什么实现Spring AOP 的实现主要基于动态代理和字节码增强两种技术。
首先,Spring AOP利用动态代理技术在运行时生成代理对象,这些代理对象能够拦截对目标对象的调用,并在调用前后执行切面逻辑。具体来说,如果目标对象实现了接口,Spring AOP会使用JDK动态代理来生成代理对象;而如果目标对象没有实现接口,Spring AOP则会使用CGLIB动态代理来生成代理对象。
其次,Spring AOP还利用了AspectJ框架来实现字节码增强。这是一种在编译时或运行时修改目标对象的字节码的技术,以此来插入 ...
如何搭建一个社区系统 —— 4. Filter之全局上下文与全链路traceId
在项目中,我们使用拦截器filter拦截所有的web请求,主要做以下两件事情:
实现用户身份识别,并将识别出来的用户信息,保存到ThreadLocal对应的上下文中,这样在后续的请求链路中,在任何地方都可以直接获取当前的登录用户,从而减少查询数据库的次数。
打印请求日志,记录请求耗时,通过MDC添加全链路的traceId,方便追踪定位。
Filter基础知识Filter称为过滤器,主要用来拦截http请求,在请求之前或者之后做一些事情。
Filter和Interceptor的区别:
具体的流程如下所示:
filter的应用场景主要包括:
在filter层,来获取用户的身份
可以考虑在filter层做一些常规的校验(如参数校验,referer校验、权限控制等)
可以在filter层做运维、安全防护相关的工作(如全链路打点,可以在filter层分配一个traceld;也可以在这一层做限流等)
具体做法
在过滤器的doFilter方法中,分为三部分:
doBefore:表示将请求转发到Controller执行之前
记录开始执行时间
记录请求相关信息(ThreadLocal变 ...
如何搭建一个社区系统 —— 3. 如何进行登录认证
登录认证永远是社区网站最核心的功能之一。本文从无状态的HTTP协议讲起,详细梳理了Cookie、Session、Token、JWT等相关技术,并给出本项目的做法。
无状态的HTTP协议HTTP 无状态协议,是指协议对于业务处理没有记忆能力,每次请求都是完全独立互不影响的,没有任何上下文信息。假如一直用这种原生无状态的 HTTP 协议,我们每换一个页面可能就得重新登录一次,这肯定是不行的。那么如何做呢?
在客户端第一次请求之后,服务端生成并向客户端分配唯一标识,然后后续客户端请求服务端的时候,只需要携带者唯一标识就可以了,如下图所示:
Cookie方案Cookie的概念HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据。它会在浏览器下次向同一服务器再发起请求时,被携带并发送到服务器上。通常 Cookie 用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。
Cookie 主要用于以下三个方面:
会话状态管理(如用户登录状态 ...
如何搭建一个社区系统 —— 2. 使用MyBatis-Plus进行CRUD
MyBatis-Plus是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。使用MyBatis-Plus能够极大地提升开发效率。
IService和BaseMapper辨析查看MyBatis-Plus的文档,我们可以发现,在其内部存在着两种CRUD操作接口,Iservice和BaseMapper,如果只是用增删改查,会发现除了方法名称不同外,两者的功能是一致的。那如何在开发中进行合理的选择?
我们先来看一下官网的描述:
Service CRUD 接口
通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用 get 查询单行 remove 删除 list 查询集合 page 分页 前缀命名方式区分 Mapper 层避免混淆,
泛型 T 为任意实体对象
建议如果存在自定义通用 Service 方法的可能,请创建自己的 IBaseService 继承 Mybatis-Plus 提供的基类
对象 Wrapper 为 条件构造器
Mapper CRUD接口
通用 CRUD 封装BaseMapper接 ...
如何搭建一个社区系统 —— 1. 数据库设计
针对社区的特点,本应用分为五个模块:
用户模块
文章模块
评论模块
消息模块
通用模块
下面针对具体的模块进行分析。
用户模块整个用户模块从功能上可以分为:
注册登录
权限管理
业务逻辑
注册登录注册登录除了常见的用户名+密码登录的方式之外,还有手机号+验证码、邮箱+验证码、第三方授权登录等。这里我们采用的是微信公众号登录方式。主要的考量是用户会觉得更加安全与方便(既不需要使用手机号,也不用担心密码泄露)。因为是个人公众号,不能实现扫码自动登录,我们采取的策略是:
用户点击登录,登录页显示二维码+验证码–>用户关注公众号,将登录页面上的验证码输入到微信公众号->自动登录。
库表设计如下:
12345678910111213CREATE TABLE `user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', `third_account_id` varchar(128) NOT NULL DEFAULT '' COMMENT '第 ...
如何实现Java采样性能分析器?以Async-Profiler为例探析
本系列试图全面分析Async-Profiler的源码逻辑,目的在于熟悉JVM API、熟悉Profile、熟悉C++编程。欢迎一起交流~
文章框架
下载Async-Profiler1.1源码,编译,尝试profile相关功能
导入CLion,修改makefile为CMakeLists,导入include文件夹,解决IDE不能识别头文件问题
阅读交互脚本profile.sh,理解命令的输入与入口函数
阅读jattach.c源码,这是项目的入口,理解注入,创建socket,连接JVM,将动态库libasyncProfiler.so Attach到JVM上。
阅读vmEntry.h,这是Attach后的入口逻辑。
未完待续,敬请期待
Hotspot中的JNI数据类型
基本数据类型
123456789101112//jni.h//如果没在jni_md.h中定义好的话#ifndef JNI_TYPES_ALREADY_DEFINED_IN_JNI_MD_H//就使用下面的定义typedef unsigned char jboolean;typedef unsigned short jchar;typedef short jshort;typedef float jfloat;typedef double jdouble;typedef jint jsize;
接下来,我们找到找到jnt_md.h中的数据定义。 jni_md.h 包含了针对 jbyte、jint 和 jlong 的机器相关的类型定义。
12345678910111213141516//jni.md.h#ifdef TARGET_ARCH_x86 // 我们的环境是这个# include "jni_x86.h"#endif#ifdef TARGET_ARCH_sparc# includ ...