自己总结的一些spring面试题
目錄
請談一談Spring中自動裝配的方式有哪些?
依賴注入有哪幾種方式?以及這些方法如何使用?
請問Spring中Bean的作用域有哪些?
什么是Spring IOC?Spring IOC的原理是什么?如果你要實現(xiàn)IOC要怎么做?
Spring中BeanFactory和ApplicationContext的區(qū)別是什么?
@Autowired和@Resource之間的區(qū)別
談?wù)凷pring Bean的生命周期?
談一下Spring AOP?
Spring中實現(xiàn)AOP的幾種方式?
Spring中循環(huán)依賴如何解決?說一下解決的原理
請談一談Spring中自動裝配的方式有哪些?
自動裝配即spring容器來幫我們進行bean的匹配和依賴注入(裝配包含類型匹配和依賴注入,這是按實際功能進行的劃分,我覺得這樣更能理解兩者關(guān)系),總的來說有兩種方式:
- 按名稱裝配:在容器中查找與依賴屬性名字相同的bean進行注入。
- 按類型裝配:在容器中查找與依賴屬性類型相同的bean進行注入。
在具體的實現(xiàn)上,可以通過Xml配置文件或注解來完成。
1. 如果通過xml配置文件實現(xiàn),需要在<bean/>標簽中設(shè)置autowire屬性,有四個可選項:no、byName、byType、constructor。
- no:不進行自動裝配,必須手動設(shè)置ref屬性指定注入對象。
- byName:按名稱裝配。
- byType:按類型裝配。
- constructor:構(gòu)造器注入,本質(zhì)上還是按類型裝配,容器會根據(jù)構(gòu)造器參數(shù)的類型來匹配,如果與依賴屬性的類型相同且容器中有這個bean,就在對象實例化的時候通過這個構(gòu)造器注入。
2. 如果通過注解來實現(xiàn),可以選擇@Autowired或@Resource注解,與xml中的byName和byType選項是一個道理。
- @Autowired:按類型裝配,可以放在屬性、setter方法或構(gòu)造器上。
- @Resource:按名稱裝配,可以放在屬性和setter方法上。
說了這么多,總結(jié)起來就是:自動裝配可以分為按名稱裝配和按類型裝配。具體實現(xiàn)可以通過配置xml文件或者使用注解來實現(xiàn)。
依賴注入有哪幾種方式?以及這些方法如何使用?
Xml配置文件:
Java Bean:
setter注入發(fā)生在bean實例化之后,constructor注入發(fā)生在bean實例化之前。上面Info是通過setter方法注入的,HelloSpring是通過constructor方法注入的。
請問Spring中Bean的作用域有哪些?
在spring5.x中,作用域有:
- singleton:bean在容器中是單例存在的。
- prototype:每次從spring容器中獲取bean時都會創(chuàng)建一個新的實例。
- request:每次http請求都會創(chuàng)建一個新的實例。僅在web環(huán)境下有效。
- session:在每個http session的生命周期里,會創(chuàng)建一個新的實例。
- application:在整個web生命周期里僅創(chuàng)建一個新的實例。
- websocket:在websocket生命周期里僅創(chuàng)建一個新的實例。
注意:request、session、application和websocket作用域只有在web環(huán)境中才有效(使用web ApplicationContext,如XmlWebApplicationContext)。如果在非web環(huán)境下(如使用ClassPathXmlApplicationContext)使用這些作用域,會拋出IllegalStateException。
什么是Spring IOC?Spring IOC的原理是什么?如果你要實現(xiàn)IOC要怎么做?
1. 什么是Spring IOC?
IOC是Inversion of Control的縮寫,意思是控制反轉(zhuǎn)。傳統(tǒng)上,對象是由程序員編寫程序代碼直接操控的,控制反轉(zhuǎn)就是反過來把這些對象的操控權(quán)交給容器,通過容器來實現(xiàn)對象組件的裝配和管理,由容器來創(chuàng)建對象并管理對象之間的依賴關(guān)系。Spring IOC就是由spring來負責(zé)控制對象的生命周期和對象間的關(guān)系。
2. Spring IOC的原理是什么?
IOC主要是獲得依賴對象的過程被反轉(zhuǎn)了,就是獲得依賴對象的過程由自身管理變?yōu)榱擞蒊OC容器主動注入,所以Spring IOC中最主要的就是依賴注入,Spring IOC的原理可以引申為DI的原理。
比如對象A需要操作數(shù)據(jù)庫,以前我們總是要在A中自己編寫代碼來獲得一個Connection對象,有了?spring我們就只需要告訴spring,A中需要一個Connection,至于這個Connection怎么構(gòu)造,何時構(gòu)造,A不需要知道。在系統(tǒng)運行時,spring會在適當?shù)臅r候制造一個Connection,然后像打針一樣,注射到A當中,這樣就完成了對各個對象之間關(guān)系的控制。A需要依賴?Connection才能正常運行,而這個Connection是由spring注入到A中的,依賴注入的名字就這么來的。那么DI是如何實現(xiàn)的呢??Java 1.3之后一個重要特征是反射(reflection),它允許程序在運行的時候動態(tài)的生成對象、執(zhí)行對象的方法、改變對象的屬性,spring就是通過反射來實現(xiàn)注入的。
1. 通過xml配置文件進行屬性注入:就是通過反射拿到待注入屬性的Field,調(diào)用Field.set()來實現(xiàn)注入。
? ? 2. 通過注解來實現(xiàn)注入:判斷注解是放到屬性上還是方法上,然后通過反射進行注入。
舉個簡單的例子,我們找女朋友常見的情況是,我們到處去看哪里有長得漂亮身材又好的女孩子,然后打聽她們的興趣愛好、qq號、電話號、ip號、iq號………,想辦法認識她們,投其所好送其所要,這個過程是復(fù)雜深奧的,我們必須自己設(shè)計和面對每個環(huán)節(jié)。傳統(tǒng)的程序開發(fā)也是如此,在一個對象中,如果要使用另外的對象,就必須得到它(自己new一個,或者從JNDI中查詢一個),使用完之后還要將對象銷毀(比如Connection等),對象始終會和其他的接口或類藕合起來。(比如類A要使用類B,類B要使用類C,如果你在對象A創(chuàng)建之后就能使用完整功能,必須在實例化對象A之前將創(chuàng)建好的對象B注入到A中,同理也必須在實例化對象B之前將創(chuàng)建好的對象C注入到B中......這里只是一個類依賴另一個類的情況,如果A不僅僅依賴于B,還依賴于D、E、F呢?B不僅僅依賴于C,還依賴于G、H、I呢?那豈不是非常復(fù)雜了?所以容器幫我們解決了這個問題)
Spring中BeanFactory和ApplicationContext的區(qū)別是什么?
BeanFactory和ApplicationContext是Spring的兩大核心接口,都可以當做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
BeanFactory:是Spring里面最底層的接口,包含了各種Bean的定義,讀取bean配置文檔,管理bean的加載、實例化,控制bean的生命周期,維護bean之間的依賴關(guān)系。
ApplicationContext接口作為BeanFactory的派生,除了提供BeanFactory所具有的功能外,還提供了更完整的框架功能:
-
繼承MessageSource,因此支持國際化。
-
能自動注冊BeanPostProcessor和BeanFactoryPostProcessor。
-
統(tǒng)一的資源文件訪問方式。
-
提供在監(jiān)聽器中注冊bean的事件。
-
同時加載多個配置文件。
-
提供了更加完整的生命周期管理。
下面是Spring 5.2.7官方文檔的說明:
@Autowired和@Resource之間的區(qū)別
@Autowired可用于:構(gòu)造函數(shù)、成員變量、Setter方法;@Resource可以用于類、成員變量、setter方法。
@Autowired和@Resource之間的區(qū)別
-
@Autowired默認是按照類型裝配注入的,默認情況下它要求依賴對象必須存在(可以設(shè)置它required屬性為false)。
-
@Resource默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean才會按照類型來裝配注入。
談?wù)凷pring Bean的生命周期?
Spring Bean的生命周期可以分為五個階段:
加載階段,即使當Spring容器被創(chuàng)建的時候,會根據(jù)xml配置文件或Spring配置類來獲取配置的bean信息,并將這些bean解析成BeanDefinition,存入到一個map中,key是beanName,value就是BeanDefinition。
實例化階段,就是通過構(gòu)造器或者工廠方法(xml中factory-bean指定工廠類,factory-method指定前面工廠類中的工廠方法,通過工廠方法來創(chuàng)建該bean對象)來實例化所有單例且非懶加載的bean(非單例的bean會在使用時實例化如getBean())。在實例化操作的前后會遍歷所有的BeanDefinition,檢查其是否實現(xiàn)了InstantiationAwareBeanPostProcessor接口,是則執(zhí)行這個接口的前置(postProcessBeforeInitialization)和后置(postProcessAfterInitialization)方法。
屬性賦值階段,會根據(jù)名稱或者類型使用反射進行依賴注入。
初始化階段,主要是執(zhí)行自定義的初始化方法(如在xml配置文件中設(shè)置的init-method屬性),如果bean實現(xiàn)了InitializingBean接口,還會調(diào)用bean的afterPropertiesSet()方法,實現(xiàn)InitializingBean接口的目的是為了對“bean的屬性設(shè)置完成”這個事件做出反應(yīng)。在初始化階段前后,會遍歷所有的BeanPostProcessor,并執(zhí)行前置(postProcessBeforeInitialization)和后置(postProcessAfterInitialization)方法。同時在初始化之前也會執(zhí)行所有的aware對象的相關(guān)方法,有一些aware(如BeanNameAware)是直接執(zhí)行,有一些(如ApplicationContextAware)是通過ApplicationContextAwareProcessor接口的before方法執(zhí)行,這個接口也是BeanPostProcessor的子接口,它會檢查當前bean是否是Aware接口的實現(xiàn)類,是的話就執(zhí)行Aware接口的特有方法。
請別再問Spring Bean的生命周期了! - 簡書 (jianshu.com)
Spring源碼系列 — Bean生命周期 - 懷瑾握瑜XI - 博客園 (cnblogs.com)
Spring AOP也是在初始化完成后,通過BeanPostProcessor的后置方法運行的。方法內(nèi)容為,通過切點(如execution(* *.find*(..))
)對bean中的方法進行匹配,如果匹配成功就為這個bean生成代理對象并放入容器中來,之后從容器中獲取的都是代理對象。
Spring AOP 源碼分析 - 篩選合適的通知器 | 田小波的技術(shù)博客 (tianxiaobo.com)
class ApplicationContextAwareProcessor implements BeanPostProcessor { ......@Overridepublic Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {AccessControlContext acc = null;if (System.getSecurityManager() != null &&(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {acc = this.applicationContext.getBeanFactory().getAccessControlContext();}if (acc != null) {AccessController.doPrivileged(new PrivilegedAction<Object>() {@Overridepublic Object run() {invokeAwareInterfaces(bean);return null;}}, acc);}else {invokeAwareInterfaces(bean);}return bean;}private void invokeAwareInterfaces(Object bean) {if (bean instanceof Aware) {if (bean instanceof EnvironmentAware) {((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());}if (bean instanceof EmbeddedValueResolverAware) {((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);}if (bean instanceof ResourceLoaderAware) {((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);}if (bean instanceof ApplicationEventPublisherAware) {((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);}if (bean instanceof MessageSourceAware) {((MessageSourceAware) bean).setMessageSource(this.applicationContext);}if (bean instanceof ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);}}}......}銷毀階段,調(diào)用DisposableBean接口的destroy方法,若容器關(guān)閉,則調(diào)用所有bean的destroy方法。如果在xml中自定義了銷毀方法(通過destroy-method屬性),則調(diào)用自定義的方法。
談一下Spring AOP?
AOP(Aspect-Oriented Programming),一般稱為面向切面編程,作為面向?qū)ο蟮囊环N補充,用于將那些與業(yè)務(wù)無關(guān),但卻對多個對象產(chǎn)生影響的公共行為和邏輯,抽取并封裝為一個可重用的模塊,這個模塊被命名為“切面”(Aspect),減少系統(tǒng)中的重復(fù)代碼,降低了模塊間的耦合度,同時提高了系統(tǒng)的可維護性。可用于權(quán)限認證、日志、事務(wù)處理等。AOP相關(guān)概念可以參考:Spring AOP 源碼分析系列文章導(dǎo)讀。
如何接入
實現(xiàn)元素
TODO(連接點,切點,切面,通知)
生成代理類
Spring啟動的時候根據(jù)Spring AOP的相關(guān)配置(注解或xml配置)生成通知器類(Advisor,可以獲取通知),然后通過代理BeanPostProcessor,在bean初始化結(jié)束后為每個bean查找合適的通知器,找到了就為bean生成代理對象并放入容器中,之后從容器中獲取的就是代理對象。
public interface Advisor {Advice getAdvice();... }AOP中生成代理類總共有兩種方式:JDKProxy和CGLIB。若目標bean實現(xiàn)了接口,就使用JDKProxy,否則使用CGLIB。也可以通過配置制定開啟CGLIB代理。如設(shè)置下面屬性為true。
<aop:aspectj-autoproxy proxy-target-class="true"/>執(zhí)行代理方法
AOP生成的代理類,業(yè)務(wù)增強的邏輯是放到攔截器中的(把before、after等通知封裝成攔截器),在執(zhí)行代理類的方法時先獲取這個方法匹配的通知器,然后將通知器中的通知轉(zhuǎn)化成相應(yīng)的攔截器,最終獲得一個ArrayList類型的攔截器列表。(先會去緩存中獲取方法的攔截器列表,拿不到再自己組裝)
之后按順序調(diào)用攔截器的invoke方法。調(diào)用的邏輯是,對于前置通知攔截器,invoke方法是先執(zhí)行通知邏輯,然后調(diào)用下一個攔截器的invoke方法;對于后置通知攔截器,invoke方法先調(diào)用下一個攔截器的invoke方法,然后再執(zhí)行通知邏輯,最后一個攔截器執(zhí)行目標方法。這就使得目標方法是在前置通知和后置通知之間執(zhí)行(看下面代碼和圖片)。
// 前置通知攔截器 public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {......@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );return mi.proceed();}...... } // ReflectiveMethodInvocation.proceed()@Overridepublic Object proceed() throws Throwable {// 如果是最后一個攔截器,執(zhí)行目標方法if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {return invokeJoinpoint();}// 獲取下一個攔截器,索引++Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);......// 執(zhí)行下一個攔截器的invoke()interceptorOrInterceptionAdvice.invoke(this)......}Spring中實現(xiàn)AOP的幾種方式?
Spring AOP的實現(xiàn)發(fā)生在bean初始化之后,通過BeanPostProcessor接口類來生成代理類。因此在ApplicationContext構(gòu)造完成之后,代理類已經(jīng)被生成,后面從IOC容器獲取的都是代理類。
Spring AOP中的動態(tài)代理主要有兩種方式,JDK動態(tài)代理和CGLIB動態(tài)代理。當類實現(xiàn)了接口,就是用JDKProxy;否則使用cglib。
-
JDK動態(tài)代理只提供接口的代理,不支持類的代理。核心InvocationHandler接口和Proxy類,InvocationHandler 通過invoke()方法反射來調(diào)用目標類中的代碼,動態(tài)地將橫切邏輯和業(yè)務(wù)編織在一起;接著,Proxy利用 InvocationHandler動態(tài)創(chuàng)建一個符合某一接口的的實例, 生成目標類的代理對象。
-
如果代理類沒有實現(xiàn) InvocationHandler 接口,那么Spring AOP會選擇使用CGLIB來動態(tài)代理目標類。CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運行時動態(tài)的生成指定類的一個子類對象,并覆蓋其中特定方法并添加增強代碼,從而實現(xiàn)AOP。CGLIB是通過繼承的方式做的動態(tài)代理,因此如果某個類被標記為final,那么它是無法使用CGLIB做動態(tài)代理的。
具體可以參見:【Java基礎(chǔ)】代理模式、靜態(tài)代理、動態(tài)代理、JDK與CGLIB代理區(qū)別、在sp
ring AOP中的應(yīng)用_奮進的小白粥-CSDN博客。
Spring中循環(huán)依賴如何解決?說一下解決的原理
將依賴注入的方式改成setter注入即可。
Spring中出現(xiàn)循環(huán)依賴問題的場景最常見于使用構(gòu)造器進行依賴注入的情況,因為使用構(gòu)造器進行依賴注入時,要求被依賴屬性的實例化發(fā)生在當前類被實例化之前。假設(shè)A和B相互依賴且都是用構(gòu)造器進行注入,如果要實例化A,必須先創(chuàng)建B,保證容器中有B這個對象,A才能實例化成功;而實例化B的時候,又必須保證A先被創(chuàng)建,所以就會陷入一個死循環(huán),A和B都不能被實例化。而采用setter注入時,依賴注入發(fā)生在bean實例化之后,在A和B被創(chuàng)建出來之后再去進行依賴注入,這樣就能注入成功。
推薦參考文章:Spring-bean的循環(huán)依賴以及解決方式_惜暮-CSDN博客_spring循環(huán)依賴
Spring事務(wù)傳播機制?
帶你讀懂Spring 事務(wù)——事務(wù)的傳播機制 - 知乎
總結(jié)
以上是生活随笔為你收集整理的自己总结的一些spring面试题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《基于数字信号处理的相干光通信技术》读书
- 下一篇: beam mysql_Beam Grap