Spring面试题

本文深入讲解Spring框架的核心概念,包括其轻量级特性、依赖注入、面向切面编程及事务管理。探讨Spring如何简化企业级应用开发,降低对象间的耦合度,以及如何通过AOP分离业务逻辑与系统服务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 什么是Spring?

  1. Spring,一种用来简化企业应用级开发的一种开源框架。
  2. Spring容器是Spring框架中一个核心的模块,用来管理对象的创建,销毁和初始化扥操作,以及对象之间的依赖关系等。
  3. 解耦:Spring帮我们管理软件之间的依赖关系,这样对象之间的耦合性就降低了,这样的维护性就得到了提高。
  4. 简化开发:它对常用的API做了封装,比如对JDBC的封装,使用Spring JDBC访问数据库,就不需要考虑如何获取连接和关闭的问题。
  5. 集成其它框架:方便扩展和优化其功能,例如和Mybatis的集成等。

2. 使用Spring框架的好处是什么?

  1. 轻量:Spring 是轻量的,基本的版本大约2MB。
  2. 容器:Spring 包含并管理应用中对象的生命周期和配置。
  3. 控制反转:使一个对象依赖的其他对象通过被动的方式传递进来,而不是对象自己创建或查找依赖对象。
  4. 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。所有的横切关注功能封装到切面(aspect)中,通过配置的方式将横切关注功能动态添加到目标代码上,进一步实现了业务逻辑和系统服务之间的分离。另一方面,有了AOP程序员可以省去很多自己写代理类的工作。
  5. MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
  6. 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
  7. 异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的异常)转化为一致的unchecked 异常。

3.  Spring由哪些模块组成?
Spring框架至今已集成了20多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成,、Web、AOP(面向切面编程)、工具、消息和测试模块。


4. BeanFactory和 Application context 有什么区别?

BeanFactory:

  1. BeanFactory 可以理解为含有bean集合的工厂类。BeanFactory 包含了种bean的定义,以便在接收到客户端请求时将对应的bean实例化。
  2. BeanFactory还能在实例化对象的时生成协作类之间的关系。此举将bean自身与bean客户端的配置中解放出来。
  3. BeanFactory还包含了bean生命周期的控制,调用客户端的初始化方法(initialization methods)和销毁方法(destruction methods)。

Application contexts:从表面上看,application context如同bean factory一样具有bean定义、bean关联关系的设置,根据请求分发bean的功能。但application context在此基础上还提供了其他的功能。

  1. 提供了支持国际化的文本消息
  2. 统一的资源文件读取方式
  3. 已在监听器中注册的bean的事件

以下是2种较常见的 ApplicationContext 实现方式:

1、ClassPathXmlApplicationContext:从classpath的XML配置文件中读取上下文,并生成上下文定义。应用程序上下文从程序环境变量中取得。
ApplicationContext context = new ClassPathXmlApplicationContext(“bean.xml”);

2、FileSystemXmlApplicationContext :由文件系统中的XML配置文件读取上下文。
ApplicationContext context = new FileSystemXmlApplicationContext(“bean.xml”);

 

IOC

  1. 什么是Spring IOC 容器?
    Spring容器=核心容器=IOC容器
    Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,并且管理这些对象的整个生命周期.
    1. Spring中的 org.springframework.beans 包和 org.springframework.context包构成了Spring框架IoC容器的基础.
    2. org.springframework.beans.factory.BeanFactory 是Spring IoC容器的具体实现,用来包装和管理各种bean。
    3. BeanFactory接口是Spring IoC 容器的核心接口。
    4. BeanFactory 接口提供了一个先进的配置机制,使得任何类型的对象的配置成为可能。
    5. ApplicationContex接口对BeanFactory(是一个子接口)进行了扩展,在BeanFactory的基础上添加了其他功能,比如与Spring的AOP更容易集成,也提供了处理message resource的机制(用于国际化)、事件传播以及应用层的特别配置,比如针对Web应用的WebApplicationContext。
  2. IOC的优点是什么?
    1. IOC 或 依赖注入把应用的代码量降到最低。它使应用容易测试,单元测试不再需要单例和JNDI查找机制。
    2. 最小的代价和最小的侵入性使松散耦合得以实现。
    3. IOC容器支持加载服务时的饿汉式初始化和懒加载。
  3. 什么是控制反转(IOC),什么是依赖注入(DI)?
    1. IOC:就是对象之间的依赖关系由容器来创建,对象之间的关系本来是由我们开发者自己创建和维护的,在我们使用Spring框架后,对象之间的关系由容器来创建和维护,将开发者做的事让容器做,这就是控制反转。BeanFactory接口是Spring Ioc容器的核心接口。
    2. DI:我们在使用Spring容器的时候,容器通过调用set方法或者是构造器来建立对象之间的依赖关系。
    3. 控制反转是目标,依赖注入是我们实现控制反转的一种手段。
  4. IOC的原理是反射,那么为什么不使用new来创建对象?
    Spring在加载类的实例时,使用工厂的方式,给出一个个实例,而在工厂里面,用了单例(有疑问),但是真正的实例化,则是反射的newInstance来创建对象,而不是new。
    反射的目的
    高内聚,低耦合。不用知道类名,可以直接实例化类,不用硬编码。
  5. Java中实现依赖注入的三种方式?
    1. set方法注入
    2. 构造器注入
    3. 接口注入
  6. 解释什么是自动装配 ?
    1. 就是将一个Bean注入到其它的Bean的Property中,默认情况下,容器不会自动装配,需要我们手动设定。Spring 可以通过向Bean Factory中注入的方式来搞定bean之间的依赖关系,达到自动装配的目的。
    2. 自动装配建议少用,如果要使用,建议使用ByName
  7. 自动装配的五种方式
    1. no:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。
    2. byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
    3. byType::通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
    4. constructor:这个方式类似于byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
    5. autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。
  8. Spring中如何注入一个java集合?
    Spring提供以下几种集合的配置元素:
    1. <list>类型用于注入一列值,允许有相同的值。
    2. <set> 类型用于注入一组值,不允许有相同的值。
    3. <map> 类型用于注入一组键值对,键和值都可以为任意类型。
    4. <props>类型用于注入一组键值对,键和值都只能为String类型。
  9. Spring有几种配置方式 ?
    1. 基于XML文件的配置 这种配置文件的格式常用<beans>开头,然后运用一系列的bean定义和专门的应用配置选项组成。 Spring XML配置方式是使用被Spring命名空间所支持的一些列XML的标签来实现的。
    2. 基于注解的配置 可以使用注解的方式来代替XML方式的bean元素的配置。这就是组件扫描,常用依赖注入的一些注解有: @Controller @Service @Autowired @RequestMapping @RequestParam @ModelAttribute @Cacheable @CacheFlush @Resource @PostConstruct @PreDestroy @Repository @Scope @SessionAttributes @InitBinder @Required @Qualifier
    3. 组件扫描: 容器会扫描base-package指定的包及其子包下面的所有类,如果该类有一些特定的注解,则纳入容器进行管理。
    4. 在类前面添加的一些特定的注解: @Component 通用注解 @Repository 持久层注解 @Service 业务层注解、 @Controller 控制层注解
    5. 基于Java的配置
  10. Spring容器中如何创建对象?
    无参构造创建
    静态工厂创建
    实例工厂创建
  11. 什么是Spring beans?
    简单来说bean就是Java对象。通过spring容器进行管理。
    Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化,装配,和管理。这些beans通过容器中配置的元数据创建。比如,以XML文件中<bean/> 的形式定义。
  12. Spring Bean的生命周期 ?
    1. 指Spring中bean元素被实例化,和被销毁的过程。我们通过init-method属性指定初始化方法; 通过destroy-method方法指定销毁方法。
    2. 注意:只有作用域为Singleton的时候才会有效。
  13. 解释Spring框架中bean的生命周期
    创建——>实例化——>初始化——>使用——>销毁
    1. Spring容器 从XML 文件中读取bean的定义,实例化一个Bean--也就是我们常说的new;
    2. 按照Spring上下文对实例化的Bean进行配置--也就是IOC注入;
    3. 如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,此处传递的就是Spring配置文件中Bean的id值
    4. 如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring工厂自身(可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以);
    5. 如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文(同样这个方式也可以实现步骤4的内容,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法);
    6.  如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
    7. 如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。
    8. 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法、;

      注:以上工作完成以后就可以应用这个Bean了,那这个Bean是一个Singleton的,所以一般情况下我们调用同一个id的Bean会是在内容地址相同的实例,当然在Spring配置文件中也可以配置非Singleton,这里我们不做赘述。
    9. 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法
    10.  最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
  14. 解释什么叫延迟加载 ?
    1. 默认情况下,容器启动之后会将所有作用域为单例的bean创建好;但是有的业务场景我们并不需要它提前都创建好
    2. 此时,我们可以在bean中设置lzay-init=“true”,这样,当容器启动之后,作用域为单例的bean,就不在创建。
  15. Spring bean元素的作用域?
    当通过Spring容器创建一个Bean实例的时候,不仅可以完成bean实例的实例化,还可以为bean指定作用域。Spring bean元素的支持以下5种作用域:
    1. Singleton:单例模式,在整个spring IOC容器中,使用singleton定义的bean将只有一个实例。
    2. Prototype:多例模式,每次通过容器中的getBean方法获取prototype定义的beans时,都会产生一个新的bean的实例。
    3. Request:对于每次Http请求,使用request定义的bean都会产生一个新的实例,只有在web应用时候,该作用域才会有效。
    4. Session:对于每次Http Session,使用session定义的Bean都将产生一个新的实例。
    5. Globalsession:每个全局的Http Sesisonn,使用session定义的本都将产生一个新的实例。
  16. Spring中的bean是线程安全的么?
    1. Spring框架并没有对单例的bean进行多线程的封装处理,线程安全问题和并发问题,需要我们开发者自己考虑。
    2. 但实际上,大部分的Spring bean并没有可变的状态(比如:service类和dao类),所有在某种程度上来说Spring单例bean是线程安全的。如果bean有多种状态的话(比如:View Model对象),就需要自行考虑线程安全问题。
  17. Spring框架中都用到了哪些设计模式 ?
    1. 代理模式,在AOP中被使用最多。
    2. 单例模式,在Spring配置文件中定义bean的时候默认的是单例模式。
    3. 工厂模式, BeanFactory用来创建对象的实例。
    4. 模板方法, 用来解决重复性代码。
    5. 前端控制器,Spring提供了DispatcherSerclet来对请求进行分发。
    6. 视图帮助,Spring提供了一系列的JSP标签。
    7. 依赖注入,它是惯穿于BeanFactory/ApplicationContext接口的核心理念。

 

Spring面向切面编程(AOP)

  1. 术语
    1. AOP
      面向切面的编程,或AOP, 是一种编程技术,允许程序模块化横向切割关注点,或横切典型的责任划分,如日志和事务管理
    2. 切面(aspect)
      AOP核心就是切面,它将多个类的通用行为封装成可重用的模块,该模块含有一组API提供横切功能。比如,一个日志模块可以被称作日志的AOP切面。根据需求的不同,一个应用程序可以有若干切面。在Spring AOP中,切面通过带有@Aspect注解的类实现。
    3. 关注点和横切关注的区别是什么?
      关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。
      横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。
    4. 连接点(joinpoint)
      被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
    5. 切入点(pointcut)
      对连接点进行拦截的定义
    6. 通知(advice)
      所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
    7. 目标对象(Target object)
      被一个或者多个方面所通知的对象,这个对象永远是一个被代理对象。也称为被通知对象。
    8. 织入(weave)
      把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时,类加载时和运行时完成。
    9. 引入(introduction)
      在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
  2. Spring AOP(面向切面)编程的原理 ?
    1. AOP面向切面编程,它是一种思想。它就是针对业务处理过程中的切面进行提取,以达到优化代码的目的,减少重复代码的目的。 就比如,在编写业务逻辑代码的时候,我们习惯性的都要写:日志记录,事务控制,以及权限控制等,每一个子模块都要写这些代码,代码明显存在重复。这时候,我们运用面向切面的编程思想,采用横切技术,将代码中重复的部分,不影响主业务逻辑的部分抽取出来,放在某个地方进行集中式的管理,调用。 形成日志切面,事物控制切面,权限控制切面。 这样,我们就只需要关系业务的逻辑处理,即提高了工作的效率,又使得代码变的简洁优雅。这就是面向切面的编程思想,它是面向对象编程思想的一种扩展。
    2. AOP的使用场景: 缓存、权限管理、内容传递、错误处理、懒加载、记录跟踪、优化、校准、调试、持久化、资源池、同步管理、事务控制等。
      AOP的相关概念: 切面(Aspect) 连接点(JoinPoint) 通知(Advice) 切入点(Pointcut) 代理(Proxy): 织入(WeaVing)
    3. Spring AOP的编程原理? 代理机制 JDK的动态代理:只能用于实现了接口的类产生代理。 Cglib代理:针对没有实现接口的类产生代理,应用的是底层的字节码增强技术,生成当前类的子类对象。
  3. 解释一下代理模式(Proxy)
    1. 代理模式: 代理模式就是本该我做的事,我不做,我交给代理人去完成。就比如,我生产了一些产品,我自己不卖,我委托代理商帮我卖,让代理商和顾客打交道,我自己负责主要产品的生产就可以了。 代理模式的使用,需要有本类,和代理类,本类和代理类共同实现统一的接口。然后在main中调用就可以了。本类中的业务逻辑一般是不会变动的,在我们需要的时候可以不断的添加代理对象,或者修改代理类来实现业务的变更。
    2. 代理模式可以分为:
      1. 静态代理
        优点:可以做到在不修改目标对象功能的前提下,对目标功能扩展
        缺点:因为本来和代理类要实现统一的接口,所以会产生很多的代理类,类太多,一旦接口增加方法,目标对象和代理对象都要维护。
      2. 动态代理(JDK代理/接口代理)
        代理对象,不需要实现接口,代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象,需要我们指定代理对象/目标对象实现的接口的类型。
      3. Cglib代理
        特点: 在内存中构建一个子类对象,从而实现对目标对象功能的扩展。
    3. 使用场景: 修改代码的时候。不用随便去修改别人已经写好的代码,如果需要修改的话,可以通过代理的方式来扩展该方法。 隐藏某个类的时候,可以为其提供代理类 当我们要扩展某个类功能的时候,可以使用代理类 当一个类需要对不同的调用者提供不同的调用权限的时候,可以使用代理类来实现。 减少本类代码量的时候。 需要提升处理速度的时候。就比如我们在访问某个大型系统的时候,一次生成实例会耗费大量的时间,我们可以采用代理模式,当用来需要的时候才生成实例,这样就能提高访问的速度。
  4. 使用aop使用注意什么
  5. Spring支持的事务管理类型有哪些?你在项目中使用哪种方式? 
    答:Spring支持编程式事务管理和声明式事务管理。许多Spring框架的用户选择声明式事务管理,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理,尽管在灵活性方面它弱于编程式事务管理,因为编程式事务允许你通过代码控制业务。

    事务分为全局事务和局部事务。全局事务由应用服务器管理,需要底层服务器JTA支持(如WebLogic、WildFly等)。局部事务和底层采用的持久化方案有关,例如使用JDBC进行持久化时,需要使用Connetion对象来操作事务;而采用Hibernate进行持久化时,需要使用Session对象来操作事务。

    Spring提供了如下所示的事务管理器。 这些事务的父接口都是PlatformTransactionManager。Spring的事务管理机制是一种典型的策略模式,PlatformTransactionManager代表事务管理接口,该接口定义了三个方法,该接口并不知道底层如何管理事务,但是它的实现类必须提供getTransaction()方法(开启事务)、commit()方法(提交事务)、rollback()方法(回滚事务)的多态实现,这样就可以用不同的实现类代表不同的事务管理策略。使用JTA全局事务策略时,需要底层应用服务器支持,而不同的应用服务器所提供的JTA全局事务可能存在细节上的差异,因此实际配置全局事务管理器是可能需要使用JtaTransactionManager的子类,如:WebLogicJtaTransactionManager(Oracle的WebLogic服务器提供)、UowJtaTransactionManager(IBM的WebSphere服务器提供)等。
  6. 如何配置配置事务增强?
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:aop="http://www.springframework.org/schema/aop"
         xmlns:tx="http://www.springframework.org/schema/tx"
         xsi:schemaLocation="
         http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/tx
         http://www.springframework.org/schema/tx/spring-tx.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd">
    
      <!-- this is the service object that we want to make transactional -->
      <bean id="fooService" class="x.y.service.DefaultFooService"/>
    
      <!-- the transactional advice -->
      <tx:advice id="txAdvice" transaction-manager="txManager">
      <!-- the transactional semantics... -->
      <tx:attributes>
        <!-- all methods starting with 'get' are read-only -->
        <tx:method name="get*" read-only="true"/>
        <!-- other methods use the default transaction settings (see below) -->
        <tx:method name="*"/>
      </tx:attributes>
      </tx:advice>
    
      <!-- ensure that the above transactional advice runs for any execution
        of an operation defined by the FooService interface -->
      <aop:config>
      <aop:pointcut id="fooServiceOperation" 
        expression="execution(* x.y.service.FooService.*(..))"/>
      <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
      </aop:config>
    
      <!-- don't forget the DataSource -->
      <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
      <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
      <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
      <property name="username" value="scott"/>
      <property name="password" value="tiger"/>
      </bean>
    
      <!-- similarly, don't forget the PlatformTransactionManager -->
      <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="dataSource"/>
      </bean>
    
      <!-- other <bean/> definitions here -->
    
    </beans>
    

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值