成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

看起來很長(zhǎng)但還是有用的Spring學(xué)習(xí)筆記

DTeam / 3518人閱讀

摘要:關(guān)于依賴注入注入的注解提供的注解不僅僅是對(duì)象,還有在構(gòu)造器上,還能用在屬性的方法上。與之相反,的限定符能夠在所有可選的上進(jìn)行縮小范圍的操作,最終能夠達(dá)到只有一個(gè)滿足所規(guī)定的限制條件。注解是使用限定符的主要方式。

本文首發(fā)于泊浮目的專欄:https://segmentfault.com/blog...

Spring致力于提供一種方法管理你的業(yè)務(wù)對(duì)象。在大量Java EE的應(yīng)用中,隨處可見Spring。今天我將簡(jiǎn)單的介紹一下Spring這個(gè)框架。

本文適合讀者:

想學(xué)Spring的Java開發(fā)者

剛用Spring不久的人

Why

為什么要使用Spring?

Spring主要兩個(gè)有功能為我們的業(yè)務(wù)對(duì)象管理提供了非常便捷的方法:

DI(Dependency Injection,依賴注入)

AOP(Aspect Oriented Programming,面向切面編程)

Java Bean

每一個(gè)類實(shí)現(xiàn)了Bean的規(guī)范才可以由Spring來接管,那么Bean的規(guī)范是什么呢?

必須是個(gè)公有(public)類

有無參構(gòu)造函數(shù)

用公共方法暴露內(nèi)部成員屬性(getter,setter)

實(shí)現(xiàn)這樣規(guī)范的類,被稱為Java Bean。即是一種可重用的組件。

額外補(bǔ)充:
Java 帝國(guó)之Java bean (上)
Java 帝國(guó)之Java bean(下)
DI-依賴注入

簡(jiǎn)單來說,一個(gè)系統(tǒng)中可能會(huì)有成千上萬個(gè)對(duì)象。如果要手工維護(hù)它們之間的關(guān)系,這是不可想象的。我們可以在Spring的XML文件描述它們之間的關(guān)系,由Spring自動(dòng)來注入它們——比如A類的實(shí)例需要B類的實(shí)例作為參數(shù)set進(jìn)去。

擴(kuò)展:Spring 的本質(zhì)系列(1) -- 依賴注入 
AOP-面向切面編程

就以日志系統(tǒng)為例。在執(zhí)行某個(gè)操作前后都需要輸出日志,如果手工加代碼,那簡(jiǎn)直太可怕了。而且等代碼龐大起來,也是非常難維護(hù)的一種情況。這里就需要面向切面來編程

擴(kuò)展:Spring本質(zhì)系列(2)-AOP 
How 關(guān)于Bean Bean的生命周期

如你所見,在bean準(zhǔn)備就緒之前,bean工廠執(zhí)行了若干啟動(dòng)步驟。我們對(duì)圖進(jìn)行詳細(xì)描述:

Spring對(duì)bean進(jìn)行實(shí)例化;

Spring將值和bean的引用注入到bean對(duì)應(yīng)的屬性中;

如果bean實(shí)現(xiàn)了BeanNameAware接口,Spring將bean的ID傳遞給setBean-Name()方法;

如果bean實(shí)現(xiàn)了BeanFactoryAware接口,Spring將調(diào)用setBeanFactory()方法,將BeanFactory容器實(shí)例傳入;

如果bean實(shí)現(xiàn)了ApplicationContextAware接口,Spring將調(diào)用setApplicationContext()方法,將bean所在的應(yīng)用上下文的引用傳入進(jìn)來;

如果bean實(shí)現(xiàn)了BeanPostProcessor接口,Spring將調(diào)用它們的post-ProcessBeforeInitialization()方法;

如果bean實(shí)現(xiàn)了InitializingBean接口,Spring將調(diào)用它們的after-PropertiesSet()方法。類似地,如果bean使用init-method聲明了初始化方法,該方法也會(huì)被調(diào)用;

如果bean實(shí)現(xiàn)了BeanPostProcessor接口,Spring將調(diào)用它們的post-ProcessAfterInitialization()方法;

此時(shí),bean已經(jīng)準(zhǔn)備就緒,可以被應(yīng)用程序使用了,它們將一直駐留在應(yīng)用上下文中,直到該應(yīng)用上下文被銷毀;

如果bean實(shí)現(xiàn)了DisposableBean接口,Spring將調(diào)用它的destroy()接口方法。同樣,如果bean使用destroy-method聲明了銷毀方法,該方法也會(huì)被調(diào)用。

Bean的作用域

Spring定義了多種Bean作用域,可以基于這些作用域創(chuàng)建bean,包括:

單例(Singleton):在整個(gè)應(yīng)用中,只創(chuàng)建bean的一個(gè)實(shí)例。

原型(Prototype):每次注入或者通過Spring應(yīng)用上下文獲取的時(shí)候,都會(huì)創(chuàng)建一個(gè)新的bean實(shí)例。

會(huì)話(Session):在Web應(yīng)用中,為每個(gè)會(huì)話創(chuàng)建一個(gè)bean實(shí)例。

請(qǐng)求(Rquest):在Web應(yīng)用中,為每個(gè)請(qǐng)求創(chuàng)建一個(gè)bean實(shí)例。

在代碼里看起來是這樣的:

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class MyIsBean{...}

XML版本:

在默認(rèn)情況下,Spring應(yīng)用上下文中所有bean都是作為以單例(singleton)的形式創(chuàng)建的。也就是說,不管給定的一個(gè)bean被注入到其他bean多少次,每次所注入的都是同一個(gè)實(shí)例。

在大多數(shù)情況下,單例bean是很理想的方案。初始化和垃圾回收對(duì)象實(shí)例所帶來的成本只留給一些小規(guī)模任務(wù),在這些任務(wù)中,讓對(duì)象保持無狀態(tài)并且在應(yīng)用中反復(fù)重用這些對(duì)象可能并不合理。

有時(shí)候,可能會(huì)發(fā)現(xiàn),你所使用的類是易變的(mutable),它們會(huì)保持一些狀態(tài),因此重用是不安全的。在這種情況下,將class聲明為單例的bean就不是什么好主意了,因?yàn)閷?duì)象會(huì)被污染,稍后重用的時(shí)候會(huì)出現(xiàn)意想不到的問題。

聲明Bean

以下是聲明Bean的注解:

@Component 組件,沒有明確的角色

@Service 在業(yè)務(wù)邏輯層使用

@Repository 在數(shù)據(jù)訪問層使用

@Controller 在展現(xiàn)層使用(MVC -> Spring MVC)使用

在這里,可以指定bean的id名:Component("yourBeanName")

同時(shí),Spring支持將@Named作為@Component注解的替代方案。兩者之間有一些細(xì)微的差異,但是在大多數(shù)場(chǎng)景中,它們是可以互相替換的。

關(guān)于依賴注入 注入Bean的注解 @Autowired Spring提供的注解

不僅僅是對(duì)象,還有在構(gòu)造器上,還能用在屬性的Setter方法上。

不管是構(gòu)造器、Setter方法還是其他的方法,Spring都會(huì)嘗試滿足方法參數(shù)上所聲明的依賴。假如有且只有一個(gè)bean匹配依賴需求的話,那么這個(gè)bean將會(huì)被裝配進(jìn)來。

如果沒有匹配的bean,那么在應(yīng)用上下文創(chuàng)建的時(shí)候,Spring會(huì)拋出一個(gè)異常。為了避免異常的出現(xiàn),你可以將@Autowired的required屬性設(shè)置為false。

將required屬性設(shè)置為false時(shí),Spring會(huì)嘗試執(zhí)行自動(dòng)裝配,但是如果沒有匹配的bean的話,Spring將會(huì)讓這個(gè)bean處于未裝配的狀態(tài)。但是,把required屬性設(shè)置為false時(shí),你需要謹(jǐn)慎對(duì)待。如果在你的代碼中沒有進(jìn)行null檢查的話,這個(gè)處于未裝配狀態(tài)的屬性有可能會(huì)出現(xiàn)NullPointerException。

@Inject注解來源于Java依賴注入規(guī)范,該規(guī)范同時(shí)還為我們定義了@Named注解。在自動(dòng)裝配中,Spring同時(shí)支持@Inject和@Autowired。盡管@Inject和@Autowired之間有著一些細(xì)微的差別,但是在大多數(shù)場(chǎng)景下,它們都是可以互相替換的。

@Autowired 是最常見的注解之一,但在老項(xiàng)目中,你可能會(huì)看到這些注解,它們的作用和@Autowired 相近:

@Inject 是JSR-330提供的注解

@Resource 是JSR-250提供的注解

條件化的Bean

假設(shè)你希望一個(gè)或多個(gè)bean只有在應(yīng)用的類路徑下包含特定的庫時(shí)才創(chuàng)建?;蛘呶覀兿M硞€(gè)bean只有當(dāng)另外某個(gè)特定的bean也聲明了之后才會(huì)創(chuàng)建。我們還可能要求只有某個(gè)特定的環(huán)境變量設(shè)置之后,才會(huì)創(chuàng)建某個(gè)bean。

在Spring 4之前,很難實(shí)現(xiàn)這種級(jí)別的條件化配置,但是Spring 4引入了一個(gè)新的@Conditional注解,它可以用到帶有@Bean注解的方法上。如果給定的條件計(jì)算結(jié)果為true,就會(huì)創(chuàng)建這個(gè)bean,否則的話,這個(gè)bean會(huì)被忽略。

通過ConditionContext,我們可以做到如下幾點(diǎn):

借助getRegistry()返回的BeanDefinitionRegistry檢查bean定義;

借助getBeanFactory()返回的ConfigurableListableBeanFactory檢查bean是否存在,甚至探查bean的屬性;

借助getEnvironment()返回的Environment檢查環(huán)境變量是否存在以及它的值是什么;

讀取并探查getResourceLoader()返回的ResourceLoader所加載的資源;

借助getClassLoader()返回的ClassLoader加載并檢查類是否存在。

處理自動(dòng)裝配的歧義性 標(biāo)示首選的bean

在聲明bean的時(shí)候,通過將其中一個(gè)可選的bean設(shè)置為首選(primary)bean能夠避免自動(dòng)裝配時(shí)的歧義性。當(dāng)遇到歧義性的時(shí)候,Spring將會(huì)使用首選的bean,而不是其他可選的bean。實(shí)際上,你所聲明就是“最喜歡”的bean。

限定自動(dòng)裝配的bean

設(shè)置首選bean的局限性在于@Primary無法將可選方案的范圍限定到唯一一個(gè)無歧義性的選項(xiàng)中。它只能標(biāo)示一個(gè)優(yōu)先的可選方案。當(dāng)首選bean的數(shù)量超過一個(gè)時(shí),我們并沒有其他的方法進(jìn)一步縮小可選范圍。

與之相反,Spring的限定符能夠在所有可選的bean上進(jìn)行縮小范圍的操作,最終能夠達(dá)到只有一個(gè)bean滿足所規(guī)定的限制條件。如果將所有的限定符都用上后依然存在歧義性,那么你可以繼續(xù)使用更多的限定符來縮小選擇范圍。

@Qualifier注解是使用限定符的主要方式。它可以與@Autowired和@Inject協(xié)同使用,在注入的時(shí)候指定想要注入進(jìn)去的是哪個(gè)bean。例如,我們想要確保要將IceCream注入到setDessert()之中:

@Autowired
@Qualifier("iceCream")
public void setDessert(Dessert dessert){
  this.dessert = dessert;
}

這是使用限定符的最簡(jiǎn)單的例子。為@Qualifier注解所設(shè)置的參數(shù)就是想要注入的bean的ID。所有使用@Component注解聲明的類都會(huì)創(chuàng)建為bean,并且bean的ID為首字母變?yōu)樾懙念惷?。因此,@Qualifier("iceCream")指向的是組件掃描時(shí)所創(chuàng)建的bean,并且這個(gè)bean是IceCream類的實(shí)例。

實(shí)際上,還有一點(diǎn)需要補(bǔ)充一下。更準(zhǔn)確地講,@Qualifier("iceCream")所引用的bean要具有String類型的“iceCream”作為限定符。如果沒有指定其他的限定符的話,所有的bean都會(huì)給定一個(gè)默認(rèn)的限定符,這個(gè)限定符與bean的ID相同。因此,框架會(huì)將具有“iceCream”限定符的bean注入到setDessert()方法中。這恰巧就是ID為iceCream的bean,它是IceCream類在組件掃描的時(shí)候創(chuàng)建的。

基于默認(rèn)的bean ID作為限定符是非常簡(jiǎn)單的,但這有可能會(huì)引入一些問題。如果你重構(gòu)了IceCream類,將其重命名為Gelato的話,那此時(shí)會(huì)發(fā)生什么情況呢?如果這樣的話,bean的ID和默認(rèn)的限定符會(huì)變?yōu)間elato,這就無法匹配setDessert()方法中的限定符。自動(dòng)裝配會(huì)失敗。

這里的問題在于setDessert()方法上所指定的限定符與要注入的bean的名稱是緊耦合的。對(duì)類名稱的任意改動(dòng)都會(huì)導(dǎo)致限定符失效。

SpringEL

Value實(shí)現(xiàn)資源的注入

Bean的初始化和銷毀

Java配置方式:initMethod和destoryMethod

注解:@PostConstruct和@PreDestory

Profile

提供在不同的環(huán)境下使用不同的配置

激活Profile

Spring在確定哪個(gè)profile處于激活狀態(tài)時(shí),需要依賴兩個(gè)獨(dú)立的屬性:spring.profiles.active和spring.profiles.default。如果設(shè)置了spring.profiles.active屬性的話,那么它的值就會(huì)用來確定哪個(gè)profile是激活的。但如果沒有設(shè)置spring.profiles.active屬性的話,那Spring將會(huì)查找spring.profiles.default的值。如果spring.profiles.active和spring.profiles.default均沒有設(shè)置的話,那就沒有激活的profile,因此只會(huì)創(chuàng)建那些沒有定義在profile中的bean。

使用profile進(jìn)行測(cè)試

當(dāng)運(yùn)行集成測(cè)試時(shí),通常會(huì)希望采用與生產(chǎn)環(huán)境(或者是生產(chǎn)環(huán)境的部分子集)相同的配置進(jìn)行測(cè)試。但是,如果配置中的bean定義在了profile中,那么在運(yùn)行測(cè)試時(shí),我們就需要有一種方式來啟用合適的profile。

Spring提供了@ActiveProfiles注解,我們可以使用它來指定運(yùn)行測(cè)試時(shí)要激活哪個(gè)profile。在集成測(cè)試時(shí),通常想要激活的是開發(fā)環(huán)境的profile。

比如Profile("dev")

Application Event

使用Application Event可以做到Bean與Bean之間的通信

Spring的事件需要遵循如下流程:

自定義事件,集成ApplicationEvent

定義事件監(jiān)聽器,實(shí)現(xiàn)ApplicationListener

使用容器發(fā)布事件

關(guān)于AOP 名詞介紹 通知(Advice)

通知定義了切面是什么以及何時(shí)使用。除了描述切面要完成的工作,通知還解決了何時(shí)執(zhí)行這個(gè)工作的問題。它應(yīng)該應(yīng)用在某個(gè)方法被調(diào)用之前?之后?之前和之后都調(diào)用?還是只在方法拋出異常時(shí)調(diào)用?

Spring切面可以應(yīng)用5種類型的通知:

前置通知(Before):在目標(biāo)方法被調(diào)用之前調(diào)用通知功能;

后置通知(After):在目標(biāo)方法完成之后調(diào)用通知,此時(shí)不會(huì)關(guān)心方法的輸出是什么;

返回通知(After-returning):在目標(biāo)方法成功執(zhí)行之后調(diào)用通知;

異常通知(After-throwing):在目標(biāo)方法拋出異常后調(diào)用通知;

環(huán)繞通知(Around):通知包裹了被通知的方法,在被通知的方法調(diào)用之前和調(diào)用之后執(zhí)行自定義的行為。

對(duì)應(yīng)注解:

注  解 通  知
@After 通知方法會(huì)在目標(biāo)方法返回或拋出異常后調(diào)用
@AfterReturning 通知方法會(huì)在目標(biāo)方法返回后調(diào)用
@AfterThrowing 通知方法會(huì)在目標(biāo)方法拋出異常后調(diào)用
@Around 通知方法會(huì)將目標(biāo)方法封裝起來
@Before 通知方法會(huì)在目標(biāo)方法調(diào)用之前執(zhí)行
連接點(diǎn)(Join point)

連接點(diǎn)是在應(yīng)用執(zhí)行過程中能夠插入切面的一個(gè)點(diǎn)。這個(gè)點(diǎn)可以是調(diào)用方法時(shí)、拋出異常時(shí)、甚至修改一個(gè)字段時(shí)。切面代碼可以利用這些點(diǎn)插入到應(yīng)用的正常流程之中,并添加新的行為。

切點(diǎn)(Pointcut)

如果說通知定義了切面的“什么”和“何時(shí)”的話,那么切點(diǎn)就定義了“何處” 。切點(diǎn)的定義會(huì)匹配通知所要織入的一個(gè)或多個(gè)連接點(diǎn)。我們通常使用明確的類和方法名稱,或是利用正則表達(dá)式定義所匹配的類和方法名稱來指定這些切點(diǎn)。有些AOP框架允許我們創(chuàng)建動(dòng)態(tài)的切點(diǎn),可以根據(jù)運(yùn)行時(shí)的決策(比如方法的參數(shù)值)來決定是否應(yīng)用通知。

切面(Aspect)

通知+切點(diǎn)=切面

引入(Introduction)

引入允許我們向現(xiàn)有的類添加新方法或?qū)傩?/p> 織入(Weaving)

織入是把切面應(yīng)用到目標(biāo)對(duì)象并創(chuàng)建新的代理對(duì)象的過程。切面在指定的連接點(diǎn)被織入到目標(biāo)對(duì)象中。在目標(biāo)對(duì)象的生命周期里有多個(gè)點(diǎn)可以進(jìn)行織入:

編譯期:切面在目標(biāo)類編譯時(shí)被織入。這種方式需要特殊的編譯器。AspectJ的織入編譯器就是以這種方式織入切面的。

類加載期:切面在目標(biāo)類加載到JVM時(shí)被織入。這種方式需要特殊的類加載器(ClassLoader),它可以在目標(biāo)類被引入應(yīng)用之前增強(qiáng)該目標(biāo)類的字節(jié)碼。AspectJ 5的加載時(shí)織入(load-time weaving,LTW)就支持以這種方式織入切面。

運(yùn)行期:切面在應(yīng)用運(yùn)行的某個(gè)時(shí)刻被織入。一般情況下,在織入切面時(shí),AOP容器會(huì)為目標(biāo)對(duì)象動(dòng)態(tài)地創(chuàng)建一個(gè)代理對(duì)象。Spring AOP就是以這種方式織入切面的。

Spring對(duì)AOP的支持:

基于代理的經(jīng)典Spring AOP;

純POJO切面(4.x版本需要XML配置);

@AspectJ注解驅(qū)動(dòng)的切面;

注入式AspectJ切面(適用于Spring各版本)。

前三種都是Spring AOP實(shí)現(xiàn)的變體,Spring AOP構(gòu)建在動(dòng)態(tài)代理基礎(chǔ)之上,因此,Spring對(duì)AOP的支持局限于方法攔截。也就是說,AspectJ才是王道。

另外在代理類中包裹切面,Spring在運(yùn)行期把切面織入到Spring管理的bean中。如下圖所示,代理類封裝了目標(biāo)類,并攔截被通知方法的調(diào)用,再把調(diào)用轉(zhuǎn)發(fā)給真正的目標(biāo)bean。當(dāng)代理攔截到方法調(diào)用時(shí),在調(diào)用目標(biāo)bean方法之前,會(huì)執(zhí)行切面邏輯。直到應(yīng)用需要被代理的bean時(shí),Spring才創(chuàng)建代理對(duì)象。 如果使用的是ApplicationContext的話,在ApplicationContext從BeanFactory中加載所有bean的時(shí)候,Spring才會(huì)創(chuàng)建被代理的對(duì)象。因?yàn)镾pring運(yùn)行時(shí)才創(chuàng)建代理對(duì)象,所以我們不需要特殊的編譯器來織入Spring AOP的切面。

例子
public interface Performance(){
  public void perform();
}

現(xiàn)在來寫一個(gè)切點(diǎn)表達(dá)式,這個(gè)表達(dá)式能夠設(shè)置當(dāng)perform()方法執(zhí)行時(shí)觸發(fā)通知的調(diào)用。

execution(* concert.Performance.perform(..))
//execution:在方法執(zhí)行時(shí)觸發(fā)
//*:返回任意類型
//concert.Performance:方法所屬類
//perform:方法名
//(..):使用任意參數(shù)

不僅如此,還可以寫的更復(fù)雜一點(diǎn)

execution(* concert.Performance.perform(..)&&within(concert.*))
//增加了一個(gè)與操作,當(dāng)concert包下的任意類方法被調(diào)用時(shí)也會(huì)觸發(fā)

在切點(diǎn)中選擇bean

execution(*concert.Performance.perform()) and bean("woodstock")
//限定bean id為woodstock

來個(gè)完整的切面

@Aspect
public class Audience{
  @Before("execution(**concert.Performance.perform(..))")
  public void silenceCellPhones(){
    System.out.println("Silencing cell phones");
  }
  @Before("execution{** concert.Performance.perform{..}}")
  public void taskSeats(){
    System.out.println("Talking seats");
  }
  @AfterReturning("execution{** concert.Performance.perform{..}}")
  public void applause(){
    System.out.println("CLAP CLAP CLAP!!!");
  }
  @AfterThrowing("execution{** concert.Performance.perform{..}}")
  public void demanRefund(){
    System.out.println("Demanding a refund");
  }
}

可以簡(jiǎn)化一下

@Aspect
public class Audience{
  //避免頻繁使用切點(diǎn)表達(dá)式
  @Pointcut("execution(** concert.Performance.perform(..))")
  public void performance(){}

  @Before("performance()")
  public void silenceCellPhones(){
    System.out.println("Silencing cell phones");
  }
  @Before("performance()")
  public void taskSeats(){
    System.out.println("Talking seats");
  }
  @AfterReturning("performance()")
  public void applause(){
    System.out.println("CLAP CLAP CLAP!!!");
  }
  @AfterThrowing("performance()")
  public void demanRefund(){
    System.out.println("Demanding a refund");
  }
}
XML中聲明切面
AOP配置元素 用途
定義AOP通知器
定義AOP后置通知(不管被通知的方法是否執(zhí)行成功)
定義AOP返回通知
定義AOP異常通知
定義AOP環(huán)繞通知
定義一個(gè)切面
啟用@AspectJ注解驅(qū)動(dòng)的切面
定義一個(gè)AOP前置通知
頂層的AOP配置元素。大多數(shù)的元素必須包含在元素內(nèi)
以透明的方式為被通知的對(duì)象引入額外的接口
定義一個(gè)切點(diǎn)

來個(gè)栗子

public class Audience{
  public void silenceCellPhones(){
    System.out.println("Silencing cell phones");
  }
  public void taskSeats(){
    System.out.println("Talking seats");
  }
  public void applause(){
    System.out.println("CLAP CLAP CLAP!!!");
  }
  public void demandRefund(){
    System.out.println("Demanding a refund");
  }
}

通過XML將無注解的Audience聲明為切面


  
    
    
    
    
  
          
AspectJ

關(guān)于Spring AOP的AspectJ切點(diǎn),最重要的一點(diǎn)就是Spring僅支持AspectJ切點(diǎn)指示器(pointcut designator)的一個(gè)子集。讓我們回顧下,Spring是基于代理的,而某些切點(diǎn)表達(dá)式是與基于代理的AOP無關(guān)的。下表列出了Spring AOP所支持的AspectJ切點(diǎn)指示器。

Spring借助AspectJ的切點(diǎn)表達(dá)式語言來定義Spring切面

AspectJ指示器 描  述
arg() 限制連接點(diǎn)匹配參數(shù)為指定類型的執(zhí)行方法
@args() 限制連接點(diǎn)匹配參數(shù)由指定注解標(biāo)注的執(zhí)行方法
execution() 用于匹配是連接點(diǎn)的執(zhí)行方法
this() 限制連接點(diǎn)匹配AOP代理的bean引用為指定類型的類
target 限制連接點(diǎn)匹配目標(biāo)對(duì)象為指定類型的類
@target() 限制連接點(diǎn)匹配特定的執(zhí)行對(duì)象,這些對(duì)象對(duì)應(yīng)的類要具有指定類型的注解
within() 限制連接點(diǎn)匹配指定的類型
@within() 限制連接點(diǎn)匹配指定注解所標(biāo)注的類型(當(dāng)使用Spring AOP時(shí),方法定義在由指定的注解所標(biāo)注的類里)
@annotation 限定匹配帶有指定注解的連接點(diǎn)
Spring高級(jí)特性

由于Spring特殊的依賴注入技巧,導(dǎo)致Bean之間沒有耦合度。
但是Bean有時(shí)需要使用spring容器本身的資源,這時(shí)你的Bean必須意識(shí)到Spring容器的存在。所以得使用Spring Aware,下面來看看Spring Aware提供的接口

BeanNameAware 獲得到容器中Bean的名稱
BeanFactory 獲得當(dāng)前的bean factory,這樣可以調(diào)用容器的服務(wù)
ApplicationContextAware* 當(dāng)前application context,這樣可以調(diào)用容器的服務(wù)
MessageSourceAware 獲得Message source
ApplicationEventPublisherAware 應(yīng)用時(shí)間發(fā)布器,可以發(fā)布時(shí)間,
ResourceLoaderAware 獲得資源加載器,可以獲得外部資源文件
@TaskExecutor

這樣可以實(shí)現(xiàn)多線程和并發(fā)編程。通過@EnableAsync開啟對(duì)異步任務(wù)的支持,并通過實(shí)際執(zhí)行的Bean的方法始中使用@Async注解來聲明其是一個(gè)異步任務(wù)

@Scheduled 計(jì)劃任務(wù)

首先通過在配置類注解@EnableScheduling來開啟對(duì)計(jì)劃任務(wù)的支持,然后在要執(zhí)行計(jì)劃任務(wù)的方法上注解@Scheduled,聲明這是一個(gè)計(jì)劃任務(wù)

@Conditional

根據(jù)滿足某一個(gè)特定條件創(chuàng)建一個(gè)特定的Bean。

組合注解與元注解

元注解就是可以注解到別的注解上的注解,被注解的注解稱之為組合注解,組合注解具備注解其上的元注解的功能。

 @Enable*注解的工作原理

通過觀察這些@Enable*注解的源碼,我們發(fā)現(xiàn)所有的注解都有一個(gè)@Import注解,@Import是用來導(dǎo)入配置類的,這也就意外著這些自動(dòng)開啟的實(shí)現(xiàn)其實(shí)是導(dǎo)入了一些自動(dòng)配置的Bean。這些導(dǎo)入配置的方式主要范圍以下三種類型:

第一類:直接導(dǎo)入配置類

第二類:依據(jù)條件選擇配置類

第三類:動(dòng)態(tài)注冊(cè)Bean

What

簡(jiǎn)單的分析一下Spring。

Spring 框架中的核心組件只有三個(gè):Core、Context 和 Bean。它們構(gòu)建起了整個(gè) Spring 的骨骼架構(gòu)。沒有它們就不可能有 AOP、Web 等上層的特性功能。下面也將主要從這三個(gè)組件入手分析 Spring。

Spring的設(shè)計(jì)理念

用過Spring的同學(xué)都知道Bean在Spring的作用是非常重要的。通過一系列簡(jiǎn)單的配置來滿足類與類之間的依賴關(guān)系——這叫做依賴注入。而依賴注入的關(guān)系是在一個(gè)叫IOC的容器中進(jìn)行管理。

核心組件

我們說到Spring 框架中的核心組件只有三個(gè):Core、Context 和 Bean。那么Core和Context是如何協(xié)作的呢?

我們知道 Bean 包裝的是 Object,而 Object 必然有數(shù)據(jù),如何給這些數(shù)據(jù)提供生存環(huán)境就是 Context 要解決的問題,對(duì) Context 來說他就是要發(fā)現(xiàn)每個(gè) Bean 之間的關(guān)系,為它們建立這種關(guān)系并且要維護(hù)好這種關(guān)系。所以 Context 就是一個(gè) Bean 關(guān)系的集合,這個(gè)關(guān)系集合又叫 Ioc 容器 ,一旦建立起這個(gè) Ioc 容器后 Spring 就可以為你工作了。那 Core 組件又有什么用武之地呢?其實(shí) Core 就是發(fā)現(xiàn)、建立和維護(hù)每個(gè) Bean 之間的關(guān)系所需要的一些列的工具。

解析核心組件 Bean

前面已經(jīng)說明了 Bean 組件對(duì) Spring 的重要性,下面看看 Bean 這個(gè)組件式怎么設(shè)計(jì)的。Bean 組件在 Spring 的 org.springframework.beans 包下。這個(gè)包下的所有類主要解決了三件事:Bean 的定義、Bean 的創(chuàng)建以及對(duì) Bean 的解析。對(duì) Spring 的使用者來說唯一需要關(guān)心的就是 Bean 的創(chuàng)建,其他兩個(gè)由 Spring 在內(nèi)部幫你完成了,對(duì)你來說是透明的。

Spring Bean 的創(chuàng)建時(shí)典型的工廠模式,他的頂級(jí)接口是 BeanFactory,下圖是這個(gè)工廠的繼承層次關(guān)系:

BeanFactory 有三個(gè)子類:ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory。但是從上圖中我們可以發(fā)現(xiàn)最終的默認(rèn)實(shí)現(xiàn)類是 DefaultListableBeanFactory,他實(shí)現(xiàn)了所有的接口。那為何要定義這么多層次的接口呢?查閱這些接口的源碼和說明發(fā)現(xiàn),每個(gè)接口都有他使用的場(chǎng)合,它主要是為了區(qū)分在 Spring 內(nèi)部在操作過程中對(duì)象的傳遞和轉(zhuǎn)化過程中,對(duì)對(duì)象的數(shù)據(jù)訪問所做的限制。例如 ListableBeanFactory 接口表示這些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是這些 Bean 是有繼承關(guān)系的,也就是每個(gè) Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定義 Bean 的自動(dòng)裝配規(guī)則。這四個(gè)接口共同定義了 Bean 的集合、Bean 之間的關(guān)系、以及 Bean 行為。

Context

ApplicationContext 是 Context 的頂級(jí)父類,他除了能標(biāo)識(shí)一個(gè)應(yīng)用環(huán)境的基本信息外,他還繼承了五個(gè)接口,這五個(gè)接口主要是擴(kuò)展了 Context 的功能。下面是 Context 的類結(jié)構(gòu)圖:

從上圖中可以看出 ApplicationContext 繼承了 BeanFactory,這也說明了 Spring 容器中運(yùn)行的主體對(duì)象是 Bean,另外 ApplicationContext 繼承了 ResourceLoader 接口,使得 ApplicationContext 可以訪問到任何外部資源,這將在 Core 中詳細(xì)說明。

ApplicationContext 的子類主要包含兩個(gè)方面:

ConfigurableApplicationContext 表示該 Context 是可修改的,也就是在構(gòu)建 Context 中用戶可以動(dòng)態(tài)添加或修改已有的配置信息,它下面又有多個(gè)子類,其中最經(jīng)常使用的是可更新的 Context,即 AbstractRefreshableApplicationContext類。

WebApplicationContext 顧名思義,就是為 web 準(zhǔn)備的 Context 他可以直接訪問到 ServletContext,通常情況下,這個(gè)接口使用的少。

再往下分就是按照構(gòu)建 Context 的文件類型,接著就是訪問 Context 的方式。這樣一級(jí)一級(jí)構(gòu)成了完整的 Context 等級(jí)層次。

總體來說 ApplicationContext 必須要完成以下幾件事:

標(biāo)識(shí)一個(gè)應(yīng)用環(huán)境

利用 BeanFactory 創(chuàng)建 Bean 對(duì)象

保存對(duì)象關(guān)系表

能夠捕獲各種事件

Context 作為 Spring 的 IOC 容器,基本上整合了 Spring 的大部分功能,或者說是大部分功能的基礎(chǔ)。

Core

Core 組件作為 Spring 的核心組件,他其中包含了很多的關(guān)鍵類,其中一個(gè)重要組成部分就是定義了資源的訪問方式。這種把所有資源都抽象成一個(gè)接口的方式很值得在以后的設(shè)計(jì)中拿來學(xué)習(xí)。下面就重要看一下這個(gè)部分在 Spring 的作用。

從上圖可以看出 Resource 接口封裝了各種可能的資源類型,也就是對(duì)使用者來說屏蔽了文件類型的不同。對(duì)資源的提供者來說,如何把資源包裝起來交給其他人用這也是一個(gè)問題,我們看到 Resource 接口繼承了 InputStreamSource 接口,這個(gè)接口中有個(gè) getInputStream 方法,返回的是 InputStream 類。這樣所有的資源都被可以通過 InputStream 這個(gè)類來獲取,所以也屏蔽了資源的提供者。另外還有一個(gè)問題就是加載資源的問題,也就是資源的加載者要統(tǒng)一,從上圖中可以看出這個(gè)任務(wù)是由 ResourceLoader 接口完成,他屏蔽了所有的資源加載者的差異,只需要實(shí)現(xiàn)這個(gè)接口就可以加載所有的資源,他的默認(rèn)實(shí)現(xiàn)是 DefaultResourceLoader

那么, Context 和 Resource 是如何建立關(guān)系的?

從上圖可以看出,Context 是把資源的加載、解析和描述工作委托給了 ResourcePatternResolver 類來完成,他相當(dāng)于一個(gè)接頭人,他把資源的加載、解析和資源的定義整合在一起便于其他組件使用。Core 組件中還有很多類似的方式。

小結(jié)

該文章算是以前學(xué)習(xí)Spring時(shí)候的一些筆記整理。如果有任何錯(cuò)誤或者不解的地方,請(qǐng)留言給我。這是一個(gè)令我們可以一起學(xué)習(xí)進(jìn)步的機(jī)會(huì)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/66883.html

相關(guān)文章

  • ZStack源碼剖析:如何在百萬行代碼中快速迭代

    摘要:本文將對(duì)核心引擎的源碼進(jìn)行剖析。在筆者看來,能夠快速迭代的原因首先是來自于每位工程師的辛勤付出。在中,還有一類很有意思的代碼,一般稱之為。筆者有機(jī)會(huì)將會(huì)在之后的系列文章分析其中的典型案例以及在代碼中使用極其頻繁的核心工具。 本文首發(fā)于泊浮目的專欄:https://segmentfault.com/blog... 前言 ZStack是下一代開源的云計(jì)算IaaS(基礎(chǔ)架構(gòu)即服務(wù))軟件。它...

    liujs 評(píng)論0 收藏0
  • ZStack源碼剖析:如何在百萬行代碼中快速迭代

    摘要:本文將對(duì)核心引擎的源碼進(jìn)行剖析。在筆者看來,能夠快速迭代的原因首先是來自于每位工程師的辛勤付出。在中,還有一類很有意思的代碼,一般稱之為。筆者有機(jī)會(huì)將會(huì)在之后的系列文章分析其中的典型案例以及在代碼中使用極其頻繁的核心工具。 本文首發(fā)于泊浮目的專欄:https://segmentfault.com/blog... 前言 ZStack是下一代開源的云計(jì)算IaaS(基礎(chǔ)架構(gòu)即服務(wù))軟件。它...

    aikin 評(píng)論0 收藏0
  • ZStack源碼剖析:如何在百萬行代碼中快速迭代

    摘要:本文將對(duì)核心引擎的源碼進(jìn)行剖析。在筆者看來,能夠快速迭代的原因首先是來自于每位工程師的辛勤付出。在中,還有一類很有意思的代碼,一般稱之為。筆者有機(jī)會(huì)將會(huì)在之后的系列文章分析其中的典型案例以及在代碼中使用極其頻繁的核心工具。 本文首發(fā)于泊浮目的專欄:https://segmentfault.com/blog... 前言 ZStack是下一代開源的云計(jì)算IaaS(基礎(chǔ)架構(gòu)即服務(wù))軟件。它...

    stackvoid 評(píng)論0 收藏0
  • Java9模塊化學(xué)習(xí)筆記三之遷移到Java9

    摘要:命令行參數(shù)文件鑒于遷移到后可能需要很長(zhǎng)的命令行參數(shù),有些會(huì)限制命令行長(zhǎng)度,支持定義一個(gè)命令行參數(shù)文件。已有三分庫可以自動(dòng)轉(zhuǎn)成模塊,只要在啟動(dòng)時(shí)將放在指定路徑中,便會(huì)自動(dòng)變成。 java[c]命令行參數(shù)文件 鑒于遷移到j(luò)ava9后可能需要很長(zhǎng)的命令行參數(shù),有些os會(huì)限制命令行長(zhǎng)度,java9支持定義一個(gè)命令行參數(shù)文件。使用方式: java @arguments.txt arguments...

    NeverSayNever 評(píng)論0 收藏0
  • Java經(jīng)典

    摘要:請(qǐng)注意,我們?cè)诹牧膯卧獪y(cè)試遇到問題多思考多查閱多驗(yàn)證,方能有所得,再勤快點(diǎn)樂于分享,才能寫出好文章。單元測(cè)試是指對(duì)軟件中的最小可測(cè)試單元進(jìn)行檢查和驗(yàn)證。 JAVA容器-自問自答學(xué)HashMap 這次我和大家一起學(xué)習(xí)HashMap,HashMap我們?cè)诠ぷ髦薪?jīng)常會(huì)使用,而且面試中也很頻繁會(huì)問到,因?yàn)樗锩嫣N(yùn)含著很多知識(shí)點(diǎn),可以很好的考察個(gè)人基礎(chǔ)。但一個(gè)這么重要的東西,我為什么沒有在一開始...

    xcold 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<