Spring知識點總結(三)之註解方式實現IOC和DI
1. 註解概念
所謂註解就是給程式看的提示資訊,很多時候都用來作為輕量級配置的方式。
關於註解的知識點,參看java基礎課程中java基礎加強部分的內容。
2. Spring中的註解
Spring除了預設的使用xml配置檔案的方式實現配置之外,也支援使用註解方式實現配置,這種方式效率更高,配置資訊清晰,修改更方便,推薦使用。
引入context名稱空間:
在MyEclipse中匯入spring-context-3.2.xsd約束檔案,要求Spring來管理。
在applicationContext.xml檔案中,引入該schema檔案:
1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3xmlns:context="http://www.springframework.org/schema/context" 4xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 5xsi:schemaLocation="http://www.springframework.org/schema/beans 6http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 7http://www.springframework.org/schema/context 8http://www.springframework.org/schema/context/spring-context-3.2.xsd 9"> 10</beans>
**可以將以上頭資訊加入MyEclipse模版,方便後續自動生成。
3. 使用類註解
使用Spring的類註解可以通過註解註冊類為bean,省去了配置檔案中的<bean>配置。
a. 開啟包掃描
在spring的配置檔案中,開啟包掃描,指定spring自動掃描哪些個包下的類。
<context:component-scan base-package="cn.tedu.beans"/>
案例:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd "> <!-- 開啟包掃描 --> <context:component-scan base-package="cn.tedu.beans"></context:component-scan> <!-- <bean id="person" class="cn.tedu.beans.Person"></bean> <bean id="cat" class="cn.tedu.beans.Cat"></bean> <bean id="dog" class="cn.tedu.beans.Dog"></bean> --> </beans>
b. 使用註解註冊bean
這個包中的類會在spring容器啟動時自動被掃描,檢測是否需要自動配置為bean.
在配置的包中的類上使用@Component註解,則這個類會自動被註冊為bean,使用當前類的class為<bean>的class,通常情況下使用類名首字母小寫為<bean>id。
案例:
package cn.tedu.beans; import org.springframework.stereotype.Component; @Component public class Person{ }
c. bean的id
可以使bean類實現BeanNameAware介面,並實現其中的setBeanName方法,spring容器會在初始化bean時,呼叫此方法告知當前bean的id。通過這個方式可以獲取bean的id資訊。
通常情況下註解註冊bean使用類名首字母小寫為bean的id,但是如果類名的第二個字母為大寫則首字母保留原樣.
cn.tedu.beans.Person --> <bean id="person" class="cn.tedu.beans.Person"/>
cn.tedu.beans.NBA --> <bean id="NBA" class="cn.tedu.beans.NBA"/>
也可以通過在@Component中配置value屬性,明確的指定當前類在註冊到spring時bean的id
案例:
1package cn.tedu.beans; 2 3import org.springframework.beans.factory.BeanNameAware; 4import org.springframework.beans.factory.annotation.Autowired; 5import org.springframework.beans.factory.annotation.Qualifier; 6import org.springframework.stereotype.Component; 7 8@Component("per") 9public class Person implements BeanNameAware{ 10@Override 11public void setBeanName(String name) { 12System.out.println("==="+this.getClass().getName()+"==="+name); 13} 14}
4. 使用屬性註解
使用屬性註解,可以為bean配置屬性的注入過程,省去了在配置檔案中進行注入配置的過程,更加便捷。
a. 在配置檔案中開啟屬性註解功能
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 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-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd "> <!-- 開啟屬性註解 --> <context:annotation-config></context:annotation-config> </beans>
b. 使用屬性註解注入bean型別資料:
在bean中的屬性上通過如下註解宣告屬性注入
@Autowired
也可以使用@Qualifier(value="dog1")註解,明確的指定,要注入哪個id的bean
程式碼:
package cn.tedu.beans; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; public class Person implements BeanNameAware{ @Autowired private Dog dog; @Autowired private Cat cat; public Dog getDog() { return dog; } public void setDogx(Dog dog) { this.dog = dog; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } @Override public String toString() { return "Person [dog=" + dog + ", cat=" + cat + "]"; } @Override public void setBeanName(String name) { System.out.println("=============="+this.getClass().getName()+"===="+name); } }
c. 屬性注入bean型別資料的原理:
當spring容器解析xml時,發現開啟了屬性註解,則會在建立bean時,檢測屬性上是否存在@Autowired註解,如果發現該註解,則會通過當前屬性的名稱尋找是否存在該id的bean,如果存在則注入進來,如果不存在,再檢查是否存在和當前屬性型別相同的bean,如果由則注入進來,如果都沒有則丟擲異常.
**也可以使用@Resource(name="id")指定注入給定id的bean,但是這種方式不建議大家使用。
d. spring內建支援注入型別的註解方式的注入 - 非集合型別
spring中可以通過註解方式 註冊bean,並可以通過@Autowired實現屬性的自動注入,但注入的都是自定義的bean型別,如果類中包含例如 int long String等spring內建可注入的型別時,又該如何注入呢? 可以使用@Value註解來實現注入。
1 package cn.tedu.beans; 2 3import org.springframework.beans.factory.BeanNameAware; 4import org.springframework.beans.factory.annotation.Autowired; 5import org.springframework.beans.factory.annotation.Value; 6import org.springframework.stereotype.Component; 7 8@Component("per") 9public class Person implements BeanNameAware{ 10@Value("999") 11private int id; 12 13@Value("zs") 14private String name; 15 16@Autowired 17private Dog dog; 18 19@Autowired 20private Cat cat; 21 22public Dog getDog() { 23return dog; 24} 25public void setDogx(Dog dog) { 26this.dog = dog; 27} 28public Cat getCat() { 29return cat; 30} 31public void setCat(Cat cat) { 32this.cat = cat; 33} 34 35@Override 36public String toString() { 37return "Person [id=" + id + ", name=" + name + ", dog=" + dog 38+ ", cat=" + cat + "]"; 39} 40@Override 41public void setBeanName(String name) { 42System.out.println("==="+this.getClass().getName()+"==="+name); 43} 44 45}
這種方式可以實現spring內建型別的注入,但是這種方式將注入的值寫死在了程式碼中,後續如果希望改變注入的初始值,必須來修改原始碼,此時可以將這些值配置到一個properties配置檔案中,再在spring中進行引入。
e. spring內建支援注入型別的註解方式的注入 - 集合型別
需要將集合型別的資料配置到spring配置檔案中,再通過@Value引入
配置過程:
將spring-util-3.2.xsd交給MyEclipse管理
在當前spring容器的配置檔案中匯入util名稱空間
再通過適當的util標籤註冊資料
案例:
1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3xmlns:context="http://www.springframework.org/schema/context" 4xmlns:util="http://www.springframework.org/schema/util" 5xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 6xsi:schemaLocation=" 7http://www.springframework.org/schema/beans 8http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 9http://www.springframework.org/schema/context 10http://www.springframework.org/schema/context/spring-context-3.2.xsd 11http://www.springframework.org/schema/util 12http://www.springframework.org/schema/util/spring-util-3.2.xsd 13"> 14<!-- 開啟屬性註解 --> 15<context:annotation-config></context:annotation-config> 16<context:component-scan base-package="cn.tedu.beans"></context:component-scan> 17<context:property-placeholder location="classpath:/person-data.properties"/> 18 19<util:list id="l1"> 20<value>北京</value> 21<value>上海</value> 22<value>廣州</value> 23<value>深證</value> 24</util:list> 25 26<util:set id="s1"> 27<value>法師</value> 28<value>射手</value> 29<value>打野</value> 30<value>戰士</value> 31<value>打野</value> 32<value>坦克</value> 33<value>打野</value> 34</util:set> 35 36<util:map id="m1"> 37<entry key="k1" value="v1"></entry> 38<entry key="k2" value="v2"></entry> 39<entry key="k3" value="v3"></entry> 40<entry key="k1" value="v4"></entry> 41</util:map> 42</beans> 43 44再在類的屬性中通過@Value注入賦值 45package cn.tedu.beans; 46 47import java.util.List; 48import java.util.Map; 49import java.util.Set; 50 51import org.springframework.beans.factory.BeanNameAware; 52import org.springframework.beans.factory.annotation.Autowired; 53import org.springframework.beans.factory.annotation.Value; 54import org.springframework.stereotype.Component; 55 56@Component("per") 57public class Person implements BeanNameAware{ 58@Value("${id}") 59private int id; 60 61@Value("${name}") 62private String name; 63 64@Value("#{@l1}") 65private List<String> addr; 66 67@Value("#{@s1}") 68private Set<String> jobs; 69 70@Value("#{@m1}") 71private Map<String,String> map; 72 73@Autowired 74private Dog dog; 75 76@Autowired 77private Cat cat; 78 79public Dog getDog() { 80return dog; 81} 82public void setDogx(Dog dog) { 83this.dog = dog; 84} 85public Cat getCat() { 86return cat; 87} 88public void setCat(Cat cat) { 89this.cat = cat; 90} 91 92public void setBeanName(String name) { 93System.out.println("=============="+this.getClass().getName()+"===="+name); 94} 95@Override 96public String toString() { 97return "Person [id=" + id + ", name=" + name + ", addr=" + addr 98+ ", jobs=" + jobs + ", map=" + map + ", dog=" + dog + ", cat=" 99+ cat + "]"; 100} 101} 102
5. 其他註解
a. @Scope(value="prototype")
配置修飾的類的bean是單例還是多例,如果不配置預設為單例
案例:
1package cn.tedu.beans; 2 3import org.springframework.context.annotation.Scope; 4import org.springframework.stereotype.Component; 5 6@Component 7@Scope("prototype") 8public class Dog { 9 10}
b. @Lazy
配置修飾的類的bean採用懶載入機制
案例:
1package cn.tedu.beans; 2 3import org.springframework.context.annotation.Lazy; 4import org.springframework.context.annotation.Scope; 5import org.springframework.stereotype.Component; 6 7@Component 8@Lazy 9public class Dog { 10public Dog() { 11System.out.println("Dog...被創建出來了..."); 12} 13}
c. @PostConstruct
在bean對應的類中 修飾某個方法 將該方法宣告為初始化方法,物件建立之後立即執行。
d. @PreDestroy
在bean對應的類中 修飾某個方法 將該方法宣告為銷燬的方法,物件銷燬之前呼叫的方法。
案例:
1package cn.tedu.beans; 2 3import javax.annotation.PostConstruct; 4import javax.annotation.PreDestroy; 5 6import org.springframework.stereotype.Component; 7 8@Component 9public class Dog { 10public Dog() { 11System.out.println("Dog...被創建出來了..."); 12} 13 14@PostConstruct 15public void init(){ 16System.out.println("Dog的初始化方法。。。"); 17} 18 19@PreDestroy 20public void destory(){ 21System.out.println("Dog的銷燬方法。。。"); 22} 23}
e. @Controller @Service @Repository @Component
這四個註解的功能是完全相同的,都是用來修飾類,將類宣告為Spring管理的bean的。
其中@Component一般認為是通用的註解
而@Controller用在軟體分層中的控制層,一般用在web層
而@Service用在軟體分層中的業務訪問層,一般用在service層
而@Repository用在軟體分層中的資料訪問層,一般用在dao層