Spring
基础
spring的设计模式?
- 工厂模式:Spring 中 BeanFactory 和 ApplicationContext 的实现都使用了工厂模式,通过工厂方法来创建实例。
- 单例模式:Spring 默认情况下,所有的 Bean 都是单例的。Spring 容器中只会存在一个实例,不会重复创建。
- 代理模式:Spring 的 AOP 功能就是基于代理模式实现的。Spring AOP 通过代理的方式来实现横切逻辑。
- 模板方法模式:Spring 中的 JdbcTemplate 和 HibernateTemplate 等模板类,都使用了模板方法模式,提供了模板方法供用户使用,隐藏了一些细节。
- 观察者模式:Spring 中的事件驱动模型就是基于观察者模式实现的。事件源产生事件,事件监听器监听事件,当事件触发时,监听器会收到通知。
- 策略模式:Spring 中有一个 Resource 接口,它的不同实现类,会根据不同的策略去访问资源。
- 适配器模式:Spring MVC 中的 HandlerAdapter 就是适配器模式的应用。不同的处理器实现不同的接口,HandlerAdapter 将请求适配到合适的处理器上。
- 装饰者模式:Spring 中的装饰器模式应用比较广泛,比如通过 AOP 实现的装饰器模式,还有 Spring Security 中的 FilterChainProxy 也是基于装饰器模式实现的。
- 原型模式:Spring 也支持原型模式,可以通过配置将 Bean 的作用域设置为 prototype,每次请求都会创建一个新的实例。
springbean加载机制?(最开始问的其实是java bean怎么加载的)
Spring IoC
spring的核心功能(ioc,aop),详细介绍一下? +2
-
控制反转即IOC (Inversion of Control),它的核心思想是将对象的创建和依赖关系的维护交给框架来完成,降低对象之间的耦合度,提高代码的可复用性和可维护性。
-
Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。
Spring中IOC的底层过程 ioc原理 +2
Spring中IOC(Inversion of Control)的底层过程主要分为以下几个步骤:
- 定义Bean的配置文件
在Spring中,通常采用XML文件作为Bean的配置文件,也可以使用注解方式或Java Config的方式进行配置。在配置文件中,需要定义Bean的ID、类型以及相关的属性。
- 加载Bean配置文件
在Spring启动时,会根据配置文件路径加载Bean的配置文件,然后解析配置文件,创建Bean的定义信息(BeanDefinition),并将其保存在BeanFactory中。
- 创建Bean实例
在创建Bean的实例时,Spring采用了反射的方式进行创建,通过调用类的构造函数或工厂方法来创建实例。在创建实例时,Spring会检查Bean的作用域(Scope),如果是Singleton,则创建一个单例对象,并将其缓存起来。如果是Prototype,则每次请求Bean时都会创建一个新的实例。
- 设置Bean属性
在创建Bean实例后,Spring会根据配置文件中的属性信息,通过反射调用Setter方法或直接设置属性值,将Bean的属性注入到Bean实例中。
- 处理Bean之间的依赖关系
在创建Bean实例时,Spring会检查Bean之间的依赖关系,如果存在依赖,则通过自动装配或配置文件中的依赖注入方式,将依赖的Bean注入到当前Bean中。
- 初始化Bean
在Bean实例创建完成后,Spring会调用初始化方法,可以通过配置文件中的init-method属性来指定初始化方法。
- 提供Bean实例
最后,Spring将创建好的Bean实例提供给应用程序使用,应用程序可以通过获取BeanFactory中的Bean实例来使用它们。
总的来说,Spring的IOC容器在启动时会根据配置文件定义的Bean信息,创建Bean实例并维护Bean之间的依赖关系,从而实现Bean的管理和注入。通过IOC,应用程序将不再依赖具体的实现类,而是依赖抽象的接口或父类,使得应用程序更加灵活和可扩展。
Spring容器的初始化过程
Condition注解用过吗
Autowired注解是利用什么机制
Bean的前后置操作如何实现的,有没有在项目中使用到
什么是 Spring Bean?
简单来说,Bean 代指的就是那些被 IoC 容器所管理的对象。
将一个类声明为 Bean 的注解有哪些?
@Component:通用的注解,可标注任意类为Spring组件。如果一个 Bean 不知道属于哪个层,可以使用@Component注解标注。@Repository: 对应持久层即 Dao 层,主要用于数据库相关操作。@Service: 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。@Controller: 对应 Spring MVC 控制层,主要用于接受用户请求并调用Service层返回数据给前端页面。
bean的生命周期详细说一下?
bean的生命周期很简单。使用Java关键字new进行bean实例化,然后该bean就可以使用了。一旦该bean不再被使用,则由Java自动进行垃圾回收。
singleton和prototype的适用场景有哪些?
在Spring中,Bean的作用域可以通过scope属性进行配置,常用的作用域包括Singleton和Prototype。
Singleton指的是一个Bean在整个应用中只会被创建一次,之后所有请求该Bean的请求都会返回同一个实例。Prototype则是每次请求该Bean时都会创建一个新的实例。
适用场景方面,一般来说,当Bean的状态不变且需要共享时,可以使用Singleton作用域。比如一些工具类、配置类等。而对于状态变化比较频繁,且不需要共享的Bean,可以使用Prototype作用域。比如一些DAO、Service等。
Resource和AutoWrited的区别
@Autowired是 Spring 提供的注解,@Resource是 JDK 提供的注解。@Autowired默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为byName(根据名称进行匹配)。- 当一个接口存在多个实现类的情况下,
@Autowired和@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired可以通过@Qualifier注解来显式指定名称,@Resource可以通过name属性来显式指定名称。
单例 Bean 的线程安全问题了解吗?
常见的有两种解决办法:
- 在 Bean 中尽量避免定义可变的成员变量。
- 在类中定义一个
ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中(推荐的一种方式)。
不过,大部分 Bean 实际都是无状态(没有实例变量)的(比如 Dao、Service),这种情况下, Bean 是线程安全的。
Spring AOP
讲讲spring的aop +2
- AOP(Aspect-Oriented Programming),一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。
(chat)Spring中AOP的底层实现 +3
Spring中的AOP底层实现主要是基于动态代理技术和字节码生成技术来实现的。
Spring支持两种AOP实现方式:基于JDK的动态代理和基于CGLIB的动态代理。默认情况下,Spring会自动选择使用哪种代理方式。
基于JDK的动态代理
JDK的动态代理是Java自带的一种动态代理技术,它只能对实现了接口的类生成代理对象。它的底层实现是通过反射技术来生成代理类。JDK动态代理创建代理对象的过程如下:
- 创建一个实现了InvocationHandler接口的代理处理器对象,它负责连接目标对象和代理对象的调用。
- 通过Proxy类的newProxyInstance()方法,传入目标对象的类加载器、目标对象实现的所有接口以及代理处理器对象,生成代理对象。
- 当调用代理对象的方法时,实际上是在调用InvocationHandler的invoke()方法,然后由它调用目标对象的方法。
基于CGLIB的动态代理
CGLIB(Code Generation Library)是一个基于ASM框架的字节码生成库,它可以在运行时动态地生成字节码,并生成代理对象。CGLIB可以对任意类生成代理对象,不需要实现接口,因此被代理的类不需要实现任何接口。CGLIB动态代理创建代理对象的过程如下:
- 创建一个MethodInterceptor接口的实现类,它负责连接目标对象和代理对象的调用。
- 通过Enhancer类的create()方法,传入目标对象的类和实现MethodInterceptor接口的代理处理器对象,生成代理对象。
- 当调用代理对象的方法时,实际上是在调用MethodInterceptor的intercept()方法,然后由它调用目标对象的方法。
无论是基于JDK的动态代理还是基于CGLIB的动态代理,Spring都是通过AOP代理工厂(AopProxyFactory)来创建代理对象的。当Spring容器创建一个需要被代理的bean时,它会根据配置信息,决定使用哪种代理方式,然后创建一个AopProxyFactory实例来生成代理对象。这个代理对象包含了所有的通知(Advice)和目标对象的引用,当调用代理对象的方法时,它会在方法调用前后执行通知的逻辑。
怎么使用Aop?
spring aop的动态代理怎么实现?以及他们的区别
Spring 的 AOP 是通过动态代理open in new window来实现的,动态代理主要有两种方式 JDK 动态代理和 Cglib 动态代理,这两种动态代理的使用和原理有些不同。
JDK 动态代理
- Interface:对于 JDK 动态代理,目标类需要实现一个 Interface。
- InvocationHandler:InvocationHandler 是一个接口,可以通过实现这个接口,定义横切逻辑,再通过反射机制(invoke)调用目标类的代码,在次过程,可能包装逻辑,对目标方法进行前置后置处理。
- Proxy:Proxy 利用 InvocationHandler 动态创建一个符合目标类实现的接口的实例,生成目标类的代理对象。
CgLib 动态代理
- 使用 JDK 创建代理有一大限制,它只能为接口创建代理实例,而 CgLib 动态代理就没有这个限制。
- CgLib 动态代理是使用字节码处理框架 ASM,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
- CgLib 创建的动态代理对象性能比 JDK 创建的动态代理对象的性能高不少,但是 CGLib 在创建代理对象时所花费的时间却比 JDK 多得多,所以对于单例的对象,因为无需频繁创建对象,用 CGLib 合适,反之,使用 JDK 方式要更为合适一些。同时,由于 CGLib 由于是采用动态创建子类的方法,对于 final 方法,无法进行代理。
MVC
说说自己对于 Spring MVC 了解? +1
Spring MVC 是基于 MVC(Model-View-Controller)设计模式的 Web 框架,主要用于构建 Web 应用程序。模型表示应用程序中使用的数据和业务逻辑,视图表示用户界面,控制器处理用户输入并作出响应。
Spring MVC 的核心组件有哪些?
记住了下面这些组件,也就记住了 SpringMVC 的工作原理。
DispatcherServlet:核心的中央处理器,负责接收请求、分发,并给予客户端响应。HandlerMapping:处理器映射器,根据 uri 去匹配查找能处理的Handler,并会将请求涉及到的拦截器和Handler一起封装。HandlerAdapter:处理器适配器,根据HandlerMapping找到的Handler,适配执行对应的Handler;Handler:请求处理器,处理实际请求的处理器。ViewResolver:视图解析器,根据Handler返回的逻辑视图 / 视图,解析并渲染真正的视图,并传递给DispatcherServlet响应客户端
SpringMVC 工作原理了解吗?
- 客户端(浏览器)发送请求,
DispatcherServlet拦截请求。 DispatcherServlet根据请求信息调用HandlerMapping。HandlerMapping根据 uri 去匹配查找能处理的Handler(也就是我们平常说的Controller控制器) ,并会将请求涉及到的拦截器和Handler一起封装。DispatcherServlet调用HandlerAdapter适配执行Handler。Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息。Model是返回的数据对象,View是个逻辑上的View。ViewResolver会根据逻辑View查找实际的View。DispaterServlet把返回的Model传给View(视图渲染)。- 把
View返回给请求者(浏览器)
MVC的使用,一些注解的信息、为什么分布式session还有没有其他解决方案、
事务
Spring 管理事务的方式有几种?
- 编程式事务管理:是指在代码中显式地通过编程实现事务管理。它需要开发者手动编写事务控制代码,通过编程控制事务的开启、提交、回滚等行为。虽然可以非常灵活地控制事务,但是代码可读性差、维护性低、耦合度高等问题也比较明显。
- 声明式事务管理:是指通过配置的方式实现事务管理,不需要在代码中显式地控制事务,只需在配置文件中声明哪些方法需要事务管理即可。Spring AOP就是利用动态代理技术实现声明式事务管理的。这种方式可以将事务管理代码和业务逻辑代码分离,使得代码更加简洁、清晰,并且能够提高代码的可读性和可维护性。
什么时候加事务注解?
在 Spring 中,使用事务注解的前提是对于某个方法需要使用事务。事务可以保证一组操作要么全部成功,要么全部失败回滚。一般来说,在以下场景需要加上事务注解:
- 数据库操作:如果一个方法需要对数据库进行操作,可能会引发异常,从而导致部分数据没有成功操作,此时需要在方法上加上事务注解,保证整个操作是原子性的,要么全部成功,要么全部失败回滚。
- 多个操作的原子性:如果一个方法中有多个操作,需要保证这些操作全部执行成功或者全部不执行,此时需要加上事务注解。
- 方法嵌套:如果一个方法调用了其他方法,这些方法也需要加上事务注解,以保证整个方法调用链都处于同一个事务中。
分布式事务是否能保证一致性?这里g
分布式事务旨在协调多个数据库或服务之间的事务,以确保数据一致性和完整性。它涉及到多个独立的事务处理系统,每个系统在自己的本地执行一个事务,并且在跨系统之间协调这些事务。
在分布式系统中,有很多因素可能导致事务不一致,例如网络通信问题、机器宕机、数据丢失等。因此,分布式事务不能完全保证数据一致性。
为了解决这个问题,常见的做法是采用柔性事务(例如 TCC、Saga 等)或者是幂等性设计等方式来避免数据一致性问题。
Spring 事务中的隔离级别有哪几种?
和事务传播行为这块一样,为了方便使用,Spring 也相应地定义了一个枚举类:Isolation
TransactionDefinition.ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,MySQL 默认采用的REPEATABLE_READ隔离级别 Oracle 默认采用的READ_COMMITTED隔离级别.TransactionDefinition.ISOLATION_READ_UNCOMMITTED:最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
@Transactional(rollbackFor = Exception.class)注解了解吗?
Exception 分为运行时异常 RuntimeException 和非运行时异常。事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。
当 @Transactional 注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解,那么这个类里面的方法抛出异常,就会回滚,数据库里面的数据也会回滚。
在 @Transactional 注解中如果不配置rollbackFor属性,那么事务只会在遇到RuntimeException的时候才会回滚,加上 rollbackFor=Exception.class,可以让事务在遇到非运行时异常时也回滚。
SpringBoot +2
SpringBoot和spring有什么差别?
spring旨在简化JavaEE开发。
Spring Boot 是 Spring 框架的一种快速开发框架,是用来简化spring的。
Springboot的核心配置文件
.yml/.properties的区别(√)
Spring Boot 的核心配置文件是 application.properties 或 application.yml,位于项目的 src/main/resources 目录下。这些配置文件可以配置一些常用的配置项,如服务器端口号、数据库连接等,Spring Boot 应用会自动读取并使用这些配置。
Spring Boot 配置加载顺序?
- 1.properties文件;
- 2.YAML文件;
- 3.系统环境变量;
- 4.命令行参数;
Spring Boot中的Starter
springboot mybatis starter,springboot redis start是什么原理
在 Spring Boot 中,Starter 是一种依赖管理方式,它通过提供一组相关的依赖,使得开发者在使用 Spring Boot 进行开发时可以更加方便快捷地引入所需的功能和组件。
例如,Spring Boot 提供了名为 spring-boot-starter-web 的 Starter,它包含了构建 Web 应用所需的所有依赖。
@SpringBootApplication(√)
@SpringBootApplication 是一个注解,它是 Spring Boot 的核心注解之一。它组合了以下三个注解:
- @Configuration:标明该类使用 Spring 基于 Java 的配置。
- @EnableAutoConfiguration:告诉 Spring Boot 自动配置功能启用,这样可以根据添加的 jar 包依赖自动配置项目,比如自动配置数据源、事务管理器等等。
- @ComponentScan:告诉 Spring 在哪里扫描组件。
简单来说,@SpringBootApplication 是一个复合注解,等价于在一个类上同时添加了 @Configuration、@EnableAutoConfiguration 和 @ComponentScan 三个注解。它标注的类通常是 Spring Boot 应用的入口类。
SpringBoot的优点
- 快速构建应用:Spring Boot 提供了很多自动化配置和开箱即用的组件,可以快速构建一个可运行的应用程序。
- 简化配置:Spring Boot 的自动化配置特性,能够帮助开发者自动配置 Spring 框架和第三方库,减少了配置的繁琐和复杂度。
- 内嵌 Web 服务器:Spring Boot 支持内嵌 Tomcat、Jetty 和 Undertow 等常用 Web 服务器,无需额外部署,便于应用程序的部署和运行。
- 生态系统丰富:Spring Boot 已经成为了 Spring 生态系统的一部分,拥有大量的社区支持和第三方库,能够快速地集成 Spring 生态系统中的各种组件和工具。
- Spring Boot 可以快速整合常用依赖(开发库,例如 spring-webmvc、jackson-json、validation-api 和 tomcat 等),提供的 POM 可以简化 Maven 的配置。当我们引入核心依赖时,SpringBoot 会自引入其他依赖。
- 健康检查和监控:Spring Boot 提供了丰富的健康检查和监控功能,开发者可以快速地集成监控系统和日志系统,提高应用程序的可靠性和可维护性。
那springcloud和SpringBoot的差别呢?
SpringBoot是快速开发的Spring框架,SpringCloud是完整的微服务框架,SpringCloud依赖于SpringBoot。
(chat)springcloud都有什么组件实现什么功能?
Spring Cloud 是一个基于 Spring Boot 的分布式系统开发工具包,主要用于开发分布式应用程序,它为开发人员提供了在分布式系统中构建和管理应用程序所需的工具和服务。
Spring Cloud 主要包含以下组件:
- 服务注册与发现:Eureka、Consul、Zookeeper;
- 客户端负载均衡:Ribbon、LoadBalancer;
- 服务熔断器:Hystrix;
- 网关路由:Zuul、Gateway;
- 配置中心:Config;
- 分布式消息传递:Spring Cloud Stream、Kafka、RabbitMQ;
- 分布式跟踪:Sleuth、Zipkin;
- 服务调用:Feign、RestTemplate;
- 服务安全:Spring Security。
这些组件分别实现了服务注册与发现、负载均衡、熔断、路由、配置中心、消息总线、分布式追踪、服务调用和安全等功能。通过这些组件,开发者可以快速构建高可用、高性能、高安全性的分布式应用程序。
Hibernate和mybatis两者的区别是什么?Hibernate的具体使用流程是什么样的?
mybatis一二级缓存?适用那些场景?
还有前后端分离协议和跨域请求
前后端分离是一种应用架构模式,前端通过异步请求获取后端数据并展示,后端提供接口服务,实现前后端的分离。在前后端分离的应用中,通常使用 RESTful API 作为协议来进行数据交互。
跨域请求是指在一个网页中请求另一个域名下的资源,由于浏览器同源策略的限制,直接跨域请求是不允许的。为了解决这个问题,通常使用以下几种方式:
- JSONP:利用 script 标签可以跨域加载资源的特性,在后端生成一个带有回调函数参数的 JavaScript 脚本,前端通过 script 标签加载该脚本,并在回调函数中获取数据。
- CORS:跨域资源共享,需要在后端设置响应头来允许跨域请求,前端无需任何特殊处理。
- 代理服务器:在同源策略限制下,通过在自己的服务器上设置代理,将请求发送到目标服务器上并将结果返回给前端,前端只需请求自己的服务器。
- WebSocket:通过建立 WebSocket 连接,客户端与服务器可以进行双向通信,跨域请求也可以通过 WebSocket 实现。
总的来说,跨域请求在前后端分离的应用中是非常常见的,开发者需要根据具体情况选择合适的方式来解决跨域问题。
异步请求遇到过吗
异步请求通常指的是通过异步方式发送的HTTP请求。传统的HTTP请求是同步的,也就是说,当客户端发送请求时,客户端会一直等待服务器的响应,直到服务器响应完毕才会继续执行下一步操作。而异步请求则不同,客户端发送请求后,不必等待服务器响应,可以继续执行其他操作。当服务器响应完毕后,客户端会得到一个通知,然后再去处理服务器的响应。
在Web开发中,异步请求可以提高页面的响应速度和用户体验。常见的异步请求方式包括Ajax、WebSocket等。在Spring框架中,可以通过异步处理机制来实现异步请求的处理,比如使用@Async注解实现方法异步调用,或者使用DeferredResult实现异步响应等。
springboot的优势 10.springboot如何进行自动装配?(忘了,面试官跟我详细讲解了一番) 11.mybatis里的mapper接口没有实现为什么不报错,@Autowired注入的是什么?(不是很懂,答得注入了代理对象)
SpringBoot那些特性?为什么要用SpringBoot?