【Java面试】SpringBoot篇

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 【Java面试】SpringBoot篇

Spring和SpringBoot的关系和区别?

他们都是Spring生态的产品。

Spring Framework是一个容器框架。

SpringBoot他不是一个框架,他是一个可以快速构建基于Spring的脚手架,里面包含了Spring和各自框架,为开发Spring生态其他框架铺平道路。他是为了更快的去开发Spring生态的整个系统而诞生的。

2者不是一个层面的东西,没有可比性。

谈谈你对SpringBoot的理解,它有哪些特性?

从本质上来说,Spring Boot就是Spring,它做了那些没有它你自己也会去做的Spring Bean配置。Spring Boot使用“约定优于配置”的理念让你的项目快速地运行起来,使用Spring Boot很容易创建一个能独立运行、准生产级别、基于Spring框架的项目,使用Spring Boot你可以不用或者只需要很少的Spring配置

简而言之,Spring Boot本身并不提供Spring的核心功能,而是作为Spring的脚手架框架,以达到快速构建项目、预置三方配置、开箱即用的目的。Spring Boot有如下的优点:

  • 可以快速构建项目,内置许多starter自动配置,开箱即用;
  • 可以对主流开发框架的无配置集成;
  • 项目可独立运行,无需外部依赖Servlet容器;
  • 提供运行时的应用监控;
  • 内置web容器,无需依赖外部web服务器,省略了web.xml,直接运行jar文件就可以启动web项目
  • 可以极大地提高开发、部署效率;
  • 管理了第三方依赖的版本,减少版本冲突问题
  • 简化开发,采用JavaConfig的方式可以使用零xml的方式开发项目
  • 可以与云计算天然集成。

SpringBoot的核心注解

  1. @SpringBootApplication注解:这个注解标识了一个SpringBoot工程,它实际上是另外三个注解的组合,这三个注解是@SpringBootConfiguration,@EnableAutoConfguration,@ComponentScan。
  2. @SpringBootConfiguration:这个注解实际就是一个@Configuration,表示启动类也是一个配置类。
  3. @EnableAutoConfguration:向Spring容器中导入了一个Selector,用来加载ClassPath下spring.factories中所定义的自动配置类,将这些自动加载为配置Bean。
  4. @Conditional也很关键,如果没有它我们无法在自定义应用中进行定制开发
    @ConditionalOnBean
    @ConditionalOnClass
    @ConditionalOnExpression

说说你对SpringBoot自动配置的理解

自动装配简单来说就是自动吧第三方的bean加载到IOC容器中去。不需要开发人员在去写bean相关的配置。在sb项目中只要在启动类上加上@SpringBootApplication注解就可以实现自动装配。这个注解是一个复合注解,真正去实现自动装配的注解是@EnableAutoConfiguration。自动装配的实现主要依靠三个核心的技术。

第一个是引入starter。启动依赖组件的时候,这个组件里面必须包含@Configuration配置类,而在这个配置类中我们需要通过@Bean这个注解去声明要加载到IOC容器中的对象。

第二个是这个配置类是放在第三方的jar包中的。然后通过sb中的约定优于配置这样的一个理念,去吧这个配置类的全路径放在classpath:/META-INF/spring.factories文件里面。这样sb就可以知道第三方jar包里面这个配置类的位置。这个步骤主要使用到了spring中的SpringFactoriesLoader来完成的。

第三个是sb拿到所有第三方jar包里面的声明的配置类之后,在通过Spring提供的ImportSelector这样的一个接口,来实现对这些配置类的动态加载。从而去完成自动装配这样一个动作。

在我看来呢,sb是约定优于配置这一理念的产物,所以在很多的地方都会看到这一思想。它的出现让开发人员可以更加聚焦于业务代码的开发,而不需要去关心和业务无关的配置。其实自动装配的思想,在SpringFrameword3.x中的@Enable注解已经有了体现。这是一个模块

驱动注解,也就是我们只要添加这个注解,就能自动开启某个功能。而不需要针对这个功能去做bean的配置。enbale的底层也是自动帮我们去完成一个模块相关bean的注入的。

为什么SpringBoot的jar包可以直接运行?

  1. SpringBoot提供了一个插件spring-boot-maven-plugin用于把程序打包成一个可执行的jar包。
  2. Spring Boot应用打包之后,生成一个Fat jar(jar包中包含jar,比较臃肿,所以叫Fat.jar),包含了应用依赖的jar包和Sprirg Boot loader相关的类。
  3. java -jar会去找jar中的manifest文件,在那里面找到真正的启动类。
    这是因为Java已经定义了java -jar这个命令去加载jar包中的manifest文件,并且以这个文件中的Main-Class后面的路径来找到启动类。
  4. Fat jar的启动Main函数是JarLauncher,它负责创建一个LaunchedURLClassLoader来加载boot-lib下面的jar,并以一个新线程启动应用的Main函数。

SpringBoot的启动原理(还在改进)

会不会自定义Starter?大概实现过程?

我们需要在我们自定义的starter中的resources下创建文件夹META-INF并在METE-INF下创建文件spring.factories。

然后在里面设定你要自动配置的配置类的全路径。格式为

之后我们编写我们的配置类,并且在配置类中通过@Bean注解把要注入IOC容器中的bean进行声明。

SpringBoot读取配置文件的原理是什么?加载顺序是怎么样的?

通过事件监听的方式读取配置文件:ConfigFileApplicationListener

优先级从高到低,高优先级的配置覆盖低优先级的配置,所有配置会形成互补配置。

SpringBoot的默认日志实现框架是什么?怎么切换成别的?

默认的日志框架是logback。

SpringBoot项目的日志门面使用的是slf4j,而SpringBoot默认使用的是logback提供的桥接器,因此SpringBoot默认会使用logback进行日志功能。

想要切换日志,那么需要做如下操作:

1:将logback的场景启动器排除(slf4j只能运行有一个桥接器)

2:添加新的日志的场景启动器

3:添加新的日志的配置文件

目前springboot已经为我们提供了logfj2和logback的starter,因此我们可以直接开箱即用。

但是如果要使用logfj,那么就需要首先排除logbakc的依赖,然后添加log4j的桥接器,然后再添加log4j的配置文件。

说说你在开发的时候怎么在SpringBoot上进行扩展?

如果想要对某个功能进行扩展,那么首先得了解这个功能是如何进行配置的,因此我可能会先去查看这个功能的官方文档,之后大致了解之后,会查看底层源码。

这里我以AOP为例吧。

我们知道AOP默认使用的是cglib来进行动态代理,那么如果我想要它使用JDK提供的动态代理怎么办呢?

那么此时就得去查看AOP对应的配置类了。

我知道SpringBoot项目中的配置类一般名称为XxxAutoConfiguration。

因此我就会搜索AopAutoConfiguration。然后查找启动的可能的配置属性。

一般查看@Condition注解里面可能会有某个属性的开关。

那么如果找到了,那么只需要去配置文件中进行属性的修改配置即可。

当然,有些自动配置类提供对外的扩展接口,实现接口也可以进行扩展,比如我们的SpringMvc。

如果我们要对SpringMvc进行扩展,那么我们只要实现WebMvcConfigurer这个接口即可。

所以我一般都会选择看源码这种方式。IDEA非常方便,搜索对应的XxxAutoConfiguration即可。

SpringBoot是如何选择使用Jetty还是Tomcat的?

我们知道,我们是可以获取到SpringBoot要进行加载的Bean的类型的,那么如果我们获取到了所有要加载的Bean,那么此时就可以通过这些Bean对象来选择是使用Jetty还是Tomcat。

比如我定义了Tomcat,那么我就选择加载Tomcat,反之我可以加载Jetty。如果都定义或者都没有定义,那么会进行报错。其中没有名字报错是因为你明明把这个项目声明为了一个Web项目,结果你没有对应的服务器,或者就是你只能选择一个服务器,结果你给我定义了多个服务器,那么我选那个?所以会报错。那么如果流程正常,我就会创建这个Bean,也就是Tomcat或者Jetty服务器。

但是其实SpringBoot默认把Jetty,Tomcat,Undertow三个Web服务器都声明为了Bean,那么很明显会出现冲突。所以此时就通过@Condition进行条件判断来选择加载那个Bean。

所以其大致流程为:

首先通过getWebServerFactory方法来获取一个ServletWebServerFactory对象,其中Jetty和Tomcat都实现了这个接口。

那么如果返回的是Tomcat的ServerFatory,那么之后的getWebServer方法返回的就是Tomcat这个web服务,反之就是Jetty。在这个方法中,Tomcat和Jetty都会在其中创建自己,然后作为一个对象返回。

那么我们知道SpringBoot默认使用的是Tomcat,那么要做到这样,只要保证我们的依赖中只有Tomcat而没有Jetty和Undertow即可。

所以此时我们引入的web-starter中,其中默认就是帮助我们引入了Tomcat这个依赖,所以,默认使用的就是Tomcat。而我们只需要使用exclude去排除tomcat依赖,并且引入我们需要的服务器,就可以转换服务器的类型。

并且,我们知道默认的Tomca的端口是8080,原因是因为SpringBoot项目中默认把这个端口写死在了Tomcat服务器的父类中。那么如果我们想要修改这个端口,就需要使用Spring提供的后置处理----BeanPostProcess来进行对端口的修改。

最终追述到ServerProperties这个配置类即可。其中有一个port属性,这个属性就会覆盖原有的Tomcat的端口。


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
6天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
11天前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
1天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
9 2
|
7天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
26 4
|
8天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
41 4
|
13天前
|
监控 前端开发 Java
Java SpringBoot –性能分析与调优
Java SpringBoot –性能分析与调优
|
16天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
20天前
|
存储 Java 程序员
Java面试加分点!一文读懂HashMap底层实现与扩容机制
本文详细解析了Java中经典的HashMap数据结构,包括其底层实现、扩容机制、put和查找过程、哈希函数以及JDK 1.7与1.8的差异。通过数组、链表和红黑树的组合,HashMap实现了高效的键值对存储与检索。文章还介绍了HashMap在不同版本中的优化,帮助读者更好地理解和应用这一重要工具。
45 5
|
19天前
|
存储 Java
[Java]面试官:你对异常处理了解多少,例如,finally中可以有return吗?
本文介绍了Java中`try...catch...finally`语句的使用细节及返回值问题,并探讨了JDK1.7引入的`try...with...resources`新特性,强调了异常处理机制及资源自动关闭的优势。
18 1
|
18天前
|
算法 Java
JAVA 二叉树面试题
JAVA 二叉树面试题
14 0