SpringBoot面试题
# spring boot的约定优于配置
约定优于配置是一种软件设计范式,其核心思想是通过预设合理的默认配置来减少开发人员需要手动指定的配置项,从而让开发者能够更专注于业务逻辑的实现。
Spring Boot就是这一理念的典型代表,它类似于Spring框架的脚手架,极大地简化了基于Spring生态的应用程序开发流程。
- 基于传统的spring框架开发web应用的时候,我们需要做很多和业务无关,并且只需要做一次的配置项,
- 比如jar包的依赖管理,
- 维护web.xml和dispatcher-servlet.xml等配置文件
- 需要手动将应用部署到外部Web容器(如Tomcat)
- 将第三方库集成到Spring IOC容器时需要编写大量配置
Spring Boot通过约定优于配置的理念,自动处理了这些基础配置
spring boot约定优于配置的体现
- spring-boot-starter启动依赖,帮助我们管理所有的jar包版本,
- 如果依赖web jar包,那么spring boot会自动内置tomcat容器来去运行web应用,我们不再需要去单独进行应用部署,
- spring boot的自动装配机制的实现中,通过扫描META-INF/spring.factories文件,去进行识别配置类,从而去实现bean的自动装载,
- 自动识别并加载resources目录下的application.properties/application.yml文件
# Springboot自动配置原理
自动装配,简单来说就是自动去把第三方组件的bean,装载到IOC容器里面,不需要开发人员再去写bean相关的一个配置
Spring Boot的自动配置原理基于**@SpringBootApplication
**注解,它封装了三个注解,分别是:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
。
其中**@EnableAutoConfiguration
是实现自动化配置的核心注解,它通过@Import
导入AutoConfigurationImportSelector
配置选择器,它实现了DeferredImportSelector接口(这个接口是一个延迟加载配置选择器,确保自动配置类的加载顺序在用户自定义 Bean 之后**,方便用户覆盖默认配置,如通过 @Bean
覆盖自动配置的 Bean)`
配置选择器内部会读取该项目以及该项目引用的Jar包的classpath路径下的META-INF/spring.factories
文件中的所配置的类的全类名,(在springboot2.7后是一个.import结尾的文件,)然后过滤出所有的AutoConfigurationClass类型的类,
然后这些配置类中所定义的Bean会根据条件注解(@ConditionalOnClass、@ConditionalOnMissingBean)决定是否将其注册到Spring容器中
更重要的是使用springboot自动装配,可以通过注解@AutoConfigurationAfter/Before来指定自动装配的顺序,而如果没有指定只会根据类名在字母表的顺序加载Bean,可能导致条件注解结果的异常,(比如School配置类的字母顺序在Student配置类前,导致Student在School后面加载,而如果School配置类的Bean上加了条件注解ConditionalOnBean(Student.class)会导致School不加载)
# SpringBoot如何解决跨域问题
根据服务器端返回的access control allow original,这样一个头的信息,来决定是否允许跨域的一个访问行为,所以我们只需要在服务器端配置这样一个属性,并配置允许哪些域名啊,支持跨域请求就好
跨域问题源于浏览器的同源策略(Same-Origin Policy)。如果前端页面和后端服务的协议、域名或端口不同,则浏览器会阻止跨域请求。
Spring Boot 解决跨域问题的方式
使用
@CrossOrigin
注解- 它可以作用于控制器类或方法级别。
- 主要参数
origins
指定允许访问资源的来源(即域名),默认值:"*"
,意味着允许所有来源。allowedHeaders
定义哪些请求头可以通过跨域请求发送到服务器。使用*
表示允许所有头部。exposedHeaders
指定哪些响应头可以通过跨域请求暴露给前端应用。methods
指定允许的HTTP方法(GET, POST, PUT, DELETE等)。使用*
表示允许所有方法。allowCredentials
指示是否支持用户凭证(Cookies、HTTP认证信息等)包含在跨域请求中。设置为true
时,必须同时指定origins
不能为"*"
(因为出于安全考虑,浏览器不允许这样配置)。
全局跨域配置
实现
WebMvcConfigurer
接口,可以在全局范围内配置跨域规则。@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") // 指定允许跨域的路径 .allowedOrigins("http://localhost:3000") // 允许的来源 .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的 HTTP 方法 .allowedHeaders("*") // 允许的请求头 .allowCredentials(true) // 是否允许发送 Cookie .maxAge(3600); // 预检请求的缓存时间(秒) } }
使用过滤器(Filter)
通过自定义过滤器,可以拦截所有请求并手动添加 CORS 相关的响应头。
@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); // 允许携带凭证 config.addAllowedOrigin("http://localhost:3000"); // 允许的源 config.addAllowedHeader("*"); // 允许的请求头 config.addAllowedMethod("*"); // 允许的HTTP方法 source.registerCorsConfiguration("/**", config); // 对所有路径生效 return new CorsFilter(source); } }
使用 Nginx 或反向代理
在生产环境中,可以通过 Nginx 或其他反向代理服务器解决跨域问题。
server { listen 80; server_name example.com; location /api/ { proxy_pass http://localhost:8080; # 转发到后端服务 add_header Access-Control-Allow-Origin "http://localhost:3000"; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE"; add_header Access-Control-Allow-Headers "*"; add_header Access-Control-Allow-Credentials "true"; } }
优点
- 将跨域逻辑从应用层移至网关层,减轻后端负担。
- 更适合微服务架构中的跨域需求。
# Spring Boot的starter
Starter组件是Spring Boot的四大核心特性之一,其他核心特性还包括自动装配(Auto-Configuration)、Actuator监控等。这些特性的设计目标都是为了让开发者能够更专注于业务逻辑开发,减少对配置和外部环境的依赖。
starter组件的主要作用
- Starter以功能维度维护依赖包的版本,开发者无需手动处理版本冲突问题,降低了因版本不匹配导致错误的可能性。
- Starter会一次性引入该功能所需的所有依赖库,避免了开发者手动逐个添加依赖的繁琐操作。
- Starter内部集成了自动装配机制。当项目引入某个Starter后,相关功能会自动集成到Spring生态中,对应的Bean也会通过自动装配机制被管理。
- 通过Starter引入的功能,其所需的配置(如数据库连接信息)可以直接在
application.properties
或application.yml
中定义。例如,引入redis-starter
后,只需在配置文件中设置Redis连接参数即可直接使用
Starter体现了Spring Boot“约定优于配置”(Convention Over Configuration)的原则。Spring Boot官方提供了大量常用Starter(如spring-boot-starter-data-redis
、spring-boot-starter-data-mongodb
)但官方并不能维护所有中间件的starter,所以对于不存在的starter组件,第三方组件一般会自己去维护一个starter,
而官方starter组件和第三方当组件,最大的区别在于命名方式上,
官方维护的starter组件,以spring-boot-starter-
为前缀,而第三方维护的starter,以-spring-boot-starter
为后缀,这也是一种约定优于配置的一个体现