zoukankan      html  css  js  c++  java
  • Spring装配Bean之组件扫描和自动装配

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

    • 组件扫描:Spring会自动发现应用上下文中所创建的bean。
    • 自动装配:Spring自动满足bean之间的依赖。

    案例:音响系统的组件。首先为CD创建CompactDisc接口及实现类,Spring会发现它并将其创建为一个bean。然后,会创建一个CDPlayer类,让Spring发现它,并将CompactDisc bean注入进来。

    创建CompactDisc接口:

    package soundsystem;
    
    public interface CompactDisc {
      void play();
    }
    

    实现CompactDisc接口:

    package soundsystem;
    import org.springframework.stereotype.Component;
    
    @Component
    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);
      }
     
    }
    

    在SgtPeppers类上使用了 @Component注解,这个注解表明该类会作为组件类,并告知Spring要为这个类创建bean,不需要显示配置SgtPeppers bean。
    不过组件扫描默认是不开启的。我们需要显示配置一下Spring,从而命令Spring去寻找带有 @Component注解的类,并创建bean。

    显示配置Spring包括Java和XML两种方式,通过Java启用组件扫描:

    package soundsystem;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan
    public class CDPlayerConfig { 
    }
    

    注意,类CDPlayerConfig通过Java代码定义了Spring的装配规则,但是可以看出并没有显示地声明任何bean,只不过它使用了 @ComponentScan注解,这个注解能够在Spring中启用组件扫描。
    如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包。因为CDPlayerConfig位于sound system包中,因此Spring默认将会扫描这个包以及这个包下的所有子包,查找所有带有 @Component注解的类。这样的话,SgtPeppers类就会被自动创建一个bean。

    通过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";
      xmlns:c="http://www.springframework.org/schema/c";
      xmlns:p="http://www.springframework.org/schema/p";
      xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd">;
    
      <context:component-scan base-package="soundsystem" />
    
    </beans>
    

    context:component-scan元素会有与 @ComponentScan相对应的属性和子元素。

    测试组件扫描能够发现CompactDisc:

    package soundsystem;
    
    import static org.junit.Assert.*;
    
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=CDPlayerConfig.class)
    public class CDPlayerTest {
    
      @Rule
      public final StandardOutputStreamLog log = new StandardOutputStreamLog();
      
      @Autowired
      private CompactDisc cd;
      
      @Test
      public void cdShouldNotBeNull() {
        assertNotNull(cd);
      }
    
    }
    

    CDPlayerTest使用了Spring的SpringJUnit4ClassRunner,以便在测试开始的时候自动创建Spring的应用上下文。注解ContextConfiguration会告诉它需要在CDPlayerConfig类中加载配置。因为CDPlayerConfig类中包含了 @ComponentScan,因此最终的应用上下文应该包含CompactDisc bean。
    测试方法断言cd属性部位null。如果不为null。就意味着Spring能发现CompactDisc类,并自动在Spring上下文中创建为bean并注入到测试代码中。

    为组件扫描的bean命名
    Spring应用上下文中所有的bean都会给定一个ID。默认bean命名为类名的第一个字母变为小写,上面的SgtPeppers bean指定的ID为sgtPeppers。
    如果想要指定bean ID,可以将ID值传递给 @Component注解。如下:

    @Component("lonelyHeartsClub")
    public class SgtPeppers implements CompactDisc {
     
    }
    

    设置组件扫描的基础包
    @Component注解没有设置任何属性的情况下,按照默认规则,Spring会以配置类所在的包作为基础包来扫描组件。但是如果想扫描不同的包,需要做的就是
    @Component的value属性中指名包的名称:

    @Configuration
    @ComponentScan("soundsystem")
    public class CDPlayerConfig { 
    }
    

    如果想更加清晰的表明设置的基础包,可以通过设置basePackages属性:

    @Configuration
    @ComponentScan(basePackages="soundsystem")
    public class CDPlayerConfig { 
    }
    

    同时basePackages支持多个基础包的设置,属性设置为数组即可:

    @Configuration
    @ComponentScan(basePackages={"soundsystem", "voice"})
    public class CDPlayerConfig { 
    }
    

    另外还提供一种方法,可以指定包中所含的类或接口:

    @Configuration
    @ComponentScan(basePackegeClasses={CDPlayer.class, DVDPlayer.class})
    public class CDPlayerConfig { 
    }
    

    通过为bean添加注解实现自动装配
    自动装配就是让Spring自动满足bean依赖的一种方式,在满足依赖的过程中,会在Spring的上下文中寻找匹配一个bean需求的其他bean。为了声明要进行自动装配,我们可以借助Spring的 @Autowried注解。
    比如说CDPlayer类,它在构造器上添加了 @Autowried注解,这表明当创建CDPlayer bean的时候,会通过这个构造器来进行实例化并且会传入一个可设置给CompactDisc类型的bean。

    package soundsystem;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class CDPlayer implements MediaPlayer {
      private CompactDisc cd;
    
      @Autowired
      public CDPlayer(CompactDisc cd) {
        this.cd = cd;
      }
    
      public void play() {
        cd.play();
      }
    
    }
    

    @Autowried注解不仅能够用在构造器上,还能用在Setter方法上。

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

    事实上,@Autowried注解可以用在类的任何方法上去引入依赖的bean,Spring都会尝试满足方法参数上所声明的依赖。
    如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常。为了避免出现异常,可以将 @Autowried的required属性设置为false:

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

    设置以后,会尝试自动装配,但是如果没有匹配的bean,Spring默认会处于未装配的状态。但是把required设置为false时,需要谨慎对待,如果代码中没有进行null检查的话,建议不使用,不然就会出现NullPointerException异常。

    验证自动装配
    前面我们的CDPlayerTest测试类,实现了自动装配CompactDisc,现在我们借助CDPlayer bean播放CD,表现出依赖的自动装配:

    package soundsystem;
    
    import static org.junit.Assert.*;
    
    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.contrib.java.lang.system.StandardOutputStreamLog;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=CDPlayerConfig.class)
    public class CDPlayerTest {
    
      @Rule
      public final StandardOutputStreamLog log = new StandardOutputStreamLog();
    
      @Autowired
      private MediaPlayer player;
      
      @Autowired
      private CompactDisc cd;
      
      @Test
      public void cdShouldNotBeNull() {
        assertNotNull(cd);
      }
    
      @Test
      public void play() {
        player.play();
        assertEquals(
            "Playing Sgt. Pepper's Lonely Hearts Club Band by The Beatles
    ", 
            log.getLog());
      }
    
    }
    

    现在除了注入CompactDisc,还将CDPlayer bean注入到测试代码的player成员变量中。

    总结一下,自动装配bean的过程:
    一、把需要被扫描的类,添加 @Component注解,使它能够被Spring自动发现。
    二、通过显示的设置Java代码 @ComponentScan注解或XML配置,让Spring开启组件扫描,并将扫描的结果类创建bean。
    三、@Autowried注解能偶实现bean的自动装配,实现依赖注入。

    转载请注明出处。
    作者:wuxiwei
    出处:http://www.cnblogs.com/wxw16/p/7704204.html

  • 相关阅读:
    627. Swap Salary
    176. Second Highest Salary
    596. Classes More Than 5 Students
    183. Customers Who Never Order
    181. Employees Earning More Than Their Managers
    182. Duplicate Emails
    175. Combine Two Tables
    620. Not Boring Movies
    595. Big Countries
    HDU 6034 Balala Power! (贪心+坑题)
  • 原文地址:https://www.cnblogs.com/wxw16/p/7704204.html
Copyright © 2011-2022 走看看