题目
- 1、JVM的内存模型,回收机制?
- 2、怎么停止这个线程?
- 3、springboot的加载流程?
- 4、对IOC和AOP的理解?
- 5、jdk和cglib实现的AOP实际上会在内存生成动态代理对象,还有什么其他办法实现AOP?
- 6、Spring中的对象的作用域?
- 7、rpc与http的区别?
- 8、设计rpc协议需要注意什么?
- 9、消息队列的使用场景?
- 10、创建类的流程,类加载流程?
解答
题目一
- 题干:JVM的内存模型,回收机制?
- 分析:
-
JVM内存模型:
两个系统 两个组件 两个系统:类加载子系统、执行引擎系统;两个组件、运行时数据区组件、本地接口组件;
主要说一下:
运行时数据区:
包括 线程共享的区域:堆、方法区、【1.8去掉方法区改为元数据区】,线程私有的:Java栈、本地方法栈、程序计数器。
堆上一般存放的是对象的实例、常量池也在堆上、因为之前常量池在方法区但是去掉了方法区。
方法区【元数据区】:类的一些信息类名、类的成员变量、类中的方法、类的静态变量等等。Class对象是放在堆上的。
程序计数器:本地方法接口执行时只记录一个undefined java方法执行的时候则记录正在执行的字节码指令的地址。
JVM栈:存放的时基本类型变量、以及非基本类型的引用、方法执行结果、栈帧。
JVM栈只支持出入栈操作:局部变量表【参数局部变量】、操作数栈【方法执行结果】、帧数据区【常量引用的地址、异常处理表】
栈溢出StackOverflow可以通过Xss参数配置线程栈的大小。有时候对于不能够逃逸的对象可以考虑栈分配。
本地方法栈:本地方法的栈帧。Native。
回收机制:
程序运行会产生很多对象占用内存空间所以需要回收并释放空间。
回收算法:计数算法、复制算法、标记清除算法、标记压缩算法。
存活少的适用赋值算法,因为复制的对象少,存活多的不适用赋值算法,一般会采取标记清除算法、标记压缩算法。
分配对象的时候,首先会给每一个线程分配一个TLAB内存区,先在这个地方分配,太大的再去堆上分配,堆上分为三个区域:eden survivor old 首先在eden区分配经过第一次GC之后存活的对象移动到survivor区这里分为from 和to 会来回互换,我们可以设置一个阈值,这个阈值是移动的最大值,不一定一定要达到这个值才移动到老年代,
年轻代的回收触发机制是:年轻代使用率99%或者接近快用完的时候。
老年代的回收:
当准备要触发一次young GC时,如果发现统计数据说之前young GC的平均晋升大小比目前old gen剩余的空间大,则不会触发young GC而是转为触发full GC(因为HotSpot VM的GC里,除了CMS的concurrent collection之外,其它能收集old gen的GC都会同时收集整个GC堆,包括young gen,所以不需要事先触发一次单独的young GC);或者,如果有perm gen的话,要在perm gen分配空间但已经没有足够空间时,也要触发一次full GC;或者System.gc()、heap dump带GC,默认也是触发full GC。 - 回答:
-
见分析。
题目二
- 题干:怎么停止这个线程?
- 分析:
-
建议使用“抛异常”的方法来实现线程的停止,因为在catch块中还可以将异常向上抛,使线程停止事件得以传播。
- 回答:
-
建议使用“抛异常”的方法来实现线程的停止,因为在catch块中还可以将异常向上抛,使线程停止事件得以传播。
题目三
- 题干:springboot的加载流程?
- 分析:
-
Spring Boot的启动类上有一个@SpringBootApplication注解,这个注解是Spring Boot项目必不可少的注解。 @SpringBootApplication是一个复合注解或派生注解,在@SpringBootApplication中有一个注解@EnableAutoConfiguration而这个注解也是一个派生注解,其中的关键功能由@Import提供,其导入的AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(…)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。自动配置生效
每一个XxxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:
@ConditionalOnBean:当容器里有指定的bean的条件下。
@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
@ConditionalOnClass:当类路径下有指定类的条件下。
@ConditionalOnMissingClass:当类路径下不存在指定类的条件下。
@ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。
以ServletWebServerFactoryAutoConfiguration配置类为例,解释一下全局配置文件中的属性如何生效,比如:server.port=8081,是如何生效的(当然不配置也会有默认值,这个默认值来自于org.apache.catalina.startup.Tomcat)。
在ServletWebServerFactoryAutoConfiguration类上,有一个@EnableConfigurationProperties注解:开启配置属性,而它后面的参数是一个ServerProperties类,这就是习惯优于配置的最终落地点。
在这个类上,我们看到了一个非常熟悉的注解:@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。
至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。
而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。 - 回答:
-
Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。
题目四
- 题干:对IOC和AOP的理解?
- 分析:
-
IOC 是工厂模式为主
通过 读取配置文件 使用反射获取JavaConfig 或者使用注解@Autowaire @Resource 的类读取这些Bean 将其映射撑BeanDefined对象,将其放在使用BeanDefineRegistry将所有扫描到的bean放到注册的Bean列表里,然后创建Bean实例,如果是单例的Bean就放在Bean的缓存池里池子里是一个Map对象 key是类名 value是bean的实例对象。多例的直接返回给调用者。
AOP 主要是代理模式 使用的是jdk动态代理【实现接口】、cglib【实现类】动态代理。
参考第十题 - 回答:
-
题目五
- 题干:jdk和cglib实现的AOP实际上会在内存生成动态代理对象,还有什么其他办法实现AOP?
- 分析:
-
静态AOP代理 Aspect J 是使用自己的类 直接硬编码 所以编译的时候直接就生成class文件了,所以这个是静态的
动态的AOP代理, jdk、cglib 一个是使用反射一个是通过asm动态字节码工具来实现的。
参考第一题 - 回答:
-
题目六
- 题干:Spring中的对象的作用域?
- 分析:
-
singleton 和prototype这两个作用域是所有的SpringBean 对应BeanDefined对象中的属性,这就是说明所有的Bean都有这两个属性,然后根据具体配置决定是哪个作用域,而对于另外两个作用域request和session ,这两个是通过WebApplicationContext扩展而来的是属于Web层次的作用域,每个请求初始化具有此作用域的Bean注解。这听起来像是原型作用域的描述,但它们有一些差异。第一个区别是原型作用域在Spring的上下文中可用。而请求作用域仅适用于Web应用程序。第二个是原型bean根据需求进行初始化,而请求bean是在每个请求下构建的。需要说的是,request作用域bean在其作用域内有且仅有一个实例。而你可以拥有一个或多个原型作用域bean实例。Session作用域的bean与request 作用域的bean没有太大的不同。它们也与纯Web应用程序上下文相关联。注解为Session作用域的Bean对于每个用户的会话仅创建一次。他们在会话结束时被破坏销毁掉。
由Session作用域限制的Bean可以被认为是面向Web的单例,因为给定环境(用户会话)仅存在一个实例。但请记住,你无法在Web应用程序上下文中使用它们(说个好理解点的,就是一个函数内部自定义变量所在的作用域,函数执行完就销毁了,没有什么逃逸,关于此处更深入的理解请看我的博文由域联系到的逃逸分析)。 - 回答:
-
见分析
题目七
- 题干:rpc与http的区别?
- 分析:
-
http是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。
对于http1.1协议它的协议如果使用在rpc中有很多无用的信息,这样会浪费网络带宽影响效率,而对于http2.0协议已经优化编码效率问题,像grpc这种rpc库使用的就是http2.0协议。此外我们可以自己制定一些RPC框架的传输协议,如Dubbo中有很多种传输协议。
简单来说成熟的rpc库相对http容器,更多的是封装了“服务发现”,“负载均衡”,“熔断降级”一类面向服务的高级特性。可以这么理解,rpc框架是面向服务的更高级的封装。如果把一个http servlet容器上封装一层服务发现和函数代理调用,那它就已经可以做一个rpc框架了。
所以为什么要用rpc调用?
因为良好的rpc调用是面向服务的封装,针对服务的可用性和效率等都做了优化。单纯使用http调用则缺少了这些特性。
一个成熟的rpc框架是很全面的,除了通信协议外还有“服务注册发现”,错误重试,服务升级的灰度策略,服务调用的负载均衡等等。 - 回答:
-
简单来说成熟的rpc库相对http容器,更多的是封装了“服务发现”,“负载均衡”,“熔断降级”一类面向服务的高级特性。可以这么理解,rpc框架是面向服务的更高级的封装。如果把一个http servlet容器上封装一层服务发现和函数代理调用,那它就已经可以做一个rpc框架了。
所以为什么要用rpc调用?
因为良好的rpc调用是面向服务的封装,针对服务的可用性和效率等都做了优化。单纯使用http调用则缺少了这些特性。
一个成熟的rpc框架是很全面的,除了通信协议外还有“服务注册发现”,错误重试,服务升级的灰度策略,服务调用的负载均衡等等。
题目八
- 题干:设计rpc协议需要注意什么?
- 分析:
-
RPC 远程过程调用 RMI 远程方法调用。
Java的RMI是面向对象的 所以返回值是对象或者基本类型比如String Integer等
RPC是一种协议 区别于HTTP协议 HTTP的协议头有哦i自己的规划有很多消息,RPC根据自己的需求指定自己的解析协议,底层使用RPC
首先,要解决通讯的问题,主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。
第二,要解决寻址的问题,也就是说,A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称名称是什么,这样才能完成调用。比如基于Web服务协议栈的RPC,就要提供一个endpoint URI,或者是从UDDI服务上查找。如果是RMI调用的话,还需要一个RMI Registry来注册服务的地址。
第三,当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal),通过寻址和传输将序列化的二进制发送给B服务器。
第四,B服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。
第五,返回值还要发送回服务器A上的应用,也要经过序列化的方式发送,服务器A接到后,再反序列化,恢复为内存中的表达方式,交给A服务器上的应用 - 回答:
-
见分析
题目九
-
题干:消息队列的使用场景?
-
分析:
-
-
回答:
-
异步、解耦、削峰、最终一致性、广播、日志处理、消息通讯。
题目十
- 题干:创建类的流程,类加载流程?
- 分析:
-
AOP 和 IOC
- 回答:
-
IOC 是工厂模式为主
通过 读取配置文件 使用反射获取JavaConfig 或者使用注解@Autowaire @Resource 的类读取这些Bean 将其映射撑BeanDefined对象,将其放在使用BeanDefineRegistry将所有扫描到的bean放到注册的Bean列表里,然后创建Bean实例,如果是单例的Bean就放在Bean的缓存池里池子里是一个Map对象 key是类名 value是bean的实例对象。多例的直接返回给调用者。
AOP 主要是代理模式 使用的是jdk动态代理【实现接口】、cglib【实现类】动态代理。静态AOP代理 Aspect J 是使用自己的类 直接硬编码 所以编译的时候直接就生成class文件了,所以这个是静态的
动态的AOP代理, jdk、cglib 一个是使用反射一个是通过asm动态字节码工具来实现的。