超高频面试题系列之----Spring全家桶(面试亲测)

什么是Spring?

Spring是一个轻量级的Java框架,用于简化Java开发,它可以做很多事情,给企业级的开发提供丰富的功能,它的核心是IoC容器和AOP模块。
通过IoC容器管理POJO对象以及他们之间的耦合关系;通过AOP以动态非侵入的方式增强服务。IoC让相互协作的组件保持松散的耦合,而AOP编程允许你把遍布于应用各层的功能分离出来形成可重用的功能组件。

描述Spring Bean 的生命周期

  1. 解析类,得到BeanDefinition;
  2. 构造方法:如果有多个构造方法就要推断构造方法,确定好构造方法;
  3. 实例化,得到一个普通对象;
  4. 依赖注入:添加了@Autowired 注解的需要进行属性填充;
  5. 回调Aware方法,比如BeanNameAware,BeanFactoryAware;
  6. 初始化前调用BeanPostProcessor(@PostConstruct);
  7. 初始化InitializingBean;
  8. 初始化后:这里会进行AOP;
  9. 生成代理对象,如果是单例就放入单例池中;
  10. 使用Bean对象

Spring中常用的设计模式

  1. 工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
  2. 单例模式:Bean默认为单例模式。
  3. 代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
  4. 模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
  5. 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener。

什么是Spring IOC 容器?

控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的"控制反转"概念就是把直接操控对象的权利交给容器。

Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。

什么是AOP

AOP(Aspect-Oriented Programming),一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。

了解AOP中的动态代理吗?

Spring AOP 中的动态代理主要有两种方式,JDK 动态代理CGLIB 动态代理

①JDK 动态代理只提供接口的代理,不支持类的代理。核心 InvocationHandler 接口和 Proxy 类,InvocationHandler 通过 invoke()方法反射来调用 目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy 利用 InvocationHandler 动态创建一个符合某一接口的的实例, 生成目标类的代理对象。

②如果代理类没有实现 InvocationHandler 接口,那么 Spring AOP 会选择 使用 CGLIB 来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现 AOP。CGLIB 是通过继承的方式做的动态代理,因此如果某个类被标记为 final, 那么它是无法使用 CGLIB 做动态代理的。

BeanFactory 和 ApplicationContext有什么区别?

BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
BeanFactory: 是Spring里面最底层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。我们一般称之为 “低级容器”。

ApplicationContext 接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能。可以称之为 “高级容器”

加载方式:
BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。

创建方式:
BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。

注册方式:
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。

Spring框架中的单例bean是线程安全的吗?

不是,Spring框架中的单例bean不是线程安全的。
spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。

实际上大部分时候 spring bean 无状态的(比如 dao 类),所有某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象),那就要开发者自己去保证线程安全了,最简单的就是改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。

能说一个Spring的IoC的具体实现吗?

使用@Autowired注解自动装配:
在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

  • 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
  • 如果查询的结果不止一个,那么@Autowired会根据名称来查找;
  • 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

Spring 事务什么时候会失效?

首先我们要知道Spring 的事务也是通过AOP实现的,并且它依赖于数据库的事务;
Spring 事务的代理逻辑:
CGLIB动态代理会利用父子类关系,生成一个XXXProxy类 去继承当前的类,重写里面的方法;

  1. 执行的时候回先看是否有@Transactional 注解;
  2. 有就会在事务管理器中新建一个数据库连接 conn,没有就直接执行方法
  3. 将conn.autocommit = false;
  4. 执行方法 sql
  5. conn. rollback / conn.commit
    超高频面试题系列之----Spring全家桶(面试亲测)_第1张图片
    从以上的介绍就可以知道如果不是Bean对象,只是简单的Java对象 Spring事务就会失效
    失效的根本原因就是AOP失效

知道Spring 循环依赖吗?

spring的循环依赖指的就是A在初始化加载的时候需要B,B又需要有C,C又需要有A,就会出现循环依赖问题,这三个类互相引用,形成一个闭环;

要知道在Spring 的官网中介绍到了这个问题,构造器注入就产生循环依赖的问题,它建议我们使用Setter方法注入,就可以避免上述的问题;
超高频面试题系列之----Spring全家桶(面试亲测)_第2张图片
以下是Spring 创建Bean,怎么解决循环依赖问题的详细过程分析:
超高频面试题系列之----Spring全家桶(面试亲测)_第3张图片
超高频面试题系列之----Spring全家桶(面试亲测)_第4张图片
超高频面试题系列之----Spring全家桶(面试亲测)_第5张图片

什么是 Spring Boot?

SpringBoot提供了一种快速使用Spring的方式,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率。

Spring Boot 的核心注解是?

启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:

@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能;
@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项;
@ComponentScan:Spring组件扫描。

Spring Boot 自动配置原理是什么?

注解 @EnableAutoConfiguration, @AutoConfigurationPackage就是自动配置的核心,
@EnableAutoConfiguration 给容器导入META-INF/spring.factories 里定义的自动配置类。
筛选有效的自动配置类。
每一个自动配置类结合对应的 xxxProperties.java 读取配置文件进行自动配置功能

Spring Boot 中如何解决跨域问题 ?

跨域可以在前端通过 JSONP 来解决,但是 JSONP 只可以发送 GET 请求,无法发送其他类型的请求,在 RESTful 风格的应用中,就显得非常鸡肋,因此我们推荐在后端通过 (CORS,Cross-origin resource sharing) 来解决跨域问题。

直接在对应的Controller上添加@CrossOrigin即可

@RestController
//实现跨域注解
//origin="*"代表所有域名都可访问
//maxAge飞行前响应的缓存持续时间的最大年龄,简单来说就是Cookie的有效期 单位为秒若maxAge是负数,
//则代表为临时Cookie,不会被持久化,Cookie信息保存在浏览器内存中,浏览器关闭Cookie就消失
@CrossOrigin(origins = "*",maxAge = 3600)
@RequestMapping("/album")
public class AlbumController {}

Spring Cloud 中解决更加简单,只需要在spring Cloud Gateway 服务中添加配置就行

spring:
  application:
    name: system-gateway
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]': # 匹配所有请求
            allowedOrigins: "*" #跨域处理 允许所有的域
            allowedMethods: # 支持的方法
            - GET
            - POST
            - PUT
            - DELETE

Spring Cloud 常用的几大组件,介绍一下

Eureka注册中心
在我们使用的每一个微服务中定义一个Eureka Client(也就是在启动类上添加注解@EnableEurekaClient)这个组件专门负责将这个服务的信息注册到Eureka Server中。而Eureka Server是一个注册中心,里面有一个注册表,保存了各服务所在的机器和端口号

知道服务的信息了,但是我们每个微服务之间的调用不可能自己创建网络连接这个时候Feign就来了

Feign
Feign使用了动态代理的方式,你只要在对应的接口上添加注解@FeignClient(name = “XXXX”)Feign就会针对这个接口创建一个动态代理,接着你要是调用那个接口,本质就是会调用 Feign创建的动态代理,Feign的动态代理会根据你在接口上的@RequestMapping等注解,来动态构造出你要请求的服务的地址最后针对这个地址,发起请求、解析响应 完美的解决服务间接口调用的问题

但是问题又来了 微服务有多个服务器!Feign怎么知道该请求哪台机器呢?

Ribbon负载均衡
这时Spring Cloud Ribbon就派上用场了。Ribbon就是专门解决这个问题的。它的作用是负载均衡,会帮你在每次请求时选择一台机器,均匀的把请求分发到各个机器上,Ribbon默认使用的最经典的Round Robin轮询算法

用一张网上的图片方便大家的理解:
超高频面试题系列之----Spring全家桶(面试亲测)_第6张图片

Hystrix熔断器
在微服务系统中,每个系统之间都是有所关联的,如果其中的一个微服务挂掉了,那么其他服务难道要一直等待他的响应,这显然是不合理的,那我们就要思考改怎么解决呢?
这时就要用到Hystrix了,Hystrix是隔离、熔断以及降级的一个框架。
Hystrix会搞很多个小小的线程池,每个线程池里的线程就仅仅用于请求当前的那个服务。如果一个服务挂掉了,每次走到这里都会卡住,这就很没有意义,不如直接返回,这个过程,就是所谓的熔断

但是你直接返回,啥也不干也有点说不过去,所以就需要一个服务降级;比如
每次调用积分服务,你就在数据库里记录一条消息,说给某某用户增加了多少积分,因为积分服务挂了,导致没增加成功!这样等积分服务恢复了,你可以根据这些记录手工加一下积分。这个过程,就是所谓的降级

Gateway 网关
在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务的接口完成一个用户请求。这显然是不合理的,这个时候就引入了网关这个概念。

网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等
超高频面试题系列之----Spring全家桶(面试亲测)_第7张图片

你可能感兴趣的:(面试专项,分布式,java,开发语言)