Spring 是一种轻量级开发框架,旨在提高开发人员的开发效率以及系统的可维护性。它是很多模块的集合,这些模块有:核心容器、Web、AOP(面向切面编程)、工具、消息和测试模块。
@Controller:返回一个视图,对应于前后端不分离的情况。
@RestController(@Controller +@ResponseBody):返回Json对象,前后端分离。
IoC:
控制反转,指创建对象的控制权转移给Spring框架进行管理,IoC 容器实际上就是个Map(key,value),Map 中存放的是各种对象。以前创建对象的主动权和时机都是由自己把控的,IOC让对象的创建不用去new了。
Di:
依赖注入,应用程序在运行时依赖IoC容器来动态注入对象需要的外部依赖。
Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。
AOP:面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块。面向对象编程是纵向的,aop是横向的,相当于在某些类或方法切一刀,声明在执行到这里之前要先执行什么,执行完这里之后要接着执行什么。
一、Aspect(切面,被抽取出来的公共模块,@Aspect):
1、advice(增强也叫通知):包括Before advice、Around advice
2、连接点(join point):指程序运行过程中所执行的方法
二、切点(point cut):切点用于定义要对哪些Join point进行拦截。
列子:
join point 就相当于爪哇的小县城里的百姓(所有可能被放入advice 的候选的点)
point cut 就相当于 老王所做的指控, 即凶手是个男性, 身高约七尺五寸(对连接点进行修饰,哪些要进行advice动作)
advice 则是施加在符合老王所描述的嫌疑人的动作: 抓过来审问。
aspect:根据老王的线索, 凡是发现有身高七尺五寸的男性, 都要抓过来审问
1、singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。
2、prototype : 每次请求都会创建一个新的 bean 实例。
3、request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
4、session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
@Component 注解作用于类,而@Bean注解作用于方法。
@Component:如果一个Bean不知道属于哪个层,可以使用注解标注。
@Repository:持久层
@Service:业务层
@Controller:视图层
1、实例化
2、初始化
3、使用
4、销毁
@Autowired:按照类型注入
@Resource:按照名称注入
Jsp时代高度耦合,Spring MVC 下我们一般把后端项目分为 Service层(处理业务)、Dao层(数据库操作)、Entity层(实体类)、Controller层(控制层。
@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。
@RequestBody:注解实现接收http请求的json数据,将json转换为java对象。
@ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。
对象关系映射框架,持久层框架,内部封装了JDBC,以前使用JDBC时每次操作数据库都需要创建连接、创建statement等语句,现在mybatis帮我们做了。
${}是属性文件中的变量占位符,属于静态文本替换。
#{}是 sql 的参数占位符,MyBatis 会将 sql 中的#{}替换为?号,在 sql执行前使用反射从参数对象中获取属性值。
resultMap>、、where、foreach、if
通过来映射字段名和实体类属性名的一一对应的关系,自定义返回类。
MyBatis 使用 RowBounds 对象进行分页,拦截待执行的 sql,然后重写 sql添加对应的物理分页语句和物理分页参数。
无需xml配置,封装成了一个个的stater,自动装配。
核心注解:SpringBootApplication是Configuration(允许在上下文中注册额外的 bean 或导入其他配置类)、EnableAutoConfiguration(启用 SpringBoot 的自动配置机制)、ComponentScan(描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类)注解的集合。
@EnableAutoConfiguration:实现自动装配的核心注解:Spring Boot 通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类按需加载,需要什么注入什么。
使用 C 语言开发的非关系型数据库,不过与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 Redis 被广泛应用于缓存方向。
1、如果用户请求的数据在缓存中就直接返回。
2、缓存中不存在的话就看数据库中是否存在。
3、数据库中存在的话就更新缓存中的数据。
4、数据库中不存在的话就返回空数据。
* select 切换
* set
* get
* keys*
* flushdb
* flushall
* exists
* move
* expire 设置期望过期的时间
* ttl 看一个键还剩多长时间过期
* type 可以查看键的类型
1、string
2、List(列表):
概念:是一个双向链表
常用命令:rpush,lpop,lpush,rpop可以实现队列、栈
3、set集合
概念:不存在重复的元素
应用场景: 需要存放的数据不能重复
常用命令:sadd key value //增加
smembers key value//查看键的值
sismember key value//是否键值是否存在
spop key //随机移除元素
差集 sdif key1 key2
交集 sinter key1 key2
并集 sunion key1 key2
4、hash(map集合)
应用场景: 系统中对象数据的存储。
hset 集合名 key value //设置map集合
hget 集合名 key
hmset 集合名 key value key2 value2//设置多个
hget 集合名 key1 key2//获取多个值
hgetall 集合名 //获取所有
5、Zset(有序集合)
概念:在set的基础上,增加了一个排序值 zadd key score value
常用命令:
如何实现排序
zrangebyscore key -inf +inf//通过score进行排序 inf是无穷的意思
zrangebyscore key -inf +inf withscores //带上排序的值
zrangebyscore key -inf 2500 withscores //小于2500的降序
##################################
移除元素
zrange 0 -1 查看所有
zrem 集合名 key
zcard 集合名 //获取集合个数
#################################
zcount 集合名 score1 score2 //获取指定区间的成员数量
特殊数据类型:
6、 bitmap
概念:bitmap 存储的是连续的二进制数字(0 和 1), 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。
应用场景:适合需要保存状态信息(比如是否签到、是否登录...)活跃用户情况
1、多线程不一定比单线程快 cpu上下文切换会损耗效率
2、高性能服务器不一定是多线程的
3、速度cpu>内存>硬盘
4、单线程编程容易并且更容易维护
5、Redis 的性能瓶颈不在 CPU ,主要在内存和网络
6、多线程就会存在死锁、线程上下文切换等问题,甚至会影响性能
在内存中不存在切换上下文 因此单线程是最佳解决方案
通过IO多路复用程序(当io对象有变化(有数据)的时候就通知用户进程)来监听来自客户端的大量连接, I/O 多路复用技术的使用让 Redis 不需要额外创建多余的线程来监听客户端的大量连接,降低了资源的消耗
内存溢出
expire 设置过期时间
满足业务
Redis 通过一个叫做过期字典(可以看作是 hash 表)来保存数据过期的时间。过期字典的键指向 Redis 数据库中的某个 key(键),过期字典的值是一个 long long 类型的整数,这个整数保存了 key 所指向的数据库键的过期时间(毫秒精度的 UNIX 时间戳)。
1、快照持久化
Redis 可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis 创建快照之后,可以对快照进行备份
2、AOF(append-only file)持久化
开启 AOF 持久化后每执行一条会更改 Redis 中的数据的命令,Redis 就会将该命令写入硬盘中的 AOF 文件。
可以用WATCH、WATCH等命令来实现事务(transaction)功能。将多个命令请求打包的功能。然后,再按顺序执行打包的所有命令,并且不会被中途打断。不支持回滚、不满足原子性。
1、什么是缓存穿透
大量请求的 key 根本不存在于缓存中,导致请求直接到了数据库上,根本没有经过缓存这一层。
2、解决办法
-缓存无效key并设置过期时间,防止缓存大量无效key
-布隆过滤器(一种来检索元素是否在给定大集合中的数据结构,数组与哈希函数组成)
1、什么是缓存雪崩?
缓存在同一时间大面积的失效,后面的请求都直接落到了数据库上,造成数据库短时间内承受大量请求。
2、解决办法
-采用 Redis 集群,避免单机出现问题整个缓存服务都没办法使用。
-设置不同的失效时间比如随机设置缓存的失效时间。
1、什么是缓存击穿?
某KEY失效时,正好有大量并发请求访问该KEY。
-使用分布式锁,只让一个进程占锁,其他休眠
新增更新删除缓存
Java 虚拟机(JVM)是运行 Java 字节码的虚拟机。,java文件经过编译形成class字节码文件,jvm将字节码翻译成可执行的二进制机器码。
JDK是功能齐全的 Java SDK,它拥有 JRE 所拥有的一切,还有编译器(javac)和工具(如 javadoc 和 jdb)。
JRE 是 Java 运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括 Java 虚拟机(JVM),Java 类库,java 命令和其他的一些基础构件。但是,它不能用于创建新程序。
-都是面向对象的语言,都支持封装、继承和多态
-Java 不提供指针来直接访问内存,程序内存更加安全
-Java 的类是单继承的,C++ 支持多重继承;虽然 Java 的类不可以多继承,但是接口可以多继承。
-Java 有自动内存管理垃圾回收机制(GC),不需要程序员手动释放无用内存。
-C ++同时支持方法重载和操作符重载,但是 Java 只支持方法重载(操作符重载增加了复杂性,这与 Java 最初的设计思想不符)。
private protected public abstract class extends
1、continue :指跳出当前的这一次循环,继续下一次循环。
2、break :指跳出整个循环体,继续执行循环下面的语句。
3、return 用于跳出所在方法,结束该方法的运行。
1、? 表示不确定的 java 类型
2、T (type) 表示具体的一个 java 类型
3、K V (key value) 分别代表 java 键值中的 Key Value
4、E (element) 代表 Element
T 是一个确定的类型,通常用于泛型类和泛型方法的定义,?是一个 不确定的类型,通常用于泛型方法的调用代码和形参,不能用于定义类和泛型方法。
Class 在实例化的时候,T 要替换成具体类。Class> 它是个通配泛型,? 可以代表任何类型,所以主要用于声明时的限制情况。
对于基本数据类型来说,==比较的是值。对于引用数据类型来说,==比较的是对象的内存地址。
equals() 作用不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。
hashCode() 的作用是获取哈希码,这个哈希码的作用是确定该对象在哈希表中的索引位置。可以用于HashSet 检查重复,哈希值一样才调用equals 看是否真的一样,用来缩小查找成本。
Java 中有 8 种基本数据类型,分别为:
1、6 种数字类型 :byte、short、int、long、float、double
2、1 种字符类型:char
3、1 种布尔型:boolean。
1、在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。静态类不能被实例化。
2、静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。
Java 程序设计语言总是采用按值调用。也就是说,方法不能修改传递给它的任何参数变量的内容。
重载:方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同。
重写就是当子类继承自父类的相同方法,但要做出有别于父类的响应。private/final/static 则子类就不能重写该方法
面向过程 :面向过程性能比面向对象高。 因为类调用时需要实例化,开销比较大,比较消耗资源.
面向对象 :面向对象易维护、易复用、易扩展。因为面向对象有封装、继承、多态性的特性.
1、成员变量是属于类的,而局部变量是在代码块或方法中定义的变量或是方法的参数
2、成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。
new 运算符,new 创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。
1、封装:封装是指把一个对象的状态信息(也就是属性)隐藏在对象内部,不允许外部对象直接访问对象的内部信息。
2、继承:不同类型的对象,相互之间经常有一定数量的共同点。
关于继承如下 3 点请记住:
子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有。(父类必须是public或者protect)
子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
子类可以用自己的方式实现父类的方法。(以后介绍)。
3、多态
同一个事件发生在不同的对象上会产生不同的结果。可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
多态的条件
继承。在多态中必须存在有继承关系的子类和父类。
重写。子类对父类的默些方法重新定义,在调用这些方法的时候就会调用子类的方法。
向上转型。在多态中需要将子类的引用赋值给父类对象,只有这样该引用才能具备技能调用父类的方法和子类的方法。
Java 的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法; 并且对于任意一个对象,都能够调用它的任意一个方法。
//方式一 Class newInstance
Class class1 = Class.forName("reflection.Student");
Student student = (Student) class1.newInstance();
System.out.println(student);
//方式二 constructor newInstance
Constructor constructor = class1.getConstructor();
Student student1 = (Student) constructor.newInstance();
System.out.println(student1);
获取构造方法 getDeclaredConstructors
Class class1 = Class.forName("reflection.Student");
Constructor[] constructors = class1.getDeclaredConstructors();
通过反射获取到某个 Method 类对象后,可以通过调用invoke方法执行。
在 Java 中,所有的异常都有一个共同的祖先
java.lang
包中的Throwable
类。Throwable
类有两个重要的子类Exception
(异常)和Error
(错误)。Exception
能被程序本身处理(try-catch
),Error
是无法处理的(只能尽量避免)。
Exception
和Error
二者都是 Java 异常处理的重要子类,各自都包含大量子类。
Exception
:程序本身可以处理的异常,可以通过catch
来进行捕获。Exception
又可以分为 受检查异常(必须处理) 和 不受检查异常(可以不处理)。Error
:Error
属于程序无法处理的错误 ,我们没办法通过catch
来进行捕获 。例如,Java 虚拟机运行错误(Virtual MachineError
)、虚拟机内存不够错误(OutOfMemoryError
)、类定义错误(NoClassDefFoundError
)等 。这些异常发生时,Java 虚拟机(JVM)一般会选择线程终止。
异常要么抛出去要么捕获
try-catch-finally
try
块: 用于捕获异常。其后可接零个或多个catch
块,如果没有catch
块,则必须跟一个finally
块。catch
块: 用于处理 try 捕获到的异常。finally
块: 无论是否捕获或处理异常,finally
块里的语句都会被执行。当在try
块或catch
块中遇到return
语句时,finally
语句块将在方法返回之前被执行。
序列化: 将数据结构或对象转换成二进制字节流的过程
反序列化:将在序列化过程中所生成的二进制字节流的过程转换成数据结构或者对象的过程
序列化的主要目的是通过网络传输对象或者说是将对象存储到文件系统、数据库、内存中。\
对于不想进行序列化的变量,使用
transient
关键字修饰。`
Java I0 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。
- InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
- OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还算是非常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以, I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。
List
(对付顺序的好帮手): 存储的元素是有序的、可重复的。Set
(注重独一无二的性质): 存储的元素是无序的、不可重复的。Map
(用 Key 来搜索的专家): 使用键值对(key-value)存储,类似于数学上的函数 y=f(x),“x”代表 key,"y"代表 value,Key 是无序的、不可重复的,value 是无序的、可重复的,每个键最多映射到一个值。
- 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
- 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
- 抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。
1、定义一个类继承Thread类,并重写Thread类的run()方法,run()方法的方法体就是线程要完成的任务,因此把run()称为线程的执行体;
2、通过实现Runnable接口创建线程类
3、通过Callable和Future接口创建线程
第一种方式由于java的单继承性,继承了Thread类就不能继承其他类了,比较尴尬。我们用的最对的是第二种方式,比较方便,但是第二种不能返回线程处理的结果,因此有了第三种方式,得到返回结果。
1、什么是哈希
是一种信息摘要算法,它还叫做哈希,或者散列。通过输入key进行Hash计算,就可以获取key的HashCode()。
2、HashMap的数据结构
哈希表结构(链表散列:数组+链表)实现
3、HashMap的工作原理
HashMap
底层是hash数组和单向链表实现,数组中的每个元素都是链表,由Node内部类(实现Map.Entry
接口)实现,HashMap
通过put&get
方法存储和获取。4、
统一管理,网关一般都会提供请求转发、安全认证(身份/权限认证)、流量控制、负载均衡、容灾、日志、监控这些功能。
让分布式或者微服务系统中不同服务之间的调用像本地调用一样简单。