java套餐
2021-04-08 08:52:05 0 举报
AI智能生成
java 基础
作者其他创作
大纲/内容
开发框架
spring
过滤器、监听器、拦截器
过滤器(Filter)
介绍
Filter 对用户请求进行预处理,接着将请求交给Servlet进行处理并响应,最后Filter再对服务器响应进行后处理。
过滤器依赖Servlet容器
应用场景
编码过滤(解决全站中文乱码)
过滤敏感词语
压缩资源
监听器(Listener)
介绍
用于监听java对象方法的调用或属性的改变
当事件源发送某些改变时,会调用监听器的方法,并把事件源传进去,那么监听器就可以操作事件源数据
监听器的底层原理采用的是观察者模式
三大监听器
ServletContextListener 对象监听器
HttpSessionListener 对象监听器
ServletRequestListener 对象监听器
HttpSessionListener 对象监听器
ServletRequestListener 对象监听器
监听对象自身的创建和销毁
监听对象中属性的创建和销毁
应用场景
统计网站在线人数
监听用户的行为等
拦截器(Interceptor)
介绍
拦截器 类似AOP的切面和通知, 通过动态代理对一个service()方法添加通知进行功能增强
拦截器只能对Controller的http请求进行拦截
拦截器基于java反射机制
IOC 控制反转
描述
所谓 IOC ,就是由 Spring IOC 容器来创建Bean,管理Bean,对Bean控制权交由容器管理
配置方式
通过xml配置文件
@Resource或@Autowired注解配置
两种类型的IOC容器实现
BeanFactory(IOC容器的基本实现)
ApplicationContext(提供更多的高级特性,是BeanFactory的子接口)
是面向使用Spring框架的开发者
几乎所有的应用场合都是直接使用ApplicationContext而非底层的BeanFactory
无论使用哪种方式,配置方式相同
无论使用哪种方式,配置方式相同
ApplicationContext的主要实现类
ClassPathXmlApplicationContext
从类路径下加载配置文件
该实现类扩展于ApplicationContext,新增了两个主要方法:refresh()和close(),
让ApplicationContext在初始化上下文的能力
让ApplicationContext在初始化上下文的能力
ApplicationContext 在初始化上下文时就实例化所有单例的Bean
WebApplicationContext是专门为web应用而准备的,
它允许从相对于web根目录的路径中完成初始化工作
它允许从相对于web根目录的路径中完成初始化工作
FileSystemXmlApplicationContext
从文件系统中加载配置文件
Bean的生命周期
1、通过构造器或工厂方法创建Bean实例化 Instantiation
2.为Bean的属性赋值和对其他Bean的引用 Populate
3.调用Bean的初始化方法 postProcessBeforeInitialization
4. 调用Bean的后置处理器postProcessBeforeInitialization 方法,就可以使用
5. 当容器关闭时,调用Bean的销毁方法 Destruction
Bean的作用域
默认情况下,Spring每个在IOC容器的Bean创建单实例,整个IOC容器范围内都能共享该实例。
五个作用域
1、singleton,默认的,这种范围确保不管接受到多个请求,每个容器中有一个bean的实例,单利模式由BeanFactory自身来维护。
2、Protype,为每一个bean对象创建多个实例。
3、request,在请求bean范围内,为每一个请求创建一个实例,在请求完成之后,bean会失效并被垃圾回收器回收。
4、session,该作用域将 bean 的定义限制为 HTTP 会话,在session过期后bean会随之消失。
5、global-session,它仅仅在基于portlet的web应用中才有意义
BeanFactory和FactoryBean的区别
共同点
都是接口
区别点
BeanFactory,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范。
它是一个工厂类,用于管理Bean的一个工厂,在Spring中,
所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。
它是一个工厂类,用于管理Bean的一个工厂,在Spring中,
所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。
FactoryBean,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean。
但为IOC容器中Bean的实现提供了更加灵活的方式,
FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式
但为IOC容器中Bean的实现提供了更加灵活的方式,
FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式
AOP 面向切面编程
描述
AOP是一种面向切面的编程思想。不影响业务的本来情况下,增加一些新的功能!
应用场景
日志记录,权限验证,效率检查,事务管理
动态代理
JDK动态代理(针对接口,代理类为其兄弟类),目标对象实现类若干接口
动态设计模式原理: 使用一个代理将对象包装起来,然后该代理对象取代原始对象,任何对
原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上。
原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上。
cglib动态代理(针对类,代理类为其子类),目标对象没有实现接口
声明切面
在spring中声明AspectJ 切面,只需要在IOC容器中将切面声明为Bean实例,
当Spring IOC 容器中初始化AspecJ 切面后,SpringIOC容器就会为那些与AspectJ 切面相匹配的Bean 创建代理。
在AspectJ 注解中,切面只是一个带有@Aspect 注解的Java 类。
通知是标注有某种注解的简单的Java 方法。
当Spring IOC 容器中初始化AspecJ 切面后,SpringIOC容器就会为那些与AspectJ 切面相匹配的Bean 创建代理。
在AspectJ 注解中,切面只是一个带有@Aspect 注解的Java 类。
通知是标注有某种注解的简单的Java 方法。
五个通知类型
前置通知(Before advice)
在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)
后置通知(After returning advice)
在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
异常通知(After throwing advice)
在方法抛出异常退出时执行的通知。
最终通知(After (finally) advice)
当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
环绕通知(Around Advice)
包围一个连接点的通知,这是最强大的一种通知类型。
环绕通知可以在方法调用前后完成自定义的行为。
它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。
环绕通知可以在方法调用前后完成自定义的行为。
它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。
事务隔离级别
当同一个应用程序或者不用应用程序中的多个事务都在同一个数据集上并发运行时,可能会出现许多意外的问题
并发事务所导致的问题可以分三种类型
脏读
对于两个事务T1,T2。T1读取了已经被T2更新但还没提交的字段,
之后,若T2回滚, T1读取的内容就是临时且无效的
之后,若T2回滚, T1读取的内容就是临时且无效的
不可重复读
对于两个事务T1,T2。 T1读取了一个字段,然后T2更新了该字段,
之后, T1再次读取同一个字段,值就不同了
之后, T1再次读取同一个字段,值就不同了
幻读
对于两个事务T1,T2。 T1从一个表读取了一个字段,然后T2在该表插入一些新的行,
之后,如果T1再次读取同一个表,就会多出几行
之后,如果T1再次读取同一个表,就会多出几行
五中隔离级别
设置
同@Transactional注解声明式的管理实务,可以在@Transactional的isolation属性设置隔离级别
1. ISOLATION_DEFAULT: 默认的隔离级别,使用数据库默认的事务隔离级别.
另外四个与 JDBC的隔离级别相对应:
2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读
3. ISOLATION_READ_COMMITTED: 允许从已经提交的事务读取,可防止脏读、但幻读,不可重复读仍然有可能发生
4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。
但是可能出现幻像读。 它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5. ISOLATION_SERIALIZABLE :完全服从acid隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低。
另外四个与 JDBC的隔离级别相对应:
2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读
3. ISOLATION_READ_COMMITTED: 允许从已经提交的事务读取,可防止脏读、但幻读,不可重复读仍然有可能发生
4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。
但是可能出现幻像读。 它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5. ISOLATION_SERIALIZABLE :完全服从acid隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低。
事务传播行为
定义
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播,
如:方法可能继续在现有事务中运行,也可能开启一个新的事务,并在自己的事务中运行
如:方法可能继续在现有事务中运行,也可能开启一个新的事务,并在自己的事务中运行
七种传播行为
propagation_required
spring默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,
一块提交,一块回滚。如果外层没有事务,新建一个事务执行
一块提交,一块回滚。如果外层没有事务,新建一个事务执行
propagation_supports
如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行。完全依赖外层的事务
propagation_mandatory
与NEVER相反,如果外层没有事务,则抛出异常
propagation_nested
该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,
即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。
即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的。
propagation_never
总是非事务地执行,如果存在一个活动事务,则抛出异常。
propagation_requires_new
该事务传播机制是每次都会新开启一个事务,同时把外层事务挂起,当当前事务执行完毕,
恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可
恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可
propagation_not_supported
该传播机制不支持事务,如果外层存在事务则挂起,执行完当前代码,
则恢复外层事务,无论是否异常都不会回滚当前的代码
则恢复外层事务,无论是否异常都不会回滚当前的代码
扫描组件
base-package属性指定一个需要扫描的基类包,spring容器将会扫描这个基类包及其子包中的所有类
如果需要扫描多个包时,可以使用逗号分隔
如果需要扫描多个包时,可以使用逗号分隔
@Autowired
通过Bean类型(byType)匹配
@Resource
通过byName自动注入
springMVC
流程原理
1、 用户发送请求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器,我们使用了@Controller注解,
添加了@Controller注解注解的类就可以担任控制器(Action)的职责,)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器,我们使用了@Controller注解,
添加了@Controller注解注解的类就可以担任控制器(Action)的职责,)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
springmvc和struts2区别
相同点
都是基于MVC设计模式
底层都是对ServletAPI的封装
处理请求的机制都有一个核心控制器
区别
springmvc的入口是Servlet,struts2的入口是filter
springmvc的最小颗粒是方法,而struts2是类,因此springmvc更快
spring Boot
为什么使用spring Boot
1、能够独立运行,内置许多Servlet容器
2、简化很多配置,并且可以自动配置
3、配置过程中没有代码生成和不用xml配置
启动流程
@SpringBootApplication
项目的核心注解,代表这是一个Sprnig Boot 应用,目的是开启自动配置
@SpringBootConfiguration
里面@Configuration, 代表这是一个配置类
@EnableAutoConfiguration
@AutoConfigurationPackage,开启自动配置包,收集和注册特定场景相关的bean
@Import(AutoConfigurationImportSelector.class),获取自动配置的实体
@ComponentScan
自动扫描并加载符合条件的bean,最终将bean加载到IOC容器中
配置
yaml,强调这种语言以数据为中心,与properties的区别
properties,以key=value格式,形式单一,功能有限,慢慢的可能会被抛弃
yaml:数据作为中心的配置文件,普通的键值对,对象,map,数组,等,所以springBoot强烈推荐我们使用yaml
语法
基本语法
k:
v:
v:
对象,map
k:
name: aa
age: 11
支持行内写法:
k:{name: aa, age:11}
name: aa
age: 11
支持行内写法:
k:{name: aa, age:11}
数组,list
lists:
- aa
- 11
- aa
- 11
单元测试
@SpringBootTest注解进行单元测试
在pom.xml文件添加spring-boot-starter-test依赖
微服务架构
微服务架构,就是将原有项目模块化,功能化。
原来一个服务器解决的问题,现在需要多个服务器,集群!
原来一个服务器解决的问题,现在需要多个服务器,集群!
微服务架构面临的4个问题
1、多个服务,服务与服务之间如何通信?
2、多个服务,客户端如何和服务器通信?
3、多服务,如何管理?
4、多服务,服务挂了怎么办?
Spring Cloud
2018年底,Netfilx 宣布Spring Cloud 无限期停止维护。
Apache Dubbo + zookeeper
待完善
Spring Cloud Alibaba
一站式解决方案,提供了全套配置
待完善
myBaties
描述
Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,
开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。
开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。
工作原理
1、SqlSessionFactoryBuilder通过Configuration对象生成SqlSessionFactory,用来开启SqlSession
2、SqlSession提供用户对数据库操作的API,完成增伤改查
3、Executor执行器负责SQL语句的生成和查询缓存的维护
4、StatementHandler 负责对JDBC statement 的操作
5、ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所对应的数据类型
6、ResultSetHandler 将JDBC返回的ResultSet 结果集对象转换成List集合
7、TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换
mapper代理
1、mapper接口的类名的全路径 必须和 mapper映射文件的namespace值一致
2、mapper接口的方法名 必须和 mapper映射文件的statement的id一致
3、mapper接口的方法参数类型 必须和 mapper映射文件的statement的parameterType的值一致
4、mapper接口的方法返回参数类型 必须和 mapper映射文件的statement的resultType的值一致
#{}和${}的区别
#{}是预编译处理,${}是字符串替换。
安全框架
Shiro
描述
Apache Shiro是Java的一个安全框架
工作流程
四大核心组件
Authentication(认证),身份证认证,一般就是登录
第1步:程序代码调用 Subject.login 方法,向AuthenticationToken(认证令牌)实例的构造函数传递用户的身份和证明。
第2步:Subject 实例,将这个令牌转交给程序的 SecurityManager。
第3步:SecurityManager,将认证请求转发给 Authenticator 实例。
第4步:Authenticator 采取AuthenticationStrategy(安全策略)完成认证处理,最终回应每个Realm结果
第2步:Subject 实例,将这个令牌转交给程序的 SecurityManager。
第3步:SecurityManager,将认证请求转发给 Authenticator 实例。
第4步:Authenticator 采取AuthenticationStrategy(安全策略)完成认证处理,最终回应每个Realm结果
Authorization(授权),权限验证
Cryptography(加密), 数据加解密,比如密码加解密等
Session Management(session管理), 用户的会话管理员,多数情况下是web session
Spring Security
待完善
JWT
描述
Json web token(JWT),是为了在网络应用环境间传递声明而执行的一种基于json开放标准
结构
JWT由三段信息构成
三部分
头部(header)
jwt的头部承载两部分信息:
1、声明类型,表示jwt
2、声明加密算法,通常直接使用HMAC SHA256
完整的头部就像下面的json:
{‘type’:'JWT', 'alg':'HS256'}
1、声明类型,表示jwt
2、声明加密算法,通常直接使用HMAC SHA256
完整的头部就像下面的json:
{‘type’:'JWT', 'alg':'HS256'}
载荷(playload)
载荷就是存放有效信息的地方,这些信息包含三个部分
三部分
标准中注册的声明
ss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
公共声明
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息。
但不建议添加敏感信息,因为该部分在客户端可解密。
但不建议添加敏感信息,因为该部分在客户端可解密。
私有声明
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,
因为base64是对称解密的
因为base64是对称解密的
完整的payload的json
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
签证(signature)
优点
1、 因为json的通用性,所以jwt支持跨语言
2、因为payload部分,所以jwt可以存储一些业务必要的非敏感信息
3、便于传输,jwt构成非常简单,字节占用很小
4、不需要在服务端存储会话信息,应用的扩展性高
缺点
1、服务器不保存会话状态,所有有效期内不能取消token或更新token,有效期内一直有效
2、jwt本身包含认证信息,所以一旦信息泄露,任何人都可以获得token的所有权限。
为了减少盗用,jwt的有效期不宜设置太长
为了减少盗用,jwt的有效期不宜设置太长
3、为了减少盗用和窃取,jwt不建议使用http协议传输代码,而是使用加的https协议
服务中间件
nginx
负载均衡
描述
nginx抗并发能力强,通常用于集群服务器的负载均衡
负载策略
1、轮询(默认),每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
2、指定权重,指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
3、IP绑定 ip_hash,每个请求按访问ip的hash结果分配,每个访客固定访问一个后端服务器,可以解决session的问题
4、fair(第三方),按后端服务器的响应时间来分配请求,响应时间短的优先分配。
5、url_hash(第三方),按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
处理静态资源,支持静态资源缓存,如图片、js、css等
反向代理
正向代理:内网通过代理服务器访问外网,如vpn
反向代理:外网通过代理服务器访问内网,可以保证内网安全性
apache
待完善
并发编程
死锁的原因
1、互斥条件
某个资源在一段时间内只能由一个进程占有,不能同时被两个或两个以上的进程占有
2、不可抢占条件
进程所获得的资源在未使用完毕之前,资源申请者不能强行地从资源占有者手中夺取资源,而只能由该资源的占有者进程自行释放
3、持有资源并不去释放
进程至少已经占有一个资源,但又申请新的资源;由于该资源已被另外进程占有,此时该进程阻塞;但是,它在等待新资源之时,仍继续占用已占有的资源。
4、循环等待条件
存在一个进程等待序列{P1,P2,Pn},其中P1等待P2所占有的某一资源,P2等待P3所占有的某一源,......,而Pn等待P1所占有的的某一资源,形成一个进程循环等待环。
死锁的预防
死锁发生时的四个必要条件,只要破坏这四个必要条件中的任意一个条件,死锁就不会发生。
1、打破互斥条件。即允许进程同时访问某些资源。但是,有的资源是不允许被同时访问的,像打印机等
集合框架
Collection 接口
Set 接口
其中的元素具有唯一性,仅允许包含一个null值对象,元素是无序的
List
元素是有序的,并且允许重复
ArrayList
底层由数组实现,非线程安全
初始化大小
jdk1.7
1.7是饿汉式创建集合容量
先调用无参构造函数,再调用有参构造函数,初始化10
jdk1.8
1.8是懒汉式创建集合容量
调用无参构造函数,默认空数组,在add的时再调用构造函数,初始化容量为10的数组
扩容机制
当插入的数据超过原来数组大小时就会进行扩容,扩容是原来的1.5倍
扩容方式: 将数据拷贝到新的数组, 原来的数组抛弃,会被GC回收
LinkedList
底层是双向链表
当数据量很大或者操作很频繁的情况下,添加和删除元素时具有比ArrayList更好的性能。
但在元素的查询和修改方面要弱于ArrayList。
Vector
底层是数组,且线程安全(synchronized关键字修饰方法)
支持动态扩容(扩容为原来的1.5倍)
Map
HashMap
初始化及扩容
初始数组容量(默认16)
负载因子(默认0.75)
当数量超过 负载因子*容量 这个阈值, 那么HashMap 就会扩容,扩容为原来的2倍
结构
jdk1.7
数组+链表(单向链表)
链表采用头部插入法
在多线程的情况下,扩容时可能会产生死锁
jdk1.8
数组+链表+红黑树
何时转红黑树
1、数组容量达到64,
2、单个链表超过8个
2、单个链表超过8个
何时转链表
当红黑树节点数量小于6
链表采用尾部插入法,避免死锁
哈希碰撞
在多线程下put操作时,执行addEntry,如果有产生哈希碰撞,
会导致两个线程得到同样的bucketIndex去存储,就会出现覆盖丢失的情况
会导致两个线程得到同样的bucketIndex去存储,就会出现覆盖丢失的情况
可以采用ConcurrentHashMap
ConcurrentHashMap
线程安全
在ConcurrentHashMap中,就是把Map分成了N个Segment(分段锁功能),
put和get的时候,都是现根据key.hashCode()算出放到哪个Segment中
put和get的时候,都是现根据key.hashCode()算出放到哪个Segment中
ConcurrentHashMap中默认是把segments初始化为长度为16的数组
put操作
value 为 null
抛出异常
value 不为 null
1、通过hash的高位获取segment 的索引值
2、对segment 上锁
3、容量不满足, 扩容
4、定位到具体的桶
5、在桶上判断key是否存在
存在,替换新增,返回旧值
不存在,添加一个节点,返回null
6、释放锁
get操作
1、根据hash定位到segment
2、判断是否桶的hash值与hash值相等
1、相等,找到指定的value
2、不相等, 返回null
Hashtable
在jdk1.1版本就有了,是线程安全
它在put,get,remove 上做了同步处理,保证了Hashtable的线程安全
因为只有一个线程可以操作Hashtable,所以效率比较低
TreeMap
实现了SortedMap 接口
底层采用红黑树算法实现
线程不安全
数据库
mysql
引擎
InnoDB(存储磁盘)
事务型的存储引擎,有行级锁和外键约束
MyIsam(存储磁盘)
不支持事务,不支持行锁和外键,所以insert和update数据操作需要锁定整个表,效率偏低
Memory(存储堆内存)
索引
聚集索引
InnoDB 存储结构是B+tree,但是叶子节点存储的是一条数据,索引和数据都在叶子节点上
非聚集索引
MyIsam 储存结构是B+tree,但是叶子节点储存的是数据的地址, 索引和数据是分开的,所以是非聚集索引
事务
ACID
原子性
整个事务中的所有操作要么全部提交成功,要么全部失败回滚
一致性
数据库总是从一个一致性的状态转换到另一个一致性的状态,其他三个都是为了保证事务的一致性
隔离性(MVCC+锁)
四种隔离级别
读未提交
脏读
不可重复读
幻想读
读已提交
不可重复读
幻想读
可重复读(系统默认)
黄想读
可串行化
持久性
一旦事务提交,则其所做的修改不会永久保存到数据库
事务日志
undo log
undo log是回滚日志,提供回滚操作
redo log
redo log是重做日志,提供前滚操作
锁
共享锁/排它锁
意向锁
间隙锁
主从复制
采用binlog
分库分表
四种分库分表
垂直分库
垂直分表
水平分库
水平分表
如何解决全表查询的问题?
Mycat
sharding-jdbc/sharding-sphere
子主题
tddl
怎么扩容?
双倍扩容,提升备库为主库,重新取模,冗余数据删除
web基础
Servlet
生命周期
init(ServletConfig config)方法,在servlet初始化时被调用
service(ServletRequest request, ServletResponse response)方法,处理客户端请求
destroy(),在servlet销毁时调用
配置
在web.xml中配置servlet和servlet-mapping信息
@WebServlet注解用于标注在一个继承了HttpServlet类之上
jsp
9个内置对象
pageContext:PageContext类型,页面上下文对象
request:ServletRequest类型,表示HTTP请求
response:ServletResponse类型,表示HTTP响应
session:HttpSession类型,表示当前会话
application:ServletContext类型,表示当前Web应用
exception:Throwable类型
out:JspWriter类型,JSP页面输出流<
page:Object类型,页面对象
config:ServletConfig对象,表示当前Servlet
4个作用域
page:当前页面范围
request:请求范围
session:当前会话范围
application:当前web应用范围
cookie
描述
cookie是web服务器发送给浏览器的一块信息,存在于客户端,只能存储String类型
大小限制
有个数和大小的限制,大小一般是4k
安全性
Cookie 在本地 可以被更改文件 敏感的数据不要放在cookie里
是否可跨域
Cookie具有不可跨域名性。
session
描述
session是存在于服务器端的,无法禁用关闭,session能够存储任意的java对象
面向对象三大特性
封装
封装就是将属性私有化,提供公有的方法访问私有的属性
通过封装,可以实现对属性的数据访问限制,增强了程序的可维护性
继承
子类继承父类的特征和行为,使得子类具有父类的各种属性和方法
特点
在继承关系中,父类更通用,子类更具体
多态
java多态性的概念可以被说成“一个接口,多个方法”
三个必要条件
要有继承
要有重写
父类引用指向子类对象
实现方式
接口实现, 继承父类进行方法重写,同一个类中进行方法重载
Swagger
描述
可以与SpringMVC 集成为项目生成Resultful API文档,并且可以直接在网页测试
常用注解
@Api()用于类:表示标识这个类是swagger的资源
tags-表示说明 value-也是说明,可以使用tags替代 但是tags如果有多个值,会生成对个list
@ApiOperation():用于方法;表示一个HTTP请求的操作
Value用于方法的描述 notes:用于提示内容 tags可以重新分组(视情况而用)
@ApiParam()用于方法,参数,字段说明;
Name:参数名 value:参数说明 required:是否必填
@ApiModel()用于类:表示对类进行说明,用于参数用实体类接收
Value:表示对象名 description:描述 这些都可以省略
@ApiModelProperty():用于方法,字段;表示对model属性的说明
Value-字段说明 name-重写属性名字 dataType-重写属性类型 required-是否必填 example-举例说明 hidden-隐藏
@ApiIgnore()用于类或者方法上,可以不被swagger显示在页面上
优点
调用和调试接口方便
和项目结合紧密,生成文档方法
支持Restful风格的API,和http中默认的方法十分契合
缺点
前置条件较多,需要部署好项目才能使用
IO模型
基本概念
区分阻塞、非阻塞、同步、异步
同步与异步
同步和异步关注的是消息通信机制
同步
发出一个功能调用时,没有得到结果前,该调用不返回。
异步
发出一个功能调用时,调用者不能立刻得到结果。
阻塞与非阻塞
阻塞和非阻塞关注的是 程序在等待调用结果(消息,返回值)时的状态
阻塞
调用结果返回之前,调用者会进入阻塞状态等待,只有得到结果后才会返回
非阻塞
指不能立刻得到结果之前,该函数阻塞当前线程,而会立刻返回
四种组合
同步阻塞(IO(BIO))
得不到结果不返回,线程进入阻塞状态等待
字节流 / 字符流
性能: 性能较差,吞吐量低
同步非阻塞(NIO)
得不到结果不返回,线程不阻塞一直在cpu运行
与传统IO(BIO)对比,IO是面向流的,NIO是面向缓冲区
主要结构
Channel(通道,双向)
多路复用。传统IO的流是单向的,不能同时用来进行读写操作,而Channel则是双向的
通过open()的静态方法打开一个通道
Selector(选择器)
Selector类是NIO的核心类,一般称为选择器或多路复用器
它能够检测多个注册的Channel上是否有事件发生,便获取事件然后进行相应的处理
Buffer(缓冲区)
作用:相当于BIO编程中常用的基本类型数组(byte[],char[]等),比如ByteBuffer就是对byte数组进行封装的,使得操作起来更方便
使用的是堆外内存,不受GC管理(GC主要是堆内存)
非线程安全:selector.select()去查询每个通道是否有到达事件,如果没有事件,则一直阻塞在那里,因此这种方式会导致用户线程的阻塞。
异步阻塞(NIO)
去到别的线程,让别的线程阻塞起来等待结果,自己不阻塞
异步非阻塞(AIO)
去到别的线程,别的线程一直在运行,直到得出结果
项目管理
maven
生命周期
Maven的生命周期是抽象的,即生命周期不做任何实际的工作,实际任务由插件完成
包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有的构建步骤
三套相互独立的生命周期
分别是clean、default和site。每个生命周期包含一些阶段,阶段是有顺序的,后面的阶段依赖于前面的阶段。
clean
pre-clean
clean
post-clean
default
compile
test
package:打包-会生成target文件
install:加入仓库
site
pre-site
post-site
site-depoly
git
待完善
缓存框架
redis
数据类型
String
set,get,exists(判断key是否存在)
常规key-value缓存应用
Hash
hget(获取值),hset(设置值),hgettal(获取所有),hdel(删除某值)
特别适合用于存储对象,可以直接仅仅修改这个对象中的某个字段的值
List
ipush,rpush,lpop,rpop,lrange
一个双向链表,既可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销
微博的关注列表,粉丝列表,消息列表等功能都可以用redis的list结构来实现
Set
sadd,spop,smembers,sunion
基于set轻易实现交集,并集,差集的操作
redis可以非常方便的实现如共同关注,共同粉丝,共同喜好等功能
Sorted Set
zadd,zrange,zrem,zcard
和set相比,sorted set 增加了一个权重参数score,使得集合中的元素能够按score进行有序排序
在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜
过期机制
应用
session
token
验证码
策略
定期删除
redis默认是每隔100ms就随机抽取一些设置了过期时间的key
如果过期就删除
之所以随机,因为遍历所有过期时间的key, 对cpu消耗大
优点
节约内存,到点删除,快速释放不必要内存
缺点
CPU压力大,无论CPU负载量多高,均占CPU
惰性删除
查询key的时候再去判断是否过期
弥补定时删除的遗留
优点
节约CPU性能
缺点
占用内存,内存压力大
内存淘汰机制
背景
内存不够,定期删除没有删掉,并且没有被查询,需要定期删除
过程
内存占用达到内存限制设定值时触发的redis淘汰策略来删除key
redis配置文件中可以使用maxmemory将内存使用限制为指定的字节数
当达到内存限制时,redis会根据选择的淘汰策略来删除key
策略
LRU(Least Recently Used) 最近最少使用的
LFU(Least Frequently Used) 最不常用的
volatile-lru 在带有过期时间的key中选择最近最少使用的(推荐)
allkeys-lru 在所有的key中选择最近最少使用的(一般推荐)
valatile-lfu 在带有过期时间key中选择最不常用的
allkeys-lfu 在所有的key中选择最不常用的
volatile-random 在带有过期时间的key中随机选择
allkeys-random 在所有key中随机选择
valatile-ttl 在带有过期时间的key中选择最近过期的
noeviction 不要删除任何东西,只是在操作上返回一个错误(默认)
持久化机制
描述
什么是redis持久化,就是将内存数据保存到硬盘
如果redis关闭持久化机制,它的数据会跟你的服务器共生存
RDB (redis database)
快照方式持久化(系统默认策略)
快照方式持久化(系统默认策略)
三种触发方式
1、save(同步)
2、bgsave(异步)
3、自动(符合配置文件中save满足条件)
子主题
流程说明
判断当前是否正在进行持久化,如果有直接返回
fork出子进程,此时父进程会阻塞
fork完成,父进程可以相应命令
子进程根据父进程内存生成快照文件,并替换原来RDB文件
优点
延时比较高,断点死机等情况,数据丢失比较多
加载RDB文件快于AOF
缺点
无法试试持久化,fork是重量级操作,频繁执行成本高
二进制存储,各版本文件格式不兼容
总结
RDB做镜像全量持久化, 因为RDB耗费较长时间,不够实时,在停机的时候会导致大量数据丢失,所以需要AOF来配合使用
AOF(Append-only file)
解决了数据持久化的实时性
解决了数据持久化的实时性
client每次请求redis,都会将写请求的命令保存到文件中
流程说明
命令写入
以文本的形式将命令写入缓冲区aof_buf
文件同步
always命令写入aof_buf后调用系统fsyns操作同步到AOF文件,fsyns完成后线程返回
everysec命令写入aof_buf后调用系统write操作,write完成后线程返回。fsync同步操作专门的线程每秒调用一次
no命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步,同步硬盘操作由操作系统周期负责,最长30秒
write仅写到缓存区,fsync才是同步到硬盘
文件重写
主节点命令写入完成后,直接返回结果给客户端,并不等待子节点同步完成
重启加载
AOF追加阻塞
当文件同步模式everysec时,主线程会检测fsync同步时间,如果距离上一次同步成功超过2秒,主线程会阻塞并等待同步完成
优点
可读性强
数据丢失可控
缺点
文件体积大,恢复时间长
总结
AOF是做增量持久化
混合持久化
重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。
我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 rdb 来说要慢很多,
这样在 Redis 实例很大的情况下,启动需要花费很长的时间。
这样在 Redis 实例很大的情况下,启动需要花费很长的时间。
Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。
AOF在重写(aof文件里可能有太多没用指令,所以aof会定期根据内存的最新数据生成aof文件)时,
将重写这一刻之前的内存rdb快照文件的内容和增量的 AOF修改内存数据的命令日志文件存在一起,
都写入新的aof文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,
原子的覆盖原有的AOF文件,完成新旧两个AOF文件的替换;
将重写这一刻之前的内存rdb快照文件的内容和增量的 AOF修改内存数据的命令日志文件存在一起,
都写入新的aof文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,
原子的覆盖原有的AOF文件,完成新旧两个AOF文件的替换;
AOF根据配置规则在后台自动重写,也可以人为执行命令bgrewriteaof重写AOF。
于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,
重启效率因此大幅得到提升。
于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,
重启效率因此大幅得到提升。
如果redis宕机或重启时想要恢复数据,会优先采用哪种方式恢复数据呢?
AOF与RDB同时开启时,会优先使用AOF恢复数据,如果采用RDB恢复数据,可以先将AOF关闭,appendonly no,重启完成后,
执行config set appendonly yes动态开启AOF
AOF与RDB同时开启时,会优先使用AOF恢复数据,如果采用RDB恢复数据,可以先将AOF关闭,appendonly no,重启完成后,
执行config set appendonly yes动态开启AOF
事务
实现方式
1、将多个命令请求打包
2、一次性、按顺序执行多个命令
3、事务执行期间,服务器不会中断事务而改去执行其他客服端的命令请求
4、将事务中所有命令都执行完毕,然后才去处理其他客户端的命令请求
三个阶段
1、开始事务
2、命令入队
3、执行事务
集群
三高架构
高可用
高并发
高性能
主从复制
描述
master可以拥有多个slave
多个slave可以连接同一个master外,还可以连接到其他slave
主从复制不会阻塞master,在同步数据时,master可以继续处理client请求
作用
数据冗余
实现数据热备份,是持久化的另一种方式
故障恢复
当主节点出现问题时,可以由从节点提供服务
负载均衡
读写分离,一主多从,从节点分担读的压力,提供并发量
同步流程
1、定时任务每秒检查是否有新的mater需求连接,如果发现就与master建立socket连接
2、slave发送ping指令到mater
3、如果mater配置request pass,slave需要发送认证给master
4、slave会发送sync命令到master
5、master启动一个后台进程,将redis中的数据快照RDB保存到文件中
7、master完成写文件操作后,将RDB发送给slave
8、slave将RDB保存到磁盘,然后加载RDB到redis内存中
9、当slave完成数据快照的恢复后,master将这期间收集的写命令发送给slave端
10、后续master收集到的写命令都会通过之前建立的连接,增量发送给slave
断点续传
1、slave向master发送psync命令,写到master的runid和复制偏移量
偏移量描述
一个数字,描述复制缓冲区的指令字节位置
master记录发送给slave指令字节对应的位置
slave记录slave接收master发送过来的指令字节对应的位置
作用,同步信息,比对master和slave的差异,slave断线后,恢复数据使用
2、master验证runid和自身runid是否一致,如果不一致,则进行全量复制
3、master验证复制偏移量是否在积压缓冲区内,如果不在,则进行全量复制
4、如果验证都通过,则master将在积压内的偏移量后的所有数据发送给slave,最后主从服务器再次回到一致状态
配置主从复制
一般情况下只需要配置丛集就好,认老大
命令
slave <masterip> <masterprot>
哨兵模式
功能描述
1、集群监控,负责监控redis master和slave进程是否正常工作
2、消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
3、故障转移,如果master node挂掉,会自动转移到slave node上
故障转移时,判断一个master node宕机,如果大部分的哨兵都同意才行,涉及到了分布式选举的问题
哨兵至少需要3个实例,来保证自己的健壮性
哨兵+redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性
4、配置中心,如果故障转移发生了,会通知client客户端新的master地址
优点
故障转移,可用性更高
主从模式升级,手动到主动,更加健壮
缺点
不好扩容
配置麻烦
常见问题
如果有大量的key需要设置同一时间过期,需要注意什么?
场景: 电商首页经常会使用定时任务刷新缓存,可能大量的数据失效时间都比较集中,
如果失效时间一样,又刚好在失效的时间点大量用户涌入,就有可能造成缓存雪崩
如果失效时间一样,又刚好在失效的时间点大量用户涌入,就有可能造成缓存雪崩
大量的key的过期时间设置的过于集中,到过期的时间点,redis可能会出现短暂的卡顿现象,严重会出现雪崩
解决方式: 一般可以在时间上加个随机值,使过期时间分散一些
高可用
缓存穿透、缓存雪崩
缓存穿透
请求的数据在缓存大量不命中,导致请求走数据库。
缓存穿透如果发生了,也可能把我们的数据库搞垮,导致整个服务瘫痪!
缓存穿透如果发生了,也可能把我们的数据库搞垮,导致整个服务瘫痪!
解决方案
1、布隆过滤器
2、缓存一个空值
缓存不命中,即使返回的空对象也将其缓存起来,同时会设置一个较短的过期时间,
之后再访问这个数据将会从缓存中获取,保护数据库数据源的安全
之后再访问这个数据将会从缓存中获取,保护数据库数据源的安全
缓存雪崩
缓存挂掉,所有的请求到数据
对缓存数据设置相同的过期时间,导致某段时间内缓存失效,请求全部走数据库。
解决方案
1、在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期
2、实现Redis的高可用(主从架构+Sentinel(哨兵) 或者Redis Cluster(集群)),尽量避免Redis挂掉这种情况发生。
memcached
key-value的存储格式
存储在内存中,重启服务后数据丢失
JVM
内存结构
虚拟机栈
是线程隔离,每个线程都会独立创建一个栈帧,每个栈帧包括
局部变量表
临时变量
对象,(存储一个地址,关联到堆里面的对象)
操作栈
动态链接
返回地址
堆
存放着对象的实例,是线程共享区
堆是垃圾收集器管理的主要区域,因此也被称为“GC堆”
方法区/元空间
程序计数器
是JVM中一块较小的内存区域,保存着当前线程执行的虚拟机字节码指令的内存地址
本地方法区
垃圾回收算法
类加载过程
0 条评论
下一页