2021年10月技术概括

一、面向对象(封装、继承、多态)
1.封装:set、get方法、可以定义命名某些规则。
2.继承:抽取公共部分属性和方法作为父类。
3.多态:继承、重写、父类类型子类对象,调用子类重写父类的方法,易于扩展维护。
二、jdk、jre、jvm的区别
1.jdk :java开发工具。
2.jre:java开发运行环境。
3.jvm:java虚拟机。
4.jdk包含jre、开发工具(java、javac、jconslo)。
5.jre包含jvm、lib类库。
6.我们写的.java文件通过javac编译成.class文件,再通过jvm根据lib类库生产机器码。
三、双=和equals的区别
1.:双=如果比较基本类型比较的是栈里放的变量值,如果比较的是引用类型比较的是栈里放的堆的地址值。
2.equals:如果没有重写的话和==没有区别,重写后的equals比较的是变量值。object,string都被重写了。
四、final的理解
1.final可以修饰类、方法、变量,都是不可以改变的。
2.为什么局部内部类和匿名内部类必须使用final修饰的局部变量?原因是外部类和内部类级别是一样的,编译后会生成两个.calss文件,而在编译的时候内部类可以复制外部类的局部变量成为内部类的局部变量,为了保证复制一致性使用final来修饰外部类的局部变量。
五、string、stringbuild、stringbuffer的区别
1.string:由于string是被final修饰的,所以每次操作都会创建一个新的对象。
2.stringbuild:线程不安全的,效率比较高。
3.stringbuffer:线程安全的,可以在多线程共享变量的情况下使用。
使用优先级:stringbulid>stringbuffer>string
六、重写和重载的区别
1.重载:重载是在同一个类中发生的,方法名相同,重载参数列表不同。
2.重写:重写是发生在父子类中的,方法名相同,参数列表相同。
七、接口和抽象类的区别
1.一个类只能单继承一个抽象类,一个类可以实现多个接口。
2.抽象类里边可以有实现了的方法,但接口里边全是未实现的方法。
3.抽象类的成员变量可以任意类型,在接口中的成员变量只能是public static final类型的。
4.他俩的设计目标不一样:接口是规范类的行为,抽象类是抽取公共部分作为公共类,为了代码复用设计的,抽象类功能比较强大,但是设计难度比较大,接口可以多实现设计难度比较小。
八、list和set的区别
1.list:list是按对象进入的顺序保存对象,是有序的,可以重复。取值方式有两种:一种是通过iterator取出所有元素,逐一遍历,另一种通过get()获取下标的方式,list可以存储多个null对象。
2.set:set的存储是无序的,不可以重复,取值方式只能通过iterator遍历器取出所有元素,逐一遍历,set只能存储一个null对象。
九、ArrayList和LinkedList的区别
1.ArrayList:基于动态数组,查找比较快,插入比较慢,但如果指定长度(不扩容的情况下),使用尾插法插入,速度也不慢。
2.LinKedList:基于链表,插入比较快,查询比较慢,另外每插入一个元素都会创建node对象,插入较多的元素,会创建很多node对象,消耗比较大。里边用一个item变量管理元素,遍历的话使用迭代器比较好,下标取值会遍历整个链表。还有indexinfo获取元素地址也会遍历整个链表。
十、hashcode和equals
1.hashcode可以计算出哈希值,哈希值是对象在哈希表中位置。
2.hashset为啥不能存储重复的元素,是因为存入hashset的元素根据hashcode计算哈希值,然后根据哈希值找到对象位置,并判断该位置是否有值,如果该位置没有值就把值放这,如果该位置有值,则再根据equals判断是否两个值是否真正相等。如果相等就不存放,如果不相等再重新散列到其他位置,这样减少equals对比,大大提高hashset去重存放效率。
3.如果对象相等,hashcode相同。
4.如果hashcode相同,对象不一定相等。
十一、HashMap和HashTable的区别
1.HashMap是线程不安全的,允许存放null键值。jdk8底层:数组加链表或者红黑树(数组长度64,链表长度8时链表变红黑树)(数组长度6红黑树变为链表),元素是内部类node对象节点存放的,根据key进行hash计算得到哈希值再二次hash计算再取数组的模得到元素存放的位置,如果该位置有值(hash冲突),在进行equals比较,如果相同就覆盖。如果该位置没有值(没有发生hash冲突)会创建node对象存入数组。为啥使用红黑树因为每次get(key)时都会equals比较遍历取值,效率低,红黑树是平衡二叉树查询效率比较高。还有就是数组扩容机制:当数组达到数组长度乘以0.75就开始扩容。如果存放null键值会放在数组索引为0的位置。
2.HashTable是线程安全的(里面每一个方法都加了锁),不允许存放null键值。
十二、 ConcurrentHashMap
1.jdk1.7:数据结构ReenTranLock+Segment+HashEntry,一个Segment包含一个HashEntry数组,一个HashEntry又是一个链表结构,Segment继承了ReenTranLock了是一个分段锁,锁定操作的Segment,其他Segment不受影响,并发个数为Segment的个数,可以根据构造函数来指定Segment的个数,一个数组扩容时,不影响其他Segment的操作。查询:二次hash,第一次找到Segment,第二次找到链表的头部。get方法无需加锁:ConcurrentHashMap里边维护node内部类,类里边有个voletile修饰的val变量是存储元素的,保证线程读的正确性。
2.jdk1.8:数据结构Syntronized+Cas+node+红黑树+Table数组,Syntronized是个重量级锁,他的作用就是在扩容和hash冲突时起作用,Cas是一个乐观锁,他的作用是操作数据(查找、替换、赋值)起作用,Cas锁的是链表的head节点,不影响链表上其他元素的操作,也就说jdk1.7锁的是Segment,jdk1.8锁的是一个node的头节点,锁的力度更细,效率更高。扩容时,阻塞所有读写操作,并发扩容(使用Syntronized锁的原因)。同样读操作无需加锁,也是voletile修饰val和next,而数组加voletile是为了在扩容时线程的可见性。
十三、线程的生命周期
1.创建、就绪、运行、阻塞、死亡。
2.线程阻塞的三种情况一种是线程执行wait方法,该线程会释放所有的占用资源,进入等待池,必须依靠其他线程调用notify或者notifyall来唤醒线程,进入锁池中,wait是object中的方法。第二种是同步阻塞,线程在获取同步锁的时候,发现同步锁有线程占用,jvm就会把该线程放到锁池中。第三种其他阻塞情况,线程调用sleep方法或者join方法或者io阻塞,jvm都会把该线程置为阻塞状态,当sleep超时或者join等待执行完毕,io执行完毕后,线程就进入就绪状态。sleep是Thead类的方法。
3.创建:new一个线程对象。就绪:线程对象创建完毕后,其他线程调用该线程的start方法,进入可运行线程池中,等待cpu调用。
运行:线程获取cpu执行权,执行代码。阻塞:线程因为某种原因放弃cpu执行权,进入阻塞状态,直到线程进入就绪状态才有可能进入运行状态。死亡:线程执行完毕或者因为异常退出run方法,线程结束生命周期。
十四、sleep(),wait(),join(),yelid()方法区别
1.sleep()是Thead类的方法,wait()是Object类的方法。
2.sleep()不会释放锁资源,wait()会释放所有资源进入等待池。
3.join()是线程a执行线程b的join(),等线程b执行完再执行线程a。
4.yelid()是线程让步,从运行状态进入就绪状态,重新获取CPU的执行权。
十五、线程安全问题
1.线程安全问题其实就是内存安全(堆)问题,因为在操作系统中每个进程都会有一块独立的内存,一个进程里边有多个线程,这个块内存有个公共区域(堆内存)是被多个线程共享的,而栈是每个线程独立拥有的,所以线程安全问题就是堆内存被共享的原因。
十六、Thread和Runnable的关系
1.Thread实现了Runnable接口,有更多的api,如果复杂场景下使用Thread。
2.卖票场景:static修饰共享变量,加Syntronized锁。
十七、守护线程的理解
1.守护线程是一个后台线程,当所有用户线程执行完毕时,守护线程也会关闭退出,所以不能用io文件操作,还有就是线程池设置成守护线程也会自动变为用户线程。守护线程里边的子线程也是守护线程。
2.使用场景Gc垃圾回收:当程序执行完,所有Thread执行完,不再产生垃圾时,垃圾回收线程也会退出。
十八、ThreadLocal的原理使用场景和ThreadLocal内存泄漏问题
1.存储结构:每一个Thread线程都会有一个ThreadLocalMap类型的变量ThreadLocals,它存储本线程的ThreadLocal对象及其对应的值。
2.存储过程:当set的时候ThreadLocal会首先获取当前线程对象然后再获取ThreadLocalMap对象,再以当前ThreadLocal对象为key,将值存到ThreadLocalMap对象中。
3.使用场景:一是在对象跨层传递的时候,避免多次传递(controller.service,dao可以不用形参的方式 )。二是在数据库连接的jdbc的时候就是用的ThreadLocal实现了事务隔离性:(spring框架在事务开启时会给当前线程绑定一Connection,事务过程中都是当前线程绑定的连接执行数据操作)。四是Session会话管理。
4.作用:线程间数据隔离。
5.ThreadLocal内存泄漏问题(占用内存),涉及强引用和弱引用问题。每次操作ThreadLocal时需要手动romove下,还有就是将ThreadLocal变量值设置为privite static 为强引用,这样ThreadLocal强引用一直存在,任何时候访问ThreadLocal弱引用都能访问道entry的value值通过romove清除强引用的value。解释:value为强引用不容易回收,所以占用内存,除非当前线程结束才不占内存。原理:当key弱引用清除为null时,再调一次ThreadLocalMap的remove方法就能清除掉value的强引用。
十九、串行,并行,并发的区别和并发的特性
1.串行是一个任务一个任务的去执行
2.并行是在同一时间点执行多个任务
3.并发类似于串行,只不过是任务在切换执行
4.原子性,可见性,有序性。
二十、为什么使用线程池,参数解释
1.为什么使用线程池,减少频繁创建销毁线程,提高响应速度,提高线程的管理型。
2.核心线程数:平时工作的线程(corePoolSize)
3.最大线程数:任务比较多时,会启用最大线程(maxinumPoolSize)
4.空闲时间:就是超过多少空闲时间的线程,会销毁掉。(KeepaliveTime),单位是unit
5.workqueue线程队列,当核心线程用完,等待的任务会先进入到线程队列,如果线程队列也占满的话,就会创建新的线程,如果线程数达到最大线程,就会启用拒接策略(handler)。
6.线程工厂(ThreadFactory)创建线程的。是个接口。
7.线程池种类
①newSingleThreadExecutor
单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务
②newFixedThreadExecutor(n)
固定数量的线程池,没提交一个任务就是一个线程,直到达到线程池的最大数量,然后后面进入等待队列直到前面的任务完成才继续执行
③newCacheThreadExecutor(推荐使用)
可缓存线程池,当线程池大小超过了处理任务所需的线程,那么就会回收部分空闲(一般是60秒无执行)的线程,当有任务来时,又智能的添加新线程来执行。
④newScheduleThreadExecutor
大小无限制的线程池,支持定时和周期性的执行线程

二十一、线程的阻塞队列和线程复用的原理
1.普通队列当任务满时不会接受新的任务,而阻塞队列任务满了以后还会把新的任务阻塞起来。
2.线程池中的线程是任务和线程分开的,一个线程当一个任务执行完会再执行下一个任务。
二十二、spring是什么
1.spring是一个轻量级开发框架包含IOC(控制反转)和AOP(面向切面编程)。
2.spring是一个对象bean容器,还可以整合其他框架。
3.spring容器管理bean对象及整个bean生命周期。
二十三、IOC和AOP的理解
1.IOC:控制反转,依赖注入,将对象的new的权利交给IOC容器管理创建,实现对象和对象某种联系。
2.AOP:切面,主要用途用于日志,事务。(前置后置环绕等等)
二十四、Spring中BeanFactory和ApplicationContext的区别
1.实例化bean的时间点不一样:BeanFactory是在使用的时候实例化,而ApplicationContext是在容器启动的时候就已经实例化好了。
2.BeanFactory是ApplicationContext父接口,ApplicationContext的功能比BeanFactory更强大。
二十五、Spring中bean的生命周期
1.spring生命周期中的阶段,包括初始化、使用、销毁。
二十六、spirngmvc的问点
1.springmvc的执行过程:前端控制器,处理器映射器,处理器适配器,适配器,返回modelandview,视图解析器解析出view返给客户端。
二十七、mybaties的问点
1.一级二级缓存:一级是sqlsession级别的,二级是mapper级别的。
2.${}和#{}的区别:#{}是预编译预处理的,防止sql注入,另一个是字符串。
二十八、springboot的几个核心注解
1.@SpringBootApplication:包含@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
2.@RestController:包含@Controller和@ResponseBody
3.@Service
4.@Repository:用于标注数据访问组件,即DAO组件。
5.@Component:泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
6.@ComponentScan:组件扫描。
7.@Configuration:指出该类是 Bean 配置的信息源,相当于XML中的,一般加在主类上
8.@EnableAutoConfiguration:让 Spring Boot 根据应用所声明的依赖来对 Spring 框架进行自动配置,一般加在主类上。
9.@AutoWired:把配置好的Bean拿来用。
10.@Resource(name=“name”,type=“type”):没有括号内内容的话,默认byName。与@Autowired干类似的事。
11.@RequestMapping:一个用来处理请求地址映射的注解
二十九、springcloud的几个核心组件
1.eureka注册中心,zuul网关,rebbion客户端负载均衡,hystrix断路器,springcloud config配置中心。
三十、数据库和中间件
1.mysql
One.数据库事务的四个特性:
原子性(Atomicity)、一致性(Correspondence)、隔离性(Isolation)、持久性(Durability)。
Two.视图的作用:
视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询;不包含任何列或数据。使用视图可以简化复杂的sql操作,隐藏具体的细节,保护数据;视图创建后,可以使用与表相同的方式利用它们。(相当于字典)。
Three.drop,delete与truncate的区别:
drop直接删掉表 truncate删除表中数据,再插入时自增长id又从1开始 delete删除表中数据,可以加where字句。
Four:索引的工作原理及其种类:
数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用B树及其变种B+树。
在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索引。
为表设置索引要付出代价的:一是增加了数据库的存储空间,二是在插入和修改数据时要花费较多的时间(因为索引也要随之变动)。
种类:唯一索引、主键索引和聚集索引。
唯一索引是不允许其中任何两行具有相同索引值的索引。
当现有数据中存在重复的键值时,大多数数据库不允许将新创建的唯一索引与表一起保存。数据库还可能防止添加将在表中创建重复键值的新数据。例如,如果在employee表中职员的姓(lname)上创建了唯一索引,则任何两个员工都不能同姓。 主键索引 数据库表经常有一列或列组合,其值唯一标识表中的每一行。该列称为表的主键。 在数据库关系图中为表定义主键将自动创建主键索引,主键索引是唯一索引的特定类型。该索引要求主键中的每个值都唯一。当在查询中使用主键索引时,它还允许对数据的快速访问。 聚集索引 在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。
如果某索引不是聚集索引,则表中行的物理顺序与键值的逻辑顺序不匹配。与非聚集索引相比,聚集索引通常提供更快的数据访问速度。
five.连接种类
外连接、内连接、交叉连接(完全)
左外连接:left join 或 left outer join(以左表为主)
右外连接:right join 或 right outer join(以右表为主)
完整外部联接:full join 或 full outer join(左右都为主,返回左右表所有行,匹配不上的为空)
内连接:join 或 inner join(只返回符合条件的table1和table2的列)
交叉连接:cross join (没有 WHERE 子句的交叉联接将产生联接所涉及的表的笛卡尔积,不带 WHERE子查询会产生笛卡尔积)
Sex.数据库优化
SQL语句优化
应尽量避免在 where 子句中使用!=或<>操作符,应尽量避免在 where 子句中对字段进行 null 值判断,都会导致引擎放弃使用索引而进行全表扫描。
用Where子句替换HAVING 子句 因为HAVING 只会在检索出所有记录之后才对结果集进行过滤。
索引优化:看上文索引
数据库结构优化:分库分表
服务器硬件优化:花钱
InnoDB存储引擎(支持事务,mysql默认的),MyISAM存储引擎
2.oracal:先创建表空间,再创建用户授权

3.redis
one.数据类型:string、hash、list、set、sortset。
Two.最近在项目中使用到Redis做缓存,方便多个业务进程之间共享数据。由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF持久化(原理是将Reids的操作日志以追加的方式写入文件)。
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
Three.redis缓存穿透、缓存击穿、缓存雪崩区别和解决方案
缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求。由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。
解决方案
接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
解决方案
1、设置热点数据永远不过期。
2、接口限流与熔断,降级。重要的接口一定要做好限流策略,防止用户恶意刷接口,同时要降级准备,当接口中的某些 服务 不可用时候,进行熔断,失败快速返回机制。
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是, 缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
解决方案
缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
设置热点数据永远不过期。

4.es:倒排索引
5.rebittmq:
RabbitMQ的六种工作模式:
1.simple简单模式
2.work工作模式(资源的竞争)
3.publish/subscribe发布订阅(共享资源)
4.routing路由模式
5.topic 主题模式(路由模式的一种)
6.6RPC 先不做解释
RabbitMQ有什么优缺点?
答:优点:解耦、异步、削峰;
缺点:降低了系统的稳定性:本来系统运行好好的,现在你非要加入个消息队列进去,那消息队列挂了,你的系统不是呵呵了。因此,系统可用性会降低;
增加了系统的复杂性:加入了消息队列,要多考虑很多方面的问题,比如:一致性问题、如何保证消息不被重复消费、如何保证消息可靠性传输等。因此,需要考虑的东西更多,复杂性增大。
如何保证RabbitMQ不被重复消费?
先说为什么会重复消费:正常情况下,消费者在消费消息的时候,消费完毕后,会发送一个确认消息给消息队列,消息队列就知道该消息被消费了,就会将该消息从消息队列中删除;
但是因为网络传输等等故障,确认信息没有传送到消息队列,导致消息队列不知道自己已经消费过该消息了,再次将消息分发给其他的消费者。
针对以上问题,一个解决思路是:保证消息的唯一性,就算是多次传输,不要让消息的多次消费带来影响;保证消息等幂性;
比如:在写入消息队列的数据做唯一标示,消费消息时,根据唯一标识判断是否消费过
如何保证RabbitMQ消息的可靠传输?
答:消息不可靠的情况可能是消息丢失,劫持等原因;
丢失又分为:生产者丢失消息、消息列表丢失消息、消费者丢失消息;
生产者丢失消息:从生产者弄丢数据这个角度来看,RabbitMQ提供transaction和confirm模式来确保生产者不丢消息.
消息队列丢数据:消息持久化。
处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。
这个持久化配置可以和confirm机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个Ack信号。

这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发。
如何保证RabbitMQ消息的顺序性?
单线程消费保证消息的顺序性;对消息进行编号,消费者处理消息是根据编号处理消息;
消费者丢失消息:消费者丢数据一般是因为采用了自动确认消息模式,改为手动确认消息即可!
消费者在收到消息之后,处理消息之前,会自动回复RabbitMQ已收到消息;
如果这时处理消息失败,就会丢失该消息;
解决方案:处理消息成功后,手动回复确认消息。
三十一、jvm优化
1.JVM调优目标:使用较小的内存占用来获得较高的吞吐量或者较低的延迟。
2.调优可以依赖、参考的数据有系统运行日志、堆栈错误信息、gc日志、线程快照、堆转储快照等。
3.调优工具
用 jps(JVM process Status)可以查看虚拟机启动的所有进程、执行主类的全名、JVM启动参数
用jstat(JVM Statistics Monitoring Tool)监视虚拟机信息
用jmap(Memory Map for Java)查看堆内存信息
利用jconsole、jvisualvm分析内存信息
底层结构
jvm的由堆,java栈,本地栈,pc程序计数器,方法区(java8叫元数据区),直接内存,类加载子系统,垃圾回收系统,执行引擎
三十二、前端和后端交互过程,以及安全问题
cookie和session的区别
一、cookie:
在网站中,http请求是无状态的。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。
二、session:
session和cookie的作用有点类似,都是为了存储用户相关的信息。不同的是,cookie是存储在本地浏览器,而session存储在服务器。存储在服务器的数据会更加的安全,不容易被窃取。但存储在服务器也有一定的弊端,就是会占用服务器的资源,但现在服务器已经发展至今,一些session信息还是绰绰有余的。
三、cookie和session结合使用:
web开发发展至今,cookie和session的使用已经出现了一些非常成熟的方案。在如今的市场或者企业里,一般有两种存储方式:
1、存储在服务端:通过cookie存储一个session_id,然后具体的数据则是保存在session中。如果用户已经登录,则服务器会在cookie中保存一个session_id,下次再次请求的时候,会把该session_id携带上来,服务器根据session_id在session库中获取用户的session数据。就能知道该用户到底是谁,以及之前保存的一些状态信息。这种专业术语叫做server side session。
基于Token的身份验证的原理
地址:https://blog.csdn.net/wnvalentin/article/details/89854980
这样大家很嗨皮了,可是服务器就不嗨皮了,每个人只需要保存自己的session id,而服务器要保存所有人的session id ! 如果访问服务器多了, 就得由成千上万,甚至几十万个。这对服务器说是一个巨大的开销 , 严重的限制了服务器扩展能力, 比如说我用两个机器组成了一个集群, 小F通过机器A登录了系统, 那session id会保存在机器A上, 假设小F的下一次请求被转发到机器B怎么办? 机器B可没有小F的 session id啊。
有时候会采用一点小伎俩: session sticky , 就是让小F的请求一直粘连在机器A上, 但是这也不管用, 要是机器A挂掉了, 还得转到机器B去。
那只好做session 的复制了, 把session id 在两个机器之间搬来搬去, 快累死了。
后来有个叫Memcached的支了招: 把session id 集中存储到一个地方, 所有的机器都来访问这个地方的数据, 这样一来,就不用复制了, 但是增加了单点失败的可能性, 要是那个负责session 的机器挂了, 所有人都得重新登录一遍, 估计得被人骂死。
也尝试把这个单点的机器也搞出集群,增加可靠性, 但不管如何, 这小小的session 对我来说是一个沉重的负担
于是有人就一直在思考, 我为什么要保存这可恶的session呢, 只让每个客户端去保存该多好?
可是如果不保存这些session id , 怎么验证客户端发给我的session id 的确是我生成的呢? 如果不去验证,我们都不知道他们是不是合法登录的用户, 那些不怀好意的家伙们就可以伪造session id , 为所欲为了。
嗯,对了,关键点就是验证 !
比如说, 小F已经登录了系统, 我给他发一个令牌(token), 里边包含了小F的 user id, 下一次小F 再次通过Http 请求访问我的时候, 把这个token 通过Http header 带过来不就可以了。
不过这和session id没有本质区别啊, 任何人都可以可以伪造, 所以我得想点儿办法, 让别人伪造不了。
那就对数据做一个签名吧, 比如说我用HMAC-SHA256 算法,加上一个只有我才知道的密钥, 对数据做一个签名, 把这个签名和数据一起作为token , 由于密钥别人不知道, 就无法伪造token了。
这个token 我不保存,当小F把这个token 给我发过来的时候,我再用同样的HMAC-SHA256 算法和同样的密钥,对数据再计算一次签名, 和token 中的签名做个比较, 如果相同, 我就知道小F已经登录过了,并且可以直接取到小F的user id , 如果不相同, 数据部分肯定被人篡改过, 我就告诉发送者: 对不起,没有认证。
Token 中的数据是明文保存的(虽然我会用Base64做下编码, 但那不是加密), 还是可以被别人看到的, 所以我不能在其中保存像密码这样的敏感信息。
当然, 如果一个人的token 被别人偷走了, 那我也没办法, 我也会认为小偷就是合法用户, 这其实和一个人的session id 被别人偷走是一样的。
这样一来,我就不保存session id 了,我只是生成token , 然后验证token,我用我的CPU计算时间获取了我的session 存储空间 !
解除了session id这个负担,可以说是无事一身轻,我的机器集群现在可以轻松地做水平扩展,用户访问量增大,直接加机器就行。这种无状态的感觉实在是太好了!
三十三 IO流
(1)明确要操作的数据是数据源还是数据目的(要读还是要写)
 源:
InputStream  Reader
目的:
OutputStream  Writer
(2)明确要操作的设备上的数据是字节还是文本     
 源:
  字节: InputStream
文本: Reader
目的:
  字节: OutputStream
  文本: Writer
(3)明确数据所在的具体设备   
   源设备:
        硬盘:文件 File开头
        内存:数组,字符串
        键盘:System.in
        网络:Socket
      对应目的设备:
        硬盘:文件 File开头
        内存:数组,字符串
        屏幕:System.out
        网络:Socket
(4)明确是否需要额外功能  
  需要转换—— 转换流 InputStreamReader 、OutputStreamWriter
    需要高效—— 缓冲流Bufferedxxx
    多个源—— 序列流 SequenceInputStream
    对象序列化—— ObjectInputStream、ObjectOutputStream
    保证数据的输出形式—— 打印流PrintStream 、Printwriter
    操作基本数据,保证字节原样性——DataOutputStream、DataInputStream
三十四liunix部署tomcat命令
1.使用当时部署tomcat的用户连接到远程的linux操作系统
2.进入到tomcat的bin目录
cd /home/hstomcat/apache-tomcat-7.0.63/bin
自己的环境,可能安装的目标不一样,需要自己把握
3.使用ls命令,可以看到bin目录下的文件
运行bin目录下的启动命令脚本
sh startup.sh或者./startup.sh
这样tomcat就启用了
4.使用ps -ef | grep javat查看tomcat进程是否启动
5.同样在tomcat的bin目录下,使用sh shutdown.sh可以关闭tomcat
三十五.spring三种注入方式
1.通过构造器来注入;
2.通过setter方法来注入;
3.通过filed变量来注入;
什么是循环依赖?
 循环依赖其实就是循环引用,也就是两个或者两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A
 Spring中循环依赖场景有:
(1)构造器的循环依赖
(2)field属性的循环依赖
其中,构造器的循环依赖问题无法解决,只能拋出BeanCurrentlyInCreationException异常,在解决属性循环依赖时,spring采用的是提前暴露对象的方法。
1.在字段上使用@Autowired注解,让Spring决定在合适的时机注入
  2.用基于setter方法的依赖注入。 
三十六.序列化和反序列化的定义:
(1)Java序列化就是指把Java对象转换为字节序列的过程
Java反序列化就是指把字节序列恢复为Java对象的过程。
(2)序列化最重要的作用:在传递和保存对象时.保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。
反序列化的最重要的作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。
总结:核心作用就是对象状态的保存和重建。(整个过程核心点就是字节流中所保存的对象状态及描述信息)
三十七、spring中的代理模式
 设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆。Spring作为业界的经典框架,无论是在架构设计方面,还是在代码编写方面,都堪称行内典范。那下面就和优就业大白一起来看看吧。

一、简单工厂模式

又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。

简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类。

spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得bean对象,但是否是在传入参数后创建还是传入参数前创建这个要根据具体情况来定。

二、工厂方法模式

通常由应用程序直接使用new创建新的对象,为了将对象的创建和使用相分离,采用工厂模式,即应用程序将对象的创建及初始化职责交给工厂对象。

一般情况下,应用程序有自己的工厂对象来创建bean.如果将应用程序自己的工厂对象交给Spring管理,那么Spring管理的就不是普通的bean,而是工厂Bean。

三、单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是是任意的java对象。

四、适配器模式

在Spring的Aop中,使用的Advice(通知)来增强被代理类的功能。Spring实现这一AOP功能的原理就使用代理模式对类进行方法级别的切面增强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,通过执行拦截器重的内容增强了代理方法的功能,实现的面向切面编程。

五、包装器模式

spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名中含有Decorator。基本上都是动态地给一个对象添加一些额外的职责。

六、代理模式

为其他对象提供一种代理以控制对这个对象的访问。 从结构上来看和Decorator模式类似,但Proxy是控制,更像是一种对功能的限制,而Decorator是增加职责。

七、观察者模式

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

八、策略模式

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值