SpringBoot面试题
什么是spring boot,它主要有哪些优点
Springboot是spring的子项目,称为一站式解决方案,集成了外部很多的优秀的框架,如常用的mysql、jdbc。
主要优点:通过maven导入各种jar包,可以减少jar包的冲突;屏息了繁琐的xml配置文件;集成的开发框架,可以做到开箱即用。
为什么要用spring boot?
优点:
快速创建独立运行的Spring应用以及与主流框架集成
1.1. 使用嵌入式的Servlet容器,应用最终可以打成Jar包的形式独立运行。
1.2. 版本仲裁中心和不同的场景启动器(starter)为Spring Boot应用开发管理这不同的框架和版本依赖。
1.3. 约定大于配置,Spring Boot为开发者导入项目所使用的框架设置好了默认配置。
1.4. Java Config代替了原有难以管理的SpringXML配置。
1.5. 提供了准生产环境的运行时的应用监控。
1.6. 与云计算的天然集成,Spring Cloud相关框架技术。
缺点:
从以上优点可知,Spring Boot的最大优点就是为开发者屏蔽了底层框架的复杂性。这样恰好是其缺点。Spring Boot降低了入门门槛,但是其封装使后期学习曲线陡峭。所以如果需要熟练的掌握该框架,必须了解其底层原理。
spring boot跟spring cloud的区别?
SpringBoot只是一个快速开发框架,使用注解简化了xml配置,内置了Servlet容器,以Java应用程序进行执行。
SpringCloud是一系列框架的集合,可以包含SpringBoot。
Spring Boot与Spring MVC的区别
- Spring Boot是Spring和Spring MVC的整合,而Spring MVC只是Spring的一个模块,一个轻量级的Web层框架
- Spring Boot几乎可以实现零配置,所有功能使用注解进行开发,运用了'约定大于配置'的思想,简化了项目开发难度,而Spring MVC需要依赖于xml配置进行开发
- Spring Boot提供了内置的tomcat,可以打成jar包直接运行,也可以使用外置容器
- Spring Boot还集成了许多第三方库配置,例如JDBC, Mongo, Redis等,应用这些第三方库,几乎可以零配置使用
SpringBoot如何修改端口号?
:::: tabs cache-lifetime="5" :options="{ useUrlFragment: false }"
::: tab yml
server:
port: 8888
:::
::: tab properties
server.port = 8888
:::
::: tab 命令行
java -jar demo.jar --server.port=8888
java - Dserver.port=8888 -jar demo.jar
:::
::::
Springboot热部署的方式
SpringBoot 1.3后才拥有SpringBoot devtools热部署
方式一:spring-boot-devtools
在项目的pom文件中添加依赖:
<!--热部署jar-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
然后在Settings→Build→Compiler中将Build project automatically
勾选上,最后使用 shift+ctrl+alt+"/" (IDEA中的快捷键) 选择"Registry
" 然后勾选 compiler.automake.allow.when.app.running
还需要修改配置:
spring:
devtools:
restart:
enabled: true #设置开启热部署
additional-paths: src/main/java #重启目录
exclude: WEB-INF/**
原理
devtools实现原理是使用了两个classloader,一个是base classloader
,用来加载那些不会改变的类(比如第三方jar包等),另一个ClassLoader加载会更改的类,称为restart ClassLoader
,这样在有代码更改的时候,原来的restart ClassLoader会被丢弃,重新创建一个ClassLoader,也就意味着应用程序重新启动通常比“冷启动”快得多,因为base classloader
已经填充好了并且是可用的。
简而言之就是:通过监控类路径资源,当类路径上的文件发生更改时,自动重新启动应用程序,由于只需要重新读取被修改的类,所以要比冷启动快。
方式二:Spring Loaded
在项目中添加如下代码
<build>
<plugins>
<plugin>
<!-- springBoot编译插件-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<!-- spring热部署 -->
<!-- 该依赖在此处下载不下来,可以放置在build标签外部下载完成后再粘贴进plugin中 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.6.RELEASE</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
添加完毕后需要使用mvn指令运行:
首先找到IDEA中的Edit configurations
,然后进行如下操作:(点击左上角的"+",然后选择maven将出现右侧面板,在红色划线部位输入如图所示指令,你可以为该指令命名(此处命名为MvnSpringBootRun
)
点击保存将会在IDEA项目运行部位出现,点击绿色箭头运行即可。
方式三:Jrebel
Jrebel是一款热部署插件。可参考这篇文章来配置:IDEA JRebel 插件热部署(史上最全)
Spring Boot 中如何解决跨域问题 ?
跨域可以在前端通过 JSONP 来解决,但是 JSONP 只可以发送 GET 请求,无法发送其他类型的请求,在 RESTful 风格的应用中,就显得非常鸡肋。
因此我们推荐在后端通过 (CORS,Crossorigin resource sharing) 来解决跨域问题。这种解决方案并非 Spring Boot 特有的,在传统的SSM 框架中,就可以通过 CORS 来解决跨域问题,只不过之前我们是在 XML 文件中配置 CORS ,现在可以通过实现WebMvcConfifigurer
接口然后重写addCorsMappings
方法解决跨域问题。
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
}
也可以在方法或者类上加@CrossOrigin
注解来解决:
@RestController
public class DeliveryController {
@CrossOrigin
@PostMapping("/delivery/addRecord")
public CommonResult<Integer> add(@RequestBody DeliveryRecord deliveryRecord) {
// ...
}
@GetMapping("/delivery/checkRecord")
public CommonResult<DeliveryRecord> checkRecord(@RequestParam Integer deliveryId) {
// ...
}
}
Spring boot的自动配置是如何实现的?
@SpringBootApplication
=@Configuration
+@EnableAutoConfiguration
+@ComponentScan
其实说白了SpringBoot的自动配置,实际是依赖@Conditional来
实现的。
@Conditional
是一个条件注解,是Spring4提供的一个新特性,用于根据特定条件来控制Bean的创建行为。
SpringBoot中对@Conditional的引用链如下:
@SpringBootApplication -> @EnableAutoConfiguration -> @Import(AutoConfigurationImportSelector.class) -> 在AutoConfigurationImportSelector
类中会执行getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes)
方法,里面有一行:
List configurations = SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
这里就会扫描具有MEAT-INF/spring.factories文件的jar包,得到所有的配置类。
而这些配置类上,基本都有以下类型的注解:
@ConditionalOnClass, @ConditionalOnMissingClass
@ConditionalOnBean, @ConditionalOnMissingBean
@ConditionalOnProperty, @ConditionalOnResource
@ConditionalOnEnabledHealthIndicator, ...
如果满足条件,则把对应的配置类装载入spring容器。
总结一下,其实就是 Spring Boot 在启动的时候,按照约定去读取 Spring Boot Starter 的配置信息,再根据配置信息对资源进行初始化,并注入到 Spring 容器中。这样 Spring Boot 启动完毕后,就已经准备好了一切资源,使用过程中直接注入对应 Bean 资源即可。
参考:
@Conditional相关的注解?
@Conditional要配合Condition的实现类(ClassCondition)进行使用。SpringBoot 提供的常用条件注解:
@ConditionalOnBean 组合@Conditional注解,当容器中有指定Bean才开启配置。
@ConditionalOnMissingBean 组合@Conditional注解,当容器中没有值当Bean才可开启配置。
@ConditionalOnClass 组合@Conditional注解,当容器中有指定Class才可开启配置。
@ConditionalOnMissingClass 组合@Conditional注解,当容器中没有指定Class才可开启配置。
@ConditionOnWebApplication 组合@Conditional注解,当前项目类型是WEB项目才可开启配置。项目有以下三种类型:
1. ANY:任意一个Web项目 1. SERVLET: Servlet的Web项目 1. REACTIVE :基于reactive-base的Web项目
@ConditionOnNotWebApplication 组合@Conditional注解,当前项目类型不是WEB项目才可开启配置。
@ConditionalOnProperty 组合@Conditional注解,当指定的属性有指定的值时才可开启配置。
@ConditionalOnExpression 组合@Conditional注解,当SpEl表达式为true时才可开启配置。
@ConditionOnJava 组合@Conditional注解,当运行的Java JVM在指定的版本范围时才开启配置。
@ConditionalResource 组合@Conditional注解,当类路径下有指定的资源才开启配置。
@ConditionOnJndi 组合@Conditional注解,当指定的JNDI存在时才开启配置。
@ConditionalOnCloudPlatform 组合@Conditional注解,当指定的云平台激活时才可开启配置。
@ConditiomalOnSingleCandidate 组合@Conditional注解,当制定的Class在容器中只有一个Bean,或者同时有多个但为首选时才开启配置。
SpringBoot 中怎么禁用某些自动配置特性?
有 3 种方法。如果我们想禁用某些自动配置特性,可以使用 @EnableAutoConfiguration
或 @SpringBootApplication
注解的 exclude
属性来指明。
// 方案1,下面的代码段是使 DataSourceAutoConfiguration 无效:
@EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class)
public class MyConfiguration {}
// 方案2
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class MyConfiguration { }
// 方案3,在配置文件中配置
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
SpringBoot的加载流程?
https://www.jianshu.com/p/dc12081b3598
SpringBoot运行原理
1) 如果我们使用的是SpringApplication的静态run方法,那么,这个方法里面首先要创建一个SpringApplication对象实例,然后调用这个创建好的SpringApplication的实例方法。在SpringApplication实例初始化的时候,它会提前做几件事情:
- 根据classpath里面是否存在某个特征类(org.springframework.web.context.ConfigurableWebApplicationContext)来决定是否应该创建一个为Web应用使用的ApplicationContext类型。
- 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer。
- 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener。
- 推断并设置main方法的定义类。
2) SpringApplication实例初始化完成并且完成设置后,就开始执行run方法的逻辑了,方法执行伊始,首先遍历执行所有通过SpringFactoriesLoader可以查找到并加载的SpringApplicationRunListener。调用它们的started()方法,告诉这些SpringApplicationRunListener,“嘿,SpringBoot应用要开始执行咯!”。
3) 创建并配置当前Spring Boot应用将要使用的Environment(包括配置要使用的PropertySource以及Profile)。
4) 遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法,告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”。
5) 如果SpringApplication的showBanner属性被设置为true,则打印banner。
6) 根据用户是否明确设置了applicationContextClass类型以及初始化阶段的推断结果,决定该为当前SpringBoot应用创建什么类型的ApplicationContext并创建完成,然后根据条件决定是否添加ShutdownHook,决定是否使用自定义的BeanNameGenerator,决定是否使用自定义的ResourceLoader,当然,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使用。
7) ApplicationContext创建好之后,SpringApplication会再次借助Spring-FactoriesLoader,查找并加载classpath中所有可用的ApplicationContext-Initializer,然后遍历调用这些ApplicationContextInitializer的initialize(applicationContext)方法来对已经创建好的ApplicationContext进行进一步的处理。
8) 遍历调用所有SpringApplicationRunListener的contextPrepared()方法。
9) 最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。
10) 遍历调用所有SpringApplicationRunListener的contextLoaded()方法。
11) 调用ApplicationContext的refresh()方法,完成IoC容器可用的最后一道工序。
12) 查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。
13) 正常情况下,遍历执行SpringApplicationRunListener的finished()方法、(如果整个过程出现异常,则依然调用所有SpringApplicationRunListener的finished()方法,只不过这种情况下会将异常信息一并传入处理。
Spring boot容器替换?
<!-- 下面的配置将使用undertow来做服务器而不是tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
在spring-boot-starter-web中,使用<exclusion>
排除掉web中引入的tomcat,使用<dependency>
重新导入undertow 即可。也可以用同样的方法,把容器替换为Jetty。
Spring boot集成Mybatis?
加入依赖即可。这个starter是mybatis提供的。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
SpringBoot读取配置相关注解有?
- @PropertySource
- @Value
- @Environment
- @ConfigurationProperties
Starters是什么?
Starters可以理解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成Spring及其他技术,而不需要到处找示例代码和依赖包。如你想使用Spring JPA
访问数据库,只要加入spring-boot-starter-data-jpa
启动器依赖就能使用了。
Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。
Starters命名
Spring Boot官方的启动器都是以spring-boot-starter-
开头命名的,代表了一个特定的应用类型。
第三方的启动器不能以spring-boot开头命名,它们都被Spring Boot官方保留。一般一个第三方的应该这样命名,像mybatis的mybatis-spring-boot-starter
。
spring boot的starter的执行原理
利用starter实现自动化配置只需要两个条件――maven依赖、配置文件,这里简单介绍下starter实现自动化配置的流程。
引入maven实质上就是导入jar包,spring-boot启动的时候会找到starter jar包中的resources/META-INF/spring.factories文件,根据spring.factories文件中的配置,找到需要自动配置的类。
Spring Boot自己实现starter?
Spring-boot-starter-parent 有什么用 ?
我们都知道,新创建一个 Spring Boot 项目,默认都是有 parent 的,这个 parent 就是 spring-boot-starter-parent ,spring-boot-starter-parent 主要有如下作用:
定义了 Java 编译版本为 1.8 。
使用 UTF-8 格式编码。
继承自spring-boot-dependencies,这个里边定义了依赖的版本,也正是因为继承了这个依赖,所以我们在写依赖时才不需要写版本号。
执行打包操作的配置。
自动化的资源过滤。
自动化的插件配置。
针对 application.properties 和 application.yml 的资源过滤,包括通过 profile
定义的不同环境的配置文件,例如 application-dev.properties 和 application-dev.yml。
Spring Boot 打成的 jar 和普通的 jar 有什么区别 ?
Spring Boot 项目最终打包成的 jar 是可执行 jar ,这种 jar 可以直接通过 java -jar xxx.jar 命令来运行,这种 jar 不可以作为普通的 jar 被其他项目依赖,即使依赖了也无法使用其中的类。
Spring Boot 的 jar 无法被其他项目依赖,主要还是他和普通 jar 的结构不同。普通的 jar 包,解压后直接就是包名,包里就是我们的代码,而 Spring Boot 打包成的可执行 jar 解压后,在 \BOOT-INF\classes 目录下才是我们的代码,因此无法被直接引用。如果非要引用,可以在 pom.xml 文件中增加配置,将 Spring Boot 项目打包成两个 jar ,一个可执行,一个可引用。
如何在 Spring Boot 启动的时候运行一些特定的代码?
可以实现接口 ApplicationRunner 或者 CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个 run 方法。如下所示:
public interface CommandLineRunner {
/**
* Callback used to run the bean.
* @param args incoming main method arguments
* @throws Exception on error
*/
void run(String... args) throws Exception;
}
//---
public interface ApplicationRunner {
/**
* Callback used to run the bean.
* @param args incoming application arguments
* @throws Exception on error
*/
void run(ApplicationArguments args) throws Exception;
}
使用方式
import org.springframework.boot.*
import org.springframework.stereotype.*
@Component
public class MyBean implements CommandLineRunner {
public void run(String... args) {
// Do something...
}
}
// 或者
@Bean
public CommandLineRunner init() {
return (String... strings) -> {
};
}
启动顺序
如果启动的时候有多个ApplicationRunner和CommandLineRunner,想控制它们的启动顺序,可以实现 org.springframework.core.Ordered
接口或者使用 org.springframework.core.annotation.Order
注解。
- 0很棒
- 0不错
- 0一般
- 0???