146抱完、什么是IoC和DI?DI是如何實(shí)現(xiàn)的刃泡?
答:IoC叫控制反轉(zhuǎn)巧娱,是Inversion of Control的縮寫,DI(Dependency Injection)叫依賴注入烘贴,是對(duì)IoC更簡(jiǎn)單的詮釋禁添。控制反轉(zhuǎn)是把傳統(tǒng)上由程序代碼直接操控的對(duì)象的調(diào)用權(quán)交給容器桨踪,通過容器來實(shí)現(xiàn)對(duì)象組件的裝配和管理老翘。所謂的”控制反轉(zhuǎn)”就是對(duì)組件對(duì)象控制權(quán)的轉(zhuǎn)移,從程序代碼本身轉(zhuǎn)移到了外部容器,由容器來創(chuàng)建對(duì)象并管理對(duì)象之間的依賴關(guān)系铺峭。IoC體現(xiàn)了好萊塢原則 – “Don’tcall me, we will call you”墓怀。依賴注入的基本原則是應(yīng)用組件不應(yīng)該負(fù)責(zé)查找資源或者其他依賴的協(xié)作對(duì)象。配置對(duì)象的工作應(yīng)該由容器負(fù)責(zé)卫键,查找資源的邏輯應(yīng)該從應(yīng)用組件的代碼中抽取出來傀履,交給容器來完成。DI是對(duì)IoC更準(zhǔn)確的描述莉炉,即組件之間的依賴關(guān)系由容器在運(yùn)行期決定钓账,形象的來說,即由容器動(dòng)態(tài)的將某種依賴關(guān)系注入到組件之中絮宁。
舉個(gè)例子:一個(gè)類A需要用到接口B中的方法梆暮,那么就需要為類A和接口B建立關(guān)聯(lián)或依賴關(guān)系,最原始的方法是在類A中創(chuàng)建一個(gè)接口B的實(shí)現(xiàn)類C的實(shí)例绍昂,但這種方法需要開發(fā)人員自行維護(hù)二者的依賴關(guān)系啦粹,也就是說當(dāng)依賴關(guān)系發(fā)生變動(dòng)的時(shí)候需要修改代碼并重新構(gòu)建整個(gè)系統(tǒng)。如果通過一個(gè)容器來管理這些對(duì)象以及對(duì)象的依賴關(guān)系治专,則只需要在類A中定義好用于關(guān)聯(lián)接口B的方法(構(gòu)造器或setter方法)卖陵,將類A和接口B的實(shí)現(xiàn)類C放入容器中,通過對(duì)容器的配置來實(shí)現(xiàn)二者的關(guān)聯(lián)张峰。
依賴注入可以通過setter方法注入(設(shè)值注入)泪蔫、構(gòu)造器注入和接口注入三種方式來實(shí)現(xiàn),Spring支持setter注入和構(gòu)造器注入喘批,通常使用構(gòu)造器注入來注入必須的依賴關(guān)系撩荣,對(duì)于可選的依賴關(guān)系,則setter注入是更好的選擇饶深,setter注入需要類提供無參構(gòu)造器或者無參的靜態(tài)工廠方法來創(chuàng)建對(duì)象餐曹。
147、Spring中Bean的作用域有哪些敌厘?
答:在Spring的早期版本中台猴,僅有兩個(gè)作用域:singleton和prototype,前者表示Bean以單例的方式存在俱两;后者表示每次從容器中調(diào)用Bean時(shí)饱狂,都會(huì)返回一個(gè)新的實(shí)例,prototype通常翻譯為原型宪彩。
補(bǔ)充:設(shè)計(jì)模式中的創(chuàng)建型模式中也有一個(gè)原型模式休讳,原型模式也是一個(gè)常用的模式,例如做一個(gè)室內(nèi)設(shè)計(jì)軟件尿孔,所有的素材都在工具箱中俊柔,而每次從工具箱中取出的都是素材對(duì)象的一個(gè)原型筹麸,可以通過對(duì)象克隆來實(shí)現(xiàn)原型模式。
Spring 2.x中針對(duì)WebApplicationContext新增了3個(gè)作用域雏婶,分別是:request(每次HTTP請(qǐng)求都會(huì)創(chuàng)建一個(gè)新的Bean)物赶、session(同一個(gè)HttpSession共享同一個(gè)Bean,不同的HttpSession使用不同的Bean)和globalSession(同一個(gè)全局Session共享一個(gè)Bean)尚骄。
說明:單例模式和原型模式都是重要的設(shè)計(jì)模式块差。一般情況下,無狀態(tài)或狀態(tài)不可變的類適合使用單例模式倔丈。在傳統(tǒng)開發(fā)中憨闰,由于DAO持有Connection這個(gè)非線程安全對(duì)象因而沒有使用單例模式;但在Spring環(huán)境下需五,所有DAO類對(duì)可以采用單例模式鹉动,因?yàn)?/i>Spring利用AOP和JavaAPI中的ThreadLocal對(duì)非線程安全的對(duì)象進(jìn)行了特殊處理。
ThreadLocal為解決多線程程序的并發(fā)問題提供了一種新的思路宏邮。ThreadLocal泽示,顧名思義是線程的一個(gè)本地化對(duì)象,當(dāng)工作于多線程中的對(duì)象使用ThreadLocal維護(hù)變量時(shí)蜜氨,ThreadLocal為每個(gè)使用該變量的線程分配一個(gè)獨(dú)立的變量副本械筛,所以每一個(gè)線程都可以獨(dú)立的改變自己的副本,而不影響其他線程所對(duì)應(yīng)的副本飒炎。從線程的角度看埋哟,這個(gè)變量就像是線程的本地變量。
ThreadLocal類非常簡(jiǎn)單好用郎汪,只有四個(gè)方法赤赊,能用上的也就是下面三個(gè)方法:
- void set(T value):設(shè)置當(dāng)前線程的線程局部變量的值。
- T get():獲得當(dāng)前線程所對(duì)應(yīng)的線程局部變量的值煞赢。
- void remove():刪除當(dāng)前線程中線程局部變量的值抛计。
ThreadLocal是如何做到為每一個(gè)線程維護(hù)一份獨(dú)立的變量副本的呢?在ThreadLocal類中有一個(gè)Map照筑,鍵為線程對(duì)象吹截,值是其線程對(duì)應(yīng)的變量的副本,自己要模擬實(shí)現(xiàn)一個(gè)ThreadLocal類其實(shí)并不困難凝危,代碼如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class MyThreadLocal {
private Map??map = Collections.synchronizedMap(new HashMap());
public void set(T newValue) {
map.put(Thread.currentThread(),??newValue);
}
public T get() {
return??map.get(Thread.currentThread());
}
public void remove() {
map.remove(Thread.currentThread());
}
}
148饭弓、解釋一下什么叫AOP(面向切面編程)?
答:AOP(Aspect-Oriented Programming)指一種程序設(shè)計(jì)范型媒抠,該范型以一種稱為切面(aspect)的語言構(gòu)造為基礎(chǔ),切面是一種新的模塊化機(jī)制咏花,用來描述分散在對(duì)象趴生、類或方法中的橫切關(guān)注點(diǎn)(crosscutting concern)阀趴。
149、你是如何理解”橫切關(guān)注”這個(gè)概念的苍匆?
答:”橫切關(guān)注”是會(huì)影響到整個(gè)應(yīng)用程序的關(guān)注功能刘急,它跟正常的業(yè)務(wù)邏輯是正交的,沒有必然的聯(lián)系浸踩,但是幾乎所有的業(yè)務(wù)邏輯都會(huì)涉及到這些關(guān)注功能叔汁。通常,事務(wù)检碗、日志据块、安全性等關(guān)注就是應(yīng)用中的橫切關(guān)注功能。
150折剃、你如何理解AOP中的連接點(diǎn)(Joinpoint)另假、切點(diǎn)(Pointcut)、增強(qiáng)(Advice)怕犁、引介(Introduction)边篮、織入(Weaving)、切面(Aspect)這些概念奏甫?
答:
a. 連接點(diǎn)(Joinpoint):程序執(zhí)行的某個(gè)特定位置(如:某個(gè)方法調(diào)用前戈轿、調(diào)用后,方法拋出異常后)阵子。一個(gè)類或一段程序代碼擁有一些具有邊界性質(zhì)的特定點(diǎn)思杯,這些代碼中的特定點(diǎn)就是連接點(diǎn)。Spring僅支持方法的連接點(diǎn)款筑。
b. 切點(diǎn)(Pointcut):如果連接點(diǎn)相當(dāng)于數(shù)據(jù)中的記錄智蝠,那么切點(diǎn)相當(dāng)于查詢條件,一個(gè)切點(diǎn)可以匹配多個(gè)連接點(diǎn)奈梳。Spring AOP的規(guī)則解析引擎負(fù)責(zé)解析切點(diǎn)所設(shè)定的查詢條件杈湾,找到對(duì)應(yīng)的連接點(diǎn)。
c. 增強(qiáng)(Advice):增強(qiáng)是織入到目標(biāo)類連接點(diǎn)上的一段程序代碼攘须。Spring提供的增強(qiáng)接口都是帶方位名的漆撞,如:BeforeAdvice、AfterReturningAdvice于宙、ThrowsAdvice等浮驳。很多資料上將增強(qiáng)譯為“通知”,這明顯是個(gè)詞不達(dá)意的翻譯捞魁,讓很多程序員困惑了許久至会。
說明:Advice在國內(nèi)的很多書面資料中都被翻譯成”通知”,但是很顯然這個(gè)翻譯無法表達(dá)其本質(zhì)谱俭,有少量的讀物上將這個(gè)詞翻譯為”增強(qiáng)”奉件,這個(gè)翻譯是對(duì)Advice較為準(zhǔn)確的詮釋宵蛀,我們通過AOP將橫切關(guān)注功能加到原有的業(yè)務(wù)邏輯上,這就是對(duì)原有業(yè)務(wù)邏輯的一種增強(qiáng)县貌,這種增強(qiáng)可以是前置增強(qiáng)术陶、后置增強(qiáng)、返回后增強(qiáng)煤痕、拋異常時(shí)增強(qiáng)和包圍型增強(qiáng)梧宫。
d. 引介(Introduction):引介是一種特殊的增強(qiáng),它為類添加一些屬性和方法摆碉。這樣塘匣,即使一個(gè)業(yè)務(wù)類原本沒有實(shí)現(xiàn)某個(gè)接口,通過引介功能兆解,可以動(dòng)態(tài)的未該業(yè)務(wù)類添加接口的實(shí)現(xiàn)邏輯馆铁,讓業(yè)務(wù)類成為這個(gè)接口的實(shí)現(xiàn)類。
e. 織入(Weaving):織入是將增強(qiáng)添加到目標(biāo)類具體連接點(diǎn)上的過程锅睛,AOP有三種織入方式:①編譯期織入:需要特殊的Java編譯期(例如AspectJ的ajc)埠巨;②裝載期織入:要求使用特殊的類加載器,在裝載類的時(shí)候?qū)︻愡M(jìn)行增強(qiáng)现拒;③運(yùn)行時(shí)織入:在運(yùn)行時(shí)為目標(biāo)類生成代理實(shí)現(xiàn)增強(qiáng)辣垒。Spring采用了動(dòng)態(tài)代理的方式實(shí)現(xiàn)了運(yùn)行時(shí)織入,而AspectJ采用了編譯期織入和裝載期織入的方式印蔬。
f. 切面(Aspect):切面是由切點(diǎn)和增強(qiáng)(引介)組成的勋桶,它包括了對(duì)橫切關(guān)注功能的定義,也包括了對(duì)連接點(diǎn)的定義侥猬。
151例驹、Spring中自動(dòng)裝配的方式有哪些?
答:
- no:不進(jìn)行自動(dòng)裝配退唠,手動(dòng)設(shè)置Bean的依賴關(guān)系鹃锈。
- byName:根據(jù)Bean的名字進(jìn)行自動(dòng)裝配。
- byType:根據(jù)Bean的類型進(jìn)行自動(dòng)裝配瞧预。
- constructor:類似于byType屎债,不過是應(yīng)用于構(gòu)造器的參數(shù),如果正好有一個(gè)Bean與構(gòu)造器的參數(shù)類型相同則可以自動(dòng)裝配垢油,否則會(huì)導(dǎo)致錯(cuò)誤盆驹。
- autodetect:如果有默認(rèn)的構(gòu)造器,則通過constructor的方式進(jìn)行自動(dòng)裝配滩愁,否則使用byType的方式進(jìn)行自動(dòng)裝配躯喇。
說明:自動(dòng)裝配沒有自定義裝配方式那么精確,而且不能自動(dòng)裝配簡(jiǎn)單屬性(基本類型硝枉、字符串等)廉丽,在使用時(shí)應(yīng)注意秸讹。
152、Spring中如何使用注解來配置Bean雅倒?有哪些相關(guān)的注解?
答:首先需要在Spring配置文件中增加如下配置:
1
然后可以用@Component弧可、@Controller蔑匣、@Service、@Repository注解來標(biāo)注需要由Spring IoC容器進(jìn)行對(duì)象托管的類棕诵。這幾個(gè)注解沒有本質(zhì)區(qū)別裁良,只不過@Controller通常用于控制器,@Service通常用于業(yè)務(wù)邏輯類校套,@Repository通常用于倉儲(chǔ)類(例如我們的DAO實(shí)現(xiàn)類)价脾,普通的類用@Component來標(biāo)注。
153笛匙、Spring支持的事務(wù)管理類型有哪些侨把?你在項(xiàng)目中使用哪種方式?
答:Spring支持編程式事務(wù)管理和聲明式事務(wù)管理妹孙。許多Spring框架的用戶選擇聲明式事務(wù)管理秋柄,因?yàn)檫@種方式和應(yīng)用程序的關(guān)聯(lián)較少,因此更加符合輕量級(jí)容器的概念蠢正。聲明式事務(wù)管理要優(yōu)于編程式事務(wù)管理骇笔,盡管在靈活性方面它弱于編程式事務(wù)管理,因?yàn)榫幊淌绞聞?wù)允許你通過代碼控制業(yè)務(wù)嚣崭。
事務(wù)分為全局事務(wù)和局部事務(wù)笨触。全局事務(wù)由應(yīng)用服務(wù)器管理,需要底層服務(wù)器JTA支持(如WebLogic雹舀、WildFly等)芦劣。局部事務(wù)和底層采用的持久化方案有關(guān),例如使用JDBC進(jìn)行持久化時(shí)葱跋,需要使用Connetion對(duì)象來操作事務(wù)持寄;而采用Hibernate進(jìn)行持久化時(shí),需要使用Session對(duì)象來操作事務(wù)娱俺。
Spring提供了如下所示的事務(wù)管理器稍味。
事務(wù)管理器實(shí)現(xiàn)類
目標(biāo)對(duì)象
DataSourceTransactionManager
注入DataSource
HibernateTransactionManager
注入SessionFactory
JdoTransactionManager
管理JDO事務(wù)
JtaTransactionManager
使用JTA管理事務(wù)
PersistenceBrokerTransactionManager
管理Apache的OJB事務(wù)
PersistenceBrokerTransactionManager管理Apache的OJB事務(wù)
這些事務(wù)的父接口都是PlatformTransactionManager。Spring的事務(wù)管理機(jī)制是一種典型的策略模式荠卷,PlatformTransactionManager代表事務(wù)管理接口模庐,該接口定義了三個(gè)方法,該接口并不知道底層如何管理事務(wù)油宜,但是它的實(shí)現(xiàn)類必須提供getTransaction()方法(開啟事務(wù))掂碱、commit()方法(提交事務(wù))怜姿、rollback()方法(回滾事務(wù))的多態(tài)實(shí)現(xiàn),這樣就可以用不同的實(shí)現(xiàn)類代表不同的事務(wù)管理策略疼燥。使用JTA全局事務(wù)策略時(shí)沧卢,需要底層應(yīng)用服務(wù)器支持,而不同的應(yīng)用服務(wù)器所提供的JTA全局事務(wù)可能存在細(xì)節(jié)上的差異醉者,因此實(shí)際配置全局事務(wù)管理器是可能需要使用JtaTransactionManager的子類但狭,如:WebLogicJtaTransactionManager(Oracle的WebLogic服務(wù)器提供)、UowJtaTransactionManager(IBM的WebSphere服務(wù)器提供)等撬即。
154立磁、如何在Web項(xiàng)目中配置Spring的IoC容器?
答:如果需要在Web項(xiàng)目中使用Spring的IoC容器剥槐,可以在Web項(xiàng)目配置文件web.xml中做出如下配置:
1
2
3
4
5
6
7
8
9
10
contextConfigLocation
classpath:applicationContext.xml
org.springframework.web.context.ContextLoaderListener
155唱歧、如何在Web項(xiàng)目中配置SpringMVC?
答:要使用Spring MVC需要在Web項(xiàng)目配置文件中配置其前端控制器DispatcherServlet粒竖,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
example
org.springframework.web.servlet.DispatcherServlet
1
example
*.html
http://bbs.itheima.com/forum.php?mod=viewthread&tid=374230