|
| 1 | +> 本文由JavaGuide整理翻译自(做了适当删减、修改和补充): |
| 2 | +> |
| 3 | +> - https://www.javaguides.net/2018/11/spring-boot-interview-questions-and-answers.html |
| 4 | +> - https://www.algrim.co/posts/101-spring-boot-interview-questions |
| 5 | +
|
| 6 | +### 1. 什么是 Spring Boot? |
| 7 | + |
| 8 | +首先,重要的是要理解 Spring Boot 并不是一个框架,它是一种创建独立应用程序的更简单方法,只需要很少或没有配置(相比于 Spring 来说)。Spring Boot最好的特性之一是它利用现有的 Spring 项目和第三方项目来开发适合生产的应用程序。 |
| 9 | + |
| 10 | +### 2. 说出使用Spring Boot的主要优点 |
| 11 | + |
| 12 | +1. 开发基于 Spring 的应用程序很容易。 |
| 13 | +2. Spring Boot 项目所需的开发或工程时间明显减少,通常会提高整体生产力。 |
| 14 | +3. Spring Boot不需要编写大量样板代码、XML配置和注释。 |
| 15 | +4. Spring引导应用程序可以很容易地与Spring生态系统集成,如Spring JDBC、Spring ORM、Spring Data、Spring Security等。 |
| 16 | +5. Spring Boot遵循“固执己见的默认配置”,以减少开发工作(默认配置可以修改)。 |
| 17 | +6. Spring Boot 应用程序提供嵌入式HTTP服务器,如Tomcat和Jetty,可以轻松地开发和测试web应用程序。(这点很赞!普通运行Java程序的方式就能运行基于Spring Boot web 项目,省事很多) |
| 18 | +7. Spring Boot提供命令行接口(CLI)工具,用于开发和测试Spring Boot应用程序,如Java或Groovy。 |
| 19 | +8. Spring Boot提供了多种插件,可以使用内置工具(如Maven和Gradle)开发和测试Spring Boot应用程序。 |
| 20 | + |
| 21 | +### 3. 为什么需要Spring Boot? |
| 22 | + |
| 23 | +Spring Framework旨在简化J2EE企业应用程序开发。Spring Boot Framework旨在简化Spring开发。 |
| 24 | + |
| 25 | + |
| 26 | + |
| 27 | +### 4. 什么是 Spring Boot Starters? |
| 28 | + |
| 29 | +Spring Boot Starters 是一系列依赖关系的集合,因为它的存在,项目的依赖之间的关系对我们来说变的更加简单了。举个例子:在没有Spring Boot Starters之前,我们开发REST服务或Web应用程序时; 我们需要使用像Spring MVC,Tomcat和Jackson这样的库,这些依赖我们需要手动一个一个添加。但是,有了 Spring Boot Starters 我们只需要一个只需添加一个**spring-boot-starter-web**一个依赖就可以了,这个依赖包含的字依赖中包含了我们开发REST 服务需要的所有依赖。 |
| 30 | + |
| 31 | +```xml |
| 32 | +<dependency> |
| 33 | + <groupId>org.springframework.boot</groupId> |
| 34 | + <artifactId>spring-boot-starter-web</artifactId> |
| 35 | +</dependency> |
| 36 | +``` |
| 37 | + |
| 38 | +### 5. 如何在Spring Boot应用程序中使用Jetty而不是Tomcat? |
| 39 | + |
| 40 | +Spring Boot Web starter使用Tomcat作为默认的嵌入式servlet容器, 如果你想使用 Jetty 的话只需要修改pom.xml(Maven)或者build.gradle(Gradle)就可以了。 |
| 41 | + |
| 42 | +**Maven:** |
| 43 | + |
| 44 | +```xml |
| 45 | +<!--从Web启动器依赖中排除Tomcat--> |
| 46 | +<dependency> |
| 47 | + <groupId>org.springframework.boot</groupId> |
| 48 | + <artifactId>spring-boot-starter-web</artifactId> |
| 49 | + <exclusions> |
| 50 | + <exclusion> |
| 51 | + <groupId>org.springframework.boot</groupId> |
| 52 | + <artifactId>spring-boot-starter-tomcat</artifactId> |
| 53 | + </exclusion> |
| 54 | + </exclusions> |
| 55 | +</dependency> |
| 56 | +<!--添加Jetty依赖--> |
| 57 | +<dependency> |
| 58 | + <groupId>org.springframework.boot</groupId> |
| 59 | + <artifactId>spring-boot-starter-jetty</artifactId> |
| 60 | +</dependency> |
| 61 | +``` |
| 62 | + |
| 63 | +**Gradle:** |
| 64 | + |
| 65 | +```groovy |
| 66 | +compile("org.springframework.boot:spring-boot-starter-web") { |
| 67 | + exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' |
| 68 | +} |
| 69 | +compile("org.springframework.boot:spring-boot-starter-jetty") |
| 70 | +``` |
| 71 | + |
| 72 | +说个题外话,从上面可以看出使用 Gradle 更加简洁明了,但是国内目前还是 Maven 使用的多一点,我个人觉得 Gradle 在很多方面都要好很多。 |
| 73 | + |
| 74 | +### 6. 介绍一下@SpringBootApplication注解 |
| 75 | + |
| 76 | +```java |
| 77 | +package org.springframework.boot.autoconfigure; |
| 78 | +@Target(ElementType.TYPE) |
| 79 | +@Retention(RetentionPolicy.RUNTIME) |
| 80 | +@Documented |
| 81 | +@Inherited |
| 82 | +@SpringBootConfiguration |
| 83 | +@EnableAutoConfiguration |
| 84 | +@ComponentScan(excludeFilters = { |
| 85 | + @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), |
| 86 | + @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) }) |
| 87 | +public @interface SpringBootApplication { |
| 88 | + ...... |
| 89 | +} |
| 90 | +``` |
| 91 | + |
| 92 | +```java |
| 93 | +package org.springframework.boot; |
| 94 | +@Target(ElementType.TYPE) |
| 95 | +@Retention(RetentionPolicy.RUNTIME) |
| 96 | +@Documented |
| 97 | +@Configuration |
| 98 | +public @interface SpringBootConfiguration { |
| 99 | + |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +可以看出大概可以把 `@SpringBootApplication `看作是 `@Configuration`、`@EnableAutoConfiguration`、`@ComponentScan ` 注解的集合。根据 SpringBoot官网,这三个注解的作用分别是: |
| 104 | + |
| 105 | +- `@EnableAutoConfiguration`:启用 SpringBoot 的自动配置机制 |
| 106 | +- `@ComponentScan`: 扫描被`@Component` (`@Service`,`@Controller`)注解的bean,注解默认会扫描该类所在的包下所有的类。 |
| 107 | +- `@Configuration`:允许在上下文中注册额外的bean或导入其他配置类 |
| 108 | + |
| 109 | +### 7. (重要)Spring Boot 的自动配置是如何实现的? |
| 110 | + |
| 111 | +这个是因为`@SpringBootApplication `注解的原因,在上一个问题中已经提到了这个注解。我们知道 `@SpringBootApplication `看作是 `@Configuration`、`@EnableAutoConfiguration`、`@ComponentScan ` 注解的集合。 |
| 112 | + |
| 113 | +- `@EnableAutoConfiguration`:启用 SpringBoot 的自动配置机制 |
| 114 | +- `@ComponentScan`: 扫描被`@Component` (`@Service`,`@Controller`)注解的bean,注解默认会扫描该类所在的包下所有的类。 |
| 115 | +- `@Configuration`:允许在上下文中注册额外的bean或导入其他配置类 |
| 116 | + |
| 117 | +`@EnableAutoConfiguration`是启动自动配置的关键,源码如下(建议自己打断点调试,走一遍基本的流程): |
| 118 | + |
| 119 | +```java |
| 120 | +import java.lang.annotation.Documented; |
| 121 | +import java.lang.annotation.ElementType; |
| 122 | +import java.lang.annotation.Inherited; |
| 123 | +import java.lang.annotation.Retention; |
| 124 | +import java.lang.annotation.RetentionPolicy; |
| 125 | +import java.lang.annotation.Target; |
| 126 | +import org.springframework.context.annotation.Import; |
| 127 | + |
| 128 | +@Target({ElementType.TYPE}) |
| 129 | +@Retention(RetentionPolicy.RUNTIME) |
| 130 | +@Documented |
| 131 | +@Inherited |
| 132 | +@AutoConfigurationPackage |
| 133 | +@Import({AutoConfigurationImportSelector.class}) |
| 134 | +public @interface EnableAutoConfiguration { |
| 135 | + String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; |
| 136 | + |
| 137 | + Class<?>[] exclude() default {}; |
| 138 | + |
| 139 | + String[] excludeName() default {}; |
| 140 | +} |
| 141 | +``` |
| 142 | + |
| 143 | +`@EnableAutoConfiguration` 注解通过Spring 提供的 `@Import` 注解导入了`AutoConfigurationImportSelector`类(`@Import` 注解可以导入配置类或者Bean到当前类中)。 |
| 144 | + |
| 145 | +` ``AutoConfigurationImportSelector`类中`getCandidateConfigurations`方法会将所有自动配置类的信息以 List 的形式返回。这些配置信息会被 Spring 容器作 bean 来管理。 |
| 146 | + |
| 147 | +```java |
| 148 | + protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { |
| 149 | + List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), |
| 150 | + getBeanClassLoader()); |
| 151 | + Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " |
| 152 | + + "are using a custom packaging, make sure that file is correct."); |
| 153 | + return configurations; |
| 154 | + } |
| 155 | +``` |
| 156 | + |
| 157 | +自动配置信息有了,那么自动配置还差什么呢? |
| 158 | + |
| 159 | +`@Conditional` 注解。`@ConditionalOnClass`(指定的类必须存在于类路径下),`@ConditionalOnBean`(容器中是否有指定的Bean)等等都是对`@Conditional`注解的扩展。拿 Spring Security 的自动配置举个例子: |
| 160 | + |
| 161 | +`SecurityAutoConfiguration`中导入了`WebSecurityEnablerConfiguration`类,`WebSecurityEnablerConfiguration`源代码如下: |
| 162 | + |
| 163 | +```java |
| 164 | +@Configuration |
| 165 | +@ConditionalOnBean(WebSecurityConfigurerAdapter.class) |
| 166 | +@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN) |
| 167 | +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) |
| 168 | +@EnableWebSecurity |
| 169 | +public class WebSecurityEnablerConfiguration { |
| 170 | + |
| 171 | +} |
| 172 | +``` |
| 173 | + |
| 174 | +`WebSecurityEnablerConfiguration`类中使用`@ConditionalOnBean`指定了容器中必须还有`WebSecurityConfigurerAdapter` 类或其实现类。所以,一般情况下 Spring Security 配置类都会去实现 `WebSecurityConfigurerAdapter`,这样自动将配置就完成了。 |
| 175 | + |
| 176 | +更多内容可以参考这篇文章:https://sylvanassun.github.io/2018/01/08/2018-01-08-spring_boot_auto_configure/ |
| 177 | + |
| 178 | +### 8. Spring Boot支持哪些嵌入式web容器? |
| 179 | + |
| 180 | +Spring Boot支持以下嵌入式servlet容器: |
| 181 | + |
| 182 | +| **Name** | **Servlet Version** | |
| 183 | +| ------------ | ------------------- | |
| 184 | +| Tomcat 9.0 | 4.0 | |
| 185 | +| Jetty 9.4 | 3.1 | |
| 186 | +| Undertow 2.0 | 4.0 | |
| 187 | + |
| 188 | +您还可以将Spring引导应用程序部署到任何Servlet 3.1+兼容的 Web 容器中。 |
| 189 | + |
| 190 | +这就是你为什么可以通过直接像运行 普通 Java 项目一样运行 SpringBoot 项目。这样的确省事了很多,方便了我们进行开发,降低了学习难度。 |
| 191 | + |
| 192 | +### 9. 什么是Spring Security ? |
| 193 | + |
| 194 | +Spring Security 应该属于 Spring 全家桶中学习曲线比较陡峭的几个模块之一,下面我将从起源和定义这两个方面来简单介绍一下它。 |
| 195 | + |
| 196 | +- **起源:** Spring Security 实际上起源于 Acegi Security,这个框架能为基于 Spring 的企业应用提供强大而灵活安全访问控制解决方案,并且框架这个充分利用 Spring 的 IoC 和 AOP 功能,提供声明式安全访问控制的功能。后面,随着这个项目发展, Acegi Security 成为了Spring官方子项目,后来被命名为 “Spring Security”。 |
| 197 | +- **定义:**Spring Security 是一个功能强大且高度可以定制的框架,侧重于为Java 应用程序提供身份验证和授权。——[官方介绍](https://spring.io/projects/spring-security)。 |
0 commit comments