1. 程式人生 > >Spring知識點總結(三)之註解方式實現IOC和DI

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"
                3         xmlns:context="http://www.springframework.org/schema/context"
                4         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                5         xsi:schemaLocation="http://www.springframework.org/schema/beans
                6         http://
www.springframework.org/schema/beans/spring-beans-3.2.xsd 7 http://www.springframework.org/schema/context 8 http://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
            案例:
 

 1                package cn.tedu.beans;
 2                 
 3                 import org.springframework.beans.factory.BeanNameAware;
 4                 import org.springframework.beans.factory.annotation.Autowired;
 5                 import org.springframework.beans.factory.annotation.Qualifier;
 6                 import org.springframework.stereotype.Component;
 7                 
 8                 @Component("per")
 9                 public class Person implements BeanNameAware{
10                     @Override
11                     public void setBeanName(String name) {
12                         System.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                 
 3                 import org.springframework.beans.factory.BeanNameAware;
 4                 import org.springframework.beans.factory.annotation.Autowired;
 5                 import org.springframework.beans.factory.annotation.Value;
 6                 import org.springframework.stereotype.Component;
 7                 
 8                 @Component("per")
 9                 public class Person implements BeanNameAware{
10                     @Value("999")
11                     private int id;
12                     
13                     @Value("zs")
14                     private String name;
15                     
16                     @Autowired
17                     private Dog dog;
18                     
19                     @Autowired
20                     private Cat cat;
21                     
22                     public Dog getDog() {
23                         return dog;
24                     }
25                     public void setDogx(Dog dog) {
26                         this.dog = dog;
27                     }
28                     public Cat getCat() {
29                         return cat;
30                     }
31                     public void setCat(Cat cat) {
32                         this.cat = cat;
33                     }
34                 
35                     @Override
36                     public String toString() {
37                         return "Person [id=" + id + ", name=" + name + ", dog=" + dog
38                                 + ", cat=" + cat + "]";
39                     }
40                     @Override
41                     public void setBeanName(String name) {
42                         System.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"
  3                     xmlns:context="http://www.springframework.org/schema/context"
  4                     xmlns:util="http://www.springframework.org/schema/util"
  5                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  6                     xsi:schemaLocation="
  7                     http://www.springframework.org/schema/beans
  8                     http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
  9                     http://www.springframework.org/schema/context
 10                     http://www.springframework.org/schema/context/spring-context-3.2.xsd
 11                     http://www.springframework.org/schema/util
 12                     http://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注入賦值
 45                 package cn.tedu.beans;
 46                 
 47                 import java.util.List;
 48                 import java.util.Map;
 49                 import java.util.Set;
 50                 
 51                 import org.springframework.beans.factory.BeanNameAware;
 52                 import org.springframework.beans.factory.annotation.Autowired;
 53                 import org.springframework.beans.factory.annotation.Value;
 54                 import org.springframework.stereotype.Component;
 55                 
 56                 @Component("per")
 57                 public class Person implements BeanNameAware{
 58                     @Value("${id}")
 59                     private int id;
 60                     
 61                     @Value("${name}")
 62                     private String name;
 63                     
 64                     @Value("#{@l1}")
 65                     private List<String> addr;
 66                     
 67                     @Value("#{@s1}")
 68                     private Set<String> jobs;
 69                     
 70                     @Value("#{@m1}")
 71                     private Map<String,String> map;
 72                     
 73                     @Autowired
 74                     private Dog dog;
 75                     
 76                     @Autowired
 77                     private Cat cat;
 78                     
 79                     public Dog getDog() {
 80                         return dog;
 81                     }
 82                     public void setDogx(Dog dog) {
 83                         this.dog = dog;
 84                     }
 85                     public Cat getCat() {
 86                         return cat;
 87                     }
 88                     public void setCat(Cat cat) {
 89                         this.cat = cat;
 90                     }
 91                 
 92                     public void setBeanName(String name) {
 93                         System.out.println("=============="+this.getClass().getName()+"===="+name);
 94                     }
 95                     @Override
 96                     public String toString() {
 97                         return "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是單例還是多例,如果不配置預設為單例
            案例:

 1                 package cn.tedu.beans;
 2                 
 3                 import org.springframework.context.annotation.Scope;
 4                 import org.springframework.stereotype.Component;
 5                 
 6                 @Component
 7                 @Scope("prototype")
 8                 public class Dog {
 9                 
10                 }

 


        b. @Lazy
            配置修飾的類的bean採用懶載入機制
            案例:

 1                 package cn.tedu.beans;
 2                 
 3                 import org.springframework.context.annotation.Lazy;
 4                 import org.springframework.context.annotation.Scope;
 5                 import org.springframework.stereotype.Component;
 6                 
 7                 @Component
 8                 @Lazy
 9                 public class Dog {
10                     public Dog() {
11                         System.out.println("Dog...被創建出來了...");
12                     }
13                 }

 


        c. @PostConstruct
            在bean對應的類中 修飾某個方法 將該方法宣告為初始化方法,物件建立之後立即執行。
        d. @PreDestroy
            在bean對應的類中 修飾某個方法 將該方法宣告為銷燬的方法,物件銷燬之前呼叫的方法。
            案例:
             

 1   package cn.tedu.beans;
 2                 
 3                 import javax.annotation.PostConstruct;
 4                 import javax.annotation.PreDestroy;
 5                 
 6                 import org.springframework.stereotype.Component;
 7                 
 8                 @Component
 9                 public class Dog {
10                     public Dog() {
11                         System.out.println("Dog...被創建出來了...");
12                     }
13                     
14                     @PostConstruct
15                     public void init(){
16                         System.out.println("Dog的初始化方法。。。");
17                     }
18                     
19                     @PreDestroy
20                     public void destory(){
21                         System.out.println("Dog的銷燬方法。。。");
22                     }
23                 }

 


        e. @Controller @Service @Repository @Component
            這四個註解的功能是完全相同的,都是用來修飾類,將類宣告為Spring管理的bean的。
            其中@Component一般認為是通用的註解
            而@Controller用在軟體分層中的控制層,一般用在web層
            而@Service用在軟體分層中的業務訪問層,一般用在service層
            而@Repository用在軟體分層中的資料訪問層,一般用在dao層