当前位置: 首页 > news >正文

Java面试:Spring及Spring Cloud技术深度剖析

Spring及Spring Cloud技术深度剖析

前言

在Java开发领域,Spring框架一直是企业级应用开发的中流砥柱,而Spring Boot的出现更是极大地简化了Spring应用的开发过程。同时,Spring Cloud为构建分布式系统提供了强大的支持。本文将围绕Spring及Spring Cloud的一系列核心问题展开详细探讨,旨在帮助开发者深入理解这些技术的原理和应用。

1. Spring Boot与以前的Spring有什么区别

Spring是一个功能强大的Java开发框架,它提供了IoC(控制反转)和AOP(面向切面编程)等核心特性,帮助开发者构建企业级应用。然而,传统的Spring开发需要大量的配置文件,如XML配置,这使得项目的搭建和维护变得复杂。

Spring Boot则是为了解决这些问题而诞生的。它采用了“约定优于配置”的原则,通过自动配置机制,减少了开发者手动编写配置文件的工作量。Spring Boot还提供了嵌入式服务器,如Tomcat、Jetty等,使得应用可以像普通Java程序一样直接运行,无需额外的服务器配置。此外,Spring Boot集成了各种开发工具和插件,如Spring Initializr,方便开发者快速创建项目。

2. Spring Boot启动加载过程是什么样的

Spring Boot的启动过程主要包括以下几个步骤:

  1. 启动入口:Spring Boot应用的启动通常从一个带有@SpringBootApplication注解的主类开始,该注解是一个组合注解,包含了@Configuration@EnableAutoConfiguration@ComponentScan
  2. 创建SpringApplication实例:在主类的main方法中,调用SpringApplication.run()方法,该方法会创建一个SpringApplication实例。
  3. 初始化环境SpringApplication实例会初始化应用的运行环境,包括加载配置文件、解析命令行参数等。
  4. 创建ApplicationContext:根据应用类型(如Web应用或非Web应用)创建相应的ApplicationContext实例。
  5. 自动配置@EnableAutoConfiguration注解会触发Spring Boot的自动配置机制,根据类路径下的依赖和配置,自动配置Spring应用的各个组件。
  6. 注册BeanApplicationContext会扫描应用中的@Component@Service@Repository等注解的类,并将它们注册为Bean。
  7. 启动嵌入式服务器:如果是Web应用,Spring Boot会启动嵌入式服务器,如Tomcat或Jetty。
  8. 应用启动完成:所有的初始化工作完成后,Spring Boot应用启动完成,开始接收请求。

3. Spring的IOC/AOP的实现

IOC(控制反转)

IOC是Spring的核心特性之一,它将对象的创建和依赖关系的管理从代码中分离出来,交给Spring容器来处理。Spring的IOC容器通过BeanFactoryApplicationContext来实现。

BeanFactory是Spring IOC容器的基础接口,它提供了基本的Bean管理功能,如获取Bean、注册Bean等。ApplicationContextBeanFactory的子接口,它在BeanFactory的基础上提供了更多的功能,如国际化支持、事件发布等。

Spring的IOC容器通过读取配置文件(如XML配置或Java注解)来创建和管理Bean。当需要使用某个Bean时,只需要从容器中获取即可,而不需要手动创建对象。

AOP(面向切面编程)

AOP是Spring的另一个核心特性,它允许开发者在不修改原有代码的情况下,对程序的功能进行增强。AOP通过将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高了代码的可维护性和可复用性。

Spring的AOP实现基于动态代理,主要有两种方式:JDK动态代理和CGLIB动态代理。JDK动态代理基于接口实现,而CGLIB动态代理基于继承实现。

4. 动态代理的实现方式,是否使用过CGLiB,和JDK的区别是什么

动态代理的实现方式

动态代理是在运行时创建代理对象的一种技术,主要有两种实现方式:JDK动态代理和CGLIB动态代理。

JDK动态代理

JDK动态代理是Java提供的一种动态代理机制,它基于接口实现。使用JDK动态代理需要实现InvocationHandler接口,并重写invoke方法。在invoke方法中,可以对目标方法进行增强。

CGLIB动态代理

CGLIB是一个强大的、高性能的代码生成库,它可以在运行时扩展Java类和实现接口。CGLIB动态代理基于继承实现,它通过生成目标类的子类来实现代理。

区别

  • 实现方式:JDK动态代理基于接口实现,而CGLIB动态代理基于继承实现。
  • 性能:在调用次数较少的情况下,JDK动态代理的性能较好;在调用次数较多的情况下,CGLIB动态代理的性能较好。
  • 适用场景:JDK动态代理适用于目标对象实现了接口的情况,而CGLIB动态代理适用于目标对象没有实现接口的情况。

5. 何时使用JDK还是CGLiB?如何强制使用CGLIB实现AOP

何时使用JDK还是CGLiB

  • 使用JDK动态代理:当目标对象实现了接口时,建议使用JDK动态代理,因为它是Java原生的动态代理机制,性能较好。
  • 使用CGLIB动态代理:当目标对象没有实现接口时,只能使用CGLIB动态代理。

如何强制使用CGLIB实现AOP

在Spring中,可以通过配置proxy-target-class属性为true来强制使用CGLIB实现AOP。例如,在XML配置中可以这样配置:

<aop:aspectj-autoproxy proxy-target-class="true"/>

在Java配置中可以这样配置:

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {// 配置类内容
}

6. Spring在选择用JDK还是CGLiB的依据是什么?CGlib比JDK快?

选择依据

Spring在选择使用JDK还是CGLIB动态代理时,主要依据目标对象是否实现了接口。如果目标对象实现了接口,Spring默认使用JDK动态代理;如果目标对象没有实现接口,Spring会使用CGLIB动态代理。

CGlib比JDK快?

在调用次数较少的情况下,JDK动态代理的性能较好,因为它是Java原生的动态代理机制,不需要额外的类生成过程。在调用次数较多的情况下,CGLIB动态代理的性能较好,因为它在生成代理类时进行了优化,减少了方法调用的开销。

7. Spring如何解决循环依赖(三级缓存)

Spring通过三级缓存来解决循环依赖问题,三级缓存分别是:

  1. singletonObjects:单例对象缓存,用于存储已经创建好的单例对象。
  2. singletonFactories:单例工厂缓存,用于存储创建单例对象的工厂。
  3. earlySingletonObjects:提前暴露的单例对象缓存,用于存储还未完全初始化的单例对象。

当一个Bean被创建时,首先会将其对应的ObjectFactory放入singletonFactories中。如果在创建过程中发现有循环依赖,会从singletonFactories中获取对应的ObjectFactory,并调用其getObject()方法,将创建的早期对象放入earlySingletonObjects中。最后,当Bean完全初始化完成后,将其从earlySingletonObjects中移除,并放入singletonObjects中。

8. Spring中解决循环依赖为什么要用三级缓存,二级为什么不行呢?

使用三级缓存的主要原因是为了支持AOP。在创建Bean的过程中,如果需要进行AOP增强,需要在早期暴露的对象上进行代理。如果只有二级缓存,无法在早期暴露的对象上进行代理,因为此时对象还没有完全初始化。

通过三级缓存,Spring可以在早期暴露的对象上进行代理,并将代理对象放入earlySingletonObjects中。这样,在解决循环依赖时,就可以使用代理对象,而不是原始对象。

9. spring能解决那些循环依赖、不能解决那些循环依赖,为什么?

能解决的循环依赖

Spring可以解决单例Bean的循环依赖问题,无论是通过构造函数注入还是通过Setter方法注入。对于单例Bean,Spring通过三级缓存机制可以在对象还未完全初始化时就提前暴露对象,从而解决循环依赖问题。

不能解决的循环依赖

Spring不能解决原型Bean的循环依赖问题。因为原型Bean每次请求都会创建一个新的对象,Spring无法提前暴露对象,也就无法解决循环依赖问题。此外,如果循环依赖是通过构造函数注入的,并且使用了@Scope("prototype")注解,Spring也无法解决循环依赖问题。

10. Spring注入bean的方式有哪些

构造函数注入

构造函数注入是通过在类的构造函数中声明依赖的Bean来实现的。例如:

public class UserService {private UserRepository userRepository;public UserService(UserRepository userRepository) {this.userRepository = userRepository;}
}

Setter方法注入

Setter方法注入是通过在类中提供Setter方法来注入依赖的Bean。例如:

public class UserService {private UserRepository userRepository;public void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}
}

字段注入

字段注入是通过在类的字段上使用@Autowired注解来注入依赖的Bean。例如:

public class UserService {@Autowiredprivate UserRepository userRepository;
}

11. Spring的后置处理器分析

Spring的后置处理器是一种特殊的Bean,它可以在Bean的生命周期的不同阶段对Bean进行处理。Spring提供了两种类型的后置处理器:BeanFactoryPostProcessorBeanPostProcessor

BeanFactoryPostProcessor

BeanFactoryPostProcessor是在BeanFactory初始化完成后,但在Bean实例化之前执行的。它可以对BeanFactory中的Bean定义进行修改。例如,可以通过PropertySourcesPlaceholderConfigurer来替换配置文件中的占位符。

BeanPostProcessor

BeanPostProcessor是在Bean实例化和属性注入之后,但在初始化方法调用前后执行的。它可以对Bean进行增强,如添加代理、修改属性等。例如,ApplicationContextAwareProcessor可以在Bean中注入ApplicationContext

12. BeanFactory和ApplicationContext的联系和区别

联系

ApplicationContextBeanFactory的子接口,它继承了BeanFactory的所有功能,并提供了更多的特性,如国际化支持、事件发布等。

区别

  • 功能特性BeanFactory是Spring IOC容器的基础接口,提供了基本的Bean管理功能;ApplicationContextBeanFactory的基础上提供了更多的高级功能,如国际化支持、事件发布、AOP自动代理等。
  • 初始化方式BeanFactory是懒加载的,只有在需要使用Bean时才会创建;ApplicationContext是在启动时就会创建所有的单例Bean。
  • 使用场景BeanFactory适用于资源有限的环境,如嵌入式系统;ApplicationContext适用于大多数企业级应用开发。

13. 说说你对spring事务的理解

Spring事务是Spring框架提供的一种机制,用于管理数据库操作的一致性和完整性。通过Spring事务,可以将一组数据库操作作为一个原子操作来执行,要么全部成功,要么全部失败。

Spring事务的实现基于AOP,通过在方法执行前后进行事务的开启、提交或回滚操作来实现事务的管理。Spring提供了两种事务管理方式:编程式事务管理和声明式事务管理。

编程式事务管理

编程式事务管理需要在代码中手动编写事务管理的代码,如开启事务、提交事务、回滚事务等。这种方式比较灵活,但代码量较大,维护成本较高。

声明式事务管理

声明式事务管理是通过注解或XML配置来实现的,不需要在代码中手动编写事务管理的代码。这种方式代码简洁,维护成本较低,是Spring中推荐的事务管理方式。

14. Spring的@Transactional如何实现的

@Transactional是Spring提供的一个注解,用于声明式事务管理。它的实现基于AOP,主要步骤如下:

  1. 解析注解:Spring在启动时会扫描带有@Transactional注解的方法,并解析注解中的属性,如事务传播级别、事务隔离级别等。
  2. 创建代理对象:Spring会为带有@Transactional注解的类创建代理对象,在代理对象中插入事务管理的逻辑。
  3. 事务拦截:在调用带有@Transactional注解的方法时,代理对象会拦截该方法的调用,并在方法执行前后进行事务的开启、提交或回滚操作。
  4. 异常处理:如果方法执行过程中抛出异常,代理对象会根据异常类型和@Transactional注解的配置决定是否回滚事务。

15. Spring的事务传播级别

Spring的事务传播级别定义了在一个事务方法中调用另一个事务方法时,事务的行为。Spring提供了7种事务传播级别:

  1. PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  2. PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
  3. PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
  4. PROPAGATION_REQUIRES_NEW:创建一个新的事务,并挂起当前事务。
  5. PROPAGATION_NOT_SUPPORTED:以非事务方式执行,并挂起当前事务。
  6. PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  7. PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则创建一个新的事务。

16. Spring的事务隔离级别

Spring的事务隔离级别定义了一个事务对其他事务的可见性。Spring提供了4种事务隔离级别:

  1. ISOLATION_DEFAULT:使用数据库的默认隔离级别。
  2. ISOLATION_READ_UNCOMMITTED:允许读取未提交的数据,可能会导致脏读、不可重复读和幻读问题。
  3. ISOLATION_READ_COMMITTED:只允许读取已提交的数据,避免了脏读问题,但可能会导致不可重复读和幻读问题。
  4. ISOLATION_REPEATABLE_READ:确保在同一个事务中多次读取同一数据时,数据的结果是一致的,避免了脏读和不可重复读问题,但可能会导致幻读问题。
  5. ISOLATION_SERIALIZABLE:最高的隔离级别,确保所有事务依次执行,避免了脏读、不可重复读和幻读问题,但会降低并发性能。

17. Spring的事务失效场景分析

方法不是public的

@Transactional注解只能用于public方法上,如果用于非public方法,事务将失效。

异常被捕获但未抛出

如果在事务方法中捕获了异常但没有重新抛出,Spring无法感知到异常,不会进行事务回滚。

自调用问题

如果在同一个类中,一个方法调用另一个带有@Transactional注解的方法,事务将失效。因为Spring的事务管理是基于AOP的,自调用不会经过代理对象,所以事务注解不会生效。

数据库不支持事务

如果使用的数据库不支持事务,如MySQL的MyISAM引擎,Spring的事务管理将失效。

18. Spring的事务失效原因分析

注解配置问题

@Transactional注解的属性配置错误,或注解没有正确使用,可能导致事务失效。

AOP代理问题

Spring的事务管理是基于AOP的,如果AOP代理配置不正确,如没有开启AOP自动代理,或代理模式选择错误,可能导致事务失效。

数据库连接问题

如果数据库连接配置不正确,或数据库连接池出现问题,可能导致事务失效。

19. Spring Cloud Zuul网关的调优策略有哪些?怎么实现其高可用?Zuu和Gataway,你们项目中是怎么选择的?项目中对Zuul网关层的要求是什么样的?

调优策略

  • 线程池配置:调整Zuul的线程池大小,根据实际业务需求合理分配线程资源。
  • 超时配置:设置合理的请求超时时间,避免长时间等待导致资源浪费。
  • 缓存配置:使用缓存来减少重复请求,提高响应速度。
  • 限流配置:对请求进行限流,防止过多的请求导致系统崩溃。

高可用实现

可以通过部署多个Zuul实例,并使用负载均衡器(如Nginx)来实现Zuul的高可用。负载均衡器会将请求均匀地分发到各个Zuul实例上,当某个实例出现故障时,负载均衡器会自动将请求转发到其他正常的实例上。

Zuul和Gateway的选择

  • Zuul:Zuul是Netflix开源的网关组件,功能强大,有丰富的过滤器和插件。适用于已经使用Netflix生态系统的项目。
  • Gateway:Spring Cloud Gateway是Spring官方推出的网关组件,基于Reactor和Netty,性能更好,支持响应式编程。适用于基于Spring Cloud的新项目。

项目中对Zuul网关层的要求

  • 高性能:能够快速处理大量的请求,减少响应时间。
  • 高可用:具备容错和故障转移能力,确保系统的稳定性。
  • 安全性:提供身份验证、授权、限流等安全功能,保护后端服务。
  • 可扩展性:能够方便地添加新的过滤器和插件,满足业务需求的变化。

20. Spring Cloud Eureka和Nacos对比?怎么做选择?Eureka中高可用是怎么做的?进行的调优有哪些?原理是什么?

对比

  • 功能特性:Eureka是Netflix开源的服务发现组件,主要提供服务注册和发现功能;Nacos是阿里巴巴开源的服务发现和配置管理平台,除了服务注册和发现功能外,还提供了配置管理、动态路由等功能。
  • 性能:Nacos在性能上优于Eureka,尤其是在大规模服务注册和发现场景下。
  • 社区活跃度:Nacos的社区活跃度较高,有更多的用户和贡献者,更新和维护也比较及时。

选择

如果项目已经使用了Netflix的其他组件,如Zuul、Ribbon等,建议选择Eureka;如果项目需要更强大的功能,如配置管理、动态路由等,建议选择Nacos。

Eureka高可用实现

Eureka的高可用是通过多个Eureka Server实例之间的相互注册和同步来实现的。每个Eureka Server实例都可以作为其他实例的客户端,将自己的服务信息注册到其他实例上,并从其他实例上获取服务信息。

调优

  • 心跳间隔:调整服务实例向Eureka Server发送心跳的间隔时间,减少网络开销。
  • 服务过期时间:设置合理的服务过期时间,避免长时间未收到心跳的服务实例一直占用资源。
  • 缓存配置:使用缓存来减少Eureka Server的负载,提高响应速度。

原理

Eureka的原理基于客户端-服务器模式。服务实例作为客户端,将自己的服务信息注册到Eureka Server上;Eureka Server作为服务器,负责存储和管理服务信息,并提供服务发现功能。服务消费者可以从Eureka Server上获取服务提供者的信息,并进行调用。

21. Spring Cloud 中常用的注解有哪些?怎么用的?

@EnableEurekaClient

用于启用Eureka客户端功能,将服务注册到Eureka Server上。例如:

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

@EnableZuulProxy

用于启用Zuul网关代理功能。例如:

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

@FeignClient

用于创建Feign客户端,实现声明式的REST调用。例如:

@FeignClient(name = "my-service")
public interface MyServiceClient {@GetMapping("/api/data")String getData();
}

@HystrixCommand

用于为方法添加Hystrix熔断机制,当方法调用失败时,会执行fallback方法。例如:

@Service
public class MyService {@HystrixCommand(fallbackMethod = "fallback")public String getData() {// 调用远程服务return restTemplate.getForObject("http://my-service/api/data", String.class);}public String fallback() {return "Fallback data";}
}

22. Spring Cloud中的组件有哪些?具体说说?微服务架构中用到的关键技术有哪些?

Spring Cloud中的组件

  • Eureka:服务注册和发现组件,用于管理服务的注册和发现。
  • Zuul:网关组件,用于实现请求的路由和过滤。
  • Ribbon:负载均衡组件,用于实现客户端的负载均衡。
  • Feign:声明式的REST客户端,用于简化REST调用。
  • Hystrix:熔断和限流组件,用于保护服务的稳定性。
  • Config:配置管理组件,用于集中管理微服务的配置。
  • Gateway:新一代的网关组件,基于Reactor和Netty,性能更好。

微服务架构中用到的关键技术

  • 服务注册和发现:通过服务注册和发现机制,微服务可以动态地注册和发现其他服务。
  • 负载均衡:通过负载均衡技术,将请求均匀地分发到多个服务实例上,提高系统的性能和可用性。
  • 熔断和限流:通过熔断和限流机制,保护服务免受故障和过载的影响。
  • 配置管理:通过配置管理技术,集中管理微服务的配置,方便配置的更新和维护。
  • 消息队列:通过消息队列实现微服务之间的异步通信,提高系统的解耦性和可扩展性。

23. Spring Cloud Config配置架构是什么样的?可视化怎么做的?设计的业务有哪些?

配置架构

Spring Cloud Config的配置架构主要由三部分组成:

  • Config Server:配置服务器,用于存储和管理配置文件。可以从本地文件系统、Git仓库、SVN仓库等获取配置文件。
  • Config Client:配置客户端,用于从Config Server获取配置信息。在应用启动时,Config Client会自动从Config Server获取配置信息,并将其注入到应用中。
  • 配置仓库:用于存储配置文件的仓库,可以是本地文件系统、Git仓库、SVN仓库等。

可视化

可以使用Spring Cloud Config Dashboard来实现Spring Cloud Config的可视化管理。Spring Cloud Config Dashboard是一个基于Web的可视化工具,它可以方便地查看和管理配置信息。

设计的业务

  • 多环境配置管理:可以为不同的环境(如开发、测试、生产)配置不同的配置文件,方便管理和维护。
  • 动态配置更新:可以在不重启应用的情况下,动态更新配置信息,提高系统的灵活性和可维护性。
  • 配置共享:可以将公共的配置信息集中管理,供多个微服务共享使用。

参考书籍、文献和资料

  • 《Spring实战》
  • 《Spring Cloud微服务实战》
  • Spring官方文档:https://spring.io/docs
  • Spring Cloud官方文档:https://spring.io/projects/spring-cloud

总结

本文围绕Spring及Spring Cloud的核心问题进行了详细探讨,包括Spring Boot与传统Spring的区别、Spring Boot的启动加载过程、Spring的IOC/AOP实现、动态代理、循环依赖解决、Bean注入方式、后置处理器、事务管理、Spring Cloud的组件和注解等。通过深入理解这些技术的原理和应用,开发者可以更好地使用Spring和Spring Cloud来构建企业级应用和分布式系统。同时,在实际项目中,需要根据具体的业务需求和场景,选择合适的技术和配置,以提高系统的性能、可用性和可维护性。

相关文章:

  • 基于Springboot + vue + 爬虫实现的高考志愿智能推荐系统
  • Nacos源码—1.Nacos服务注册发现分析二
  • 驱动开发硬核特训 │ 深度解析 fixed regulator 驱动与 regulator_ops
  • Linux 命令行利用 speedtest 测速
  • MySQL 的覆盖索引是什么?
  • 8.Android(通过Manifest配置文件传递数据(meta-data))
  • 【lammps】后处理 log.lammps
  • 如何在idea 中写spark程序
  • Linux学习笔记(一):Linux下的基本指令
  • 详解RabbitMQ工作模式之简单模式
  • 天猫TP代运营服务商-品融电商:助力品牌破局增长的专业推手
  • 智慧健康养老实训室建设方案:科技引领养老健康服务人才培养
  • 技术与文化双轮驱动:数字化转型的核心要素
  • 运维实施27-Linux权限管理
  • OpenGL进阶系列21 - OpenGL SuperBible - blendmatrix 例子学习
  • Pytorch深度学习框架60天进阶学习计划 - 第53天:自监督学习范式(一)
  • C++?模板!!!
  • 深入浅出JavaScript常见设计模式:从原理到实战(2)
  • TMI投稿指南(二):投稿文章注意事项
  • 维安WAYON推出32位MCU:WY32F1030系列
  • 五一假期如何躺赚利息?来看国债逆回购操作攻略
  • 杨国荣︱学术上的立此存照——《故旧往事,欲说还休》读后
  • 国家卫健委:工作相关肌肉骨骼疾病、精神和行为障碍成职业健康新挑战
  • 银川市市长信箱被指已读乱回,官方回应
  • 美国政府将暂时恢复部分受影响留学生的合法身份,并将制订新标准
  • 申花四连胜领跑中超联赛,下轮榜首大战对蓉城将是硬仗考验