在线教育后端开发项目总结

文章目录

  • 一 数据库访问接口
    • 1 MyBatis
    • 2 Spring Data JPA
    • 3 Spring Data MongoDB
  • 二 数据库
    • 1 MySQL
    • 2 MongoDB
    • 3 Redis
  • 三 开发规范化、响应格式与异常处理
    • 1 开发规范
    • 2 响应格式
    • 3 异常处理
  • 四 RabbitMQ
  • 五 Spring Cloud 相关工具
    • 1 Eureka
    • 2 Ribbon
    • 3 Feign
    • 4 Zuul 网关
  • 六 搜索服务
    • 1 ElasticSearch
    • 2 Logstash
  • 七 用户认证与授权
    • 1 Spring Security OAuth2
    • 2 JWT(Json Web Token)
    • 3 单点登录和身份校验
    • 4 用户授权 RBAC(Role-Based Access Control)


一 数据库访问接口

1 MyBatis

  • 用于写相对复杂(多表连接的) SQL 命令
  • 使用时,用 @Mapper 注释 xxMapper 接口,在接口中定义方法,并创建同名的 xxMapper.xml 文件,在方法对应的标签存放 SQL 命令
  • 更多关于 MyBatis

2 Spring Data JPA

  • Spring 提供的操作 MySQL 单张数据表的 API,无需自行编写 SQL
  • 接口一般命名为 xxRepository
public interface TeachplanRepository extends JpaRepository<Teachplan, String> {/*** 根据课程id 和 parent id 查询课程计划*/List<Teachplan> findByCourseidAndParentid(String courseId, String parentId);
}
  • 需要对数据表对应的类加一系列注解(不止如下所示)
    在这里插入图片描述

3 Spring Data MongoDB

  • 使用方法类似于 Spring Data JPA,需要通过对类的注释,实现模型-表的映射
// 数据表对应的类
@Document(collection = "filesystem")
public class FileSystem {// 省略表的一系列属性...
}// dao
public interface FileSystemRepository extends MongoRepository<FileSystem, String> {
}

二 数据库

1 MySQL

  • InnoDB 存储引擎:
    索引结构是B+树(和B树相比查询效率更稳定,I/O次数少,对范围查找的支持更好
    实现了行级锁
    支持外键
  • 一些优化措施:
    查询操作时,只返回需要的行或列
    尽量不在数据表中存储 NULL,不在 SQL 命令的条件中判断 NULL
    字段的数据类型定义准确
    设计数据表时遵循范式规则 1/2/3NF
    对数据表进行适当的行、列拆分
  • 索引分类:
    主索引/二级索引
    聚簇索引/非聚簇索引…
  • 如果没有主键也没有合适的唯一索引,那么 InnoDB 内部会生成一个隐藏的主键作为聚集索引,这个隐藏的主键是一个6个字节的列,该列的值会随着数据的插入自增

2 MongoDB

  • NoSQL 的一种,以类 Json 的文档格式存储数据,文档型数据库
  • 本项目中负责存放一系列的页面信息
  • 索引结构是B树
  • 不具有 MySQL 的完善的事务特性,在本项目中用于存储非核心数据

在这里插入图片描述

3 Redis

  • NoSQL 的一种,一般作为缓存数据库辅助持久化的数据库
  • 本项目中负责存放登录用户的 (access_token, JWT + refresh_token) 的键值对
  • 拥有两种持久化机制:RDB 和 AOF,其特性查阅链接
  • 项目中使用 StringRedisTemplate 操作 Redis
  • 更多关于 Redis

三 开发规范化、响应格式与异常处理

1 开发规范

  • get 请求时,采用 key/value 格式请求,SpringMVC 可采用基本类型的变量接收,也可以采用对象接收
  • post 请求时,可以提交 form 表单数据(application/x-www-form-urlencoded)和 Json 数据(application/json),文件等多部件类型(multipart/formdata)三种数据格式,SpringMVC 接收 Json 数据
  • Controller 主要作为响应 URL 的接口(粘合剂的作用),业务逻辑实现放在 Service 层,DAO 仅仅负责与数据库交互而不考虑任何业务逻辑

2 响应格式

  • 设置枚举类型的响应代码
public enum CommonCode implements ResultCode {SUCCESS(true,10000,"操作成功!"),FAIL(false,11111,"操作失败!"),UNAUTHENTICATED(false,10001,"此操作需要登陆系统!"),UNAUTHORISE(false,10002,"权限不足,无权操作!"),SERVER_ERROR(false,99999,"抱歉,系统繁忙,请稍后重试!"),INVALIDPARAM(false, 10003, "参数非法");// ...
}
  • 针对不同的客户端请求,返回对应的一致的类型:查询返回 QueryResponseResult,添加返回 ResponseResult

3 异常处理

  • 设置枚举类型的异常代码,写入异常编号和异常信息
  • 使用统一的类抛出(使用静态方法包装)和捕获异常(使用 SpringMVC 提供的 @ControllerAdvice 注解类 和 @ExceptrionHandler 注解方法)
  • 自定义异常类型继承自 RuntimeException,属于 unchecked 异常,不捕获仍然可以运行,实际交给增强控制器完成捕获
// 异常抛出:使用静态方法包装
public class ExceptionCast {public static void cast(ResultCode resultCode) {throw new CustomException(resultCode);}
}// 异常捕获:使用Spring提供的 @ControllerAdvice注解类 和 @ExceptrionHandler注解方法
@ControllerAdvice
public class ExceptionCatch {private static final Logger LOGGER = LoggerFactory.getLogger(CustomException.class);private static ImmutableMap<Class<? extends Throwable>, ResultCode> EXCEPTIONS;//使用builder来构建一个异常类型和错误代码的异常protected static ImmutableMap.Builder<Class<? extends Throwable>,ResultCode> builder = ImmutableMap.builder();static{// 加入一些基础的异常类型判断...builder.put(HttpMessageNotReadableException.class, CommonCode.INVALIDPARAM);}// 处理自定义异常,形参为捕获异常类型@ExceptionHandler@ResponseBodypublic ResponseResult customException(CustomException customException) {ExceptionCatch.LOGGER.error("捕获到自定义异常");ResultCode resultCode = customException.getResultCode();return new ResponseResult(resultCode);}// 处理不可预料异常@ExceptionHandler@ResponseBodypublic ResponseResult exception(Exception e) {if (ExceptionCatch.EXCEPTIONS == null) {EXCEPTIONS = ExceptionCatch.builder.build();  // 构建map}ResultCode resultCode = ExceptionCatch.EXCEPTIONS.get(e.getClass());if (resultCode != null) {// map中有该异常类型return new ResponseResult(resultCode);} else {// 没有,返回99999return new ResponseResult(CommonCode.SERVER_ERROR);}}
}

四 RabbitMQ

  • 项目中简单用到了 routing 模式,生产者发送消息时需要指定 routing key,交换机会根据 routing key 将消息投递到指定的队列
  • 使用消息队列的主要优点:解耦、异步、削峰(因为 MQ 短时间积压数据是可以接受的)
  • RabbitMQ 结构:
    在这里插入图片描述

五 Spring Cloud 相关工具

1 Eureka

  • 注册中心
    微服务数量众多,要进行远程调用就需要知道服务端的 IP 地址和端口,注册中心帮助管理这些服务的 IP 和端口
    注册的微服务会向注册中心实时上报自己的状态,注册中心统一管理这些微服务的状态
    将存在问题的服务踢出服务列表,客户端获取可用的服务进行调用
  • 注册中心同样属于一个微服务,它的启动类要加上注解 @EnableEurekaServer
  • 对于要向注册中心注册的微服务,需要在启动类加注解 @EnableDiscoveryClient,表示它是一个 Eureka 的客户端,用于发现其它微服务
  • 高可用 Eureka 需要两个注册中心相互注册,即使其中一台停机也不会影响服务的注册和发现
  • 启动后访问指定端口就可以便捷地检测微服务情况,本项目为 50101 和 50102

2 Ribbon

  • 执行客户端的负载均衡(而非 Nginx 这种服务端的负载均衡),Ribbon 先从 EurekaServer 中获取服务列表,根据负载均衡的算法去调用微服务
  • Spring Cloud 引入 Ribbon 配合 RestTemplate (本项目使用 okhttp 进行远程调用)实现客户端负载均衡
  • RestTemplate 是 Spring 提供的一个访问 HTTP 服务的客户端类,微服务之间的调用需要使用 RestTemplate
  • 使用方法:
    1、添加相关依赖并配置
    2、创建 resttemplate 的 bean,使用 @LoadBalanced 注解
    在这里插入图片描述
    3、服务名代替 IP 地址+端口号,发挥注册中心的作用(不用手动写入 IP 地址+端口号 而交给注册中心管理),后面拼接相应 Controller 方法路径
    在这里插入图片描述

3 Feign

  • 可以实现 像调用本地接口一样调用远程接口 ,这个远程接口指的是在注册中心注册过的某个微服务提供的 Controller 方法
  • 内部集成了 Ribbon,可以实现客户端负载均衡
  • 使用方法:
    使用@EnableFeignClients 注解启动类,Spring 会扫描标记了 @FeignClient 注解的接口,生成代理对象
    使用 @FeignClient 注解客户端接口,并指定该接口绑定的微服务名(指定后 Feign 会从注册中心获取服务列表,并通过负载均衡算法进行服务调用
    如果接口的方法返回类型为对象,则该类型必须有无参构造器
    Feign 根据接口方法的注解的 URL,进行远程调用
@FeignClient(name = "XC-SERVICE-MANAGE-CMS")  // 指定该接口绑定的微服务名
public interface CmsPageClient {@GetMapping("/cms/page/get/{id}")CmsPage findById(@PathVariable("id") String id);
}

4 Zuul 网关

在这里插入图片描述

  • 网关在微服务前边设置一道屏障,请求先到服务网关,网关会对请求进行过滤、校验、路由等处理。有了服务网关可以提高微服务的安全性,网关校验请求的合法性,请求不合法将被拦截,拒绝访问
  • 用网关的好处是,无论调用哪个微服务,客户端所有的请求都访问网关的 IP 地址和端口号,由网关使用 Eureka 负责将请求路由到指定的微服务(因为 Zuul 的配置了 Eureka 中各种微服务的 ID)
zuul:routes:manage‐course: #路由名称,名称任意,保持所有路由名称唯一path: /course/**serviceId: xc‐service‐manage‐course # 从Eureka中找到服务的ip和端口# url: http://localhost:31200 # 也可转发到指定urlstrip‐prefix: false #true:代理转发时去掉前缀sensitiveHeaders: # 默认zuul会屏蔽cookie,不会传到下游服务,设置为空则取消屏蔽,如果设置了具体的头信息则不会传到下游服务# ignoredHeaders: Authorization  # 可以设置过滤的头信息,默认为空表示不过滤任何头,jwt要放在header中所以要关闭该功能

六 搜索服务

1 ElasticSearch

  • 在项目中实现课程搜索的功能,应用流程:
    1、用户在前端搜索关键字,前端通过 HTTP 方式请求项目服务端
    2、项目服务端通过 RESTful 方式请求 ES 集群进行搜索(需要手动构建 HTTP Request
    3、ES 集群从索引库检索数据并返回
  • 另外用到了 ES 的可视化插件 Head 和 IK 分词器(中文分词)
  • 6.0之前的版本有 type(类型)概念,type 相当于关系数据库的表,但 ES 官方建议索引库只存放相同类型的文档,即用关系数据库的表概念类比ES的索引库。项目中将 type 指定为 doc,只是无意义的占位符
  • 可以使用 Postman 发送各种类型的 HTTP Request 操作 ES
  • 项目中需要在配置类生成 RestClient 的 Bean,用来操作 ES
@Configuration
public class ElasticsearchConfig {@Value("${dino.elasticsearch.hostlist}")private String hostlist;@Beanpublic RestHighLevelClient restHighLevelClient(){//解析hostlist配置信息String[] split = hostlist.split(",");//创建HttpHost数组,其中存放es主机和端口的配置信息HttpHost[] httpHostArray = new HttpHost[split.length];for(int i=0;i<split.length;i++){String item = split[i];httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");}//创建RestHighLevelClient客户端return new RestHighLevelClient(RestClient.builder(httpHostArray));}}

2 Logstash

  • Logstash 的功能是,将 MySQL 的数据表同步到索引库
  • 配置并启动 Logstash,如果 document 的时间戳大于上次采集的时间,就更新索引库
  • 项目中为了便于搜索服务的开发,将课程的一系列信息汇总为一张数据表,将该表同步到索引库,并使用 JPA 操作数据表
  • 因为课程服务是从 ES 的索引库而非数据库搜索,所以 Service 层没有自动注入 DAO

七 用户认证与授权

1 Spring Security OAuth2

  • 常用的有:授权码模式(主要用于第三方登录)和密码模式。项目采用密码模式
  • 授权码模式流程:
    在这里插入图片描述
1、客户端请求第三方授权 GET localhost:40400/auth/oauth/authorize?client_id=XcWebApp&response_type=code&scop=app&redirect_uri=http://localhost
- client_id:客户端 id,和授权配置类中设置的客户端 id 一致
- response_type:授权码模式固定为 code
- scop:客户端范围,和授权配置类中设置的 scop 一致
- redirect_uri:跳转 uri,当授权码申请成功后会跳转到此地址,并在后边带上 code参数(授权码)2、用户(资源拥有者)同意给客户端授权3、客户端获取到授权码 7bjwZ5,请求认证服务器申请令牌 POST http://localhost:40400/auth/oauth/token,需要在请求体中添加:
- grant_type:授权类型,填写 authorization_code,表示授权码模式
- code:授权码,就是刚刚获取的授权码,授权码只使用一次就无效了,需要重新申请
- redirect_uri:申请授权码时的跳转 url,和申请授权码时用的 redirect_uri 一致4、认证服务器向客户端响应令牌 (私钥生成令牌){"access_token": "eyJhbGciOiJSUzI1NiI...","token_type": "bearer","refresh_token": "eyJhbGciOiTtaBGa6LRtIhzz3Eyjw...","expires_in": 43199,"scope": "app","jti": "a8d04b91-57d16..."}5、客户端请求资源服务器的资源,资源服务校验令牌合法性,完成授权(公钥校验令牌)资源服务器也要引入相应的依赖,创建 config 等,才能具有验证令牌合法性的功能6、资源服务器返回受保护资源
  • 密码模式:密码模式与授权码模式的区别是申请令牌不再使用授权码,而是直接通过正确的用户名和密码即可申请令牌

2 JWT(Json Web Token)

  • JWT = Header + Payload + Signature
    Header:描述 JWT 的元数据,包括令牌的类型(即 JWT)及使用的哈希算法,内容用 Base64Url 编码
    Payload:负载是存放有效信息的地方,它可以存放 JWT 提供的字段,比如 iss(签发者)、exp(过期时间戳)、sub(面向的用户)等,也可自定义字段
    Signature:签名部分,防止 JWT 被篡改 指定的哈希算法( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
  • 考虑到 Cookie 的容量比较小,在 Cookie 中存放 access_token,HTTP Header 中存放 JWT,Redis 中存放 (access_token, JWT + refresh_token) 的键值对以供查询
  • 使用 JWT 的一个显著优点是,资源服务器可以自行认证 JWT,而不用传递给认证服务器
    在这里插入图片描述

3 单点登录和身份校验

  • 单点登录:微服务之间相互调用,需要验证 JWT 的合法性,使用 Feign Interceptor
  • 网关在将请求转发到指定微服务前,负责检验 JWT 的合法性:
    1、从 Cookie 查询 access_token 令牌是否存在,不存在则拒绝访问
    2、从 HTTP Header 查询 JWT 令牌是否存在,不存在则拒绝访问
    3、从 Redis 中查询 JWT 令牌是否过期,过期则拒绝访问
  • 具体实现:在网关微服务添加 @Component
@Component
public class LoginFilter extends ZuulFilter {@AutowiredAuthService authService;/*** 过滤器类型:pre、routing、post、error*/@Overridepublic String filterType() {return "pre";}/*** 过滤器序号*/@Overridepublic int filterOrder() {return 0;}/*** 是否生效*/@Overridepublic boolean shouldFilter() {return true;}/*** 执行过滤操作* 1、从cookie查询用户身份令牌是否存在,不存在则拒绝访问* 2、从http header查询jwt令牌是否存在,不存在则拒绝访问* 3、验证redis中的jwt是否过期,过期则拒绝访问*/@Overridepublic Object run() throws ZuulException {RequestContext context = RequestContext.getCurrentContext();HttpServletRequest request = context.getRequest();HttpServletResponse response = context.getResponse();// 1.查询cookie的access_tokenString accessTokenFromCookie = this.authService.getAccessTokenFromCookie(request);if (StringUtils.isEmpty(accessTokenFromCookie)) {this.accessDenied();return null;}// 2.查询header的jwtString jwtTokenFromHeader = this.authService.getJwtTokenFromHeader(request);if (StringUtils.isEmpty(jwtTokenFromHeader)) {this.accessDenied();return null;}// 3.验证redis中的jwt是否过期Long expire = this.authService.checkJwtFromRedis(accessTokenFromCookie);if (expire <= 0) {this.accessDenied();return null;}return null;}

4 用户授权 RBAC(Role-Based Access Control)

  • 权限就是对资源的控制,对 web 应用来说就是对 url 的控制
  • 核心为五张数据表:用户表、用户角色表、角色表、角色权限表、权限表,使用时的查询流程:
    根据用户ID查询用户角色表,获取角色ID
    根据角色ID查询角色权限表,获取权限ID
    根据权限ID查询权限表,获取权限
    <select id="selectPermissionByUserId" resultType="com.framework.domain.ucenter.Menu">select id, code, p_id pId, menu_name menuName, url, is_menu isMenu, level, sort, status, icon,create_time createTime, update_time updateTime from Menu where id in (select menu_id from Permission where role_id in (select role_id from User_role where user_id = #{userId}))</select>
  • 获取到的权限被写入 JWT 中,在访问微服务前需要校验用户权限是否够
  • 在 config 类上注解 @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true),然后Controller 方法注解@PreAuthorize("hasAuthority('course_find_list')"),指定该方法只能被 JWT 中含有 course_find_list 权限的用户调用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307143.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通讯故障_掌握PLC必备知识,人机界面和 PLC 出现通讯故障如何分析解决

此次主要在阐述人机界面和 PLC 通讯时的模式状态&#xff0c;并列举了通讯故障实例。帮助大伙加深对这俩者的了解&#xff0c;掌握起来也不再是难题&#xff0c;解决掉拦路虎。一 台数 显 四 辊 卷 板 机PLC 控 制 系 统 核 心 与 人机界面在使用过程中&#xff0c;出现人机界面…

后端学习 - 设计模式与设计原则

文章目录设计原则1 单一职责原则2 开闭原则3 Liskov 替换原则4 依赖倒置原则5 接口隔离原则6 迪米特法则设计模式&#xff1a;创建型模式1 工厂模式2 抽象工厂模式3 单例模式设计模式&#xff1a;行为型模式1 观察者模式2 模板模式3 备忘录模式设计模式&#xff1a;结构型模式1…

ai的预览模式切换_AI字体制作,用AI制作创意阶梯式文字

本篇教程通过AI制作一款创意阶梯式文字&#xff0c;教程中有很多知识点需要掌握&#xff0c;比如路径分割为网络&#xff0c;3D效果应用等&#xff0c;我们要利用他们创造出我们需要的文字出来&#xff0c;具体是如何制作的&#xff0c;我们通过教程一起来学习一下吧。效果图&a…

新版本 Swashbuckle swagger 组件中的 坑

新版本 Swashbuckle swagger 组件中的 Servers 坑Intro上周做了公司的项目升级&#xff0c;从 2.2 更新到 3.1&#xff0c; swagger 直接更新到了最新&#xff0c;swagger 用的组件是 Swashbuckle.AspNetCore&#xff0c;然后遇到一个 swagger 的问题&#xff0c; 在本地测试是…

后端学习 - MySQL存储引擎、索引与事务

文章目录一 存储引擎1 MyISAM 与 InnoDB 的差异二 索引1 主键索引与二级索引、索引覆盖、延迟关联2 聚簇索引与非聚簇索引3 数据结构3.1 哈希表3.2 B树3.3 B树3.4 跳表3.5 为什么不使用红黑树3.6 为什么不使用B树**4 索引下推 ICP **5 索引失效&#xff08;索引不命中&#xff…

. NET5正式版本月来袭,为什么说gRPC大有可为?

当前企业正在慢慢改用微服务架构来构建面向未来的应用程序&#xff0c;微服务使企业能够有效管理基础架构&#xff0c;轻松部署更新或改进&#xff0c;并帮助IT团队的创新和学习。它还可以帮助企业能够设计出可以轻松按需扩展的应用程序&#xff0c;此外&#xff0c;随着企业转…

后端学习 - 操作系统

文章目录一 基本概念1 操作系统的特征2 操作系统的位置3 计算机的硬件组成4 中断与异常5 系统调用二 进程管理1 进程控制块 PCB&#xff08;Process Control Block&#xff09;2 进程的状态与转换3 进程间的通信4 线程5 调度算法6 死锁7 PV 操作三 内存管理1 内存的非连续分配2…

西门子触摸屏脚本程序_通过驿唐PLC501远程下载Smart Line触摸屏

通过驿唐PLC-501远程下载Smart Line触摸屏一、触摸屏设置将PLC-501和Smart 700 IE V3通过网线连到一起。触摸屏上电后&#xff0c;点击Control Panel进入控制面板界面。进入控制面板后&#xff0c;点击Ethernet设置IP地址&#xff0c;与PLC-501联网宝在同一个网段。联网宝的IP地…

.NET for Apache Spark 1.0 版本发布

.NET for Apache Spark 1.0 现已发布&#xff0c;这是一个用于 Spark 大数据的 .NET 框架&#xff0c;可以让 .NET 开发者轻松地使用 Apache Spark。该软件包由微软和 .NET Foundation 牵头&#xff0c;经过大约两年的开发。在 2019 年的 Spark AI 峰会上&#xff0c;微软曾宣…

fillrect不填充被覆盖的区域 mfc_quot;条带覆盖quot;猜想的中二证明:quot;球面条线覆盖或点覆盖quot;积分π...

注销&#xff1a;“黎曼猜想”复平面质数单向“虚”圆柱螺旋&#xff1a;几何法证明&#xff0c;技术应用​zhuanlan.zhihu.com假设有这样一部针点打印机从球心对球面打印&#xff0c;外部有一台蓝牙打印&#xff0c;球面打印蓝牙条带打印同步&#xff0c;球面被覆盖&#xff0…

让你变厉害的7个底层思维

职场&认知洞察 丨 作者 / findyi这是findyi公众号分享的第89篇原创文章如果把你的思维比做操作系统&#xff0c;那思维模型就是一个个App。这些App会给你提供新的视角&#xff0c;快速帮你决策&#xff0c;提升你的工作效率。顶级的思维模型能提高你成功的可能性&#xff0…

后端学习 - 计算机网络

文章目录一 基本概念1 计算机网络体系结构2 时延二 应用层&#xff1a;HTTP1 请求和响应报文、常见 header2 URL & RESTful API3 HTTP 协议通信过程4 HTTP 方法5 HTTP 状态码6 短连接、长连接与流水线7 Cookie8 Session三 应用层&#xff1a;HTTPS1 加密方式2 证书认证四 应…

跟我一起学Redis之Redis配置文件啃了一遍之后,从尴尬变得有底气了(总结了一张思维图)...

前言秋高气爽的一天&#xff0c;那时候年轻帅气的我正在参照着搜索引擎写代码&#xff0c;迷之微笑般的敲着键盘(又从搜索引擎上找到代码案例啦)&#xff0c;突然领导在小隔间里传来了呼唤声&#xff0c;然后有了以下场景&#xff1a;领导&#xff1a;小Z&#xff0c;你过来一下…

1093芯片做正弦波逆变器_长途自驾游“缺电”如何选购正确车载逆变器,避开商家套路...

让车友三分钟就能看明白如何选择车用逆变器&#xff0c;节约车友时间。长途自驾游充电是一个难题&#xff0c;手机充电还好办&#xff0c;其他笔记本、电饭煲、车载冰箱或者无人机电池等充电就会用到220V电源&#xff0c;那就必须用到逆变器(逆变器就是将12V或24V直流电&#x…

Spring 相关问题

文章目录Spring1 Spring 框架中用到的设计模式2 Spring 事务、隔离级别3 单例 Bean 是线程安全的吗Spring IOC1 Spring 容器&#xff1a;BeanFactory & ApplicationContext2 依赖注入的两种方式3 Bean 的生命周期4 依赖注入的四个注解5 如何解决循环依赖Spring AOP1 基本概…

ndr4108贴片晶振是多少频率_关于山羊挺身你知道多少?这些干货速来了解一下...

就是因为有些人愿意吃苦&#xff0c;有些人缺乏决心毅力&#xff0c;才会有成功和失败之分。身材不是一天不运动或一天乱吃所造成&#xff0c;瘦身健身的效果也不是一天的努力可以看出来的。如同学业、事业&#xff0c;成功都不是一条直线&#xff0c;而是一条上上下下的崎岖路…

BeetleX之Websocket服务使用

BeetleX.FastHttpApi不仅是一个Webapi服务组件&#xff0c;它同时也是一个Websocket服务组件。由于BeetleX.FastHttpApi的实现是直接支持Websocket Upgrade操作&#xff0c;所以当启动服务后是HTTP还是Websocket完全取决于请求方&#xff1b;其原理和aspcore一样&#xff0c;同…

typeorm_Nestjs 热更新 + typeorm 配置

Nestjs 开发环境热更新的方案Nestjs 的热更新是基于 Webpack HMR(Hot-Module Replacement) 方案警告请注意&#xff0c;webpack不会自动将您的资产(例如graphql文件)复制到dist文件夹。同样&#xff0c;webpack与glob静态路径(例如TypeOrmModule中的实体属性)不兼容。1 使用 CL…

缓存一致性和跨服务器查询的数据异构解决方案canal

当项目的请求量上去了之后&#xff0c;通常有两种做法来应对高并发&#xff0c;第一是尽最大可能的使用cache来对抗&#xff0c;第二是尽最大可能的分库分表对抗。。。说起来容易&#xff0c;做起来并不那么乐观&#xff0c;这一篇就来浅析下。一&#xff1a;如何保证缓存一致性…

synchronized 实现原理

参考链接 文章目录一 基本使用1 三个作用2 三种用法二 同步原理1 监视器 Monitor2 synchronized 用于同步代码块3 synchronized 用于同步方法3 Mark Word4 对象头的 Mark Word 和线程的 Lock Record三 锁的优化1 自旋锁2 锁消除3 锁粗化4 偏向锁5 轻量级锁、重量级锁以及三种锁…