SpringBean 配置方式


SpringBean 配置方式_第1张图片


上篇文章介绍的IOC的理念与优点,这一章我们介绍如何将自己开发的Bean装配到Spring IOC容器中。

Spring 配置3种方式

  • 在XML文件中显式配置

  • 在Java 接口实现配置

  • 隐式Bean 的发现机制和自动装配原则

Spring 如何选择配置?

这方面,并没有唯一的正确答案。你所做出的选择必须要适合你和你的项目。而且,谁说我们只能选择其中的一种方案呢?Spring的配置风格是可以互相搭配的,所以你可以选择使用XML装配一些bean,使用Spring基于Java的配置(JavaConfig)来装配另一些bean,而将剩余的 bean让Spring去自动发现。 

装配方式的优先级

在现实的工作中,这 3 种方式都会被用到,并且在学习和工作之中常常混合使用,所以这里给出一些关于这 3 种优先级的建议:

隐式Bean的发现机制和自动装配原则

首选自动装配机制,显示配置越少越好。

优点:减少程序开发者的决定权,简单又不失灵活。

Java 的接口和类中实现配置

在没有办法使用自动装配原则情况,我们考虑此类方法。

优点:减少xml配置文件,也更为容易。

xml文件配置

最后选择xml文件配置。

优点:简单易懂

典型场景:

当使用三方类时,并不是我们开发,也无法修改代码,这个时候通过XML方式配置使用。


自动化装配Bean


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

  • 组件扫描(component scaning)   

  • 自动装配(autowing)

组件扫描

Spring 会自动发现应用上下文所创建的Bean。

自动装配(autowing)

Spring 自动满足Bean之间的依赖。组件扫描和自动装配组合在一起就能发挥出强大的威力,它们能够将你的显式配置降低到最少。

 代码实现

在这个MP3和流式媒体音乐的时代,磁带显得陈旧,随着以物理载体方式越来越少。尽管如此,磁带为我们阐述DI如何运行提供一个很好的样例。如果不将磁带放入磁带播放器中,那么磁带其实没有太大用处,所有可以说磁带依赖于磁带播放器。

磁带接口 

public interface Tape {

    void play();
}

熊猫播放器实现类

@Component
public class PandaPlayer implements Tape {

private String singer = "周杰伦";

private String songName = "双截棍";

public void play() {
    System.out.println("开始播放:"+singer+"的"+songName);
}

}

配置类

@Configuration
@ComponentScan
public class TapeConfig {

}

测试类

@RunWith(SpringJUnit4ClassRunner.class)
 // 自动装配的配置
 @ContextConfiguration(classes = TapeConfig.class)
 public class PlayerTest {

// 1、通过扫描包的方式实现装配bean,使用@Component注解或@Named 注解进行配置
@Autowired 
private Tape tape;

@Test 
public void player(){ 
    assertNotNull(tape); tape.play();
}
}


测试结果

开始播放:周杰伦的双截棍


如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包。因为TapeConfig类位于com.automatic.service包中,因此Spring 将会扫描这个包以及这个包下的所有子包,查找带有@Component注解的类。这样的话,就能发现Tape,并且会在Spring中自动为 其创建一个bean。




自动装配

简单来说,自动装配就是让Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在Spring应用上下文中寻找匹配某个bean需求的其他bean。为了声明要进行自动装配,我们可以借助Spring的@Autowired注解。


使用@Autowired是放到构造方法中,@Autowired注解不仅能够用在构造器上,还能用在属性的Setter方法上或者普通方法中。 


Player播放接口

public interface Player {

void play();
}


索尼播放器实现类

@Component
public class SonyPlayer implements Player {

private Tape tape;

@Autowired
public SonyPlayer (Tape tape) {
    this.tape = tape;
}

public void play() {
    System.out.println("----start----");
    tape.play();
    System.out.println("----end----");
}

}

测试方法

@Autowired
 private Player player;

 @Test public void player(){
      assertNotNull(player); 
      player.play(); 
}  


测试结果

 ----start----
 开始播放:周杰伦的双截棍
 ----end----

 



通过Java代码装配Bean


尽管在很多场景下通过组件扫描和自动装配实现Spring的自动化配置是更为推荐的方式,但有时候自动化配置的方案行不通,因此需要明确配置Spring。比如说,你想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加@Component和@Autowired注解的,因此就不能使用自动化装配的方案了。


下面的例子是参考《Sring实战第四版》,觉得比较容易理解:

CD播放类

public class CDPlayer {

private CompactDisc cd;

public void play() {
    cd.play();
}
// 省略setget方法
}

播放接口

public interface CompactDisc {

void play();
}

歌曲

 public class HardDaysNight  implements CompactDisc {

private String title = "Hard. DaysNight's Lonely Hearts Club Band";
private String artist = "The Hard";

public void play() {
    System.out.println("Playing " + title + " by " + artist);
}


}

public class Revolver implements CompactDisc {

private String title = "Revolver. Revolver's Lonely Hearts Club Band";
private String artist = "The Revolver";

public void play() {
    System.out.println("Playing " + title + " by " + artist);
}
}

public class SgtPeppers implements CompactDisc {

private String title = "Sgt. Pepper's Lonely Hearts Club Band";
private String artist = "The Beatles";

public void play() {
    System.out.println("Playing " + title + " by " + artist);
}
}

public class WhiteAlbum  implements CompactDisc {

private String title = "White. Album's Lonely Hearts Club Band";
private String artist = "The White";

public void play() {
    System.out.println("Playing " + title + " by " + artist);
}
}

重点在这里Config配置类

 /*
 * Spring 的组件扫描默认是不启用的,需要显式配置启用组件扫描去寻找被 
 @Component 注解修饰的组件类,并为其创建 bean 实例。
 * */
 /*
  * 标记类 CDPlayerConfig 是 Spring 的配置类,通过 java 代码定义 
  Spring 的装配规则。
  * 该类应该包含在Spring应用上下文中如何创建bean的细节。
  * */
@Configuration
public class CDPlayerConfig {


    /*
    * 要在 JavaConfig 中声明 bean ,我们需要编写一个方法,这个方法会创建所需类型的实例,然后给这个方法添加 @Bean 注解。
    *
    * @Bean 注解会告诉 Spring 这个方法将会返回一个对象,该对象要注册为 Spring 应用上下文中的 bean 。
    * 方法体中包含了最终产生 bean 实例的逻辑。
    *
    * 默认,bean 的 ID 和方法名是一样的,如下 bean 的 ID 为 sgtPeppers 。
    * 如果想手动为 bean 指定一个 ID ,可以使用 @Bean 的 name 属性,如:
    *   @Bean(name="lonelyHeartsClubBand")
    * */
    @Bean
    public CompactDisc sgtPeppers() {
        return new SgtPeppers();
    }

    // 这里是使用 Java 创建 bean,因此我们可以发挥 Java 提供的所有功能,只要最终生成一个 CompactDisc 实例即可。例如:
    @Bean
    public CompactDisc randomBeatlesCD() {
        CompactDisc cd;
        int choice = (int) Math.floor(Math.random() * 4);
        switch (choice) {
            case 1:
                cd = new SgtPeppers();
                break;
            case 2:
                cd = new WhiteAlbum();
                break;
            case 3:
                cd = new HardDaysNight();
                break;
            default:
                cd = new Revolver();
                break;
        }
        return cd;
    }

    /*
    * Spring 装配方式一:
    * 在JavaConfig中装配bean的最简单方式就是引用创建bean的方法。
    * */
    @Bean
    public CDPlayer cdPlayer() {
  //            return new CDPlayer(sgtPeppers());
        return new CDPlayer(new WhiteAlbum());
    }

    /*
    * Spring 装配方式二:
    * 当 Spring 调用 cdPlayer() 创建 CDPlayer bean 的时候,它会自动装配一个 CompactDisc 到配置方法之中。
    * 然后,方法体就可以按照合适的方式来使用它。
    *
    * 通过这种方式引用其他的 bean 通常是最佳的选择,因为它不会要求将 CompactDisc 声明到同一个配置类之中。
    * 在这里甚至没有要求 CompactDisc 必须要在 JavaConfig 中声明,
    * 实际上它可以通过组件扫描功能自动发现或者通过 XML 来进行配置。
    * 你可以将配置分散到多个配置类、XML 文件以及自动扫描和装配 bean 之中,
    * 只要功能完整健全即可。不管 CompactDisc 是采用什么方式创建出来的,
    * Spring 都会将其传入到配置方法中,并用来创建 CDPlayer bean 。
    *
    * 当配置类中有多个同类型的 bean 时,此时可以使用 @Qualifier 注解来指定参数注入的是哪一个具体的 bean 。
    * */
    @Bean
    public CDPlayer cdPlayer(@Qualifier("randomBeatlesCD") CompactDisc compactDisc) {
        return new CDPlayer(compactDisc);
    }

    /*
    * 我们也可以采用属性赋值的方式来注入依赖值,这里所存在的可能性仅仅受到Java语言的限制。
    * */
  //        @Bean
//        public CDPlayer cdPlayer(@Qualifier("sgtPeppers") 
  CompactDisc compactDisc) {
  //            CDPlayer cdPlayer = new CDPlayer();
 //            cdPlayer.setCd(compactDisc);
 //            return cdPlayer;
  //        }
   }

测试方法

 @Autowired
 private CDPlayer cdPlayer;

 @Test
 public void cdShouldNotBeNull() {
    assertNotNull(cdPlayer);
    cdPlayer.play();
 }

测试结果

 Playing Revolver. Revolver's Lonely Hearts Club Band by The Revolver

每次运行的结果是不同,因为randomBeatlesCD()方法。




XML文件装配Bean

使用xml文件进行配置,配置比较简单易懂。

public class ComplexAssembly {

private Long id;

private List list;

private Map map;

private Properties properties;

private Set set;

private String[] array;

// 省略setget方法
}


这个 Bean 没有任何的实际意义,只是为了介绍如何装配这些常用的集合类:

xml文件







    
        value-list-1
        value-list-2
        value-list-3
    





    
        
        
        
    





    
        value-prop-1
        value-prop-2
        value-prop-3
    





    
        value-set-1
        value-set-2
        value-set-3
    





    
        value-array-1
        value-array-2
        value-array-3
    



测试方法

     @Test
 public void getXmlComplexAssembly() {
     ApplicationContext context = new ClassPathXmlApplicationContext(
                new String[]{"applicationContext.xml"}
                );

     ComplexAssembly complexAssembly = (ComplexAssembly) context.getBean("complexAssembly");
     System.out.println(complexAssembly.getId());
     System.out.println(complexAssembly.getMap().get("key1"));

 }

测试结果

  1
  value-key-1


总结:
      List 属性为对应的  元素进行装配,然后通过多个  元素设值
      Map 属性为对应的  元素进行装配,然后通过多个  元素设值, 只是 entry 包含一个键值对(key-value)的设置
      Properties 属性为对应的  元素进行装配,通过多个  元素设值,只是 properties 元素有一个必填属性 key ,然后可以设置值
      Set 属性为对应的  元素进行装配,然后通过多个  元素设值
 对于数组而言,可以使用  设置值,然后通过多个  元素设值。




命名空间装配


除了上述的配置之外, Spring 还提供了对应的命名空间的定义,只是在使用命名空间的时候要先引入对应的命名空间和 XML 模式(XSD)文件。

  • p-命名空间

  • c-命名空间

  • util-命名空间




p标签

SpringBean 配置方式_第2张图片

使用p命名空间需要添加

                        
  class="com.xml.service.ComplexAssembly">
    
 


c标签

SpringBean 配置方式_第3张图片


通过这个类举例子

 package pojo;
 public class Student { 
   int id; 
   String name;
  public Student(int id, String name) 
  { 
   this.id = id; this.name = name; 

  } 
   // setter and getter 
}

 在 c-命名空间和模式声明之后,我们就可以使用它来声明构造器参数了:

 
 
   
    


 
       c:id="2" c:name="学生2"/>




util标签

SpringBean 配置方式_第4张图片




    
    





   
   
 

 只是 util-命名空间中的多个元素之一,下表提供了 util-命名空间提供的所有元素:

SpringBean 配置方式_第5张图片

Spring 作用域

SpringBean 配置方式_第6张图片

总  结


在Spring中装配bean的三种主要方式:自动化配置、基于Java的显式配置以及基于XML的显式配置。不管你采用什么方式,这些技术都描述了Spring应用中的组件以及这些组件之间的关系。 


本文中源码:

https://github.com/xiaonongOne/spring-bean


下面是微信公众号二维码,欢迎来骚扰。

SpringBean 配置方式_第7张图片

你可能感兴趣的:(SpringBean 配置方式)