面经-应届生秋招上岸笔记(低难度 带项目版)
数据类型
基本数据类型
byte short int long float double char boolean
(字节)1 2 4 8 4 8 2 1
自动类型转换:byte-short-int-long-float-double
引用数据类型
String,数组等
switch,String,Static
switch:case:byte,short,int,char,String(JDK7) 忘写break会向下穿透
String:final,StringBuilder(s):容器,可变字符串类,提高字符串的操作效率。
Static:被类的所有对象共享,随类加载而加载,方法只能访问静态成员,无this。静态方法不能被重写。
继承,重写Override,权限修饰符
根据多个类的共性内容向上抽取而来。
缺:侵入性,耦合性(设计模式 合成复用原则);优:复用性,可维护性
继承的成员变量访问:子类局部-子类成员范围(默认this)-父类成员范围
子类初始化时会完成父类数据初始化,会使用父类无参构造方法。
重写:子类需要父类的功能且又有自己特有的内容。
权限修饰符:private(同类)>默认(同包子类、无关类)>protected(不同包子类)>public
抽象类,接口
共性方法抽取到父类后发现该方法实现逻辑无法在父类中给出具体明确。不能创建对象,有构造方法。
子类必须重写所有抽象方法。固定逻辑可用final修饰。可变子类重写。
接口:变量默认final static;无构造方法。不能创建对象。继承实现默认先使用继承。静态方法不能冲突。
代码块
构造代码块(类中方法外)构造方法前执行
静态代码块(类中方法外)类加载前执行
局部代码块(方法中)限定变量生命周期,及早释放
多态
同一个对象在不同时刻表现出不同形态。Animal a=new Cat();
(向下转型:从父类型换回子。需要强制类型转换,目标类型!=实际类型,会造成类型转换异常instanceOf)
继承/实现,方法重写,父类引用指向子类对象。右边对象实现解耦,便于扩展维护。
Cat c = new Animal();必须强转,可以调用子类的特有功能。
内部类
内部类可直接访问外部类private对象;外部类必须先创建对象。
成员内部类,局部内部类
匿名内部类(将继承/实现,方法重写,创建对象放在了一步实现。定义在方法内部。可以直接在调用方法的参数中创建匿名内部类)_所需类型:接口/抽象类/具体类 _限制:一个或多个抽象方法 _原理:编译后产生一个单独的class文件
lambda表达式:关注点更明确,参数类型可以全省略,只有一个参数的时候可以省略括号,只有一条语句可以省略{}和return。 _只能接口 _有且只有一个抽象方法 _不产生单独class文件,运行时动态生成
API
Math:abs,ceil(向上取整),floor,round(四舍五入),max,min,pow,random
System:exit终止当前虚拟机,currentTimeMillis()返回时间ms,arraycopy(数组,起始,目的地,起始,个数)
Object:toString(),equals(),equalsIgnoreCase()忽略大小写,finalize()
Objects:toString(对象,对象为空时返回),isNull(),nonNull()
BigDecimal精确计算:普:十进制-二进制计算-十进制展示。BigDecimal(String)直接计算,add,subtract,multiply,divide。divide(bd,精确几位,舍入模式)进一,去尾,四舍五入
String:length,charAt,toCharArray,subString,replace,split,equals
Arrays:toString,sort(排序),binarySearch(数组,key)二分查找返回key索引
包装类
Integer:可直接在对象中定义功能方法操作该数据。
存入数据库为null值而非默认值0;
自动装箱:底层自动valueOf();自动拆箱:parseInt()
异常
Throwable-Error(JVM错误,无法处理),Exception-RuntimeException运行时异常(空指针、数组索引越界),其他
throws:方法声明后,跟异常类名
throw:方法体内,跟异常对象名,手动抛出异常,由方法体内语句处理。告诉调用者方法中出现问题。
try:可能触发异常的函数。(可以使程序继续运行)
catch:捕获异常并创建一个包含异常信息的对象。多个异常多次catch,父类在最下面。
finally:执行清除、释放资源操作。
final:类:不能再被继承;变量、方法:不能再被修改。基本类型变量:值不能被修改。引用类型变量:地址值不能被修改。只能在构造方法结束前赋值。
finalize:方法。用于在垃圾对象在从内存中清除出去之前整理系统资源,做清理工作(删除文件前关闭文件)。资源清理. 构造方法调用时,jvm会将其包装成finalizer对象,加入unfinalized队列中(双向链表)。当进行垃圾回收时,将这些对象对应的finalizer加入一空队列ReferenceQueue(单向链表)。回收时机:第二次。缺点:不会报异常,守护线程随线程结束。影响性能,慢,可能导致垃圾进入老年代。
自定义异常:自定义类+Exception,继承RuntimeException或Exception;无参,有参。
集合
集合-Collection单列-List有序(ArrayList、LinkList),Set(HashSet无序(LinkedHashSet有序不重,哈希表+双链表),TreeSet升序,红黑树,数字直接排序,字符串首字母排序,对象自定义规则(实现Comparable接口,重写compareTo方法,return))
Map双列-HashMap,TreeMap<全不安全>
循环:普通for,增强for(for(String str:list)),迭代器(iterator,while it.hasNext())
红黑树:根节点必黑,如果节点红则子节点必黑。每个节点从该节点到后代的路径均含相同数目黑节点。
arrayList扩容:无参、有参add、addaAll(复制)
LinkList、ArrayList:连续内存,随机访问快(下标)、尾插性能好、缓存,读写快(局部性原理){占用空间大}
HashMap:快速查找。哈希码-桶下标(key-二次hash(降低哈希碰撞,均匀)%数组长度)-链表>阈值8(数组>64)(Dos攻击,亿分之6)(退化:树<=6且root、左右孩子、左孙子null)/红黑树。put:未占用:Node/红黑树、链表。线程不安全,1.7扩容并发死链,1.8(尾插、大于阈值扩容、优化计算Node索引)数据错乱
HashTable、ConcurrentHashMap:线程安全,kv非空。并发度:H整个一把锁,C1.8后数组头节点锁。扩容:H初始11,*2+1;C链表超过(满)容量的3/4容量翻倍(复制,旧变F,get判断F,put已替换加锁,帮忙)
泛型
类型安全检测。把执行时期的问题提前到编译期。避免强制类型转换和转换异常。<?>泛型通配符extends,super
stream流
获取stream流,中间方法(过滤,去重),终结方法 list.stream().filter(s->s.startswith("章")).forEach(s->sout);
IO流
字节流:字节输入流InputStream,字节输出流OutputStream
字符流:字符输入流Reader,字符输出流Writer
BufferedXX:缓冲流,自带缓冲区,提高性能
ObjectOutputStream对象序列化,OutputStreamWrite对象反序列化(原型模式深克隆)
多线程,并行并发,线程进程
并行:同一时刻多个指令在多个CPU上同时执行
并发:同一时刻多个指令在单个CPU上交替执行
进程:资源分配的最小单位(火车)(独立性,动态性,并发性)
线程:CPU调度的最小单位(车厢)
一火车多车厢;不同进程数据难共享;同一进程线程易共享(换站);进程消耗更多资源;进程间不会相互影响,一个线程挂了所有线程都挂;多进程多机,多线程多核;进程上的线程可以上锁(互斥锁)(洗手间);进程可以限定信号量(限人数餐厅)
多线程实现方式:继承Thread类(简单,扩展性差,不能返回执行结果);实现Runnable接口(扩展性强,复杂,不能返回执行结果);实现Callable接口(复杂,扩展性强,可返回结果)
线程调度:分时调度模型(线程轮流使用CPU),抢占调度模型(优先级高先使用)
死锁:两个或多个线程互相持有对方所需的资源导致他们都处于等待状态。
线程安全问题:多个线程同时修改和访问同一个资源。加sychornized锁:代码块(影响其他无关线程运行),方法(范围更小)。加Lock锁:灵活方便。unlock()释放锁。
线程状态:新建,可运行,锁阻塞,无限等待,有时限等待,终止(执行完毕/出现异常)
多线程读写:failFast(并发修改异常)、failSafe(破坏一致性,读写分离)
线程池参数:核心线程、任务队列、救急线程、拒绝策略(异常、调用者执行、丢弃新任务、丢弃老任务)
volatitle线程安全:可见性(JIT优化)、有序性(读下先写上后屏障)、原子性
ThreadLocal线程变量:作用:线程隔离资源共享。原理:ThreadLocalMap(set、get、remove)。扩容:元素>容量2/3,翻倍。索引冲突:线性探测法。弱引用,key-null key,周围。
wait、wait(long)、sleep(long):线程阻塞。sleep:归属Thread(Object),醒来时机、锁特性synchronized不释放。
Lock,synchronized:语法:s-jvm-c++;L-接口-jdk-java。功能:悲观锁,互斥、同步、锁重入;L:获取等待状态、公平锁、可打断、可超时、可条件变量,读多写少。性能:无竞争s性能好;竞争激烈。
悲观锁、乐观锁:思想(争抢/重试),代表(sy、L/cas)、性能(阻塞)、额外(重试减少阻塞/CPU多核)
可重入性:每一个锁关联一个线程持有者和计数器,当计数器为 0 时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为 1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为 0,则释放该锁。
线程池:Executor(可能导致内存溢出),ThreadPoolExecutor(运行规则明确,避免资源耗尽)
JVM
JVM内存结构:类加载子系统-Java内存结构:线程共享(方法区、堆-对象)、程序计数器-线程、虚拟机栈-变量。执行引擎:解释器-机器码、即时编译器-JIT缓存、GC-本地方法接口-本地库
JVM内存参数:新生代:伊甸园区、from、to(幸存者区),老年代(分代回收思想)
垃圾回收算法:标记清除、标记整理、标记复制。三色标记-并发漏标-增量更新、原始快照。小范围GC、混合、Full
垃圾回收器:并行GC(新小老Full注重吞吐量),并发标记(标记清除+并发失败Full注重响应时间),G1(标记复制+混合收集,失败Full)
内存溢出:误用固定大小线程池、任务队列耗尽(使用线程池时自己的构造方法),误用带缓冲线程池、内存资源耗尽,查询数量大,动态生成类
类加载:加载(创建.class对象,父类未加载时先加载父类),链接(验证(字节码规范合法安全),准备(static变量分配内存空间和默认值),解析(将常量池的符号引用解析为直接引用)),初始化(执行静态代码块,为非final对象赋值)
双亲委派:启动类加载器、扩展类加载器、应用程序类加载器、自定义类加载器,优先委派上级,上级共享类,保证核心先加载。
Finalize: 资源清理. 构造方法调用时,jvm会将其包装成finalizer对象,加入unfinalized队列中(双向链表)。当进行垃圾回收时,将这些对象对应的finalizer加入一空队列ReferenceQueue(单向链表)。回收时机:第二次。缺点:不会报异常,守护线程随线程结束。影响性能,慢,可能导致垃圾进入老年代。
类加载器
类加载时机:创建类的对象;调用类的类方法;访问类的变量或赋值;使用反射机制强制创建某个类的class对象;初始化某个类的子类;运行某个主类。
类加载过程:加载(通过全限定名获取定义此类的二进制字节流,加载到内存中并创建一个.class对象)。验证(看文件中信息是否符合虚拟机规范,是否有安全隐患。准备(为静态变量分配内存并初始化)。解析(将类的符号引用替换成直接引用)。初始化(给静态变量赋值,初始化其他资源)。
反射
运行状态中对任意一个类都可以获取其所有属性和方法;对任意对象都能调用其属性和方法;根据配置文件信息动态获取信息和动态调用对象。运行时获取类的字节码文件并解析。破坏封装性。
作用:绕过编译阶段为集合添加数据。会自动擦除泛型。做Java高级框架。
计算机网络
要素:IP(定位网上设备)。端口(应用在设备中的地址),协议(数据在网上传输的规范)。
OSI:物理层(双向传输),数据链路层(MAC地址,数据帧,差错检测,交换机),网络层(IP地址,连接外网内网,路由协议选择最佳路径),传输层(端口号),会话层(应用程序之间),表示层(数据加密),应用层(用户)
TCP/IP:数据链路层(物理媒介传输 ARP),网络层(数据包转发 IP确定通信路径 ICMP检测网络连接),传输层(两台主机的应用端到端通信 TCP 超时重传,数据确认 可靠,面向连接,基于流stream,有粘包现象(发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾 tcp协议将较小的内容拼接成大的内容,一次性发送到服务器端 解决:每次使用tcp协议发送数据流时,在开头标记一个数据流长度信息,并固定该报文长度(自定义协议).在客户端接收数据时先接收该长度字节数据,判断客户端发送数据流长度,并只接收该长度字节数据,就可以实现拆包) 三次握手四次挥手 UDP 不可靠,无连接,基于数据报 可广播发送,开销小,速度快,易丢失数据),应用层
输入一个网址的流程:url->http报文->dns域名解析->tcp三次握手->发起HTTP请求->拆分HTTP报文添加TCP头部->IP头部->MAC头部->交换机(根据mac寻找相应端口)->路由器(去掉mac,根据ip转发)->服务端(mac->ip->tcp(序列号,返回ACK,端口号))->HTTP进程->请求来到后台(SpringMVC)->dispatcherServle(前端控制器)->HanderMapping->controller->ModelAndView->ModelAndView对应的VIewResoler->返回浏览器渲染
动态代理
被代理者不能或不愿做某事,动态代理对业务功能进行代理。
优点:灵活,可不改变源码增强方法功能。提高可扩展性和开发效率。
MySQL
DDL(数据定义语言),DML(数据操纵语言),DQL(数据查询语言),DCL(数据控制语言)函数
select *from表where条件 group by 分组字段 having 分组后条件 order by 排asc desc序 limit 起始索引,查询数
执行顺序:from,where(分组前过滤,不满足条件不参与分组),group by,having(分组后过滤结果,可判断聚合函数),select,order by,limit
索引:存储引擎用来快速查找记录的一种数据结构。
单列索引(唯一索引(可null),普通索引,主键索引),组合索引,全文索引(大量数据,精度不好),空间索引
优点:加快查询速度,减少分组和排序时间。缺点:创建和维护成本,占用磁盘空间。
适用范围:列不频繁更新,数据量大,重复字段少。
索引创建:建表的时候创建索引(INDEX [indexName] (columnName(length)) );CREATE INDEX indexName ON tableName (columnName(length)); ALTER TABLE tableName ADD INDEX indexName(columnName);
事务:原子性,一致性,隔离性,持久性。
隔离级别:读未提交(脏读幻读不可重复读),读已提交(幻读不可重复读),可重复读(默认,读时不允许修改,幻读),序列化(效率低下)
锁:表锁(锁冲突概率高,并发度低,_查询),行hang锁(开销大,开锁慢,可能死锁, _索引)
读锁(共享锁)(只能读,多个读操作可同时),写锁(排他锁)(操作未完成前阻断其他)
mysql数据库优化:使用慢查询日志定位效率低的sql语句。选取最适用的字段属性,数据库中的表越小,在上面执行的查询就越快。使用连接来代替子查询。
索引优化。创建索引,1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。索引失效:like 以%开头;当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效;组合索引,不是使用第一列索引,索引失效;如果列类型是字符串,那一定要在条件中将数据使用引号引用起来;在索引列上使用 IS NULL 或 IS NOT NULL操作(可能);当全表扫描速度比索引速度快时,mysql会使用全表扫描,此时索引失效。2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描。3.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。 4.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描。5.in 和 not in 也要慎用,否则会导致全表扫描
Redis
noSQL非结构化,表间无关联,非sql,ACID-BASE(无事务)
特点:k-v;单线程,每个命令具备原子性;低延迟,速度快;支持数据持久化;支持多语言客户端
字符类型:String(string,int,float),Hash(散列,HashMap),List(单双向链表,类似LinkedList),Set(HashSet),SortedSet(可排序的set集合)
redis缓存更新策略:需求低一致性:内存淘汰机制;高:主动更新,超时剔除
缓存失效 :缓存穿透:一直查一个null值,穿透redis。解决:缓存一个null/布隆过滤器
缓存雪崩:大量key同时失效。解决:不同key随机值后释放;多级缓存。
缓存击穿:一个高并发访问且重建复杂的key突然失效,无数请求冲击sql。解决:互斥锁(一致性,影响性能),逻辑过期(性能好,不保证一次性)
Redis和MySQL缓存一致性:
解决方案:不存在完全一致,只能保证最终一致。1.先写SQL再写Redis,如果A线程访问redis中没有的东西,读完了之后B线程插队修改,又写redis,A线程再修改Redis,会出现问题。2.先写Redis再写SQL,A线程先写入Redis新数据,B线程又修改,写入Redis新数据,B线程修改SQL,A线程修改SQL。3.先删除Redis再修改SQL:A删除Redis,B查询缓存未命中,再查询数据库去Redis写入旧数据,A更新后Redis里还是旧数据。4.缓存双删:A删除缓存,B查询未命中,A更新成功后B如果回写缓存,A(等待500ms)再把缓存删掉。风险不可控。5.删除请求入队列:消息队列重试机制保证顺序并且一定删除。6.先写SQL再删Redis:A更新SQL2,B查询返回1,A删除缓存1,C查询返回2,A回写缓存2.不适用于秒杀,库存。实时一致性方案,不一致的条件苛刻,可以容忍。7.监听SQL日志,通过异步方式将数据队列更新(消费队列+重复机制)到Redis。(前提:查询请求不会回写Redis)。不能保证实时性,只能保证最终一致性。
Redis 持久化的两种方式
-
RDB:RDB 持久化机制,是对 redis 中的数据执行周期性的持久化。
-
AOF:AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,在 redis 重启的时候,可以通过回放 AOF 日志中的写入指令来重新构建整个数据集。
Spring
IOC:控制反转,将对象的控制权转交给spring进行管理。spring管理对象的创建和对象间的依赖关系。
实现方式:依赖注入。优点:降低对象间的依赖程度和耦合度。(springboot自动装配)
AOP:面向切面编程。剖开封装的对象内部,将类的公共行为进行封装(如日志)减少重复代码,降耦合,利于可操作性和可维护性。(Spring事务)
springboot
特点:自动装配。自动装配就是自动地把其他组件中的Bean装载到IOC容器中,不需要开发人员再去配置文件中添加大量的配置。只需要在springboot的启动类上添加一个SptingBootApplication的一个注解。
首先获取配置文件spring.factories找到全限定类名,然后通过反射机制得到class类对象,然后通过并发安全集合concurrentHashMap进行装载,k是class对象,v存储class.newInstance。实现ioc功能。
原理:@SptingBootApplication这个注解是暴露给用户使用的一个入口,它的底层其实是由@EnableAutoConfiguration这个注解来实现的,自动装配的实现,归纳为以下三个核心的步骤:
第一步:启动依赖组件的时候,组件中必须要包含@Configuration的配置类,在这个配置类里面声明为Bean注解,然后将方法的返回值或者是属性注入到IOC容器中。
第二部:第三方jar包,SpringBoot会采用SPI机制,在/META-INF/目录下增加spring.factories文件,然后SpringBoot会自动根据约定,自动使用SpringFactoriesLoader来加载配置文件中的内容
第三步:Spring获取到第三方jar中的配置以后会调用ImportSelector接口来完成动态加载,
这样设计的好处,在于大幅度减少了臃肿的配置文件,而各模块之间的依赖,也
比如我们使用Spring创建Web程序的时候需要引用非常多的Maven依赖,而SpringBoot中只需要引用一个Maven依赖就可以来创建Web程序。并且SpringBoot把我们常用的依赖都放在了一起,,我们只需要去引入spring-boot-starter-web这个依赖就可以去完成一个简单的Web应用。以前我们使用Spring的时候需要xml文件来配置开启一些功能,现在使用SpringBoot就不需要xml文件了,只需要一个加了@Configuration注解的类,或者是实现了对因接口的配置类就可以了。SpringBoot自动装配是Spring的完善和扩展,就是为了我们便捷开发,方便测试和部署,提高效率而诞生的框架技术。
创建对象:类加载检查,内存分配,初始化默认值,设置对象头,执行初始化方法
SpringRefresh:初始化 ApplicationContext 容器.创建准备环境对象;创建beanFactory,bean创建,依赖注入,初始化;准备beanFact;子类扩展beanFacto;后处理器扩展beanFactory;准备bean后处理器;增加国际化;添加事件广播器成员;子类扩展;注册事件监听器对象;初始化单例bean对象;添加生命周期处理器。
Bean生命周期:处理名称,检查缓存;检查父工厂;检查DependsOn;按Scope创建bean(单例多例,自定义);创建bean实例,依赖注入,初始化;类型转换;销毁bean
事务失效的场景:抛出检查异常导致事务无法正确回滚(配置 rollbackFor 属性), 业务方法内自己 try-catch 异常导致事务不能正确回滚(异常原样抛出), aop 切面顺序导致导致事务不能正确回滚, 非 public 方法导致的事务失效, @Transactional 没有保证原子行为(select不阻塞)
springMVC执行流程:浏览器(1HTTP),前端控制器,处理器映射器(2Handler,3执行链),处理器适配器(4适配器),Controller(5执行Handler,67前返回modelandView),视图解析器89,View(视图渲染,HTTP响应)
微服务
分布式:为了解耦,便于升级维护,将服务进行拆分,springcloud解决了拆分中的服务治理问题。根据业务模块将一个单体应用拆分成许多独立项目,独立完成开发部署。进而构成一个服务集群。
相关组件:注册中心(记录服务ip,端口以及功能),配置中心(管理服务群的所有配置),网关(将请求路由到对应服务,拦截非必要请求),分布式缓存,消息队列,日志
负载均衡:高并发组件,将网络流量平均分配在多个服务器上,提高系统整体响应速度和可用性。安全防护。
特征:单一职责,面向服务,独立,隔离性强
串联:springcloudfeign或dubbo
消息队列
AMQP协议。
消息重复消费:网络波动。生产者或消费者重发。解决:使用数据库一个表来记录消息id和状态。每次消费之前,都查询判断消息的状态,是否已经被消费了。
消息丢失:消息发出后网络故障,服务器没收到(消息确认机制:配置,生产方发送消息时try catch捕获异常,记录日志,发送失败定时任务定时扫描重发);服务器收到后没持久化,宕机(消息确认);服务器收到后消费方还未处理完,服务挂了,消息自动签收(消息手动签收机制:失败或异常重新入队)。
Druid德鲁伊连接池
连接池是创建和管理一个连接的缓冲池技术。我们原先在连接数据库时都是用到一次,创建一次连接,不用就关闭,再用的时候再连接。但是一旦访问数据库的请求多了起来,就会很容易占用服务器资源,还耗时。 使用连接池就能很好的解决这种问题。 为什么用连接池: 连接池技术是在服务启动的时候就事先在连接池中放入一定数量的连接对象,当你需要的时候,直接从连接池中拿已经创建好的对象而不是临时去创建一个连接,这样就能提高效率。
为什么用D:Druid是阿里巴巴开源平台上的一个项目,它结合了C3P0、DBCP、Proxool等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池,也是目前最好的数据库连接池之一。
方式:maven引入jar包。.properties配置文件配置 初始默认连接数,最大连接数,获取连接时最大等待时间。编写DBUtils工具类,通过druid连接池连接数据库并封装查询操做。
Swagger
接口说明文档。添加依赖swagger2,swaggerUI。swagger配置类封装接口文档信息,指定文档风格。
@Api(value=“接口说明”,tags=“用户管理”)类注解,对控制类进行说明。
@ApiOperation(“...接口”)说明接口方法的作用。
@ApiImplicitParam(dateType=“int“,name=”password“,value=”密码“,required=false,defaultValue=”111“)说明接口方法的参数
@ApiModel(value=”对象“,description=”注解说明“)
RestFul
1.每个URL请求路径代表服务器上的唯一资源。 @RequestMapping(value = "/delete/{gid}")
2.使用不同的请求方式表示不同的操作
springmvc对RESTful风格提供了很好的支持。在我们定义一个接口的URL时,可以通过两种方式:RequestMapping(value="/{id}",method=RequestMethod.GET)方式指定请求方式;也可以使用特定请求方式的注解设定URL:@PostMapping("/add")”,“@DeleteMapping("/{id}"),@PutMapping("/{id}"),@GetMapping("/{id}")”
post 添加 get 查询 put 修改 delete 删除 option (预检)
get与post区别:POST 和GET本质都是一样的,GET可以加Request Body ,POST也可以在URL中添加参数。都是HTTP请求的基本方法。
GET请求在浏览器刷新或者回退的时候是无害的,POST的话数据会被重新提交。GET可以存在缓存中,POST不行。GET 编码格式只能用
3.接口响应的资源的表现形式采用JSON(或者XML)
在控制器类 或者 每个接口方法添加“@ResponseBody”注解,将返回的对象格式化为JSON。
或者直接在控制器类使用@RestController注解声明控制器。
4.前端(Android、ios、pc)通过无状态的HTTP协议与后端接口进行交互。
JWT
json web token
。它将用户信息
优点:简洁(可通过URL、POST参数或在HTTP header发送,数据量小,传送块。自包含(负载中可以包含用户所需要的信息,避免多次查询数据库。跨语言(Token以JSON加密形式存在于客户端,任何web形式都支持),不需要在服务端保存会话信息,适用于微服务。
缺点:不易过期。
组成:头部(数据类型和加密算法)+playload(有效信息,用户数据信息)+签证(用来标识真伪的验证信息)
JWT vs Token:都是访问资源的令牌,都可以记录用户的信息,都是使服务器无状态变化,都是验证成功后客户端才能访问服务器端上受保护的资源。
区别:token:服务器验证客户端发送的token时还需要查询数据库获取用户信息,然后验证token是否有效。JWT:将token和payload加密后储存于客户端,服务端只需要使用密钥进行校验即可,不需要查询数据库。JWT已包含了用户信息。
token
访问资源接口时所需要的资源凭证。
简单token:uid(用户唯一身份标识)+time(当前时间戳)+sign(签名)+token前几位以hash算法压缩成的一定长度的16进制字符串。
特点:服务端无状态变化,可扩展性好;支持移动端设备;安全;支持跨域程序调用。
token身份验证流程:浏览器向服务器发送username&password,服务器将登录凭证做数字签名,加密后得到字符串作为token,向浏览器返回。拿到token后将token保存在本地,请求API时携带token,服务器拿到token穿时做解密和签名认证,判断其有效性,向浏览器返回数据。
token vs Cookie:token和cookie一样都是首次登陆时,由服务器下发,都是当交互时进行验证的功能,作用都是为无状态的HTTP提供的持久机制。
cookie 举例:服务员看你的身份证,给你一个编号,以后,进行任何操作,都出示编号后服务员去看查你是谁。
token 举例:直接给服务员看自己身份证
对于token而言,服务器不需要去查看你是谁,不需要保存你的会话。当用户logout的时候cookie和服务器的session都会注销;但是当logout时候token只是注销浏览器信息,不查库。token优势在于,token由于服务器端不存储会话,所以可扩展性强,token还可用于APP中。 可以避免 CSRF 攻击。
cookie vs Session:会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。cookie是针对每个网站的信息,每个网站只能对应一个,其他网站无法访问,这个文件保存在客户端,每次您拨打相应网站,浏览器都会查找该网站的 cookies,如果有,则会将该文件发送出去。cookies文件的内容大致上包括了诸如用户名、密码、设置等信息。session:是针对每个用户的,只有客户端才能访问,程序为该客户添加一个 session。session中主要保存用户的登录信息、操作信息等等。此 session将在用户访问结束后自动消失(如果也是超时)。存储数据的大小不同,一个 cookie存储的数据不超过3 K; session存储在服务器上可以任意存储数据,但是,当 session存储数据太多时,服务器可选择进行清理。
ngrox内网穿透
支付回调:当用户支付成功之后,支付平台会向我们指定的服务器接口发送请求传递订单支付状态数据。1.创建一个控制器定义回调接口 2.设置回调URL:在订单接口中申请支付链接时将回调接口的路径设置给微信支付平台 3.如果按照如上配置,当用户支付成功之后,微信支付平台会向 http://192.168.55.3:8080/pay/callback 发送请求,因为我们的服务器项目是运行在本地计算机的(IP为内网IP),微信平台无法访问。
内网穿透: 当客户端运行时会向服务器端请求建立连接,通过第三方(ngrok)建立隧道并获取唯一的隧道ID,当访问唯一的隧道的url网址时即可对外提供公网访问。支付成功后回调请求会到内网穿透的服务器,服务器相当于一个路由表,查询映射关系之后转发到连接,转发给客户端。(客户端——>服务器(建立长连接) , 支付平台——>服务器——>客户端)
高并发加速
1Nginx+LVS负载,也可以多机房部署,分流
2使用分布式、集群分散并发量,
3对热点数据直接用Redis做缓存,避免所有数据都去数据库进行查询。
4采用队列实现异步响应,提高响应速度。
5使用Hystrix的信号量隔离和线程池隔离来限流,并且使用Hystrix的熔断降级策略返回兜底数据等等
6对数据库进行集群和库表散列:大量请求访问一个数据库会导致数据库压力过大,从而使用集群部署可以减缓数据库的压力。库表散列就是将数据库的数据采用hash算法分散到各个分表中,从而可以提高查询的效率,不用每次都去查询所有的数据表。
设计模式
单一职责原则:提高复用性,高内聚低耦合。
开闭原则:对开放拓展,对修改关闭。灵活性,稳定性,抽象化。
里氏代换原则:父类可替换为子类,反之不成立。(抽象化,代码复用,扩展性)
依赖倒转原则:针对抽象层编程。(抽象化)
接口隔离原则:多个专门的接口取代统一接口,不依赖不需要的接口。
合成复用原则:多组合聚合,少继承。(降耦合)
迪米特法则:一个软件实体尽可能少地与其他实体相互作用。只与直接朋友通信。(松耦合)
单例instance:饿汉式Runtime() (反射破坏单例(构造方法),反序列化,Unsafe),枚举类饿汉式,懒汉式(线程不安全,锁(性能)),双检锁懒volatile,Syste中的Console
名称 | 定义 | 优点 | 缺点 | 适用环境 | 备注 |
---|---|---|---|---|---|
简单工厂 (静态工厂) (创建型) | 根据参数的不同返回不同类的实例。 OA系统 | 对象的创建、使用分离。 使用配置文件,提高了系统灵活性。 客户端只需要知道产品类对应参数。 | 工厂类职责过重。 扩展困难。 增加了系统复杂性和理解难度。 | 工厂类负责创建的对象少。 不关心创建细节。 | 单一职责原则 降耦合 开闭原则 |
工厂方法 | 将类的实例化延迟到子类中完成,由子类决定实例化(创建)哪个类。 日志记录器 | 向客户隐藏哪种具体产品类被实例化。 工厂自主确定创建何种产品对象。 加入新产品符合开闭原则。 | 类的个数成对增加,系统复杂度提升。 增加了系统的抽象性和理解难度。 | 客户不知道具体产品类的类名。 抽象工厂类通过其子类指定创建哪个对象。 | 开闭原则 可扩展性 |
抽象工厂 | 提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。 电器工厂,数据库操作工厂 | 隔离了具体类的生成。 保证客户端始终只使用同一产品族对象。 增加新的产品族方便,符合开闭原则。 | 增加新的产品等级结构麻烦,违背开闭原则。 | 系统不依赖产品创建、组合、表达细节。 每次只使用一个产品族且所有产品一起使用。 产品等级结构稳定。 | +新产品族,符合开闭。 +新产品等级结构,不符合开闭。 |
建造者 Builder | 将复杂对象的构建与表示分离,使同样的构建可以创建不同表示。 KFC套餐,JavaMail | 产品本身与产品创建过程解耦。 替换/新增具体建造者符合开闭原则。 可更精细地控制产品创建过程。 | 产品之间差异大则不适用。 产品内部变化复杂需更多具体建造类,导致系统过于庞大。 | 需要生成的产品有复杂的内部结构,属性相互依赖。 对象创建过程独立于创建对象的类。 | |
原型模式 Prototype | 给出一个原型对象指明所要创建的对象类型,复制这个原型对象创建更多同类型对象。 浅克隆,深克隆(序列化),邮件复制。 | 简化对象创建过程,提高新实例创建效率。 简化创建结构,扩展性好。 深克隆方式能保存对象状态。(撤销) | 每个类需要配备一个克隆方法。 改造已有类需修改源码,改变开闭原则。 深克隆代码复杂。 | 创建新对象成本较大。 对象的状态变化小。 避免使用分层次工厂类。 | |
单例模式 Singleton | 确保一个类中只有一个实例,自行实例化并向整个系统提供这个实例。 身份证,打印池 | 提供了对唯一实例的受控访问。 节约系统资源,提高性能。 允许多例类。 | 扩展困难。 单例类职责过重。 垃圾自动回收机制丢失单例对象的状态。 | 只需要/允许创建一个对象。 只允许使用一个公共访问点。 | |
适配器模式 (结构型) Adaptee | 将一个接口转换成客户希望的另一个接口,使接口不兼容的类可以一起工作。 机器人模仿,加密适配器 | 将目标类和适配器解耦。 增加了类的透明性和复用性。 灵活性和扩展性好。 | 类适配器:一次只适配一个适配者类。 目标抽象类只能为接口,不能为类。 对象适配器:置换适配者类的某些方法麻烦。 | 系统需要使用一些现有的类,而这些类的接口不符合系统需要。 创建一个可以重复使用的类。 | |
桥接模式 Implementor | 抽象与实现部分分离,使他们可以独立地变化。 大中小彩色毛笔,跨平台视频播放器 | 分离抽象接口及其实现部分。 取代多层继承,减少子类个数。 提高系统的可扩展性。 | 增加系统的理解与设计难度。 难以正确识别系统中两个独立变化的维度。 | 增加抽象化和具体化间的灵活性。 抽象、实现部分独立扩展互不影响。 不希望使用继承。 | |
组合模式 Leaf | 组合多个对象形成树形结构以表示整体-部分的结构层次,对单个对象和组合对象的使用具有一致性。 水果盘,文件浏览 | 定义分层次复杂对象,忽略层次差异。 增加新容量构件和叶子构件方便。 实现树形结构面向对象。 | 抽象复杂,难度大。 增加新构件时很难对容器中的构件类型进行限制。 | 希望客户一致对待整体,部分层次结构。 面向对象开发系统中处理树形结构。 系统中可分离出叶子和容器对象。 | |
装饰模式 Decorator | 动态地给一个对象增加一些额外职责。 变形金刚变飞机、机器人,多重加密系统 | 比继承灵活,不会急剧增加类的个数。 动态方式扩展对象功能。 可对一个对象多次装饰。 加新的构件类和装饰类符合开闭原则。 | 一定程度下影响对象性能。 比继承更易出错,难排错。 | 动态透明地给单个对象添加职责。 不能采用继承方式扩展系统。 | |
外观模式 Facade | 为复杂子系统提供一个统一入口。 电源总开关,文件加密外观类, | 减少了客户端所需处理的对象数目。 实现了子系统与客户端间的松耦合。 子系统修改对其他子系统,外观无影响。 | 不能很好地限制客户端直接使用子系统类。 增加新子系统需修改外观类,违背开闭原则。 | 为复杂子系统提供简单入口。 客户端与多个子系统存在依赖性。 层次性结构通过外观类建立联系。 | 迪米特法则 降耦合 |
代理模式 Proxy | 给对象提供一个代理,并由代理对象控制原对象的引用。 论坛权限控制,图片预览 | 协调调用者、被调用者,降耦合。 增加/更换代理类无须修改代码,符合开闭原则。 | (保护代理)可能造成请求处理缓慢。 (远程代理)实现过程复杂。 | 远程代理,虚拟代理(预览),缓冲代理(共享访问),保护代理(权限),智能引用代理 | |
命令模式(对象型行为模式) Invoker | 将一个请求封装为一个对象,使请求调用者和接收者解耦。 电视遥控器(开关,exchange),功能键 | 降低系统耦合度。 新命令易加入系统,符合开闭原则。 命令队列,宏命令,请求撤销,恢复。 | 可能会导致某些系统有过多具体命令类。 | 将请求调用者和接收者解耦。 不同时间指定请求,请求排队,执行命令撤销,恢复。 | |
迭代器模式 Iterator | 提供一种方法访问聚合对象,而不暴露对象的内部表示。 遥控器换台 | 同一聚合对象可定义多种遍历方式。 简化了聚合类。 增加聚合类、迭代器方便,符合开闭原则。 | 增加新聚合类需要新迭代器类,复杂性提升。 设计难度大,很难全面考虑。 | 访问聚合对象内容而不暴露内部。 为一个聚合类提供多种遍历方式。 为遍历不同聚合结构提供统一接口。 | 单一职责原则 |
观察者模式 Observer | 定义了对象间的一种一对多依赖关系,使每当一个对象状态改变时,其依赖对象得到通知并被自动更新。 猫狗鼠,MVC,自定义登录控件 | 可实现表示层与数据逻辑层分离。 支持广播通信,一对多。 在观察目标和观察者间建立了一个抽象耦合。 增加具体观察者和观察目标符合开闭原则。 | 通知所有观察者会花费很多时间。 如有循环依赖可能使系统崩溃。 观察者不知道目标对象是怎么发生变化的。 | 抽象模型一方面依赖于另一方面。 一个对象改变会导致别的对象改变。 需要在系统中创建一个触发链。 | |
状态模式 State | 允许一个对象在其内部改变时改变它的行为。 论坛用户等级,人开心时笑伤心时哭,银行账户余额为正则绿、欠款则红 | 封装状态转换规则,集中管理代码。 注入不同状态可使环境对象行为不同。 允许状态转换逻辑与状态对象合成一体。 多环境对象共享一个状态对象,可以减少类的个数。 | 增加类和对象的个数,增大开销。 使用不当代码会导致混乱,增加难度。 新增/修改状态类不符合开闭原则。 | 状态改变导致对象行为变化。 代码有大量与对象状态有关的条件语句。 | |
策略模式 Strategy | 定义一系列算法,并将每个算法封装在一个类中,并让他们可以互相替换。让算法独立于使用它的客户而变化。 旅游出行策略,排序策略 | 支持开闭原则,可管理相关算法族。 可替换继承,提高算法复用。 避免多重条件语句。 | 客户端必须知道所有策略类并进行选择。 可能造成系统产生很多具体策略类。 无法同时使用多个策略类。 | 一个系统需动态地在多种算法中选择一个。 避免使用难以维护的多重条件选择。 不希望客户知道与算法相关的数据结构。 | 算法保密性 安全性 |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性