[java八股文][JavaSpring面试篇]SpringBoot

为什么使用springboot

  • 简化开发:Spring Boot通过提供一系列的开箱即用的组件和自动配置,简化了项目的配置和开发过程,开发人员可以更专注于业务逻辑的实现,而不需要花费过多时间在繁琐的配置上。
  • 快速启动:Spring Boot提供了快速的应用程序启动方式,可通过内嵌的Tomcat、Jetty或Undertow等容器快速启动应用程序,无需额外的部署步骤,方便快捷。
  • 自动化配置:Spring Boot通过自动配置功能,根据项目中的依赖关系和约定俗成的规则来配置应用程序,减少了配置的复杂性,使开发者更容易实现应用的最佳实践。

#SpringBoot比Spring好在哪里

  • Spring Boot 提供了自动化配置,大大简化了项目的配置过程。通过约定优于配置的原则,很多常用的配置可以自动完成,开发者可以专注于业务逻辑的实现。
  • Spring Boot 提供了快速的项目启动器,通过引入不同的 Starter,可以快速集成常用的框架和库(如数据库、消息队列、Web 开发等),极大地提高了开发效率。
  • Spring Boot 默认集成了多种内嵌服务器(如Tomcat、Jetty、Undertow),无需额外配置,即可将应用打包成可执行的 JAR 文件,方便部署和运行。

#SpringBoot用到哪些设计模式?

  • 代理模式:Spring 的 AOP 通过动态代理实现方法级别的切面增强,有静态和动态两种代理方式,采用动态代理方式。
  • 策略模式:Spring AOP 支持 JDK 和 Cglib 两种动态代理实现方式,通过策略接口和不同策略类,运行时动态选择,其创建一般通过工厂方法实现。
  • 装饰器模式:Spring 用 TransactionAwareCacheDecorator 解决缓存与数据库事务问题增加对事务的支持。
  • 单例模式:Spring Bean 默认是单例模式,通过单例注册表(如 HashMap)实现。
  • 简单工厂模式:Spring 中的 BeanFactory 是简单工厂模式的体现,通过工厂类方法获取 Bean 实例。
  • 工厂方法模式:Spring中的 FactoryBean 体现工厂方法模式,为不同产品提供不同工厂。
  • 观察者模式:Spring 观察者模式包含 Event 事件、Listener 监听者、Publisher 发送者,通过定义事件、监听器和发送者实现,观察者注册在 ApplicationContext 中,消息发送由 ApplicationEventMulticaster 完成。
  • 模板模式:Spring Bean 的创建过程涉及模板模式,体现扩展性,类似 Callback 回调实现方式。
  • 适配器模式:Spring MVC 中针对不同方式定义的 Controller,利用适配器模式统一函数定义,定义了统一接口 HandlerAdapter 及对应适配器类。

#怎么理解SpringBoot中的约定大于配置

约定大于配置是Spring Boot的核心设计理念,它通过预设合理的默认行为和项目规范,大幅减少开发者需要手动配置的步骤,从而提升开发效率和项目标准化程度。

理解 Spring Boot 中的"约定大于配置"原则,可以从以下几个方面来解释:

  • 自动化配置 :Spring Boot 提供了大量的自动化配置,通过分析项目的依赖和环境,自动配置应用程序的行为。开发者无需显式地配置每个细节,大部分常用的配置都已经预设好了。例如,引入spring-boot-starter-web后,Spring Boot会自动配置内嵌Tomcat和Spring MVC,无需手动编写XML。
  • 默认配置:Spring Boot 为诸多方面提供大量默认配置,如连接数据库、设置 Web 服务器、处理日志等。开发人员无需手动配置这些常见内容,框架已做好决策。例如,默认的日志配置可让应用程序快速输出日志信息,无需开发者额外繁琐配置日志级别、输出格式与位置等。
  • 约定的项目结构 :Spring Boot 提倡特定项目结构,通常主应用程序类(含 main 方法)置于根包,控制器类、服务类、数据访问类等分别放在相应子包,如com.example.demo.controller放控制器类,com.example.demo.service放服务类等。此约定使团队成员更易理解项目结构与组织,新成员加入项目时能快速定位各功能代码位置,提升协作效率。

#SpringBoot的项目结构是怎么样的?

一个正常的企业项目里一种通用的项目结构和代码层级划分的指导意见。按这《阿里巴巴Java开发手册》时本书上说的,一般分为如下几层:

  • 开放接口层:可直接封装 Service 接口暴露成 RPC 接口;通过 Web 封装成 http 接口;网关控制层等。

  • 终端显示层:各个端的模板渲染并执行显示的层。当前主要是 velocity 渲染,JS 渲染,JSP 渲染,移动端展示等。

  • Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。

  • Service 层:相对具体的业务逻辑服务层。

  • Manager 层:通用业务处理层,它有如下特征:

    • 1)对第三方平台封装的层,预处理返回结果及转化异常信息,适配上层接口。
    • 2)对 Service 层通用能力的下沉,如缓存方案、中间件通用处理。
    • 3)与 DAO 层交互,对多个 DAO 的组合复用。
  • DAO 层:数据访问层,与底层 MySQL、Oracle、Hbase、OceanBase 等进行数据交互。

  • 第三方服务:包括其它部门 RPC 服务接口,基础平台,其它公司的 HTTP 接口,如淘宝开放平台、支付宝付款服务、高德地图服务等。

  • 外部接口:外部(应用)数据存储服务提供的接口,多见于数据迁移场景中。

如果从一个用户访问一个网站的情况来看,对应着上面的项目代码结构来分析,可以贯穿整个代码分层:

对应代码目录的流转逻辑就是:

所以,以后每当我们拿到一个新的项目到手时,只要按照这个思路去看别人项目的代码,应该基本都是能理得顺的。

#SpringBoot自动装配原理是什么?

什么是自动装配?

SpringBoot 的自动装配原理是基于Spring Framework的条件化配置和@EnableAutoConfiguration注解实现的。这种机制允许开发者在项目中引入相关的依赖,SpringBoot 将根据这些依赖自动配置应用程序的上下文和功能。

SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的META-INF/spring.factories文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。

通俗来讲,自动装配就是通过注解或一些简单的配置就可以在SpringBoot的帮助下开启和配置各种功能,比如数据库访问、Web开发。

SpringBoot自动装配原理

首先点进 @SpringBootApplication 注解的内部

接下来将逐个解释这些注解的作用:

  • @Target({ElementType.TYPE}): 该注解指定了这个注解可以用来标记在类上。在这个特定的例子中,这表示该注解用于标记配置类。
  • @Retention(RetentionPolicy.RUNTIME): 这个注解指定了注解的生命周期,即在运行时保留。这是因为 Spring Boot 在运行时扫描类路径上的注解来实现自动配置,所以这里使用了 RUNTIME 保留策略。
  • @Documented: 该注解表示这个注解应该被包含在 Java 文档中。它是用于生成文档的标记,使开发者能够看到这个注解的相关信息。
  • @Inherited: 这个注解指示一个被标注的类型是被继承的。在这个例子中,它表明这个注解可以被继承,如果一个类继承了带有这个注解的类,它也会继承这个注解。
  • @SpringBootConfiguration: 这个注解表明这是一个 Spring Boot 配置类。如果点进这个注解内部会发现与标准的 @Configuration 没啥区别,只是为了表明这是一个专门用于 SpringBoot 的配置。
  • @EnableAutoConfiguration: 这个注解是 Spring Boot 自动装配的核心。它告诉 Spring oot 启用自动配置机制,根据项目的依赖和配置自动配置应用程序的上下文。通过这个注解,SpringBoot 将尝试根据类路径上的依赖自动配置应用程序。
  • @ComponentScan: 这个注解用于配置组件扫描的规则。在这里,它告诉 SpringBoot 在指定的包及其子包中查找组件,这些组件包括被注解的类、@Component 注解的类等。其中的 excludeFilters 参数用于指定排除哪些组件,这里使用了两个自定义的过滤器,分别是 TypeExcludeFilter 和 AutoConfigurationExcludeFilter。

@EnableAutoConfiguration 这个注解是实现自动装配的核心注解

  • @AutoConfigurationPackage,将项目src中main包下的所有组件注册到容器中,例如标注了Component注解的类等
  • @Import({AutoConfigurationImportSelector.class}),是自动装配的核心,接下来分析一下这个注解

AutoConfigurationImportSelector 是 Spring Boot 中一个重要的类,它实现了 ImportSelector 接口,用于实现自动配置的选择和导入。具体来说,它通过分析项目的类路径和条件来决定应该导入哪些自动配置类。

代码太多,选取部分主要功能的代码:

java 复制代码
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
		ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
    
    // ... (其他方法和属性)

  // 获取所有符合条件的类的全限定类名,例如RedisTemplate的全限定类名(org.springframework.data.redis.core.RedisTemplate;),这些类需要被加载到 IoC 容器中。
	@Override
	public String[] selectImports(AnnotationMetadata annotationMetadata) {
		// 扫描类路径上的 META-INF/spring.factories 文件,获取所有实现了 AutoConfiguration 接口的自动配置类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);

		// 过滤掉不满足条件的自动配置类,比如一些自动装配类
		configurations = filter(configurations, annotationMetadata, attributes);

		// 排序自动配置类,根据 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 注解指定的顺序
		sort(configurations, annotationMetadata, attributes);

		// 将满足条件的自动配置类的类名数组返回,这些类将被导入到应用程序上下文中
		return StringUtils.toStringArray(configurations);
	}

	// ... (其他方法)
	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		// 获取自动配置类的候选列表,从 META-INF/spring.factories 文件中读取
		// 通过类加载器加载所有候选类
		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());

		// 过滤出实现了 AutoConfiguration 接口的自动配置类
		configurations = configurations.stream()
				.filter(this::isEnabled)
				.collect(Collectors.toList());

		// 对于 Spring Boot 1.x 版本,还需要添加 spring-boot-autoconfigure 包中的自动配置类
		// configurations.addAll(getAutoConfigEntry(getAutoConfigurationEntry(metadata)));
		return configurations;
	}

	// ... (其他方法)
	protected List<String> filter(List<String> configurations, AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		// 使用条件判断机制,过滤掉不满足条件的自动配置类
		configurations = configurations.stream()
				.filter(configuration -> isConfigurationCandidate(configuration, metadata, attributes))
				.collect(Collectors.toList());
		return configurations;
	}

	// ... (其他方法)
	protected void sort(List<String> configurations, AnnotationMetadata metadata,
			AnnotationAttributes attributes) {
		// 根据 @AutoConfigureOrder 和 @AutoConfigureAfter/@AutoConfigureBefore 注解指定的顺序对自动配置类进行排序
		configurations.sort((o1, o2) -> {
			int i1 = getAutoConfigurationOrder(o1, metadata, attributes);
			int i2 = getAutoConfigurationOrder(o2, metadata, attributes);
			return Integer.compare(i1, i2);
		});
	}
  
  	// ... (其他方法)

}

梳理一下,以下是AutoConfigurationImportSelector的主要工作:

  • 扫描类路径: 在应用程序启动时,AutoConfigurationImportSelector 会扫描类路径上的 META-INF/spring.factories 文件,这个文件中包含了各种 Spring 配置和扩展的定义。在这里,它会查找所有实现了 AutoConfiguration 接口的类,具体的实现为getCandidateConfigurations方法。

  • 条件判断: 对于每一个发现的自动配置类,AutoConfigurationImportSelector 会使用条件判断机制(通常是通过 @ConditionalOnXxx注解)来确定是否满足导入条件。这些条件可以是配置属性、类是否存在、Bean是否存在等等。

  • 根据条件导入自动配置类: 满足条件的自动配置类将被导入到应用程序的上下文中。这意味着它们会被实例化并应用于应用程序的配置。

#说几个启动器(starter)?

  • spring-boot-starter-web:这是最常用的起步依赖之一,它包含了Spring MVC和Tomcat嵌入式服务器,用于快速构建Web应用程序。
  • spring-boot-starter-security:提供了Spring Security的基本配置,帮助开发者快速实现应用的安全性,包括认证和授权功能。
  • mybatis-spring-boot-starter:这个Starter是由MyBatis团队提供的,用于简化在Spring Boot应用中集成MyBatis的过程。它自动配置了MyBatis的相关组件,包括SqlSessionFactory、MapperScannerConfigurer等,使得开发者能够快速地开始使用MyBatis进行数据库操作。
  • spring-boot-starter-data-jpaspring-boot-starter-jdbc:如果使用的是Java Persistence API (JPA)进行数据库操作,那么应该使用spring-boot-starter-data-jpa。这个Starter包含了Hibernate等JPA实现以及数据库连接池等必要的库,可以让你轻松地与MySQL数据库进行交互。你需要在application.properties或application.yml中配置MySQL的连接信息。如果倾向于直接使用JDBC而不通过JPA,那么可以使用spring-boot-starter-jdbc,它提供了基本的JDBC支持。
  • spring-boot-starter-data-redis:用于集成Redis缓存和数据存储服务。这个Starter包含了与Redis交互所需的客户端(默认是Jedis客户端,也可以配置为Lettuce客户端),以及Spring Data Redis的支持,使得在Spring Boot应用中使用Redis变得非常便捷。同样地,需要在配置文件中设置Redis服务器的连接详情。
  • spring-boot-starter-test:包含了单元测试和集成测试所需的库,如JUnit, Spring Test, AssertJ等,便于进行测试驱动开发(TDD)。

#写过SpringBoot starter吗?

步骤1: 创建Maven项目

首先,需要创建一个新的Maven项目。在pom.xml中添加Spring Boot的starter parent和一些必要的依赖。例如:

java 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.0</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

步骤2: 添加自动配置

在src/main/resources/META-INF/spring.factories中添加自动配置的元数据。例如:

复制代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration = com.example.starter.MyAutoConfiguration

然后,创建MyAutoConfiguration类,该类需要@Configuration和@EnableConfigurationProperties注解。@EnableConfigurationProperties用于启用你定义的配置属性类。

复制代码
@Configuration
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {

    @Autowired
    private MyProperties properties;

    @Bean
    public MyService myService() {
        return new MyServiceImpl(properties);
    }
}

步骤3: 创建配置属性类

创建一个配置属性类,使用@ConfigurationProperties注解来绑定配置文件中的属性。

复制代码
@ConfigurationProperties(prefix = "my")
public class MyProperties {
    private String name;
    // getters and setters
}

步骤4: 创建服务和控制器

创建一个服务类和服务实现类,以及一个控制器来展示你的starter的功能。

复制代码
@Service
public interface MyService {
    String getName();
}

@Service
public class MyServiceImpl implements MyService {
    private final MyProperties properties;

    public MyServiceImpl(MyProperties properties) {
        this.properties = properties;
    }

    @Override
    public String getName() {
        return properties.getName();
    }
}

@RestController
public class MyController {
    private final MyService myService;

    public MyController(MyService myService) {
        this.myService = myService;
    }

    @GetMapping("/name")
    public String getName() {
        return myService.getName();
    }
}

步骤5: 发布Starter

将你的starter发布到Maven仓库,无论是私有的还是公共的,如Nexus或Maven Central。

步骤6: 使用Starter

在你的主应用的pom.xml中添加你的starter依赖,然后在application.yml或application.properties中配置你的属性。

复制代码
my:
    name: Hello World

#SpringBoot里面有哪些重要的注解?还有一个配置相关的注解是哪个?

Spring Boot 中一些常用的注解包括:

  • @SpringBootApplication:用于标注主应用程序类,标识一个Spring Boot应用程序的入口点,同时启用自动配置和组件扫描。
  • @Controller:标识控制器类,处理HTTP请求。
  • @RestController:结合@Controller和@ResponseBody,返回RESTful风格的数据。
  • @Service:标识服务类,通常用于标记业务逻辑层。
  • @Repository:标识数据访问组件,通常用于标记数据访问层。
  • @Component:通用的Spring组件注解,表示一个受Spring管理的组件。
  • @Autowired:用于自动装配Spring Bean。
  • @Value:用于注入配置属性值。
  • @RequestMapping:用于映射HTTP请求路径到Controller的处理方法。
  • @GetMapping、@PostMapping、@PutMapping、@DeleteMapping:简化@RequestMapping的GET、POST、PUT和DELETE请求。

另外,一个与配置相关的重要注解是:

  • @Configuration:用于指定一个类为配置类,其中定义的bean会被Spring容器管理。通常与@Bean配合使用,@Bean用于声明一个Bean实例,由Spring容器进行管理。

#springboot怎么开启事务?

在 Spring Boot 中开启事务非常简单,只需在服务层的方法上添加 @Transactional 注解即可。

例如,假设我们有一个 UserService 接口,其中有一个保存用户的方法 saveUser():

复制代码
public interface UserService {
    void saveUser(User user);
}

我们希望在这个方法中开启事务,只需在该方法上添加 @Transactional 注解,如下所示:

复制代码
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Override
    @Transactional
    public void saveUser(User user) {
        userRepository.save(user);
    }
}

这样,当调用 saveUser() 方法时,Spring 就会自动为该方法开启一个事务。如果方法执行成功,事务会自动提交;如果方法执行失败,事务会自动回滚。

复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

#Springboot怎么做到导入就可以直接使用的?

这个主要依赖于自动配置、起步依赖和条件注解等特性。

起步依赖

起步依赖是一种特殊的 Maven 或 Gradle 依赖,它将项目所需的一系列依赖打包在一起。例如,spring-boot-starter-web 这个起步依赖就包含了 Spring Web MVC、Tomcat 等构建 Web 应用所需的核心依赖。

开发者只需在项目中添加一个起步依赖,Maven 或 Gradle 就会自动下载并管理与之关联的所有依赖,避免了手动添加大量依赖的繁琐过程。

比如,在 pom.xml 中添加 spring-boot-starter-web 依赖:

复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

自动配置

Spring Boot 的自动配置机制会根据类路径下的依赖和开发者的配置,自动创建和配置应用所需的 Bean。它通过 @EnableAutoConfiguration 注解启用,该注解会触发 Spring Boot 去查找 META - INF/spring.factories 文件。

spring.factories 文件中定义了一系列自动配置类,Spring Boot 会根据当前项目的依赖情况,选择合适的自动配置类进行加载。例如,如果项目中包含 spring-boot-starter-web 依赖,Spring Boot 会加载 WebMvcAutoConfiguration 类,该类会自动配置 Spring MVC 的相关组件,如 DispatcherServlet、视图解析器等。

开发者可以通过自定义配置来覆盖自动配置的默认行为。如果开发者在 application.propertiesapplication.yml 中定义了特定的配置,或者在代码中定义了同名的 Bean,Spring Boot 会优先使用开发者的配置。

条件注解

条件注解用于控制 Bean 的创建和加载,只有在满足特定条件时,才会创建相应的 Bean。Spring Boot 的自动配置类中广泛使用了条件注解,如 @ConditionalOnClass@ConditionalOnMissingBean 等。

比如,@ConditionalOnClass 表示只有当类路径中存在指定的类时,才会创建该 Bean。例如,在 WebMvcAutoConfiguration 类中,可能会有如下代码:

复制代码
@Configuration
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
public class WebMvcAutoConfiguration {
    // 配置相关的 Bean
}

这段代码表示只有当类路径中存在 ServletDispatcherServletWebMvcConfigurer 类时,才会加载 WebMvcAutoConfiguration 类中的配置。

#SpringBoot 过滤器和拦截器说一下?

在 Spring Boot 中,过滤器(Filter)和拦截器(Interceptor)是用于处理请求和响应的两种不同机制。

特性 过滤器(Filter) 拦截器(Interceptor)
规范/框架 Servlet规范(javax.servlet.Filter Spring MVC框架(org.springframework.web.servlet.HandlerInterceptor
作用范围 全局(所有请求、静态资源) Controller层(仅拦截Spring管理的请求)
执行顺序 在Servlet之前执行 在DispatcherServlet之后、Controller方法前后执行
依赖注入支持 无法直接注入Spring Bean(需间接获取) 支持自动注入Spring Bean
触发时机 doFilter()在请求前/响应后被调用 preHandlepostHandleafterCompletion分阶段触发
适用场景 全局请求处理(编码、日志、安全) 业务逻辑相关的处理(权限、参数校验)

过滤器是 Java Servlet 规范中的一部分,它可以对进入 Servlet 容器的请求和响应进行预处理和后处理。过滤器通过实现 javax.servlet.Filter 接口,并重写其中的 initdoFilterdestroy 方法来完成相应的逻辑。当请求进入 Servlet 容器时,会按照配置的顺序依次经过各个过滤器,然后再到达目标 Servlet 或控制器;响应返回时,也会按照相反的顺序再次经过这些过滤器。

拦截器是 Spring 框架提供的一种机制,它可以对控制器方法的执行进行拦截。拦截器通过实现 org.springframework.web.servlet.HandlerInterceptor 接口,并重写其中的 preHandlepostHandleafterCompletion 方法来完成相应的逻辑。当请求到达控制器时,会先经过拦截器的 preHandle 方法,如果该方法返回 true,则继续执行后续的控制器方法和其他拦截器;在控制器方法执行完成后,会调用拦截器的 postHandle 方法;最后,在请求处理完成后,会调用拦截器的 afterCompletion 方法。

过滤器和拦截器的区别如下:

  • 所属规范:过滤器是 Java Servlet 规范的一部分,而拦截器是 Spring 框架提供的机制。
  • 执行顺序:过滤器在请求进入 Servlet 容器后,在到达目标 Servlet 或控制器之前执行;拦截器在请求到达控制器之后,在控制器方法执行前后执行。
  • 使用范围:过滤器可以对所有类型的请求进行过滤,包括静态资源请求;拦截器只能对 Spring MVC 控制器的请求进行拦截。
  • 功能特性:过滤器主要用于对请求和响应进行预处理和后处理,如字符编码处理、请求日志记录等;拦截器可以更细粒度地控制控制器方法的执行,如权限验证、性能监控等。
相关推荐
fanged3 小时前
构建系统maven
java·maven
沙滩小岛小木屋3 小时前
maven编译时跳过test过程
java·maven
江沉晚呤时4 小时前
SQL Server 事务详解:概念、特性、隔离级别与实践
java·数据库·oracle·c#·.netcore
还是鼠鼠4 小时前
单元测试-概述&入门
java·开发语言·后端·单元测试·log4j·maven
一步一念4 小时前
Langchaine4j 流式输出 (6)
spring boot·ai·langchain4j
独行soc6 小时前
2025年渗透测试面试题总结-匿名[校招]高级安全工程师(代码审计安全评估)(题目+回答)
linux·安全·web安全·面试·职场和发展·渗透测试
MyikJ6 小时前
Java求职面试:从Spring到微服务的技术挑战
java·数据库·spring boot·spring cloud·微服务·orm·面试技巧
MyikJ6 小时前
Java 面试实录:从Spring到微服务的技术探讨
java·spring boot·微服务·kafka·spring security·grafana·prometheus
ShiinaMashirol7 小时前
代码随想录打卡|Day50 图论(拓扑排序精讲 、dijkstra(朴素版)精讲 )
java·图论
江城开朗的豌豆7 小时前
JavaScript篇:a==0 && a==1 居然能成立?揭秘JS中的"魔法"比较
前端·javascript·面试