Spring的一個(gè)核心功能是IOC,就是將Bean初始化加載到容器中供炼,Bean是如何加載到容器的一屋,可以使用Spring注解方式或者Spring XML配置方式。
Spring注解方式減少了配置文件內(nèi)容袋哼,更加便于管理冀墨,并且使用注解大大提高了開發(fā)效率!
下面按照分類講解Spring中常用的一些注解涛贯。
1.聲明bean的注解(將普通類加入容器形成Bean)
- @Component 組件诽嘉,沒有明確的角色
- @Service 在業(yè)務(wù)邏輯層使用(業(yè)務(wù)邏輯層)
- @Repository 在數(shù)據(jù)訪問層使用(數(shù)據(jù)訪問層)
- @Controller 在展現(xiàn)層使用,控制器的聲明(頁(yè)面訪問控制層)
這些都是注解在平時(shí)的開發(fā)過程中出鏡率極高弟翘,@Component虫腋、@Repository、@Service稀余、@Controller實(shí)質(zhì)上屬于同一類注解岔乔,用法相同,功能相同滚躯,區(qū)別在于標(biāo)識(shí)組件的類型雏门。@Component可以代替@Repository、@Service掸掏、@Controller茁影,因?yàn)檫@三個(gè)注解是被@Component標(biāo)注的。
如下@controller源碼:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
String value() default "";
}
1丧凤、被注解的java類當(dāng)做Bean實(shí)例募闲,Bean實(shí)例的名稱默認(rèn)是Bean類的首字母小寫,其他部分不變愿待。@Service也可以自定義Bean名稱浩螺,但是必須是唯一的!
2仍侥、盡量使用對(duì)應(yīng)組件注解的類替換@Component注解要出,在spring未來的版本中,@Controller农渊,@Service患蹂,@Repository會(huì)攜帶更多語(yǔ)義。并且便于開發(fā)和維護(hù)!
3传于、指定了某些類可作為Spring Bean類使用后囱挑,最好還需要讓spring搜索指定路徑,在Spring配置文件加入如下配置:
<!-- 自動(dòng)掃描指定包及其子包下的所有Bean類 -->
<context:component-scan base-package="org.springframework.*"/>
2.注入bean的注解(從容器中獲取Bean即裝配bean)
開發(fā)中最常用到的用于裝配的注解是:@Autowired和@Resource
-
@Autowired注解:
@Autowired源碼:
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD,
ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
@Autowired注解可用于為類的屬性沼溜、構(gòu)造器平挑、方法進(jìn)行注值。默認(rèn)情況下系草,其依賴的對(duì)象必須存在(bean可用)弹惦,如果需要改變這種默認(rèn)方式,可以設(shè)置其required屬性為false悄但。另外一個(gè)比較重要的點(diǎn)就是棠隐,@Autowired注解默認(rèn)按照類型裝配,如果容器中包含多個(gè)同一類型的Bean檐嚣,那么啟動(dòng)容器時(shí)會(huì)報(bào)找不到指定類型bean的異常助泽,解決辦法是結(jié)合@Qualified注解進(jìn)行限定,指定注入的bean名稱嚎京,例如:
public class MovieRecommender {
@Autowired
private MovieCatalog movieCatalog;
private CustomerPreferenceDao customerPreferenceDao;
@Autowired
public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
this.customerPreferenceDao = customerPreferenceDao;
}
}
@Controller
public class HappyController {
@Autowired //默認(rèn)依賴的ClubDao 對(duì)象(Bean)必須存在
//@Autowired(required = false) 改變默認(rèn)方式
@Qualifier("goodClubService")
private ClubService clubService;
// Control the people entering the Club
// do something
}
@Service(value="goodClubService")
//使用@Service注解不加value ,默認(rèn)名稱是clubService
public class ClubServiceImpl implements ClubService {
@Autowired
private ClubDao clubDao;
public void doHappy(){
//do some Happy
}
}
-
@Resource注解
@Resource源碼:
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
String name() default "";
Class type() default java.lang.Object.class;
對(duì)于@Resource注解嗡贺,它并不屬于spring的注解,而是來自于JSR-250鞍帝。其默認(rèn)情況下按照bean的名稱進(jìn)行注入诫睬,當(dāng)找不到匹配項(xiàng)時(shí)會(huì)按照類型裝配。當(dāng)按照名稱進(jìn)行裝配時(shí)帕涌,可以指定其name屬性摄凡,倘若沒有指定,注解標(biāo)注在哪個(gè)字段上蚓曼,其默認(rèn)名稱就是那個(gè)字段的名稱亲澡。當(dāng)然,@Resource注解也支持按指定類型進(jìn)行裝配纫版,給它的type屬性賦特定類型的值即可(注意床绪,當(dāng)指定了name屬性后,只能按照名稱裝配)
public class AnotationExp {
@Resource(name = "HappyClient")
private HappyClient happyClient;
@Resource(type = HappyPlayAno .class)
private HappyPlayAno happyPlayAno;
}
- 總結(jié)
相同點(diǎn):
@Resource的作用相當(dāng)于@Autowired其弊,均可標(biāo)注在字段或?qū)傩缘膕etter方法上癞己。
不同點(diǎn):
a:提供方 @Autowired是Spring的注解,@Resource是javax.annotation注解梭伐,而是來自于JSR-250痹雅,J2EE提供,需要JDK1.6及以上籽御。
b :注入方式 @Autowired只按照Type 注入练慕;@Resource默認(rèn)按Name自動(dòng)注入惰匙,也提供按照Type 注入技掏;
c:屬性
@Autowired注解可用于為類的屬性铃将、構(gòu)造器、方法進(jìn)行注值哑梳。默認(rèn)情況下劲阎,其依賴的對(duì)象必須存在(bean可用),如果需要改變這種默認(rèn)方式鸠真,可以設(shè)置其required屬性為false悯仙。
還有一個(gè)比較重要的點(diǎn)就是,@Autowired注解默認(rèn)按照類型裝配吠卷,如果容器中包含多個(gè)同一類型的Bean锡垄,那么啟動(dòng)容器時(shí)會(huì)報(bào)找不到指定類型bean的異常,解決辦法是結(jié)合@Qualifier注解進(jìn)行限定祭隔,指定注入的bean名稱货岭。
@Resource有兩個(gè)中重要的屬性:name和type。name屬性指定byName疾渴,如果沒有指定name屬性千贯,當(dāng)注解標(biāo)注在字段上,即默認(rèn)取字段的名稱作為bean名稱尋找依賴對(duì)象搞坝,當(dāng)注解標(biāo)注在屬性的setter方法上搔谴,即默認(rèn)取屬性名作為bean名稱尋找依賴對(duì)象。
需要注意的是桩撮,@Resource如果沒有指定name屬性敦第,并且按照默認(rèn)的名稱仍然找不到依賴對(duì)象時(shí), @Resource注解會(huì)回退到按類型裝配店量。但一旦指定了name屬性申尼,就只能按名稱裝配了。
d:@Resource注解的使用性更為靈活垫桂,可指定名稱师幕,也可以指定類型 ;@Autowired注解進(jìn)行裝配容易拋出異常诬滩,特別是裝配的bean類型有多個(gè)的時(shí)候霹粥,而解決的辦法是需要在增加@Qualifier進(jìn)行限定。
3. Java配置類相關(guān)注解
- @Configuration 聲明當(dāng)前類為配置類疼鸟,其中內(nèi)部組合了@Component注解后控,表明這個(gè)類是一個(gè)bean相當(dāng)于xml形式的Spring配置(類上)
Spring的官方團(tuán)隊(duì)說@Component可以替代 @Configuration注解,事實(shí)上我們看源碼也可以發(fā)現(xiàn)看到空镜,如下
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component //看這里:铺浴0破印!
public @interface Configuration {
String value() default "";
- @Bean 注解在方法上张抄,聲明當(dāng)前方法的返回值為一個(gè)bean砂蔽,替代xml中的方式(方法上)
- @ComponentScan 用于對(duì)Component進(jìn)行掃描,相當(dāng)于xml中的context:component-scan/(類上)
- @WishlyConfiguration 為@Configuration與@ComponentScan的組合注解署惯,可以替代這兩個(gè)注解
4.Spring @Configuration與@Component的區(qū)別
代碼如下:
@Configuration
public static class Config {
@Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
@Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean());
}
}
@Component
public static class Config {
@Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
@Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean());
}
}
第一段代碼可以正常運(yùn)行左驾,并且可以預(yù)期地從SimpleBeanConsumer
獲得指向singleton的鏈接SimpleBean
。但是不幸的是极谊,它在簽名環(huán)境中不起作用诡右。
第二個(gè)配置是完全錯(cuò)誤的,因?yàn)镾pring會(huì)創(chuàng)建一個(gè)SimpleBean的單例bean轻猖,但是SimpleBeanConsumer將獲得另一個(gè)SimpleBean實(shí)例(也就是相當(dāng)于直接調(diào)用new SimpleBean() 帆吻,這個(gè)bean是不歸Spring管理的),既new SimpleBean() 實(shí)例是Spring上下文控件之外的咙边。
這種現(xiàn)象的原因可以解釋如下:
如果使用@Configuration
猜煮,則所有標(biāo)記為的方法@Bean
都將被包裝到CGLIB包裝器中,該包裝器將像第一次調(diào)用此方法一樣工作样眠,然后將執(zhí)行原始方法的主體友瘤,并將結(jié)果對(duì)象注冊(cè)在spring上下文中。所有其他調(diào)用僅返回從上下文中檢索到的bean檐束。
在上面的第二個(gè)代碼塊中辫秧,new SimpleBeanConsumer(simpleBean())
僅調(diào)用一個(gè)純java方法。要更正第二個(gè)代碼塊被丧,我們可以執(zhí)行以下操作:
@Component
public static class Config {
@Autowired
SimpleBean simpleBean;
@Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
@Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean);
}
}
- 原因總結(jié)
使用@ configuration盟戏,所有標(biāo)記為@ bean的方法將被包裝成一個(gè)CGLIB包裝器,它的工作方式就好像是這個(gè)方法的第一個(gè)調(diào)用甥桂,那么原始方法的主體將被執(zhí)行柿究,最終的對(duì)象將在spring上下文中注冊(cè)。所有進(jìn)一步的調(diào)用只返回從上下文檢索的bean黄选。
Spring注解——使用@ComponentScan自動(dòng)掃描組件
5.切面(AOP)相關(guān)注解
Spring支持AspectJ的注解式切面編程蝇摸。
- @EnableAspectJAutoProxy 開啟基于注解的aop模式
- @Aspect 聲明一個(gè)切面(類上)
- @After 在方法執(zhí)行之后執(zhí)行(方法上)
- @Before 在方法執(zhí)行之前執(zhí)行(方法上)
- @Around 在方法執(zhí)行之前與之后執(zhí)行(方法上)
- @PointCut 聲明切點(diǎn)
- @EnableAspectJAutoProxy在java配置類中使用該注解開啟Spring對(duì)AspectJ代理的支持(類上)
6.@Bean的屬性支持
- @Scope 設(shè)置Spring容器如何新建Bean實(shí)例(方法上,必須有@Bean)
其設(shè)置類型包括:
Singleton (單例,一個(gè)Spring容器中只有一個(gè)bean實(shí)例办陷,默認(rèn)模式),
Protetype (每次調(diào)用新建一個(gè)bean),
Request (web項(xiàng)目中貌夕,給每個(gè)http request新建一個(gè)bean),
Session (web項(xiàng)目中,給每個(gè)http session新建一個(gè)bean),
GlobalSession(給每一個(gè) global http session新建一個(gè)Bean實(shí)例)
- @StepScope 在Spring Batch中還有涉及
- @Qualifier注解定義Bean名稱(方法上民镜,必須有@Bean)啡专。
當(dāng)你創(chuàng)建多個(gè)具有相同類型的 bean 時(shí),并且想要用一個(gè)屬性只為它們其中的一個(gè)進(jìn)行裝配制圈,在這種情況下们童,你可以使用 @Qualifier 注釋和 @Autowired 注釋通過指定哪一個(gè)真正的 bean 將會(huì)被裝配來消除混亂畔况。 - @PostConstruct 用來標(biāo)記是在項(xiàng)目啟動(dòng)的時(shí)候執(zhí)行這個(gè)方法。用來修飾一個(gè)非靜態(tài)的void()方法
也就是spring容器啟動(dòng)時(shí)就執(zhí)行慧库,多用于一些全局配置跷跪、數(shù)據(jù)字典之類的加載。
被@PostConstruct修飾的方法會(huì)在服務(wù)器加載Servlet的時(shí)候運(yùn)行完沪,并且只會(huì)被服務(wù)器執(zhí)行一次域庇。PostConstruct在構(gòu)造函數(shù)之后執(zhí)行,init()方法之前執(zhí)行嵌戈。PreDestroy()方法在destroy()方法執(zhí)行執(zhí)行之后執(zhí) - @PreDestory 被@PreDestroy修飾的方法會(huì)在服務(wù)器卸載Servlet的時(shí)候運(yùn)行覆积,并且只會(huì)被服務(wù)器調(diào)用一次,類似于Servlet的destroy()方法熟呛。被@PreDestroy修飾的方法會(huì)在destroy()方法之后運(yùn)行宽档,在Servlet被徹底卸載之前
7.@Value注解
@Value 為屬性注入值(屬性上)
示例:
注入普通字符:
@Value("Michael Jackson")
String name;
注入操作系統(tǒng)屬性:
@Value("#{systemProperties['os.name']}")
String osName;
注入表達(dá)式結(jié)果:
@Value("#{ T(java.lang.Math).random() * 100 }")
String randomNumber;
注入其它bean屬性:
@Value("#{domeClass.name}")
String name;
注入文件資源:
@Value("classpath:com/hgs/hello/test.txt")
String Resource file;
注入網(wǎng)站資源:
@Value("http://www.cznovel.com")
Resource url;
注入配置文件:
@Value("${book.name}")
String bookName;
注入配置使用方法:
① 編寫配置文件(test.properties)
book.name=《三體》
② @PropertySource 加載配置文件(類上)
@PropertySource("classpath:com/hgs/hello/test/test.propertie")
③ 還需配置一個(gè)PropertySourcesPlaceholderConfigurer的bean。