点击上方蓝色“方志朋”,选择“设为星标”

回复“666”获取独家整理的学习资料!

转自:RudeCrab,

链接:blog.csdn.net/RudeCrab/article/details/108317569

前言

登录认证,估计是所有系统中最常见的功能了,并且也是最基础、最重要的功能。为了做好这一块而诞生了许多安全框架,比如最常见的Shiro、Spring Security等。

本文是一个系列文章,最终的目的是想与大家分享在实际项目中如何运用安全框架完成登录认证(Authentication)、权限授权(Authorization)等功能。只不过一上来就讲框架的配置和使用我觉得并不好,一是对于新手来说会很懵逼,二是不利于大家对框架的深入理解。所以本文先写 手撸登录认证基本功能,下一篇文章再写 不用安全框架手撸权限授权,最后再写 如何运用安全框架整合这些功能。

本文会从最简单、最基础的讲解起,新手可放心食用。读完文章你能收获:

  • 登录认证的原理;

  • 如何使用 Session 和 JWT 分别完成登录认证功能;

  • 如何使用过滤器和拦截器分别完成对登录认证的统一处理;

  • 如何实现上下文对象。

本文所有代码全部放在了 Github 上,clone 下来即可运行查看效果。

基础知识

登录认证(Authorization)的概念非常简单,就是通过一定手段对用户的身份进行确认。

确认这还不容易?就是判断用户的账号和密码是否正确嘛,if、else 搞定。没错,这的确很容易,但是确认过后呢?要知道在web系统中有一个重要的概念就是:HTTP 请求是一个无状态的协议。就是说浏览器每一次发送的请求都是独立的,对于服务器来说你每次的请求都是“新客”,它不记得你曾经有没有来过。举一个例子大家就知道了:

A:你早上吃的啥?

B:小笼包。

A:味道咋样啊?

B:哈?啥味道咋样?!

无状态,也可以叫作无记忆,服务器不会记得你之前做了什么,它只会看到你当前的请求。所以,在Web系统中确认了用户的身份后,还需要有种机制来记住这个用户已经登录过了,不然用户每一次操作都要输入账号密码,那这系统也没法用了!

那怎样才能让服务器记住你的登录状态呢?那就是凭证!登录之后每一次请求都携带一个登录凭证来告诉服务器我是谁,这样才能有以下的效果:

A:你早上吃的啥?

B:小笼包。

A:你早上吃的小笼包味道咋样啊?

B:味道不错。

现在流行两种方式登录认证方式:SessionJWT,无论是哪种方式其原理都是 Token 机制,即保存凭证:

  1. 前端发起登录认证请求;

  2. 后端登录验证通过,返回给前端一个凭证

  3. 前端发起新的请求时携带凭证

接下来我们就上代码,用这两种方式分别实现登录认证功能。

实现

我们使用 SpringBoot 来搭建Web项目,只需导入 Web 项目依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

我们再建一个实体类用来模拟用户:

public class User{private String username;private String password;
}

Session

Session 是一种有状态的会话管理机制,其目的就是为了解决HTTP无状态请求带来的问题。

当用户登录认证请求通过时,服务端会将用户的信息存储起来,并生成一个 Session Id 发送给前端,前端将这个 Session Id 保存起来(一般是保存在 Cookie 中)。之后前端再发送请求时都携带 Session Id,服务器端再根据这个 Session Id 来检查该用户有没有登录过:

基本功能

接下来我们就用代码来实现具体功能,非常简单,我们只需要在用户登录的时候将用户信息存在 HttpSession 中就完成了:

@RestController
public class SessionController {@PostMapping("login")public String login(@RequestBody User user, HttpSession session) {// 判断账号密码是否正确,这一步肯定是要读取数据库中的数据来进行校验的,这里为了模拟就省去了if ("admin".equals(user.getUsername()) && "admin".equals(user.getPassword())) {// 正确的话就将用户信息存到session中session.setAttribute("user", user);return "登录成功";}return "账号或密码错误";}@GetMapping("/logout")public String logout(HttpSession session) {// 退出登录就是将用户信息删除session.removeAttribute("user");return "退出成功";}
}

在后续会话中,用户访问其他接口就可以检查用户是否已经登录认证:

@GetMapping("api")
public String api(HttpSession session) {// 模拟各种api,访问之前都要检查有没有登录,没有登录就提示用户登录User user = (User) session.getAttribute("user");if (user == null) {return "请先登录";}// 如果有登录就调用业务层执行业务逻辑,然后返回数据return "成功返回数据";
}@GetMapping("api2")
public String api2(HttpSession session) {// 模拟各种api,访问之前都要检查有没有登录,没有登录就提示用户登录User user = (User) session.getAttribute("user");if (user == null) {return "请先登录";}// 如果有登录就调用业务层执行业务逻辑,然后返回数据return "成功返回数据";
}

我们现在来测试一下效果,先不登录调用一下其他接口看看:

可以看到是调用失败的,那我们再进行登录:

登录成功后我们再调用刚才的接口:

这样就完成了基本的登录功能!是不是相当简单?

之前说过保持登录的核心就是凭证,可上面的代码也没看到传递凭证的过程呀,这是因为这些工作 Servlet 都帮我们做好了!

如果用户第一次访问某个服务器时,服务器响应数据时会在响应头的 Set-Cookie 标识里将 Session Id 返回给浏览器,浏览器就将标识中的数据存在 Cookie 中:

浏览器后续访问服务器就会携带 Cookie:

每一个 Session Id 都对应一个 HttpSession 对象,然后服务器就根据你这个 HttpSession 对象来检测你这个客户端是否已经登录了,也就是刚才代码里演示的那样。

有人可能会问,前后端分离一般都是用 Ajax 跨域请求后端数据,怎么携带 cookie 呢?这个很简单,只需要 Ajax 请求时设置 withCredentials=true 就可以跨域携带 cookie 信息了。

过滤器

完成了基本的登录认证后我们再加强一下功能!除了登录接口外,我们其他接口都要在 Controller 层里做登录判断,这太麻烦了。我们完全可以对每个接口过滤拦截一下,判断有没有登录,如果没有登录就直接结束请求,登录了才放行。这里我们通过过滤器来实现:

@Component
public class LoginFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 简单的白名单,登录这个接口直接放行if ("/login".equals(request.getRequestURI())) {filterChain.doFilter(request, response);return;}// 已登录就放行User user = (User) request.getSession().getAttribute("user");if (user != null) {filterChain.doFilter(request, response);return;}// 走到这里就代表是其他接口,且没有登录// 设置响应数据类型为json(前后端分离)response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();// 设置响应内容,结束请求out.write("请先登录");out.flush();out.close();}
}

这时我们 Controller 层就可以去除多余的登录判断逻辑了:

@GetMapping("api")
public String api() {return "api成功返回数据";
}@GetMapping("api2")
public String api2() {return "api2成功返回数据";
}

重启服务后我们再调用一下登录接口看下效果:

过滤器生效了!

上下文对象

在有些情况下,就算加了过滤器后我们现在还不能在 Controller 层将 Session 代码去掉!因为在实际业务中对用户对象操作是非常常见的,而我们的业务代码一般都写在 Service 业务层,那么我们 Service 层想要操作用户对象还得从 Controller 那传参过来,就像这样:

@GetMapping("api")
public String api(HttpSession session) {User user = (User) session.getAttribute("user");// 将用户对象传递给Service层userService.doSomething(user);return "成功返回数据";
}

每个接口都要这么写太麻烦了,有没有什么办法可以让我直接在 Service 层获取到用户对象呢?当然是可以的。我们可以通过 SpringMVC 提供的 RequestContextHolder 对象在程序任何地方获取到当前请求对象,从而获取我们保存在 HttpSession 中的用户对象。我们可以写一个上下文对象来实现该功能:

public class RequestContext {public static HttpServletRequest getCurrentRequest() {// 通过`RequestContextHolder`获取当前request请求对象return ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();}public static User getCurrentUser() {// 通过request对象获取session对象,再获取当前用户对象return (User)getCurrentRequest().getSession().getAttribute("user");}
}

然后我们在 Service 层直接调用我们写的方法就可以获取到用户对象啦:

public void doSomething() {User user = RequestContext.getCurrentUser();System.out.println("service层---当前登录用户对象:" + user);
}

我们再在 Controller 层直接调用 Service:

@GetMapping("api")
public String api() {// 各种业务操作userService.doSomething();return "api成功返回数据";
}

这样一套做好之后,看下前端成功调用 API 接口时的效果:

Service层成功获取上下文对象!

JWT

除了 Session 之外,目前比较流行的做法就是使用 JWT(JSON Web Token)。关于 JWT 网上有很多讲解资料,一个工具而已会用就行,所以在这里我就不过多解释这玩意了,大家只需要知道这两点就行:

  1. 可以将一段数据加密成一段字符串,也可以从这字符串解密回数据;

  2. 可以对这个字符串进行校验,比如有没有过期,有没有被篡改。

有两上面两个特性之后就可以用来做登录认证了。当用户登录成功的时候,服务器生成一个 JWT 字符串返回给浏览器,浏览器将JWT保存起来,在之后的请求中都携带上 JWT,服务器再对这个 JWT 进行校验,校验通过的话就代表这个用户登录了:

咦!这不和 Session 一样嘛,就是把 Session Id 换成了 JWT 字符串而已,这图啥啊。

没错,整体流程来说是一样的,我之前也说了,无论哪种方式其核心都是 Token 机制。但 Session 和 JWT 有一个重要的区别,就是 Session 是有状态的,JWT 是无状态的

说人话就是,Session 在服务端保存了用户信息,而 JWT 在服务端没有保存任何信息。当前端携带 Session Id 到服务端时,服务端要检查其对应的 HttpSession 中有没有保存用户信息,保存了就代表登录了。当使用 JWT 时,服务端只需要对这个字符串进行校验,校验通过就代表登录了。

至于这两种方式各有什么好处和坏处先别着急讨论,咱先将 JWT 用起来!两者的优缺点文章最后会做讲解滴。

基本功能

要用到 JWT 先要导入一个依赖项:

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>

为了方便使用,我们先写一个 JWT 的工具类,工具类就提供两个方法一个生成一个解析 :

public final class JwtUtil {/*** 这个秘钥是防止JWT被篡改的关键,随便写什么都好,但决不能泄露*/private final static String secretKey = "whatever";/*** 过期时间目前设置成2天,这个配置随业务需求而定*/private final static Duration expiration = Duration.ofHours(2);/*** 生成JWT* @param userName 用户名* @return JWT*/public static String generate(String userName) {// 过期时间Date expiryDate = new Date(System.currentTimeMillis() + expiration.toMillis());return Jwts.builder().setSubject(userName) // 将userName放进JWT.setIssuedAt(new Date()) // 设置JWT签发时间.setExpiration(expiryDate)  // 设置过期时间.signWith(SignatureAlgorithm.HS512, secretKey) // 设置加密算法和秘钥.compact();}/*** 解析JWT* @param token JWT字符串* @return 解析成功返回Claims对象,解析失败返回null*/public static Claims parse(String token) {// 如果是空字符串直接返回nullif (StringUtils.isEmpty(token)) {return null;}// 这个Claims对象包含了许多属性,比如签发时间、过期时间以及存放的数据等Claims claims = null;// 解析失败了会抛出异常,所以我们要捕捉一下。token过期、token非法都会导致解析失败try {claims = Jwts.parser().setSigningKey(secretKey) // 设置秘钥.parseClaimsJws(token).getBody();} catch (JwtException e) {// 这里应该用日志输出,为了演示方便就直接打印了System.err.println("解析失败!");}return claims;}
}

工具类做好之后我们可以开始写登录接口了,和之前大同小异:

@RestController
public class JwtController {@PostMapping("/login")public String login(@RequestBody User user) {// 判断账号密码是否正确,这一步肯定是要读取数据库中的数据来进行校验的,这里为了模拟就省去了if ("admin".equals(user.getUsername()) && "admin".equals(user.getPassword())) {// 如果正确的话就返回生成的token(注意哦,这里服务端是没有存储任何东西的)return JwtUtil.generate(user.getUsername());}return "账号密码错误";}
}

在后续会话中,用户访问其他接口时就可以校验 token 来判断其是否已经登录。前端将 token 一般会放在请求头的 Authorization 项传递过来,其格式一般为类型 + token。这个倒也不是一定得这么做,你放在自己自定义的请求头项也可以,只要和前端约定好就行。这里我们方便演示就将 token 直接放在 Authorization 项里了:

@GetMapping("api")
public String api(HttpServletRequest request) {// 从请求头中获取token字符串String jwt = request.getHeader("Authorization");// 解析失败就提示用户登录if (JwtUtil.parse(jwt) == null) {return "请先登录";}// 解析成功就执行业务逻辑返回数据return "api成功返回数据";
}@GetMapping("api2")
public String api2(HttpServletRequest request) {String jwt = request.getHeader("Authorization");if (JwtUtil.parse(jwt) == null) {return "请先登录";}return "api2成功返回数据";
}

接下来我们测试一下效果,先进行登录:

可以看到登录成功后服务器返回了 token 过来,然后我们将这个token设置到请求头中再调用其他接口看看效果:

可以看到成功返回数据了!我们再试一下不携带token和篡改token后调用其他接口会怎样:

可以看到,没有携带 token 或者私自篡改了 token 都会验证失败!

拦截器

和之前一样,如果每个接口都要手动判断一下用户有没有登录太麻烦了,所以我们做一个统一处理,这里我们换个花样用拦截器来做:

public class LoginInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 简单的白名单,登录这个接口直接放行if ("/login".equals(request.getRequestURI())) {return true;}// 从请求头中获取token字符串并解析Claims claims = JwtUtil.parse(request.getHeader("Authorization"));// 已登录就直接放行if (claims != null) {return true;}// 走到这里就代表是其他接口,且没有登录// 设置响应数据类型为json(前后端分离)response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();// 设置响应内容,结束请求out.write("请先登录");out.flush();out.close();return false;}
}

拦截器类写好之后,别忘了要使其生效,这里我们直接让 SpringBoot 启动类实现WevMvcConfigurer 接口来做:

@SpringBootApplication
public class LoginJwtApplication implements WebMvcConfigurer {public static void main(String[] args) {SpringApplication.run(LoginJwtApplication.class, args);}@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 使拦截器生效registry.addInterceptor(new LoginInterceptor());}
}

这样就能省去接口中校验用户登录的逻辑了:

@GetMapping("api")
public String api() {return "api成功返回数据";
}@GetMapping("api2")
public String api2() {return "api2成功返回数据";
}

可以看到,拦截器已经生效了!

上下文对象

统一拦截做好之后接下来就是我们的上下文对象,JWT 不像 Session 把用户信息直接存储起来,所以 JWT 的上下文对象要靠我们自己来实现。

首先我们定义一个上下文类,这个类专门存储 JWT 解析出来的用户信息。我们要用到 ThreadLocal,以防止线程冲突:

public final class UserContext {private static final ThreadLocal<String> user = new ThreadLocal<String>();public static void add(String userName) {user.set(userName);}public static void remove() {user.remove();}/*** @return 当前登录用户的用户名*/public static String getCurrentUserName() {return user.get();}
}

这个类创建好之后我们还需要在拦截器里做下处理:

public class LoginInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {...省略之前写的代码// 从请求头中获取token字符串并解析Claims claims = JwtUtil.parse(request.getHeader("Authorization"));// 已登录就直接放行if (claims != null) {// 将我们之前放到token中的userName给存到上下文对象中UserContext.add(claims.getSubject());return true;}...省略之前写的代码}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 请求结束后要从上下文对象删除数据,如果不删除则可能会导致内存泄露UserContext.remove();super.afterCompletion(request, response, handler, ex);}
}

这样一个上下文对象就做好了,用法和之前一样,可以在程序的其他地方直接获取到数据,我们在 Service 层中来使用它:

public void doSomething() {String currentUserName = UserContext.getCurrentUserName();System.out.println("Service层---当前用户登录名:" + currentUserName);
}

然后 Controller 层调用 Service 层:

@GetMapping("api")
public String api() {userService.doSomething();return "api成功返回数据";
}

这样一套做好之后,看下前端成功调用 API 接口时的效果:

控制台成功打印了!

补充

代码到此就完成了!就像开头所说,本文只是讲解了基本的登录认证功能实现,还有很多很多细节没有提及,比如密码加密、防 XSS/CSRF 攻击等。接下来我要补充的也不是这些细节,而是补充一些其他的基础知识,帮助大家更好的理解本文讲解的内容!

注意事项

本文为了方便演示省略了很多非登录认证核心的相关代码,比如在统一处理中如果发现用户没有登录应该是直接抛出自定义异常,然后由异常全局处理返回给前端统一的数据响应体,而不是像我们现在代码中一样直接用 PrintWriter 输出流输出数据。关于这方面可以参考我之前写的博客进行改造:【项目实践】SpringBoot三招组合拳,手把手教你打出优雅的后端接口。

再有就是 JWT 的相关注意点。通过代码看到生成一个 JWT 字符串很简单,谁都可以生成。然后字符串这东西也谁都可以篡改,我们怎么保证这个字符串就是我们系统签发出去的呢?又怎么保证我们签发出去的字符串有没有被篡改呢? 其中关键点就是工具类里写的 secretKey 属性了。JWT 根据这个秘钥会生成一个独特的字符串,别人没有这个秘钥的话是无法伪造或篡改 JWT 的!所以这个秘钥是重中之重,在实际开发中一定要谨防泄露:开发环境下设置一个秘钥,生产环境设置一个秘钥,这个生产环境下的秘钥还要严防死守,可以通过配置中心来配置并且要防止开发人员在代码中打印出秘钥!

我们代码中演示的 JWT 是只存放了用户名,实际开发中你想存什么就存什么,不过一定不要存敏感信息(比如密码)!因为 JWT 只能防止被篡改,不能防止别人解密你这个字符串!

Session 和 JWT 的优劣

两种方式都可以实现登录认证,那么在实际开发中到底用哪一种估计是大家比较关心的问题!在这里我就简单说明一下两者各自的优劣,至于具体选型就根据自己实际业务需求来了。首先说一下两者的优点

Session 的优点:

  • 开箱即用,简单方便;

  • 能够有效管理用户登录的状态:续期、销毁等(续期就是延长用户登录状态的时间,销毁就是清楚用户登录状态,比如退出登录)。

JWT 的优点:

  • 可直接解析出数据,服务端无需存储数据;

  • 天然地易于水平扩展(ABC 三个系统,我同一个 Token 都可以登录认证,非常简单就完成了单点登录)。

再说一下缺点

Session 的缺点:较JWT而言,需要额外存储数据。

JWT 的缺点:

  • JWT 签名的长度远比一个 Session Id长很多,增加额外网络开销;

  • 无法销毁、续期登录状态;

  • 秘钥或 Token 一旦泄露,攻击者便可以肆无忌惮操作我们的系统。

其实上面说的这些优缺点都可以通过一些手段来解决,就看自己取舍了!比如 Session 就不易于水平扩展吗?当然不是,无论是 Session 同步机制还是集中管理都可以非常好的解决。再比如 JWT 就真的无法销毁吗?当然也不是,其实可以将 Token 也在后端存储起来让其变成有状态的,就可以做到状态管理了!

软件开发没有银弹,技术选型根据自己业务需求来就好,千万不要单一崇拜某一技术而排斥其他同类技术!

收尾

OK,文章到这就要结束了!本文重点不是具体的代码,而是登录认证的基本原理!原理搞懂了,不管什么方式都是大同小异。

本文所有代码都放在了 Github 上,clone 下来即可运行查看效果!如果对你有帮助麻烦点个 Star 哦,我会持续更多【项目实践】的!

下一篇文章就开始写如何实现权限授权功能,也是从最最简单的知识讲起,轻松无压力看到最后就会发现自己已经会了!


http://www.taodudu.cc/news/show-122282.html

相关文章:

  • 为什么建议使用你 LocalDateTime ,而不是 Date?
  • 监控、链路追踪、日志这三者有何区别?
  • 还分不清 Cookie、Session、Token、JWT?
  • 当Docker遇到Intellij IDEA,再次解放了生产力~
  • Guava 中的 Stopwatch 是个什么鬼?
  • Mybatis接口Mapper内的方法为啥不能重载?
  • 看看人家那后端API接口写得,那叫一个优雅!
  • Spring 中的bean 是线程安全的吗?
  • 有了这个 IDEA的兄弟,你还用 Navicat 吗?全家桶不香吗?
  • SpringBoot集成Quartz实现定时任务的动态创建、启动、暂停、恢复、删除。
  • 写了个牛逼的日志切面,甩锅更方便了!
  • 老板:kill -9的原理都不知道就敢到线上执行,明天不用来了
  • 两天标星2.2K!GitHub 开源自动刷喵币项目?
  • 你还在认为 count(1) 比 count(*) 效率高?
  • Spring Boot 打包不同环境配置与 Shell 脚本部署
  • 一份 Spring Boot 项目搭建模板
  • 讨论:Service层需要接口吗?
  • 必须了解的 MySQL 三大日志
  • jar包又冲突了?如何快速确定与哪个jar包冲突?
  • 面试官扎心一问:知道 CopyOnWriteArrayList 吗?
  • 自从上线了 Prometheus 监控告警,真香!
  • 卸载Notepad++!事实已证明,它更牛逼……
  • 教你如何通过分析GC日志来进行JVM调优
  • 一个 SpringBoot 项目该包含哪些?
  • 非常有必要了解的Springboot启动扩展点
  • 星巴克不使用两阶段提交
  • 怎么去掉 IDEA 中 XML 显示的屎黄色
  • 后端必备 Git 分支开发:规范指南
  • 如何优雅的转换 Bean 对象!
  • 你还在用Swagger?试试这个神器!

在用安全框架前,我想先让你手撸一个登陆认证相关推荐

  1. 很多小伙伴不太了解ORM框架的底层原理,这不,冰河带你10分钟手撸一个极简版ORM框架(赶快收藏吧)

    大家好,我是冰河~~ 最近很多小伙伴对ORM框架的实现很感兴趣,不少读者在冰河的微信上问:冰河,你知道ORM框架是如何实现的吗?比如像MyBatis和Hibernate这种ORM框架,它们是如何实现的 ...

  2. 【RPC框架、RPC框架必会的基本知识、手写一个RPC框架案例、优秀的RPC框架Dubbo、Dubbo和SpringCloud框架比较】

    一.RPC框架必会的基本知识 1.1 什么是RPC? RPC(Remote Procedure Call --远程过程调用),它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络的技术. ...

  3. 如何手撸一个较为完整的RPC框架?

    点击关注公众号,实用技术文章及时了解 来源:juejin.cn/post/6992867064952127524 缘起 最近在公司分享了手撸RPC,因此做一个总结. 概念篇 RPC 是什么? RPC ...

  4. 如何手撸一个较为完整的RPC框架

    [文章作者/来源]一个没有追求的技术人/https://sourl.cn/sJ4Brp 缘 起 最近在公司分享了手撸RPC,因此做一个总结. 概 念 篇 RPC 是什么? RPC 称远程过程调用(Re ...

  5. 从零开始手撸一个热修复框架

    1.前言 热修复原理,这个一直是这几年来很热门的话题,在项目中使用的话,也基本要么是阿里系或者腾讯系的开源框架.但是作为一个光会使用的程序员是远远不够的.这篇文章会从dex分包的原因,原理,热修复的由 ...

  6. 手撸一个RPC框架——傻瓜式教程(一)

    RPC框架-傻瓜式教程(一) 前言,太久没写博客了,有点手生,总结一下自己对RPC框架的学习过程 首先我们知道RPC的全名是,全程服务调用,我们用它来做什么,简单地说就是客户端通过接口调用服务端的函数 ...

  7. 经典项目|手撸一个高质量RPC框架

    hi, 大家好,RPC是后端系统节点之间通信的核心技术,属于后端开发必须要学习的技能. 后端技术趋势指南|如何选择自己的技术方向 如何从0搭建公司的后端技术栈 远程过程调用(Remote Proced ...

  8. 【限流02】限流算法实战篇 - 手撸一个单机版Http接口通用限流框架

    本文将从需求的背景.需求分析.框架设计.框架实现几个层面一步一步去实现一个单机版的Http接口通用限流框架. 一.限流框架分析 1.需求背景 微服务系统中,我们开发的接口可能会提供给很多不同的系统去调 ...

  9. 面试官让我手写一个RPC框架

    如今,分布式系统大行其道,RPC 有着举足轻重的地位.Dubbo.Thrift.gRpc 等框架各领风骚,学习RPC是新手也是老鸟的必修课.本文带你手撸一个rpc-spring-starter,深入学 ...

最新文章

  1. CentOS 6.0安装VNC Server
  2. Ubuntu14.04重启网卡不生效
  3. mysql 5.6到percona 5.6小版本升级
  4. gzip(来源百度百科)
  5. 读取模式错误,计算引擎操作复杂……面对Hadoop这些问题该如何应对?
  6. 请把ios文件解压出来是什么意思_【张小亮】最新版本行会3。中文版本。解压即玩。...
  7. ZENG msgbox仿qq提示
  8. API 接口 并发测试 Jmeter Postman
  9. excel中多条件求和_在Excel中求和的7种方法
  10. 【懒人神器】鼠标自动连续点击器免费下载
  11. pyqt获得鼠标_PyQt5编程:鼠标事件
  12. [参文]GCN+交通
  13. 使用git中rebase遇到的坑二 could not apply xxxx
  14. android pie新功能,Android Pie:3个隐藏功能 | MOS86
  15. 南京大学软件学院2018保研夏令营经验
  16. JavaScript 逆向爬取实战
  17. 方差、协方差、协方差矩阵的概念及意义 的理解
  18. Oracle常用函数大全
  19. 尚硅谷大数据技术Spark教程-笔记01【Spark(概述、快速上手、运行环境、运行架构)】
  20. 计算机组成原理的基本知识

热门文章

  1. 阶段1 语言基础+高级_1-3-Java语言高级_02-继承与多态_第5节 final关键字_5_final关键字用于修饰成员变量...
  2. python基础类型
  3. WPF入门教程-转载
  4. MySQL主从复制的常用拓扑结构
  5. [转载]Using ngOptions In AngularJS
  6. 使用 fcntl 函数 获取,设置文件的状态标志
  7. MiniGUI - UNIX Domain Socket 封装
  8. 浅浅认识之VBS脚本访问接口与COMODO拦截COM接口
  9. 【直播】张晋:心跳信号分类模型融合
  10. mysql 亿级表count_码云社 | 砺锋科技-MySQL的count(*)的优化,获取千万级数据表的总行数 - 用代码改变世界...