搜索
您的当前位置:首页正文

Spring学习(二)搞定依赖注入(DI)

来源:二三娱乐
Spring

导语:

依赖注入(DI)是Spring的最基本要素,而DI的本质是装配(wiring)。
装配就是创建应用对象之间协作关系的行为。

spring三种主要的装配bean机制:

  • 在XML中进行显式配置

  • 在Java中进行显式配置

  • 隐式的bean发现机制和自动装配

一、在XML中进行显式配置

xml配置bean,意味着要创建一个XML文件,并且要以<beans>元素为根。

  1. 声明bean的方式(使用<bean>元素并指定class属性):
<bean class="com.du.Hello"/>
因为没有明确给定id,所以该bean的id会是“com.du.Hello#0”,如果声明了另一个Hello,那么它自动得到的id将会是“com.du.Hello#1”。
  1. 借助构造器注入初始化bean

在xml中声明DI时,有两种基本的配置方案:

  • <constructor-arg>元素
  • 使用Spring3.0所引入的c-命名空间


    通过Spring的c-命名空间将bean引用注入到构造器参数中

c-命名空间是在Spring 3.0中引入的, 它是在XML中更为简洁地描述构造器参数的方式。 要使用它的话, 必须要在XML的顶部声明其模式, 如下所示:

声明c命名空间

2.1构造器注入bean引用

使用ref属性来引用其它的bean
 //<constructor-arg>元素
<bean id="cdPlayer" class="soundsystem.CDPlayer">
    <constructor-arg ref="compactDisc" />
 </bean>
//c-命名空间 ,有4种方式
1. 
<bean id="cdPlayer" class="soundsystem.CDPlayer"
        c:cd-ref="compactDisc" />
</beans>
2. 
<bean id="cdPlayer" class="soundsystem.CDPlayer"
        c:_-ref="compactDisc" />
</beans>
3. 
<bean id="cdPlayer" class="soundsystem.CDPlayer"
        c:_0-ref="compactDisc" />
</beans>
4.
<bean id="cdPlayer" class="soundsystem.CDPlayer"
        c:_1-ref="compactDisc" />
</beans>

2.2将字面量注入到构造器中

 //<constructor-arg>元素
 <bean id="compactDisc"
        class="soundsystem.BlankDisc">
    <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
    <constructor-arg value="The Beatles" />
 </bean>
//c-命名空间
 引用构造器参数的名字引入字面量
 <bean id="compactDisc" class="soundsystem.BlankDisc"
        c:_title="Sgt. Pepper's Lonely Hearts Club Band" 
        c:_artist="The Beatles" />
 通过参数索引装配相同的字面量值
<bean id="compactDisc" class="soundsystem.BlankDisc"
        c:_0="Sgt. Pepper's Lonely Hearts Club Band" 
        c:_1="The Beatles" />
如果只有一个构造器参数的话,可以这样声明字面量值:
<bean id="cdPlayer" class="soundsystem.CDPlayer"
         c:_="Sgt. Pepper's Lonely Hearts Club Band"  />

2.3装配集合

  • 使用<list>元素声明构造器属性
使用<value>元素指定列表中的元素值
 <bean id="compactDisc" class="soundsystem.collections.BlankDisc">
    <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
    <constructor-arg value="The Beatles" />
    <constructor-arg>
      <list>
        <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>
      </list>
    </constructor-arg>
  </bean>
使用<ref>元素实现bean引用列表的装配。
 <bean id="compactDisc" class="soundsystem.collections.BlankDisc">
    <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
    <constructor-arg value="The Beatles" />
    <constructor-arg>
      <list>
        <ref bean="" />
        <ref bean="" />
    <ref bean="" />
    ...
      </list>
    </constructor-arg>
  </bean>
  • 也可以使用<set>元素:
    <set>和<list>元素的区别不大, 其中最重要的不同在于当Spring创建要装配的集合时, 所创建的是java.util.Set还是java.util.List。 如果是Set的话, 所有重复的值都会被忽略掉, 存放顺序也不会得以保证。 不过无论在哪种情况下, <set>或<list>都可以用来装配List、 Set甚至数组。

  • 使用c-命名空间的属性无法实现装配集合的功能,只能使用<constructor-arg>

  1. 设置属性
  • <property>元素
  • p-命名空间
    为了启用p-命名空间, 必须要在XML文件中与其他的命名空间一起对其进行声明:


    声明p命名空间
  • 装配bean引用:
//使用<property>元素:
<bean id="cdPlayer" class="soundsystem.properties.CDPlayer">
 <property name="compactDisc" ref="compactDisc" />
</bean>
//使用p-命名空间:
<bean id="cdPlayer"
       class="soundsystem.properties.CDPlayer"
       p:compactDisc-ref="compactDisc" />
  • 装配字面量:
//使用<property>元素:
<property name="artist" value="The Beatles" />
//使用p-命名空间:
p:artist="The Beatles"
  • 使用<list>元素设置集合属性
//使用<property>元素:
<bean id="compactDisc"
        class="soundsystem.properties.BlankDisc">
    <property name="tracks">
      <list>
        <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>
      </list>
    </property>
  </bean>

但需要注意的是, 我们不能使用p-命名空间来装配集合, 没有便利的方式使用p-命名空间来指定一个值(或bean引用) 的列表。 但是, 我们可以使用Spring util-命名空间中的一些功能来简化BlankDiscbean。
首先, 需要在XML中声明util-命名空间及其模式:


声明util命名空间
//使用util-命名空间功能之一<util:list>元素来装配集合:
<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的属性中:

  • 使用<property>元素:
    <property name="tracks" ref="trackList" />
  • 使用p-命名空间
    p:tracks-ref="trackList"

<util:list>只是util-命名空间中的多个元素之一,在需要的时候,可能会用到util-命名空间中的其它部分成员。
Spring util-命名空间中的元素:

<util:constant> 引用某个类型的public static域, 并将其暴露为bean
util:list 创建一个java.util.List类型的bean, 其中包含值或引用
util:map 创建一个java.util.Map类型的bean, 其中包含值或引用
util:properties 创建一个java.util.Properties类型的bean
util:property-path 引用一个bean的属性(或内嵌属性) , 并将其暴露为bean
util:set 创建一个java.util.Set类型的bean, 其中包含值或引用

二、在Java类中进行显式配置

创建JavaConfig类显示配置Spring:关键在于为其添加 @Configuration 注解。它包含在Spring应用上下文中如何创建bean的细节。

  • 创建配置类
    创建JavaConfig类的关键在于为其添加 @Configuration注解, @Configuration注解表明这个类是一个配置类, 该类应该包含在Spring应用上下文中如何创建bean的细节。
  • 声明简单的bean
    要在JavaConfig中声明bean, 我们需要编写一个方法, 这个方法会创建所需类型的实例, 然后给这个方法添加 @Bean注解。 比方说, 下面的代码声明了CompactDisc bean:
     @Bean
      public CompactDisc compactDisc() {
        return new SgtPeppers();
      }
    
    @Bean注解会告诉Spring这个方法将会返回一个对象, 该对象要注册为Spring应用上下文中的bean。 方法体中包含了最终产生bean实例的逻辑。默认情况下, bean的ID与带有 @Bean注解的方法名是一样的(compactDisc)。可以通过name属性指定一个不同的名字:
      @Bean(name="name1")
      public CompactDisc compactDisc() {
        return new SgtPeppers();
      }
    
    借助JavaConfig实现注入
     @Bean
     public CompactDisc compactDisc() {
        return new SgtPeppers();
      }
    
    此时spring容器中已经存在CompactDisc Bean,可以根据compactDisc()方法将其注入到CDPlayer中:
      @Bean
      public CDPlayer cdPlayer() {
        return new CDPlayer(compactDisc());
    }
    
    也可以将spring容器中存在的任意CompactDisc Bean注入到CDPlayer中:
      @Bean
      public CDPlayer cdPlayer(CompactDisc compactDisc) {
        return new CDPlayer(compactDisc);
     }
    

三、自动化装配bean

spring从两个角度来实现自动化装配:

  • 组件扫描(component scanning) : Spring会自动发现应用上下文中所创建的bean。
  • 自动装配(autowiring) : Spring自动满足bean之间的依赖。
  1. 创建可被发现的bean
public interface CompactDisc {
 void play();
}
@Component
public class SgtPeppers implements CompactDisc {
 ...
}
spring根据类名为SgtPeppersbean设置一个ID为sgtPeppers(将类名的第一个字母变为小写)。如果想为这个bean设置不同的ID:
@Component("name")
public class SgtPeppers implements CompactDisc {
   ...
}
这就将这个bean的ID标记为了name。
  1. 通过为bean添加注解实现自动装配
    简单来说, 自动装配就是让Spring自动满足bean依赖的一种方法, 在满足依赖的过程中, 会在Spring应用上下文中寻找匹配某个bean需求的其他bean。 为了声明要进行自动装配, 我们可以借助Spring的@Autowired注解。
@Component
public class CDPlayer implements MediaPlayer {
  private CompactDisc cd;
  public CDPlayer() {
}
  @Autowired
  public CDPlayer(CompactDisc cd) {
    this.cd = cd;
  }
  public void play() {
    cd.play();
  }
}

@Autowired注解不仅能够用在构造器上, 还能用在属性的Setter方法上。 比如说, 如果CDPlayer有一个setCompactDisc()方法, 那么可以采用如下的注解形式进行自动装配:

  @Autowired
  public void setCompactDisc(CompactDisc cd) {
    this.cd = cd;
  }

实际上, Setter方法并没有什么特殊之处。 @Autowired注解可以用在类的任何方法上。
在自动装配中, Spring同时支持@Inject和@Autowired。 尽管@Inject和@Autowired之间有着一些细微的差别, 但是在大多数场景下, 它们都是可以互相替换的。

  1. 设置组件扫描
  • 通过Java代码
//如果没有其他配置的话, @ComponentScan默认会扫描与配置类相同的包。 
@Configuration
@ComponentScan
public class CDPlayerConfig { 
}
//可以指定包
@Configuration
@ComponentScan("soundsystem")
public class CDPlayerConfig { 
}
  • 使用XML
<context:component-scan base-package="packagename" />

四、混合配置

  • 两个java配置类混合
    @Configuration
    @Import(CDPlayerConfig.class,CDConfig.class)
    public class SoundSystemConfig {}
    
  • 一个java配置类与xml中配置的bean混合
    @Configuration
    @Import(CDPlayerConfig.class)
    @ImportResource("classpath:cd-config.xml")
    public class SoundSystemConfig {}
    
  • 以上两种方式都是采用java类配置的,还可以在xml中混合配置:
    <bean class="soundsystem.CDConfig" />
    <import resource="cdplayer-config.xml" />
    
Top