个人整理的面试题汇总(七)——Spring相关

it2026-01-26  5

IOC

IOC(Inversion Of Control)控制反转。两种实现方式:DL(依赖查找),DI(依赖注入)。Spring就是实现的DI。

IOC的想法是通过一个第三方的IOC容器实现各个相互依赖对象之间的解耦。通过引入IOC容器,可以使复杂系统中的各个对象不再相互依赖,使每个开发者可以只关注于实现自己的类,与别人的工作没有任何关系。比如在没有IOC容器这个“粘合剂”时,当类A代码的某个阶段,需要用到类B时,需要主动的创建对象B,或者调用已经创建好的B对象,也就是对象A依赖于对象B。而有了IOC容器,就可以实现类A不主动的创建B对象,在需要B对象的地方,IOC会创建一个对象B给对象A使用,这样对象A就与对象B失去了联系,创建B的行为也由A主动创建变成了IOC容器创建,A被动接受,也就是说A对B的控制权颠倒了过来,也就是IOC控制反转的名称的由来。

IOC的问题 1. IOC依赖反射,而反射在运行效率上有些损失,因此追求效率的项目需要斟酌对IOC的使用。2. 需要进行大量的配置工作,同时由于新引入的IOC容器使创建对象变得复杂,客观上增加了成本。

Spring中IOC的实现方式 Spring设计了两个接口来表示容器:BeanFactory和ApplicationContext,前者为低级容器,后者为高级容器,实际上,IOC只靠低级容器BeanFactory就可以实现。BeanFactory可以认为他是一个HashMap,key是beanname,value是该bean的实例。调用 getBean 的时候,从 BeanDefinition 所属的 Map 里,拿出 Class 对象进行实例化,同时,如果有依赖关系,将递归调用 getBean 方法, 完成依赖注入。上面就是 Spring 低级容器(BeanFactory)的 IoC。

MVC框架

MVC是Model—View—Controler的简称,它是一种架构模式,它分离了表现与交互。它被分为三个核心部件:模型、视图、控制器。

下面是每一个部件的分工:

Model(模型),是程序的主体部分,主要包含业务数据和业务逻辑。在模型层,还会涉及到用户发布的服务,在服务中会根据不同的业务需求,更新业务模型中的数据。

View(视图),是程序呈现给用户的部分,是用户和程序交互的接口,用户会根据具体的业务需求,在View视图层输入自己特定的业务数据,并通过界面的事件交互,将对应的输入参数提交给后台控制器进行处理。

Controller(控制器),Controller是用来处理用户输入数据,以及更新业务模型的部分。控制器中接收了用户与界面交互时传递过来的数据,并根据数据业务逻辑来执行服务的调用和更新业务模型的数据和状态。

通过这种设计模型把应用逻辑,处理过程和显示逻辑分成不同的组件实现,这些组件可以进行交互和重用。

使用MVC有哪些好处?

1.各司其职,互不干涉

在MVC模式中,三个层各施其职,所以如果一旦哪一层的需求发生了变化,就只需要更改相应的层中的代码而不会影响到其它层中的代码。

2.有利于开发中的分工

在MVC模式中,由于按层把系统分开,那么就能更好的实现开发中的分工。网页设计人员可以进行开发视图层中的JSP,对业务熟悉的开发人员可开发业务层,而其它开发人员可开发控制层。

3.有利于组件的重用

分层后更有利于组件的重用。如控制层可独立成一个能用的组件,视图层也可做成通用的操作界面。

SpringMVC细节,和Servlet的关系

一、首先说mvc和单独一个servlet的区别: 如果我的tomcat服务器要实现一个功能,比如说接收一个请求,从数据库里查出一条用户信息(select),然后返回到服务器,那么不用mvc的方法是: 只有一个servlet也可以实现,自定义一个servlet,在tomcat的web.xml的中注册,接收 /select 请求,在servlet里手写实现jdbc接口连接数据库完成查询,得到response的输出流,把查询结果write到页面上。这样耦合度很高,向页面上写response也很麻烦。 使用mvc模式可以降低耦合度,jsp也可以简化输出的过程。Controller层的servlet接受请求信息,调用Model层的Dao的方法实现与数据库的连接、查询,将查到的数据利用View层jsp技术显示给用户。 二、为什么要用springmvc: 这时候要再实现几个功能,向数据库中添加用户(insert),删除用户(delete),更改用户(update)等等功能,如果传统mvc模式怎么做? (一)写几个新的servlet。然后在web.xml中注册新sevlet,并映射对应的/insert /delete /update /XXX,在这些新的servlet中调用View和Model层完成功能。 这样新定义servlet的方法比较麻烦,要去继承HttpServlet接口,实现接口方法,手写调用jsp的重定向或者请求转发,还要再web.xml中注册。 (二)直接在原来的servlet中添加方法。然后把web.xml中原来的/select改成 / 来映射所有请求,在原来的servlet中加入判断,不同的请求执行不同的方法。 这第(二)种实现方法,仔细想一想,是不是和springmvc就有点像了?这时这仅有一个的servlet就对应着springmvc中的DispatcherServlet,我们写的实现这些功能的方法就对应着springmvc中我们要写的很多controller,我们在servlet中写的判断,springmvc就通过处理器映射器、处理器适配器这两大组件帮我们实现了。即: 我们写的单一的servlet------------------------>springmvc的DispatcherServlet 我们servlet里的判断语句---------------------->处理器映射器,处理器适配器 我们servlet里的方法----------------------------->各种controller 三、总结 springmvc框架三大组件(DispatcherServlet,处理器映射器,处理器适配器)就是一个可以处理多种请求的强大的servlet。它长这样:

public class DispatcherServlet implements Servlet{ //main方法 public void main{ if(映射器说要执行A){ this.controllerA(); } if(映射器判断要执行B){ this.controllerB(); } } //Controller就是各种方法 public TA controllerA(){ } public TB controllerB(){ } }

AOP

对于OOP语言来说,当需要为部分对象引入公共部分的时候,OOP就会引入大量的重复代码【这些代码我们可以称之为横切代码】。而这也是Aop出现的原因,没错,Aop就是被设计出来弥补OOP短板的。Aop便是将这些横切代码封装到一个可重用模块中,继而降低模块间的耦合度,这样也有利于后面维护。

Ioc的主要作用是应用对象之间的解耦,而Aop则可以实现横切代码【如权限、日志等】与他们绑定的对象之间的解耦,举个浅显易懂的小栗子,在用户调用很多接口的地方,我们都需要做权限认证,判断用户是否有调用该接口的权限,如果每个接口都要自己去做类似的处理,未免有点sb了,也不够装x,因此Aop就可以派上用场了,将这些处理的代码放到切片中,定义一下切片、连接点和通知,就可以运行了。

PointCut【切点】 其实切点的概念很好理解,你想要去切某个东西之前总得先知道要在哪里切入是吧,切点格式如下:execution( *com.nuofankj.springdemo.aop.Service.(…)) 可以看出来,格式使用了正常表达式来定义那个范围内的类、那些接口会被当成切点,简单明了。

Advice Advice行内很多人都定义成了通知,但是我总觉得有点勉强。所谓的Advice其实就是定义了Aop何时被调用,确实有种通知的感觉,何时调用其实也不过以下几种:

Before 在方法被调用之前调用After 在方法完成之后调用After-returning 在方法成功执行之后调用After-throwing 在方法抛出异常之后调用Around 在被通知的方法调用之前和调用之后调用

JoinPoint【连接点】 JoinPoint连接点,其实很好理解,上面又有通知、又有切点,那和具体业务的连接点又是什么呢?没错,其实就是对应业务的方法对象,因为我们在横切代码中是有可能需要用到具体方法中的具体数据的,而连接点便可以做到这一点。

Spring AOP(Aspect Oriented Programming,面向切面编程)是OOPs(面向对象编程)的补充,它也提供了模块化。在面向对象编程中,关键的单元是对象,AOP的关键单元是切面,或者说关注点(可以简单地理解为你程序中的独立模块)。一些切面可能有集中的代码,但是有些可能被分散或者混杂在一起,例如日志或者事务。这些分散的切面被称为横切关注点。一个横切关注点是一个可以影响到整个应用的关注点,而且应该被尽量地集中到代码的一个地方,例如事务管理、权限、日志、安全等。 AOP让你可以使用简单可插拔的配置,在实际逻辑执行之前、之后或周围动态添加横切关注点。这让代码在当下和将来都变得易于维护。如果你是使用XML来使用切面的话,要添加或删除关注点,你不用重新编译完整的源代码,而仅仅需要修改配置文件就可以了。 Spring AOP通过以下两种方式来使用。但是最广泛使用的方式是Spring AspectJ 注解风格(Spring AspectJ Annotation Style)

使用AspectJ 注解风格使用Spring XML 配置风格

在Java中动态代理有两种方式:

JDK动态代理CGLib动态代理

JDK动态代理是需要实现某个接口了,而我们类未必全部会有接口,于是CGLib代理就有了~~

CGLib代理其生成的动态代理对象是目标类的子类Spring AOP默认是使用JDK动态代理,如果代理的类没有接口则会使用CGLib代理。

那么JDK代理和CGLib代理我们该用哪个呢??在《精通Spring4.x 企业应用开发实战》给出了建议:

如果是单例的我们最好使用CGLib代理,如果是多例的我们最好使用JDK代理

原因:

JDK在创建代理对象时的性能要高于CGLib代理,而生成代理对象的运行性能却比CGLib的低。如果是单例的代理,推荐使用CGLib

看到这里我们就应该知道什么是Spring AOP(面向切面编程)了:将相同逻辑的重复代码横向抽取出来,使用动态代理技术将这些重复代码织入到目标对象方法中,实现和原来一样的功能。

这样一来,我们就在写业务时只关心业务代码,而不用关心与业务无关的代码

所以必须得深化点,你得告诉他,aop实现原理其实是java动态代理,但是jdk的动态代理必须实现接口,所以spring的aop是用cglib这个库实现的,cglib使用了asm这个直接操纵字节码的框架,所以可以做到不实现接口的情况下完成动态代理。

代理模式: 代理(Proxy)是一种设计模式,提供了间接对目标对象进行访问的方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的功能上,增加额外的功能补充,即扩展目标对象的功能.这就符合了设计模式的开闭原则,即在对既有代码不改动的情况下进行功能的扩展。

举个例子来说明代理的作用:明星与经纪人之间就是被代理和代理的关系,明星出演活动的时候,明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.这就是代理思想在现实中的一个例子。

静态代理

在使用静态代理时,被代理对象与代理对象需要一起实现相同的接口或者是继承相同父类,因此要定义一个接口或抽象类.

静态代理总结: 优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展. 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.而动态代理方式可以解决上面的问题

动态代理

动态代理的主要特点就是能够在程序运行时JVM才为被代理对象生成代理对象。

常说的动态代理也叫做JDK代理也是一种接口代理,JDK中生成代理对象的代理类就是Proxy,所在包是java.lang.reflect

总结:代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能使用动态代理,因此这也算是这种方式的缺陷。

Cglib代理

上面的静态代理和动态代理模式有个相同点就是都要求目标对象是实现一个接口的对象,然而并不是任何对象都会实现一个接口,也存在没有实现任何的接口的对象,这时就可以使用继承目标类以目标对象子类的方式实现代理,这种方法就叫做:Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.

使用JDK动态代理有一个限制,就是被代理的对象必须实现一个或多个接口,若想代理没有实现接口的类,就需要使用Cglib实现.

总结:

在Spring的AOP编程中:

如果加入容器的目标对象有实现接口,用JDK代理

如果目标对象没有实现接口,用Cglib代理。

https://www.cnblogs.com/jie-y/p/10732347.html

Spring事务

1、事务认识 大家所了解的事务Transaction,它是一些列严密操作动作,要么都操作完成,要么都回滚撤销。Spring事务管理基于底层数据库本身的事务处理机制。数据库事务的基础,是掌握Spring事务管理的基础。这篇总结下Spring事务。 事务具备ACID四种特性,ACID是Atomic(原子性)、Consistency(一致性)、Isolation(隔离性)和Durability(持久性)的英文缩写。 (1)原子性(Atomicity) 事务最基本的操作单元,要么全部成功,要么全部失败,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。 (2)一致性(Consistency) 事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。 (3)隔离性(Isolation) 指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。 (4)持久性(Durability) 指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。 2、事务的传播特性 事务传播行为就是多个事务方法调用时,如何定义方法间事务的传播。Spring定义了7中传播行为: (1)propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是Spring默认的选择。 (2)propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。 (3)propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。 (4)propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。 (5)propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 (6)propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。 (7)propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作。 3、事务的隔离级别 (1)read uncommited:是最低的事务隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。 (2)read commited:保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据。 (3)repeatable read:这种事务隔离级别可以防止脏读,不可重复读。但是可能会出现幻象读。它除了保证一个事务不能被另外一个事务读取未提交的数据之外还避免了以下情况产生(不可重复读)。 (4)serializable:这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读之外,还避免了幻象读 (5)脏读、不可重复读、幻象读概念说明: a.脏读:指当一个事务正字访问数据,并且对数据进行了修改,而这种数据还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据还没有提交那么另外一个事务读取到的这个数据我们称之为脏数据。依据脏数据所做的操作肯能是不正确的。 b.不可重复读:指在一个事务内,多次读同一数据。在这个事务还没有执行结束,另外一个事务也访问该同一数据,那么在第一个事务中的两次读取数据之间,由于第二个事务的修改第一个事务两次读到的数据可能是不一样的,这样就发生了在一个事物内两次连续读到的数据是不一样的,这种情况被称为是不可重复读。 c.幻象读:一个事务先后读取一个范围的记录,但两次读取的纪录数不同,我们称之为幻象读(两次执行同一条 select 语句会出现不同的结果,第二次读会增加一数据行,并没有说这两次执行是在同一个事务中) 4、事务几种实现方式 (1)编程式事务管理对基于 POJO 的应用来说是唯一选择。我们需要在代码中调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。 (2)基于 TransactionProxyFactoryBean的声明式事务管理 (3)基于 @Transactional 的声明式事务管理 (4)基于Aspectj AOP配置事务

Spring互相依赖IOC能启动吗

其实就是Spring如何解决相互依赖对象的注入问题。

第一种,解决setter对象的依赖,就是说在A类需要设置B类,B类需要设置C类,C类需要设置A类,这时就出现一个死循环,

spring的解决方案是,初始化A类时把A类的初始化Bean放到缓存中,然后set B类,再把B类的初始化Bean放到缓存中,然后set C类,初始化C类需要A类和B类的Bean,这时不需要初始化,只需要从缓存中取出即可.

该种仅对single作用的Bean起作用,因为prototype作用的Bean,Spring不对其做缓存

第二种,解决构造器中对其它类的依赖,创建A类需要构造器中初始化B类,创建B类需要构造器中初始化C类,创建C类需要构造器中又要初始化A类,因而形成一个死循环,Spring的解决方案是,把创建中的Bean放入到一个“当前创建Bean池”中,在初始化类的过程中,如果发现Bean类已存在,就抛出一个“BeanCurrentInCreationException”的异常

MyBatis

特点:

mybatis是一种持久层框架,也属于ORM映射。前身是ibatis。相比于hibernatehibernate为全自动化,配置文件书写之后不需要书写sql语句,但是欠缺灵活,很多时候需要优化;mybatis为半自动化,需要自己书写sql语句,需要自己定义映射。增加了程序员的一些操作,但是带来了设计上的灵活,并且也是支持hibernate的一些特性,如延迟加载,缓存和映射等;对数据库的兼容性比hibernate差。移植性不好,但是可编写灵活和高性能的sql语句。

简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。

灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。

解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。

提供映射标签,支持对象与数据库的ORM字段关系映射

提供对象关系映射标签,支持对象关系组建维护

提供XML标签,支持编写动态sql。

优缺点:

1.sql语句与代码分离,存放于xml配置文件中:

优点:便于维护管理,不用在java代码中找这些语句;

缺点: JDBC方式可以用用打断点的方式调试,但是Mybatis不能,需要通过log4j日志输出日志信息帮助调试,然后在配置文件中修改。

2.用逻辑标签控制动态SQL的拼接:

优点:用标签代替编写逻辑代码;

缺点:拼接复杂SQL语句时,没有代码灵活,拼写比较复杂。不要使用变通的手段来应对这种复杂的语句。

3.查询的结果集与java对象自动映射:

优点:保证名称相同,配置好映射关系即可自动映射或者,不配置映射关系,通过配置列名=字段名也可完成自动映射。

缺点:对开发人员所写的SQL依赖很强。

4.编写原声SQL:

优点:接近JDBC,比较灵活。

缺点:对SQL语句依赖程度很高;并且属于半自动,数据库移植比较麻烦,比如mysql数据库编程Oracle数据库,部分的sql语句需要调整。

常用的注解

@Autowired:

@Service:

@Controller:

@RequestMapping:

@ResponseBody:

Spring IOC的加载过程

Spring中IOC容器的顶层接口是BeanFactory,ApplicationContext继承了BeanFactory,他们都是创建Bean工厂的接口,其下有三个我们常用的实现,分别是

classpathXmlApplicationContext : 它是从类的根路径下加载配置文件,推荐使用这种FileSystemXmlApplicationContext: 它是从磁盘上加载配置文件,配置文件可以在磁盘的任意位置AnnotationConfigApplicationContext : 当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。

我们创建IOC容器就是基于以上几个接口和类。

在一般的Spring应用中,我们一般使用 ApplicationContext context = new ClassPathXmlApplicationContext(xml路径); 这种方式来创建context。而在web应用中,tomcat服务器会在读取web.xml时,启动ContextLoaderListener,其中的初始化函数就会创建context,创建完成后,在configureAndRefreshWebApplicationContext 方法中调用最终初始化Bean的refresh方法。因此在web服务器启动后,我们的context就创建好了。

而对bean的加载,就是通过刚才提到的refresh方法完成的。

首先是一个synchronized加锁,当然要加锁,不然你先调一次refresh()然后这次还没处理完又调一次,就会乱套了;接着往下看prepareRefresh();这个方法是做准备工作的,记录容器的启动时间、标记“已启动”状态、处理配置文件中的占位符,可以点进去看看,这里就不多说了。下一步ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();这个就很重要了,这一步是把配置文件解析成一个个Bean,并且注册到BeanFactory中,注意这里只是注册进去,并没有初始化。先继续往下看,等会展开这个方法详细解读然后是prepareBeanFactory(beanFactory);这个方法的作用是:设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean,这里都是spring里面的特殊处理,然后继续往下看postProcessBeanFactory(beanFactory);方法是提供给子类的扩展点,到这里的时候,所有的 Bean 都加载、注册完成了,但是都还没有初始化,具体的子类可以在这步的时候添加一些特殊的 BeanFactoryPostProcessor 的实现类,来完成一些其他的操作。接下来是invokeBeanFactoryPostProcessors(beanFactory);这个方法是调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 方法;然后是registerBeanPostProcessors(beanFactory);这个方法注册 BeanPostProcessor 的实现类,和上面的BeanFactoryPostProcessor 是有区别的,这个方法调用的其实是PostProcessorRegistrationDelegate类的registerBeanPostProcessors方法;这个类里面有个内部类BeanPostProcessorChecker,BeanPostProcessorChecker里面有两个方法postProcessBeforeInitialization和postProcessAfterInitialization,这两个方法分别在 Bean 初始化之前和初始化之后得到执行。然后回到refresh()方法中继续往下看initMessageSource();方法是初始化当前 ApplicationContext 的 MessageSource,国际化处理,继续往下initApplicationEventMulticaster();方法初始化当前 ApplicationContext 的事件广播器继续往下onRefresh();方法初始化一些特殊的 Bean(在初始化 singleton beans 之前);继续往下registerListeners();方法注册事件监听器,监听器需要实现 ApplicationListener 接口;继续往下重点到了:finishBeanFactoryInitialization(beanFactory);初始化所有的 singleton beans(单例bean),懒加载(non-lazy-init)的除外,这个方法也是等会细说finishRefresh();方法是最后一步,广播事件,ApplicationContext 初始化完成

https://www.cnblogs.com/bj-xiaodao/p/10777396.html

@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); //1. 创建真正的bean容器 ConfiurabaleBeanFactroy //2.加载beandefiniton(描述要初始化的Bean的信息) //3.将beandefiniton注册到BeanDefitionRegistry ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); //执行实现了BeanFactoryPostProcessor接口的Bean //比如PropertyPlaceHolderConfigurer(context:property-placeholer)就是此处被调用的,替换掉BeanDefition中的占位符(${})中的内容 // Invoke factory processors registered as beans in the context. //针对beandifition实例进行操作 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. //主要针对bean实例进行操作的的, //比如容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器(实现@Autowired注解功能) 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. //初始化非懒加载方式的单例bean实例 自定的的java类 compent 之类,这里的单例可以用过 scope作用域来进行自定义 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(); } } }
最新回复(0)