spring大全 面试 知识面面观
1. 详细列举Spring核心模块组成 ?
Spring 核心容器 – 该层基本上是 Spring Framework 的核心。
它包含以下模块:
1:Spring Core
2:Spring Bean
3:SpEL (Spring Expression Language)
4:Spring Context 数据访问/集成 – 该层提供与数据库交互的支持。它包含以下模块:
5:JDBC (Java DataBase Connectivity)
6:ORM (Object Relational Mapping)
7:OXM (Object XML Mappers)
8:JMS (Java Messaging Service)
9:Transaction
10:Web – 该层提供了创建 Web 应用程序的支持。它包含以下模块:AOP – 该层支持面向切面编程
Web
11:Web – Servlet
12:Web – Socket
13:Web – Portlet
14:Instrumentation – 该层为类检测和类加载器实现提供支持。
15:Test – 该层为使用 JUnit 和 TestNG 进行测试提供支持。
16:几个杂项模块:
Messaging – 该模块为 STOMP 提供支持。它还支持注解编程模型,该模型用于从 WebSocket 客户端路由和处理 STOMP 消息。
Aspects – 该模块为与 AspectJ 的集成提供支持。
2. 详细阐述Spring的IOC和DI ?
1:什么是“控制反转”
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来降低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。【百度百科】
在软件工程中,控制反转(IoC)是一种编程原则。与传统控制流程相比,IoC反转了控制流程。在IoC中,计算机程序的自定义编写部分接收来自通用框架的控制流程。与传统程序编程相比,具有这种设计的软件架构反转了控制:在传统编程中,表示程序目的的自定义代码调用可重用库来处理一般任务,但在控制反转中,框架调用自定义或特定于任务的代码。【维基百科】
简单描述就是,对象a中用到了对象b,一般情况下,需要在a的代码中显示的new一个b的对象。使用控制反转设计原则后,a中只需要定义一个对象b,不需要实例化new,而是通过相关的容器控制程序来将b对象在外部new出来并赋值给a中的b。控制反转有时被戏称为“好莱坞原则:不要打电话给我们,我们会打电话给你”。
2:什么是“依赖注入”
依赖注入(Dependency Injection)是Spring框架的核心之一。【百度百科】
在软件工程中,依赖注入是一种设计模式,其中一个对象或函数接收它所依赖的其他对象或函数。依赖注入是控制反转的一种形式,旨在分离构造对象和使用对象的关注点,从而生成松散耦合的程序。该模式确保希望使用给定服务的对象或函数不必知道如何构造这些服务具体实现。相反,接收“客户机”(对象或函数)由外部代码(“注入器”)提供其依赖关系,而它无需感知实现细节。【维基百科】
简单描述就是,在控制反转中提到相关的容器控制程序来将b对象在外部new出来并赋值给a中的b,这个就是依赖注入的过程。
IoC,DI关系
IoC(控制反转)主要指将对象的创建权交给外界(例如Spring容器),这里的交给外界就是控制反转的过程,在对象创建过程中普遍会依赖其他的对象资源,所以需要外界对原始对象进行属性依赖的赋值操作,这个过程就是DI(依赖注入)。在这里我们要清楚是将手动创建对象的权利反转给Spring容器,Spring容器对创建的对象进行依赖注入。所以IoC和DI是相辅相成的搭档,IoC需要DI进行依赖的赋值,他们都是为实现解耦而服务的。
3. 解释什么是声明式的事务管理?Spring如何实现声明式的事务管理?
声明式的事务管理主要是将在进行对数据库中数据的添加或者修改时需要执行事务管理,主要是为了避免在执行添加或修改的时候添加或修改不完全正确,导致数据丢失。spring使用AOP面向切面的思想进行事务管理的。
Spring为我们提供了两种的事务管理,编程式事务管理和声明式事务管理,因为spring提倡使用声明式事务管理,所以笔者本身也具体学习研究和应用声明式事务,这里只详细谈谈声明式事务,而编程式事务就一句概括;
编程式事务:使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
声明式事务:spring的声明式事务的实现方式有两种,一种是基于AOP切面实现声明式事务,而第二种是基于注解@ Transacitional实现,但是两种都需要在sprig的xml配置才能启动事务管理;本篇文章先讲基于注解Transacitional的声明式事务的实现,这里先看下xml配置文件是怎么配置的,代码如下:
<tx:annotation-driven transaction-manager=“txManager” proxy-target-class=“true”></tx:annotation-driven>
其中,tx:annotation-driven标签表示开启事务管理
4. 对Spring的理解,项目中都用什么?怎么用的?对IOC、和AOP的理解及实现原理
Spring是一个开源框架,处于MVC模式中的控制层,它能应对需求快速的变化,其主要原因它有一种面向切面编程(AOP)的优势,其次它提升了系统性能,因为通过依赖倒置机制(IOC),系统中用到的对象不是在系统加载时就全部实例化,而是在调用到这个类时才会实例化该类的对象,从而提升了系统性能。这两个优秀的性能使得Spring受到许多J2EE公司的青睐,如阿里里中使用最多的也是Spring相关技术。
Spring的优点:
1、降低了组件之间的耦合性,实现了软件各层之间的解耦。
2、可以使用容易提供的众多服务,如事务管理,消息服务,日志记录等。
3、容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能。
Spring中AOP技术是设计模式中的动态代理模式。只需实现jdk提供的动态代理接口InvocationHandler,所有被代理对象的方法都由InvocationHandler接管实际的处理任务。面向切面编程中还要理解切入点、切面、通知、织入等概念。
Spring中IOC则利用了Java强大的反射机制来实现。所谓依赖注入即组件之间的依赖关系由容器在运行期决定。其中依赖注入的方法有两种,通过构造函数注入,通过set方法进行注入。
5. 详细叙述什么是Spring开发框架 ?
Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。主要包括以下七个模块:
1:Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
2:Spring Core:核心类库,所有功能都依赖于该类库,提供IOC和DI服务;
3:Spring AOP:AOP服务;
4:Spring Web:提供了基本的面向Web的综合特性,提供对常见框架如Struts2的支持,Spring能够管理这些框架,将Spring的资源注入给框架,也能在这些框架的前后插入拦截器;
5:Spring MVC:提供面向Web应用的Model-View-Controller,即MVC实现。
6:Spring DAO:对JDBC的抽象封装,简化了数据访问异常的处理,并能统一管理JDBC事务;
7:Spring ORM:对现有的ORM框架的支持;
6. 简述 Java - Spring 框架的优点?
Spring具有简单、可测试和松耦合等特点,从这个角度出发,Spring不仅可以用于服务器端开发,也可以应用于任何Java应用的开发中,Spring框架优点总结:
1、非侵入式设计
Spring是一种非侵入式(non-invasive)框架,它可以使应用程序代码对框架的依赖最小化。
2、 方便解耦、简化开发
Spring就是一个大工厂,可以将所有对象的创建和依赖关系的维护工作都交给Spring容器管理,大大地降低了组件之间的耦合性。
3、支持AOP
Spring提供了对AOP的支持,它允许将一些通用任务,如安全、事务、日志等进行集中式处理,从而提高了程序的复用性。
4、支持声明式事务处理
只需要通过配置就可以完成对事务的管理,而无需手动编程。
5、方便程序的测试
Spring提供了对Junit4的支持,可以通过注解方便的测试Spring程序。
6、方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持。
7、降低Java EE API的使用难度
Spring对Java EE开发中非常难用的一些API(如:JDBC、JavaMail等),都提供了封装,使这些API应用难度大大降低。
Spring是一个容器,凡是在容器里的对象才会有Spring所提供的这些服务和功能。Spring里用的经典的一个设计模式就是模板方法模式。Spring里的配置很多很难记住,把服务和功能理解了也就基本上掌握了Spring。
7. 简述Spring的AOP理解 ?
OOP面向对象,允许开发者定义纵向的关系,但并不适用于定义横向的关系,会导致大量代码的重复,而不利于各个模块的重用。
AOP,一般称为面向切面,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,提高系统的可维护性。可用于权限认证、日志、事务处理。
AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
(1)AspectJ是静态代理,也称为编译时增强,AOP框架会在编译阶段生成AOP代理类,并将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法
(3)静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
8. 解释Spring AOP里面的关键词 ?
Spring AOP里面的关键词
(1)连接点(Join point):指程序运行过程中所执行的方法。在Spring AOP中,一个连接点总代表一个方法的执行。
(2)切面(Aspect):被抽取出来的公共模块,可以用来会横切多个对象。Aspect切面可以看成 Pointcut切点 和 Advice通知 的结合,一个切面可以由多个切点和通知组成。
在Spring AOP中,切面可以在类上使用 @AspectJ 注解来实现。
(3)切点(Pointcut):切点用于定义 要对哪些Join point进行拦截。
切点分为execution方式和annotation方式。execution方式可以用路径表达式指定对哪些方法拦截,比如指定拦截add*、search*。annotation方式可以指定被哪些注解修饰的代码进行拦截。
(4)通知(Advice):指要在连接点(Join Point)上执行的动作,即增强的逻辑,比如权限校验和、日志记录等。通知有各种类型,包括Around、Before、After、After returning、After throwing。
(5)目标对象(Target):包含连接点的对象,也称作被通知(Advice)的对象。 由于Spring AOP是通过动态代理实现的,所以这个对象永远是一个代理对象。
(6)织入(Weaving):通过动态代理,在目标对象(Target)的方法(即连接点Join point)中执行增强逻辑(Advice)的过程。
(7)引入(Introduction):添加额外的方法或者字段到被通知的类。Spring允许引入新的接口(以及对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制
9. 简述Spring通知(Advice)有哪些类型?
Spring通知(Advice)有哪些类型:
(1)前置通知(Before Advice):在连接点(Join point)之前执行的通知。
(2)后置通知(After Advice):当连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
(3)环绕通知(Around Advice):包围一个连接点的通知,这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也可以选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
(4)返回后通知(AfterReturning Advice):在连接点正常完成后执行的通知(如果连接点抛出异常,则不执行)
(5)抛出异常后通知(AfterThrowing advice):在方法抛出异常退出时执行的通知
10. 请简述Spring的Advice的执行顺序?
(1)没有异常情况下的执行顺序:
around before advice
before advice
target method 执行
after advice
around after advice
afterReturning advice
(2)出现异常情况下的执行顺序:
around before advice
before advice
target method 执行
after advice
around after advice
afterThrowing advice
java.lang.RuntimeException:异常发生
11. 详细叙述Spring容器的启动流程 ?
(1)初始化Spring容器,注册内置的BeanPostProcessor的BeanDefinition到容器中:
① 实例化BeanFactory【DefaultListableBeanFactory】工厂,用于生成Bean对象
② 实例化BeanDefinitionReader注解配置读取器,用于对特定注解(如@Service、@Repository)的类进行读取转化成 BeanDefinition 对象,(BeanDefinition 是 Spring 中极其重要的一个概念,它存储了 bean 对象的所有特征信息,如是否单例,是否懒加载,factoryBeanName 等)
③ 实例化ClassPathBeanDefinitionScanner路径扫描器,用于对指定的包目录进行扫描查找 bean 对象
(2)将配置类的BeanDefinition注册到容器中:
(3)调用refresh()方法刷新容器:
① prepareRefresh()刷新前的预处理:
② obtainFreshBeanFactory():获取在容器初始化时创建的BeanFactory:
③ prepareBeanFactory(beanFactory):BeanFactory的预处理工作,向容器中添加一些组件:
④ postProcessBeanFactory(beanFactory):子类重写该方法,可以实现在BeanFactory创建并预处理完成以后做进一步的设置
⑤ invokeBeanFactoryPostProcessors(beanFactory):在BeanFactory标准初始化之后执行BeanFactoryPostProcessor的方法,即BeanFactory的后置处理器:
⑥ registerBeanPostProcessors(beanFactory):向容器中注册Bean的后置处理器BeanPostProcessor,它的主要作用是干预Spring初始化bean的流程,从而完成代理、自动注入、循环依赖等功能
⑦ initMessageSource():初始化MessageSource组件,主要用于做国际化功能,消息绑定与消息解析:
⑧ initApplicationEventMulticaster():初始化事件派发器,在注册监听器时会用到:
⑨ onRefresh():留给子容器、子类重写这个方法,在容器刷新的时候可以自定义逻辑
⑩ registerListeners():注册监听器:将容器中所有的ApplicationListener注册到事件派发器中,并派发之前步骤产生的事件:
⑪ finishBeanFactoryInitialization(beanFactory):初始化所有剩下的单实例bean,核心方法是preInstantiateSingletons(),会调用getBean()方法创建对象;
⑫ finishRefresh():发布BeanFactory容器刷新完成事件
12. 请简述Spring Bean的生命周期?
Spring Bean的生命周期包含下图的流程
(1)实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。
对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
(2)设置对象属性(依赖注入):实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成属性设置与依赖注入。
(3)处理Aware接口:Spring会检测该对象是否实现了xxxAware接口,通过Aware类型的接口,可以让我们拿到Spring容器的一些资源:
①如果这个Bean实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,传入Bean的名字;
②如果这个Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。
②如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
③如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
(4)BeanPostProcessor前置处理:如果想对Bean进行一些自定义的前置处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
(5)InitializingBean:如果Bean实现了InitializingBean接口,执行afeterPropertiesSet()方法。
(6)init-method:如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
(7)BeanPostProcessor后置处理:如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
(8)DisposableBean:当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
(9)destroy-method:最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
13. 请简述BeanFactory和ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。
(1)BeanFactory是Spring里面最底层的接口,是IoC的核心,定义了IoC的基本功能,包含了各种Bean的定义、加载、实例化,依赖注入和生命周期管理。ApplicationContext接口作为BeanFactory的子类,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
继承MessageSource,因此支持国际化。
资源文件访问,如URL和文件(ResourceLoader)。
载入多个(有继承关系)上下文(即同时加载多个配置文件) ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。
提供在监听器中注册bean的事件。
(2)
①BeanFactroy采用的是延迟加载形式来注入Bean的,只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能提前发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。
②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。
③ApplicationContext启动后预载入所有的单实例Bean,所以在运行的时候速度比较快,因为它们已经创建好了。相对于BeanFactory,ApplicationContext 唯一的不足是占用内存空间,当应用程序配置Bean较多时,程序启动较慢。
(3)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
(4)BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader
14. 请说明Spring中bean的作用域 ?
(1)singleton:默认作用域,单例bean,每个容器中只有一个bean的实例。
(2)prototype:为每一个bean请求创建一个实例。
(3)request:为每一个request请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
(4)session:与request范围类似,同一个session会话共享一个实例,不同会话使用不同的实例。
(5)global-session:全局作用域,所有会话共享一个实例。如果想要声明让所有会话共享的存储变量的话,那么这全局变量需要存储在global-session中。
15. Spring框架中的Bean是线程安全的么?如果线程不安全,那么如何处理?
Spring容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体情况还是要结合Bean的作用域来讨论。
(1)对于prototype作用域的Bean,每次都创建一个新对象,也就是线程之间不存在Bean共享,因此不会有线程安全问题。
(2)对于singleton作用域的Bean,所有的线程都共享一个单例实例的Bean,因此是存在线程安全问题的。但是如果单例Bean是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Controller类、Service类和Dao等,这些Bean大多是无状态的,只关注于方法本身。
有状态Bean(Stateful Bean) :就是有实例变量的对象,可以保存数据,是非线程安全的。
无状态Bean(Stateless Bean):就是没有实例变量的对象,不能保存数据,是不变类,是线程安全的。
对于有状态的bean(比如Model和View),就需要自行保证线程安全,最浅显的解决办法就是将有状态的bean的作用域由“singleton”改为“prototype”。
也可以采用ThreadLocal解决线程安全问题,为每个线程提供一个独立的变量副本,不同线程只操作自己线程的副本变量。
16. 请列举Spring基于xml注入bean的几种方式 ?
set()方法注入;
构造器注入:①通过index设置参数的位置;②通过type设置参数类型;
静态工厂注入;
实例工厂;
17. 阐述Spring如何解决循环依赖问题 ?
循环依赖问题在Spring中主要有三种情况:
(1)通过构造方法进行依赖注入时产生的循环依赖问题。
(2)通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题。
(3)通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题。
在Spring中,只有第(3)种方式的循环依赖问题被解决了,其他两种方式在遇到循环依赖问题时都会产生异常。这是因为:
第一种构造方法注入的情况下,在new对象的时候就会堵塞住了,其实也就是”先有鸡还是先有蛋“的历史难题。
第二种setter方法(多例)的情况下,每一次getBean()时,都会产生一个新的Bean,如此反复下去就会有无穷无尽的Bean产生了,最终就会导致OOM问题的出现。
Spring在单例模式下的setter方法依赖注入引起的循环依赖问题,主要是通过二级缓存和三级缓存来解决的,其中三级缓存是主要功臣。解决的核心原理就是:在对象实例化之后,依赖注入之前,Spring提前暴露的Bean实例的引用在第三级缓存中进行存储
18. 简述Spring的自动装配 ?
在Spring中,使用autowire来配置自动装载模式,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象。
(1)在Spring框架xml配置中共有5种自动装配:
no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。
byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。
byType:通过参数的数据类型进行自动装配。
constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。
(2)基于注解的自动装配方式:
使用@Autowired、@Resource注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
如果查询的结果不止一个,那么@Autowired会根据名称来查找;
如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。
@Autowired可用于:构造函数、成员变量、Setter方法
注:@Autowired和@Resource之间的区别:
(1) @Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
(2) @Resource默认是按照名称来装配注入的,只有当找不到与名称匹配的bean才会按照类型来装配注入
19. 详细阐述Spring事务的实现方式和实现原理 ?
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。Spring只提供统一事务管理接口,具体实现都是由各数据库自己实现,数据库事务的提交和回滚是通过 redo log 和 undo log实现的。Spring会在事务开始时,根据当前环境中设置的隔离级别,调整数据库隔离级别,由此保持一致。
(1)Spring事务的种类:
spring支持编程式事务管理和声明式事务管理两种方式:
①编程式事务管理使用TransactionTemplate。
②声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前启动一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中,减少业务代码的污染。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。
(2)spring的事务传播机制:
spring事务的传播机制说的是,当多个事务同时存在的时候,spring如何处理这些事务的行为。事务传播机制实际上是使用简单的ThreadLocal实现的,所以,如果调用的方法是在新线程调用的,事务传播实际上是会失效的。
① PROPAGATION_REQUIRED:(默认传播行为)如果当前没有事务,就创建一个新事务;如果当前存在事务,就加入该事务。
② PROPAGATION_REQUIRES_NEW:无论当前存不存在事务,都创建新事务进行执行。
③ PROPAGATION_SUPPORTS:如果当前存在事务,就加入该事务;如果当前不存在事务,就以非事务执行。‘
④ PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
⑤ PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则按REQUIRED属性执行。
⑥ PROPAGATION_MANDATORY:如果当前存在事务,就加入该事务;如果当前不存在事务,就抛出异常。
⑦ PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
(3)Spring中的隔离级别:
① ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。
② ISOLATION_READ_UNCOMMITTED:读未提交,允许事务在执行过程中,读取其他事务未提交的数据。
③ ISOLATION_READ_COMMITTED:读已提交,允许事务在执行过程中,读取其他事务已经提交的数据。
④ ISOLATION_REPEATABLE_READ:可重复读,在同一个事务内,任意时刻的查询结果都是一致的。
⑤ ISOLATION_SERIALIZABLE:所有事务逐个依次执行。
20. 思考Spring 框架中都用到了哪些设计模式?
(1)工厂模式:Spring使用工厂模式,通过BeanFactory和ApplicationContext来创建对象
(2)单例模式:Bean默认为单例模式
(3)策略模式:例如Resource的实现类,针对不同的资源文件,实现了不同方式的资源获取策略
(4)代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术
(5)模板方法:可以将相同部分的代码放在父类中,而将不同的代码放入不同的子类中,用来解决代码重复的问题。比如RestTemplate, JmsTemplate, JpaTemplate
(6)适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式,Spring MVC中也是用到了适配器模式适配Controller
(7)观察者模式:Spring事件驱动模型就是观察者模式的一个经典应用。
(8)桥接模式:可以根据客户的需求能够动态切换不同的数据源。比如我们的项目需要连接多个数据库,客户在每次访问中根据需要会去访问不同的数据库
21. 请简述Spring框架中有哪些不同类型的事件?
答案
Spring 提供了以下5种标准的事件:
(1)上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。
(2)上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。
(3)上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。
(4)上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。
(5)请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。
如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知
22. 请问什么是Java Spring注解 ?
答案
Java 注解就是代码中的一些特殊标记(元信息),用于在编译、类加载、运行时进行解析和使用,并执行相应的处理。它本质是继承了 Annotation 的特殊接口,其具体实现类是 JDK 动态代理生成的代理类,通过反射获取注解时,返回的也是 Java 运行时生成的动态代理对象 $Proxy1。通过代理对象调用自定义注解的方法,会最终调用 AnnotationInvocationHandler 的 invoke 方法,该方法会从 memberValues 这个Map中查询出对应的值,而 memberValues 的来源是Java常量池。
注解在实际开发中非常常见,比如 Java 原生的 @Overried、@Deprecated 等,Spring的 @Controller、@Service等,Lombok 工具类也有大量的注解,不过在原生 Java 中,还提供了元 Annotation(元注解),他主要是用来修饰注解的,比如 @Target、@Retention、@Document、@Inherited 等。
@Target:标识注解可以修饰哪些地方,比如方法、成员变量、包等,具体取值有以下几种:ElementType.TYPE/FIELD/METHOD/PARAMETER/CONSTRUCTOR/LOCAL_VARIABLE/ANNOTATION_TYPE/PACKAGE/TYPE_PARAMETER/TYPE_USE
@Retention:什么时候使用注解:SOURCE(编译阶段就丢弃) / CLASS(类加载时丢弃) / RUNTIME(始终不会丢弃),一般来说,我们自定义的注解都是 RUNTIME 级别的,因为大多数情况我们是根据运行时环境去做一些处理,一般需要配合反射来使用,因为反射是 Java 获取运行是的信息的重要手段
@Document:注解是否会包含在 javadoc 中;
@Inherited:定义该注解与子类的关系,子类是否能使用。
23. 简述Spring如何自定义注解?
答案
① 创建一个自定义注解:与创建接口类似,但自定义注解需要使用 @interface
② 添加元注解信息,比如 @Target、@Retention、@Document、@Inherited 等
③ 创建注解方法,但注解方法不能带有参数
④ 注解方法返回值为基本类型、String、Enums、Annotation 或其数组
⑤ 注解可以有默认值;
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface CarName {
String value() default “”;
}
24. Spring AOP和AspectJ AOP有什么区别?
答案
Spring AOP是属于运行时增强,而AspectJ是编译时增强。Spring AOP基于代理(Proxying),而AspectJ基于字节码操作(Bytecode Manipulation)。
Spring AOP已经集成了AspectJ,AspectJ应该算得上是Java生态系统中最完整的AOP框架了。AspectJ相比于Spring AOP功能更加强大,但是Spring AOP相对来说更简单。
如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择AspectJ,它比SpringAOP快很多
25. 简述Spring中的单例Bean的线程安全问题?
答案
大部分时候我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例bean存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。
有两种常见的解决方案:
1.在bean对象中尽量避免定义可变的成员变量(不太现实)
2.在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中(推荐的一种方式)
26. 简述@Component和@Bean的区别 ?
答案
1.作用对象不同。@Component注解作用于类,而@Bean注解作用于方法。
2.@Component注解通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用@ComponentScan注解定义要扫描的路径)。@Bean注解通常是在标有该注解的方法中定义产生这个bean,告诉Spring这是某个类的实例,当我需要用它的时候还给我。
3.@Bean注解比@Component注解的自定义性更强,而且很多地方只能通过@Bean注解来注册bean。比如当引用第三方库的类需要装配到Spring容器的时候,就只能通过@Bean注解来实现。
@Bean注解的使用示例:
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
上面的代码相当于下面的XML配置:
下面这个例子是无法通过@Component注解实现的:
@Bean
public OneService getService(status) {
case (status) {
when 1:
return new serviceImpl1();
when 2:
return new serviceImpl2();
when 3:
return new serviceImpl3();
}
}
27. 简述将类声明为Spring的bean的注解有哪些方式 ?
答案
我们一般使用@Autowired注解去自动装配bean。而想要把一个类标识为可以用@Autowired注解自动装配的bean,可以采用以下的注解实现:
1.@Component注解。通用的注解,可标注任意类为Spring组件。如果一个Bean不知道属于哪一个层,可以使用@Component注解标注。
2.@Repository注解。对应持久层,即Dao层,主要用于数据库相关操作。
3.@Service注解。对应服务层,即Service层,主要涉及一些复杂的逻辑,需要用到Dao层(注入)。
4.@Controller注解。对应Spring MVC的控制层,即Controller层,主要用于接受用户请求并调用Service层的方法返回数据给前端页面
28. Spring事务中的隔离级别有哪几种?
答案
在TransactionDefinition接口中定义了五个表示隔离级别的常量:
ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql默认采用的REPEATABLE_READ隔离级别;Oracle默认采用的READ_COMMITTED隔离级别。
ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别
29. 简述Spring事务中有哪几种事务传播行为?
答案
在TransactionDefinition接口中定义了八个表示事务传播行为的常量。
支持当前事务的情况:
PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)。
不支持当前事务的情况:
PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
其他情况:
PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED。
30. 简述什么是Spring IoC容器 以及其优点 ?
答案
Spring框架官方文档说:控制反转(IoC)容器是Spring框架中最重要的部分,没有之一。控制反转(Inversion of Control, IoC),是面向对象编程的一种设计原则,可以用来降低代码之间的耦合度。其中最常见的方式叫作依赖注入(Dependency Injection, 简称DI, @Autowired),还有一种方式叫“依赖查找”(Dependency Lookup)。
通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递(注入)给它。换句话说,它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
控制反转,并不是什么先进的技术,只是一种设计原则或设计模式。对于IoC来说,最重要的就是容器。容器管理着Bean的生命周期,控制着Bean的依赖注入。
#控制反转(IoC)有什么作用?#
管理对象的创建和依赖关系的维护。对象的创建并不是一件简单的事,在对象关系比较复杂时,如果依赖关系需要程序员来维护,那是相当麻烦的。
解耦,由容器去维护具体的对象
托管了类的产生过程,比如需要在类的产生过程中做一些处理,最直接的例子就是代理,如果有容器程序可以把这部分处理交给容器,应用程序则无需关心类是如何完成代理的。
**优点:**集中管理对象,方便维护,降低耦合度
31. 简述什么是Spring的依赖注入(DI)?
答案
首先要理解什么是依赖。依赖的解释:依赖是一种关系,一个类依赖另一个类,也就是一个类中有另一个类的引用。依赖注入的思想是不直接new对象,而是通过传递外部引用,也就是通过外部注入依赖。依赖注入的主要作用是让相互协作的软件组件保持松散耦合。因此
#Spring的依赖注入的含义是:#
依赖注入(DI,DependencyInjection),也叫控制反转(IoC,inversion of control)是Spring框架的核心机制
Spring中的依赖注入就是上面说的外部,实例不再由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类。
32. 简述Spring IoC的实现机制 ?
答案
Spring IOC 的实现原理主要包括以下几个方面:
类扫描和装载
在Spring IOC容器启动时,会先进行XML配置文件的解析,然后通过类扫描器扫描指定的包路径,找出所有标注为@Component、@Service、@Controller、@Repository等注解的Java类,并将它们加载到JVM中。
Bean定义解析
将扫描出来的各个Java类根据它们的注解类型,解析成相应的Bean定义对象,并将这些Bean定义对象保存在Spring IOC容器内的Bean定义注册表中。
Bean实例化
Spring IOC容器根据Bean定义注册表中的信息,通过反射机制创建一个个Bean实例,并将其保存在单例Bean缓存池中。
Bean属性注入
在Bean实例化之后,Spring IOC容器会检测Bean中是否有需要自动注入的属性,并根据属性类型进行匹配注入。属性注入可以通过构造器注入、Setter方法注入以及注解注入等方式实现。
生命周期管理
Spring IOC容器中的Bean在创建和销毁时都会触发相应的生命周期事件,Spring IOC容器要负责监听和管理这些事件。当Spring IOC容器启动时,会先执行所有注册的Bean的初始化方法;当Spring IOC容器关闭时,会执行所有注册的Bean的销毁方法。
AOP支持
Spring IOC容器还提供了AOP的支持,通过动态代理技术,在Bean调用时动态地将一些公共逻辑织入Bean的方法中,从而避免了代码的冗余。
33. Spring框架提供的容器有哪些?
答案
( 1 )Spring BeanFactory容器
最简单的容器,给DI提供了基本的支持。类全名为org.springframework.beans.factory.BeanFactory。
public static void main(String[] args){
//ClassPathResource加载在路径CLASSPATH下可用的xml配置文件
//XmlBeanFactory负责创建并初始化所有对象,即xml文件中的Bean
XmlFactory factory = new XmlBeanFactory(new ClassPathResource(“.xml"));
类名 对象名 = (类名)factory.getBean("”);
}
( 2 )Spring ApplicationContext容器
在Spring BeanFactory容器的基础上,添加了更多企业特定的功能,该类的全名为org.springframework.context.ApplicationContext。较BeanFactory而言,可以加载配置文件中定义的bean,将所有bean集中在一起,有请求的时候分配bean。
public static void main(String[] args){
//ApplicationContext接口的实现类有很多种,这里使用ClassPathXmlApplicationContext
ApplicationContext app = new ClassPathXmlApplicationContext(“.xml");
类名 对象名 =(类名)app.getBean("”);
}
34. 简述BeanFactory的作用 ?
答案
BeanFactory是Spring中非常核心的一个顶层接口;
它是Bean的工厂,它的主要职责就是生产Bean;
它实现了简单工厂的设计模式,通过调用getBean传入标识生产一个Bean;
它有非常多的实现类,每个工厂都有不同的职责(单一职责)功能,最强大的工厂是:DefaultListableBeanFactory,Spring底层就是使用的该实现工厂进行生产Bean的。
在Spring Framework中, BeanFactory作为非常基础的接口存在,提供了Bean注册能力(包括Bean查询、类型判断、scope判断等基础能力);在继承体系上,可以分成 BeanFactory实现类和 ApplicationContext两条继承线路。
两者的关系如下:BeanFactory实现类属于外观模式的子系统(SubSystem)承担着外界提供Bean对象的主要责任,是功能实现的主体;ApplicationContext作为BeanFactory实现类的外观系统(Facade System),通过 BeanFactory 提供的接口结合具体的业务场景解析元数据( BeanDefinition )的解析和注册,并进行Bean对象的初步加载。另外, ApplicationContext继承于接口 BeanFactory ,并在 BeanFactory的基础上,提供AoP能力的集成、消息资源的管理、事件发布机制、以及基于特定场景(Web系统、文件系统)的能力封装等主要功能。
BeanFactory 的主要实现类: BeanFactory 的主要实现类包括 StaticListableBeanFactory、 DefaultListableBeanFactory、 SimpleJndiBeanFactory等三个公共类,分别面向静态场景、默认枚举配置场景和JNDI等场景,对应的实现思路也不尽相同。
StaticListableBeanFactory可以看做是基于 Map的简单封装,不包括Bean的实例化过程,需要用户手动注册后才可以使用,不具备依赖注入能力,是 BeanFactory最为简单的实现;
DefaultListableBeanFactory是Spring BeanFactory的默认实现,是Spring IoC容器中最为复杂的部分;
SimpleJndiBeanFactory则是基于JNDI场景发现对应Bean。
35. 简述Spring ApplicationContext ?
答案
ApplicationContext 的主要实现类是 ClassPathXmlApplicationContext 和 FileSystemApplicationContext, 前者默认从类路径加载配置文件, 后者默认从文件系统中装载配置文件. ApplicationContext继承了 ListableBeanFactory 和 HierarchicalBeanFactory 接口. 还通过多个其他的接口扩展了 BeanFactory 的功能.
这些接口如下:
ApplicationEventPublisher: 让容器拥有发布应用上下文事件的功能, 包括容器启动事件, 关闭事件等. 实现了 ApplicationListerer事件监听接口的Bean 可以接收到容器事件, 并对事件进行响应处理.
MessageSource: 为应用提供 il8n 国际化消息访问的功能.
ResourcePatternResolver: 所有ApplicationContext实现类都实现了类似于 PathMatchingResourcePatternResolver 的功能. 可以通过资源文件路径装载配置文件.
LifeCycle: 该接口提供了 start()和stop() 两个方法, 主要用于异步处理过程. 在具体使用时, 该接口同时被 ApplicationContext实现及具体Bean实现, ApplicationContext会将 start/stop 的信息传递给容器中所有实现了该接口的Bean. 以达到管理和控制JMX, 任务调度等目的
36. 简述BeanDefinition的作用 ?
答案
BeanDefinition它主要负责存储Bean的定义信息:决定Bean的生产方式。
BeanDefinition在Spring中是用来描述Bean对象的,其不是一个bean实例,仅仅是包含bean实例的所有信息,比如属性值、构造器参数以及其他信息。Bean对象创建是根据BeanDefinition中描述的信息来创建的,BeanDefinition存在的作用是为了可以方便的进行修改属性值和其他元信息,比如通过BeanFactoryPostProcessor进行修改一些信息,然后在创建Bean对象的时候就可以结合原始信息和修改后的信息创建对象了。
BeanDefinition 是定义 Bean 的配置元信息接口,包含:
Bean 的类名
设置父 bean 名称、是否为 primary、
Bean 行为配置信息,作用域、自动绑定模式、生命周期回调、延迟加载、初始方法、销毁方法等
Bean 之间的依赖设置,dependencies
构造参数、属性设置
派生出 AnnotatedBeanDefinition 接口,以及常用子类 RootBeanDefinition、GenericBeanDefinition。可以使用 BeanDefinitionBuilder 或 new BeanDefinition 实现类构建 BeanDefinition 对象
37. 请简述BeanFactory和FactoryBean的区别 ?
答案
两者的区别在:前者是工厂类,简单理解成 beanName和bean对象映射关系的维护者(是个容器),提供根据beanName查询bean对象的能力;后者是工厂类,描述的是Bean对象实例化的过程,用于生成特定类型的对象。BeanFactory is a factory, FactoryBean is a bean。
FactoryBean 当你向容器注册名字为 factoryBeanName 的 FactoryBean的时候,你向容器注册的是 名字为&factoryBeanName的FactoryBean的对象,,通过factoryBeanName获取到的是 FactoryBean#getObject 返回的对象,该对象不受Spring 容器管理,具体参考What’s a FactoryBean?。
当创建Bean的过程中涉及到多个依赖对象的复杂配置(不是简单的属性注册),或者存在一定的复用性时,可以通过 FactoryBean 简化一部分实例过程,减少无关Bean的注册。例如 AbstractEntityManagerFactoryBean 相关实现
38. 简述Spring IOC有哪些扩展点,在什么时候调用 ?
答案
对 Spring 的 Ioc 容器来说,主要有:BeanFactoryPostProcessor, BeanPostProcessor。他们分别是在构建 BeanFactory和构建 Bean 对象时调用。还有就是InitializingBean 和DisposableBean, 他们分别是在 Bean 实例创建和销毁时被调用。用户可以实现这些接口中定义的方法,Spring 就会在适当的时候调用他们。还有一个是 FactoryBean 它是个特殊的 Bean,这个 Bean 可以被用户更多的控制。
这些扩展点通常也是我们使用Spring来完成特定任务的地方
-
BeanDefinitionRegistryPostProcessor接口
BeanDefinitionRegistryPostProcessor接口继承了BeanFactoryPostProcessor接口,作用是动态注册BeanDefinition,调用时机是在IoC加载时注册BeanDefinition的时候这个接口扩展了标准的BeanFactoryPostProcessor接口,允许在普通的BeanFactoryPostProcessor接口实现类执行之前注册更多的BeanDefinition。特别是BeanDefinitionRegistryPostProcessor可以注册BeanFactoryPostProcessor的BeanDefinition. -
BeanFactoryPostProcessor接口
BeanFactory生成后,如果想要对BeanFactory做一些处理,可以使用BeanFactoryPostProcessor接口。换句话说,就是在注册BeanDefinition的时候可以对beanFactory进行扩展。调用时机是在Ioc加载时注册BeanDefinition的时候调用
39. 简述Bean实例化中有哪些扩展?
答案
1:InstantiationAwareBeanPostProcessor接口,该接口是BeanPostProcessor的子接口,用于在实例化之后,但在设置显示属性或自动装配之前,设置实例化之前的回调函数。通常用于抑制特定目标bean的默认实例化。例如创建具有特殊TargetSource(池化目标,延迟初始化目标等)的代理,或者实现其他注册策略,如字段注入
2:BeanPostProcessor接口,这个接口允许自定义修改新的bean实例,例如检查标记接口或用代理包装,注意,如果有相互依赖的bean,这里可能无法使用代理
3:InitializingBean接口
在执行完BeanPostProcessor的postProcessBeforeInitialization方法后,如果这个bean实现了InitializingBean接口,则会去调用afterPropertiesSet方法
4:各种Aware
在在执行完BeanPostProcessor的postProcessBeforeInitialization方法前,如果bean实现了BeanNameAware或BeanClassLoaderAware或BeanFactoryAware,则会调用接口相关的方法,入参就是这个bean关心的值
5:BeanDefinition入口扩展
在定义bean时,可以指定构造函数,设置属性,还可以设置init-method和destroy-method。构造函数不用说,设置属性是在InstantiationAwareBeanPostProcessor#PostProcessPropertyValues方法后执行的,init-method是在InitializingBean的afterPropertiesSet方法后执行的,而destroy-method是在容器关闭是被调用的
40. Spring的扩展点中的接口是怎么在Spring中生效的?
答案
换句话说,也就是扩展点在什么时候被调用或者被添加到BeanFactory中等待调用呢?
首先从容器级别分析,重点关注上下文的抽象类AbstractApplicationContext#refresh方法,源码如下:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 设置上下文启动时间和活跃标记,同时加载属性资源。
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 停掉之前启动的beanFactory如果有的话,同时新生成一个beanFactory,加载配置中的BeanDefinition。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 给beanFactory设置类加载器,添加后置处理器ApplicationContextAwareProcessor
等等。
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset ‘active’ flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring’s core, since we
// might not ever need metadata for singleton beans anymore…
resetCommonCaches();
}
}
}
其中
invokeBeanFactoryPostProcessors方法的调用逻辑是:
如果beanFactory是BeanDefinitionRegistry的实现类,拿到入参所有的BeanFactoryPostProcessor接口实现类,挑选出实现BeanDefinitionRegistryPostProcessor接口的实现类先执行postProcessBeanDefinitionRegistry方法。
然后调用beanFactory中实现BeanDefinitionRegistryPostProcessor接口的实现类中实现PriorityOrdered接口的实现类,调用这些实现类前先根据PriorityOrdered的getOrder方法进行排序,然后再按顺序调用postProcessBeanDefinitionRegistry方法。
接着再调用beanFactory中实现BeanDefinitionRegistryPostProcessor接口的实现类中实现了Ordered接口的类,也是按顺序调用postProcessBeanDefinitionRegistry方法。
最后调用beanFactory中其他的实现BeanDefinitionRegistryPostProcessor接口的实现类的postProcessBeanDefinitionRegistry方法。
最终先调用入参中所有实现BeanDefinitionRegistryPostProcessor接口的实现类的postProcessBeanFactory方法,再调用入参中实现了BeanFactoryPostProcessor接口的实现类的postProcessBeanFactory方法。
如果不是则只把入参中的BeanFactoryPostProcessor实现类全部调用一遍。
上边都做完了,接着从beanFactory中获取实现了BeanFactoryPostProcessor接口的bean(没有被执行过),也是分为三类,PriorityOrdered组优先调用,Ordered其次,其他垫底。
最终清除beanFactory的metaData缓存
registerBeanPostProcessors方法的调用逻辑是:
首先添加BeanPostProcessorChecker;
然后把beanFactory中实现BeanPostProcessor接口的实现类分成四个部分分别添加到beanFactory:
PriorityOrdered部分,实现了PriorityOrdered接口且并不属于MergedBeanDefinitionPostProcessor的
Ordered部分,实现了Ordered接口且并不属于MergedBeanDefinitionPostProcessor的
其他的不属于MergedBeanDefinitionPostProcessor的
属于MergedBeanDefinitionPostProcessor的
其中PriorityOrdered和Ordered部分先排序,然后按上边的顺序分别加入到beanFactory的beanPostProcessors属性中
然后考虑bean级别,其余的bean上的接口属性之类的,都是在bean的生成中逐个调用的
41. 解释JavaBean和SpringBean和对象的区别?
答案
(1)什么是JavaBean:
JavaBean是一种JAVA语言写的可重用组件。JavaBean符合一定规范写的Java类,是一种规范。它的方法命名
1.所有属性为private
2.这个类必须具有一个公共的(public)无参构造函
3.private属性必须提供public的getter和setter来给外部访问,并且方法的命名也必须遵循一定的命名规范
4.这个类是可序列化的,要实现serializable接口
(2)么是SpringBean
SpringBean是受Spring管理的对象 所有能受Spring容器管理的对象都可以成为SpringBean.
二者之间的区别:
用处不同:传统javabean更多地作为值传递参数,而spring中的bean用处几乎无处不在,任何组件都可以被称为bean
写法不同:传统javabean作为值对象,要求每个属性都提供getter和setter方法;但spring中的bean只需为接受设值注入的属性提供setter方法
生命周期不同:传统javabean作为值对象传递,不接受任何容器管理其生命周期;spring中的bean有spring管理其生命周期行为
42. 简述Sprint配置Bean有哪几种方式?
答案
1 通过XML方式:<\bean class=“com.example.UserService” id=“”>
2 注解:@Component(@Controller、@Service、@Repostory),前提是需要配置扫描包,底层通过反射调用构造方法
3 使用javaConfig: @Bean,标注在方法上,返回一个对象,可以自己控制实例化过程,通常和@Configuration一起使用
4 使用注解@Import:3种方式:ImportSelector,ImportBeanDefinitionRegistrar,直接导入一个其他的配置类@Import(SecondJavaConfig.class)
43. 简述Spring 提供了哪些配置方式?
答案
#1:基于 xml 配置
bean 所需的依赖项和服务在 XML 格式的配置文件中指定。这些配置文件通常包含许多 bean 定义和特定于应用程序的配置选项。它们通常以 bean 标签开头。例如:
#2:基于注解配置
您可以通过在相关的类,方法或字段声明上使用注解,将 bean 配置为组件类本身,而不是使用 XML 来描述 bean 装配。默认情况下,Spring 容器中未打开注解装配。因此,您需要在使用它之前在 Spring 配置文件中启用它。例如:
#3:基于 Java API 配置
Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。
@Bean 注解扮演与 元素相同的角色。
@Configuration 类允许通过简单地调用同一个类中的其他 @Bean 方法来定义 bean 间依赖关系。
例如:
@Configuration
public class StudentConfig {
@Bean
public StudentBean myStudent() {
return new StudentBean();
}
}
44. 请简述将类声明为Spring的 bean 的注解有哪些?
答案
一般使用 @Autowired 注解自动装配 bean,要想把类标识成可用于 @Autowired 注解自动装配的 bean 的类,采用以下注解可实现:
@Component :通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于哪个层,可以使用@Component 注解标注。 8 @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
@Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。
@Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。
45. 解释如果Spring中出现同名bean怎么办?
答案
同一个配置文件内同名的Bean,以最上面定义的为准
不同配置文件中存在同名Bean,后解析的配置文件会覆盖先解析的配置文件
同文件中ComponentScan和@Bean出现同名Bean。同文件下@Bean的会生效,@ComponentScan扫描进来不会生效。通过@ComponentScan扫描进来的优先级是最低的,原因就是它扫描进来的Bean定义是最先被注册的
46. 简述依赖注入的基本原则 ?
答案
依赖注入的基本原则是:应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由IoC容器负责,“查找资源”的逻辑应该从应用组件的代码中抽取出来,交给IoC容器负责。容器全权负责组件的装配,它会把符合依赖关系的对象通过属性(JavaBean中的setter)或者是构造器传递给需要的对象
47. 简述Spring有哪些不同类型的依赖注入实现方式?
答案
依赖注入是时下最流行的IoC实现方式,依赖注入分为接口注入(Interface Injection),Setter方法注入(Setter Injection)和构造器注入(Constructor Injection)三种方式。其中接口注入由于在灵活性和易用性比较差,现在从Spring4开始已被废弃。
构造器依赖注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。
Setter方法注入:Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入
48. 请简述Sping 构造器依赖注入和 Setter方法注入的区别 ?
答案
-
在Setter注入,可以将依赖项部分注入,构造方法注入不能部分注入,因为调用构造方法如果传入所有的参数就会报错。
-
如果我们为同一属性提供Setter和构造方法注入,Setter注入将覆盖构造方法注入。但是构造方法注入不能覆盖setter注入值。显然,构造方法注入被称为创建实例的第一选项。
-
使用setter注入你不能保证所有的依赖都被注入,这意味着你可以有一个对象依赖没有被注入。在另一方面构造方法注入直到你所有的依赖都注入后才开始创建实例。
-
在构造函数注入,如果A和B对象相互依赖:A依赖于B,B也依赖于A,此时在创建对象的A或者B时,Spring抛出ObjectCurrentlyInCreationException。所以Spring可以通过setter注入,从而解决循环依赖的问题
49. 简述Spring如何处理线程并发问题?
答案
在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域,因为Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal采用了“空间换时间”的方式。
ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal
50. 简述什么是Spring的内部bean?什么是Spring inner beans?
答案
在Spring框架中,当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean。内部bean可以用setter注入“属性”和构造方法注入“构造参数”的方式来实现,内部bean通常是匿名的,它们的Scope一般是prototype。
51. Spring中如何注入一个Java集合?
答案
Spring提供以下几种集合的配置元素:
类型用于注入一列值,允许有相同的值。
类型用于注入一组值,不允许有相同的值。
类型用于注入一组键值对,键和值都可以为任意类型。
类型用于注入一组键值对,键和值都只能为String类型。
52. 简述什么是bean的自动装配?
答案
在Spring框架中,在配置文件中设定bean的依赖关系是一个很好的机制,Spring 容器能够自动装配相互合作的bean,这意味着容器不需要和配置,能通过Bean工厂自动处理bean之间的协作。这意味着 Spring可以通过向Bean Factory中注入的方式自动搞定bean之间的依赖关系。自动装配可以设置在每个bean上,也可以设定在特定的bean上。
53. 解释不同方式的自动装配,spring 自动装配 bean 有哪些方式?
答案
在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用autowire来配置自动装载模式。
在Spring框架xml配置中共有5种自动装配:
no:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。
byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。
byType:通过参数的数据类型进行自动装配。
constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。
autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配
54. 简述使用@Autowired注解自动装配的过程?
答案
使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置,。
在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;
如果查询的结果不止一个,那么@Autowired会根据名称来查找;
如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false
55. 请问Spring自动装配有哪些局限性?
答案
自动装配的局限性是:
重写:你仍需用 和 配置来定义依赖,意味着总要重写自动装配。
基本数据类型:你不能自动装配简单的属性,如基本数据类型,String字符串,和类。
模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配
56. 解释可以在Spring中注入一个null 和一个空字符串吗?
答案
可以
57. 简述Spring怎样开启注解装配?
答案
注解装配在默认情况下是不开启的,为了使用注解装配,我们必须在Spring配置文件中配置 元素
58. 简述@Component, @Controller, @Repository, @Service 有何区别?
答案
@Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。
@Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。
@Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。
@Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException
59. 简述@Required 注解作用 ?
答案
这个注解表明bean的属性必须在配置的时候设置,通过一个bean定义的显式的属性值或通过自动装配,若@Required注解的bean属性未被设置,容器将抛出BeanInitializationException。示例:
public class Employee {
private String name;
@Required
public void setName(String name){
this.name=name;
}
public string getName(){
return name;
}
}
60. 简述@Autowired 注解的作用 ?
答案
@Autowired默认是按照类型装配注入的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。@Autowired 注解提供了更细粒度的控制,包括在何处以及如何完成自动装配。它的用法和@Required一样,修饰setter方法、构造器、属性或者具有任意名称和/或多个参数的PN方法。
public class Employee {
private String name;
@Autowired
public void setName(String name) {
this.name=name;
}
public string getName(){
return name;
}
}
61. 请简述@Autowired和@Resource之间的区别 ?
答案
一、@Autowired和@Resource都可以用来装配bean,都可以写在字段上,或者方法上。
二、@Autowired属于Spring的;@Resource为JSR-250标准的注释,属于J2EE的。
三、@Autowired默认按类型装配,默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,例如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:
@Autowired() @Qualifier(“baseDao”)
private BaseDao baseDao;
四、@Resource,默认安装名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
例如:
@Resource(name=“baseDao”)
private BaseDao baseDao;
五、推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。
1、@Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配
2、指定了name或者type则根据指定的类型去匹配bean
3、指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错
然后,区分一下@Autowired和@Resource两个注解的区别:
1、@Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配
2、@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了
Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。
个人见解:
1、@Autowired和@Resource都是基于@service、@controller、@repository以及xml配置中
2、@Autowired和@Resource匹配的内容取决于@service()括号内的内容或 spring的xml配置里 的id(xml配置优先)
3、如果使用@Resource,请最好这么写@Resource(name=”BWM”),因为他是默认按name匹配的,不填写就按type匹配
4、如果使用@Autowired,请最好不要加@Qualifier(“BWM”),因为他是默认按type匹配的,填写就按name匹配
5、其实@Autowired + @Qualifier(“BWM”) == @Resource(name=”BWM”),@Autowired ==@Resource()或@Resource,用哪个都可以
6、最好不要这么写 @Resource()+ @Qualifier(“BWM”) ,虽然也可以,但是感觉不伦不类,前者属于j2EE,后者属于spring
7、当 一个接口有两个以上实现类的时候才会用到@Autowired + @Qualifier(“BWM”) 或 @Resource(name=”BWM”),这时,如果使用的是xml,则不用担心,因为你一定会写id;
如果使用的是@Service(),请注意:最好在括号内写上name,和@Autowired +@Qualifier(“BWM”)或Resource(name=”BWM”)成对出现,增强可读性,避免出错,因为有一种特殊情况会使你出错,spring@Service生成bean的命名规则:当类的名字是以两个或以上连续的大写字母开头的话,bean的名字会与类名保持一致,首字母不小写
8、当一个接口只有一个实现类,@Autowired和@Resource没有区别,但是最好用@Autowired,原因请看下文
9、@Resource默认按name匹配,,当有一个接口有多个实现类的时候,引用都是一个接口,不好区分,才使用name区分,这种情况使用@Resource和@Autowired都可以,推荐使用@Resource,且都是按name匹配,一般不用type匹配,引用的是同一个接口,同一个type还有一种方式:使用byType类型时,使用@Service+@Primary组合,一个接口当有多个实现类,,@Primary强制指定一个实现类
10、@Autowired默认按type匹配,,当有一个接口只有有一个实现类的时候,引用是一个接口,只有一个实现类,没必要使用name区分,这种情况使用@Resource和@Autowired都可以,推荐使用@Autowired,一般都是按type匹配,也可以按name匹配,比较麻烦不推荐
(比如:一个与世隔绝的村子,只有一个姓李的人,大家叫他“老李”,都知道他是谁,就没必要叫名字。但是这个村要是有2-100姓李的,你叫“老李”,大家就不知道是叫谁了,这时候就要加名字。type=姓 name=名;如果有个姓李的,十分厉害,十分有名,那可能叫“老李”,就特指他一个人,优先级最高 ,等价于@Primary)
总结:
当一个接口只有一个实现类,推荐使用@Autowired,默认byType注入,不一定 真的byType,可以修改为byName,@Resource同理;
当一个接口有多个实现类,推荐使用@Resource,默认byName注入;
具体情况具体分析 : 比如当一个接口有多个实现类,用@Primary 告诉spring 在犹豫的时候(byName是不会犹豫的,会确定一个唯一实现类,@Primary没有意义)优先选择哪一个具体的实现。spring优先注入@Primary修饰的那个;或者使用@Qualifier来标注需要注入的类。
@Service是注入,生成bean实例,既有type也有name. @Service标注名称,如@Service(“Benz”),则bean的名称就是Benz,如果不标注,@Service(),spring会默认注入一个beanName,要注意特殊情况,看上文
@Autowired和@Resource只是查找匹配,然后给属性赋值。private Car car;
@Service
public class CarFactory {
@Resource(name=“benz”)//byName匹配,此时beanName=benz;如果将(name=“benz”)去掉,beanName=car,即属性名;只要byName匹配不到,就会使用byType匹配
private Car car;
public String toString(){
return car.carName();
}
public void Test(){
System.out.println(“it is ok!”);
}
}
如果@Resource(name=”benz”)换成@Autowired+@Qualifier(“benz”),此时也是按照byName,此时beanName=benz,如果再去掉@Qualifier(“benz”),就是byType匹配,beanType=XXX.Car.class
注意 :@Autowired和@Resource只是匹配beanName,决定注入beanName的是@service()括号内的name(没有的话spring会自动生成一个,有一个特殊情况请看上文)或 spring的xml配置里 的id=name(xml配置优先)
62. 简述@Qualifier 注解的作用 ?
答案
通过使用 @Qualifier 注解,我们可以消除需要注入哪个 bean 的问题。让我们重新回顾一下前面的例子,看看我们如何通过包含 @Qualifier 注释来指出我们想要使用哪个 bean 来解决问题:
@Component
public class FooService {
@Autowired
@Qualifier(“fooFormatter”)
private Formatter formatter;
//todo
}
通过将 @Qualifier 注解与我们想要使用的特定 Spring bean 的名称一起进行装配,Spring 框架就能从多个相同类型并满足装配要求的 bean 中找到我们想要的,避免让Spring脑裂。我们需要做的是@Component或者@Bean注解中声明的value属性以确定名称。
其实我们也可以在 Formatter 实现类上使用 @Qualifier 注释,而不是在 @Component 或者 @Bean 中指定名称,也能达到相同的效果:
@Component
@Qualifier(“fooFormatter”)
public class FooFormatter implements Formatter {
public String format() {
return “foo”;
}
}
@Component
@Qualifier(“barFormatter”)
public class BarFormatter implements Formatter {
public String format() {
return “bar”;
}
}
63. 简述@RequestMapping 注解作用 ?
答案
@RequestMapping 是 Spring Web 应用程序中最常被用到的注解之一。这个注解会将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上。并且一个处理请求地址映射的注解,可用在类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
以下为@RequestMapping的源码
package org.springframework.web.bind.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target( {
ElementType.METHOD, ElementType.TYPE
}
)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default “”;
@AliasFor(“path”)
String[] value() default {
}
;
@AliasFor(“value”)
String[] path() default {
}
;
RequestMethod[] method() default {
}
;
String[] params() default {
}
;
String[] headers() default {
}
;
String[] consumes() default {
}
;
String[] produces() default {
}
;
}
方法上:
请求 URL 的第二级访问目录。
属性:
value:用于指定请求的 URL。它和 path 属性的作用是一样的。
method:用于指定请求的方式。
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样。
例如:
params = {
“accountName”
}
,表示请求参数必须有
accountNameparams = {
“moeny!100”
}
,表示请求参数中 money 不能是 100。
headers:用于指定限制请求消息头的条件。
注意:
以上四个属性只要出现 2 个或以上时,他们的关系是与的关系。
作用:
用于建立请求URL和处理请求方法之间的对应关系。
64. Spring框架中如何更有效地使用JDBC?
答案
使用Spring JDBC 框架,资源管理和错误处理的代价都会被减轻。所以开发者只需写statements 和 queries从数据存取数据,JDBC也可以在Spring框架提供的模板类的帮助下更有效地被使用,这个模板叫JdbcTemplate
65. 解释Spring JDBC 抽象和 DAO 模块 ?
答案
通过使用 JDBC 抽象和 DAO 模块,保证数据库代码的简洁,并能避免数据库资源错误关闭导致的问题,它在各种不同的数据库的错误信息之上,提供了一个统一的异常访问层。它还利用 Spring 的 AOP 模块给 Spring 应用中的对象提供事务管理服务。
66. 解释Spring DAO 作用?
答案
Spring DAO 使得 JDBC,Hibernate 或 JDO 这样的数据访问技术更容易以一种统一的方式工作。这使得用户容易在持久性技术之间切换。它还允许您在编写代码时,无需考虑捕获每种技术不同的异常。
67. Spring JDBC API 中存在哪些类?
答案
JDBC API 是一种 Java API,用于访问几乎任何类型的表格数据。(作为一个兴趣点,JDBC 是商标名称,并不是首字母缩略词,然而 JDBC 通常被认为代表 Java 数据库连接。)JDBC API 由一组用 Java 编写的类和接口组成。为工具/数据库开发人员提供标准 API 的编程语言,可以使用全 Java API 编写工业级数据库应用程序。
JdbcTemplate
SimpleJdbcTemplate
NamedParameterJdbcTemplate
SimpleJdbcInsert
SimpleJdbcCall
68. 简述 JdbcTemplate是什么 ?
答案
JdbcTemplate 类提供了很多便利的方法解决诸如把数据库数据转变成基本数据类型或对象,执行写好的或可调用的数据库操作语句,提供自定义的数据错误处理
69. Spring通过什么方式访问Hibernate?使用 Spring 访问 Hibernate 的方法有哪些?
答案
在Spring中有两种方式访问Hibernate:
使用 Hibernate 模板和回调进行控制反转
扩展 HibernateDAOSupport 并应用 AOP 拦截器节点
70. 如何通过HibernateDaoSupport将Spring和Hibernate结合起来?
答案
用 Spring 的 SessionFactory 调用 LocalSessionFactory。集成过程分三步:
配置 the Hibernate SessionFactory
继承 HibernateDaoSupport 实现一个 DAO
在 AOP 支持的事务中装配。
71. 简述JDK动态代理和CGLIB动态代理的区别 ?
答案
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。
如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最终生成的代理实例; method 是被代理目标实例的某个具体方法; args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用
72. 如何理解 Spring 中的代理?
答案
将 Advice 应用于目标对象后创建的对象称为代理。在客户端对象的情况下,目标对象和代理对象是相同的
Advice + Target Object = Proxy
73. Spring在运行时通知对象是什么?
答案
通过在代理类中包裹切面,Spring在运行期把切面织入到Spring管理的bean中。代理封装了目标类,并拦截被通知方法的调用,再把调用转发给真正的目标bean。当代理拦截到方法调用时,在调用目标bean方法之前,会执行切面逻辑。
直到应用需要被代理的bean时,Spring才创建代理对象。如果使用的是ApplicationContext的话,在ApplicationContext从BeanFactory中加载所有bean的时候,Spring才会创建被代理的对象。因为Spring运行时才创建代理对象,所以我们不需要特殊的编译器来织入SpringAOP的切面。
74. 解释为什么Spring只支持方法级别的连接点?
答案
因为Spring基于动态代理,所以Spring只支持方法连接点。Spring缺少对字段连接点的支持,而且它不支持构造器连接点。方法之外的连接点拦截功能,我们可以利用Aspect来补充。
75. Spring AOP 中,关注点和横切关注的区别是什么?
答案
关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。
横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点
76. 详细解释什么是切面 Aspect?
答案
aspect 由 pointcount 和 advice 组成,切面是通知和切点的结合。 它既包含了横切逻辑的定义, 也包括了连接点的定义. Spring AOP 就是负责实施切面的框架, 它将切面所定义的横切逻辑编织到切面所指定的连接点中.
AOP 的工作重心在于如何将增强编织目标对象的连接点上, 这里包含两个工作:
如何通过 pointcut 和 advice 定位到特定的 joinpoint 上
如何在 advice 中编写切面代码.
可以简单地认为, 使用 @Aspect 注解的类就是切面。
77. 简述解释基于XML Schema方式的切面实现 ?
答案
在这种情况下,切面由常规类以及基于XML的配置实现。
78. 解释Spring有几种不同类型的自动代理?
答案
三种
BeanNameAutoProxyCreator
DefaultAdvisorAutoProxyCreator
Metadata autoproxying
79. Spring 框架中事务管理有哪些优点?
答案
Spring框架事务管理为不同的事务API,如JTA、JDBC、Hibernate、JPA和JDO,提供一个不变的编程模式
Spring框架为编程式事务管理提供了一套简单的API而不是一些复杂的事务API。
Spring框架支持声明式事务管理。
Spring框架和Spring各种数据访问抽象层很好得集成
80. 简述Spring Native 框架是什么?
答案
Spring团队发布Spring Native Beta版。
通过Spring Native,Spring应用将有机会以GraalVM原生镜像的方式运行。
为了更好地支持原生运行,Spring Native提供了Maven和Gradle插件,并且提供了优化原生配置的注解
81. 简述Spring Native 的优缺点?
答案
Spring Native优点
1)立即启动,一般启动时间小于100ms;
2)更低的内存消耗;
3)独立部署,不再需要JVM;
4)同样的峰值性能要比JVM消耗的内存小。
Spring Native缺点
1)构建时间长;
2)只支持新的Springboot版本(Spring Native 0.9.0 supports Spring Boot 2.4.3, Spring Native 0.9.1 will support Spring Boot 2.4.4, etc.)
82. 简述Spring 中如何定义 Bean 的范围?
答案
在Spring中定义一个时,我们也可以为bean声明一个范围。它可以通过bean定义中的scope属性定义。
例如,当Spring每次需要生成一个新的bean实例时,bean的scope属性就是原型。另一方面,当每次需要Spring都必须返回相同的bean实例时,bean的scope属性必须设置为singleton。
注:bean的scope属性有prototype,singleton,request, session几个属性
83. 简述@RequestParam注解的作用 ?
答案
@RequestParam是Spring MVC框架中的一个注解,它的作用是将请求参数绑定到方法的参数上。
在Spring
MVC框架中,当浏览器向服务器发起请求时,请求中可能会包含一些参数,例如查询字符串或表单数据。使用@RequestParam注解可以将这些请求参数的值映射到控制器方法的参数上,从而方便地获取和使用这些参数。
@RequestParam注解有以下属性:
value:请求参数的名称。如果请求参数的名称与方法参数的名称相同,则该属性可以省略。
required:指定请求参数是否是必需的,默认为true。如果设置为false,则表示该参数是可选的。
defaultValue:指定当请求参数未提供时使用的默认值。
例如,以下代码演示了如何在控制器方法中使用@RequestParam注解来获取请求参数:
@RequestMapping(“/hello”)
public String hello(@RequestParam(“name”) String name, @RequestParam(value = “age”, required = false, defaultValue = “0”) int age) {
System.out.println("Hello " + name + “, you are " + age + " years old.”);
return “hello”;
}
在上面的示例中,我们使用@RequestParam注解将"name"和"age"请求参数映射到控制器方法的"name"和"age"参数上。我们还指定了"age"参数是可选的,并且当请求中未提供"age"参数时使用默认值0。
@RequestParam注解是Spring MVC框架中用于绑定HTTP请求参数到方法参数的注解。它的作用是告诉Spring MVC框架要从HTTP请求中获取特定名称的参数,并将其赋值给注解所标注的方法参数。
84. 简述Spring中@Primary注解 ?
答案
Spring的@Primary注解,该注解是框架在3.0版中引入的。
其作用与功能,当有多个相同类型的bean时,使用@Primary来赋予bean更高的优先级
85. Spring中XML配置和注解之间有什么区别?
答案
XML 配置可以和注解混合使用,但是混合使用的话,XML 配置会覆盖 annotation (注解),因此并不推荐混合使用。
XML 配置的优点:
XML 配置方式进一步降低了耦合,是的应用更容易拓展,即使对配置文件进一步修改也不需要对工程进行修改和重新编译。
在处理打业务量的时候,使用 XML 配置应该更好一些,因为 XML 中更加清晰的表明了各个对象之间的关系,各个业务类之间的调用。同时 Spring 的配置也能一目了然
若用 XML 配置大量业务代码时,会使 XML 文件过大,不易查看,这一点可以通过利用业务分解书写多个 XML 配置文件解决
XML 配置的缺点:
配置文件读取和解析需要花费一定时间
配置文件过多的时候难以管理
无法对配置的正确性进行校验,增加了测试难度
注解配置的优点:
注解在 class 文件中,可以降低维护成本,annotation 的配置机制简单明显
不需要第三方解析工具,利用反射技术就可以完成任务
编辑期即可验证正确性,查错更容易
注解配置的缺点:
如果需要对 annotation 进行修改,需要重新编译整个工程
业务类之间的关系不如 XML 配置那样容易把握
如果在程序中 annotation 过多,直接影响代码质量,对于代码的简洁度有一定的影响
86. 简述@SpringBootApplication的作用 ?
答案
@SpringBootApplication 注解是在springboot1.2.0中引入的,它支持自动配置特性。
此批注封装了三种不同注解的作用:
@Configuration:允许开发人员显式地注册bean
@ComponentScan:启用组件扫描,这样控制器类和其他组件将被自动发现并注册为Spring应用程序上下文中的bean
@EnableAutoConfiguration:启动SpringBoot的自动配置特性
此注解可以使用以下可选参数:
exclude:从自动配置中排除的类列表
excludeNames:从自动配置中排除完全限定类名的列表
scanBasePackage:其中提供了扫描程序包的列表
scanBasePackageClasses:提供必须应用于扫描的其他包中的类的列表
87. 简述Spring @InitBinder ?
答案
@InitBinder注解可以作用在被@Controller注解的类的方法上,表示为当前控制器注册一个属性编辑器,用于对WebDataBinder进行初始化,且只对当前的Controller有效。@InitBinder标注的方法会被多次执行的,也就是说来一次请求就会执行一次@InitBinder注解方法的内容。
A. @InitBinder注解是在其所标注的方法执行之前被解析和执行;
B. @InitBinder的value属性,控制的是模型Model里的KEY,而不是方法名;
C. @InitBinder标注的方法也不能有返回值;
D. @InitBinder对@RequestBody这种基于消息转换器的请求参数是失效的。
应用场景
用于将前端传递过来的数据进行类型转换或者叫属性编辑,如:将前端传递过来的字符串格式的日期数据,转化为DATE类型。
作用范围
@InitBinder是属于Controller级别的属性编辑器,并非全局级别(针对所有Controller)的属性编辑器,也就是一个@InitBinder只对当前所在的Controller有效,对其他Controller无效的,如果项目中有多个Controller中都要进属性编辑怎么办呢?一般我们将@InitBinder标注的方法定义在基础的控制器上,所有具体的Controller继承这个基础的Controller即可。
/**
- WEB层通用数据处理
- @author ROCKY
*/
public class BaseController {
/**
- 将前端传递过来的日期格式的字符串转化为Date类型,否则无法将数据绑定到实体中。
- 自定义类型转换器有两种方式:A. implements Converter 或者 B. extends PropertyEditorSupport;
- 在WebDataBinder对象中,可以设置前缀,可以设置允许、禁止的字段、必填字段以及验证器,可以自定义类型转换器。
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
// Date 类型转换
binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) {
setValue(DateUtils.parseDate(text));
}
});
}
}
88. 简述Spring @ControllerAdvice ?
答案
这是一个增强的 Controller,对controller层做异常处理、数据预处理、全局数据绑定, springboot 会自动扫描到,不需要调用。
这个注解是spring MVC提供的,在springboot中也可以使用
全局异常处理
使用 @ControllerAdvice 注解,相当于开启了全局异常捕获,具体实现只需两步:
第一步:定义类,添加 @ControllerAdvice 注解,开启全局异常捕获;
第二步:在方法上,使用 @ExceptionHandler,定义捕获异常的类型即可。
@ControllerAdvice
public class ControllerExceptionHandler {
/**
- 校验的统一异常处理
- @param e
- @return ComResponse
- BindException 有针对性的,是校验不通过时,报的错误异常类做处理
- Exception 对所有的报错异常做处理
*/
@ExceptionHandler(value = {BindException.class})
@ResponseBody
public ComResponse validExceptionHandler(BindException e) {
// 获取我们定义的校验失败的异常信息
String msg = e.getBindingResult().getAllErrors().get(0).getDefaultMessage();
ComResponse comResponse = new ComResponse<>();
comResponse.setMsg(msg);
comResponse.setSuccess(false);
return comResponse;
}
}
在该类中,你可以定义多个方法,不同方法吹不同的异常,只需要指定:@ExceptionHandler(value = {xxxException.class}),例如专门做空指针的处理方法,专门做数组越界的处理方法。
@ExceptionHandler 注解来指明异常的处理类型,上边例子中,指定BindException类型,那么除了参数校验抛出的异常,其他异常不会进这个方法中来。
89. 简述@ControllerAdvice和@RestControllerAdvice区别?
答案
在具体使用上:
1)注解有@ControllerAdvice的类, 需要在具体方法上同时添加@ExceptionHandler和@ResponseBody注解;
2)注解有@RestControllerAdvice的类,只需要在具体方法上添加@ExceptionHandler注解。
90. 解释Spring注解 @ModelAttribute?
答案
注解用途
@ModelAttribute注解用于将方法的参数或方法的返回值绑定到指定的模型属性上,并返回给Web视图
注释方法
被@ModelAttribute注解注释的方法会在此Controller每个方法执行前被执行
91. 简述如何通过spring JdbcTemplate获取数据?
答案
有两个接口可用于从数据库中获取数据:
ResultSetExtractor
RowMapper
92. 简述NamedParameterJdbcTemplate以及其优点 ?
答案
NamedParameterJdbcTemplate建立在spring提供的JDBCTemplate之上,用于与数据库的低层通信。 它使得可以将SQL查询参数作为键值对传递。 结果,程序代码比索引或“?”更具可读性,因此可以作为更好的文档。 占位符方法。 如果参数数量巨大,则后者尤其难以遵循
93. 简述JDBC和Spring JDBC有什么区别?
答案
Spring jdbc就是在原生的JDBC代码上进行封装,提供一些接口,节省大量代码,传统的JDBC步骤为:建立连接、定义sql,执行sql,返回结果集、关闭连接释放资源。而在spring中,只需要调用相应的接口来实现sql定义和获取结果集,其他步骤都可以由spring实现。
94. Spring 应用程序有哪些不同组件?
答案
Spring 应用一般有以下组件:
接口 - 定义功能。
Bean 类 - 它包含属性,setter 和 getter 方法,函数等。
Spring 面向切面编程(AOP) - 提供面向切面编程的功能。
Bean 配置文件 - 包含类的信息以及如何配置它们。
用户程序 - 它使用接口
95. 请列举Spring 支持哪些 ORM 框架 ?
答案
Hibernate
MyBatis
iBatis
JPA
JDO
OJB
96. 简述AOP 中的 Aspect、Advice、Pointcut、JointPoint 和 Advice 参数分别是什么?
答案
Aspect - Aspect 是一个实现交叉问题的类,例如事务管理。方面可以是配置的普通类,然后在 Spring Bean 配置文件中配置,或者我们可以使用 Spring AspectJ 支持使用 @Aspect 注解将类声明为 Aspect。
Advice - Advice 是针对特定 JoinPoint 采取的操作。在编程方面,它们是在应用程序中达到具有匹配切入点的特定 JoinPoint 时执行的方法。您可以将 Advice 视为 Spring 拦截器(Interceptor)或 Servlet 过滤器(filter)。
Advice Arguments - 我们可以在 advice 方法中传递参数。我们可以在切入点中使用 args() 表达式来应用于与参数模式匹配的任何方法。如果我们使用它,那么我们需要在确定参数类型的 advice 方法中使用相同的名称。
Pointcut - Pointcut 是与 JoinPoint 匹配的正则表达式,用于确定是否需要执行 Advice。 Pointcut 使用与 JoinPoint 匹配的不同类型的表达式。Spring 框架使用 AspectJ Pointcut 表达式语言来确定将应用通知方法的 JoinPoint。
JoinPoint - JoinPoint 是应用程序中的特定点,例如方法执行,异常处理,更改对象变量值等。在 Spring AOP 中,JoinPoint 始终是方法的执行器
97. 指出在 Spring AOP中 concern 和 cross-cutting concern 的不同 ?
答案
concern 是我们想要在应用程序的特定模块中定义的行为。它可以定义为我们想要实现的功能。
cross-cutting concern 是一个适用于整个应用的行为,这会影响整个应用程序。例如,日志记录,安全性和数据传输是应用程序几乎每个模块都需要关注的问题,因此它们是跨领域的问
98. 简述Spring中什么是编织(Weaving)?
答案
为了创建一个 advice 对象而链接一个 aspect 和其它应用类型或对象,称为编织(Weaving)。在 Spring AOP 中,编织在运行时执行
99. 简述Spring事务的传播级别 ?
答案
Spring事务定义了7种传播机制:
- PROPAGATION_REQUIRED:默认的Spring事物传播级别,若当前存在事务,则加入该事务,若不存在事务,则新建一个事务。
- PAOPAGATION_REQUIRE_NEW:若当前没有事务,则新建一个事务。若当前存在事务,则新建一个事务,新老事务相互独立。外部事务抛出异常回滚不会影响内部事务的正常提交。
- PROPAGATION_NESTED:如果当前存在事务,则嵌套在当前事务中执行。如果当前没有事务,则新建一个事务,类似于REQUIRE_NEW。
- PROPAGATION_SUPPORTS:支持当前事务,若当前不存在事务,以非事务的方式执行。
- PROPAGATION_NOT_SUPPORTED:以非事务的方式执行,若当前存在事务,则把当前事务挂起。
- PROPAGATION_MANDATORY:强制事务执行,若当前不存在事务,则抛出异常.
- PROPAGATION_NEVER:以非事务的方式执行,如果当前存在事务,则抛出异常。
Spring事务传播级别一般不需要定义,默认就是PROPAGATION_REQUIRED,除非在嵌套事务的情况下需要重点了解。
100. 下列Spring MVC注解中,可以映射多种HTTP请求类型的是( ) ?
A @RequestMapping
B @GetMapping
C @PostMapping
D @DeleteMapping
答案
A
@RequestMapping注解可以映射多种HTTP请求类型,具体的类型通过method配置项指定。为了简化method配置项,Spring 4.3版本新增了几个注解,这些注解可以看成是@RequestMapping注解的快捷方式,相当于固定了method配置项的值,这些注解包括:@GetMapping、@PostMapping、@PatchMapping、@PutMapping、@DeleteMapping。
101. 简述下列选项中,不属于Spring IoC注入方式的是( ) ?
A基于属性注入
B基于构造方法注入
C基于setter方法注入
D基于getter方法注入
答案
D Spring IoC的注入方式有三种,分别是基于属性注入、基于构造方法注入、基于setter方法注入。
102. 简述下列关于Spring MVC注解的描述中,错误的是( ) ?
A @RequestMapping可以声明类或方法的访问路径,还可以声明请求的方式。
B @PathVariable可以将请求路径中的参数,绑定到控制器中方法的参数。
C @RequestParam可以将请求对象中的参数,绑定到控制器中方法的参数。
D @ResponseBody用于向浏览器响应字符串,它只能应用于异步请求之中。
答案
D @ResponseBody一般在异步获取数据时使用,但不代表它只能应用于异步请求之中。
103. 简述关于Spring AOP的织入,下列说法错误的是( ) ?
A织入,就是将方面组件中定义的横切逻辑,织入到目标对象的连接点的过程。
B可以在编译时织入,需要使用特殊的编译器。
C可以在装载类时织入,需要使用特殊的类装载器。
D可以在运行时织入,需要使用特殊的JRE。
答案
D
104. 简述在Spring MVC中,我们可以通过URL携带参数。例如,“/user/{id}” 是为某Controller中某方法声明的访问路径,其中“{id}”代表这一级携带的是id参数。那么,下列注解中可以用于提取id参数的是( ) ?
A @RequestParam
B @RequestMapping
C @ResponseBody
D @PathVariable
答案
D 用于从URL中提取参数的注解是@PathVariable。
105. Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,其中PROPAGATION_REQUIRED代表( ) ?
A 支持当前事务,如果当前没有事务,则以非事务方式执行。
B 使用当前的事务,如果当前没有事务,则抛出异常。
C 新建事务,如果当前存在事务,则把当前事务挂起。
D 如果当前没有事务,则新建一个事务;如果已存在一个事务,则加入到这个事务中
答案
D PROPAGATION_SUPPORTS支持当前事务,如果当前没有事务,则以非事务方式执行;PROPAGATION_MANDATORY传播行为使用当前的事务,如果当前没有事务,则抛出异常;PROPAGATION_REQUIRES_NEW新建事务,如果当前存在事务,则把当前事务挂起。
106. 简述在BeanFactory定义方法中,哪个方法可以用于获取Bean的Class类型( ) ?
A getType(String name)
B getBean(String name)
C containsBean(String name)
D isSingleton(String name)
答案
A getBean(String name)方法是从Spring容器中获取对应Bean对象的方法,如存在,则返回该对象。containsBean(String name)方法用于判断Spring容器中是否存在该对象。isSingleton(String name)方法用于判断Bean对象是否为单例对象
107. 关于Spring MVC开发,下列说法错误的是( ) ?
A 在控制器的方法中,我们可以直接使用Request、Response对象处理请求与响应。
B ModelAndView对象,既可以存储模型数据,又可以存储模板路径。
C Model对象只能存放模型数据,它和ModelAndView一样,需要主动实例化。
D Spring MVC的核心组件是DispatcherServlet,它负责分发所有的请求。
答案
C
108. 简述下列关于@Transactional注解的说法中,错误的是( ) ?
A @Transactional可以作用在类上,代表这个类的所有方法都将启用事务。
B 可以通过@Transactional的propagation属性,指定事务的传播行为。
C 可以通过@Transactional的isolation属性,指定事务的隔离级别。
D 可以通过@Transactional的rollbackFor属性,指定发生哪些异常时回滚。
答案
A @Transactional可以作用在类上,代表这个类的所有公共非静态方法都将启用事务。
109. 简述下列关于@RequestParam注解的说明中,错误的是( ) ?
A @RequestParam注解用于对HTTP请求参数和控制器方法参数进行映射。
B @RequestParam注解的value成员用于指定要映射的HTTP请求参数名。
C @RequestParam注解的required成员用于指定该参数是否必填。
D @RequestParam注解的required成员默认值为false,也就是映射的参数默认可以为空。
答案
D @RequestParam注解的required成员用于指定该参数是否必填,其默认值为true,也就是映射的参数默认不能为空。
110. 简述下列选项中,哪一个不是Spring MVC的核心组件( ) ?
A DispatcherServlet
B SpringFactoriesLoader
C HandlerMapping
D ModelAndView
答案
B SpringFactoriesLoader是Spring Boot的组件,不是Spring MVC的组件。
111. 关于Spring AOP的术语,下列说法错误的是( ) ?
A 连接点(join point),对应的是具体被拦截的对象,因为Spring只支持方法,所以被拦截的对象往往就是指特定的方法,AOP将通过动态代理技术把它织入对应的流程中。
B 切点(point cut),有时候,我们的切面不单单应用于单个方法,也可能是多个类的不同方法,这时,可以通过正则式和指示器的规则去定义,从而适配连接点。切点就是提供这样一个功能的概念。
C 通知(advice),就是按照约定的流程下的方法,分为前置通知、后置通知、环绕通知、事后返回通知和异常通知,它会根据约定织入流程中。
D 切面(aspect),即被代理的对象。
答案
D 切面(aspect),是一个可以定义切点、各类通知和引入的内容,SpringAOP将通过它的信息来增强Bean的功能或者将对应的方法织入流程。
112. 简述Spring对事务隔离级别提供了支持,并通过枚举类型Propagation定义了7种事务隔离级别,下列关于Propagation成员的解释中错误的是( ) ?
A REQUIRED:若当前存在事务,就沿用当前事务,否则就新建一个事务来运行此方法。
B REQUIRED_NEW:无论当前是否存在事务,都要新建一个事务来运行此方法。
C SUPPORTS:若当前存在事务,就沿用当前事务,否则就采用无事务的方式运行此方法。
D NESTED:无论当前是否存在事务,都创建嵌套事务,并在嵌套事务中运行此方法。
答案
D NESTED表示,若当前存在事务,则采用嵌套事务执行此方法,否则就创建新事务来执行此方法。
113. Spring Bean 的默认作用范围是( ) ?
A singleton
B prototype
C request
D session
答案
A
114. 简述关于Spring AOP的几种通知方式,下列说法错误的是( ) ?
A前置通知会在执行目标方法之前运行。
B目标方法运行结束之后,无论有没有异常发生后置通知都会触发。
C目标方法出现异常后会触发异常通知,然后才会触发返回通知。
D环绕通知可以决定目标方法的调用也可以控制返回对象。
答案
C
115. 简述关于Spring MVC拦截器,下列说法错误的是( ) ?
A 开发Spring MVC拦截器,需实现WebMvcConfigurer接口。
B preHandle方法在Controller之前执行,若返回false,则终止执行后续的请求。
C postHandle方法在Controller之后、模板之前执行。
D afterCompletion方法在模板之后执行。
答案
A 拦截器需实现HandlerInterceptor接口,而WebMvcConfigurer接口是MVC配置类要实现的接口。
116. 简述下列关于@ComponentScan注解的说法中,错误的是( ) ?
A @ComponentScan注解用于定义Bean的扫描策略。
B @ComponentScan注解默认规则是对当前包的子包中的Bean进行扫描。
C @ComponentScan注解的basePackages属性用于自定义要扫描哪些包。
D @ComponentScan注解只是定义了扫描范围,在此范围内带有特定注解的Bean才会被载入容器
答案
B @ComponentScan注解默认规则是对当前包及其子包中的Bean进行扫描。
117. 简述在Spring事务的ISOLATION_REPEATABLE_READ隔离级别下,有可能出现以下哪种情况( ) ?
A 脏读
B 幻读
C 不可重复读
D 都有可能发生
答案
B ISOLATION_REPEATABLE_READ隔离级别下,对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,这种隔离级别可以阻止脏读和不可重复读,但幻读仍有可能发生。
118. 简述下列不属于Spring Boot注解的是( ) ?
A @Controller
B @EnableAutoConfiguration
C @Conditional
D @SpringBootApplication
答案
A @Controller是Spring MVC的注解。
119. 简述@RequestMapping注解的属性不包括以下哪个( ) ?
Amethod
Bvalue
Crequired
Dparams
答案
C method属性代表指定请求的method的类型,value属性指请求的实际地址,params是指定request中一定要有的参数值。required是@RequestParam注解的属性,是指该参数是否为必传项,默认为true,表示请求中一定要传入对应的参数。
120. 简述下列选项中,哪个不是Spring MVC拦截器的方法( ) ?
A preHandle()
B postHandle()
C afterHandle()
D afterCompletion()
答案
C Spring MVC拦截器包含三个方法:preHandle()、postHandle()、afterCompletion()。
121. 简述下列选项中,属于Spring MVC的注解的有( ) ?
A@RequestMapping
B@RequestParam
C@RequestBody
D@PathVariable
答案
ABCD
122. Spring创建Bean的方式有哪几种方式( ) ?
A 构造器
B 接口
C 实例工厂
D 静态工厂
答案
ACD Spring容器创建Bean对象的方法有三种方式,分别是:用构造器来实例化,使用静态工厂方法实例化和使用实例工厂方法实例化。
123. 在使用@Autowired注解时,如果一个类可以有多种类型,就会对Spring IoC 容器注入造成困扰,这种情况我们称之为歧义性,为解决这一问题,我们可以使用( )注解 ?
A @Component
B @Primary
C @Resource
D @Qualifier
答案
BD 当发现有多种类型的Bean时,@Primary注解会通知IoC容器优先使用它所标注的Bean进行注入;@Quelifier注解可以与@AutoWired注解组合使用,达到通过类型和名称一起筛选Bean的效果
124. 简述以下关于@Autowired注解说法正确的是( ) ?
A @Autowired是Spring提供的注解。
B @Autowired是JDK提供的注解。
C @Autowired注解只能根据类型注入Bean。
D @Autowired注解既可以根据类型注入Bean也可以根据名称注入Bean
答案
A C
@Autowired是Spring提供的注解,它提供这样的规则:首先根据类型找到对应的Bean, 如果对应类型的 Bean 不是唯一的,那么就根据属性名称和Bean的名称进行匹配。如果匹配得上,就会使用该Bean;如果还无法匹配,就会抛出异常
125. 下列关于Spring MVC注解的说法中,正确的是( ) ?
A@ControllerAdvice用于定义控制器的通知类,它可以对指定的控制器进行增强。
B@InitBinder用于定义控制器参数绑定规则,如转换规则,它会在参数转换之前执行。
C@ExceptionHandler用于定义控制器发生异常后的操作。
D@ModelAttribute用于定义控制器方法执行之前,对数据模型的操作。
答案
ABCD
126. 简述下列选项中,属于Spring Bean的作用域的是( ) ?
A singleton
B prototype
C request
D response
答案
ABC
Spring容器中Bean包含五种作用域:singleton、prototype、request、session、globalSession。
127. 简述关于IoC注解,下面说法错误的是( ) ?
A@Autowired用于注入Bean,该注解只能写在成员变量的前面。
B@Qualifier用于声明Bean的名称,该注解只能引用Bean的自定义名称。
C@Bean用于装配第三方的Bean,它不能装配自定义的Bean。
D@Configuration用于声明配置类,该注解是基于@Component实现的。
答案
ABC @AutoWired注解还可以写在set方法、构造器上;@Qualifier注解也可以引用默认名称;@Bean注解可以用于装配任何Bean。
128. 下列关于Spring事务管理的描述中,错误的是( )?
A
A Spring提供了声明式事务、编程式事务两种事务管理方案。
B 声明式事务,只需通过XML或注解进行配置,即可实现对事务的管理。
C 编程式事务,需要通过TransactionTemplate组件执行SQL,达到管理事务的目的。
D 声明式事务优于编程式事务,应该一律采用声明式事务。
答案
D 在有些场景下,我们需要获取事务的状态,是执行成功了还是失败回滚了,那么使用声明式事务就不够用了,需要编程式事务。
129. 简述若要在Controller中声明一个访问路径为“/set”,并且只能响应POST请求的方法,则下列注解中正确的是( ) ?
A @RequestMapping(“/set”)
B @RequestMapping(path = “/set”)
C @RequestMapping(path = “/set”, method = RequestMethod.POST)
D 其他选项都正确
答案
C
130. 简述已知项目中定义了如下Controller: ?
@Controller
@RequestMapping(“/user”)
public class UserControlelr {
@RequestMapping(path = “/otp/{phone}”, method = RequestMethod.GET)
@ResponseBody
public String getOTP(@PathVariable(“phone”) String phone) {
…
}
}
以下URL中,可以正确访问UserController的getOTP方法的是( )
A /user/otp
B /otp/user
C /user/otp/13912345678
D /otp/13912345678/user
答案
C Controller中方法的访问路径是“类的访问路径+方法的访问路径”,而getOTP()方法的访问路径有两级,其中第二级是代表手机号的字符串,所以正确答案是C。
131. SpringBoot注解中,主要功能是启动Spring应用程序上下文时进行自动配置的注解是( ) ?
A@SpringBootApplication
B@Import
C@EnableAutoConfiguration
D@Conditional
答案
C @EnableAutoConfiguration的主要功能是启动Spring应用程序上下文时进行自动配置,它会尝试猜测并配置项目可能需要的Bean。自动配置通常是基于项目classpath中引入的类和已定义的Bean来实现的,在此过程中,被自动配置的组件来自项目自身和项目依赖的jar包中。
132. 下列关于@Bean注解的说法中,错误的是( ) ?
A @Bean注解作用在方法上,表示该方法的返回值将被装配到容器中。
B @Bean注解包含name属性,可以通过该属性指定装配的Bean的名称。
C @Bean注解依赖于@Configuration注解,即它所在的类必须带有@Configuration注解。
D @Bean注解可以装配任意的Bean,尤其适合装配那些初始化过程十分复杂的Bean
答案
C @Bean注解通常出现在带有@Configuration注解的类中,但这不是必要的条件,它也可以出现在带有@Component注解的类中,甚至是普通的类中。
原文地址:https://blog.csdn.net/jylee/article/details/140624909
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!