10万字208道Java经典面试题总结(2024修订版)- SpringBoot篇下篇

时间:2024-11-21 08:05:44

目录

      • 1、Spring Boot的配置文件有哪几种格式,它们之间有何区别?
      • 2、Spring Boot如何实现跨域资源共享(CORS)?
      • 3、Spring Boot中的配置文件如何进行加密?
      • 4、Spring Boot如何集成Spring Data JPA?
      • 5、Spring Boot如何集成Spring Security?
      • 6、Spring Boot如何实现RESTful API的版本控制?
      • 7、Spring Boot如何集成Redis?
      • 8、Spring Boot如何集成RabbitMQ?
      • 9、Spring Boot如何集成Apache Kafka?
      • 10、Spring Boot如何集成Elasticsearch?
      • 11、Spring Boot如何实现数据源的动态切换?
      • 12、Spring Boot如何实现应用级别的日志记录?
      • 13、如何在Spring中使用注解来实现动态切换profiles?
      • 14、如何使用 Spring Boot 实现异常处理?
      • 15、如何在Spring Boot中自定义异常处理?
      • 16、什么是 CSRF 攻击?
      • 17、Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?
      • 18、@EnableAutoConfiguration注解的作用是什么?
      • 19、Spring Boot的自动配置原理是什么?
      • 20、你如何理解 Spring Boot 配置加载顺序?
      • 21、什么是Spring Boot的配置参数优先级规则?
      • 22、YAML 配置的优势在哪里 ?
      • 23、YAML的缩进规则是如何工作的?
      • 24、Spring Boot 是否可以使用 XML 配置 ?
      • 25、比较一下 Spring Security 和 Shiro 各自的优缺点 ?
      • 26、Spring Security有哪些应用场景?
      • 27、如何使用Spring Security进行用户认证?
      • 28、Spring Boot 中如何解决跨域问题 ?
      • 29、运行 Spring Boot 有哪几种方式?
      • 30、Spring Boot 需要独立的容器运行吗?
      • 31、在没有外部Servlet容器的情况下,如何启动Spring Boot应用?
      • 32、Spring Boot 中如何实现定时任务?
      • 33、聊一聊Spring Boot的工作原理?
      • 34、Spring Boot比Spring做了哪些改进?
      • 35、关于Spring Boot的热加载功能,聊聊工作原理、如何配置以及在实际应用中的优缺点。
      • 36、spring-boot-devtools 有什么功能?
      • 37、Spring Boot DevTools如何实现自动重启?
      • 38、Spring Boot DevTools的缓存禁用是如何工作的?
      • 39、如何在Spring Boot DevTools中配置全局设置?
      • 40、如何在Spring Boot中使用WebSocket?

1、Spring Boot的配置文件有哪几种格式,它们之间有何区别?

Spring Boot支持多种配置文件格式,主要的格式有:

(1)properties格式:使用键值对的方式进行配置,键和值之间用等号(=)或冒号(:)分隔。properties文件简单明了,易于理解和使用。

spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=dbuser
spring.datasource.password=dbpass

(2)YAML (YAML Ain’t Markup Language)格式:YAML是一种更现代的配置文件格式,它以数据为中心,而不是以标记为中心。YAML文件的可读性更好,支持复杂的数据结构,如列表和嵌套结构。

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: dbuser
    password: dbpass

(3)环境变量:除了文件配置,Spring Boot也可以从操作系统的环境变量中读取配置。

(4)properties和YAML格式的主要区别:

  • 结构性:YAML支持更复杂的结构,如列表和嵌套映射,而properties文件则更简单,只支持键值对。
  • 可读性:YAML通常被认为更易于阅读,因为它使用缩进来表示层级关系,而properties文件使用点和括号来表示层级关系。
  • 数组支持:在YAML中,可以使用列表来表示数组,而在properties文件中,通常通过在键后面添加索引来表示数组,如mylist[0]=val1。
  • 注释:properties文件使用#或!来添加注释,而YAML使用#。
  • 扩展性:YAML的扩展性更好,可以更容易地添加新的配置项而不干扰现有的配置结构。
  • Spring Boot的配置加载顺序:Spring Boot在加载配置时,会考虑多个配置文件和源,包括命令行参数、环境变量、不同profile的配置文件等。YAML文件通常可以覆盖properties文件中的设置。
  • 配置分离:在YAML中,可以使用—来分隔多个独立的配置文档,这在properties文件中是不可能的。

选择使用哪种格式的配置文件,通常取决于个人偏好、项目需求和配置的复杂性。在Spring Boot中,两种格式都是一等公民,可以根据自己的喜好和需求选择使用。

2、Spring Boot如何实现跨域资源共享(CORS)?

方法一:使用@CrossOrigin注解

在控制器类或者具体的方法上使用@CrossOrigin注解。这个注解是Spring框架自带的,用于允许跨域访问。

@RestController
public class MyController {

    @CrossOrigin(origins = "http://example.com") // 允许指定域名的跨域请求
    @GetMapping("/api/data")
    public ResponseEntity<?> getData() {
        // ...
    }
}

你还可以使用通配符来允许所有域名的跨域请求:

@CrossOrigin(origins = "*") // 允许所有域名的跨域请求

方法二:配置全局CORS

创建一个配置类,使用WebMvcConfigurer的实现来全局配置CORS。

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**") // 允许跨域请求的路径
                .allowedOrigins("http://example.com") // 允许的域名列表
                .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的HTTP方法
                .allowedHeaders("*") // 允许的HTTP头
                .allowCredentials(true) // 是否允许证书(cookies)
                .maxAge(3600); // 预请求的有效期
    }
}

同样,你也可以使用通配符来允许所有域名:

registry.addMapping("/api/**")
        .allowedOrigins("*")
        // 其他配置...

注意事项:

  • 使用@CrossOrigin注解时,它只影响带有该注解的控制器或方法。
  • 使用全局CORS配置时,它会影响所有未明确拒绝的跨域请求。
  • 出于安全考虑,生产环境中应该明确允许的域名,而不是使用通配符*。
  • CORS配置中的allowedHeaders参数应该明确指定所需的头信息,而不是使用*,以减少安全风险。

通过以上两种方法,你可以在Spring Boot应用中实现跨域资源共享,从而允许不同域的前端应用访问你的后端服务。

3、Spring Boot中的配置文件如何进行加密?

在Spring Boot中,出于安全考虑,有时需要对配置文件中的敏感信息进行加密,比如数据库密码、第三方服务的API密钥等。Spring Boot提供了一种简单的方法来加密配置文件中的属性。

配置属性替换

Spring Boot允许使用特定格式的占位符来引用外部配置值。这些值可以存储在外部文件或环境变量中,并且可以被加密。例如:

spring.datasource.password=${MY_DB_PASSWORD}
在这个例子中,MY_DB_PASSWORD是一个环境变量,它的值可以是加密的字符串。

使用Spring Boot配置加密

Spring Boot支持使用jasypt加密库来加密配置属性。以下是使用jasypt进行配置加密的步骤:

(1)添加jasypt依赖:首先,需要在项目的pom.xml或build.gradle文件中添加jasypt的依赖。

<!-- Maven -->
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.4</version>
</dependency>

(2)生成加密字符串:使用jasypt的加密工具生成加密字符串。你可以使用命令行工具或编程方式进行加密。

使用命令行工具加密:

java -cp jasypt-1.9.3.jar 
org.jasypt.intf.cli.JasyptPBEStringEncryptionCLI input="your-plain-text" password=encryption-password

这将输出加密后的字符串,如:ENC(your-encrypted-text)

(3)配置加密属性:在application.properties或application.yml文件中,使用加密后的字符串替换敏感信息。

spring.datasource.password=ENC(your-encrypted-text)
配置解密密钥:为了解密配置文件中的属性,需要提供一个解密密钥。这个密钥可以存储在环境变量中,以避免在代码中硬编码密钥。

在application.properties中配置:

jasypt.encryptor.password=encryption-password

或者,使用环境变量:

export JASYPT_ENCRYPTOR_PASSWORD=encryption-password

(4)使用加密属性:现在,Spring Boot应用在启动时会自动解密配置文件中的加密属性,并使用解密后的值。

注意事项:

  1. 选择一个强密码作为加密密钥,并且不要在代码库中泄露它。
  2. 确保只有授权的人员能够访问解密密钥。
  3. 定期更换加密密钥,并更新所有加密的配置值。

通过这种方式,你可以在Spring Boot应用中安全地使用加密的配置属性,而无需担心敏感信息泄露。

4、Spring Boot如何集成Spring Data JPA?

Spring Data JPA 是 Spring 框架的一个模块,它简化了与 Java 持久化 API (JPA) 的交互,提供了一种声明式的数据访问。在 Spring Boot 应用中集成 Spring Data JPA 可以提高数据访问层的效率。以下是集成 Spring Data JPA 的基本步骤:

(1)添加依赖

首先,需要在项目的 pom.xml(Maven)或 build.gradle(Gradle)文件中添加 Spring Data JPA 的依赖。

对于 Maven:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- 其他依赖 -->
</dependencies>

对于 Gradle:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    // 其他依赖
}

(2)配置数据源

在 application.properties 或 application.yml 文件中配置数据库连接信息。

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/your_database
    username: your_username
    password: your_password
    driver-class-name: com.mysql.cj.jdbc.Driver

(3)配置 JPA

同样在配置文件中,配置 JPA 的相关属性,如实体扫描位置、数据库方言等。

# application.properties
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

(4)实体类

创建 JPA 实体类,使用 JPA 注解来映射数据库表和列。

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    // getters and setters
}

(5)仓库接口

创建一个继承 JpaRepository 的接口,Spring Data JPA 会根据接口方法名称自动实现数据访问逻辑。

public interface UserRepository extends JpaRepository<User, Long> {
    // 可以添加自定义查询方法
    List<User> findByName(String name);
}

(6)使用仓库

在服务层注入 UserRepository 并使用它来执行数据操作。

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public List<User> findAllUsers() {
        return userRepository.findAll();
    }

    public List<User> findUsersByName(String name) {
        return userRepository.findByName(name);
    }
    // 其他业务方法
}

(7)启动类

确保你的 Spring Boot 启动类上有 @SpringBootApplication 注解,这样 Spring Boot 才能自动扫描并加载配置。

@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

完成以上步骤后,你的 Spring Boot 应用就可以使用 Spring Data JPA 进行数据库操作了。Spring Data JPA 提供了大量简化 CRUD 操作的方法,同时也支持通过方法名定义查询,极大地提高了开发效率。

5、Spring Boot如何集成Spring Security?

Spring Security 是一个功能强大且可高度定制的身份验证和访问控制框架。在 Spring Boot 应用中集成 Spring Security 可以提供安全的用户认证和授权机制。以下是集成 Spring Security 的基本步骤:

(1)添加依赖

首先,在项目的 pom.xml(Maven)或 build.gradle(Gradle)文件中添加 Spring Security 的依赖。

对于 Maven:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <!-- 其他依赖 -->
</dependencies>

对于 Gradle:

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
    // 其他依赖
}

(2)配置 Spring Security

创建一个配置类,继承 WebSecurityConfigurerAdapter 并重写相应的方法来定义安全策略。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/").permitAll()  // 允许所有用户访问首页
                .anyRequest().authenticated()    // 其他所有请求需要认证
                .and()
            .formLogin()
                .loginPage("/login")            // 定制登录页
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }
    
    // 可以添加更多的安全配置
}

(3)创建登录页

Spring Security 会根据 configure(HttpSecurity http) 方法中定义的 loginPage 路径来寻找登录页。你可以创建一个自定义的登录页,或者使用 Spring Boot 默认提供的登录页。

(4)用户认证

Spring Security 支持多种用户认证方式,包括内存数据库、JDBC 数据库、LDAP 等。以下是使用内存数据库进行用户认证的示例:

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth
        .inMemoryAuthentication()
            .withUser("user").password(passwordEncoder().encode("password")).roles("USER")
            .and()
            .withUser("admin").password(passwordEncoder().encode("admin")).roles("USER", "ADMIN");
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
}

(5)启动类

确保你的 Spring Boot 启动类上有 @SpringBootApplication 注解,这样 Spring Boot 才能自动扫描并加载配置。

@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }
}

(6)自定义安全配置

根据需要,你可以添加更多的安全配置,如密码策略、记住我功能、CORS 过滤器、自定义权限验证等。

(7)测试

启动应用并访问受保护的资源,以确保安全配置按预期工作。

通过以上步骤,你可以在 Spring Boot 应用中集成 Spring Security,实现用户认证和授权。Spring Security 提供了灵活的扩展点,允许你根据应用的具体需求定制安全策略。

6、Spring Boot如何实现RESTful API的版本控制?

在Spring Boot中实现RESTful API的版本控制是一个常见的需求,因为随着API的发展,可能需要对API进行修改或添加新功能,同时保持向后兼容性。以下是一些实现RESTful API版本控制的方法:

(1)URI版本控制

最简单的方法是在URI路径中包含版本号。

GET /api/v1/users
GET /api/v2/users

(2)请求头版本控制

通过在HTTP请求头中指定版本号来控制版本

GET /users
Accept: application/vnd.mycompany.v1+json

(3)媒体类型版本控制

使用自定义的媒体类型来区分版本,可以在Content-Type或Accept请求头中指定:

GET /users HTTP/1.1
Content-Type: application/vnd.mycompany-api+json; version=2.0

(4)使用Spring Boot的版本控制

Spring Boot允许你通过配置来定义API的版本。你可以在application.properties或application.yml文件中添加版本前缀:

spring.mvc.pathversion.version-pattern=v##

(5)实现自定义的URL路径匹配

创建一个自定义的PathMatcher或RequestMappingHandlerMapping,以便在内部逻辑中处理版本控制。

(6)使用Spring Profile

通过Spring Profile来区分不同版本的实现。你可以为每个版本创建一个Profile,并在部署时激活相应的Profile。

(7)利用Spring Boot的Controller方法级别的路由

在同一个Controller中定义不同版本的API方法,并通过方法级别的路由来区分。

(8)使用Spring Cloud Gateway或Zuul

如果你在使用Spring Cloud,可以利用Spring Cloud Gateway或Netflix Zuul来实现API网关,并在网关层面上进行版本控制。

(9)自定义Spring Boot的HandlerMapping

创建一个自定义的HandlerMapping实现,以便基于版本号来路由请求到不同的Controller。

(10)使用Spring Boot Actuator

Spring Boot Actuator提供了一个管理端点,可以用来获取应用程序的版本信息。

选择哪种方法取决于你的具体需求、API的复杂性以及你希望如何管理不同版本的API。通常,URI版本控制是最简单且广泛使用的方法,因为它直观且易于理解和实施。然而,对于大型和复杂的系统,可能需要更灵活的版本控制策略。

7、Spring Boot如何集成Redis?

在Spring Boot中集成Redis是一个相对简单的过程,主要得益于Spring Boot对各种存储解决方案的自动配置支持。

以下是集成Redis的基本步骤:

(1)添加依赖

首先,需要在项目的pom.xml文件中添加Spring Boot对Redis支持的依赖。对于使用Spring Data Redis的项目,可以添加以下依赖:

<dependencies>
    <!-- Spring Boot Starter Data Redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!-- 其他依赖 -->
</dependencies>

确保使用的是与Spring Boot版本兼容的Redis依赖版本。

(2)配置Redis服务器

在application.properties或application.yml文件中配置Redis服务器的地址和端口。

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: 123456

(3)自动配置

Spring Boot将自动配置Spring Data Redis连接工厂和操作库,无需手动配置。

(4)使用RedisRepository

如果你使用Spring Data Redis,可以创建一个继承RedisRepository的接口来简化数据访问层的编码。

@Repository
public interface MyRedisRepository extends CrudRepository<MyEntity, String> {
    // 自定义查询方法...
}

(5)注入RedisTemplate

在需要使用Redis的组件中,注入StringRedisTemplate或RedisTemplate来执行各种操作。

@Service
public class MyService {
    @Autowired
    private StringRedisTemplate redisTemplate;

    public void doSomething() {
        // 使用redisTemplate操作Redis
    }
}

(6)使用 lettuce 或 Jedis 客户端

从Spring Boot 2.0开始,默认的Redis客户端是lettuce。如果你更喜欢使用Jedis,可以在application.properties中配置:

spring.redis.lettuce.enabled=false
spring.redis.jedis.enabled=true

(7)配置SSL连接

如果Redis服务器配置了SSL,需要添加相关依赖并配置SSL连接。

(8)集群支持

如果使用Redis集群,需要配置集群节点信息:

spring.redis.cluster.nodes=127.0.0.1:7000,127.0.0.1:7001

(9)测试连接

启动应用程序后,可以通过注入的RedisTemplate或自定义的Repository来测试Redis连接是否成功。

(10)使用Spring Cache

如果你想要利用Redis作为Spring的缓存提供者,可以添加spring-boot-starter-cache依赖,并在配置中启用对Redis的缓存支持。

8、Spring Boot如何集成RabbitMQ?

在Spring Boot中集成RabbitMQ主要涉及以下步骤:

(1)添加依赖

在项目的pom.xml文件中添加RabbitMQ的Spring Boot Starter依赖。

<dependencies>
    <!-- Spring Boot Starter for RabbitMQ -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <!-- 其他依赖 -->
</dependencies>

(2)配置RabbitMQ

在application.properties或application.yml中配置RabbitMQ服务器的连接信息。

spring:
  rabbitmq:
    addresses: 127.0.0.1
    username: guest
    password: guest

(3)配置ConnectionFactory

如果需要自定义ConnectionFactory,可以创建一个配置类并使用@Configuration注解。在该类中,可以使用@Bean注解来声明一个ConnectionFactory。

@Configuration
public class RabbitMQConfig {

    @Bean
    public ConnectionFactory connectionFactory() {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("127.0.0.1");
        factory.setUsername("guest");
        factory.setPassword("guest");
        return factory;
    }
}

(4)配置RabbitMQ的Listener容器

使用SimpleMessageListenerContainer作为消息监听容器。在配置类中声明并配置它:

@Configuration
@EnableRabbit
public class RabbitMQConfig extends AbstractRabbitListenerContainerFactory {

    @Autowired
    private ConnectionFactory connectionFactory;

    @Override
    protected ConnectionFactory getConnectionFactory() {
        return connectionFactory;
    }

    @Bean
    public SimpleMessageListenerContainer container() {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.setQueueNames("myQueue");
        container.setMessageListener(messageListener());
        return container;
    }

    @Bean
    public MessageListener messageListener() {
        return new MyMessageListener();
    }
}

(5)编写消息监听者

创建一个消息监听者,实现MessageListener接口或使用@RabbitListener注解。

public class MyMessageListener implements MessageListener {

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        // 处理接收到的消息
    }
}

或者使用注解:

@Component
public class MyMessageListener {

    @RabbitListener(queues = "myQueue")
    public void listen(String message) {
        // 处理接收到的字符串消息
    }
}

(6)配置交换机和队列

如果需要,可以配置自定义的交换机和队列,以及它们之间的绑定关系。

@Bean
public Queue myQueue() {
    return new Queue("myQueue", true);
}

@Bean
public FanoutExchange myFanoutExchange() {
    return new FanoutExchange("myFanoutExchange");
}

@Bean
public Binding myBinding() {
    return BindingBuilder.bind(myQueue()).to(myFanoutExchange());
}

(7)测试连接

启动应用程序后,可以通过发送和接收消息来测试RabbitMQ连接是否成功。

(8)配置管理端点

如果你希望Spring Boot暴露RabbitMQ的健康和信息端点,可以添加以下配置:

management.endpoints.web.exposure.include=health,info,rabbitmq

(9)高级配置

根据需要,可能还需要配置其他高级特性,如消息确认、事务、TTL(消息存活时间)、死信交换机等。

9、Spring Boot如何集成Apache Kafka?

在Spring Boot中集成Apache Kafka主要涉及以下步骤:

(1)添加依赖:

在项目的pom.xml文件中添加Spring for Apache Kafka的依赖。

<dependencies>
    <!-- Spring Boot Starter for Apache Kafka -->
    <