《spring 實戰 第四版》第二 、三章 spring 的bean裝配

1. spring 裝配bean 的三種方式

(1) 自動化裝配bean(隱式)

  • 適用對象:組件類

@Component(“rename”) @Named(“rename”) 聲明組件類,並重命名

  • 適用對象:配置類

@ComponentScan 在java config類上使用,啓用spring的組件掃描並創建bean,默認當前包。

@ComponentScan(basePackages = {“com.system”,“com.video”}) 設置掃描指定的一個或多個基礎包(全限定包名)

@ComponentScan(basePackageClasses = {“XXPlayer.class”,“XXPlayer.class”}) 指定一個或多個類所在的包作爲掃描的基礎包

(在IDEA,當bean裝配過程沒有匹配到或者出現多個bean匹配接口將編譯錯誤)

  • 適用對象:controller類或者測試類

@ContextConfiguration(classes = XXConfig.class) 聲明在XXConfig 這個配置類中加載配置

  • @Autowire @ Inject 將bean注入當前類

    可應用於所依賴的類聲明上,即bean裝配到該聲明上

    構造器或者setter以及其他方法上,即bean將嘗試裝配到方法參數所聲明的依賴。
    當沒有匹配到bean,將拋出異常

@Autowire(required = false) 當沒有匹配的Bean時,bean將會處於未匹配狀態,即null

  • 缺陷是無法實現第三方庫組件的裝配

    因爲無法在第三方類庫修改源碼,即無法添加相應的裝配bean註解

MediaPlayer.java

public interface MediaPlayer {

   void play();
}

CompactDisc.java

public interface CompactDisc {
   void play();
}

CDPlayer.java

@Component
public class CDPlayer implements MediaPlayer{

   private CompactDisc compactDisc;

   public CDPlayer(CompactDisc compactDisc){
       this.compactDisc = compactDisc;
   }
   public void play() {
       compactDisc.play() ;
   }
}

SgtPeppers.java

@Component  //聲明爲組件類
public class SgtPeppers implements CompactDisc {

   public void play() {
       System.out.println("SgtPeppers");
   }
}

配置類 CDPlayerConfig.java

//聲明配置類
@Configuration
//啓用組件掃描
@ComponentScan(basePackageClasses = {CDPlayer.class})//包名或者類名
public class CDPlayerConfig {

}

也可以通過 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">
       
    <context:component-scan base-package="soundSystem">

</beans>

測試類 CompactDiscTest.java

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class) //聲明使用的配置類加載配置
public class CompactDiscTest {
   @Autowired
   private CompactDisc compactDisc;
   
   @Autowired
   private MediaPlayer mediaPlayer;

   @Test
   public void beanTest(){
       assertNotNull(mediaPlayer);
       assertNotNull(compactDisc);
   }
}

(2) 通過java代碼裝配bean(顯式)

JavaConfig 往往放在單獨的包中,與應用邏輯代碼分開

  • @Configuration 表明該類是配置類,功能是生產bean,故不應該侵入業務代碼
  • @Bean 表明返回的對象將註冊爲spring應用上下文中的bean,默認id是方法名。 可通過name屬性重命名。
    ( PS:@Autowired 聲明的對象名與該ID保持一致
@Configuration
public class CDPlayerConfig{
    @Bean(name = "sgtPeppers")
    public CompactDisc sgtPeppers(){
        return new SgtPeppers();
    }
    
    @Bean
    public CDPlayer cdPlayer(){
       return new CDPlayer(sgtPeppers()); 
    }
    
    //以下sgtPeppers()返回上面spring通過@Bean(name = "sgtPeppers")創建的bean,同樣的otherCDPlayer()也如此
    //在這種方式下,注入的bean的@Bean方法sgtPeppers()需要同一個配置類聲明
    @Bean
    public CDPlayer otherCDPlayer(){
        return new CDPlayer(sgtPeppers());
    }
    
    //這種方式是最佳選擇,自動裝配一個CompactDisc到配置方法中
    //這裏的 CompactDisc bean 創建方式可以是當前配置類(或其他配置類),XML文件和自動掃描裝配 bean
    @Bean
    public CDPlayer cdPlayer(CompactDisc compactDisc){
        return new CDPlayer(compactDisc);
    }

}
  • cdPlayer()中調用的sgtPlayer()方法已經用@Bean註解,Spring將會攔截所有對他的調用,並確保直接返回該方法所創建的bean,而不是每次都對其進行實際的調用來創建新的對象。
  • spring 中的bean都是單例的

(3)通過XML裝配bean(顯式)

通過這個元素,spring調用對應類的默認構造器創建bean

a. 構造器注入對象引用

  • 構造器注入
<?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="codingdojo.parkingboy.spring.auto_bean.SgtPeppers" />
    
    <bean id="cDPlayer" class="codingdojo.parkingboy.spring.auto_bean.CDPlayer">
        <constructor-arg ref="compactDisc"/>
    </bean>

</beans>
  • C-命名空間注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       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="codingdojo.parkingboy.spring.auto_bean.SgtPeppers"/>
    
    <bean id="cDPlayer" class="codingdojo.parkingboy.spring.auto_bean.CDPlayer" 
          c:compactDisc-ref ="compactDisc"/>
    //c:compactDisc-ref 的compactDisc 是構造器參數名 第二個是注入bean的id     
    
    <bean id="cDPlayer" class="codingdojo.parkingboy.spring.auto_bean.CDPlayer"
          c:_0-ref ="compactDisc"/>//0表示第一個參數
    
    <bean id="cDPlayer" class="codingdojo.parkingboy.spring.auto_bean.CDPlayer"
          c:_0-ref ="compactDisc"/>//有且只有一個參數
    
</beans>

b. 構造器注入字面量(變量)

以上都是類對象注入構造器,下面介紹字面量(變量)的注入

BlankDisc.java

public class BlankDisc implements CompactDisc {
    private String title;
    private String artist;
    public BlankDisc(String title,String artist){
        this.title = title;
        this.artist = artist;
    }
    public void play() {
        System.out.println("Playing" + title + "by" + artist);
    }
}
  • 注入
<bean id="blankDisc" class="codingdojo.parkingboy.spring.xml_bean.BlankDisc">
        <constructor-arg index="0" value="gentle music"/>
        <constructor-arg index="1" value="Jason"/>
    </bean>
  • c 命名空間注入
<bean id="blankDisc" class="codingdojo.parkingboy.spring.xml_bean.BlankDisc"
        c:artist="gentle music" c:title="Jason"/>

c. 構造器注入集合(只能通過 注入)

BlankDisc.java

public class BlankDisc implements CompactDisc {
    private List<String> songs;
    
    public BlankDisc(List<String> songs){
        this.songs =songs
    }
    public void play() {
        for(String song:songs){
            System.out.println("Playing" + song);
        }
        
    }
}
<bean id="blankDisc" class="codingdojo.parkingboy.spring.xml_bean.BlankDisc">
        <constructor-arg >
            <list>
                <value>A</value>
                <value>B</value>
                <value>C</value>
            </list>
        </constructor-arg>
</bean>

注入對象引用的集合

public CDPlayer(List<CompactDisc> ads){....}
<bean id="blankDisc" class="codingdojo.parkingboy.spring.xml_bean.BlankDisc">
        <constructor-arg >
            <list>
                <ref bean = "sgtPeppers"/>
                <ref bean = "whilteAlbum"/>
                <ref bean = "hardDaysNight"/>
            </list>
        </constructor-arg>
</bean>

d. 屬性注入

前面我們都是使用構造器注入的方式,一般來說:強依賴(必不可少的)使用構造器注入,可選性依賴使用屬性注入。
這裏的 CompactDisc 可以爲強依賴,也可以是可選性的。下面是兩種方式的注入:

  1. 通過構造器注入 CompactDisc
public class CDPlayer implements MediaPlayer {

    private CompactDisc compactDisc;

    public CDPlayer(CompactDisc compactDisc){
        this.compactDisc = compactDisc;
    }
    public void play() {
        compactDisc.play() ;
    }
}
  1. 通過屬性注入 CompactDisc
public class HDPlayer implements MediaPlayer {

    private CompactDisc compactDisc;

    public void setCompactDisc(CompactDisc compactDisc) {
        this.compactDisc = compactDisc;
    }
    
    public void play() {
        compactDisc.play();
    }
}
  • 屬性注入
<bean id="hdPlayer" class="codingdojo.parkingboy.spring.xml_bean.HDPlayer">
    <property name="compactDisc" ref="compactDisc"/>
</bean>

這裏通過 ref 調用setCompactDisc()方法將引用 bean 注入到屬性compactDisc

  • p 命名空間 屬性注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       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="codingdojo.parkingboy.spring.auto_bean.SgtPeppers"/>
    
    <bean id="hdPlayer" class="codingdojo.parkingboy.spring.xml_bean.HDPlayer" 
        p:compactDisc_ref = "compactDisc"
    />
    
</beans>

在這裏插入圖片描述

e. 屬性注入字面量(變量)

BlankDisc.java

public class BlankDisc implements CompactDisc {
    private String title;
    private String artist;
    
    public void setTitle(String title){
        this.title = title;
    }
    
    public void setArtist(String artist){
        this.artist = artist;
    }
   
    public void play() {
        System.out.println("Playing" + title + "by" + artist);
    }
}
  • 注入屬性
<bean id="blankDisc" class="codingdojo.parkingboy.spring.xml_bean.BlankDisc">
    <property name="title" value = "gentle music"/>
    <property name="artist" value = "Jason"/>
</bean>
  • p 命名空間 注入屬性
<bean id="blankDisc" class="codingdojo.parkingboy.spring.xml_bean.BlankDisc">
    <properties>
        <p:title = "gentle music"/>
        <p:artist = "Jason"/>
    </properties>
</bean>

f. 屬性注入集合

BlankDisc.java

public class BlankDisc implements CompactDisc {
    private String title;
    private String artist;
    private List<String> tracks;
    
    public void setTitle(String title){
        this.title = title;
    }
    
    public void setArtist(String artist){
        this.artist = artist;
    }
    
    public void setTracks(List<String> tracks){
        this.tracks = tracks;
    }
   
    public void play() {
        System.out.println("Playing" + title + "by" + artist);
        for(String track:tracks){
            System.out.println("-Track:"+track);
        }
    }
}
  • 注入集合
<bean id="blankDisc" class="codingdojo.parkingboy.spring.xml_bean.BlankDisc">
        <property name = "tracks" >
            <list>
                <value>A</value>
                <value>B</value>
                <value>C</value>
            </list>
        </properties>
</bean>
  • 這裏我們使用 util-命名空間 實現p 命名空間 注入集合
<util:list id="trackList">
  <value>Sgt. Pepper's Lonely Hearts Club Band</value>
  <value>With a Little Help from My Friends</value>
  <value>Lucy in the Sky with Diamonds</value>
  <value>Getting Better</value>
  <value>Fixing a Hole</value>
  <value>She's Leaving Home</value>
  <value>Being for the Benefit of Mr. Kite!</value>
  <value>Within You Without You</value>
  <value>When I'm Sixty-Four</value>
  <value>Lovely Rita</value>
  <value>Good Morning Good Morning</value>
  <value>Sgt. Pepper's Lonely Hearts Club Band (Reprise)</value>
  <value>A Day in the Life</value>
</util:list>
<bean id="blankDisc" class="codingdojo.parkingboy.spring.xml_bean.BlankDisc">
    <properties>
        <p:title = "gentle music"/>
        <p:artist = "Jason"/>
        <p:tracks-ref="trackList" />
    </properties>
</bean>

  • 關於 util- 命名空間的其他屬性說明
    在這裏插入圖片描述

JavaConfig 和 xml 配置 的混合使用

在JavaConfig中引用xml配置

在xml配置中引用 JavaConfig

2. 高級裝配

配置profile bean

通常不同的開發環境我們都會使用不同的環境配置,比如配置文件,可以配置多個profile bean,並在不同需要中指定profile進行開發測試。

通過@Profile註解配置profile

@Configuration
public class DataSourceConfig {
  
  @Bean(destroyMethod = "shutdown")
  @Profile("dev") //創建了dev profile 的bean
  public DataSource embeddedDataSource() {
    return new EmbeddedDatabaseBuilder()
        .setType(EmbeddedDatabaseType.H2)
        .addScript("classpath:schema.sql")
        .addScript("classpath:test-data.sql")
        .build();
  }

  @Bean
  @Profile("prod")//創建 prod profile 的 bean
  public DataSource jndiDataSource() {
    JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
    jndiObjectFactoryBean.setJndiName("jdbc/myDS");
    jndiObjectFactoryBean.setResourceRef(true);
    jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
    return (DataSource) jndiObjectFactoryBean.getObject();
  }

}

這裏的裝配的bean 是基於激活的profile,即只有處於active 激活狀態的profile 相應的bean纔會被創建。(PS:沒有指定profile的bean,即沒有使用@Profile,始終都會被創建,也就沒有有沒有激活之說)

在XML中配置profile

datasource-config.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" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xmlns:jee="http://www.springframework.org/schema/jee" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
    http://www.springframework.org/schema/jee
    http://www.springframework.org/schema/jee/spring-jee.xsd
    http://www.springframework.org/schema/jdbc
    http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/beans ">

  <beans profile="dev">
    <jdbc:embedded-database id="dataSource" type="H2">
      <jdbc:script location="classpath:schema.sql"/>
      <jdbc:script location="classpath:test-data.sql"/>
    </jdbc:embedded-database>
  </beans>

  <beans profile="prod">
    <jee:jndi-lookup id="dataSource"
                     lazy-init="true"
                     jndi-name="jdbc/myDatabase"
                     resource-ref="true"
                     proxy-interface="javax.sql.DataSource"/>
  </beans>
</beans>

如果以下是項目resources的目錄結構

--resources
        |__common
            |__log4j.properties
            
        |__dev
            |__jdbc.properties
            
        |__prod
            |__jdbc.properties

可以這樣進行配置datasource-config.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.2.xsd">

  <description>spring profile配置</description>

  <!-- 開發環境配置文件 -->
  <beans profile="development">
    <context:property-placeholder
            location="classpath*:common/*.properties, classpath*:dev/*.properties" />
    <bean id="dataSource"
          class="com.mchange.v2.c3p0.ComboPooledDataSource"
          destroy-method="close">

      <property name="driverClass" value="${jdbc.driver_class}"></property>
      <property name="jdbcUrl" value="${jdbc.connection.url}"></property>
      <property name="user" value="${jdbc.connection.username}"></property>
      <property name="password" value="${jdbc.connection.password}"></property>

    </bean>
  </beans>

  <!-- 生產環境配置文件 -->
  <beans profile="production">
    <context:property-placeholder
            location="classpath*:common/*.properties, classpath*:prod/*.properties" />
    <bean id="dataSource"
          class="com.mchange.v2.c3p0.ComboPooledDataSource"
          destroy-method="close">

      <property name="driverClass" value="${jdbc.driver_class}"></property>
      <property name="jdbcUrl" value="${jdbc.connection.url}"></property>
      <property name="user" value="${jdbc.connection.username}"></property>
      <property name="password" value="${jdbc.connection.password}"></property>

    </bean>
  </beans>
</beans>

激活profile

可以通過設置spring.profiles.default和spring.profiles.active這兩個屬性來激活和使用對應的配置文件。default爲默認,如果沒有通過active來指定,那麼就默認使用default定義的環境。

這兩個屬性可以通過多種方法來設置:

  • 在web.xml中作爲web應用的上下文參數context-param;
  • 在web.xml中作爲DispatcherServlet的初始化參數;
  • 作爲JNDI條目;
  • 作爲環境變量;
  • 作爲JVM的系統屬性;
  • 在集成測試類上,使用@ActiveProfiles註解配置。

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

    <display-name>Archetype Created Web Application</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath*:/applicationContext*.xml
        </param-value>
    </context-param>

    <!-- 在上下文context-param中設置profile.default的默認值 -->
    <context-param>
        <param-name>spring.profiles.default</param-name>
        <param-value>development</param-value>
    </context-param>

    <!-- 在上下文context-param中設置profile.active的默認值 -->
    <!-- 設置active後default失效,web啓動時會加載對應的環境信息 -->
    <context-param>
        <param-name>spring.profiles.active</param-name>
        <param-value>development</param-value>
    </context-param>

    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 在DispatcherServlet參數中設置profile的默認值,active同理 -->
        <init-param>
            <param-name>spring.profiles.default</param-name>
            <param-value>development</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

指定 profile 進行測試

可以通過@ActiveProfiles來指定激活的profile

  @RunWith(SpringJUnit4ClassRunner.class)
  @ContextConfiguration("classpath:datasource-config.xml")
  @ActiveProfiles("prod")
  public static class ProductionDataSourceTest_XMLConfig {
        @Autowired(required=false)
        private DataSource dataSource;
        
        @Test
        public void shouldBeEmbeddedDatasource() {
          // should be null, because there isn't a datasource configured in JNDI
          assertNull(dataSource);
    }
  }

有條件地裝配bean

概述

在應用的類路徑下包含特定的庫,或者在另外特定的bean 聲明之後,或者只有在特定環境配置之後才創建bean。

@Conditional

public interface Condition {

	/**
	 * Determine if the condition matches.
	 * @param context the condition context
	 * @param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}
	 * or {@link org.springframework.core.type.MethodMetadata method} being checked.
	 * @return {@code true} if the condition matches and the component can be registered
	 * or {@code false} to veto registration.
	 */
	boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);

}

這個接口就是設置條件必須實現的,實現方法matches 並在裏面設置相關條件,該方法返回true即是條件成立,可以創建@Conditional 修飾的bean。

例子說明

  • 組件類
public class MagicBean {

}
  • 配置類
@Configuration
public class MagicConfig {

  @Bean
  @Conditional(MagicExistsCondition.class)
  public MagicBean magicBean() {
    return new MagicBean();
  }
  
}

@Conditional(MagicExistsCondition.class)指定Conditional接口的實現類

  • Conditional接口的實現類
public class MagicExistsCondition implements Condition {

  @Override
  public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

      Environment env = context.getEnvironment();
      return env.containsProperty("magic");//判斷環境中是否存在magic屬性

  }
  
}

實現matches方法,設置條件

  • 測試類
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=MagicConfig.class)
public class MagicExistsTest {

  @Autowired
  private ApplicationContext context;
  
  /*
   * This test will fail until you set a "magic" property.
   * You can set this property as an environment variable, a JVM system property, by adding a @BeforeClass
   * method and calling System.setProperty() or one of several other options.
   */
  @BeforeClass
  public static void setProperty(){
    System.setProperty("magic","value");
  }

  @Test
  public void shouldNotBeNull() {
    assertTrue(context.containsBean("magicBean"));
  }
  
}

Spring 條件註解(@Conditional)實例

處理自動裝配bean 的歧義性

使用@Primary 標識“喜歡”

public interface Animal{
    
}
@Component
public class Dog implements Animal{}

@Component
public class Cat implements Animal{}

此時就不知道“愛好”哪隻動物了,需要進行指定首選的“愛好”動物

public class myHobby{
    
    @Autowired
    private Animal animal;
    
    public myHobby(Animal animal){
        this.animal = animal;
    }
}
  • 可以加上@Primary 指定首選
@Component
@Primary
public class Cat implements Animal{}
  • 如果使用xml創建bean
<bean id = "cat" class = "com.zexing.Cat" primary = "true">

使用@Qualifier 標識限定詞

  • 當有多個@Primary首選bean, 或者使用@Qualifier 代替其來指定 bean裝配。
public class myHobby{
    
    @Autowired
    @Qualifier("cat")
    private Animal animal;
    
    public myHobby(Animal animal){
        this.animal = animal;
    }
}

這裏@Qualifier(“cat”)的cat是spring 給定的默認限定符,即與 bean 的ID相同。
當然可以給該限定符重命名,在組件類上進行設置。

@Component
@Qualifier("cute")
public class Cat implements Animal{}

這裏的@Qualifier(“cute”)可以描述爲該bean的特徵,即“可愛的動物”。
還有一個重點,就是這樣做更多的是爲了解除限定詞與類名的緊耦合,避免類名的重構導致限定符的失效

public class myHobby{
    
    @Autowired
    @Qualifier("cute")
    private Animal animal;
    
    public myHobby(Animal animal){
        this.animal = animal;
    }
}

當然我們可以認爲 Dog 也具有“cute” 的屬性,這時我們不能使用兩個@Qualifier,添加更多屬性來區分它們。(PS:不允許出現相同類型的多個註解)

  • 使用自定義新的註解

    如 @Cute 來代替 @Qualifier(“cute”)
@Target({ElementType.TYPE,ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cute {
}

interface @Red

@Target({ElementType.TYPE,ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Red {
}

interface @Black

@Target({ElementType.TYPE,ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Black {
}

所以cat 的組件類如下

@Component
@Cute
@Red
public class Cat implements Animal {
}

“我的愛好動物”是 cat

public class myHobby{
    
    @Autowired
    @Cute
    @Red
    private Animal animal;
    
    public myHobby(Animal animal){
        this.animal = animal;
    }
}

參考文章 Spring 註解實現Bean依賴注入之@Qualifier

bean的作用域

運行時屬性注入

注入外部源的值 @PropertySource

student.java

public class Student {

    private String name;
    private String sex ;

    public Student(String name,String sex){
        this.name = name;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public String getSex() {
        return sex;
    }
}
  1. 傳統的屬性注入,用的是hard code的方式
    @Bean(name = "Mike")
    public Student student(){
        return new Student("Mike","male");
    }
  1. 使用@PropertySource,同Environment對象取出屬性值(PS:屬性文件會加載到Environment對象中)

app.properties

stu.name=jack
stu.sex=male

StudentCofig.java

@Configuration
@PropertySource("classpath:com/zexing/propertySource/app.properties")
public class StudentCofig {

    @Autowired
    Environment environment;

    @Bean(name = "Jack")
    public Student student1(){return new Student(environment.getProperty("stu.name"),environment.getProperty("stu.sex"));}

    @Bean(name = "Mike")
    public Student student(){
        return new Student("Mike","male");
    }
    
}

Environment 對象的方法

  • getProperty(String key, String defaultValue) 檢索屬性值,null值或者不存在則使用默認值
  • getProperty(String key, Class targetType) 將String類型的檢索值轉成期望的對象類型
  • getProperty(String key, Class targetType, T defaultValue) 檢索值轉化和設置默認值
  • containsProperty(String) 判斷屬性值是否存在
  1. 使用佔位符

    xml文件配置加載屬性文件
<context:property-placeholder
            location="classpath*:com/zexing/propertySource/app.properties" />
    <bean id="Jack1"
          class="com.zexing.propertySource.Student"
          c:name="${stu.name}"
          c:sex="${stu.sex}"/>

測試

    @Test
    public void setStuWithXml(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:/com/zexing/propertySource/app.xml");
        Student jack = (Student) applicationContext.getBean("Jack1");
        assertEquals("jack",jack.getName());
    }

【TODO】spring表達式語言SpEL

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章