寫(xiě)在前面:
眾所周知荐类,在JavaEE開(kāi)發(fā)框架中肃叶,Spring框架是用的最多的,注解在框架的定位也就越來(lái)越明顯了十嘿。說(shuō)句玩笑話(huà):能用一個(gè)注解解決的因惭,絕不用一堆配置和代碼解決;如果不能解決绩衷,那么來(lái)兩個(gè)注解蹦魔;(穩(wěn)住,別噴...)
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)注明作者及文章出處噢获黔!