1. 程式人生 > >Spring學習記錄

Spring學習記錄

開發十年,就只剩下這套架構體系了! >>>   

Java類定義配置

@Configuration //標記為配置類
@ComponentScan //標記為掃描當前包及子包所有標記為@Component的類
@ComponentScan(basePackageClasses = {介面.class,...}) //標記為掃描當前包及子包所有標記為@Component的類
@ComponentScan(basePackages = {包名,包名,...}) //標記為掃描當前包及子包所有標記為@Component的類

定義元件

@Component //標記為元件類
@Autowired //標記為自動匯入
@Autowired(required=false) //標記為可選匯入

自動裝配歧義性

@Primary //標記為優先選擇
@Qualifier //標記這個元件的別名或選擇某個別名的元件作為匯入物件
@Resource //

分層架構中定義元件

@Controller //標記為控制層元件,是@Component的即意化名稱
@Service //標記為服務層元件,是@Component的即意化名稱
@Repository //標記為資料層元件,是@Component的即意化名稱

Spring測試環境,未能按照視訊中的方式成功執行過,先記錄著

@RunWith
@ContextConfiguration

使用xml啟用元件掃描

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

顯示裝配情景

1.當某些情景下有些類無法進行自動裝配時,可在 <span style="color:#B3AD28">@Configuration</span> 標記類中新增<span style="color:#FFAA33">public</span> 方法且在方法上新增 <span style="color:#B3AD28">

@Bean</span>標記,這個時候Spring在進行掃描到 <span style="color:#B3AD28">@Configuration</span>類時便會在其中查詢 <span style="color:#B3AD28">@Bean</span>標記進行容器託管 2.在多個非關聯類中進行託管後在建立關聯關係的時候可以通過某一個類的建構函式進行注入如:

@Configuration
public class Configs{
    @Bean //某些無法隱式自動注入的類進行託管
    public A getA(){
        return new A();
    }
    
    @Bean
    public B getB(){
        return new B(getA());//呼叫多次?,在spring中只會建立一次
    }
}
  • <strong style="color:#FF0000 ">or</strong>
@Configuration
public class Configs{
    @Bean //某些無法隱式自動注入的類進行託管
    public A getA(){
        return new A();
    }
    
    @Bean
    public B getB(A a){
        return new B(a);//呼叫多次?,在spring中只會建立一次
    }
}

處理自動裝配歧義性

  • 首選bean
    • 在宣告類的時候使用<span style="color:#B3AD28">@Primary</span>且在相同介面的實現類上只能定義一個
  • 使用限定符
    • 在宣告的時候和裝配的時候分別使用<span style="color:#B3AD28">@Qualifier</span>
  • 使用限定符和bean id
    • 在宣告的時候指定bean的id(預設的id是首字母小寫的類名)
    • 在裝配的時候使用<span style="color:#B3AD28">@Qualifier</span>
    @Configuration
    public class Configs{
        @Bean
        @Qualifier("b")
        public A getBImplA(){
            return new B();//返回一個實現A介面的B類物件
        }
    
        @Bean
        @Qualifier("c")
        public A getCImplA(){
            return new C();//返回一個實現A介面的C類物件
        }
    
        @Bean
        public S getS(@Qualifier("b")A a){//注入A介面型別時指定了b這個別名的實現類
            return new S(a);
        }
    }
    
    • 如果在程式碼中不使用<span style="color:#B3AD28">@Qualifier</span>則可在形參上指定為<span style="color:#B3AD28">@Qualifier( <span style="color:#33CCFF">"getBImplA"</span> )</span>方法的名字即可

XML配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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.xsd">
    <!--id對bean的唯一性標記,字元間不得有空格-->
    <bean id="compactDisc" class="china.wuhan.soundsystem.CompactDisc"/>
    <!--name同樣標記,但name可以用空格設定多個別名-->
    <bean name="compactDisc01 compactDisc02" class="china.wuhan.soundsystem.CompactDisc"/>
</beans>

<span style="color:#DDAA00">bean</span>標籤屬性中id與name同樣標記名字,但id只能有一個且全域性也只能有一個,而name可以設定多個名字,全域性不允許有多個同時標記

使用XML進行建構函式的自動注入

package china.wuhan.soundsystem;

public class CompactDisc {
    public CompactDisc() {
        System.out.println("CompactDisc 建構函式..." + this.toString());
    }

    public void play(){
        System.out.println("播放CD音樂..." + this.toString());
    }
}
package china.wuhan.soundsystem;

public class CDPlay {

    private CompactDisc cd;

    public CDPlay() {
        System.out.println("CDPlay的無參構造..." + this.toString());
    }

    public CDPlay(CompactDisc cd) {
        this.cd = cd;
        System.out.println("CDPlay的有參構造..." + this.toString());
    }

    public void play(){
        cd.play();
    }
}
package china.wuhan.soundsystem;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        System.out.println("App running...");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        CDPlay cdplay = (CDPlay)context.getBean("cdplay");
        cdplay.play();
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       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.xsd">
    <bean id="compactDisc" class="china.wuhan.soundsystem.CompactDisc"/>
    <bean id="cdplay" class="china.wuhan.soundsystem.CDPlay">
        <constructor-arg ref="compactDisc"/>
    </bean>
</beans>
  • 在針對建構函式多個入參進行注入時可以使用index屬性或c名字空間
public class CompactDisc {
    public CompactDisc(String title,String name) {
        System.out.println("title " + title);
        System.out.println("name " + name);
        System.out.println("CompactDisc 建構函式..." + this.toString());
    }
}
<bean name="compactDisc" class="china.wuhan.soundsystem.CompactDisc">
    <constructor-arg index="0" value="Hello"></constructor-arg>
    <constructor-arg index="1" value="World"></constructor-arg>
</bean>
<bean name="compactDisc"
          class="china.wuhan.soundsystem.CompactDisc"
          c:title="Hello"
          c:name="World"/>
  • 上述呈現的兩種均可,當然還有其它方法就不列舉了,在使用c:名字空間時需要新增限定
xmlns:c="http://www.springframework.org/schema/c"
<bean id="cdplayer2" class="scorpius.soundsystem.CDPlayer" c:cd-ref="cd2"/>
c:  //表示使用c名字空間
cd  //作用在建構函式入參的變數名上,名字與建構函式入參的變數名一致
-ref //表示引用方式

如果建構函式中入參存在List,Map,Set等

  • List

  • 簡單型別

<constructor-arg name="引數名字">
    <list>
        <value>1</value>
        <value>2</value>
        <value>3</value>
        ...
    </list>
</constructor-arg>
  • 物件型別
<constructor-arg name="引數名字">
    <list>
        <ref bean="bean ID"/>
        ...
    </list>
</constructor-arg>
  • Set
<constructor-arg name="引數名字">
    <set>
        <value>1</value>
        <value>2</value>
        <value>3</value>
        ...
    </set>
</constructor-arg>
  • Map
<constructor-arg name="引數名字">
    <map>
        <entry key="鍵名" value-ref="值"/>
        <entry key="鍵名" value-ref="值"/>
        <entry key="鍵名" value-ref="值"/>
        ...
    </map>
</constructor-arg>

map中每一個元素都是一個entry節點,節點屬性中key表示鍵,value表示普通型別的值,value-ref表示物件型別的值

  • Array

  • 如果入參是陣列型別,則使用如下方式

<constructor-arg name="引數名字">
    <array>
        <value>1</value>
        <value>2</value>
        <value>3</value>
        ...
    </array>
</constructor-arg>
<constructor-arg name="引數名字">
    <array>
        <ref bean="bean ID"/>
        ...
    </array>
</constructor-arg>

如果是陣列是普通型別則使用array中的value節點即可,如果是複雜型別則使用<ref>節點,並且使用bean屬性關聯beanID

屬性注入

  • 有些時候,我們並不需要從建構函式注入,而是從set方法來注入,哪麼就可以使用屬性注入,屬性注入與上不同的在於,建構函式注入需要的是入參的變數名與配置的bean中的constructor-arg中的name要保持一致性,而屬性注入則是要求set方法的名字在去掉set後首字母小寫後的名字必須與配置中的property節點name屬性的值一致
public class Music {
    private String title;
    private Integer length;
    
    ...
    public void setTitle(String title) {
        this.title = title;
    }
    public void setLength(Integer length) {
        this.length = length;
    }
    ...
}
<bean id="music" class="scorpius.soundsystem.Music">
    <property name="title" value="音樂一"/>
    <property name="length" value="360"/>
</bean>
  • 注入物件陣列
<bean id="cd" class="scorpius.soundsystem.CD">
    <property name="name" value="磁碟一"/>
    <property name="artist" value="演唱者"/>
    <property name="musics">
        <array value-type="scorpius.soundsystem.Music">
            <ref bean="music"/>
        </array>
    </property>
</bean>
  • p:名稱空間

除了上述的用節點注入之外還可以使用p名字空間注入,與c:構造名字空間一樣,p:屬性名字空間與之有著相同的用法,可相參考使用

  • util:名稱空間

util:名稱空間相對上面來說要複雜

<util:list id="自定義空間名">
    <ref bean="物件beanId"
</util:list>

<bean   id="cd" 
        class="scorpius.soundsystem.CD" 
        p:name="屬性name的注入值" 
        p:artist="屬性artist的注入值" 
        p:musics-ref="自定義空間名"/>

總結

  • 依賴構造器

    • 注入方法有兩種
      • constructor-arg節點
      • c:名稱空間
    • name表示的是入參的變數名
  • 依賴set函式

    • 注入方法有兩種
      • property節點
      • p:名稱空間
    • name表示的是set函式去掉set字首後首字母小寫的名字
  • 帶ref的表示的是物件引用

  • util:名稱空間相當於bean的建立與定義

bean節點scope屬性

  • scope作用域
    • sinleton 單例[預設]
      • 整個應用程式中,只建立bean的一個例項
    • prototype 原型
      • 每次注入或通過spring上下文獲取的時候,都會建立一個新的bean
      • 只有在獲取物件時才會建立物件
    • session 會話
      • 在Web應用中,為每個會話建立一個bean例項
    • request 請求
      • 在Web應用中,為每個請求建立一個bean例項
  • @Scope註解與其作用一致

延遲載入

  • lazy-init
    • true 啟用延遲載入,也就是說只要要獲取時才會建立物件
    • fase
  • @Lazy效果一致

初始化/銷燬

  • init-method 等同於 @PostConstruct註解
    • 物件建立時會被呼叫的方法
  • destroy-method 等同於 @PreDestroy註解
    • 物件刪除時會被呼叫的方法

工廠方法建立物件

package scorpus;

public class Person {
    public Person() {
        System.out.println("Person...");
    }
}
package scorpus;

public class PersonFactory {
    public static Person createFactory(){
        System.out.println("靜態工廠方法...");
        return new Person();
    }

    public Person getPersion(){
        System.out.println("例項工廠方法...");
        return new Person();
    }
}
<bean id="persion1" class="scorpus.PersonFactory" factory-method="createFactory"/>
    
<bean id="persionFactory" class="scorpus.PersonFactory"/>
<bean id="persion2" factory-bean="persionFactory" factory-method="getPersion"/>
  • 感謝:千峰機構的免費視訊,著實解惑不少
  • 所有記錄均在OpenJDK12上執行過,可