Java基础
数组
一组连续空间,存储多个相同类型的值
特点
- 数据类型相同
- 长度固定
数组的扩容
- 创建一个新数组,使用For循环将元素逐一赋值
- System.arraycopy(原数组名,原数组起始下标,新数组名,新数组起始下标,复制的长度)
- Java.util.Arrays.copyOf(原数组名,新数组名)
排序
- 冒泡(相邻两个元素两两比较,互换位置)
- 选择(固定值和其他值依次比较,互换位置)
- 快速
查找
- 二分法查找【递归】
静态&最终&抽象
静态static
简述
- 可以修饰属性和方法
- 修饰属性——>静态属性(类属性)
- 修饰方法——>静态方法(类方法)
- 静态成员全类所有对象共享
- 全类就一份,不会因为创建多个对象而产生多份
- 不必创建对象,直接通过类名进行访问
特点
- 静态方法可以直接访问静态成员
- 静态方法不能直接访问非静态成员
- 可以继承,没有覆盖和多态
抽象Abstract
简述
- 修饰类——>称为抽象类,无法New对象
- 作用
- 为子类提供共性的属性和方法
- 可以声明引用,强制使用多态(分类引用指向子类对象)
- 作用
- 修饰方法——>称为抽象方法,无法直接使用
- 作用
- 强制子类覆盖父类中所有的抽象方法,如果不覆盖,该类必须声明为抽象类
- 作用
最终Final
简述
- 修饰类——>没有子类
- 修饰方法——>可以继承,不能覆盖
- 修饰变量——>只能赋值一次,不能改变,修饰变量我们称之为常量
- 实例变量:没有默认值,必须手动赋值,赋值的时机:
- 显示初始化
- 动态代码块
- 每一个构造方法
- 静态变量:没有默认值,必须手动赋值,赋值的时机:
- 显示初始化
- 静态代码块
- 局部变量
- 基本数据类型:数值不可变
- 引用数据类型:地址不可变
- 实例变量:没有默认值,必须手动赋值,赋值的时机:
类加载过程
https://blog.csdn.net/romantic_jie/article/details/91355437
JVM原理&调优【重点】
略(后面详细介绍)
Object类
所有的父类,如果没有显示继承,那么隐式存在
作用
- 作为形参——>可以接受所有对象
- 作为返回值类型——>可以返回所有对象
- Java中每一个对象多可调用Object类中的方法
Object类常用的方法有哪些?(低于5个)
- hashCode toString getClass equals wait notify notiyAll clone fianlize等
集合
简述
Java集合类存放在java.util包中,是一个用来存放对象的容器。
注意:
- 1.集合只能存放对象。比如你存入一个int型数据66放入集合中,其实它是自动转换成Integer类后存入的,Java中每一种基本数据类型都有对应的引用类型。
- 2.集合存放的都是对象的引用,而非对象本身。所以我们称集合中的对象就是集合中对象的引用。对象本身还是放在堆内存中。
- 3.集合可以存放不同类型,不限数量的数据类型。
集合和数组的区别
- 长度
- 数组不可变
- 集合可变
- 元素的数据类型
- 数组可以存储基本类型数据和引用数据类型
- 集合只能存储引用数据类型
集合类原理,尤其HashMap、HashTable、ConcurrentHashMap等
-
HashTable: KV都不允许为null,线程安全,效率低
-
HashMap(和HashTable相反):哈希表(
Node[]
)、链表(Node next
解决哈希冲突)、红黑树(TreeNode
解决链表过长,效率过低问题) -
ConcurrentHashMap:1.7版本之前 哈希表 + 链表 + 分段锁 1.8以后 哈希表 + 链表 + 红黑树
CAS(Compare And Set): 类似于乐观锁
面试题?
List下有三个实现类的特点
ArrayList:底层数组实现,查询快,增删慢。线程不安全,效率高。
Vector:底层数组实现,查询快,增删慢。线程安全,效率低。
LinkedList:底层链表实现,查询慢,增删快。
set集合
list和set区别?
* List:有序,可重复
* Set:无序,不可重复
HashSet
* 如何保证元素唯一:HashSet存储元素底层依靠两个方法hashcode() equals()
* 执行步骤:
* hashcode先执行,会判断存储的元素哈希值是否一样
* 相同:执行equals判断内容
* 相同:不存
* 不同:存
* 不同:存储
注:如果存储自定义对象,请在类中覆盖hashcode和equals。
Map和Colleciton区别
Collection:List可重复,Set集合不可重复。光棍
Map:键不可重复,值可重复。
IO
分类
- 方法:输入流和输出流
- 功能:节点流和过滤流
- 单位:字节流和字符流
使用
略
对象序列化和反序列化
网络中传输的数据均为字节,保证数据能够进行网络传输
- 实现序列化接口
- 不需要参与对象的序列化
transient
BIO、NIO、AIO?
-
BIO:同步阻塞IO
-
NIO:同步非阻塞IO Netty
-
AIO:异步非阻塞IO
网络编程
阻塞和非阻塞体现在线程利用率
阻塞:先有线程再有完整的IO操作,线程服务于一次完整的IO
非阻塞:关注的事件,事件发生后进行事件操作,线程利用率更高
同步和异步
request.getInputStream
线程
进程:正在运行的程序。
cpu:单cpu一个时间点只能执行一个进程。
- 为什么我们感觉多个进程是同时执行的?
- 是因为cpu在做着程序之间的高效切换,让我们感觉是同时在执行。
线程:在一个进程中,包含多个任务,而每一个任务就是一个线程。
多线程:每一个进程想要执行必须抢到cpu才能执行,如果一个进程中线程的数量比较多,那么该进程抢到的概率就更大,但是不保证一定抢到,因为线程的执行是随机性的。
并发:在一段时间内多个线程切换执行。
并行:在一个时间点多个线程同时执行。
创建
- extend Thread
- implements Runnable
- 线程池
运行状态
- 初始化状态
- 就绪状态 thread.start()
- 运行状态
- 阻塞状态 sleep(不会释放锁) | wait(释放锁标记)
- 死亡状态
线程安全
多线程并发环境中操作临界资源,保证线程的安全,对临界资源加锁
同步锁
- 同步方法
- 同步代码块
线程池
将需要执行的任务交给线程池,线程池会分配线程去执行该任务,任务执行结束线程不会死亡,而是回到线程池中处于空闲状态,等待下一个任务。
- FixedThreadPool
- CachedThreadPool
反射
类对象
通过.class文件获取的对象,使用该对象中的构造方法,实例变量,实例方法。
- getClass
- Class.forName(推荐(将来可以将字符串写入到配置文件中))
- 对象.class
使用
- 反射调用方法、属性
设计模式
-
单例(静态内部类)
保证内存中只有一个对象
- 私有属性方法
- 本类提供一个对象
- 将该类对象提供给外界使用
-
工厂(好处 : 解耦合)
主要解决的是对象创建的问题,工厂的职责在于创建一个对象
-
代理(静态代理、动态代理)
客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。
-
适配器
将一个类的接口转成客户期望的另外一个接口,使得原本由于接口不匹配而不能一起工作的那些类可以一起工作。
-
责任链
当系统需要嵌入多个独立功能模块时,可以使用责任链设计模式
责任
:主要负责实际功能实现。链
:用于协调责任调度,记录调度状态。
网络
TCP/IP协议的三次握手和四次挥手
https://blog.csdn.net/qq_38950316/article/details/81087809
网络七层模型
- 应用层 Http
- 会话层
- 表示层
- 传输层 TCP/UDP 报文
- 网络层
- 数据链路层
- 物理层
JavaWEB框架复习
Java 语法基础:HashMap结构,锁-分类,JVM GC策略,自定线程池参数含义,JVM内存分析指令-jmap,jstack,jstats, Java类加载策略,网络编程 阻塞IO和NIO – 高级Java开发工程师
Spring
概念:一款轻量级的javaEE解决方案,众多优秀设计模式的组合
IOC(控制反转)
控制:给属性赋值的权利
反转:把给属性赋值的权利由代码反转到了配置文件中
控制反转,有容器工厂负责对象的创建销毁(生命周期)
<bean id="xxx">
或者@Bean
DI(依赖注入)
当一个类型需要另一个类型时,可以把另一个类型作为该类型的属性,通过对应的注入方式进行赋值
set注入
、构造注入
和自动注入(ByType @Autowired | ByName @Resource)
AOP(面向切面编程)
将代码中其它功能(事务、日志、性能等)剥离出来形成独立的功能方法或者功能类,如果使用到这些功能时,通过动态代理方式生成代理类,增强普通类功能
动态代理(字节码处理技术): 原始方法 + 额外功能 = 代理类
- JDK(默认):必须提供接口
- CGLIB(基于父子类继承关系):可以是接口也可以是普通类
使用
- 基于接口
- 基于注解:
@Before
@After
和@Around
等
切入点表达式
- 通用表达式:
exeuction(* com.baizhi.*.*(..))
事务传播属性
解决事务嵌套问题
- SUPPORT(support):支持当前事务,如果无事务环境则以无事务方式运行
- REQUIRED(required):必须有事务,如果有事务则使用当前事务,如果无新建事务
- NOT_SUPPORT:外部有事务则挂起(以非事务的形式执行)
- MANDATORY(mandatory):外部必须有事务,没有事务就报错
- NEVER:外部必须没有事务,有事务报错
1.PROPAGATION(propagation)_REQUIRED – 如果存在当前事务则用当前事务;如果不存在当前事务,就新建一个事务。这是最常见的选择。
2.PROPAGATION_SUPPORTS – 支持当前事务,如果当前没有事务,就以非事务方式执行。
3.PROPAGATION_MANDATORY – 支持当前事务,如果当前没有事务,就抛出异常。
4.PROPAGATION_REQUIRES_NEW – 新建事务,如果当前存在事务,把当前事务挂起。开启一个新事务,新事务执行完毕后,唤醒之前挂起的事务,继续执行。如果不存在当前事务,则新建一个事务
5.PROPAGATION_NOT_SUPPORTED – 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6.PROPAGATION_NEVER – 以非事务方式执行,如果当前存在事务,则抛出异常。
7.PROPAGATION_NESTED – 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
隔离属性
脏读: 一个事务读取了另一个事务尚未提交的数据
isolation=“READ_COMMITTED” 解决脏读问题
不可重复读:多次读取到的数据不一致
isolation=“REPEATABLE(repeatable)_READ” 解决不可重复读问题
幻影读:多次统计的结果不一致
isolation=“SERIALIZABLE(serializable)” 解决幻影读问题
安全:SERIALIZABLE>REPEATABLE_READ>READ_COMMITTED
性能:READ_COMMITTED>REPEATABLE_READ>SERIALIZABLE
isolation=“DEFAULT” 根据数据库默认隔离属性定
Oracle数据库隔离属性级别: READ_COMMITTED
Mysql数据库隔离属性级别: REPEATABLE_READ
传播属性 (补充)
作用:解决事务嵌套问题
propagation=“REQUIRED” 默认值 当外部有事务则融入到外部事务中,如果外部没有事务,则开启新的事务 (增删改)
propagation=“SUPPORTS” 当外部有事务则融入到外部事务中,如果外部没有事务,也不开启事务(查)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I5L3l4to-1586439809864)(D:\java168\java168\三阶段资料\框架阶段\Spring\Spring-Day4\图片\传播属性补充.png)]
只读属性
read-only=false 默认值 (增删改)
read-only=true 查询(提高查询效率)
超时属性
作用:决定释放锁标记的等待时长
time-out=-1 由数据库来决定
异常属性
作用:哪些异常进行提交?哪些异常进行回滚?
默认对于未检查异常进行回滚操作,对已检查异常进行提交操作
rollback-for 指定哪些异常进行回滚操作
no-rollback-for 指定哪些异常进行提交操作
总结:实战开发中事务属性的应用
增删改: isolation=“default” propagation=“REQUIRED” read-only=“false” time-out="-1"
异常属性默认 (全部用默认)
查询: isolation=“default” propagation=“SUPPORTS” read-only=“true” time-out="-1"
异常属性默认
Spring工厂创建对象的生命周期
对象什么时候被创建?
对象只创建一次时(scope=“singleton”):工厂被创建则对象被创建 饿汉式
对象每次创建新的(scope=“prototype”): 该对象使用时被创建 懒汉式
对象什么时候被销毁?
工厂关闭时,对象被销毁 但是还与垃圾回收机制有关
init-method 指定对象创建调用的初始化方法
destory-method 指定对象销毁调用的销毁方法
SSM(Spring+Struts2+Mybatis)注解版
作用:替换配置文件中,复杂的配置
开发步骤:
1.把注解放置对应的位置上
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c6e0pLf5-1586439809865)(C:\Users\战神\AppData\Roaming\Typora\typora-user-images\1586434941807.png)]
2.告知Spring框架在哪一个包中使用了注解
<!--配置扫描哪一个包下的注解-->
<context:component-scan base-package="com.baizhi.entity">/context:component-scan
常用注解:
-
@Component
放置位置:类上
作用:创建简单对象
注意:默认提供ID 类名首字母小写
-
@Service
位置:Service实现类上
作用:创建Service实现类对象
-
@Autowired
位置:属性上
作用:为属性做自动注入
前提:在Spring工厂中必须有为该属性注入的值
-
@Transactional
位置:方法 类
作用:为方法添加对应的事务
前提: 必须激活该注解
!--激活@Transactional注解-- <tx:annotation-driven transaction
manager="transactionManager">/tx:annotation-driven
-
@Controller
位置:类
作用:自动创建Action对象
-
@Scope
位置:类
作用:决定对象创建的次数
singleton 只创建一次
prototype 每次创建新的
开发步䠫:
1.建表
2.写实体
3.定义DAO接口
4.Mapper文件实现DAO接口
5.Spring配置文件中配置mybatis相关的内容
6.定义Service接口
7.实现Service接口
i.@Service 自动创建Service实现类对象
ii.@Autowired 自动为DAO属性做注入
8.配置额外功能事务
i.@Transactional 给对应的方法添加事务
ii.在Spring配置文件中进行激活
9.开发Action
i.@Controller 创建Action对象
ii.@Scope 决定创建对象的次数
iii.@Autowired 自动注入Service实现类对象
10.struts.xml中配置
11.告知Spring框架在那一个包下使用了注解
SpringMVC
概念:是一款控制层的框架,解决MVC分层开发中控制层的问题
好处:
-
SpringMVC框架是Spring全家桶体系的组成部分,与Spring体系做到无缝衔接
-
SpringMVC无论从开发效率还是运行效率都比Struts2高
作用
1.接收数据
2.调用业务
3.跳转页面
SpringMVC中的基础语法
@RequestMapping注解
作用:
1.指定后台Action的访问路径
2.指定该方法被访问的请求方式
位置:
类 相当于struts2中的namespace
方法 相当于struts2中的name
RequestMethod.GET 该方法只能被GET方式访问
RequestMethod.POST 该方法只能被POST方式访问
method ={RequestMethod.POST,RequestMethod.GET} 既可以被POST方式又可以被GET方式访问 (默认)
@RequestParam注解
i.解决传入的键与形参名不一致的问题
ii.可以设置接收数据的默认值
@DateTimeFormat注解
@DateTimeFormat(pattern = “yyyy-MM-dd”) 自定义接收数据类型
SpringMVC中的跳转
Forward跳转(请求转发):一次请求 地址栏不变 可以使用Request作用域传递数据
Redirect跳转(重定向): 两次请求 地址栏发生改变 不可以使用Request作用域传递数据
SpringMVC中的传递数据(补充)
使用Model和ModelMap替换Request作用域
作用: 与视图层解耦合
SpringMVC拦截器
作用:减少控制器中代码的冗余
开发步䠫:
1.implements HandlerInterceptor 接口
2.在SpringMVC的配置文件中配置
MVC软件设计风格
-
模型
-
视图
-
控制
接受客户端请求 —> 业务处理 —> 返回客户端
工作原理
SpringMVC流程
1、 用户发送请求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、 Controller执行完成返回ModelAndView。
7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、 ViewReslover解析后返回具体View。
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、 DispatcherServlet响应用户。
SpringBoot
介绍
简化Spring应用的初始搭建以及开发过程,内嵌WEB容器,提供自动配置,程序员只需要关注业务功能开发而不是Bean的配置;
springboot(微框架) = springmvc(控制器) + spring(项目管理)
特点
创建独立的Spring应用程序
嵌入的Tomcat,无需部署WAR文件
简化Maven配置
自动配置Spring
没有XML配置
Restful
软件设计风格
使用请求方式说明对资源操作;
GET http://localhost:8080/user/1 # 获取用户id=1
DELETE http://localhost:8080/user/1 # 删除用户id=1
POST【更新】
PUT【新增】
自动配置
Spring4.0后提供配置注解
根据导入的依赖自动完成配置
web
---> DispatcherServlet
---> CharacterEncodingFitler
切面编程
springboot是对原有项目中spring框架和springmvc的进一步封装,因此在springboot中同样支持spring框架中AOP切面编程,不过在springboot中为了快速开发仅仅提供了注解方式的切面编程.
相关注解
- @Aspect 用来类上,代表这个类是一个切面
- @Before 用在方法上代表这个方法是一个前置通知方法
- @After 用在方法上代表这个方法是一个后置通知方法
- @Around 用在方法上代表这个方法是一个环绕的方法
- @order(数字)用在类上,数字越小进入越早
重点注解
参考: https://www.cnblogs.com/tanwei81/p/6814022.html
- @RestController: 就是@Controller+@ResponseBody组合,支持RESTful访问方式,返回结果都是json字符串。
- @ResponsrBody:返回Json数据
- @Controller:用于定义控制器类
- @Autowired:自动导入依赖的bean
- @Service:修饰Server层的组件
- @SpringBootApplication 注解等价于:
- @Configuration 项目启动时自动配置spring 和 springmvc 初始搭建
- @EnableAutoConfiguration 自动与项目中集成的第三方技术进行集成
- @ComponentScan 扫描入口类所在子包以及子包后代包中注解(也可以从新指定要扫描哪些包)
MyBatis
优秀的持久层框架,对数据库进行访问和操作。
替换JDBC技术 ----- 定制化SQL(动态SQL),高级映射关系,支持缓存。
核心组件
mybtis中代码的书写
JDBC —> 接口 Connection PreparedStatement ResultSet DrvierManager
Resources、SqlSessionFactory、SqlSession
Resources : 读取MyBatis的核心配置文件。
SqlSession : 类似连接Connection
将mapper.xml文件 转换成对应的DAO实现类(DAOImpl)
内部封装了Connection对象 使用SqlSession去访问数据库
sqlSession.commit(); sqlSession.rollback();
SqlSessionFactory :SqlSession的工厂 用来创建SqlSession对象。
缓存机制
应用优化策略,提高访问效率,大大减轻数据库的访问负载
-
一级缓存:SqlSession,缓存依赖于会话
-
二级缓存:NameSpace级别,所有的查询语句都会进行缓存,在调用增删改方法时所有的查询缓存会失效;
<cache />
—> JVM<cache class="第三方缓存服务实现"/>
—> 保存第三方存储系统(内存 分布式)基于Redis管理MyBatis二级缓存 构建分布式缓存服务;
注意:
好处 : 减少数据库的通信次数,提高效率。
不好 : 缓存 ---> 大量占用内存。 空间 换 时间
不安全的,数据的不一致。
1. 关注 缓存的命中率
Cache Hit Ratio [com.baizhi.dao.DepDAO]: 0.75
如果命中过低不建议使用缓存
2. 脏数据 --- 缓存中的数据和数据库中的数据不一致
执行Commit操作会自动清空缓存数据
ResultMap和ResultType?
- Map:手动指定实体属性和字段映射关系
- Type:自动映射
resultMap 结果 映射 — 对应关系
ORM思想:实体属性,表中的列名 一一对应。
现实中往往因为数据的命名或其他原因无法满足实体类属性和数据库列名一一对应。
动态SQL标签
- 略
MyBatis参数绑定机制
mapper文件中取值的语法: #{…} . ${} 存在SQL注入的风险 不建议使用
关系型数据库(MySQL)
基本SQL语法
DQL (Data Query Language) : 数据查询语言
DDL(创建表) : 数据的定义语言
DML(增删改) : 数据修改语言
- 基本Select、Update、Insert、Delete
- insert into 表名(列1,列2…) values (数据1,数据2…)
- update 表名 set 列名=数据,列名=数据… where 条件
- delete from 表名 where 条件
- 函数使用max、min、avg、now等
- 表连接查询
case...when..
- 数据库
- 表
create、alter、desc、drop、truncate
事务 【重点】
ACID四大特性?
- 原子性:一个事务内,所有操作是一个不可分割的整体;
- 一致性:事务操作前后对数据的影响是一致的
- 隔离性:事务和事务的操作时隔离的,互不影响干涉;
- 持久性:事务操作一旦提交,对数据库影响是不可逆的
事务问题?
脏读(A事务读取到了B事务未提交的数据)
不重复读(A事务内多次读取同一条数据,结果不一致)
幻影读(A事务多次读取结果的条数不一致)
事务隔离级别?
- 读未提交:没有解决任何的事务问题
- 读已提交:解决脏读,Oracle默认
- 重复度:解决不可重复读,MySQL默认
- 序列化读: 解决所有的事务问题;
等级:由低到高
效率:由高到低
事务传播属性?
参考Spring
索引 【重点】
常用索引类型
-
主键索引:约束
primary key
,建议在查表时使用主键,因为这样做的话可以使用到主键索引 -
唯一索引:约束
unique
-
复合索引:对多个字段创建一个索引;
-
普通索引:单字段创建一个索引
create index 索引名 on 表名(字段1,字段2,字段3....)
索引方法
-
Hash
-
BTree
https://blog.csdn.net/iteye_19269/article/details/82678056
视图(view)
简化SQL语句
create view 视图名 select ...
数据库引擎 【重点】
-
Myisam 不支持事务和外键 适用于只读查询
-
Innodb 支持事务和外键 适用于读写查询
https://www.cnblogs.com/wangsen/p/10863405.html
https://www.cnblogs.com/klb561/p/10344364.html
存储过程 【一般】
https://www.runoob.com/w3cnote/mysql-stored-procedure.html
SQL优化
-
尽可能利用索引查询
-
尽量避免三张表以上的连接操作,可以使用子查询代替表连接
-
查询利用条件查询,避免全表的扫表
-
避免使用
*
,建议使用字段方式总结:上网资料 + 理解
设计范式
一、二、三范式
总结资料
https://www.cnblogs.com/wenxiaofei/p/9853682.html
悲观锁和乐观锁
- 乐观锁:数据改操作,查询当前数据的版本号,应用更改,再结束后再次查询版本号,如果版本号变化回滚事务,没有变化提交事务;
Struts2
解决现有MVC开发思想中 控制器的问题。 —> 替换Servlet技术
框架: framewrok 软件开发中的半成品!!!
解决了软件开发过程中的通用问题(代码冗余或设计的不合理),从而提高了开发效率。
接收参数 冗余、类型转换、编码的处理
流程跳转 硬编码 ---> 跳转路径写死在java文件中
Servlet(单例)
不能定义成员变量
Struts2(多例)
每一次请求访问都会创建一个全新的对象(构造方法被多次调用),可以定义成员变量
Struts2中的跳转
Servlet 中跳转 请求转发 / 重定向
forward: 一次请求使用request作用域传递数据,地址栏不发生改变。
redirect : 两次请求不能使用request作用域传递数据,地址栏发生改变。
Struts2 中依然保持这两种跳转方式,由原有的代码书写变成的Struts.xml的配置
四个: forward redirect
Action ---> jsp dispatcher(默认值) redirect
Action ---> Action chain redirectAction
DMI的开发方式
目的: 减少Action的数量,将多个Action中的方法抽取的一个Action中书写。
注意: 尽量将一类的Action书写在一起 UserAction ProductAction
拦截器
作用: 可以将多个action中的冗余代码,抽取到拦截器中定义, 实现代码的复用。
拦截器可以拦截请求 , 也可以拦截响应。
开发步䠫:
拦截器的开发步骤:
1. 开发拦截器(代码) 实现接口 interceptor
intercept 方法 ----> ai.invoke(); 放行 / return “String” 错误跳转的页面。
2. 配置 struts.xml
2.1 声明拦截器
2.2 定义拦截器栈
2.3 完成拦截器栈的使用配置
a. 使用默认的拦截器配置 package中所有的action都拦截
b. 在action标签中使用拦截器栈
方法拦截器
只针对Action中某一类特定的方法进行拦截。
继承 : MethodFilterInterceptor
Struts2中成员变量的作用
-
接收数据
-
替换request作用域
-
从struts.xml中读取数据 <param name=“filename” 数据 </param
-
向struts.xml中传输数据 ${ 成员变量名称 }
Redis
基于内存KV存储的非关系数据库
传统的关系型数据库只能存储结构化数据,对于非结构化的数据支持不够完善,nosql这个技术门类的出现,更好的解决了这些问题,它 告诉了世界不仅仅是sql。
特点
- Redis是一个高性能key/value内存型数据库
- Redis支持丰富的数据类型如(String,list,set,zset,hash)
- Redis支持持久化 内存中数据持久化到硬盘
- Redis单线程,单进程 效率高 (不支持并发操作)
数据常用数据类型
Key:String
Value:String、List、Set、Sorted Set、Hash
数据持久化机制
-
RDB(内存快照)
在某个时刻,将Redis内存中全量数据逆向生产一个快照文件
dump.rdb
,在Redis Server恢复运行时通过加载二进制快照文件实现内存数据的恢复;问题:丢失未保存在快照中的内存数据
60s 10000 300s 10 900s 1
-
AOF(追加日志)
写操作日志文件,通过方式将用户的写操作指令记录到
appendonly.aof
,在Redis Server恢复运行时通过再次执行日志文件中写操作命令实现内存数据的恢复;默认 1s 记录一次 1写操作 记录一次 写入时机由系统决定
-
aof日志文件重写:不断追加写操作指令导致日志文件越来越大
-
自动触发:
auto-aof-rewrite-percentage 100
或者auto-aof-rewrite-min-size 64mb
-
手动触发
bgrewrite
-
-
应用
- 内存式存储系统
- 分布式缓存服务
- 分布式锁
- 业务功能
- 发布订阅(pub/sub)
- Redis事务
集群
- 哨兵集群(主从又是主备)
- Cluster(三主三从,哈希槽16384)
ElasticSearch
基于Lucene全文检索引擎
关键术语
- Index(索引):类似于关系型数据库中Database
- Type(类型):类似于关系型数据库中Table,在7.0版本后废弃
- Document(文档):一条JSON记录
- Field(域):类似于记录的字段
- NRT(近实时):数据写入到ES到被检索到大概有1s的延迟
- Shard(分片):一个Index由多个数据分片构成
- Cluster(集群):ES一组服务构成集群
- Mapping(映射):Type Schema结构约束
- Replicas(复制分片):对分片数据的冗余备份,在读操作时可以提高效率;
操作
DSL风格
请求方式 + 资源 + RequetBody (请求参数)
分词器
IK分词
深度分页问题?
es 默认采用的分页方式是 from+ size 的形式,在深度分页的情况下,这种使用方式效率是非常低的,比如from = 5000, size=10, es 需要在各个分片上匹配排序并得到5000*10条有效数据,然后在结果集中取最后10条;
https://blog.csdn.net/u011228889/article/details/79760167
全文检索原理
反向索引
通过运行创建索引,在查询时根据匹配索引寻找数据的过程;类似于查字典过程(索引:拼音表或者偏旁部首表 数据:中文汉字)
我爱北京天安门 —> 我 | 爱 | 北京 | 天安门 —> 索引
北京 --> 北京 —> 匹配索引 —> 我爱北京天安门
ELK(大数据数据采集 存储 分析可视化展示方案)
https://blog.csdn.net/qq_31871785/article/details/86149698
略
JAVA WEB
JDBC
数据库连接技术
PreparedStatement和Statement区别?
- 不存在SQL注入
- ?占位 后赋值
- 效率高 异构SQL
ThreadLocal理解? 【重点】
线程局部变量
保证在同一个线程中能够获取到相同的变量对象;
Thread#ThreadLocalMap#getOrSet
Servlet
运行在服务器端JAVA程序
Session和Cookie? 会话追踪技术
- Session 服务器端对象 (创建:客户端第一次请求时,销毁:超时 | 手动)
- Cookie 浏览器本地对象(kv,有效时间 -1)
JSP
Java动态网页技术(不重要 | 淘汰)
9大内置对象:request、session、application、page、pageContext、exception、config、response、out
前端HTML\CSS等
略
HashMap底层实现原理
JDK7 数组+链表
JDK8 数组+链表+红黑树
- 当数组中某一个链表长度>=8,数组的长度>=64时,会将此链表转换为红黑树的存储方式。
名词解析
capacity:容量
factor:因子
HashMap的概述
HashMap是Map接口的实现类,键值对存储(基于哈希表的映射:根据指定的键,可以获取对应 的值),并允许null作为键和值,线程不安全,即方法为非同步(Lock、Synchronized)方法
Lock:显示加锁,加完之后必须手动的释放(unlock)
Synchronized:自动释放
Java.util.concurrent.locks(juc):Java并发包
HashMap的存储结构
- Java编程语言中,最基本的两种结构:数组和链表(引用模拟指针),所有的数据结构都可以
用这两种基本结构进行构建。
数组的特点(连续的一组空间):寻址容易,插入和删除难,空间浪费;
而链表的特点(空间不连续):寻址困难,插入和删除容易,节省空间。
- 综合数组和链表两者的特点,HashMap(直译为散列表,音译为哈希表)采用数组+链表的存
储方式。
- 底层结构是一个数组(默认长度为16),而数组元素是一个单向的链表,每一个数组存储的元
素代表的是每一个链表的头结点。结构如下:
HashMap数组+链表案列
Public class TESThASHmAP{
public static void main(String[] args){
//头插法
Node head;
Node n1 = new Node(data:"aa");
head =n1;
Node n0 = new Node(data:"00");
no.next = n1;
head = n0;
Node n2 = new Node(data:"bb");
n1.next = n2;
n2.next = new Node(data:"cc");
//尾插法
//先遍历for循环,获取最后一个
//遍历链表
for(Node n = head;n!=null;n=n.next){
Syatem.out.println(n.getData());
}
//数组+链表
Node[] ns = new Node[3];
ns[0] = new Node(data:"aa");
ns[1] = head; //链表
}
Class Node{
//数据区
Private String data;
//地址区
Node next;
Node before;
Public Node(String data){
this.data = data;
}
Public String getData(){
return this.data;
}
}
}
Fail-Fast机制(快速失败)
Jdk保护集合(线程安全)的策略
常见问题:
为什么当负载因子达到0.75f时进行扩容?
负载因子过大,会导致链表过长,耗时(遍历),性能降低
负载因子过小,会造成空间浪费
HashMap底层数组长度为什么保持2N次冥?
提高效率
相同的对象返回相同的Hash值,不同的对象返回不同的Hash值
下标:Hash&数组长度-1?
尽可能不破坏离散度
减少下标冲突的可能性(提高离散度)
HashSet底层存储(数组)
无序的
存储的下标取决于元素的Hash值&数组的长度
HashSet底层本质为HashMap
JVM(Java虚拟机)(重点)
运行在操作系统之上的
Java虚拟机内存结构
橙色:线程共享
灰色:线程独有
.class文件通过类加载加载到Java虚拟机中
Java虚拟机是一大块内存,内存分为栈空间、堆空间、本地方法区、程序计数器
堆空间:存储对象的
栈空间:局部变量
-
程序计数器(指示器)
一块小的内存空间,告知程序下一步做什么的指令,每个线程拥有一个独立的程序计数器
-
Java虚拟机栈(先进后出)
每一个方法被调用都会分配一个栈帧,一个栈帧里面包含局部变量表、调用链接、方法的出口
-
本地方法栈(Native)
-
Java堆(GC堆–垃圾回收器)
- 新生代(YGS)
- 老生代(TGS)
- 永久代(PS)
-
方法区:存储虚拟机加载的信息、常量、静态变量
类加载
类加载机制
虚拟机把描述类的数据从.class文件加载到内存中,并对数据进行校 验、转换解析和初始 化,最终形成可以被虚拟机直接使用的Java类型
类加载过程
- 加载
将class文件字节码内容加载到内存中;并将这些内容转换成方法区中的运行时数据结构;
在内存中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口
- 验证
确保class 文件中的字节内容符合jvm规范,并且不会危害jvm自身的安全。
- 准备
正式为类变量(静态变量)分配内存空间,并为静态变量初始化(赋默认 值),静态变量的内存在方法区中分配。
- 解析
虚拟机常量池内的符号引用替换为直接引用的过程。
- 比如String s =“aaa”,转化为 s的地址指向“aaa”的地址
- 初始化
根据程序员通过程序制定的主观计划完成静态变量等资源的初始化。 在这个过程会完成静态变量的赋值和静态代码块中的语句。
什么时候使用到类加载?
- 第一次使用创建该类对象
- 第一次调用类中的静态成员、方法、属性
- Class.ForName(反射)
- 子类类加载会导致父类类加载
类加载器(ClassLoader)
用于实现类加载过程中加载阶段,负责将class文件字节码内容加载到内 存中;并将这些内容转换成方法区中的运行时数据结构,在内存中生成一个代表这个类的 java.lang.Class对象, 作为方法区类数据的访问入口。
类加载器分类
虚拟机自带的类加载
- 启动类加载器:
C++语言实现,负责加载 %Java_home%/jre/lib/rt.jar 中的内容
-
扩展类加载器:
Java语言实现,负责加载 %Java_home%/jre/lib/ext/*.jar中的内容
-
应用程序类加载器:
也可以称为系统类加载器,它负责加载用户类路径classPath的所有类。
如果应用程序中没有定义过自己的类加载器,一般情况默认使用应用程序类加载。
用户自定义的类加载器
继承java.lang.ClassLoader
双亲委派模型(Parents Delegation Model)
应用程序类加载器拿到一个任务,逐级委派给父加载器,当父类加载反馈自己无法完成这个加载请求**(它的搜索范围中没有找到所需要的类)**的时候,子类才会尝试自己加载。
好处
Java随着它的类加载一起具备了一种带有优先级的层次关系
加载位于rt.jar中的java.lang.Object类,无论哪一个类加载加载这个类,最终都委托给最顶级的启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。
如何保证在生成类对象的时候它的线程安全?
Synchronized(加锁)
堆体系结构概述
堆(java堆,CG堆)
是JVM中所管理的内存中最大的一块内存区域,是线程共享的,在JVM启动时创建,存放了对象的实例及数组(所有new的对象)
堆内存逻辑分为
- 新生代(YGS)
- 老生代(TGS)
- 永久代(PS)
分配图(JDK7.0)
简述:
新生区是对象的创建、应用、消亡的区域,一个对象在这里产生、应用、最终被垃圾回收器收集,消亡。
新生区又分为两部分:伊甸区和幸存者区。
所有新创建的对象(new) 都是在伊甸区;
幸存者分为两个:幸存者0区和1区
- 当伊甸区的空间用完时,程序需要创建新的对象
- JVM对伊甸区开始进行垃圾回收,应用的是YGC,将伊甸区不再使用的对象进行销毁
- 然后将伊甸区剩余的对象移到幸存者0区,0区满了,对0区进行垃圾销毁,存活的对象移到幸存者1区
- 如果1区也满了,则再将1区的对象移动到养老区
- 如果养老区也满了,此时JVM将开启 FullGC(简称:FGC),进行养老区的内存清理
- 但是如果执行Full GC之后依然无法保存 新的对象,则产生OOM异常:堆内存溢出
永久区:存放静态常量的
分配图(JDK8.0)
将永久区取消了,由元空间(物理内存)代替
-Xms(启动空间):设置初始分配大小,默认为物理内存的 1/64
-Xmx(最大空间):最大分配内存,默认为物理内存的 1/4
-XX:+PrintGCDetails:输出详细的GC处理日志
调参
内存溢出
StankOverflowError(栈溢出)
Memory leak(内存泄漏)
申请的内存空间没有被释放,会降低程序运行效率,多次泄漏就会造成内存溢出
OOM(内存溢出)
没有足够的内存空间供其使用
产生原因
- 内存泄漏
- 集合对象不用时,没有及时设置为Null
- 各种连接没有及时关闭(流入IO流、网络连接、数据库连接)
- 变量的作用范围定义不合理
- 内存溢出
- 堆内存溢出:Java.lang.OutOfMemoryError:Java heap space
- 如:循环次数过多,而产生了过多的重复的对象实例
- 栈溢出:无穷递归会导致方法调用栈溢出
- 方法区溢出:加载过多的类
- 堆内存溢出:Java.lang.OutOfMemoryError:Java heap space
避免方法
-
尽早释放无用对象的引用
适应临时变量时,让引用变量在退出时设置为 null,暗示垃圾收集器来收集对象
-
尽量少用静态变量
因为静态变量是全局的,GC 不会回收
-
尽量运用对象池技术提高系统性能
常量池、串池、连接池(重复利用,提高效率)
-
不要在经常调用的方法中创建对象,尤其忌讳在循环中创建对象
-
优化配置
Java内存模型(JMM)
是一种抽象的概念,并不真实存在,它描述的是一组规则和规范
Java线程会将主内存(共享)中的数据拷贝到自身工作内存中完成相应操作,再将结果保存(save)到主内存中
三大特性
- 原子性
是指一个操作是不可中断的,即时是多个线程一起执行的时候,一 个操作一旦开始,就不会被其他线程干扰。
实现:在 Java 中可以使用 synchronized/Lock 关键字来保证方法和代码块内的操 作原子性。
- 可见性
是指一个线程修改了某一个共享的值,其他线程是否能够立即知道这个值被修改。
实现:可以以利用 Java 中的 volatile 关键字来保证多线程操作时变量的可见 性;也可以利用 synchronized /final 关键字实现可见性。
- 有序性(防止指令重排)
是指程序执行的顺序按照代码的先后顺序执行。
实现:可以使用 Java 中 synchronized/volatile 关键字来保证多线程之 间操作的有序性