美文网首页互联网科技Java0.面试技能
备战金九银十,Java研发面试题(Spring、MySQL、JV

备战金九银十,Java研发面试题(Spring、MySQL、JV

作者: Java_苏先生 | 来源:发表于2019-07-28 21:17 被阅读29次

    八月在即,马上就是"金九银十",又是跳槽招聘季。咱们这行公认涨薪不如跳槽加的快。但不建议频繁跳槽,还是要学会融合团队,抓住每个机会提升技能。

    苏先生在这里给大家整理了一套各大互联网公司面试都喜欢问的一些问题或者一些出场率很高的Java研发面试题,给在校招或者社招路上的你一臂之力。

    目录

    1. Spring
    2. Netty
    3. MySQL
    4. JVM
    5. Tomcat
    6. Mybatis
    7. Redis
    8. Kafka
    9. 读者福利

    一. Spring

    1、什么是 Spring 框架?Spring 框架有哪些主要模块?

    Spring 框架是一个为 Java 应用程序的开发提供了综合、广泛的基础性支持的 Java 平台。

    Spring 帮助开发者解决了开发中基础性的问题,使得开发人员可以专注于应用程序的开发。

    Spring 框架本身亦是按照设计模式精心打造,这使得我们可以在开发环境中安心的集成 Spring 框架,不必担心 Spring 是如何在后台进行工作的。

    Spring 框架至今已集成了 20 多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。

    2、什么是控制反转(IOC)?什么是依赖注入?

    控制反转是应用于软件工程领域中的,在运行时被装配器对象来绑定耦合对象的一种编程技巧,对象之间耦合关系在编译时通常是未知的。在传统的编程方式中,业 务逻辑的流程是由应用程序中的早已被设定好关联关系的对象来决定的。在使用控制反转的情况下,业务逻辑的流程是由对象关系 图来决定的,该对象关系图由装配 器负责实例化,这种实现方式还可以将对象之间的关联关系的定义抽象化。而绑定的过程是通过“依赖注入”实现的。

    控制反转是一种以给予应用程序中目标组件更多控制为目的设计范式,并在我们的实际工作中起到了有效的作用。

    依赖注入是在编译阶段尚未知所需的功能是来自哪个的类的情况下,将其他对象所依赖的功能对象实例化的模式。这就需要一种机制用来激活相应的组件以提供特定的功能,所以依赖注入是控制反转的基础。否则如果在组件不受框架控制的情况下,框架又怎么知道要创建哪个组件?

    3、怎样用注解的方式配置 Spring?

    Spring 在 2.5 版本以后开始支持用注解的方式来配置依赖注入。可以用注解的方式来替代 XML 方式的 bean 描述,可以将 bean 描述转移到组件类的 内部,只需要在相关类上、方法上或者字段声明上使用注解即可。注解注入将会被容器在 XML 注入之前被处理,所以后者会覆盖掉前者对于同一个属性的处理结果。

    注解装配在 Spring 中是默认关闭的。所以需要在 Spring 文件中配置一下才能使用基于注解的装配模式。如果你想要在你的应用程序中使用关于注解的方法的话,请参考如下的配置。

    <beans>
    <context:annotation-config/>
    <!-- bean definitions go here -->
    </beans>
    

    在 <context:annotation-config/>标签配置完成以后,就可以用注解的方式在 Spring 中向属性、方法和构造方法中自动装配变量。

    下面是几种比较重要的注解类型

    1. @Required:该注解应用于设值方法。
    2. @Autowired:该注解应用于有值设值方法、非设值方法、构造方法和变量。
    3. @Qualifier:该注解和@Autowired 注解搭配使用,用于消除特定 bean 自动装配的歧义。
    4. JSR-250 Annotations:Spring 支持基于 JSR-250 注解的以下注解,@Resource、@PostConstruct 和 @PreDestroy。

    二. Netty

    1、Netty 的特点?

    一个高性能、异步事件驱动的 NIO 框架,它提供了对 TCP、UDP 和文件传输的支持使用更高效的 socket 底层,对 epoll 空轮询引起的 cpu 占用飙升在内部进行了处理,避免了直接使用 NIO 的陷阱,简化了 NIO 的处理方式。

    采用多种 decoder/encoder 支持,对 TCP 粘包/分包进行自动化处理可使用接受/处理线程池,提高连接效率,对重连、心跳检测的简单支持可配置 IO 线程数、TCP 参数, TCP 接收和发送缓冲区使用直接内存代替堆内存,通过内存池的方式循环利用 ByteBuf通过引用计数器及时申请释放不再引用的对象,降低了 GC 频率使用单线程串行化的方式,高效的 Reactor 线程模型大量使用了 volitale、使用了 CAS 和原子类、线程安全类的使用、读写锁的使用

    2、Netty 的线程模型?

    Netty 通过 Reactor 模型基于多路复用器接收并处理用户请求,内部实现了两个线程池,boss 线程池和 work 线程池,其中 boss 线程池的线程负责处理请求的 accept 事件,当接收到 accept 事件的请求时,把对应的 socket 封装到一个 NioSocketChannel 中,并交给 work线程池,其中 work 线程池负责请求的 read 和 write 事件,由对应的 Handler 处理。

    • 单线程模型:所有 I/O 操作都由一个线程完成,即多路复用、事件分发和处理都是在一个Reactor 线程上完成的。既要接收客户端的连接请求,向服务端发起连接,又要发送/读取请求或应答/响应消息。一个 NIO 线程同时处理成百上千的链路,性能上无法支撑,速度慢,若线程进入死循环,整个程序不可用,对于高负载、大并发的应用场景不合适。

    • 多线程模型:有一个 NIO 线程(Acceptor) 只负责监听服务端,接收客户端的 TCP 连接请求;NIO 线程池负责网络 IO 的操作,即消息的读取、解码、编码和发送;1 个 NIO 线程可以同时处理 N 条链路,但是 1 个链路只对应 1 个 NIO 线程,这是为了防止发生并发操作问题。但在并发百万客户端连接或需要安全认证时,一个 Acceptor 线程可能会存在性能不足问题。

    • 主从多线程模型:Acceptor 线程用于绑定监听端口,接收客户端连接,将 SocketChannel从主线程池的 Reactor 线程的多路复用器上移除,重新注册到 Sub 线程池的线程上,用于 处理 I/O 的读写等操作,从而保证 mainReactor 只负责接入认证、握手等操作;

    3、BIO、NIO 和 AIO 的区别?

    • BIO:一个连接一个线程,客户端有连接请求时服务器端就需要启动一个线程进行处理。线程开销大。

    • 伪异步 IO:将请求连接放入线程池,一对多,但线程还是很宝贵的资源。

    • NIO:一个请求一个线程,但客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有 I/O 请求时才启动一个线程进行处理。

    • AIO:一个有效请求一个线程,客户端的 I/O 请求都是由 OS 先完成了再通知服务器应用去启动线程进行处理,BIO 是面向流的,NIO 是面向缓冲区的;BIO 的各种流是阻塞的。而 NIO 是非阻塞的;BIO的 Stream 是单向的,而 NIO 的 channel 是双向的。

    • NIO 的特点:事件驱动模型、单线程处理多任务、非阻塞 I/O,I/O 读写不再阻塞,而是返回 0、基于 block 的传输比基于流的传输更高效、更高级的 IO 函数 zero-copy、IO 多路复用大大提高了 Java 网络应用的可伸缩性和实用性。基于 Reactor 线程模型。

    在 Reactor 模式中,事件分发器等待某个事件或者可应用或个操作的状态发生,事件分发器就把这个事件传给事先注册的事件处理函数或者回调函数,由后者来做实际的读写操作。如在 Reactor 中实现读:注册读就绪事件和相应的事件处理器、事件分发器等待事件、事件到来,激活分发器,分发器调用事件对应的处理器、事件处理器完成实际的读操作,处理读到的数据,注册新的事件,然后返还控制权。

    三. MySQL

    1、有哪些数据库优化方面的经验?

    • ①. 用 PreparedStatement, 一般来说比 Statement 性能高:一个 sql 发给服务器去执行,涉及步骤:语法检查、语义分析, 编译,缓存。

    • ②. 有外键约束会影响插入和删除性能,如果程序能够保证数据的完整性, 那在设计数据库时就去掉外键。

    • ③. 表中允许适当冗余,譬如,主题帖的回复数量和最后回复时间等

    • ④. UNION ALL 要比 UNION 快很多,所以,如果可以确认合并的两个结 果集中不包含重复数据且不需要排序时的话,那么就使用 UNION ALL。 >>UNION 和 UNION ALL 关键字都是将两个结果集合并为一 个,但这两者从使用和效率上来说都有所不同。 >1. 对重复结果的处 理:UNION 在进行表链接后会筛选掉重复的记录,Union All 不会去除 重复记录。 >2. 对排序的处理:Union 将会按照字段的顺序进行排 序;UNION ALL 只是简单的将两个结果合并后就返回。

    2、mysql 中 myisam 与 innodb 的区别?

    • ①. 事务支持 > MyISAM:强调的是性能,每次查询具有原子性,其执行数 度比 InnoDB 类型更快,但是不提供事务支持。 > InnoDB:提供事 务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚 (rollback)和崩溃修复能力(crash recovery capabilities)的事务安全 (transaction-safe (ACID compliant))型表。

    • ②. InnoDB 支持行级锁,而 MyISAM 支持表级锁. >> 用户在操作 myisam 表时,select,update,delete,insert 语句都会给表自动 加锁,如果加锁以后的表满足 insert 并发的情况下,可以在表的尾部插入新的数据。

    • ③. InnoDB 支持 MVCC, 而 MyISAM 不支持

    • ④. InnoDB 支持外键,而 MyISAM 不支持

    • ⑤. 表主键 > MyISAM:允许没有任何索引和主键的表存在,索引都是保 存行的地址。 > InnoDB:如果没有设定主键或者非空唯一索引,就会 自动生成一个 6 字节的主键(用户不可见),数据是主索引的一部分,附 加索引保存的是主索引的值。

    • ⑥. InnoDB 不支持全文索引,而 MyISAM 支持。

    • ⑦. 可移植性、备份及恢复 > MyISAM:数据是以文件的形式存储,所以 在跨平台的数据转移中会很方便。在备份和恢复时可单独针对某个表进 行操作。 > InnoDB:免费的方案可以是拷贝数据文件、备份 binlog,或者用 mysqldump,在数据量达到几十 G 的时候就相对痛 苦了

    • ⑧. 存储结构 > MyISAM:每个 MyISAM 在磁盘上存储成三个文件。第一 个文件的名字以表的名字开始,扩展名指出文件类型。.frm 文件存储表 定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名 是.MYI (MYIndex)。 > InnoDB:所有的表都保存在同一个数据文件 中(也可能是多个文件,或者是独立的表空间文件),InnoDB 表的大 小只受限于操作系统文件的大小,一般为 2GB。

    3、MySQL 中 InnoDB 引擎的行锁是通过加在什么上完成(或称实现) 的?

    InnoDB 行锁是通过给索引上的索引项加锁来实现的,这一点 MySQL 与 Oracle 不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB 这 种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB 才使用行级 锁,否则,InnoDB 将使用表锁!

    四. JVM

    1、内存模型以及分区,需要详细到每个区放什么。

    JVM 分为堆区和栈区,还有方法区,初始化的对象放在堆里面,引用放在栈里面,class 类信息常量池(static 常量和 static 变量)等放在方法区new:

    • 方法区:主要是存储类信息,常量池(static 常量和 static 变量),编译后的代码(字节码)等数据
    • 堆:初始化的对象,成员变量 (那种非 static 的变量),所有的对象实例和数组都要在堆上分配
    • 栈:栈的结构是栈帧组成的,调用一个方法就压入一帧,帧上面存储局部变量表,操作数栈,方法出口等信息,局部变量表存放的是 8 大基础类型加上一个应用类型,所以还是一个指向地址的指针
    • 本地方法栈:主要为 Native 方法服务
    • 程序计数器:记录当前线程执行的行号

    2、堆里面的分区:Eden,survival (from+ to),老年代,各自的特点。

    堆里面分为新生代和老生代(java8 取消了永久代,采用了 Metaspace),新生代包 含 Eden+Survivor 区,survivor 区里面分为 from 和 to 区,内存回收时,如果用的是复 制算法,从 from 复制到 to,当经过一次或者多次 GC 之后,存活下来的对象会被移动 到老年区,当 JVM 内存不够用的时候,会触发 Full GC,清理 JVM 老年区 当新生区满了之后会触发 YGC,先把存活的对象放到其中一个 Survice 区,然后进行垃圾清理。因为如果仅仅清理需要删除的对象,这样会导致内存碎 片,因此一般会把 Eden 进行完全的清理,然后整理内存。那么下次 GC 的时候, 就会使用下一个 Survive,这样循环使用。如果有特别大的对象,新生代放不下, 就会使用老年代的担保,直接放到老年代里面。因为 JVM 认为,一般大对象的存 活时间一般比较久远。

    3、简述 java 垃圾回收机制?

    在 java 中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行。在JVM 中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。

    五. Tomcat

    1、Tomcat 的缺省端口是多少,怎么修改?

    • 找到 Tomcat 目录下的 conf 文件夹
    • 进入 conf 文件夹里面找到 server.xml 文件
    • 打开 server.xml 文件
    • 在 server.xml 文件里面找到下列信息<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" uriEncoding="utf-8"/> port="8080"改成你想要的端口

    2、Tomcat 有几种部署方式?

    • 直接把 Web 项目放在 webapps 下,Tomcat 会自动将其部署
    • 在 server.xml 文件上配置<Context>节点,设置相关的属性即可
    • 通过 Catalina 来进行配置:进入到 conf\Catalina\localhost 文件下,创建一个 xml 文件,该文件的名字就是站点的名字。

    3、tomcat 容器是如何创建 servlet 类实例?用到了什么原理?

    当容器启动时,会读取在 webapps 目录下所有的 web 应用中的 web.xml 文 件,然后对 xml 文件进行解析,并读取 servlet 注册信息。然后,将每个应用中注册的 servlet 类都进行加载, 并通过反射的方式实例化。(有时候也是在第一次请求时实例化)在 servlet 注册时加上如果为正数,则在 一开始就实例化,如果不写或为负数,则第一次请求实例化。

    六. MyBatis

    1、讲下 MyBatis 的缓存

    MyBatis 的缓存分为一级缓存和二级缓存,一级缓存放在 session 里面,默认就有,二级缓存放在它的命名空间里,默认是不打开的,使用二级缓存属性类需要实现 Serializable 序列化接口(可用来保存对象的状态),可在它的映射文件中配置<cache/>

    2、Mybatis 是如何进行分页的?分页插件的原理是什么?

    • Mybatis 使用 RowBounds 对象进行分页,也可以直接编写 sql 实现分页,也可以使用Mybatis 的分页插件。
    • 分页插件的原理:实现 Mybatis 提供的接口,实现自定义插件,在插件的拦截方法内拦截待执行的 sql,然后重写 sql。举例:select * from student,拦截 sql 后重写为:select t.* from (select * from student)tlimit 0,10

    3、简述 Mybatis 的插件运行原理,以及如何编写一个插件?

    • Mybatis 仅可以编写针对 ParameterHandler、ResultSetHandler、StatementHandler、Executor 这 4 种接口的插件,Mybatis 通过动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler 的 invoke()方法,当然,只会拦截那些你指定需要拦截的方法。
    • 实现 Mybatis 的 Interceptor 接口并复写 intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。

    七. Redis

    1、Redis 有哪几种数据淘汰策略?

    • noeviction:返回错误当内存限制达到,并且客户端尝试执行会让更多内存被使用的命令。
    • allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
    • volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
    • allkeys-random: 回收随机的键使得新添加的数据有空间存放。
    • volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
    • volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

    2、为什么 Redis 需要把所有数据放到内存中?

    Redis 为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。

    所以 redis 具有快速和数据持久化的特征,如果不将数据放在内存中,磁盘 I/O 速度为严重影响 redis 的性能。

    在内存越来越便宜的今天,redis 将会越来越受欢迎, 如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。

    3、Redis 如何做内存优化?

    尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。

    比如你的 web 系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的 key,而是应该把这个用户的所有信息存储到一张散列表里面。

    八. Kafka

    1、Kafka 的设计是什么样的呢?

    Kafka 将消息以 topic 为单位进行归纳
    将向 Kafka topic 发布消息的程序成为 producers.
    将预订 topics 并消费消息的程序成为 consumer.
    Kafka 以集群的方式运行,可以由一个或多个服务组成,每个服务叫做一个 broker.
    producers 通过网络将消息发送到 Kafka 集群,集群向消费者提供消息

    2、数据传输的事物定义有哪三种?

    数据传输的事务定义通常有以下三种级别:

    • 最多一次: 消息不会被重复发送,最多被传输一次,但也有可能一次不传输
    • 最少一次: 消息不会被漏发送,最少被传输一次,但也有可能被重复传输.
    • 精确的一次(Exactly once): 不会漏传输也不会重复传输,每个消息都传输被一次而且仅仅被传输一次,这是大家所期望的

    3、Kafka 高效文件存储设计特点:

    • Kafka 把 topic 中一个 parition 大文件分成多个小文件段,通过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用。
    • 通过索引信息可以快速定位 message 和确定 response 的最大大小。
    • 通过 index 元数据全部映射到 memory,可以避免 segment file 的 IO 磁盘操作。
    • 通过索引文件稀疏存储,可以大幅降低 index 文件元数据占用空间大小。

    相关文章

      网友评论

        本文标题:备战金九银十,Java研发面试题(Spring、MySQL、JV

        本文链接:https://www.haomeiwen.com/subject/bzfyrctx.html