1、什么是spring?
Spring是一个Java开发框架,它提供了一种可扩展的模型来开发Java应用程序。Spring框架的目标是提供一个全面的解决方案,用于构建企业级应用程序。Spring框架的核心特点包括依赖注入(DI)、面向切面编程(AOP)、声明式事务管理、MVC框架等。
Spring框架的核心是Spring容器,它是一个负责管理应用程序中的对象的容器。容器使用依赖注入技术来自动注入依赖项,使得开发者可以专注于编写应用程序的业务逻辑而不必关心对象创建和管理的细节。此外,Spring框架还提供了很多其他的功能和扩展,例如Spring Security、Spring Data等,可以让开发者更加容易地开发出高质量的Java应用程序。
2、Autowired和Resource关键字的区别?
@Autowired和@Resource都是用于在Spring容器中自动装配Bean的关键字,它们的作用相似,但是存在一些区别。
@Autowired注解是Spring提供的一种基于类型的自动装配方式。它可以用于自动装配Spring容器中所有可以类型匹配的Bean。当有多个Bean与要装配的类型匹配时,Spring会尝试根据Bean的名称来进行匹配。如果仍然无法确定装配哪个Bean,则会抛出异常。
@Resource注解是J2EE提供的一种基于名称的自动装配方式。它可以用于自动装配Spring容器中指定名称的Bean。如果未指定名称,则会按照变量名进行匹配。如果有多个Bean与名称匹配,Spring会尝试根据Bean的类型来进行匹配。如果仍然无法确定装配哪个Bean,则会抛出异常。
因此,主要的区别在于:
Autowired是基于类型的自动装配,而Resource是基于名称的自动装配。
Autowired是Spring提供的注解,而Resource是J2EE提供的注解。
在实际使用中,如果Bean的名称与变量名不同,或者存在多个Bean与类型或名称匹配,建议使用@Resource注解来指定具体的Bean名称,以避免出现错误。
3、依赖注入的方式有几种,各是什么?
依赖注入的方式有三种,分别是:
1.构造函数注入(Constructor Injection):通过在类的构造函数中声明需要注入的依赖项,容器会在创建对象时自动将依赖项注入到构造函数中。
2.Setter方法注入(Setter Injection):通过在类中声明Setter方法,并在方法中传入需要注入的依赖项,容器会在创建对象后自动调用Setter方法注入依赖项。
3.字段注入(Field Injection):通过在类中声明需要注入的依赖项的字段,并在字段上使用注解(如@Autowired、@Resource等)来标识需要注入的依赖项,容器会在创建对象后自动注入依赖项。
4、讲一下什么是Spring容器?
Spring容器是Spring框架的核心部分,它负责管理Spring应用程序中所有的Bean对象。Spring容器提供了一个容器环境,将应用程序中的对象、组件和其他元素组织起来,并协调它们之间的交互。在Spring容器中,所有的对象都是由容器进行创建、组装和管理的,应用程序只需要通过依赖注入(DI)的方式获取需要的Bean对象即可。
Spring容器的主要作用包括:
实例化和管理Bean对象:Spring容器负责创建和管理应用程序中所有的Bean对象,并且可以在需要时对这些对象进行初始化、销毁、缓存等操作,以确保应用程序能够正确地运行。
提供依赖注入(DI)支持:Spring容器通过依赖注入的方式将应用程序中的各个组件和对象连接起来,从而实现了对象之间的松耦合,使应用程序更加灵活和易于维护。
提供AOP支持:Spring容器提供了AOP(面向切面编程)的支持,使得应用程序可以更加方便地实现横切关注点的编程,如事务管理、日志记录、安全控制等。
提供声明式事务管理支持:Spring容器提供了声明式事务管理的支持,使得应用程序可以更加方便地管理数据库事务,从而提高了应用程序的可靠性和性能。
Spring容器主要有两种实现方式:
BeanFactory容器:BeanFactory是Spring容器的基本实现,提供了最基本的依赖注入和生命周期管理功能。它是一个轻量级的容器,仅在需要时才会对Bean进行初始化。
ApplicationContext容器:ApplicationContext是BeanFactory的子类,提供了更丰富的功能,如国际化、事件处理、资源访问等。ApplicationContext在启动时就会对Bean进行初始化,因此启动时间较长,但在应用程序运行时可以提供更快的响应速度。同时,ApplicationContext也是Spring容器的推荐实现方式。
5、说说你对Spring MVC的理解
Spring MVC是Spring框架的一个重要组成部分,它是一种基于MVC(Model-View-Controller)设计模式的Web框架,用于构建Web应用程序。Spring MVC通过提供一系列标准化的接口和类,使得开发者可以更加方便地实现Web应用程序的开发和管理。
Spring MVC的主要组件包括:
控制器(Controller):负责处理用户请求,并将请求转发给相应的服务层进行处理。
视图(View):负责渲染模型数据,并将结果返回给客户端。
模型(Model):负责封装数据,并将数据传递给视图进行展示。
Spring MVC的工作流程如下:
客户端发送请求到DispatcherServlet。
DispatcherServlet将请求转发给HandlerMapping,寻找匹配的Controller。
HandlerMapping将请求映射到相应的Controller。
Controller处理请求,并将处理结果封装到ModelAndView中。
ModelAndView被传递给ViewResolver,由ViewResolver根据视图名称解析出对应的视图。
视图将模型数据渲染成HTML,并将结果返回给客户端。
6、SpringMVC常用的注解有哪些?
SpringMVC常用的注解包括:
@Controller:标识一个类为SpringMVC的控制器,处理用户请求。
@RequestMapping:将请求映射到对应的处理方法上,可以用于类和方法上。可指定HTTP请求方法(GET、POST等)、URL路径等属性。
@RequestParam:绑定请求参数到方法参数上,可以指定参数名、是否必需等属性。
@PathVariable:用于从URL路径中获取参数值,将参数值绑定到方法参数上。
@ResponseBody:将方法返回值直接作为响应体返回给客户端,常用于返回JSON、XML等数据格式。
@RequestBody:将请求体中的数据绑定到方法参数上,常用于接收JSON、XML等数据格式的请求。
@ModelAttribute:将请求参数绑定到一个JavaBean对象上,常用于表单提交。
@SessionAttribute:将指定名称的属性存储到会话(Session)中,常用于跨请求共享数据。
@CookieValue:将请求中指定名称的Cookie值绑定到方法参数上。
@Valid:用于数据校验,常用于表单提交。配合javax.validation包中的注解一起使用,如@NotNull、@Size、@Pattern等。
@ExceptionHandler:用于处理指定类型的异常,常用于统一处理异常信息。
以上注解是SpringMVC开发中常用的注解,使用它们可以简化代码开发,提高代码的可读性和可维护性。
7、谈谈你对Spring的AOP理解
在Spring框架中,AOP(Aspect-Oriented Programming)是一个重要的模块,它允许开发者通过切面(Aspect)的方式,将系统中的关注点(Concern)从核心业务逻辑中分离出来,以达到提高系统模块化、可维护性和可扩展性的目的。
AOP主要基于以下几个核心概念:
切面(Aspect):一个横跨多个核心逻辑的功能,即横切关注点。例如,日志、安全、事务等。
连接点(Join Point):程序执行过程中可以插入切面的点,例如,方法调用、异常处理、属性设置等。
切入点(Pointcut):一组匹配连接点的规则,用于确定哪些连接点应该被切面处理。
通知(Advice):切面在连接点处执行的操作,包括前置通知、后置通知、环绕通知、异常通知和最终通知等。
切面执行顺序(Ordering):多个切面对同一个连接点进行处理时,需要确定它们的执行顺序。
在Spring框架中,AOP的实现主要基于动态代理和字节码生成技术,通过在运行时生成代理对象,来实现对目标对象的方法进行拦截和增强。开发者可以通过声明式的方式配置AOP,将切面和通知应用到目标对象上,而不需要在代码中显式地进行调用。
总之,Spring的AOP能够提高代码的可维护性、可扩展性和可重用性,使得系统中的各个模块可以更加独立、聚焦,从而提高系统的整体质量和效率。
8、Spring AOP和AspectJ AOP有什么区别?
Spring AOP和AspectJ AOP是两种不同的AOP实现方式,它们的区别主要在以下几个方面:
实现方式:Spring AOP是基于代理的AOP实现,它是通过在运行时动态生成代理对象来实现对目标对象方法的拦截和增强;而AspectJ AOP是基于字节码增强的AOP实现,它是通过在编译期间修改目标类的字节码来实现对目标对象的方法拦截和增强。
支持的切入点表达式:Spring AOP仅支持基于方法级别的切入点表达式,如execution、within、this、target等;而AspectJ AOP支持更加丰富的切入点表达式,包括基于方法、字段、构造器等不同级别的切入点表达式,以及复合切入点表达式、逻辑切入点表达式等。
对于静态方法和final方法的支持:Spring AOP无法拦截静态方法和final方法;而AspectJ AOP可以拦截静态方法和final方法。
集成方式:Spring AOP是Spring框架的一部分,与Spring IoC容器紧密集成,方便在Spring应用中使用;而AspectJ AOP是独立的AOP框架,需要单独引入和配置。
总之,Spring AOP相对简单、易用,可以与Spring框架紧密集成;而AspectJ AOP相对强大、灵活,支持更多的切入点表达式和拦截方式,但需要单独引入和配置。具体使用哪种AOP实现方式,需要根据实际业务需求和技术场景进行选择。
9、在Spring AOP 中,关注点和横切关注的区别是什么?
在Spring AOP中,关注点和横切关注是AOP的两个重要概念,它们之间的区别如下:
关注点(Concern):关注点是指在软件系统中需要模块化的功能或需求,例如日志、事务、安全、缓存等,一个系统通常有多个关注点。关注点定义了系统的功能需求,可以被抽象为一组类或方法。在AOP中,关注点可以视为被横切的对象。
横切关注(Cross-cutting Concerns):横切关注是指那些与业务逻辑无关,但是多个模块或层次共同使用的功能或需求,例如日志、事务、安全、缓存等,这些功能横跨多个模块和层次,不易被封装到单个模块中。在AOP中,横切关注是指在系统中被多个关注点共享的行为,它们可以通过AOP的方式进行统一实现和管理。
因此,关注点是指在系统中需要模块化的功能或需求,而横切关注是指跨越多个模块和层次的通用功能或需求。在AOP中,横切关注可以通过切面的方式进行统一管理和实现,从而提高代码的复用性和可维护性。
10、什么是通知呢?有哪些类型呢?
通知(Advice)是指在目标对象的方法执行过程中,AOP框架注入的一段代码,它可以在目标对象方法执行前、执行后、抛出异常等不同的执行时机进行拦截和增强,从而实现横切关注的功能。
在Spring AOP中,通知可以分为以下几种类型:
前置通知(Before Advice):在目标对象方法执行之前执行的通知,可以用于打印日志、权限检查、性能监控等场景。
后置通知(After Returning Advice):在目标对象方法执行之后执行的通知,可以用于打印返回结果、清理资源等场景。
环绕通知(Around Advice):在目标对象方法执行之前和之后都可以执行的通知,可以用于在目标对象方法执行前进行前置处理,执行后进行后置处理,也可以控制目标对象方法的执行过程。
异常通知(After Throwing Advice):在目标对象方法抛出异常后执行的通知,可以用于记录异常日志、异常处理等场景。
最终通知(After Advice):在目标对象方法执行之后无论是否抛出异常都会执行的通知,可以用于清理资源、释放锁等场景。
在AOP中,通知是实现横切关注的关键,通过注入不同类型的通知,可以实现对目标对象方法不同阶段的拦截和增强。
11、解释一下spring bean的生命周期
首先是实例化、属性赋值、初始化、销毁这 4 个大阶段;
再是初始化的具体操作,有 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始化操作;
销毁的具体操作,有注册相关销毁回调接口,最后通过DisposableBean 和 destory-method 进行销毁。
12、解释Spring支持的几种bean的作用域?
Spring框架支持以下五种作用域:
singleton:默认的作用域,每个Bean在整个应用中只有一个实例,所有对Bean的请求都返回同一个对象实例。
prototype:每次请求Bean时,容器都会创建一个新的Bean实例,并返回给请求者。
request:每个HTTP请求都会创建一个新的Bean实例,Bean实例将绑定到HTTP请求的生命周期内,当请求结束时,Bean实例也会被销毁。
session:每个HTTP会话都会创建一个新的Bean实例,Bean实例将绑定到HTTP会话的生命周期内,当会话结束时,Bean实例也会被销毁。
global-session:它是为Portlet环境准备的作用域,它允许多个Portlet共享一个全局的HTTP会话,它的生命周期是整个Web应用的生命周期。
其中,singleton作用域是默认的作用域,也是最常用的作用域。对于一些比较轻量的Bean,如工具类等,使用singleton作用域可以提高应用的性能。而对于一些需要动态创建的Bean,如请求处理器等,使用prototype作用域可以保证每个请求都有一个独立的处理器实例,避免了线程安全问题。
除了以上五种作用域,Spring还支持自定义作用域,通过实现Scope接口可以自定义一个新的作用域,以满足特定的业务需求。
13、Spring基于xml注入bean的几种方式?
Spring框架基于XML配置文件的方式支持以下几种方式来注入Bean:
构造函数注入:通过构造函数来实例化Bean对象,并传递参数来设置Bean对象的属性值。在XML配置文件中使用<constructor-arg>标签来指定参数值,可以通过type属性来指定参数类型,也可以通过index属性或name属性来指定参数的位置或名称。
Setter方法注入:通过Setter方法来设置Bean对象的属性值。在XML配置文件中使用<property>标签来指定属性名和属性值,Spring会自动调用相应的Setter方法来设置属性值。
工厂方法注入:使用工厂方法来创建Bean对象。在XML配置文件中使用<bean>标签的factory-method属性来指定工厂方法名,使用<constructor-arg>标签来指定参数值。
静态工厂方法注入:使用静态工厂方法来创建Bean对象。在XML配置文件中使用<bean>标签的class属性来指定工厂类名,使用factory-method属性来指定工厂方法名,使用<constructor-arg>标签来指定参数值。
实例工厂方法注入:使用实例工厂方法来创建Bean对象。在XML配置文件中使用<bean>标签的class属性来指定工厂类名,使用factory-bean属性来指定工厂对象名,使用factory-method属性来指定工厂方法名,使用<constructor-arg>标签来指定参数值。
除了以上几种方式,还可以使用注解的方式来注入Bean,例如使用@Autowired或@Resource注解来自动注入依赖对象。同时,Spring也支持混合使用以上几种方式来注入Bean,以满足不同的业务需求。
14、Spring框架中都用到了哪些设计模式?
Spring框架是一个非常强大的企业级应用程序开发框架,它涵盖了众多的设计模式,其中一些常见的设计模式包括:
依赖注入(DI)和控制反转(IOC)模式:Spring框架的核心思想就是依赖注入和控制反转,它们是Spring框架中最重要的设计模式。
工厂模式:Spring框架中使用BeanFactory和ApplicationContext等工厂类来创建Bean对象,这些工厂类都是基于工厂模式设计的。
代理模式:Spring框架中的AOP功能就是基于代理模式实现的,它通过代理对象来控制原始对象的访问。
模板方法模式:Spring框架中的JdbcTemplate和HibernateTemplate等类都是基于模板方法模式设计的,它们封装了通用的数据库操作逻辑,开发人员只需要继承这些类并实现必要的回调方法即可。
观察者模式:Spring框架中的事件机制就是基于观察者模式实现的,它允许开发人员在应用程序中发布和监听事件。
策略模式:Spring框架中的DispatcherServlet就是基于策略模式实现的,它根据请求的URL路径选择不同的处理策略。
适配器模式:Spring框架中的HandlerAdapter就是基于适配器模式实现的,它将不同类型的处理器适配到统一的接口上。
总之,Spring框架中使用的设计模式非常多样化,涵盖了多种常用的设计模式,这些设计模式都为Spring框架的高效、灵活和可扩展性奠定了坚实的基础。
15、说说Spring 中 ApplicationContext 和 BeanFactory 的区别
在 Spring 中,ApplicationContext 和 BeanFactory 都是用来管理 Spring Bean 的容器,但它们之间有以下几点区别:
ApplicationContext 是 BeanFactory 的子接口,它提供了更多的功能,例如支持国际化、资源访问、事件传递、AOP 等。
ApplicationContext 在启动时就会预处理所有的 Bean,如果有配置错误,会在启动时就抛出异常,而 BeanFactory 则是在获取 Bean 时才进行初始化,如果有配置错误,只有在获取 Bean 时才会抛出异常。
ApplicationContext 可以自动检测 Bean 的依赖关系并自动注入依赖的 Bean,而 BeanFactory 则需要手动配置注入依赖的 Bean。
ApplicationContext 支持多种资源的访问方式,例如文件系统、类路径、Web URL 等,而 BeanFactory 只支持基本的资源访问方式。
ApplicationContext 支持事件传递机制,可以监听和发布事件,而 BeanFactory 不支持事件传递机制。
综上所述,ApplicationContext 比 BeanFactory 更加强大,它提供了更多的功能,可以自动化处理更多的任务,但它也需要更多的系统资源。如果应用程序需要更高的性能,可以使用 BeanFactory,如果需要更多的功能,可以使用 ApplicationContext。
16、Spring 框架中的单例 Bean 是线程安全的么?
不是,在 Spring 框架中,单例 Bean 是默认在整个应用程序中共享的实例,这意味着多个线程可以同时访问同一个单例 Bean 实例。因此,Spring 容器会确保单例 Bean 实例的线程安全。
Spring 通过以下两种方式来保证单例 Bean 的线程安全:
通过 synchronized 关键字保护 Bean 实例的访问。
在 Spring 容器初始化单例 Bean 时,会在 Bean 的 getBean() 方法上添加 synchronized 关键字,确保在多线程环境下只有一个线程可以访问 Bean 实例。
通过方法级别的锁来保护 Bean 实例的访问。
当使用注解方式配置 Bean 的时候,可以使用 @Scope("singleton") 注解来确保 Bean 实例的单例模式。在这种情况下,Spring 容器会在 Bean 实例的方法上添加锁,以确保在多线程环境下只有一个线程可以访问 Bean 实例。
如果单例 Bean 中存在共享状态,那么在多线程环境下仍然需要考虑线程安全的问题,可以通过使用 synchronized 关键字或其他并发控制手段来保证线程安全。
17、Spring 是怎么解决循环依赖的?
循环依赖指两个或多个 Bean 之间相互依赖,形成一个环形依赖。Spring 容器默认情况下是不支持循环依赖的,因为容器需要先实例化 Bean,才能进行依赖注入,但是如果出现循环依赖,则会陷入死循环。
为了解决循环依赖问题,Spring 使用了三级缓存机制:
第一级缓存:Spring 容器在实例化 Bean 时,会将正在创建的 Bean 放到一个缓存 Map 中。如果在创建 Bean 的过程中,出现了依赖其他正在创建的 Bean 的情况,则会把依赖的 Bean 的 ObjectFactory 放到这个 Map 中,表示这个 Bean 还没有完全创建好。
第二级缓存:当创建一个 Bean 需要依赖另外一个还未创建完成的 Bean 时,Spring 容器会把当前正在创建的 Bean 放到第二级缓存中。这个缓存中存储的是已经实例化、但还未进行属性注入的 Bean 对象,以便后续注入。
第三级缓存:在 Bean 的属性注入完成后,Spring 容器会把这个 Bean 放到第三级缓存中。这个缓存中存储的是已经实例化并进行了属性注入的 Bean 对象。
当需要获取某个 Bean 时,Spring 容器会先从第一级缓存中查找,如果找不到则会从第二级缓存中查找,如果还是找不到,则会实例化 Bean 并加入到第三级缓存中。
通过三级缓存的机制,Spring 容器可以解决大部分循环依赖的问题,但是如果出现了循环依赖的死循环,则会抛出 BeanCurrentlyCreationException 异常,表示无法解决循环依赖问题。在开发过程中,应尽量避免出现循环依赖的情况。
18、说说事务的隔离级别
在关系型数据库中,事务的隔离级别定义了多个事务之间彼此之间的可见性和影响的程度。Spring 框架提供了对事务的支持,同时也支持多种隔离级别,包括以下 5 种:
读未提交(Read Uncommitted):允许脏读,即一个事务可以读取到另一个未提交事务的数据。
读已提交(Read Committed):禁止脏读,但允许不可重复读,即一个事务可以读取到另一个事务已提交的数据。
可重复读(Repeatable Read):禁止脏读和不可重复读,但允许幻读,即在一个事务内,多次读取同一范围的数据可能会返回不同的结果。
串行化(Serializable):禁止脏读、不可重复读和幻读,强制事务串行执行。
默认隔离级别(默认是读已提交):禁止脏读,但允许不可重复读和幻读。
19、说说事务的传播级别
在 Spring 框架中,当一个事务方法调用另一个事务方法时,这两个事务如何协同工作是由事务的传播行为控制的。Spring 支持多种传播行为,包括以下 7 种:
PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果不存在,则新建一个事务。这是默认值。
PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果不存在,则以非事务状态执行。
PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果不存在,则抛出异常。
PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则挂起当前事务。
PROPAGATION_NOT_SUPPORTED:以非事务状态执行操作,如果当前存在事务,则挂起当前事务。
PROPAGATION_NEVER:以非事务状态执行操作,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果不存在事务,则新建一个事务。
20、Spring框架的事务管理有哪些优点
Spring框架的事务管理有以下优点:
与Spring容器紧密集成,便于开发和维护。
声明式事务管理使得代码简洁,易于维护。开发者只需要使用注解或XML进行配置,就可以完成事务的管理。
Spring的事务管理支持多种事务定义方式,包括编程式事务管理和声明式事务管理。这样可以根据业务需求进行选择。
Spring的事务管理可以管理多个事务,即使在一个事务中涉及多个数据源,也可以进行管理。
Spring的事务管理提供了对事务状态的良好支持,包括对事务的回滚、提交和挂起等操作。这些操作可以提高数据的安全性和完整性。
Spring的事务管理提供了对JTA事务的支持,可以管理跨越多个应用程序或资源的分布式事务。
综上所述,Spring框架的事务管理具有简单、灵活、高效等优点,可以帮助开发者更好地管理和控制事务。
21、事务三要素是什么?
事务三要素是指事务的三个基本特征,即原子性、一致性和隔离性。
原子性(Atomicity):事务是一个不可分割的工作单位,要么全部执行,要么全部不执行,事务的各项操作要么全部成功,要么全部失败回滚,不允许只执行其中的一部分操作。
一致性(Consistency):事务执行前后,数据的完整性、一致性都必须得到保障。在事务执行过程中,系统的约束条件不能被破坏,数据的约束条件必须得到维护。
隔离性(Isolation):多个事务并发执行时,事务之间是相互隔离的,一个事务不应该影响其他事务的执行。隔离级别是事务并发控制的核心,常见的隔离级别有:读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)。
这三个要素是事务的核心特性,对事务的正确性和完整性都至关重要。只有同时满足这三个要素,才能保证事务的正确性和完整性。