Spring注解Annotion詳解

概述

注釋配置相對于 XML 配置具有很多的優勢:

  • 它可以充分利用 Java 的反射機制獲取類結構信息,這些信息可以有效減少配置的工作。如使用 JPA 注釋配置 ORM 映射時,我們就不需要指定 PO 的屬性名、類型等信息,如果關系表字段和 PO 屬性名、類型都一致,您甚至無需編寫任務屬性映射信息——因為這些信息都可以通過 Java 反射機制獲取。
  • 注釋和 Java 代碼位于一個文件中,而 XML 配置采用獨立的配置文件,大多數配置信息在程序開發完成后都不會調整,如果配置信息和 Java 代碼放在一起,有助于增強程序的內聚性。而采用獨立的 XML 配置文件,程序員在編寫一個功能時,往往需要在程序文件和配置文件中不停切換,這種思維上的不連貫會降低開發效率。

因此在很多情況下,注釋配置比 XML 配置更受歡迎,注釋配置有進一步流行的趨勢。spring?2.5 的一大增強就是引入了很多注釋類,現在您已經可以使用注釋配置完成大部分 XML 配置的功能。在這篇文章里,我們將向您講述使用注釋進行 Bean 定義和依賴注入的內容。


原來我們是怎么做的

在使用注釋配置之前,先來回顧一下傳統上是如何配置 Bean 并完成 Bean 之間依賴關系的建立。下面是 3 個類,它們分別是 Office、Car 和 Boss,這 3 個類需要在 Spring 容器中配置為 Bean:

Office 僅有一個屬性:


清單 1. Office.java

                
package com.baobaotao;
public class Office {private String officeNo =”001”;//省略 get/setter@Overridepublic String toString() {return "officeNo:" + officeNo;}
}

?

Car 擁有兩個屬性:


清單 2. Car.java

                
package com.baobaotao;public class Car {private String brand;private double price;// 省略 get/setter@Overridepublic String toString() {return "brand:" + brand + "," + "price:" + price;}
}

?

Boss 擁有 Office 和 Car 類型的兩個屬性:


清單 3. Boss.java

                
package com.baobaotao;public class Boss {private Car car;private Office office;// 省略 get/setter@Overridepublic String toString() {return "car:" + car + "\n" + "office:" + office;}
}

?

我們在 Spring 容器中將 Office 和 Car 聲明為 Bean,并注入到 Boss Bean 中:下面是使用傳統 XML 完成這個工作的配置文件 beans.xml:


清單 4. beans.xml 將以上三個類配置成 Bean

                
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><bean id="boss" class="com.baobaotao.Boss"><property name="car" ref="car"/><property name="office" ref="office" /></bean><bean id="office" class="com.baobaotao.Office"><property name="officeNo" value="002"/></bean><bean id="car" class="com.baobaotao.Car" scope="singleton"><property name="brand" value=" 紅旗 CA72"/><property name="price" value="2000"/></bean>
</beans>

?

當我們運行以下代碼時,控制臺將正確打出 boss 的信息:


清單 5. 測試類:AnnoIoCTest.java

                
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnoIoCTest {public static void main(String[] args) {String[] locations = {"beans.xml"};ApplicationContext ctx = new ClassPathXmlApplicationContext(locations);Boss boss = (Boss) ctx.getBean("boss");System.out.println(boss);}
}

?

這說明 Spring 容器已經正確完成了 Bean 創建和裝配的工作。


使用 @Autowired 注釋

Spring 2.5 引入了?@Autowired?注釋,它可以對類成員變量、方法及構造函數進行標注,完成自動裝配的工作。來看一下使用@Autowired?進行成員變量自動注入的代碼:


清單 6. 使用 @Autowired 注釋的 Boss.java

                
package com.baobaotao;
import org.springframework.beans.factory.annotation.Autowired;public class Boss {@Autowiredprivate Car car;@Autowiredprivate Office office;…
}

?

Spring 通過一個?BeanPostProcessor?對?@Autowired?進行解析,所以要讓@Autowired?起作用必須事先在 Spring 容器中聲明AutowiredAnnotationBeanPostProcessor?Bean。


清單 7. 讓 @Autowired 注釋工作起來

                
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"><!-- 該 BeanPostProcessor 將自動起作用,對標注 @Autowired 的 Bean 進行自動注入 --><bean class="org.springframework.beans.factory.annotation.        AutowiredAnnotationBeanPostProcessor"/><!-- 移除 boss Bean 的屬性注入配置的信息 --><bean id="boss" class="com.baobaotao.Boss"/><bean id="office" class="com.baobaotao.Office"><property name="officeNo" value="001"/></bean><bean id="car" class="com.baobaotao.Car" scope="singleton"><property name="brand" value=" 紅旗 CA72"/><property name="price" value="2000"/></bean>
</beans>

?

這樣,當 Spring 容器啟動時,AutowiredAnnotationBeanPostProcessor?將掃描 Spring 容器中所有 Bean,當發現 Bean 中擁有@Autowired?注釋時就找到和其匹配(默認按類型匹配)的 Bean,并注入到對應的地方中去。

按照上面的配置,Spring 將直接采用?Java?反射機制對 Boss 中的?car?和?office?這兩個私有成員變量進行自動注入。所以對成員變量使用@Autowired?后,您大可將它們的 setter 方法(setCar()?和?setOffice())從 Boss 中刪除。

當然,您也可以通過?@Autowired?對方法或構造函數進行標注,來看下面的代碼:


清單 8. 將 @Autowired 注釋標注在 Setter 方法上

                
package com.baobaotao;public class Boss {private Car car;private Office office;@Autowiredpublic void setCar(Car car) {this.car = car;}@Autowiredpublic void setOffice(Office office) {this.office = office;}…
}

?

這時,@Autowired?將查找被標注的方法的入參類型的 Bean,并調用方法自動注入這些 Bean。而下面的使用方法則對構造函數進行標注:


清單 9. 將 @Autowired 注釋標注在構造函數上

                
package com.baobaotao;public class Boss {private Car car;private Office office;@Autowiredpublic Boss(Car car ,Office office){this.car = car;this.office = office ;}…
}

?

由于?Boss()?構造函數有兩個入參,分別是?car?和?office@Autowired?將分別尋找和它們類型匹配的 Bean,將它們作為Boss(Car car ,Office office)的入參來創建?Boss?Bean。


當候選 Bean 數目不為 1 時的應對方法

在默認情況下使用?@Autowired?注釋進行自動注入時,Spring 容器中匹配的候選 Bean 數目必須有且僅有一個。當找不到一個匹配的 Bean 時,Spring 容器將拋出BeanCreationException?異常,并指出必須至少擁有一個匹配的 Bean。我們可以來做一個實驗:


清單 10. 候選 Bean 數目為 0 時

                
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd "><bean class="org.springframework.beans.factory.annotation.        AutowiredAnnotationBeanPostProcessor"/> <bean id="boss" class="com.baobaotao.Boss"/><!-- 將 office Bean 注釋掉 --><!-- <bean id="office" class="com.baobaotao.Office"><property name="officeNo" value="001"/></bean>--><bean id="car" class="com.baobaotao.Car" scope="singleton"><property name="brand" value=" 紅旗 CA72"/><property name="price" value="2000"/></bean>
</beans>

?

由于?office?Bean 被注釋掉了,所以 Spring 容器中將沒有類型為?Office?的 Bean 了,而 Boss 的office?屬性標注了?@Autowired,當啟動 Spring 容器時,異常就產生了。

當不能確定 Spring 容器中一定擁有某個類的 Bean 時,可以在需要自動注入該類 Bean 的地方可以使用?@Autowired(required = false),這等于告訴 Spring:在找不到匹配 Bean 時也不報錯。來看一下具體的例子:


清單 11. 使用 @Autowired(required = false)

                
package com.baobaotao;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;public class Boss {private Car car;private Office office;@Autowiredpublic void setCar(Car car) {this.car = car;}@Autowired(required = false)public void setOffice(Office office) {this.office = office;}…
}

?

當然,一般情況下,使用?@Autowired?的地方都是需要注入 Bean 的,使用了自動注入而又允許不注入的情況一般僅會在開發期或測試期碰到(如為了快速啟動 Spring 容器,僅引入一些模塊的 Spring 配置文件),所以@Autowired(required = false)?會很少用到。

和找不到一個類型匹配 Bean 相反的一個錯誤是:如果 Spring 容器中擁有多個候選 Bean,Spring 容器在啟動時也會拋出?BeanCreationException?異常。來看下面的例子:


清單 12. 在 beans.xml 中配置兩個 Office 類型的 Bean

                
… 
<bean id="office" class="com.baobaotao.Office"><property name="officeNo" value="001"/>
</bean>
<bean id="office2" class="com.baobaotao.Office"><property name="officeNo" value="001"/>
</bean>
…

?

我們在 Spring 容器中配置了兩個類型為?Office?類型的 Bean,當對 Boss 的?office?成員變量進行自動注入時,Spring 容器將無法確定到底要用哪一個 Bean,因此異常發生了。

Spring 允許我們通過?@Qualifier?注釋指定注入 Bean 的名稱,這樣歧義就消除了,可以通過下面的方法解決異常:


清單 13. 使用 @Qualifier 注釋指定注入 Bean 的名稱

                
@Autowired
public void setOffice(@Qualifier("office")Office office) {this.office = office;
}

?

@Qualifier("office")?中的?office?是 Bean 的名稱,所以?@Autowired?和@Qualifier?結合使用時,自動注入的策略就從 byType 轉變成 byName 了。@Autowired?可以對成員變量、方法以及構造函數進行注釋,而@Qualifier?的標注對象是成員變量、方法入參、構造函數入參。正是由于注釋對象的不同,所以 Spring 不將?@Autowired?和@Qualifier?統一成一個注釋類。下面是對成員變量和構造函數入參進行注釋的代碼:

對成員變量進行注釋:


清單 14. 對成員變量使用 @Qualifier 注釋

                
public class Boss {@Autowiredprivate Car car;@Autowired@Qualifier("office")private Office office;…
}

?

對構造函數入參進行注釋:


清單 15. 對構造函數變量使用 @Qualifier 注釋

                
public class Boss {private Car car;private Office office;@Autowiredpublic Boss(Car car , @Qualifier("office")Office office){this.car = car;this.office = office ;}
}

?

@Qualifier?只能和?@Autowired?結合使用,是對?@Autowired?有益的補充。一般來講,@Qualifier?對方法簽名中入參進行注釋會降低代碼的可讀性,而對成員變量注釋則相對好一些。


使用 JSR-250 的注釋

Spring 不但支持自己定義的?@Autowired?的注釋,還支持幾個由 JSR-250 規范定義的注釋,它們分別是?@Resource@PostConstruct?以及?@PreDestroy

@Resource

@Resource?的作用相當于?@Autowired,只不過?@Autowired?按 byType 自動注入,面@Resource?默認按 byName 自動注入罷了。@Resource?有兩個屬性是比較重要的,分別是 name 和 type,Spring 將@Resource?注釋的 name 屬性解析為 Bean 的名字,而 type 屬性則解析為 Bean 的類型。所以如果使用 name 屬性,則使用 byName 的自動注入策略,而使用 type 屬性時則使用 byType 自動注入策略。如果既不指定 name 也不指定 type 屬性,這時將通過反射機制使用 byName 自動注入策略。

Resource 注釋類位于 Spring 發布包的 lib/j2ee/common-annotations.jar 類包中,因此在使用之前必須將其加入到項目的類庫中。來看一個使用@Resource的例子:


清單 16. 使用 @Resource 注釋的 Boss.java

                
package com.baobaotao;import javax.annotation.Resource;public class Boss {// 自動注入類型為 Car 的 Bean@Resourceprivate Car car;// 自動注入 bean 名稱為 office 的 Bean@Resource(name = "office")private Office office;
}

?

一般情況下,我們無需使用類似于?@Resource(type=Car.class)?的注釋方式,因為 Bean 的類型信息可以通過 Java 反射從代碼中獲取。

要讓 JSR-250 的注釋生效,除了在 Bean 類中標注這些注釋外,還需要在 Spring 容器中注冊一個負責處理這些注釋的?BeanPostProcessor

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>

?

CommonAnnotationBeanPostProcessor?實現了?BeanPostProcessor?接口,它負責掃描使用了 JSR-250 注釋的 Bean,并對它們進行相應的操作。

@PostConstruct 和 @PreDestroy

Spring 容器中的 Bean 是有生命周期的,Spring 允許在 Bean 在初始化完成后以及 Bean 銷毀前執行特定的操作,您既可以通過實現 InitializingBean/DisposableBean 接口來定制初始化之后 / 銷毀之前的操作方法,也可以通過 <bean> 元素的 init-method/destroy-method 屬性指定初始化之后 / 銷毀之前調用的操作方法。關于 Spring 的生命周期,筆者在《精通 Spring 2.x—企業應用開發精解》第 3 章進行了詳細的描述,有興趣的讀者可以查閱。

JSR-250 為初始化之后/銷毀之前方法的指定定義了兩個注釋類,分別是 @PostConstruct 和 @PreDestroy,這兩個注釋只能應用于方法上。標注了 @PostConstruct 注釋的方法將在類實例化后調用,而標注了 @PreDestroy 的方法將在類銷毀之前調用。


清單 17. 使用 @PostConstruct 和 @PreDestroy 注釋的 Boss.java

                
package com.baobaotao;import javax.annotation.Resource;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;public class Boss {@Resourceprivate Car car;@Resource(name = "office")private Office office;@PostConstructpublic void postConstruct1(){System.out.println("postConstruct1");}@PreDestroypublic void preDestroy1(){System.out.println("preDestroy1"); }…
}

?

您只需要在方法前標注?@PostConstruct?或?@PreDestroy,這些方法就會在 Bean 初始化后或銷毀之前被 Spring 容器執行了。

我們知道,不管是通過實現?InitializingBean/DisposableBean?接口,還是通過 <bean> 元素的init-method/destroy-method?屬性進行配置,都只能為 Bean 指定一個初始化 / 銷毀的方法。但是使用?@PostConstruct?和?@PreDestroy?注釋卻可以指定多個初始化 / 銷毀方法,那些被標注?@PostConstruct?或@PreDestroy?注釋的方法都會在初始化 / 銷毀時被執行。

通過以下的測試代碼,您將可以看到 Bean 的初始化 / 銷毀方法是如何被執行的:


清單 18. 測試類代碼

                
package com.baobaotao;import org.springframework.context.support.ClassPathXmlApplicationContext;public class AnnoIoCTest {public static void main(String[] args) {String[] locations = {"beans.xml"};ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(locations);Boss boss = (Boss) ctx.getBean("boss");System.out.println(boss);ctx.destroy();// 關閉 Spring 容器,以觸發 Bean 銷毀方法的執行}
}

?

這時,您將看到標注了?@PostConstruct?的?postConstruct1()?方法將在 Spring 容器啟動時,創建Boss?Bean 的時候被觸發執行,而標注了?@PreDestroy注釋的?preDestroy1()?方法將在 Spring 容器關閉前銷毀Boss?Bean 的時候被觸發執行。


使用 <context:annotation-config/> 簡化配置

Spring 2.1 添加了一個新的 context 的 Schema 命名空間,該命名空間對注釋驅動、屬性文件引入、加載期織入等功能提供了便捷的配置。我們知道注釋本身是不會做任何事情的,它僅提供元數據信息。要使元數據信息真正起作用,必須讓負責處理這些元數據的處理器工作起來。

而我們前面所介紹的?AutowiredAnnotationBeanPostProcessor?和?CommonAnnotationBeanPostProcessor?就是處理這些注釋元數據的處理器。但是直接在 Spring 配置文件中定義這些 Bean 顯得比較笨拙。Spring 為我們提供了一種方便的注冊這些BeanPostProcessor?的方式,這就是 <context:annotation-config/>。請看下面的配置:


清單 19. 調整 beans.xml 配置文件

                
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"><context:annotation-config/> <bean id="boss" class="com.baobaotao.Boss"/><bean id="office" class="com.baobaotao.Office"><property name="officeNo" value="001"/></bean><bean id="car" class="com.baobaotao.Car" scope="singleton"><property name="brand" value=" 紅旗 CA72"/><property name="price" value="2000"/></bean>
</beans>

?

<context:annotationconfig/> 將隱式地向 Spring 容器注冊AutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessorPersistenceAnnotationBeanPostProcessor?以及equiredAnnotationBeanPostProcessor?這 4 個 BeanPostProcessor。

在配置文件中使用 context 命名空間之前,必須在 <beans> 元素中聲明 context 命名空間。


使用 @Component

雖然我們可以通過?@Autowired?或?@Resource?在 Bean 類中使用自動注入功能,但是 Bean 還是在 XML 文件中通過 <bean> 進行定義 —— 也就是說,在 XML 配置文件中定義 Bean,通過@Autowired?或?@Resource?為 Bean 的成員變量、方法入參或構造函數入參提供自動注入的功能。能否也通過注釋定義 Bean,從 XML 配置文件中完全移除 Bean 定義的配置呢?答案是肯定的,我們通過 Spring 2.5 提供的@Component?注釋就可以達到這個目標了。

為什么 @Repository 只能標注在 DAO 類上呢?這是因為該注解的作用不只是將類識別為 Bean,同時它還能將所標注的類中拋出的數據訪問異常封裝為 Spring 的數據訪問異常類型。 Spring 本身提供了一個豐富的并且是與具體的數據訪問技術無關的數據訪問異常結構,用于封裝不同的持久層框架拋出的異常,使得異常獨立于底層的框架。

Spring 2.5 在 @Repository 的基礎上增加了功能類似的額外三個注解:@Component、@Service、@Constroller,它們分別用于軟件系統的不同層次:

  • @Component 是一個泛化的概念,僅僅表示一個組件 (Bean) ,可以作用在任何層次。
  • @Service 通常作用在業務層,但是目前該功能與 @Component 相同。
  • @Constroller 通常作用在控制層,但是目前該功能與 @Component 相同。

通過在類上使用 @Repository、@Component、@Service 和 @Constroller 注解,Spring 會自動創建相應的 BeanDefinition 對象,并注冊到 ApplicationContext 中。這些類就成了 Spring 受管組件。這三個注解除了作用于不同軟件層次的類,其使用方式與 @Repository 是完全相同的。

?

?

下面,我們完全使用注釋定義 Bean 并完成 Bean 之間裝配:


清單 20. 使用 @Component 注釋的 Car.java

                
package com.baobaotao;import org.springframework.stereotype.Component;@Component
public class Car {…
}

?

僅需要在類定義處,使用?@Component?注釋就可以將一個類定義了 Spring 容器中的 Bean。下面的代碼將?Office?定義為一個 Bean:


清單 21. 使用 @Component 注釋的 Office.java

                
package com.baobaotao;import org.springframework.stereotype.Component;@Component
public class Office {private String officeNo = "001";…
}

?

這樣,我們就可以在 Boss 類中通過?@Autowired?注入前面定義的?Car?和?Office Bean?了。


清單 22. 使用 @Component 注釋的 Boss.java

                
package com.baobaotao;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;@Component("boss")
public class Boss {@Autowiredprivate Car car;@Autowiredprivate Office office;…
}

?

@Component?有一個可選的入參,用于指定 Bean 的名稱,在 Boss 中,我們就將 Bean 名稱定義為“boss”。一般情況下,Bean 都是 singleton 的,需要注入 Bean 的地方僅需要通過 byType 策略就可以自動注入了,所以大可不必指定 Bean 的名稱。

在使用?@Component?注釋后,Spring 容器必須啟用類掃描機制以啟用注釋驅動 Bean 定義和注釋驅動 Bean 自動注入的策略。Spring 2.5 對 context 命名空間進行了擴展,提供了這一功能,請看下面的配置:


清單 23. 簡化版的 beans.xml

                
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"><context:component-scan base-package="com.baobaotao"/>
</beans>

?

這里,所有通過 <bean> 元素定義 Bean 的配置內容已經被移除,僅需要添加一行 <context:component-scan/> 配置就解決所有問題了——Spring XML 配置文件得到了極致的簡化(當然配置元數據還是需要的,只不過以注釋形式存在罷了)。<context:component-scan/> 的 base-package 屬性指定了需要掃描的類包,類包及其遞歸子包中所有的類都會被處理。

<context:component-scan/> 還允許定義過濾器將基包下的某些類納入或排除。Spring 支持以下 4 種類型的過濾方式,通過下表說明:


表 1. 掃描過濾方式

過濾器類型說明
注釋假如 com.baobaotao.SomeAnnotation 是一個注釋類,我們可以將使用該注釋的類過濾出來。
類名指定通過全限定類名進行過濾,如您可以指定將 com.baobaotao.Boss 納入掃描,而將 com.baobaotao.Car 排除在外。
正則表達式通過正則表達式定義過濾的類,如下所示: com\.baobaotao\.Default.*
AspectJ 表達式通過 AspectJ 表達式定義過濾的類,如下所示: com. baobaotao..*Service+

下面是一個簡單的例子:

<context:component-scan base-package="com.baobaotao"><context:include-filter type="regex" expression="com\.baobaotao\.service\..*"/><context:exclude-filter type="aspectj" expression="com.baobaotao.util..*"/>
</context:component-scan>

?

值得注意的是 <context:component-scan/> 配置項不但啟用了對類包進行掃描以實施注釋驅動 Bean 定義的功能,同時還啟用了注釋驅動自動注入的功能(即還隱式地在內部注冊了AutowiredAnnotationBeanPostProcessor?和?CommonAnnotationBeanPostProcessor),因此當使用 <context:component-scan/> 后,就可以將 <context:annotation-config/> 移除了。

默認情況下通過?@Component?定義的 Bean 都是 singleton 的,如果需要使用其它作用范圍的 Bean,可以通過@Scope?注釋來達到目標,如以下代碼所示:

@scopee


清單 24. 通過 @Scope 指定 Bean 的作用范圍

                
package com.baobaotao;
import org.springframework.context.annotation.Scope;
…
@Scope("prototype")
@Component("boss")
public class Boss {…
}

?

這樣,當從 Spring 容器中獲取?boss?Bean 時,每次返回的都是新的實例了。


采用具有特殊語義的注釋

Spring 2.5 中除了提供?@Component?注釋外,還定義了幾個擁有特殊語義的注釋,它們分別是:@Repository@Service?和@Controller。在目前的 Spring 版本中,這 3 個注釋和?@Component?是等效的,但是從注釋類的命名上,很容易看出這 3 個注釋分別和持久層、業務層和控制層(Web 層)相對應。雖然目前這 3 個注釋和@Component?相比沒有什么新意,但 Spring 將在以后的版本中為它們添加特殊的功能。所以,如果 Web 應用程序采用了經典的三層分層結構的話,最好在持久層、業務層和控制層分別采用@Repository@Service?和?@Controller?對分層中的類進行注釋,而用@Component?對那些比較中立的類進行注釋。


注釋配置和 XML 配置的適用場合

是否有了這些 IOC 注釋,我們就可以完全摒除原來 XML 配置的方式呢?答案是否定的。有以下幾點原因:

  • 注釋配置不一定在先天上優于 XML 配置。如果 Bean 的依賴關系是固定的,(如 Service 使用了哪幾個 DAO 類),這種配置信息不會在部署時發生調整,那么注釋配置優于 XML 配置;反之如果這種依賴關系會在部署時發生調整,XML 配置顯然又優于注釋配置,因為注釋是對 Java 源代碼的調整,您需要重新改寫源代碼并重新編譯才可以實施調整。
  • 如果 Bean 不是自己編寫的類(如?JdbcTemplateSessionFactoryBean?等),注釋配置將無法實施,此時 XML 配置是唯一可用的方式。
  • 注釋配置往往是類級別的,而 XML 配置則可以表現得更加靈活。比如相比于?@Transaction?事務注釋,使用 aop/tx 命名空間的事務配置更加靈活和簡單。

所以在實現應用中,我們往往需要同時使用注釋配置和 XML 配置,對于類級別且不會發生變動的配置可以優先考慮注釋配置;而對于那些第三方類以及容易發生調整的配置則應優先考慮使用 XML 配置。Spring 會在具體實施 Bean 創建和 Bean 注入之前將這兩種配置方式的元信息融合在一起。

?

轉載于:https://www.cnblogs.com/shiddong/p/5576950.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372822.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372822.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372822.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

CopyOnWrite容器

1.簡介 1.CopyOnWrite是程序優化的策略,當共享的內容需要修改時,復制出去一份進行修改,然后將原來的引用指向修改完的 2.java并發包(java.util.concurrent)中CopyOnWriteArrayList和CopyOnWriteArraySet實現了這個并發容器 3.好處:因為寫時是在復制的一份上操作,所以可以并發的…

Akka的字數統計MapReduce

在我與Akka的日常工作中&#xff0c;我最近寫了一個字數映射表簡化示例。 本示例實現了Map Reduce模型&#xff0c;該模型非常適合橫向擴展設計方法。 流 客戶端系統&#xff08;FileReadActor&#xff09;讀取文本文件&#xff0c;并將每一行文本作為消息發送給ClientActor。…

mysql如何設置多節點_詳細介紹Mysql5.7從節點設置多線程主從復制的辦法

軟件安裝&#xff1a;裝機軟件必備包SQL是Structured Query Language(結構化查詢語言)的縮寫。SQL是專為數據庫而建立的操作命令集&#xff0c;是一種功能齊全的數據庫語言。在使用它時&#xff0c;只需要發出“做什么”的命令&#xff0c;“怎么做”是不用使用者考慮的。SQL功…

python學習筆記 可變參數關鍵字參數**kw相關學習

在Python中可以定義可變參數&#xff0c;顧名思義&#xff0c;可變參數就是傳入參數是可變的。可以是任意個&#xff0c;以一個簡單的數學編程為例&#xff0c;計算 sum a * a b * b .....z * z 函數定義可以如下&#xff1a; def getsum(num) :sum 0for n in num :sum su…

Struts2之環境配置

在學習struts2之前&#xff0c;首先我們要明白使用struts2的目的是什么&#xff1f;它能給我們帶來什么樣的好處&#xff1f; 設計目標 Struts設計的第一目標就是使MVC模式應用于web程序設計。在這兒MVC模式的好處就不在提了。 技術優勢 Struts2有兩方面的技術優勢&#xff0c;…

mysql數據庫備份shell_mysql數據庫備份shell腳本分享

#!/bin/bash#2020年04月27日15:56:21#auto backup mysql db#by author www.cnbugs.com########################SQL_DB"$*"SQL_USR"backup"SQL_PWD"123456"SQL_CMD"/usr/bin/mysqldump"SQL_DIR"/data/backup/date %F"if [ $…

懶惰的JSF Primefaces數據表分頁–第1部分

今天&#xff0c;我們將使用帶有視圖范圍的托管bean的惰性列表進行JSF數據表分頁。 這些單詞/表達式是什么意思&#xff1f; 如今&#xff0c;有幾個JSF框架為數據表提供現成的分頁&#xff0c;列排序器和其他功能。 今天&#xff0c;我們將使用Primefaces數據表。 通常&#…

java 動態增加定時任務

直接上代碼 import org.apache.tools.ant.util.DateUtils; import org.quartz.CronTrigger; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerFactory; import org.quartz.impl.StdSchedulerFactory;import java.util.Calendar; import…

基于JavaFX的SimpleDateFormat演示程序

對于使用Java Date進行格式化的新手甚至對于使用Java Date進行格式化的有經驗的Java開發人員而言&#xff0c;可能有些棘手的事情是使用SimpleDateFormat規范日期/時間格式。 SimpleDateFormat的基于類級別的Javadoc的文檔非常詳盡&#xff0c;涵蓋了表示日期/時間的各個組成部…

mysql中預定義常量_PHP預定義常量

這些常量在 PHP 的內核中定義。它包含 PHP、Zend 引擎和 SAPI 模塊。PHP_VERSION (string)PHP_OS (string)PHP_EOL (string)自 PHP 4.3.10 和 PHP 5.0.2 起可用PHP_INT_MAX (integer)自 PHP 4.4.0 和 PHP 5.0.5 起可用PHP_INT_SIZE (integer)自 PHP 4.4.0 和 PHP 5.0.5 起可用D…

iOS與H5交互

前提&#xff1a;在iOS控制器中加載UIWebView&#xff0c;設置代理&#xff0c;遵守UIWebViewDelegate協議。 一、iOS調用JS方法 通過iOS調用JS代碼實現起來比較方便直接調用UIWebView的方法- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script…

cocos2dx 3.x 蒙板 遮罩 點擊圓功能

//注冊觸摸EventListenerTouchOneByOne *listener EventListenerTouchOneByOne::create();listener->onTouchBegan CC_CALLBACK_2(HelloWorld::onTouchBegan,this);listener->onTouchMoved CC_CALLBACK_2(HelloWorld::onTouchMoved,this);listener->onTouchEnded …

markdownTest

MARKDOWNTEST 11111111111111有一種神奇的語言&#xff0c;它比html還簡單&#xff0c;它巧妙地將內容與格式整合在一起——它就是Markdown有一種神奇的語言&#xff0c;它比html還簡單&#xff0c;它巧妙地將內容與格式整合在一起——它就是Markdown 111111111111111222222222…

python模擬密碼有效性檢測功能_檢查密碼有效性(Django/Python)

我有一個非常小的Django應用程序&#xff0c;主要是為了學習。我使用的是Django提供的內置用戶模型。為了學習這個功能&#xff0c;我創建了一些頁面&#xff0c;這些頁面允許我創建和編輯用戶&#xff0c;而不必進入管理面板。在register頁面允許我非常容易地檢查密碼和電子郵…

教程:Hibernate,JPA –第1部分

這是關于使用Hibernate和JPA的教程的第一部分。 這部分是對JPA和Hibernate的介紹。 第二部分將研究使用Spring ORM組合Spring MVC應用程序以減少創建CRUD應用程序所需的代碼量。 為此&#xff0c;您需要熟悉Maven&#xff0c;JUnit&#xff0c;SQL和關系數據庫。 依存關系 首…

TCP、UDP套接字的數據傳輸

tcp發送數據&#xff1a; 1 #include <sys/types.h> 2 #include <socket.h> 3 ssize_t send(int sockfd,const void *msg,size_t len,int flags); 函數send只能對面向連接的套接字使用。參數sockfd為已經建立好連接的套接字描述符。參數msg指向待發送數據的緩沖區&…

Windows下用PIP安裝scipy出現no lapack/blas resources found

Windows下升級了pandas&#xff0c;但是發現scipy包隨后引用出錯&#xff0c;后來確認需重新安裝scipy&#xff0c; 在用PIP安裝scipy出現no lapack/blas resources found的錯誤&#xff0c;具體原因可參考 這里。 后來找到一種簡便的解決方案&#xff0c;只要在網站 Unofficia…

Aleri –復雜事件處理

Sybase的Aleri流媒體平臺是CEP市場中最受歡迎的產品之一。 它在Sybase的交易平臺RAP版本中使用&#xff0c;該版本在資本市場中廣泛用于管理投資組合中的頭寸。 今天&#xff0c;在這個由多個部分組成的系列文章的第一個部分中&#xff0c;我希望提供Aleri平臺的概述&#xff0…

python版本回退_Python爬蟲之BeautifulSoup解析之路

上一篇分享了正則表達式的使用&#xff0c;相信大家對正則也已經有了一定的了解。它可以針對任意字符串做任何的匹配并提取所需信息。但是我們爬蟲基本上解析的都是html或者xml結構的內容&#xff0c;而非任意字符串。正則表達式雖然很強大靈活&#xff0c;但是對于html這樣結構…

0615 團隊第二階段貢獻

0615 團隊第二階段貢獻 列志華http://www.cnblogs.com/liezhihua/ 26% 組長 黃柏堂 http://www.cnblogs.com/huang123/ 22% 團隊 韓麒麟 http://www.cnblogs.com/hanqilin/ 26% 團隊 王俊杰 http://www.cnblogs.com/wangjunjie123/ 28%團隊posted on 2016…