本文介绍了剖析面试最常见问题之 Spring Boot求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。
对技术面试,学习经验等有一些体会,在此分享。
- 剖析面试最常见问题之 Spring Boot
-
- 1. 简单介绍一下 Spring?有啥缺点?
- 2. 为什么要有 SpringBoot?
- 3. 说出使用 Spring Boot 的主要优点
- 4. 什么是 Spring Boot Starters?
- 5. Spring Boot 支持哪些内嵌 Servlet 容器?
- 6. 如何在 Spring Boot 应用程序中使用 Jetty 而不是 Tomcat?
- 7. 介绍一下@SpringBootApplication 注解
- 8. Spring Boot 的自动配置是如何实现的?
- 9. 开发 RESTful Web 服务常用的注解有哪些?
- 10. Spirng Boot 常用的两种配置文件
- 11. 什么是 YAML?YAML 配置的优势在哪里 ?
- 12. Spring Boot 常用的读取配置文件的方法有哪些?
- 12.1. 通过 @value 读取比较简单的配置信息
- 12.2. 通过@ConfigurationProperties读取并与 bean 绑定
-
剖析面试最常见问题之 Spring Boot
市面上关于 Spring Boot 的面试题抄来抄去,毫无价值可言。
这篇文章,我会简单就自己这几年使用 Spring Boot 的一些经验,总结一些常见的面试题供小伙伴们自测和学习。少部分关于 Spring/Spring Boot 的介绍参考了官网,其他皆为原创。
1. 简单介绍一下 Spring?有啥缺点?
Spring 是重量级企业开发框架 Enterprise JavaBean(EJB) 的替代品,Spring 为企业级 Java 开发提供了一种相对简单的方法,通过 依赖注入 和 面向切面编程 ,用简单的 Java 对象(Plain Old Java Object,POJO) 实现了 EJB 的功能
虽然 Spring 的组件代码是轻量级的,但它的配置却是重量级的(需要大量 XML 配置) 。
为此,Spring 2.5 引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式 XML 配置。Spring 3.0 引入了基于 Java 的配置,这是一种类型安全的可重构配置方式,可以代替 XML。
尽管如此,我们依旧没能逃脱配置的魔爪。开启某些 Spring 特性时,比如事务管理和 Spring MVC,还是需要用 XML 或 Java 进行显式配置。启用第三方库时也需要显式配置,比如基于 Thymeleaf 的 Web 视图。配置 Servlet 和过滤器(比如 Spring 的DispatcherServlet
)同样需要在 web.xml 或 Servlet 初始化代码里进行显式配置。组件扫描减少了配置量,Java 配置让它看上去简洁不少,但 Spring 还是需要不少配置。
光配置这些 XML 文件都够我们头疼的了,占用了我们大部分时间和精力。除此之外,相关库的依赖非常让人头疼,不同库之间的版本冲突也非常常见。
2. 为什么要有 SpringBoot?
Spring 旨在简化 J2EE 企业应用程序开发。Spring Boot F 旨在简化 Spring 开发(减少配置文件,开箱即用!)。
3. 说出使用 Spring Boot 的主要优点
- 开发基于 Spring 的应用程序很容易。
- Spring Boot 项目所需的开发或工程时间明显减少,通常会提高整体生产力。
- Spring Boot 不需要编写大量样板代码、XML 配置和注释。
- Spring 引导应用程序可以很容易地与 Spring 生态系统集成,如 Spring JDBC、Spring ORM、Spring Data、Spring Security 等。
- Spring Boot 遵循“固执己见的默认配置”,以减少开发工作(默认配置可以修改)。
- Spring Boot 应用程序提供嵌入式 HTTP 服务器,如 Tomcat 和 Jetty,可以轻松地开发和测试 web 应用程序。(这点很赞!普通运行 Java 程序的方式就能运行基于 Spring Boot web 项目,省事很多)
- Spring Boot 提供命令行接口(CLI)工具,用于开发和测试 Spring Boot 应用程序,如 Java 或 Groovy。
- Spring Boot 提供了多种插件,可以使用内置工具(如 Maven 和 Gradle)开发和测试 Spring Boot 应用程序。
4. 什么是 Spring Boot Starters?
Spring Boot Starters 是一系列依赖关系的集合,因为它的存在,项目的依赖之间的关系对我们来说变的更加简单了。
举个例子:在没有 Spring Boot Starters 之前,我们开发 REST 服务或 Web 应用程序时; 我们需要使用像 Spring MVC,Tomcat 和 Jackson 这样的库,这些依赖我们需要手动一个一个添加。但是,有了 Spring Boot Starters 我们只需要一个只需添加一个spring-boot-starter-web一个依赖就可以了,这个依赖包含的字依赖中包含了我们开发 REST 服务需要的所有依赖。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
5. Spring Boot 支持哪些内嵌 Servlet 容器?
Spring Boot 支持以下嵌入式 Servlet 容器:
Name | Servlet Version |
---|---|
Tomcat 9.0 | 4.0 |
Jetty 9.4 | 3.1 |
Undertow 2.0 | 4.0 |
您还可以将 Spring 引导应用程序部署到任何 Servlet 3.1+兼容的 Web 容器中。
这就是你为什么可以通过直接像运行 普通 Java 项目一样运行 SpringBoot 项目。这样的确省事了很多,方便了我们进行开发,降低了学习难度。
6. 如何在 Spring Boot 应用程序中使用 Jetty 而不是 Tomcat?
Spring Boot (spring-boot-starter-web
)使用 Tomcat 作为默认的嵌入式 servlet 容器, 如果你想使用 Jetty 的话只需要修改pom.xml
(Maven)或者build.gradle
(Gradle)就可以了。
Maven:
<!--从Web启动器依赖中排除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> <!--添加Jetty依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
Gradle:
compile("org.springframework.boot:spring-boot-starter-web") { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' } compile("org.springframework.boot:spring-boot-starter-jetty")
说个题外话,从上面可以看出使用 Gradle 更加简洁明了,但是国内目前还是 Maven 使用的多一点,我个人觉得 Gradle 在很多方面都要好很多。
7. 介绍一下@SpringBootApplication 注解
package org.springframework.boot.autoconfigure; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { ...... }
package org.springframework.boot; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { }
可以看出大概可以把 @SpringBootApplication
看作是 @Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:
@EnableAutoConfiguration
:启用 SpringBoot 的自动配置机制@ComponentScan
: 扫描被@Component
(@Service
,@Controller
)注解的 bean,注解默认会扫描该类所在的包下所有的类。@Configuration
:允许在上下文中注册额外的 bean 或导入其他配置类
8. Spring Boot 的自动配置是如何实现的?
这个是因为@SpringBootApplication
注解的原因,在上一个问题中已经提到了这个注解。我们知道 @SpringBootApplication
看作是 @Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合。
@EnableAutoConfiguration
:启用 SpringBoot 的自动配置机制@ComponentScan
: 扫描被@Component
(@Service
,@Controller
)注解的 bean,注解默认会扫描该类所在的包下所有的类。@Configuration
:允许在上下文中注册额外的 bean 或导入其他配置类
@EnableAutoConfiguration
是启动自动配置的关键,源码如下(建议自己打断点调试,走一遍基本的流程):
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Import; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
@EnableAutoConfiguration
注解通过 Spring 提供的 @Import
注解导入了AutoConfigurationImportSelector
类(@Import
注解可以导入配置类或者 Bean 到当前类中)。
AutoConfigurationImportSelector
类中getCandidateConfigurations
方法会将所有自动配置类的信息以 List 的形式返回。这些配置信息会被 Spring 容器作 bean 来管理。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
自动配置信息有了,那么自动配置还差什么呢?
@Conditional
注解。@ConditionalOnClass
(指定的类必须存在于类路径下),@ConditionalOnBean
(容器中是否有指定的 Bean)等等都是对@Conditional
注解的扩展。
拿 Spring Security 的自动配置举个例子:SecurityAutoConfiguration
中导入了WebSecurityEnablerConfiguration
类,WebSecurityEnablerConfiguration
源代码如下:
@Configuration @ConditionalOnBean(WebSecurityConfigurerAdapter.class) @ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @EnableWebSecurity public class WebSecurityEnablerConfiguration { }
WebSecurityEnablerConfiguration
类中使用@ConditionalOnBean
指定了容器中必须还有WebSecurityConfigurerAdapter
类或其实现类。所以,一般情况下 Spring Security 配置类都会去实现 WebSecurityConfigurerAdapter
,这样自动将配置就完成了。
9. 开发 RESTful Web 服务常用的注解有哪些?
Spring Bean 相关:
@Autowired
: 自动导入对象到类中,被注入进的类同样要被 Spring 容器管理。@RestController
:@RestController
注解是@Controller和
@ResponseBody
的合集,表示这是个控制器 bean,并且是将函数的返回值直 接填入 HTTP 响应体中,是 REST 风格的控制器。@Component
:通用的注解,可标注任意类为Spring
组件。如果一个 Bean 不知道属于哪个层,可以使用@Component
注解标注。@Repository
: 对应持久层即 Dao 层,主要用于数据库相关操作。@Service
: 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。@Controller
: 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。
处理常见的 HTTP 请求类型:
@GetMapping
: GET 请求、@PostMapping
: POST 请求。@PutMapping
: PUT 请求。@DeleteMapping
: DELETE 请求。
前后端传值:
@RequestParam
以及@Pathvairable :@PathVariable用于获取路径参数,@RequestParam用于获取查询参数。
@RequestBody
:用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且 Content-Type 为application/json
格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去。系统会使用HttpMessageConverter
或者自定义的HttpMessageConverter
将请求的 body 中的 json 字符串转换为 java 对象。
详细介绍可以查看这篇文章:《Spring/Spring Boot 常用注解总结》 。
10. Spirng Boot 常用的两种配置文件
我们可以通过 application.properties
或者 application.yml
对 Spring Boot 程序进行简单的配置。如果,你不进行配置的话,就是使用的默认配置。
11. 什么是 YAML?YAML 配置的优势在哪里 ?
YAML 是一种人类可读的数据序列化语言。它通常用于配置文件。与属性文件相比,如果我们想要在配置文件中添加复杂的属性,YAML 文件就更加结构化,而且更少混淆。可以看出 YAML 具有分层配置数据。
相比于 Properties 配置的方式,YAML 配置的方式更加直观清晰,简介明了,有层次感。
但是,YAML 配置的方式有一个缺点,那就是不支持 @PropertySource
注解导入自定义的 YAML 配置。
12. Spring Boot 常用的读取配置文件的方法有哪些?
我们要读取的配置文件application.yml
内容如下:
wuhan2020: 2020年初武汉爆发了新型冠状病毒,疫情严重,但是,我相信一切都会过去!武汉加油!中国加油! my-profile: name: Guide哥 email: koushuangbwcx@163.com library: location: 湖北武汉加油中国加油 books: - name: 天才基本法 description: 二十二岁的林朝夕在父亲确诊阿尔茨海默病这天,得知自己暗恋多年的校园男神裴之即将出国深造的消息——对方考取的学校,恰是父亲当年为她放弃的那所。 - name: 时间的秩序 description: 为什么我们记得过去,而非未来?时间“流逝”意味着什么?是我们存在于时间之内,还是时间存在于我们之中?卡洛·罗韦利用诗意的文字,邀请我们思考这一亘古难题——时间的本质。 - name: 了不起的我 description: 如何养成一个新习惯?如何让心智变得更成熟?如何拥有高质量的关系? 如何走出人生的艰难时刻?
12.1. 通过 @value
读取比较简单的配置信息
使用 @Value("${property}")
读取比较简单的配置信息:
@Value("${wuhan2020}") String wuhan2020;
需要注意的是
@value
这种方式是不被推荐的,Spring 比较建议的是下面几种读取配置信息的方式。
12.2. 通过@ConfigurationProperties
读取并与 bean 绑定
LibraryProperties
类上加了@Component
注解,我们可以像使用普通 bean 一样将其注入到类中使用。
import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; import java.util.List; @Component @ConfigurationProperties(prefix = "library") @Setter @Getter @ToString class LibraryProperties { private String location; private List<Book> books; @Setter @Getter @ToString static class Book { String name; String description; } }
这个时候你就可以像使用普通 bean 一样,将其注入到类中使用:
“`java
package cn.javaguide.readconfigproperties;
import org.springframework.beans.factory.InitializingBean;
- 剖析面试最常见问题之 Spring Boot
-
- 1. 简单介绍一下 Spring?有啥缺点?
- 2. 为什么要有 SpringBoot?
- 3. 说出使用 Spring Boot 的主要优点
- 4. 什么是 Spring Boot Starters?
- 5. Spring Boot 支持哪些内嵌 Servlet 容器?
- 6. 如何在 Spring Boot 应用程序中使用 Jetty 而不是 Tomcat?
- 7. 介绍一下@SpringBootApplication 注解
- 8. Spring Boot 的自动配置是如何实现的?
- 9. 开发 RESTful Web 服务常用的注解有哪些?
- 10. Spirng Boot 常用的两种配置文件
- 11. 什么是 YAML?YAML 配置的优势在哪里 ?
- 12. Spring Boot 常用的读取配置文件的方法有哪些?
- 12.1. 通过 @value 读取比较简单的配置信息
- 12.2. 通过@ConfigurationProperties读取并与 bean 绑定
-
剖析面试最常见问题之 Spring Boot
市面上关于 Spring Boot 的面试题抄来抄去,毫无价值可言。
这篇文章,我会简单就自己这几年使用 Spring Boot 的一些经验,总结一些常见的面试题供小伙伴们自测和学习。少部分关于 Spring/Spring Boot 的介绍参考了官网,其他皆为原创。
1. 简单介绍一下 Spring?有啥缺点?
Spring 是重量级企业开发框架 Enterprise JavaBean(EJB) 的替代品,Spring 为企业级 Java 开发提供了一种相对简单的方法,通过 依赖注入 和 面向切面编程 ,用简单的 Java 对象(Plain Old Java Object,POJO) 实现了 EJB 的功能
虽然 Spring 的组件代码是轻量级的,但它的配置却是重量级的(需要大量 XML 配置) 。
为此,Spring 2.5 引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式 XML 配置。Spring 3.0 引入了基于 Java 的配置,这是一种类型安全的可重构配置方式,可以代替 XML。
尽管如此,我们依旧没能逃脱配置的魔爪。开启某些 Spring 特性时,比如事务管理和 Spring MVC,还是需要用 XML 或 Java 进行显式配置。启用第三方库时也需要显式配置,比如基于 Thymeleaf 的 Web 视图。配置 Servlet 和过滤器(比如 Spring 的DispatcherServlet
)同样需要在 web.xml 或 Servlet 初始化代码里进行显式配置。组件扫描减少了配置量,Java 配置让它看上去简洁不少,但 Spring 还是需要不少配置。
光配置这些 XML 文件都够我们头疼的了,占用了我们大部分时间和精力。除此之外,相关库的依赖非常让人头疼,不同库之间的版本冲突也非常常见。
2. 为什么要有 SpringBoot?
Spring 旨在简化 J2EE 企业应用程序开发。Spring Boot F 旨在简化 Spring 开发(减少配置文件,开箱即用!)。
3. 说出使用 Spring Boot 的主要优点
- 开发基于 Spring 的应用程序很容易。
- Spring Boot 项目所需的开发或工程时间明显减少,通常会提高整体生产力。
- Spring Boot 不需要编写大量样板代码、XML 配置和注释。
- Spring 引导应用程序可以很容易地与 Spring 生态系统集成,如 Spring JDBC、Spring ORM、Spring Data、Spring Security 等。
- Spring Boot 遵循“固执己见的默认配置”,以减少开发工作(默认配置可以修改)。
- Spring Boot 应用程序提供嵌入式 HTTP 服务器,如 Tomcat 和 Jetty,可以轻松地开发和测试 web 应用程序。(这点很赞!普通运行 Java 程序的方式就能运行基于 Spring Boot web 项目,省事很多)
- Spring Boot 提供命令行接口(CLI)工具,用于开发和测试 Spring Boot 应用程序,如 Java 或 Groovy。
- Spring Boot 提供了多种插件,可以使用内置工具(如 Maven 和 Gradle)开发和测试 Spring Boot 应用程序。
4. 什么是 Spring Boot Starters?
Spring Boot Starters 是一系列依赖关系的集合,因为它的存在,项目的依赖之间的关系对我们来说变的更加简单了。
举个例子:在没有 Spring Boot Starters 之前,我们开发 REST 服务或 Web 应用程序时; 我们需要使用像 Spring MVC,Tomcat 和 Jackson 这样的库,这些依赖我们需要手动一个一个添加。但是,有了 Spring Boot Starters 我们只需要一个只需添加一个spring-boot-starter-web一个依赖就可以了,这个依赖包含的字依赖中包含了我们开发 REST 服务需要的所有依赖。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
5. Spring Boot 支持哪些内嵌 Servlet 容器?
Spring Boot 支持以下嵌入式 Servlet 容器:
Name | Servlet Version |
---|---|
Tomcat 9.0 | 4.0 |
Jetty 9.4 | 3.1 |
Undertow 2.0 | 4.0 |
您还可以将 Spring 引导应用程序部署到任何 Servlet 3.1+兼容的 Web 容器中。
这就是你为什么可以通过直接像运行 普通 Java 项目一样运行 SpringBoot 项目。这样的确省事了很多,方便了我们进行开发,降低了学习难度。
6. 如何在 Spring Boot 应用程序中使用 Jetty 而不是 Tomcat?
Spring Boot (spring-boot-starter-web
)使用 Tomcat 作为默认的嵌入式 servlet 容器, 如果你想使用 Jetty 的话只需要修改pom.xml
(Maven)或者build.gradle
(Gradle)就可以了。
Maven:
<!--从Web启动器依赖中排除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> <!--添加Jetty依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
Gradle:
compile("org.springframework.boot:spring-boot-starter-web") { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' } compile("org.springframework.boot:spring-boot-starter-jetty")
说个题外话,从上面可以看出使用 Gradle 更加简洁明了,但是国内目前还是 Maven 使用的多一点,我个人觉得 Gradle 在很多方面都要好很多。
7. 介绍一下@SpringBootApplication 注解
package org.springframework.boot.autoconfigure; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { ...... }
package org.springframework.boot; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { }
可以看出大概可以把 @SpringBootApplication
看作是 @Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:
@EnableAutoConfiguration
:启用 SpringBoot 的自动配置机制@ComponentScan
: 扫描被@Component
(@Service
,@Controller
)注解的 bean,注解默认会扫描该类所在的包下所有的类。@Configuration
:允许在上下文中注册额外的 bean 或导入其他配置类
8. Spring Boot 的自动配置是如何实现的?
这个是因为@SpringBootApplication
注解的原因,在上一个问题中已经提到了这个注解。我们知道 @SpringBootApplication
看作是 @Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合。
@EnableAutoConfiguration
:启用 SpringBoot 的自动配置机制@ComponentScan
: 扫描被@Component
(@Service
,@Controller
)注解的 bean,注解默认会扫描该类所在的包下所有的类。@Configuration
:允许在上下文中注册额外的 bean 或导入其他配置类
@EnableAutoConfiguration
是启动自动配置的关键,源码如下(建议自己打断点调试,走一遍基本的流程):
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Import; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
@EnableAutoConfiguration
注解通过 Spring 提供的 @Import
注解导入了AutoConfigurationImportSelector
类(@Import
注解可以导入配置类或者 Bean 到当前类中)。
AutoConfigurationImportSelector
类中getCandidateConfigurations
方法会将所有自动配置类的信息以 List 的形式返回。这些配置信息会被 Spring 容器作 bean 来管理。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
自动配置信息有了,那么自动配置还差什么呢?
@Conditional
注解。@ConditionalOnClass
(指定的类必须存在于类路径下),@ConditionalOnBean
(容器中是否有指定的 Bean)等等都是对@Conditional
注解的扩展。
拿 Spring Security 的自动配置举个例子:SecurityAutoConfiguration
中导入了WebSecurityEnablerConfiguration
类,WebSecurityEnablerConfiguration
源代码如下:
@Configuration @ConditionalOnBean(WebSecurityConfigurerAdapter.class) @ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @EnableWebSecurity public class WebSecurityEnablerConfiguration { }
WebSecurityEnablerConfiguration
类中使用@ConditionalOnBean
指定了容器中必须还有WebSecurityConfigurerAdapter
类或其实现类。所以,一般情况下 Spring Security 配置类都会去实现 WebSecurityConfigurerAdapter
,这样自动将配置就完成了。
9. 开发 RESTful Web 服务常用的注解有哪些?
Spring Bean 相关:
@Autowired
: 自动导入对象到类中,被注入进的类同样要被 Spring 容器管理。@RestController
:@RestController
注解是@Controller和
@ResponseBody
的合集,表示这是个控制器 bean,并且是将函数的返回值直 接填入 HTTP 响应体中,是 REST 风格的控制器。@Component
:通用的注解,可标注任意类为Spring
组件。如果一个 Bean 不知道属于哪个层,可以使用@Component
注解标注。@Repository
: 对应持久层即 Dao 层,主要用于数据库相关操作。@Service
: 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。@Controller
: 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。
处理常见的 HTTP 请求类型:
@GetMapping
: GET 请求、@PostMapping
: POST 请求。@PutMapping
: PUT 请求。@DeleteMapping
: DELETE 请求。
前后端传值:
@RequestParam
以及@Pathvairable :@PathVariable用于获取路径参数,@RequestParam用于获取查询参数。
@RequestBody
:用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且 Content-Type 为application/json
格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去。系统会使用HttpMessageConverter
或者自定义的HttpMessageConverter
将请求的 body 中的 json 字符串转换为 java 对象。
详细介绍可以查看这篇文章:《Spring/Spring Boot 常用注解总结》 。
10. Spirng Boot 常用的两种配置文件
我们可以通过 application.properties
或者 application.yml
对 Spring Boot 程序进行简单的配置。如果,你不进行配置的话,就是使用的默认配置。
11. 什么是 YAML?YAML 配置的优势在哪里 ?
YAML 是一种人类可读的数据序列化语言。它通常用于配置文件。与属性文件相比,如果我们想要在配置文件中添加复杂的属性,YAML 文件就更加结构化,而且更少混淆。可以看出 YAML 具有分层配置数据。
相比于 Properties 配置的方式,YAML 配置的方式更加直观清晰,简介明了,有层次感。
但是,YAML 配置的方式有一个缺点,那就是不支持 @PropertySource
注解导入自定义的 YAML 配置。
12. Spring Boot 常用的读取配置文件的方法有哪些?
我们要读取的配置文件application.yml
内容如下:
wuhan2020: 2020年初武汉爆发了新型冠状病毒,疫情严重,但是,我相信一切都会过去!武汉加油!中国加油! my-profile: name: Guide哥 email: koushuangbwcx@163.com library: location: 湖北武汉加油中国加油 books: - name: 天才基本法 description: 二十二岁的林朝夕在父亲确诊阿尔茨海默病这天,得知自己暗恋多年的校园男神裴之即将出国深造的消息——对方考取的学校,恰是父亲当年为她放弃的那所。 - name: 时间的秩序 description: 为什么我们记得过去,而非未来?时间“流逝”意味着什么?是我们存在于时间之内,还是时间存在于我们之中?卡洛·罗韦利用诗意的文字,邀请我们思考这一亘古难题——时间的本质。 - name: 了不起的我 description: 如何养成一个新习惯?如何让心智变得更成熟?如何拥有高质量的关系? 如何走出人生的艰难时刻?
12.1. 通过 @value
读取比较简单的配置信息
使用 @Value("${property}")
读取比较简单的配置信息:
@Value("${wuhan2020}") String wuhan2020;
需要注意的是
@value
这种方式是不被推荐的,Spring 比较建议的是下面几种读取配置信息的方式。
12.2. 通过@ConfigurationProperties
读取并与 bean 绑定
LibraryProperties
类上加了@Component
注解,我们可以像使用普通 bean 一样将其注入到类中使用。
import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; import java.util.List; @Component @ConfigurationProperties(prefix = "library") @Setter @Getter @ToString class LibraryProperties { private String location; private List<Book> books; @Setter @Getter @ToString static class Book { String name; String description; } }
这个时候你就可以像使用普通 bean 一样,将其注入到类中使用:
“`java
package cn.javaguide.readconfigproperties;
import org.springframework.beans.factory.InitializingBean;
- 剖析面试最常见问题之 Spring Boot
-
- 1. 简单介绍一下 Spring?有啥缺点?
- 2. 为什么要有 SpringBoot?
- 3. 说出使用 Spring Boot 的主要优点
- 4. 什么是 Spring Boot Starters?
- 5. Spring Boot 支持哪些内嵌 Servlet 容器?
- 6. 如何在 Spring Boot 应用程序中使用 Jetty 而不是 Tomcat?
- 7. 介绍一下@SpringBootApplication 注解
- 8. Spring Boot 的自动配置是如何实现的?
- 9. 开发 RESTful Web 服务常用的注解有哪些?
- 10. Spirng Boot 常用的两种配置文件
- 11. 什么是 YAML?YAML 配置的优势在哪里 ?
- 12. Spring Boot 常用的读取配置文件的方法有哪些?
- 12.1. 通过 @value 读取比较简单的配置信息
- 12.2. 通过@ConfigurationProperties读取并与 bean 绑定
-
剖析面试最常见问题之 Spring Boot
市面上关于 Spring Boot 的面试题抄来抄去,毫无价值可言。
这篇文章,我会简单就自己这几年使用 Spring Boot 的一些经验,总结一些常见的面试题供小伙伴们自测和学习。少部分关于 Spring/Spring Boot 的介绍参考了官网,其他皆为原创。
1. 简单介绍一下 Spring?有啥缺点?
Spring 是重量级企业开发框架 Enterprise JavaBean(EJB) 的替代品,Spring 为企业级 Java 开发提供了一种相对简单的方法,通过 依赖注入 和 面向切面编程 ,用简单的 Java 对象(Plain Old Java Object,POJO) 实现了 EJB 的功能
虽然 Spring 的组件代码是轻量级的,但它的配置却是重量级的(需要大量 XML 配置) 。
为此,Spring 2.5 引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式 XML 配置。Spring 3.0 引入了基于 Java 的配置,这是一种类型安全的可重构配置方式,可以代替 XML。
尽管如此,我们依旧没能逃脱配置的魔爪。开启某些 Spring 特性时,比如事务管理和 Spring MVC,还是需要用 XML 或 Java 进行显式配置。启用第三方库时也需要显式配置,比如基于 Thymeleaf 的 Web 视图。配置 Servlet 和过滤器(比如 Spring 的DispatcherServlet
)同样需要在 web.xml 或 Servlet 初始化代码里进行显式配置。组件扫描减少了配置量,Java 配置让它看上去简洁不少,但 Spring 还是需要不少配置。
光配置这些 XML 文件都够我们头疼的了,占用了我们大部分时间和精力。除此之外,相关库的依赖非常让人头疼,不同库之间的版本冲突也非常常见。
2. 为什么要有 SpringBoot?
Spring 旨在简化 J2EE 企业应用程序开发。Spring Boot F 旨在简化 Spring 开发(减少配置文件,开箱即用!)。
3. 说出使用 Spring Boot 的主要优点
- 开发基于 Spring 的应用程序很容易。
- Spring Boot 项目所需的开发或工程时间明显减少,通常会提高整体生产力。
- Spring Boot 不需要编写大量样板代码、XML 配置和注释。
- Spring 引导应用程序可以很容易地与 Spring 生态系统集成,如 Spring JDBC、Spring ORM、Spring Data、Spring Security 等。
- Spring Boot 遵循“固执己见的默认配置”,以减少开发工作(默认配置可以修改)。
- Spring Boot 应用程序提供嵌入式 HTTP 服务器,如 Tomcat 和 Jetty,可以轻松地开发和测试 web 应用程序。(这点很赞!普通运行 Java 程序的方式就能运行基于 Spring Boot web 项目,省事很多)
- Spring Boot 提供命令行接口(CLI)工具,用于开发和测试 Spring Boot 应用程序,如 Java 或 Groovy。
- Spring Boot 提供了多种插件,可以使用内置工具(如 Maven 和 Gradle)开发和测试 Spring Boot 应用程序。
4. 什么是 Spring Boot Starters?
Spring Boot Starters 是一系列依赖关系的集合,因为它的存在,项目的依赖之间的关系对我们来说变的更加简单了。
举个例子:在没有 Spring Boot Starters 之前,我们开发 REST 服务或 Web 应用程序时; 我们需要使用像 Spring MVC,Tomcat 和 Jackson 这样的库,这些依赖我们需要手动一个一个添加。但是,有了 Spring Boot Starters 我们只需要一个只需添加一个spring-boot-starter-web一个依赖就可以了,这个依赖包含的字依赖中包含了我们开发 REST 服务需要的所有依赖。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
5. Spring Boot 支持哪些内嵌 Servlet 容器?
Spring Boot 支持以下嵌入式 Servlet 容器:
Name | Servlet Version |
---|---|
Tomcat 9.0 | 4.0 |
Jetty 9.4 | 3.1 |
Undertow 2.0 | 4.0 |
您还可以将 Spring 引导应用程序部署到任何 Servlet 3.1+兼容的 Web 容器中。
这就是你为什么可以通过直接像运行 普通 Java 项目一样运行 SpringBoot 项目。这样的确省事了很多,方便了我们进行开发,降低了学习难度。
6. 如何在 Spring Boot 应用程序中使用 Jetty 而不是 Tomcat?
Spring Boot (spring-boot-starter-web
)使用 Tomcat 作为默认的嵌入式 servlet 容器, 如果你想使用 Jetty 的话只需要修改pom.xml
(Maven)或者build.gradle
(Gradle)就可以了。
Maven:
<!--从Web启动器依赖中排除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> <!--添加Jetty依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
Gradle:
compile("org.springframework.boot:spring-boot-starter-web") { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' } compile("org.springframework.boot:spring-boot-starter-jetty")
说个题外话,从上面可以看出使用 Gradle 更加简洁明了,但是国内目前还是 Maven 使用的多一点,我个人觉得 Gradle 在很多方面都要好很多。
7. 介绍一下@SpringBootApplication 注解
package org.springframework.boot.autoconfigure; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) public @interface SpringBootApplication { ...... }
package org.springframework.boot; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { }
可以看出大概可以把 @SpringBootApplication
看作是 @Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:
@EnableAutoConfiguration
:启用 SpringBoot 的自动配置机制@ComponentScan
: 扫描被@Component
(@Service
,@Controller
)注解的 bean,注解默认会扫描该类所在的包下所有的类。@Configuration
:允许在上下文中注册额外的 bean 或导入其他配置类
8. Spring Boot 的自动配置是如何实现的?
这个是因为@SpringBootApplication
注解的原因,在上一个问题中已经提到了这个注解。我们知道 @SpringBootApplication
看作是 @Configuration
、@EnableAutoConfiguration
、@ComponentScan
注解的集合。
@EnableAutoConfiguration
:启用 SpringBoot 的自动配置机制@ComponentScan
: 扫描被@Component
(@Service
,@Controller
)注解的 bean,注解默认会扫描该类所在的包下所有的类。@Configuration
:允许在上下文中注册额外的 bean 或导入其他配置类
@EnableAutoConfiguration
是启动自动配置的关键,源码如下(建议自己打断点调试,走一遍基本的流程):
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Import; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
@EnableAutoConfiguration
注解通过 Spring 提供的 @Import
注解导入了AutoConfigurationImportSelector
类(@Import
注解可以导入配置类或者 Bean 到当前类中)。
AutoConfigurationImportSelector
类中getCandidateConfigurations
方法会将所有自动配置类的信息以 List 的形式返回。这些配置信息会被 Spring 容器作 bean 来管理。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct."); return configurations; }
自动配置信息有了,那么自动配置还差什么呢?
@Conditional
注解。@ConditionalOnClass
(指定的类必须存在于类路径下),@ConditionalOnBean
(容器中是否有指定的 Bean)等等都是对@Conditional
注解的扩展。
拿 Spring Security 的自动配置举个例子:SecurityAutoConfiguration
中导入了WebSecurityEnablerConfiguration
类,WebSecurityEnablerConfiguration
源代码如下:
@Configuration @ConditionalOnBean(WebSecurityConfigurerAdapter.class) @ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @EnableWebSecurity public class WebSecurityEnablerConfiguration { }
WebSecurityEnablerConfiguration
类中使用@ConditionalOnBean
指定了容器中必须还有WebSecurityConfigurerAdapter
类或其实现类。所以,一般情况下 Spring Security 配置类都会去实现 WebSecurityConfigurerAdapter
,这样自动将配置就完成了。
9. 开发 RESTful Web 服务常用的注解有哪些?
Spring Bean 相关:
@Autowired
: 自动导入对象到类中,被注入进的类同样要被 Spring 容器管理。@RestController
:@RestController
注解是@Controller和
@ResponseBody
的合集,表示这是个控制器 bean,并且是将函数的返回值直 接填入 HTTP 响应体中,是 REST 风格的控制器。@Component
:通用的注解,可标注任意类为Spring
组件。如果一个 Bean 不知道属于哪个层,可以使用@Component
注解标注。@Repository
: 对应持久层即 Dao 层,主要用于数据库相关操作。@Service
: 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。@Controller
: 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。
处理常见的 HTTP 请求类型:
@GetMapping
: GET 请求、@PostMapping
: POST 请求。@PutMapping
: PUT 请求。@DeleteMapping
: DELETE 请求。
前后端传值:
@RequestParam
以及@Pathvairable :@PathVariable用于获取路径参数,@RequestParam用于获取查询参数。
@RequestBody
:用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且 Content-Type 为application/json
格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去。系统会使用HttpMessageConverter
或者自定义的HttpMessageConverter
将请求的 body 中的 json 字符串转换为 java 对象。
详细介绍可以查看这篇文章:《Spring/Spring Boot 常用注解总结》 。
10. Spirng Boot 常用的两种配置文件
我们可以通过 application.properties
或者 application.yml
对 Spring Boot 程序进行简单的配置。如果,你不进行配置的话,就是使用的默认配置。
11. 什么是 YAML?YAML 配置的优势在哪里 ?
YAML 是一种人类可读的数据序列化语言。它通常用于配置文件。与属性文件相比,如果我们想要在配置文件中添加复杂的属性,YAML 文件就更加结构化,而且更少混淆。可以看出 YAML 具有分层配置数据。
相比于 Properties 配置的方式,YAML 配置的方式更加直观清晰,简介明了,有层次感。
但是,YAML 配置的方式有一个缺点,那就是不支持 @PropertySource
注解导入自定义的 YAML 配置。
12. Spring Boot 常用的读取配置文件的方法有哪些?
我们要读取的配置文件application.yml
内容如下:
wuhan2020: 2020年初武汉爆发了新型冠状病毒,疫情严重,但是,我相信一切都会过去!武汉加油!中国加油! my-profile: name: Guide哥 email: koushuangbwcx@163.com library: location: 湖北武汉加油中国加油 books: - name: 天才基本法 description: 二十二岁的林朝夕在父亲确诊阿尔茨海默病这天,得知自己暗恋多年的校园男神裴之即将出国深造的消息——对方考取的学校,恰是父亲当年为她放弃的那所。 - name: 时间的秩序 description: 为什么我们记得过去,而非未来?时间“流逝”意味着什么?是我们存在于时间之内,还是时间存在于我们之中?卡洛·罗韦利用诗意的文字,邀请我们思考这一亘古难题——时间的本质。 - name: 了不起的我 description: 如何养成一个新习惯?如何让心智变得更成熟?如何拥有高质量的关系? 如何走出人生的艰难时刻?
12.1. 通过 @value
读取比较简单的配置信息
使用 @Value("${property}")
读取比较简单的配置信息:
@Value("${wuhan2020}") String wuhan2020;
需要注意的是
@value
这种方式是不被推荐的,Spring 比较建议的是下面几种读取配置信息的方式。
12.2. 通过@ConfigurationProperties
读取并与 bean 绑定
LibraryProperties
类上加了@Component
注解,我们可以像使用普通 bean 一样将其注入到类中使用。
import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; import java.util.List; @Component @ConfigurationProperties(prefix = "library") @Setter @Getter @ToString class LibraryProperties { private String location; private List<Book> books; @Setter @Getter @ToString static class Book { String name; String description; } }
这个时候你就可以像使用普通 bean 一样,将其注入到类中使用:
“`java
package cn.javaguide.readconfigproperties;
import org.springframework.beans.factory.InitializingBean;
部分转自互联网,侵权删除联系
最新评论