1. 程式人生 > >Spring 進階(7) 使用註解配置bean(3)

Spring 進階(7) 使用註解配置bean(3)

  1. 這裡主要介紹自動裝配和精確裝配
    1. 自動裝配可以通過@Autowired註解,被這個註解修飾的方法會在容器中找和id和引數名字一樣的bean,然後把它裝配進去。需要 指出的是,當容器中有大於一個bean符合條件的話,會丟擲異常,當有大於一個bean符合條件的話,spring什麼也不做。
      package InstanceClass;
      
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.annotation.Lazy;
      import org.springframework.stereotype.Component;
      
      import javax.annotation.PostConstruct;
      import javax.annotation.PreDestroy;
      
      //同上
      @Lazy(false)
      @Component
      public class ClassB {
          private String name;
          private ClassC classC;
      
      
          public ClassC getClassC() {
              return classC;
          }
          @Autowired
          public void setClassC(ClassC classC) {
              this.classC = classC;
          }
      
          void setName(String name) {
              this.name = "ok1";
          }
      
          public void thisIsMyName(){
              System.out.println("B' s name is " + name);
          }
      
          @PostConstruct
          public void init(){
               System.out.println("It is B's init");
          }
      
          public String getName() {
              return name;
          }
      
          @PreDestroy
          public  void destory(){
               System.out.println("It is B's destory");
          }
      
      }
      
      package InstanceClass;
      
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.stereotype.Component;
      
      @Component
      public class ClassC {
          @Value("classC")
          private String name;
      
          public String getName() {
              return name;
          }
      }
      
      package TestPackage;
      
      import InstanceClass.ClassA;
      import InstanceClass.ClassB;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      //測試類
      public class SpringTest {
          public static void main(String []args){
              ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
              ClassA classA = applicationContext.getBean("classA", ClassA.class);
             System.out.println(classA.toString());
      
             classA = applicationContext.getBean("classA", ClassA.class);
             System.out.println(classA.getClassB().getName());
      
              ClassB classB = applicationContext.getBean("classB", ClassB.class);
            System.out.println(classB.getClassC().getName());
              ((ClassPathXmlApplicationContext) applicationContext).registerShutdownHook();
          }
      }
      
      <?xml version="1.0" encoding="GBK"?>
      <!--要使用註解的話,就要先引入對應的配置-->
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
      	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
      	http://www.springframework.org/schema/context
      	http://www.springframework.org/schema/context/spring-context-4.0.xsd">
      
          <!--顯式指定要在那個路徑下自動配置bean-->
          <context:component-scan base-package="InstanceClass"/>
      
      </beans>

       執行測試類看到結果

      It is B's init
      [email protected]
      null
      classC
      It is B's destory

      可以看到,spring把classC當作引數傳進去了

    2. 自動裝配還允許有多個引數

      @Autowired
          public void setClassCAndClassD(ClassC classC , ClassD classD) {
              this.classC = classC;
              this.classD = classD;
      
          }

      測試類

      package TestPackage;
      
      import InstanceClass.ClassA;
      import InstanceClass.ClassB;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      //測試類
      public class SpringTest {
          public static void main(String []args){
              ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
              ClassA classA = applicationContext.getBean("classA", ClassA.class);
             System.out.println(classA.toString());
      
             classA = applicationContext.getBean("classA", ClassA.class);
             System.out.println(classA.getClassB().getName());
      
              ClassB classB = applicationContext.getBean("classB", ClassB.class);
            System.out.println(classB.getClassC().getName() + "," + classB.getClassD().getName());
              ((ClassPathXmlApplicationContext) applicationContext).registerShutdownHook();
          }
      }
      

      輸出

      It is B's init
      [email protected]
      null
      classC,classD
      It is B's destory
      

       

    3. 還不止這樣呢,對於在額按中定義的陣列。入股使用自動裝配註解修飾的話,spring還會去本容器中找到所有和被修飾的陣列的類(包括他的子類)去填充這個陣列。程式碼如下

      1. 先把ClassC和ClassD定義成interface的實現類

      2. 在ClassB中用自動裝配修飾interface陣列

            @Autowired
            private Interface[] interfaces;

         

      3. 測試類,可以看到interfaces陣列的長度為2

        1. 在classB中

            @PreDestroy
              public  void destory(){
                   System.out.println("It is B's destory");
                   System.out.println(interfaces.length);
              }

           

        2. 測試類中

           ((ClassPathXmlApplicationContext) applicationContext).registerShutdownHook();

      4. 當Autowired修飾了set方法,spring就會在指定的路徑去尋找符合條件的bean把他填充進去,但是,當指定的路徑下有不止一個bean符合條件的時候,spring就會不知道怎麼辦了,畢竟它只是一個spring,這是應該在符合的bean中,將其中的一個作為候選bean,這樣spring就會把它填充進去啦~

            private Interface interface1;
        //ClassC 和ClassD都是Interface的子類,所以這裡就有不止一個bean符合條件。
        
            public Interface getInterface1() {
                return interface1;
            }
        
            @Autowired
            public void setInterface1(Interface interface1) {
                this.interface1 = interface1;
            }
        
        @Component
        @Primary
        //當把ClassC用Primary註解以後,spring就會知道應該把ClassC填進去啦
        public class ClassC  implements Interface {
            @Value("classC")
            private String name;
        
            public String getName() {
                return name;
            }
        }