Spring相關(guān)核心知識點
1.1 說一說對Spring中IOC的理解
IOC即“控制反轉(zhuǎn)”,不是什么技術(shù),而是一種設(shè)計思想。IOC意味著將你設(shè)計好的對象交給容器控制,而不是傳統(tǒng)的在你的對象內(nèi)部直接控制
誰控制誰,控制什么:傳統(tǒng)Java程序設(shè)計,我們直接在對象內(nèi)部通過new進行創(chuàng)建對象,是程序主動去創(chuàng)建依賴對象;而IOC是有專門一個容器來創(chuàng)建這些對象,即由IOC容器來控制對象的創(chuàng)建
為何是反轉(zhuǎn),哪些方面反轉(zhuǎn)了:有反轉(zhuǎn)就有正轉(zhuǎn),傳統(tǒng)應用程序是由我們自己在對象中主動控制去直接獲取依賴對象,也就是正轉(zhuǎn);而反轉(zhuǎn)則是由容器來幫忙創(chuàng)建及注入依賴對象;因為由容器幫我們查找及注入依賴對象,對象只是被動的接受依賴對象,所以是反轉(zhuǎn)
簡單來說IOC控制反轉(zhuǎn)指的就是對象控制權(quán)力的轉(zhuǎn)移 , 以前是由程序員自己創(chuàng)建對象自己管理對象 , 使用Spring之后由Spring幫助我們創(chuàng)建對象 , 管理對象, 對象的控制權(quán)就轉(zhuǎn)移到Spring框架了 , 所以叫控制反轉(zhuǎn)
1.2 Spring中有哪些依賴注入的方式
所謂依賴注入就是在 Spring IOC 容器創(chuàng)建對象的過程中,將所依賴的對象通過配置進行注入。我們可以通過依賴注入的方式來降低對象間的耦合度
依賴注入分為Setter方 法注入(Setter Injection)和構(gòu)造器注入(Constructor Injection)和 注解注入三種方式
1.3 說一說對Spring中AOP的理解
AOP就是我們常說的面向切面編程。使用AOP可以將系統(tǒng)中的一些公共模塊抽取出來,減少公共模塊和業(yè)務(wù)代碼的耦合。利用 AOP 可以對業(yè)務(wù)邏輯的各個部分進行隔離,從而使得業(yè)務(wù)邏輯各 部分之間的耦合度降低,提高程序的可重用性,同時提高了開發(fā)的效率 ?
像Spring中的事物控制使用的就是AOP機制實現(xiàn)的 , 同時也可以使用AOP做一些權(quán)限控制 , 日志記錄 , 接口統(tǒng)一緩存等操作
Spring中的AOP底層主要是通過動態(tài)代理機制實現(xiàn)的 , 主要使用的是JDK動態(tài)代理和CGLIB動態(tài)代理
在 Spring 中 AOP 代理使用 JDK 動態(tài)代理和 CGLIB 代理來實現(xiàn),默認如果目標對象是接口,則使用 JDK 動態(tài)代理,否則使用 CGLIB 來生成代理類
JDK 動態(tài)代理是基于接口的代理 ,
Object proxy = Proxy.newProxyInstance(類加載器,目標對象接口, 代理執(zhí)行器InvocationHandler)
1.5 如何實現(xiàn)一個AOP
實現(xiàn)AOP非常簡單 , 主要有兩種方式 :
第一種是通過XML配置的方式實現(xiàn)AOP
<aop:config>
<!-- 前置切入點 (在哪里插入)-->
? <aop:pointcut expression="execution(public void cust.zaw.aop.Log.addLog())" id="poioncut"/>
<!-- advisor: 相當于 鏈接切入點 和 切面的線 -->
? <aop:advisor advice-ref="logBefore" pointcut-ref="poioncut"/>
</aop:config>
第二種是通過注解的方式實現(xiàn)AOP
//日志切面類
//得加上此注解此切面類才會生效
@Aspect
public class MyLog {
//抽取公共的切入點表達式
//該表達式表明MyService類下的所有方法都加上aop功能
@Pointcut("execution(public int org.com.MyService.*(..))")
public void pointCut(){};
//在目標方法之前切入
//復用上面定義的pointCut()方法上的切入點表達式
@Before("pointCut()")
public void logStart(JoinPoint joinPoint){
? ? //獲取目標方法名 (單純?nèi)〕鰜矶严旅鏇]有用到這個變量)
? ? String methodName = joinPoint.getSignature().getName();
? ? //獲取目標方法參數(shù)列表 (下面有輸出這個)
? ? Object[] args = joinPoint.getArgs();
? ? System.out.println("除法運行...參數(shù)列表是: {" + Arrays.asList(args) + "}");
}
//在目標方法之后切入
@After("pointCut()")
public void logEnd(){
? ? System.out.println("除法結(jié)束...");
}
//在目標方法正常返回切入
//result是目標方法正常返回的返回值
@AfterReturning(value = "pointCut()", returning = "result")?
public void logReturn(Object result){
? ? System.out.println("除法正常返回...運行結(jié)果: { " + result + " }");
}
//在目標方法異常時切入
//exception是目標方法異常的異常對象
@AfterThrowing(value = "pointCut()", throwing = "exception")?
public void logException(Exception exception){
? ? System.out.println("除法異常...異常信息: {" + exception+ "}");
}
}
@Pointcut : 定義切入點表達式
@Before : 前置通知
@After : 最終通知
@AfterReturning : 后置通知
Spring框架支持以下五種bean的作用域:
1.singleton : bean在每個Spring ioc 容器中只有一個實例
2.prototype:一個bean的定義可以有多個實例
3.request:每次http請求都會創(chuàng)建一個bean
4.session:在一個HTTP Session中,一個bean定義對應一個實例
5.global-session:在一個全局的HTTP Session中,一個bean定義對應一個實例
1.7 Spring框架中的單例bean是線程安全的嗎?
不是,Spring框架中的單例bean不是線程安全的 , spring 中的 bean 默認是單例模式,spring 框架并沒有對單例 bean 進行多線程的封裝處理。
1.8 講一講Spring中Bean創(chuàng)建的流程
調(diào)用容器中InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation()方法,可以在Bean實例化前修改BeanDefinition
2.實例化:將指定的BeanDefinition轉(zhuǎn)換成BeanWrapper,然后調(diào)用createBeanInstance創(chuàng)建Bean的實例。Bean的實例化有多種策略,如工廠方法、指定參數(shù)構(gòu)造器和默認無參構(gòu)造器等??傊琧reateBeanInstance()方法會返回一個剛實例化好的、屬性未賦值的空Bean
1.屬性填充:調(diào)用populateBean()方法,為Bean進行屬性的賦值和依賴的注入
2.屬性填充后置處理:調(diào)用容器中InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation()方法,進行屬性填充后處理
3.初始化前置處理:調(diào)用BeanPostProcessor的postProcessBeforeInitialization()方法進行初始化前置處理。
4.初始化:調(diào)用Bean的初始化方法,順序為:InitializingBean的afterPropertiesSet() -> 注冊的init-method
5.初始化后置處理:調(diào)用BeanPostProcessor的postProcessAfterInitialization()執(zhí)行初始化后置處理
6.調(diào)用registerDisposableBeanIfNecessary()方法,注冊Bean的銷毀處理邏輯:
1.9 講一講Spring中Bean的生命周期
bean 的生命周期從調(diào)用 beanFactory 的 getBean 開始,到這個 bean 被銷毀

1.10 Spring是如何解決循環(huán)依賴的
循環(huán)依賴是指一個或多個對象之間存在直接或間接的依賴關(guān)系,這種依賴關(guān)系構(gòu)成一個環(huán)形調(diào)用 , 舉個例子 : A 依賴B , B依賴C , C依賴A , 這樣就形成了循環(huán)依賴

Spring解決循環(huán)依賴問題, 靠的是三級緩存機制 , Spring中的三級緩存
第一級緩存:singletonObjects
,用于保存實例化、注入、初始化完成的 bean 實例
第二級緩存:earlySingletonObjects
,用于保存實例化完成的 bean 實例
第三級緩存:singletonFactories
,用于保存 bean 創(chuàng)建工廠,以便后面有機會創(chuàng)建代理對象
三級緩存的執(zhí)行邏輯
????先從“第一級緩存”找對象,有就返回,沒有就找“二級緩存”
????找“二級緩存”,有就返回,沒有就找“三級緩存”
????找“三級緩存”,找到了,就獲取對象,放到“二級緩存”,從“三級緩存”移除
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
? ? //從一級緩存獲取Bean
? ? Object singletonObject = this.singletonObjects.get(beanName);
? ? if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
? ? ? ? //從二級緩存獲取Bean
? ? ? ? singletonObject = this.earlySingletonObjects.get(beanName);
? ? ? ? if (singletonObject == null && allowEarlyReference) {
? ? ? ? ? ? synchronized(this.singletonObjects) {
? ? ? ? ? ? ? ? singletonObject = this.singletonObjects.get(beanName);
? ? ? ? ? ? ? ? if (singletonObject == null) {
? ? ? ? ? ? ? ? ? ? singletonObject = this.earlySingletonObjects.get(beanName);
? ? ? ? ? ? ? ? ? ? if (singletonObject == null) {
? ? ? ? ? ? ? ? ? ? ? ? //從三級緩存獲取Bean工廠
? ? ? ? ? ? ? ? ? ? ? ? ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
? ? ? ? ? ? ? ? ? ? ? ? if (singletonFactory != null) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? //通過Bean工廠獲取Bean對象
? ? ? ? ? ? ? ? ? ? ? ? ? ? singletonObject = singletonFactory.getObject();
? ? ? ? ? ? ? ? ? ? ? ? ? ? //將Bean保存到二級緩存
? ? ? ? ? ? ? ? ? ? ? ? ? ? this.earlySingletonObjects.put(beanName, singletonObject);
? ? ? ? ? ? ? ? ? ? ? ? ? ? //從三級緩存移除
? ? ? ? ? ? ? ? ? ? ? ? ? ? this.singletonFactories.remove(beanName);
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? return singletonObject;
}
???一級緩存:就是個單例池,用來存放已經(jīng)初始化完成的單例 Bean
? ?二級緩存:是為了避免因為 AOP 創(chuàng)建多個對象,其中存儲的是半成品的 AOP 的單例 bean
???三級緩存:是為打破循環(huán),存放的是生成半成品單例 Bean 的工廠方法
1.11 Spring中在什么情況下事物會失效
Spring中事物失效的場景很多 , 例如 :
1.因為Spring事務(wù)是基于代理來實現(xiàn)的,所以某個加了@Transactional的?法只有是被代理對象調(diào)?時, 那么這個注解才會?效 ! 如果使用原始對象事物會失效
2.同時如果某個?法是private的,那么@Transactional也會失效,因為底層cglib是基于??類來實現(xiàn) 的,?類是不能重載?類的private?法的,所以?法很好的利?代理,也會導致@Transactianal失效
3.如果在業(yè)務(wù)中對異常進行了捕獲處理 , 出現(xiàn)異常后Spring框架無法感知到異常, @Transactional也會失效
4.@Transational中默認捕獲的是RuntimeException , 如果沒有指定捕獲的異常類型, 并且程序拋出的是非運行時異常, 事物會失效
1.12 說一說@Transational
的原理
1.Spring事務(wù)底層是基于數(shù)據(jù)庫事務(wù)和AOP機制的
2.?先對于使?了@Transactional注解的Bean,Spring會創(chuàng)建?個代理對象作為Bean
3.當調(diào)?代理對象的?法時,會先判斷該?法上是否加了@Transactional注解
4.如果加了,那么則利?事務(wù)管理器創(chuàng)建?個數(shù)據(jù)庫連接
5.并且修改數(shù)據(jù)庫連接的autocommit屬性為false,禁?此連接的?動提交,這是實現(xiàn)Spring事務(wù)? 常重要的?步
6.然后執(zhí)?當前?法,?法中會執(zhí)?sql
7.執(zhí)?完當前?法后,如果沒有出現(xiàn)異常就直接提交事務(wù)
8.如果出現(xiàn)了異常,并且這個異常是需要回滾的就會回滾事務(wù),否則仍然提交事務(wù)
1.13 @Transational
屬性有哪些
常用的屬性有 :
1.propagation : 事物傳播行為
2.isolation : 事物隔離級別, 默認數(shù)據(jù)庫隔離級別
3.readOnly : 是否是只讀事物
4.rollbackFor : 指定哪些異常需要回滾 , 默認RuntimeException
5.noRollbackFor : ?指定哪些異常不需要回滾
1.14 說一下Spring的事務(wù)傳播行為有哪些
1.PROPAGATION_REQUIRED:如果當前沒有事務(wù),就創(chuàng)建一個新事務(wù),如果當前存在事務(wù),就加入該事務(wù),該設(shè)置是最常用的設(shè)置
2.PROPAGATION_REQUIRES_NEW:創(chuàng)建新事務(wù),無論當前存不存在事務(wù),都創(chuàng)建新事務(wù)
3.PROPAGATION_SUPPORTS:支持當前事務(wù),如果當前存在事務(wù),就加入該事務(wù),如果當前不存在事務(wù),就以非事務(wù)執(zhí)行。
4.PROPAGATION_NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當前存在事務(wù),就把當前事務(wù)掛起
5.PROPAGATION_MANDATORY:支持當前事務(wù),如果當前存在事務(wù),就加入該事務(wù),如果當前不存在事務(wù),就拋出異常
6.PROPAGATION_NEVER:以非事務(wù)方式執(zhí)行,如果當前存在事務(wù),則拋出異常
7.PROPAGATION_NESTED:如果當前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當前沒有事務(wù),則按REQUIRED屬性執(zhí)行
1.15 @Autowired
和@Resource
有什么區(qū)別
@Resource
和@Autowired
都可以標注在字段或?qū)傩缘膕etter方法上 , 代表自動注入 , 他們的區(qū)別主要有 :
1.提供方不同:@Autowired是由Spring提供;@Resource是由javax提供,需要JDK1.6及以上
2.注入方式不同:@Autowired只按照byType 注入;@Resource默認按byName自動注入,也提供按照byType 注入;
3.使用方式不同:@Autowired按類型裝配依賴對象,默認情況下它要求依賴對象必須存在,如果我們想使用按名稱裝配,可以結(jié)合@Qualifier注解一起使用。@Resource有兩個中重要的屬性:name和type。name屬性指定byName,type屬性指定byType
1.16 Spring中使用的設(shè)計模式有哪些
1.單例模式 : Spring中的單例Bean沒有使用單例設(shè)計模式 , 但是在其他地方使用了單例設(shè)計模式 , 例如 :
org.springframework.transaction.TransactionDefinition#withDefaults
org.springframework.aop.TruePointcut#INSTANCE
org.springframework.core.OrderComparator#INSTANCE
2.構(gòu)建者模式 : 主要用于構(gòu)建對象, 例如 org.springframework.beans.factory.support.BeanDefinitionBuilder
org.springframework.http.ResponseEntity.HeadersBuilder
org.springframework.http.ResponseEntity.BodyBuilder
3.工廠模式 : 隱藏對象創(chuàng)建細節(jié) ?, 例如: Spring 中的 ApplicationContext 與 BeanFactory 中的 getBean 都可以視為工廠方法
4.適配器模式 : 將一個類的接口變成客戶端所期望的另一種接口,從而使原本因接口不匹配而導致無法在一起工作的兩個類能夠一起工作 , Spring中典型的實現(xiàn)有幾處:
?org.springframework.web.servlet.HandlerAdapter – 因為控制器實現(xiàn)有各種各樣,它們的處理方法都不一樣,為了統(tǒng)一調(diào)用,必須適配為 HandlerAdapter 接口
org.springframework.beans.factory.support.DisposableBeanAdapter – 因為銷毀方法多種多樣,因此都要適配為 DisposableBean 來統(tǒng)一調(diào)用銷毀方法
org.springframework.web.servlet.handler.HandlerInterceptorAdapter : web攔截器的適配器
5.代理模式 : 通過代理對象, 控制目標對象的訪問
org.springframework.aop.framework.JdkDynamicAopProxy
org.springframework.aop.framework.ObjenesisCglibAopProxy
6.裝飾模式 : 對目標對象功能進行增強 , Spirng中提供的各種Wrapper結(jié)尾的類基本上都是裝飾模式 , 例如 :
org.springframework.http.client.support.HttpRequestWrapper
org.springframework.web.util.ContentCachingRequestWrapper
7.觀察者模式 : Spring中的一些監(jiān)聽器 , 基本都是使用的觀察者模式 , 例如 ;
org.springframework.context.ApplicationListener
org.springframework.context.event.ApplicationEventMulticaster
org.springframework.context.ApplicationEvent
8.模版方法模式 : ?Spring中一定了很多以 Template 命名的類 , 都是屬于模版方法模式
大部分以 Template 命名的類,如 JdbcTemplate,TransactionTemplate