美文网首页java
Spring装配bean的三种方式

Spring装配bean的三种方式

作者: _Nevermore | 来源:发表于2017-06-01 19:44 被阅读450次

    一.自动化装配bean

    1.1 创建可被发现的bean
    @Component
    这个简单的注解表明该类会作为组件类,并告知Spring要为这个类创建bean
    

    启用组建扫描

    注:@configuration:表明是一个配置类

    @ComponentScan
    public class CDPlayerConfig{
    }   
     在XML中 <context: componnet-scan base-package="soundsystem">
    
    1.2为组件扫描的bean命名

    如果没有个bean设置ID,Spring会根据类名为其指定一个ID,默认名字就是把类名的第一个字母变为小写.

    @Component("lonelyHeartsClub") //设置期望的ID
    public class SgtPeppers implements CompactDisc{
    }
    

    另外还一种为bean命名的方式,使用Java依赖注入规范中所提供的@Named注解来为bean设置ID

    @Named("lonelyHeartsClub")
    public class SgtPeppers implements CompactDisc{
    }
    
    1.3设置组件扫描的基础包
    //直接在value属性中指明包的名称
    @Configuration
    @ComponentScan("soundsystem")
    public class CDPlayerConfig{}
    
    //通过basePackages属性配置
    @Configuration
    @ComponentScan(basePackages="soundsystem")
    public class CDPlayerConfig{}
    
    //设置多个基础包,用数组表示
    @Configuration
    @ComponentScan(basePackages={"soundsystem","video"})
    public class CDPlayerConfig{}
    
    //基础包以String类型表示是不安全的,如果重构代码的话,指定的基础包可能会出现错误,用指定为包中所包含的类或接口的方法
    @Configuration
    @ComponentScan(basePackageClasses={CDPlayer.class,DVDPlayer.class})
    public class CDPlayerConfig{}
    

    但是,很多对象会依赖其他对象才能完成任务,这样的话,我们需要有一种方法能够将组件扫描得到的bean和它们的依赖装配在一起,那就需要自动装配.

    1.4通过bean添加注解实现自动装配

    @Autowired

    @Component
    public class CDPlayer implements MediaPlayer{
      private CompactDisc cd;
    
      @Autowired//这表明当Spring创建CDPlayer bean的时候,会通过这个构造器来进行实例化并且会传入一个可设置给CompactDisc类型的bean.
      public CDPlayer(CompactDisc cd){//构造器
        this.cd = cd;
      }
    
      public void paly(){
        cd.paly();
      }
    }
    

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

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

    但是如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常,为了避免异常的出现,你可以将@Autowired的requied属性设置为false

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

    但是
    一,把required属性设置为false时,你需要谨慎对待,如果代码中没有进行null检查的话,这个处于未装配的属性有可能会出现空指针异常.
    二,如果有多个bean都能满足依赖关系的话,Spring将会抛出一个异常,表明没有明确指定要选择哪个bean进行自动装配,这个以后再讨论.

    @Autowired可以换成@Inject,@Inject注解来源于Java依赖注入规范,该规范同时还为我们定义了@Named注解.
    尽管@Inject和@Autowierd有细微的差别,但大多数场景下,它们都可以互换.
    

    二 通过Java代码装配bean

    有些情况下,比如说,要将第三方库的组件装配到你的应用中,就不能在它的类上添加@Component和@Autowired注解的,因此,就不能使用自动化装配的方案了.
    在这种情况下,就需要采用显示装配的方式.在进行显示配置有Java和XML两种方案.

    2.1创建配置类(JavaConfig类)
    @Configuration
    public class CDPlayerConfig{}
    //创建JavaConfig类的关键在于为其添加@Configruation注解,表明这是一个配置类
    
    2.2声明简单的bean
    @Bean
    public CompactDisc sgtPeppers(){
      return new SgtPeppers();
    }
    //@Bean注解会告诉Spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文的bean,默认情况下,
    bean的ID于带有@Bean注解的方法名一样,也可以重命名
    
    @Bean(name="lonelyHeartsClubBand")
    public CompactDisc sgtPeppers(){
      return new SgtPeppers();
    }
    
    2.3借助JavaConfig实现注入

    声明CompactDisc bean是非常简单,它自身没有其他依赖,但现在,我们需要声明CDPlayer bean,它依赖于CompactDisc,在JavaConfig中,如何将他们装配在一起呢?

    在JavaConfig中装配bean的最简单方式就是 引用创建bean的方法.

    @Bean
    public CDPlayer cdPlayer(){
      return new CDPlayer(sgtPeppers());
    }
    //因为sgtPeppers()方法上添加了@Bean注解,Spring将会拦截所有对它的调用,
    //并确保直接返回该方法创建的bean,而不是每次都对其进行实际的调用.
    

    默认情况下,Spring中的bean都是单例,所以,Spring会拦截对sgtPeppers()的调用并确保返回的是Spring所创建的bean,也就是Spring本身在调用sgtPeppers()时所创建的CompactDisc bean.

    如果调用方法来引用bean的方式有点困惑,也可以这么理解

    @Bean
    public CDPlayer cdPlayer(CompactDisc compactDisc){
      return new CDPlayer(compactDisc);
    }
    //在这里,cdPlayer()方法请求一个CompactDisc作为参数,当Springs调用cdPlayer()创建CDPlayer bean的时候,
    //它会自动装配一个CompactDisc到配置方法之中,然后方法体按照合适的方法来使用它.
    

    也可以通过Setter方法注入CompactDisc

    @Bean
    public CDPlayer cdPlayer(CompactDisc compactDisc){
      CDPlayer cdPlayer = new CDPlayer(compactDisc);
      cdPlayer.setCompactDisc(compactDisc);
      return cdPlayer;
    }
    

    三 通过XML装配bean

    3.1创建XML配置规范
    <?xml version="1.0" encoding="UTF-8">
    <beans xmlns="http://........"
                 xmlns:xsi="http://.....''>
      <!--  configuration details go here -->
    </beans>
    //借助Spring Tool Suite 创建XML配置文件
    
    3.2声明一个简单的<bean>
    <bean class="soundsystem.SgtPeppers" />
    //这里声明一个很简单的bean,因为没有明确给定ID,所以这个bean将会根据全限定类名来进行命名,
    //这里的bean的ID将会是"soundsystem.SgtPeppers#0".其中,"#0"是一个计数的形式,来区分相同类型的bean.
    
    //更好的方法是借助id属性
    <bean id="compactDisc" class="soundsystem.SgtPeppers" />
    
    //XML装配bean的缺点
    //1.当Spring发现这个<bean>元素时,它将会调用SgtPeppers的默认构造器来创建bean.在XML配置中,bean的创建显得更加被动
    //2.不如JavaConfig强大,在JavaConfig配置中,可以通过任何想象到的方法来创建bean实例(构造器,set方法等)
    //3.在简单的<bean>声明中,将bean的类型以字符串的形式设置在了class属性中,不能保证设置给class属性的值是真正的类
    //4.重命名了类,也会引起麻烦
    
    3.3借助构造器注入初始化bean

    有两种基本的配置方案可选择
    1.<constructor-arg>元素
    2.使用Spring3.0所引入的c-命名空间

    (1)构造器注入--bean引用
    <bean id="cdPlayer" class="soundsystem.CDPlayer">
      <constructor-arg ref="compactDisc">
    </bean>
    //当Spring遇到<bean>这个元素时,它会创建一个CDPlayer实例.<constructor-arg>元素会告知Spring要将
    //一个ID为compactDisc的bean引用传递到CDPlayer的构造器中.
    

    作为替代方案,也可以使用Spring的c-命名空间
    要在XML的顶部声明其模式

    <?xml version="1.0" encoding="UTF-8">
    <beans xmlns="http://........"
                xmlns:c="http://www.springframework.org/schema/c"
                 xmlns:xsi="http://.....''>
      <!--  configuration details go here -->
    </beans>
    

    然后可以使用它了

    <bean id="cdPlayer" class="soundsystem.CDPlayer"
       c:cd-ref="compactDisc">
    //"c:" 命名空间的前缀
    //"cd" 构造器参数名
    //"-ref"注入bean引用
    //"compactDisc" 要注入bean 的ID
    

    如果在优化构建的过程,将调试标志移除掉,那么这种方式可能无法正常执行.代替方案

    <bean id="cdPlayer" class="soundsystem.CDPlayer"
       c:_0-ref="compactDisc">
    //把参数名换成"0",也就是参数的索引,但XML中不允许数字作为属性的第一个字符,因此添加下划线"_"
    

    如果只有一个参数,根本不用去标示参数

    <bean id="cdPlayer" class="soundsystem.CDPlayer"
       c:_-ref="compactDisc">
    
    (2)将字面量注入到构造器中

    之前是将对象的引用装配到依赖于它们的其他对象之中,如果有时候,我们需要做的只是用一个字面量值来配置对象.为了阐述这点,创建CompactDisc的一个新的实现

    public class BlankDisc implements CompactDisc{
      private String title;
      private String artist;
      
      public BlandDisc(String title,String artist){
        this.title = title;
        this.artist = artist;
      }
    
      public void paly(){
        System.out.println("Playing"+title+"by"+artist);
      }
    
    }
    

    这个于SgtPeppers不同,它可以设置任意想要的title和artist,我们可以已有的SgtPeppers替换为这个类

    <bean id="compactDisc"
        class="soundysytem.BlankDisc">
      <constructor-arg value="Sgt.Peper's Lonely Hearts" />
      <constructor-arg value="The beatles"/>
    </bean>
    

    这里再次使用<constructor-arg>元素进行构造器参数的注入,但是没有使用ref属性来引用其他的bean,而是使用了value属性,通过该属性表明给定的值要以字面量的形式注入到构造器之中.

    如果要以c-命名空间,可以引用构造器参数名字

    <bean id="compactDisc"
        class="soundsystem.BlanDisc"
        c:_title="Sgt.Peper's Lonely Hearts"
        c:_artist="The beatles"/>
    </bean>
    

    可以看到,装配引用和装配字面量的区别在于去掉了-ref后缀,也可以这样通过参数索引

    <bean id="compactDisc"
        class="soundsystem.BlanDisc"
        c:_0="Sgt.Peper's Lonely Hearts"
        c:_1="The beatles"/>
    </bean>
    
    (3)装配集合
    <bean id="compactDisc"
        class="soundsystem.BlankDisc">
      <constructor-arg value="Sgt.Peper's Lonely Hearts" />
      <constructor-arg value="The beatles" />
      <constructor-arg>
        <list>
          <value>Sgt. Pepper's Lonely Heats</value>
          <value>With a Little Help</value>
          <value>Lucy in the Sky</value>
          <value>Getting Better</value>
          <value>Fixing a Hole</value>
        </list>
      </constructor-arg>
    </bean>
    

    也可以使用<ref>元素代替<value>,实现bean引用列表的装配
    假设你有一个Discography类,它的构造器如下

    public Discography(String artist,List<CompactDisc> cds){...}
    

    那么,可以采取如下的方式配置 Discography bean:

    <bean id="beatlesDiscography" class="soundsystem.Discography">
      <constructor-arg value="The Beatles" />
      <constructor-arg>
        <list>
          <ref bean="sgtPeppers" />
          <ref bean="whiteAlbum" />
          ...
        </lsit>
      </constructor-arg>
    

    也可以使用<set>元素,set不重复,不能保证顺序,list可以重复,保证顺序

    <bean id="compactDisc"
        class="soundsystem.BlankDisc">
      <constructor-arg value="Sgt.Peper's Lonely Hearts" />
      <constructor-arg value="The beatles" />
      <constructor-arg>
        <set>
          <value>Sgt. Pepper's Lonely Heats</value>
          <value>With a Little Help</value>
          <value>Lucy in the Sky</value>
          <value>Getting Better</value>
          <value>Fixing a Hole</value>
        </set>
      </constructor-arg>
    </bean>
    
    3.4设置属性

    使用Spring XML实现属性注入,假设属性注入的CDPlayer如下

    import soundsystem.CompactDisc;
    import soundsystem.MediaPlayer;
    
    public class CDPlayer implements MediaPlayer{
      private CompactDisc compactDisc;
    
      @Autowired
      public void setCompactDisc(CompactDisc compactDisc){
        this.compactDisc = compactDisc; 
      }
    
      public void paly(){
        compactDisc.play();
      }
    } 
    

    注入compactDisc属性

    <bean id="cdPlayer" class="soundsystem.CDPlayer">
        <property name="compactDisc" ref="compactDisc" />
    </bean>
    //通过ref引用了ID为compactDisc的bean,将其注入到compactDisc属性中(通过setCompactDisc()方法)
    

    使用p-命名空间,先声明

    <?xml version="1.0" encoding="UTF-8">
    <beans xmlns="http://........"
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:xsi="http://.....''>
      <!--  configuration details go here -->
    </beans>
    

    装配

    <bean id="cdPlayer" class="soundsystem.CDPlayer"
        p:compactDisc-ref="compactDisc" />
    </bean>
    //"p:" :前缀
    //前面的compactDisc: 属性名
    //-ref:  注入bean引用
    //后面的compactDisc: 所注入bean的ID
    
    (1)将字面量注入到属性中

    新的BlankDisc类如下

    public class BlankDisc implements CompactDisc{
    
      private String title;
      private String artist;
      private List<String> tracks;
    
       public void setTitel(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(){
          ....
        }
    }
    

    使用property元素的value属性实现装配

    <bean id="compactDisc"
          class="soundsystem.BlankDisc">
      <property name="title" value="Sgt.peper's loney hearts club" />
      <property name="artist" value="The Beatles" />
      <property name="tracks">
        <list>
          <value>Sgt.peper's loney hearts club</value>
          <value>loney hearts club</value>
          <value>hearts club</value>
          <value>club hearts</value>
          ...
        </list>
       </property>
    

    另一种可选方案就是 用p-命名空间的属性完成

    <bean id="compactDisc"
          class="soundsystem.BlankDisc"
          p:title="Sgt.peper's loney hearts club"
          p:artist="The Beatles">
      <property name="tracks">
        <list>
          <value>Sgt.peper's loney hearts club</value>
          <value>loney hearts club</value>
          <value>hearts club</value>
          <value>club hearts</value>
          ...
        </list>
       </property>
    

    但是,注意,不能用p-空间命名来装配集合,可以使用Spring util -命名空间的一些功能来简化BlankDisc bean
    首先,在XML中声明utli-命名空间及其模式

    <?xml version="1.0" encoding="UTF-8">
    <beans xmlns="http://........"
                xmlns:c="http://www.springframework.org/schema/c"
                xmlns:util="http://www.springframework.org/schema/util"
                 xmlns:xsi="http://.....''>
      <!--  configuration details go here -->
    </beans>
    

    util-命名空间所提供的功能之一就是<util:list>元素,它会创建一个列表的bean.

    <util:list id="trackList">
         <value>Sgt.peper's loney hearts club</value>
         <value>loney hearts club</value>
         <value>hearts club</value>
         <value>club hearts</value>
    </util:lsit>
    

    现在,我们能像使用其他的bean一样,把这个列表的bean注入到BlankDisc bean的tracks属性中

    <bean id="compactDisc"
               class = "soundsystem.BlankDisc"
               p:title="Sgt.pepers lonely hearts"
               p:artist="The Beatles"
               p:tracks-ref="trackList">
    
    

    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,其中包含值或引用
    
    导入和混合配置

    相关文章

      网友评论

        本文标题:Spring装配bean的三种方式

        本文链接:https://www.haomeiwen.com/subject/pspefxtx.html