因为细节内容切实太多啦,所以只把局部知识点整理出来粗略的介绍,每个小节点外面都有更细化的内容!

接下来开始分享啦

架构

前后端拆散:

补充:

  • setting.xml 文件的作用:settings.xml是maven的全局配置文件。而pom.xml文件是所在我的项目的部分配置。Settings.xml中蕴含相似本地仓储地位、批改近程仓储服务器、认证信息等配置。
  • maven的作用:借助Maven,可将jar包仅仅保留在“仓库”中,有须要该文件时,就援用该文件接口,不须要复制文件过去占用空间
注:这个“仓库”应该就是本地装置maven的目录下的Repository的文件夹

分布式锁

线程锁:当某个办法或代码应用锁,在同一时刻仅有一个线程执行该办法或该代码段。线程锁只在同一JVM中无效,因为线程锁的实现在基本上是依附线程之间共享内存实现的。如synchronized

过程锁:为了管制同一操作系统中多个过程拜访某个共享资源。

分布式锁:当多个过程不在同一个零碎中,用分布式锁管制多个过程对资源的拜访。

分布式锁个别有三种实现形式:

  1. 数据库乐观锁;
  2. 基于Redis的分布式锁;
  3. 基于ZooKeeper的分布式锁。

乐观锁的实现:应用版本标识来确定读到的数据与提交时的数据是否统一。提交后批改版本标识,不统一时能够采取抛弃和再次尝试的策略。

分布式锁基于Redis的实现:(本零碎锁采纳的)

根本命令:

  • SETNX(SET if Not exist):当且仅当 key 不存在,将 key 的值设为 value ,并返回1;若给定的 key 曾经存在,则 SETNX 不做任何动作,并返回0。
  • GETSET:将给定 key 的值设为 value ,并返回 key 的旧值。先依据key获取到旧的value,再set新的value。
  • EXPIRE 为给定 key 设置生存工夫,当 key 过期时,它会被主动删除。

加锁形式:

这里的jedis是Java对Redis的集成

jedis.set(String key, String value, String nxxx, String expx, int time)

谬误的加锁形式1:

如果程序在执行完setnx()之后忽然解体,导致锁没有设置过期工夫。那么将会产生死锁。

Long result = jedis.setnx(Key, value); if (result == 1) { // 若在这里程序忽然解体,则无奈设置过期工夫,将产生死锁 jedis.expire(Key, expireTime); }

谬误的加锁形式2:

分布式锁采纳(Key,过期工夫)的形式,如果锁存在,那么获取它的过期工夫,如果锁确实曾经过期了,那么取得锁,并且设置新的过期工夫

谬误剖析:不同的客户端之间须要同步好工夫。

 //+V:BGM7756,收费支付材料long expires = System.currentTimeMillis() + expireTime; String expiresStr = String.valueOf(expires); // 如果以后锁不存在,返回加锁胜利 if (jedis.setnx(lockKey, expiresStr) == 1) { return true; } // 如果锁存在,获取锁的过期工夫 String currentValueStr = jedis.get(lockKey); if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) { // 锁已过期,获取上一个锁的过期工夫,并设置当初锁的过期工夫 String oldValueStr = jedis.getSet(lockKey, expiresStr); if (oldValueStr != null && oldValueStr.equals(currentValueStr)) { // 思考多线程并发的状况,只有一个线程的设置值和以后值雷同,它才有权力加锁 return true; } } // 其余状况,一律返回加锁失败 return false; //+V:BGM7756,收费支付材料
中场休息时间!最近整顿了一份Java外围知识点。笼罩了springboot、JVM、锁、并发、Java反射、Spring

原理、微服务、Zookeeper、数据库、数据结构等大量知识点。

如果须要收费获取到这个【材料】文档的话增加微信:BGM7756

解锁:判断锁的拥有者后能够应用 jedis.del(lockKey) 来开释锁。

分布式锁基于Zookeeper的实现

Zookeeper简介:Zookeeper提供一个多层级的节点命名空间(节点称为znode),每个节点都用一个以斜杠(/)分隔的门路示意,而且每个节点都有父节点(根节点除外)。

例如,/foo/doo这个示意一个znode,它的父节点为/foo,父父节点为/,而/为根节点没有父节点。

client不管连贯到哪个Server,展现给它都是同一个视图,这是zookeeper最重要的性能。

Zookeeper 的外围是原的播送,这个机制保障了各个Server之间的同步。实现这个机制的协定叫做Zab协定。Zab协定有两种模式,它们别离是恢复模式(选主)和播送模式(同步)。当服务启动或者在领导者解体后,Zab就进入了恢复模式,当领导者被选举进去,且大多数Server实现了和 leader的状态同步当前,恢复模式就完结了。状态同步保障了leader和Server具备雷同的零碎状态。

为了保障事务的程序一致性,zookeeper采纳了递增的事务id号(zxid)来标识事务,实现中zxid是一个64位的数字。

Zookeeper的分布式锁原理

获取分布式锁的流程:

  1. 在获取分布式锁的时候在locker节点(locker节点是Zookeeper的指定节点)下创立长期程序节点,开释锁的时候删除该长期节点。
  2. 客户端调用createNode办法在locker下创立长期程序节点,而后调用getChildren(“locker”)来获取locker上面的所有子节点,留神此时不必设置任何Watcher。
  3. 客户端获取到所有的子节点path之后,如果发现自己创立的子节点序号最小,那么就认为该客户端获取到了锁。
  4. 如果发现自己创立的节点并非locker所有子节点中最小的,阐明本人还没有获取到锁,此时客户端须要找到比本人小的那个节点,而后对其调用exist()办法,同时对其注册事件监听器。
  5. 之后,让这个被关注的节点删除,则客户端的Watcher会收到相应告诉,此时再次判断本人创立的节点是否是locker的节点中序号最小的,如果是则获取到了锁,如果不是则反复以上步骤持续获取到比本人小的一个节点并注册监听。

我的解释:

A在Locker下创立了Node_n —>循环 ( 每次获取Locker下的所有子节点 —> 对这些节点按节点自增号排序程序 —> 判断本人创立的Node_n是否是第一个节点 —> 如果是则取得了分布式锁 —> 如果不是监听上一个节点Node_n-1 等它开释掉分布式锁。)

@ControllerAdvice解决全局异样

Mybatis注解形式的应用:

@insert 用注解形式写SQL语句

分布式系统的下的Session

1、分布式系统:多节点,节点发送数据交互,不共享主内存,但通过网络发送音讯单干。

分布式:不同功能模块的节点

集群:雷同性能的节点

2、Session 与token

服务端在HTTP头里设置SessionID而客户端将其保留在cookie

而应用Token时须要手动在HTTP头里设置,服务器收到申请后取出cookie进行验证。

都是一个用户一个标记

3、分布式系统中的Session问题:

高并发:通过设计保证系统可能同时并行处理很多申请。

当高并发量的申请达到服务端的时候通过负载平衡的形式散发到集群中的某个服务器,这样就有可能导致同一个用户的屡次申请被散发到集群的不同服务器上,就会呈现取不到session数据的状况。

依据拜访不同的URL,负载到不同的服务器下来

三台机器,A1部署类目,A2部署商品,A3部署单服务

通用计划:用Redis保留Session信息,服务器须要时都去找Redis要。登录时保留好key-value,登出时让他生效

垂直扩大:IP哈希 IP的哈希值雷同的拜访同一台服务器

session的一致性:只有用户不重启浏览器,每次http短连贯申请,实践上服务端都能定位到session,放弃会话。

Redis作为分布式锁

高并发:通过设计保证系统可能同时并行处理很多申请。(零碎学习并发常识,能够在Java知音公众号回复“多线程聚合”)

同步:Java中的同步指的是通过人为的管制和调度,保障共享资源的多线程拜访成为线程平安。

线程的Block状态:

a.调用join()和sleep()办法,sleep()工夫完结或被打断

b.wait(),使该线程处于期待池,直到notify()/notifyAll():不开释资源

此外,在runnable状态的线程是处于被调度的线程,Thread类中的yield办法能够让一个running状态的线程转入runnable。

Q:为什么wait,notify和notifyAll必须与synchronized一起应用?Obj.wait()、Obj.notify必须在synchronized(Obj){…}语句块内。

A:wait就是说线程在获取对象锁后,被动开释对象锁,同时本线程休眠。

Q:Synchronized:

A:Synchronized就是非偏心锁,它无奈保障期待的线程获取锁的程序。

偏心和非偏心锁的队列都基于锁外部保护的一个双向链表,表结点Node的值就是每一个申请以后锁的线程。偏心锁则在于每次都是顺次从队首取值。

ReentrantLock重要性:

重入锁能够看这两篇文章,都比较简单

https://www.jianshu.com/p/587...

https://www.jianshu.com/p/1c5...

Spring + Redis缓存的两个重要注解:

  • @cacheable 只会执行一次,当标记在一个办法上时示意该办法是反对缓存的,Spring会在其被调用后将其返回值缓存起来,以保障下次利用同样的参数来执行该办法时能够间接从缓存中获取后果。
  • @cacheput:与@Cacheable不同的是应用@CachePut标注的办法在执行前不会去查看缓存中是否存在之前执行过的后果,而是每次都会执行该办法,并将执行后果以键值对的模式存入指定的缓存中。

对数据库加锁(乐观锁 与 乐观锁)

乐观锁依赖数据库实现:

select * from account where name=”Erica” for update

这条sql 语句锁定了account 表中所有合乎检索条件(name=”Erica”)的记录,使该记录在批改期间其它线程不得占有。

代码层加锁:

String hql ="from TUser as user where user.name='Erica'";Query query = session.createQuery(hql);query.setLockMode("user",LockMode.UPGRADE); //加锁List userList = query.list();//执行查问,获取数据

其它

@Data 相似于主动生成了Getter()、Setter()、ToString()等办法。

JAVA1.8的新个性StreamAPI:Collectors中提供了将流中的元素累积到汇聚后果的各种形式

List<Menu> menus=Menu.getMenus.stream().collect(Collectors.toList())

For - each 写法:

for each语句是java5新增,在遍历数组、汇合的时候,for each领有不错的性能。

public static void main(String[] args) { String[] names = {"beibei", "jingjing"}; for (String name : names) { System.out.println(name); } }

for each尽管能遍历数组或者汇合,然而只能用来遍历,无奈在遍历的过程中对数组或者汇合进行批改。

BindingResult:一个@Valid的参数后必须紧挨着一个BindingResult 参数,否则spring会在校验不通过时间接抛出异样。

@Datapublic class OrderForm { @NotEmpty(message = "姓名必填") private String name;}

后盾:

 //+V:BGM7756,收费支付材料@RequestMapping("save") public String save( @Valid OrderForm order,BindingResult result) { // if(result.hasErrors()){ List<ObjectError> ls=result.getAllErrors(); for (int i = 0; i < ls.size(); i++) { log.error("参数不正确,OrderForm={}", order); throw new SellException( ………… , result.getFeildError.getDefaultMessage() ) System.out.println("error:"+ls.get(i)); } } return "adduser"; } //+V:BGM7756,收费支付材料

result.getFeildError.getDefaultMessage()可抛出“姓名必填” 的异样。

4、List转为Map

 //+V:BGM7756,收费支付材料public class Apple { private Integer id; private String name; private BigDecimal money; private Integer num; /*构造函数*/}List<Apple> appleList = new ArrayList<>();//寄存apple对象汇合Apple apple1 = new Apple(1,"苹果1",new BigDecimal("3.25"),10);Apple apple12 = new Apple(1,"苹果2",new BigDecimal("1.35"),20);Apple apple2 = new Apple(2,"香蕉",new BigDecimal("2.89"),30);Apple apple3 = new Apple(3,"荔枝",new BigDecimal("9.99"),40);appleList.add(apple1);appleList.add(apple12);appleList.add(apple2);appleList.add(apple3);Map<Integer, Apple> appleMap =appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1)); //+V:BGM7756,收费支付材料

5、Collection的子类:List、Set

List:ArrayList、LinkedList 、Vector

List:有序容器,容许null元素,容许反复元素

Set:元素是无序的,不容许元素

最风行的是基于 HashMap 实现的 HashSet,由hashCode()和equals()保障元素的唯一性。

能够用set帮忙去掉List中的反复元素,set的构造方法的参数能够是List,结构后是一个去重的set。

HashMap的补充:它不是Collection下的

Map能够应用containsKey()/containsValue()来查看其中是否含有某个key/value。

HashMap会利用对象的hashCode来疾速找到key。

插入过程:通过一个hash函数确定Entry的插入地位index=hash(key),然而数组的长度无限,可能会产生index抵触,当产生了抵触时,会应用头插法,即为新来的Entry指向旧的Entry,成为一个链表。

每次插入时顺次遍历它的index下的单链表,如果存在Key统一的节点,那么间接替换,并且返回新的值。

然而单链表不会始终减少元素,当元素个数超过8个时,会尝试将单链表转化为红黑树存储。

为何加载因子默认为0.75?(0.75开始扩容)

答:通过源码里的javadoc正文看到,元素在哈希表中散布的桶频率遵从参数为0.5的泊松散布。

总结

通过下面的介绍,置信大家对springboot微信点餐开源零碎方面有了进一步的意识,心愿可能帮忙到大家!

因为细节内容切实太多啦,所以只把局部知识点整理出来粗略的介绍

最近整顿了一份Java外围知识点。笼罩了springboot、JVM、锁、并发、Java反射、Spring
原理、微服务、Zookeeper、数据库、数据结构等大量知识点。

如果须要收费获取到这个【材料】文档增加微信:BGM7756