淺談Spring框架注解的用法分析

寫(xiě)在前面:

眾所周知荐类,在JavaEE開(kāi)發(fā)框架中肃叶,Spring框架是用的最多的,注解在框架的定位也就越來(lái)越明顯了十嘿。說(shuō)句玩笑話(huà):能用一個(gè)注解解決的因惭,絕不用一堆配置和代碼解決;如果不能解決绩衷,那么來(lái)兩個(gè)注解蹦魔;(穩(wěn)住,別噴...)

配圖.jpg

1.@Component是Spring定義的一個(gè)通用注解咳燕,可以注解任何bean勿决。

2.@Scope定義bean的作用域,其默認(rèn)作用域是"singleton"招盲,除此之外還有prototype低缩,request,session和global session曹货。


案例:@Component和@Scope用法分析:

BeanAnnotation類(lèi):

@Scope
@Component
public class BeanAnnotation {

    public void say(String arg) {
        System.out.println("BeanAnnotation : " + arg);
    }
    
    public void myHashCode() {
        System.out.println("BeanAnnotation : " + this.hashCode());
    }

}

junit4測(cè)試類(lèi)→TestBeanAnnotation類(lèi):

@RunWith(BlockJUnit4ClassRunner.class)
public class TestBeanAnnotation extends UnitTestBase {

    public TestBeanAnnotation() {
        super("classpath*:spring-beanannotation.xml");
    }

    @Test
    public void testSay() {
        BeanAnnotation bean = super.getBean("beanAnnotation");
        bean.say("This is test.");
    }

    @Test
    public void testScpoe() {
        BeanAnnotation bean = super.getBean("beanAnnotation");
        bean.myHashCode();
        bean = super.getBean("beanAnnotation");
        bean.myHashCode();
    }

}

Spring配置文件→spring-beanannotation.xml:

<context:component-scan base-package="com.beanannotation"></context:component-scan>

我們先從Spring配置文件分析咆繁,base-package="com.beanannotation"說(shuō)明我們只處理這個(gè)包名下面的注解。

然后分析BeanAnnotation類(lèi)顶籽,有一個(gè)say的方法玩般。假設(shè)我們不清楚這是一個(gè)什么類(lèi)型(注:Service或者DAO)的類(lèi),我們可以用一個(gè)通用的注解@Component礼饱。

最后分析TestBeanAnnotation類(lèi)坏为,testSay方法里super.getBean("beanAnnotation")是從IOC的容器中取到這個(gè)bean,并調(diào)用bean的say方法镊绪。

提出問(wèn)題的時(shí)間到了匀伏,當(dāng)我們super.getBean的時(shí)候是通過(guò)bean的id從IOC容器中獲取的,那么這個(gè)id是什么呢镰吆?因?yàn)樵谖覀兲砑覢Component到BeanAnnotation類(lèi)上的時(shí)候帘撰,默認(rèn)的id為beanAnnotation。如果指定了@Component的名稱(chēng)万皿,譬如指定為@Component(”bean”)的時(shí)候摧找,在單元測(cè)試的時(shí)候就必須把super.getBean得到的id與之相對(duì)應(yīng)才能測(cè)試成功核行。

在這里我把@Scope注解單獨(dú)分離出來(lái)分析,在TestBeanAnnotation類(lèi)里面有一個(gè)testScpoe方法蹬耘。在BeanAnnotation類(lèi)里面有一個(gè)myHashCode方法芝雪,可能大家有些疑惑,為什么要用this.hashCode()综苔?因?yàn)锧Scope指定的是bean的作用域惩系,為了保證測(cè)試類(lèi)的結(jié)果準(zhǔn)確明了,所以采用哈希碼值來(lái)判斷是否為同一個(gè)對(duì)象如筛。


3.@Repository堡牡、@Service、@Controller是更具有針對(duì)性的注解杨刨。
PS:這里我們需要明白這三個(gè)注解是基于@Component定義的注解哦:
①晤柄、@Repository通常用于注解DAO類(lèi),也就是我們常說(shuō)的持久層妖胀。
②芥颈、@Service通常用于注解Service類(lèi),也就是服務(wù)層赚抡。
③爬坑、@Controller通常用于Controller類(lèi),也就是控制層(MVC)涂臣。

4.@Autowired理解為“傳統(tǒng)”的setter方法盾计,可以用在setter方法上,也可以用在構(gòu)造器或者成員變量肉康,能夠進(jìn)行Spring Bean的自動(dòng)裝配闯估。


案例:@Autowired用法分析一:

Spring配置文件→spring-beanannotation.xml:

<context:component-scan base-package="com.beanannotation"></context:component-scan>

SimpleMovieLister類(lèi):

public class SimpleMovieLister {

    private MovieFinder movieFinder;
    
    @Autowired(required=false)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

}

在默認(rèn)的情況下,如果找不到合適的bean將會(huì)導(dǎo)致autowiring失敗拋出異常吼和,我們可以將@Autowired注解在這個(gè)set方法上涨薪,標(biāo)記required=false來(lái)避免。但是炫乓,這不是一個(gè)必須的刚夺,如果找不到movieFinder的實(shí)例,是不會(huì)拋出異常的末捣,只有在使用的時(shí)候發(fā)現(xiàn)movieFinder為null侠姑,在這種情況下,就要求我們?cè)谑褂玫臅r(shí)候箩做,首先判斷movieFinder是不是為null莽红,如果是就會(huì)報(bào)空指針異常 。

值得注意的是,我們知道每個(gè)類(lèi)可以有很多個(gè)構(gòu)造器安吁,但是在使用@Autowired的時(shí)候醉蚁,有且只能有一個(gè)構(gòu)造器能夠被標(biāo)記為required=true(注:required的默認(rèn)值為false)。


案例:@Autowired用法分析二:

BeanImplOne類(lèi):

@Order
@Component
public class BeanImplOne implements BeanInterface {

}

BeanImplTwo類(lèi):

@Order
@Component
public class BeanImplTwo implements BeanInterface {

}

BeanInterface類(lèi):

public interface BeanInterface {

}

BeanInvoker類(lèi):

@Component
public class BeanInvoker {
    
    @Autowired
    private List<BeanInterface> list;
    
    @Autowired
    private Map<String, BeanInterface> map;
    
    public void say() {
        if (null != list && 0 != list.size()) {
            for (BeanInterface bean : list) {
                System.out.println(bean.getClass().getName());
            }
        } else {
            System.out.println(" list is null !");
        }
        
        if (null != map && 0 != map.size()) {
            for (Map.Entry<String, BeanInterface> entry : map.entrySet()) {
                System.out.println(entry.getKey() + "      " + entry.getValue().getClass().getName());
            }
        } else {
            System.out.println("map is null !");
        }
    }
}

測(cè)試類(lèi)TestInjection:

@RunWith(BlockJUnit4ClassRunner.class)
public class TestInjection extends UnitTestBase {
    
    public TestInjection() {
        super("classpath:spring-beanannotation.xml");
    }
    
    @Test
    public void testMultiBean() {
        BeanInvoker invoker = super.getBean("beanInvoker");
        invoker.say();
    }
    
}

首先鬼店,我們清楚BeanImplOne類(lèi)和BeanImplTwo類(lèi)是實(shí)現(xiàn)了BeanInterface接口的网棍,在BeanInvoker類(lèi)里面我們定義了list和map,我們通過(guò)@Autowired注解把BeanImplOne類(lèi)和BeanImplTwo類(lèi)注解進(jìn)入其中妇智。那么怎么證實(shí)是@Autowired注解把這兩個(gè)類(lèi)注入到list或者map中的呢滥玷?那么請(qǐng)看if循環(huán)語(yǔ)句和foreach循環(huán)打印,通過(guò)這個(gè)邏輯判斷巍棱,如果能夠打印出BeanImplOne類(lèi)和BeanImplTwo類(lèi)的路徑名惑畴,就說(shuō)明這樣是可以的。如果有些小伙伴可能不信航徙,那么可以試著不使用@Autowired注解桨菜,看結(jié)果怎么樣。

測(cè)試類(lèi)沒(méi)有什么好說(shuō)的捉偏,各位小伙伴有沒(méi)有注意到@Order注解呢?這里需要解釋的就是泻红,如果在@Order注解里面輸入執(zhí)行的數(shù)字夭禽,比如1或者2,那么打印出來(lái)的路徑名就會(huì)按順序谊路,也就是說(shuō)通過(guò)指定@Order注解的內(nèi)容可以實(shí)現(xiàn)優(yōu)先級(jí)的功能讹躯。


5.@ImportResource注解引入一個(gè)資源,對(duì)應(yīng)一個(gè)xml文件
6.@Value注解從資源文件中缠劝,取出它的key并賦值給當(dāng)前類(lèi)的成員變量


案例:@ImportResource和@Value用法分析:

MyDriverManager類(lèi):

public class MyDriverManager {
    
    public MyDriverManager(String url, String userName, String password) {
        System.out.println("url : " + url);
        System.out.println("userName: " + userName);
        System.out.println("password: " + password);
    }

}

config.xml:

<context:property-placeholder location="classpath:/config.properties"/>

StoreConfig類(lèi):

@Configuration
@ImportResource("classpath:config.xml")
public class StoreConfig {
    
    @Value("${jdbc.url}")
    private String url;
    
    @Value("${jdbc.username}")
    private String username;
    
    @Value("${jdbc.password}")
    private String password;
    
    @Bean
    public MyDriverManager myDriverManager() {
        return new MyDriverManager(url, username, password);
    }

這個(gè)案例我們使用注解配置jdbc數(shù)據(jù)庫(kù)的連接潮梯,首先創(chuàng)建一個(gè)內(nèi)含構(gòu)造器的MyDriverManager類(lèi),然后配置config.xml里面的資源文件路徑惨恭,以便@ImportResource注解獲取秉馏,最后配置StoreConfig類(lèi)。(注意url脱羡、username萝究、password也必須要和數(shù)據(jù)庫(kù)的保持一致哦)

詳解StoreConfig類(lèi):首先我們定義三個(gè)成員變量,然后給每一個(gè)成員變量打上一個(gè)@value注解锉罐,注意@value里面的內(nèi)容一定是資源文件里面的key值帆竹。這里的@ImportResource注解就是指明一個(gè)資源文件,在這個(gè)資源文件里面獲取到對(duì)應(yīng)的數(shù)據(jù)脓规。那么@Configuration注解是用來(lái)干嘛的呢栽连?為什么不用@Component注解呢?其實(shí)是這樣的侨舆,@Component注解用于將所標(biāo)注的類(lèi)加載到 Spring 環(huán)境中秒紧,這時(shí)候是需要配置component-scan才能使用的绢陌,而@Configuration注解是Spring 3.X后提供的注解,它用于取代XML來(lái)配置 Spring噩茄。


7.@Bean注解用來(lái)標(biāo)識(shí)配置和初始化一個(gè)由SpringIOC容器管理的新對(duì)象的方法下面,類(lèi)似XML中配置文件的<bean/>

ps:默認(rèn)的@Bean注解是單例的,那么有什么方式可以指定它的范圍呢绩聘?所以這里才出現(xiàn)了@Scope注解

8.@Scope注解沥割,在@Scope注解里面value的范圍和Bean的作用域是通用的,proxyMode的屬性是采用哪一種的單例方式(一種是基于接口的注解凿菩,一種是基于類(lèi)的代理)


案例:@Bean和@Scope用法分析:

    @Bean
    @Scope(value ="session",proxyMode = "scopedProxyMode.TARGET_CLASS")
    public UserPreferences userPreferences(){
        return new userPreferences();
    }
    
    @Bean
    public service userService(){
        UserService service =new SimpleUserService();
        service.setUserPreferences(userPreferences);
        return service;
    }

如果大家覺(jué)得我寫(xiě)的對(duì)你有幫助机杜,請(qǐng)順手點(diǎn)個(gè)贊支持一下唄;如果大家覺(jué)得我有寫(xiě)的不對(duì)的地方衅谷,歡迎大家多多發(fā)言椒拗。謝謝!

轉(zhuǎn)載請(qǐng)注明作者及文章出處噢获黔!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蚀苛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子玷氏,更是在濱河造成了極大的恐慌堵未,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盏触,死亡現(xiàn)場(chǎng)離奇詭異渗蟹,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)赞辩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)雌芽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人辨嗽,你說(shuō)我怎么就攤上這事世落。” “怎么了召庞?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵岛心,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我篮灼,道長(zhǎng)忘古,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任诅诱,我火速辦了婚禮髓堪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己干旁,他們只是感情好驶沼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著争群,像睡著了一般回怜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上换薄,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天玉雾,我揣著相機(jī)與錄音,去河邊找鬼轻要。 笑死复旬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冲泥。 我是一名探鬼主播驹碍,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼凡恍!你這毒婦竟也來(lái)了志秃?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤嚼酝,失蹤者是張志新(化名)和其女友劉穎洽损,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體革半,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年流码,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了又官。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡漫试,死狀恐怖六敬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情驾荣,我是刑警寧澤外构,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站播掷,受9級(jí)特大地震影響审编,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜歧匈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一垒酬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦勘究、人聲如沸矮湘。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)缅阳。三九已至,卻和暖如春景描,著一層夾襖步出監(jiān)牢的瞬間十办,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工伏伯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留橘洞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓说搅,卻偏偏與公主長(zhǎng)得像炸枣,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子弄唧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容