秒杀流程、IOC和AOP、对高并发的理解、java反射、Mybatis的一二级缓存、动态sql、SpringBoot自动装载、java是值传递、sql优化、防止sql注入、Hsah碰撞、循环依赖
秒杀流程、IOC和AOP、对高并发的理解、java反射、Mybatis的一二级缓存、动态sql、SpringBoot自动装载、java是值传递、sql优化、防止sql注入、Hsah碰撞、循环依赖List Map Set将Bean放入Spring容器中的方式如果客户端禁用cookie, session还能用吗Redis数据结构及应用场景Java stream操作流常用的方式Stream流中的方法
秒杀流程
1、提前预热
2、不走购物车
3、xxljob(调用商品接口、提前预热、调用库存接口)
介绍一下IOC和AOP
ioc具有依赖注入的容器,负责管理对象的实例化,通常需要主动去new对象,现在将new对象的过程权限交给ioc容器来处理.这就实现了控制反转
(将对象的生命周期将给bean容器管理,实现代码的解耦和灵活性,通过依赖注入实现)
aop 业务交叉,在不改变原来代码的基础上实现对业务的增强(面向切面编程)
谈一下对高并发的理解,平时怎么处理高并发问题
高并发是指系统在同一时间内处理大量请求。
1、使用缓存技术 redis
2、数据库优化
3、负载均衡,使用负载均衡技术分发到不同的服务器,避免单个服务器过载
4、限流与熔断
@Autowired @Resource的区别
1. @Autowired:是Spring框架提供的注解,通过类型匹配的方式进行依赖注入。它可以用于属性、构造方法、Setter方法和其他自定义方法上。当有多个匹配的依赖项时,可使@Qualifier注解指定具体的依赖项。@Autowired注解默认是按照byType方式进行注入,如果找不到匹配的依赖项,会抛出异常。
2. @Resource:是Java EE提供的注解,通过名称匹配的方式进行依赖注入。它可以用于属性、Setter方法和其他自定义方法上。@Resource注解默认是按照byName方式进行注入,如果找不到匹配的依赖项,会尝试按照byType方式进行注入。可以通过@Resource(name = "beanName")注解指定具体的依赖项。
什么是java反射
Java反射机制是指在运行时,通过获取类的信息并操作类或对象的属性、方法、构造函数等。它允许程序在运行时动态地加载和使用,而不需要在编译时就确定这些类的具体信息。(可能会带来性能上的开销)
反射机制运用的场景
我们在实际开发中很少用到反射,但spring使用反射机制来实现依赖注入、自动装配、AOP(面向切面编程)动态代理等功能。当然了还有数据库jdbc的连接
-
框架和库开发:很多框架和库使用反射来实现插件系统,使用户能够动态加载和扩展功能。例如,Spring框架使用反射来管理和初始化Bean对象。
-
序列化和反序列化:对象的序列化和反序列化需要访问对象的私有字段和方法,反射可用于实现这些操作。Java中的
ObjectOutputStream和ObjectInputStream就使用了反射。 -
注解处理器:许多注解处理工具使用反射来扫描和分析源代码中的注解,然后生成相关的代码。例如,Java的注解处理器可用于生成代码,从而减少样板代码的编写。
-
单元测试和调试工具:测试框架和调试工具可以使用反射来检查和修改类的状态,以便进行单元测试或诊断问题。
-
JavaBean 操作:在图形用户界面(GUI)开发中,反射可用于自动地设置和获取JavaBean的属性,使用户界面与数据模型之间的绑定更加灵活。
-
反射也可以用于实现一些高级的编程技巧,如动态代理、AOP(面向切面编程)和依赖注入,用于实现日志记录、性能监控、事务管理等功能
Mybatis的一二级缓存
1. 一级缓存:一级缓存是MyBatis默认开启的缓存,它是指在同一个SqlSession中,对于相同的查询语句和参数,第一次查询会将结果缓存到内存中,后续相同的查询会直接从缓存中获取结果,避免了重复查询数据库。一级缓存的作用域是SqlSession级别的,当SqlSession关闭或清除缓存时,一级缓存也会被清除。
2. 二级缓存:二级缓存是在SqlSessionFactory级别上的缓存,它可以被多个SqlSession共享。当多个SqlSession执行相同的查询时,查询结果会被缓存到二级缓存中。当其他SqlSession执行相同的查询时,会先从二级缓存中获取结果,而不是直接查询数据库。二级缓存的作用范围是Mapper级别的,可以通过配置开启或关闭二级缓存。
为什么要用动态sql
为了满足实际开发中,能够根据用户随时更改的业务需求,灵活地对数据进行增删改操作,尽可能减少对代码的更改,及时完成要求。
Spring Boot 自动装载原理
首先SpringBoot要想启动,就必须要加一个复合注解@SpringBootApplication,
在这个注解里面有三个注解,而自动装配就是通过@EnableAutoConfiguration注解里的EnableAutoConfigurationImportSelector.class来实现的,
并给你指定路径要去METAINF下的spring.factories文件找动配置类
java是值传递还是引用传递?
基本类型作为参数被传递时肯定是值传递;
引用类型作为参数被传递时也是值传递,
只不过这个值实际上是对象内存地址的引用。
在Java中,无论是基础类型传递还是对象传递,总是按值传递的。
常用的sql优化
1、避免使用select *
2、分页优化limit 避免一次性返回过多数据,可进行分页,对于一百万数据取最后20条,我们可查用 select id,name,age from user where id>1000000 limit 20
3、使用union all 代理 union union会进行去重
4、避免使用or 使用in
5、使用join优化 避免使用子查询
6、优化like语句
如何防止sql注入
#占位符可以防止SQL注入攻击,因为参数值会被预编译,不会将参数值直接拼接到SQL语句中。
$占位符不会对参数进行预编译,参数值会直接拼接到SQL语句中,所以需要注意SQL注入攻击的风险。
Hsah碰撞是什么?如何解决
hash碰撞指的是,两个不同的值(比如张三、李四的学号)经过hash计算后,得到的hash值相同,导致冲突。
解决方式:
1、开放地址法 如果hash值相同,回向右边继续寻找,找到null位置,然后放进去
2、拉链法 通过hash算法如果有值,则将对象放到该链的链表上
3、再哈希法 通过hash值算法,如果有值则再进行hash算法算一次,直到能存放为止
4、公共溢出区 如果发生碰撞,则将它放在单独的区域,查找的时候没找到就去单独区找
Spring是如何解决循环依赖的
Spring框架使用一种特殊的机制来解决循环依赖问题,这个机制被称为"提前暴露(early exposure)"或"三级缓存"。
1.Spring首先从一级缓存singletonObjects中获取。
2.如果获取不到,并且对象正在创建中,就再从二级缓存earlySingletonObjects中获取。
3.如果还是获取不到且允许singletonFactories通过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取.
4.如果从三级缓存中获取到就从singletonFactories中移除,并放入earlySingletonObjects中。其实也就是从三级缓存移动到了二级缓存。
这机制使得Spring能够在发生循环依赖时仍然成功实例化bean,并确保它们在正确的时间点初始化。下面是Spring解决循环依赖的基本原理:
-
Bean定义阶段:当Spring容器初始化时,它首先解析所有bean的定义,包括它们的依赖关系。
-
实例化Bean对象:在实例化bean时,Spring会创建一个包装对象(proxy)作为bean的代理,而不是直接创建实际的bean对象。这个代理对象用来处理循环依赖。
-
注册Bean对象:Spring容器会将正在创建的bean对象放入三级缓存中,分为三个阶段:未暴露、已暴露和已完成。一开始,bean对象被标记为"未暴露"。
-
依赖注入:Spring继续实例化其他bean,并进行依赖注入。当遇到循环依赖的情况时,代理对象会返回一个尚未初始化的bean代理,以满足依赖关系。
-
初始化Bean:在后续的阶段,Spring容器会递归地初始化依赖的bean。当初始化完成后,bean会被标记为"已完成"。
-
暴露Bean:在合适的时机,Spring会将bean标记为"已暴露",这表示该bean已准备好供其他bean引用。
通过这个机制,Spring能够成功处理循环依赖,确保每个bean在被使用之前都已经初始化完成。这减少了循环依赖导致的问题,同时也提高了性能,因为不需要频繁地创建和销毁bean对象。
Spring解决循环依赖的方法有点像"你帮我,我帮你"的情况。当两个类彼此互相需要并创建对方的实例时,Spring采用以下步骤来解决这个问题:
-
首先,Spring创建两个类的代理(类似于替身)对象,而不是直接创建它们的实际对象。这些代理对象充当了缓冲的角色。
-
接着,Spring会先创建一个类的代理对象,并将它注入到另一个类中,以满足它的依赖。
-
这时,第一个类的代理对象已经被创建,但它并没有真正的初始化。Spring会继续创建第二个类的代理对象,并将它注入到第一个类中。
-
现在,第二个类的代理对象也已经被创建,但同样尚未真正初始化。这时,Spring会开始初始化这两个代理对象,确保它们能够正常工作。
通过这种方式,Spring在互相依赖的类之间建立了一个"先创建代理,后初始化"的机制,避免了循环依赖问题。最终,这两个类都能够正常工作,而不会陷入无限循环的初始化中。
List Map Set
List适用于需要有序、允许重复元素的场景;
Map适用于需要通过键快速查找值的场景,键唯一;
Set适用于不允许重复元素的场景。
将Bean放入Spring容器中的方式
1、@Configuration+ @Bean 在配置类中引入第三方bean
2、使用注解 @Compoent 然后在注解类上@ComponentScan进行路径配置扫描
3、@Import直接导入类
4、通过xml的配置
如果客户端禁用cookie, session还能用吗
如果浏览器禁用了 cookie,浏览器请求服务器无法携带 sessionid,服务器无法识别请求中的用户身份,session失效。
解决方案:
方案1.通过url重写,把 sessionid 作为参数追加的原 url 中,后续的浏览器与服务器交互中携带 sessionid 参数。
方案2.服务器的返回数据中包含 sessionid,浏览器发送请求时,携带 sessionid 参数。
方案3.通过 Http 协议其他 header 字段,服务器每次返回时设置该 header 字段信息,浏览器中 js 读取该 header 字段,请求服务器时,js设置携带该 header 字段。
Redis数据结构及应用场景
1、字符串(String):存储字符串、整数或浮点数等类型的值。计数器
2、列表(List):按照插入顺序存储一组字符串
3、集合(Set):无序存储一组字符串,支持集合运算。交集并集
4、有序集合(ZSet):有序存储一组字符串,每个字符串关联一个分数,支持按照分数范围查询和排名查询。
5、哈希表(Hash):存储键值对,其中健和值都是字符串类型。
应用场景:
1、缓存:Redis可以作为缓存服务器,将常用的数据缓存在内存中,提高访问速度。
2、计数器:使用Redis的原子操作实现计数器功能,如网站访问量统计、商品销量统计等。
3、分布式锁:使用Redis的setnx命令实现分布式锁功能,在分环境下保证同一时刻只有一个客户端能够执行某个操作。
4、发布/订阅系统:Redis支持发布/订阅模式,在消息发布者和消息订阅者之间建立通信渠道,实现实时消息推送功能。MQ
5、排行榜系统:使用Redis的有序集合实现排行榜功能,根据分数排序并返回排名前N的数据。
6、地理位置服务:使用Redis的地理位置功能,存储地理位置信息,并支持查询附近的位置信息。
Java stream操作流常用的方式
在Java中,Stream操作流是Java 8新引入的一个功能,它提供了很多强大的操作,方便我们进行集合的处理和操作。常用的Stream操作方式有:
1.过滤:使用filter()方法可以过滤掉集合中不符合条件的元素。
2.映射:使用map()方法可以对集合中的每一个元素进行映射处理。
3.排序:使用sorted()方法可以对集合中的元素进行排序。
4.去重:使用distinct()方法去掉集合中的重复的元素。
5.统计:使用count()方法可以对集合中的元素进行统计。
6.聚合:使用reduce()方法可以对集合中的元素进行聚合计算。
7.遍历:使用forEach()方法可以遍历集合中的每一个元素。
8.匹配:使用anyMatch()、allMatch()、noneMatch()方法可以对集合中的元素进行匹配判断。
9.分组:使用qroupingBy()方法可以按照某一个属性进行分组。
10.转换:使用collect()方法可以将集合中的元素转换为另一个集合。
11.平均:使用average()方法可以用于计算一组元素的平均值。
Stream流中的方法
Stream提供了大量的方法进行聚集操作,这些方法既可以是“中间的”,也可以是“末端的”。
中间方法:中间操作允许流保持打开状态,并允许直接调用后续方法。上面程序中的map()方法就是中间方法。中间方法的返回值是另外一个流。
末端方法:末端方法是对流的最终操作。当对某个Stream执行末端方法后,该流将会被“消耗”且不再可用。上面程序中的sum()、count()、average()等方法都是末端方法。
除此之外,关于流的方法还有如下两个特征:
有状态的方法:这种方法会给流增加一些新的属性,比如元素的唯一性、元素的最大数量、保证元素以排序的方式被处理等。有状态的方法往往需要更大的性能开销。
短路方法:短路方法可以尽早结束对流的操作,不必检查所有的元素。
下面简单介绍一下Stream常用的中间方法:
filter(Predicate predicate):过滤Stream中所有不符合predicate的元素。
mapToXxx(ToXxxFunction mapper):使用ToXxxFunction对流中的元素执行一对一的转换,该方法返回的新流中包含了ToXxxFunction转换生成的所有元素。
peek(Consumer action):依次对每个元素执行一些操作,该方法返回的流与原有流包含相同的元素。该方法主要用于调试。
distinct():该方法用于排序流中所有重复的元素(判断元素重复的标准是使用equals()比较返回true)。这是一个有状态的方法。
sorted():该方法用于保证流中的元素在后续的访问中处于有序状态。这是一个有状态的方法。
limit(long maxSize):该方法用于保证对该流的后续访问中最大允许访问的元素个数。这是一个有状态的、短路方法。
下面简单介绍一下Stream常用的末端方法:
forEach(Consumer action):遍历流中所有元素,对每个元素执行action。
toArray():将流中所有元素转换为一个数组。
reduce():该方法有三个重载的版本,都用于通过某种操作来合并流中的元素。
min():返回流中所有元素的最小值。
max():返回流中所有元素的最大值。
count():返回流中所有元素的数量。
anyMatch(Predicate predicate):判断流中是否至少包含一个元素符合Predicate条件。
noneMatch(Predicate predicate):判断流中是否所有元素都不符合Predicate条件。
findFirst():返回流中的第一个元素。
findAny():返回流中的任意一个元素。
除此之外,Java 8允许使用流式API来操作集合,Collection接口提供了一个stream()默认方法,该方法可返回该集合对应的流,接下来即可通过流式API来操作集合元素。由于Stream可以对集合元素进行整体的聚集操作,因此Stream极大地丰富了集合的功能。
Java 8新增了Stream、IntStream、LongStream、DoubleStream等流式API,这些API代表多个支持串行和并行聚集操作的元素。上面4个接口中,Stream是一个通用的流接口,而IntStream、LongStream、DoubleStream则代表元素类型为int、long、double的流。
Java 8还为上面每个流式API提供了对应的Builder,例如Stream.Builder、IntStream.Builder、LongStream.Builder、DoubleStream.Builder,开发者可以通过这些Builder来创建对应的流。
独立使用Stream的步骤如下:
1、使用Stream或XxxStream的builder()类方法创建该Stream对应的Builder。
2、重复调用Builder的add()方法向该流中添加多个元素。
3、调用Builder的build()方法获取对应的Stream。
4、调用Stream的聚集方法。
在上面4个步骤中,第4步可以根据具体需求来调用不同的方法,Stream提供了大量的聚集方法供用户调用,具体可参考Stream或XxxStream的API文档。对于大部分聚集方法而言,每个Stream只能执行一次。
类加载的过程
1. 加载:通过类加载器(ClassLoader)查找并加载类的字节码文件。类加载器可以是系统类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)或应用类加载器(Application ClassLoader)等。类加载器根据类的全限定名(包名+类名)定位类的字节码文件,并读取到内存中。
2. 验证:对加载的字节码文件进行验证,确保其符合Java虚拟机规范。验证的内容包括语法验证、语义验证、字节码验证等。
3. 准备:为类的静态变量分配内存,并设置默认初始值。这些变量会在类的初始化阶段赋予正确的初始值。
4. 解析:将类中的符号引用(如方法、字段的符号引用)解析为直接引用(如方法、字段在内存中的地址)。解析过程可以在加载阶段之后进行,也可以在初始化阶段之后进行。
5. 初始化:对类进行初始化,即执行类的初始化方法(<clinit>)。类的初始化过程包括静态变量的赋值、静态代码块的执行等。初始化是类加载的最后一步,类加载过程中的其他步骤都是为了保证类的正确加载和初始化。
红黑树的时间复杂度为O(log n)
数组的时间复杂度为O(1)。
对于单向链表,插入和删除操作的时间复杂度为O(1),搜索操作,需要遍历链表,时间复杂度为O(n)
对于双向链表,插入和删除操作的时间复杂度同样为O(1),但搜索操作可以通过双向遍历进行优化,平均时间复杂度为O(n/2)
更多推荐



所有评论(0)