Q:Spring依赖注入方式都有哪几种?
A:Spring依赖注入方式有3种,分别是属性注入(set注入)、构造方法注入。工厂方法注入。可以通过注解或者XML配置文件的形式进行注入。
1、属性注入
属性注入即通过 setXxx() 方法注入 Bean 的属性值或者依赖对象,由于属性注入方式具有可选择性和灵活性高的优点,因此属性注入是实际项目中最常采用的注入方式 。
属性注入要求 Bean 提供一个默认的构造函数,并为需要注入的属性提供对应的 Setter 方法 。Spring 先调用 Bean 的默认构造函数实例化 Bean 对象,然后通过反射来调用 Setter 方法注入属性值。
2、构造方法注入
也可以直接指定Bean的Factory Method,然后通过静态方法调用。
详情可以参考简书文章:https://www.jianshu.com/p/d41c596316c1
Q:Spring自动装配的方式都有哪几种?
A:
1、no : 默认的方式是不进行自动装配,通过手工设置ref 属性来进行装配bean
<bean id="person" class="com.myapp.core.autowire.Person"> <property name="book" ref="book" /> </bean> <bean id="book" class="com.myapp.core.autowire.Book"></bean
2、byName:通过在Bean中设置autowire=“byName”,Spring自动寻找与property中的name相同的Bean进行装配。
<bean id="person" class="com.myapp.core.autowire.Person" autowire="byName"> </bean> <bean id="book" class="com.myapp.core.autowire.Book"></bean>
3、byType:通过在Bean中设置autowire="byType",Spring自动寻找与property中的数据类型一致的Bean进行装配。
<bean id="person" class="com.myapp.core.autowire.Person" autowire="byType"/> <bean id="book" class="com.myapp.core.autowire.Book"></bean>
4、constructor:通过在Bean中设置autowrite="constructor",Spring自动寻找与构造函数的数据类型一致的Bean进行装配。
<bean id="person" class="com.myapp.core.autowire.Person" autowire="constructor"/> <bean id="book" class="com.myapp.core.autowire.Book"></bean>
5、auto-detect:先尝试使用constructor装配,使用constructor装配失败则使用byType进行自动装配。
<bean id="person" class="com.myapp.core.autowire.Person" autowire="autodetect" /> <bean id="book" class="com.myapp.core.autowire.Book"></bean>
详情可以参考知乎文章: https://www.zhihu.com/question/39361250/answer/80937680
Q:什么是循环依赖,Spring怎么解决循环依赖问题
A:
并非所有循环依赖Spring都能够解决。Spring不能解决构造器的循环依赖、以及Prototype类型属性的循环依赖。Spring能够解决Singleton类型属性的循环依赖,而Spring的Bean,默认就是Singleton(单例)类型。
Spring解决单例类型属性的循环依赖,是通过三级缓存以及提前暴露早期对象引用的技术。
Spring的三级缓存通过Map实现,如下:
源码 | 级别 | 描述 |
---|---|---|
singletonObjects | 一级缓存 | 用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用 |
earlySingletonObjects | 二级缓存 | 存放原始的 bean 对象(尚未填充属性),用于解决循环依赖 |
singletonFactories | 三级缓存 | 存放 bean 工厂对象,用于解决循环依赖 |
现在假设A、B两个类的属性互相依赖,如下:
class A{
private B b;
}
class B{
private A a;
}
Spring创建对象时会调用doCreateBean()方法,在该方法中,Spring会先进行实例化(为对象分配内存空间),再通过populateBean()方法,进行属性赋值。
当创建A类的a对象时,Spring会先对a对象进行实例化,此时a对象在堆中已经实例化完成,只是相关的属性还没有赋值而已。(可以理解为一个半成品对象)然后Spring发现a对象依赖了b属性,它会将a对象先放入三级缓存中,再递归的调用doCreateBean(),尝试创建b对象。在创建b对象的过程中,会去缓存中一级一级的查找,在三级缓存中,b找到了a对象的引用,此时b对象会顺利的完成实例化和初始化过程,b对象的实例会被放入一级缓存中。然后重新返回到a对象的属性赋值过程,此时因为b对象已经完全创建好了,a对象也会顺利的完成初始化,a对象的早期暴露引用会从三级缓存中删除,a对象的实例会被放入一级缓存中。这样就解决了循环依赖的问题。
详情可以参考: https://www.jianshu.com/p/8bb67ca11831
https://www.jianshu.com/p/a77e64250a9e
Q:简述Spring Bean的生命周期
A:
主要逻辑都在doCreateBean()方法中,从大的阶段来记忆,分为4个阶段,③和④是用户可以自定义扩展的阶段。这4个阶段是依次执行的:
①实例化( createBeanInstance() )
②属性注入( populateBean() )
③初始化( initializeBean() )
④销毁( disposableBean() )
Spring为我们提供了很多常用的扩展点,以下根据扩展点的类型对扩展点进行分类:
①影响多个Bean的接口
- BeanPostProcessor
- InstantiationAwareBeanPostProcessor
Spring最核心的2个接口,Spring的IOC、AOP等也有之相关。其中InstantiationAwareBeanPostProcessor继承自BeanPostProcessor,作用于实例化前后。BeanPostProcessor作用于初始化前后。分别对应第①和第③阶段生命周期。InstantiationAwareBeanPostProcessor有2个调用点,postProcessBeforeInstantiation在doCreateBean()之前进行, postProcessAfterInstantiation 在populateBean()属性赋值方法内进行,但先于实际的属性赋值。
BeanPostProcessor的调用点包括 postProcessBeforeInitialization 和 postProcessAfterInitialization,这2个方法包围住了invokeInitMethods()。
②只调用一次的接口
Aware接口:都是在初始化前调用,作用是从Spring容器中获取一些容器资源,可以具体分为2组:
1、BeanNameAware,BeanClassLoaderAware,BeanFactoryAware
这一组Aware都是在代码中直接调用的(invokeAwareMethods())。
2、EnvironmentAware, EmbeddedValueResolverAware , ApplicationContextAware
这一组Aware均为 ApplicationContext 相关,是通过BeanPostProcessor提供的postProcessBeforeInitialization()来实现的。
最后是2个生命周期接口:
① InitializingBean ,对应初始化阶段,在invokeInitMethods()方法中调用,可自定义init-method。
② DisposableBean ,对应销毁阶段,在 ConfigurableApplicationContext的close()方法中执行,本质是获取所有实现了DisposableBean的Bean,并调用它们的destroy()方法,可自定义destroy-method。
详情可参考:
https://www.jianshu.com/p/1dec08d290c1
https://www.jianshu.com/p/38032b0b9869
Q:Springboot启动流程
A:
来源:oschina
链接:https://my.oschina.net/u/4469818/blog/4365052