Spring是我们工作中必用的开发框架,而Spring中存在很多概念,本文将给大家介绍其中最重要的几个核心概念和相关面试题,希望大家认真看完,看完必有收获。
什么是BeanDefinition?
BeanDefinition表示Bean定义, Spring根据BeanDefinition来创建Bean对象, BeanDefinition有很多的属性用来描述Bean, BeanDefinition是Spring中非常核心的概念。
BeanDefinition中几个核心属性:
-
beanClass:表示一个bean的类型,比如:UserService.class、OrderService.class, Spring在创建Bean的过程中会根据此属性来实例化得到对象。
-
scope:表示一个bean的作用域,比如: scope等于singleton,该bean就是一个单例Bean;scope等于prototype,该bean就是一个原型bean。
-
isLazy:表示一个bean是不是需要懒加载,如果一个bean是原型bean,那么isLazy属性不起作用,如果一个bean是单例bean,并且如果isLazy为true,那么该bean就是一个懒加载的单例bean,则会在第一次getBean的时候生成该bean,否则,如果是一个非懒加载的单例bean,则会在Spring启动过程中直接生成好。
-
dependsOn:表示一个bean在创建之前所依赖的其他bean,在一个bean创建之前,它所依赖的这些bean得先全部创建好。
-
primary:表示一个bean是主bean,在Spring中一个类型可以有多个bean对象,在进行依赖注入时,如果根据类型找到了多个bean,此时会判断这些bean中是否存在一个主bean,如果存在,则直接将这个bean注入给属性。
-
initMethodName:表示一个bean的初始化方法,一个bean的生命周期过程中有一个步骤叫初始化,Spring会在这个步骤中去调用bean的初始化方法,初始化逻辑有程序员自己控制,表示程序员可以自定义逻辑对bean进行加工。
@Component注解、@Bean注解、<bean/>标签所定义的Bean都会被解析生成BeanDefinition对象。
什么是BeanFactory?
BeanFactory是一种“Spring容器”, BeanFactory翻译过来就是Bean工厂, 顾名思义,它可以用来创建Bean、获取Bean, BeanFactory是Spring中非常核心的组件。
BeanFactory将利用BeanDefinition来生成Bean对象, BeanDefinition相当于BeanFactory的原材料, Bean对象就相当于BeanFactory所生产出来的产品。
BeanFactory核心的子接口和实现类:
-
ListableBeanFactory
-
ConfigurableBeanFactory
-
AutowireCapableBeanFactory
-
AbstractBeanFactory
-
DefaultListableBeanFactory
DefaultListableBeanFactory是最重要的,它的功能包括:支持单例Bean、支持Bean别名、支持父子BeanFactory、 支持Bean类型转化、支持Bean后置处理、 支持FactoryBean、支持自动装配,等等。
什么是Bean的生命周期?
Bean生命周期描述的是Spring中一个Bean创建过程和销毁过程中所经历的步骤,其中比较复杂的就是Bean创建过程。Spring基于Bean生命周期提供了很多扩展机制,可以让程序员利用生命周期机制对Bean进行自定义加工。
Bean生命周期中主要的几个步骤:
-
生成BeanDefinition:BeanDefinition表示Bean定义,它定义了某个Bean的类型,Spring就是利用BeanDefinition来创建Bean的,比如需要利用BeanDefinition中beanClass属性确定Bean的类型,从而实例化出来对象。
-
构造方法推断:一个Bean中可以有多个构造方法,此时就需要Spring来判断到底使用哪个构造方法,这个过程是比较复杂的,篇幅有限,不展开介绍。通过构造方法推断之后确定一个构造方法后,就可以利用构造方法实例化得到一个对象了。
-
实例化:通过构造方法反射得到一个实例化对象,在Spring中,可以通过BeanPostProcessor机制对实例化进行干预。
-
属性填充:实例化所得到的对象,是“不完整”的对象,“不完整”的意思是该对象中的某些属性还没有进行属性填充,也就是Spring还没有自动给某些属性赋值,属性填充就是我们通常说的自动注入、依赖注入。
-
初始化:在一个对象的属性填充之后,Spring提供了初始化机制,程序员可以利用初始化机制对Bean进行自定义加工,比如可以利用InitializingBean接口、@PostConstruct注解通过某个方法来对Bean中的其他属性进行赋值,或者对Bean中的属性进行校验。
-
初始化后:初始化后是Bean创建生命周期中最后一个步骤,我们常说的AOP机制,就是在这个步骤中通过BeanPostProcessor机制实现的,初始化之后得到的对象才是真正的Bean对象。
@Autowired注解是如何工作的?
@Autowired是用来标识Bean中的某个属性是不是需要Spring来进行依赖注入的。@Autowired可以写在属性上、普通方法上、构造方法上。不同位置的@Autowired工作原理是类似的。@Autowired中的required属性表示如果没有对象可以注入给属性,是否抛异常,默认为ture(抛异常)。
-
@Autowired加在某个属性上,Spring在进行Bean的生命周期过程中,在属性填充这一步,会基于实例化出来的对象,对该对象中加了@Autowired的属性自动给属性赋值。Spring会先根据属性的类型去Spring容器中找出该类型所有的Bean对象,如果找出来多个,则再根据属性的名字从多个中再确定一个。如果required属性为true,并且根据属性信息找不到对象,则直接抛异常。
-
当@Autowired注解写在某个方法上时(该方法不是一定要setter方法),Spring在Bean生命周期的属性填充阶段,会自动去调用当前bean对象中加了@Autowired的方法,在调方法之前会根据方法参数(参数类型、参数名)从Spring容器中找到对象当做方法的入参。
-
@Autowired加在构造方法上时,Spring会在推断构造方法阶段,选择使用该构造方法来进行实例化,只不过在利用构造方法反射实例化之前,得先根据构造方法参数(参数类型、参数名)从Spring容器中找到Bean对象,来作为构造方法的入参,从而调用构造方法实例化得到对象。
@Resource注解是如何工作的?
@Resource注解与@Autowired类似,也是用来对属性进行依赖注入的,@Resource是Java规范层面所设计的注解,Spring负责实现该注解所对应的功能,@Autowired注解是Spring自身所提供的用来进行依赖注入的注解,它们依赖注入的逻辑也是有不同的。
@Resource注解中有一个name属性,针对name属性是否有值,@Resource的依赖注入底层流程是不同的:
-
@Reousrce如果name属性有值,那么Spring会直接根据所指定的name值去Spring容器找Bean对象,如果找到了则成功,如果没有找到,则报错。
-
如果@Resource中的name属性没有值,则:1、先根据属性名字判断该属性名字在Spring容器中是否存在对应的Bean对象。2、如果判断出来该属性名字存在对应的Bean对象,则成功找到Bean对象进行注入。3、如果判断出来该属性名字不存在对应的Bena对象,则再根据属性类型去Spring容器找Bean对象,找到一个则成功进行注入。
@Value注解是如何工作的?
@Value注解和@Resource、@Autowired类似,也是用来对属性进行依赖注入的,只不过@Value是用来从Properties文件中来获取值的,并且@Value可以解析SpEL(Spring表达式)。
用法一:@Value("zhouyu")
直接将字符串“zhouyu”赋值给属性,如果属性类型不是String,或无法进行类型转化,则报错。
用法二:@Value("${zhouyu}")
将${}中所指定的字符串当做key,从Properties文件中找出对应的value,然后赋值给属性,如果没找到则会把“${zhouyu}”当做普通字符串注入给属性,如果找到了则将找到的value注入给属性。
用法三:@Value("#{zhouyu}")
将#{}中所指定字符串当做Spring表达式,Spring会按照表达式语法解析表达式,比如当前Demo,Spring会把"zhouyu"当做一个beanName,根据此beanName从Spring容器中bean,如果找到则进行属性注入,没找到则报错。
本文就到这里,后续继续给大家整理出一些框架或中间件中的核心概念理解。最后我这里整理了一些大厂的面经资料,可以扫下方名片找小助手领取一下,希望能对你们有用。