Spring之装配Bean

0、Spring装配Bean的三种方式

       创建应用对象之间协作关系的行为通常称为装配(wiring),这也是依赖注入(DI)的本质。Spring提供了三种主要装配机制。

  • 在XML中进行显式配置。
  • 在Java中进行显式配置。
  • 隐式的bean发现机制和自动装配。

        Spring的配置 风格是可以互相搭配的,所以你可以选择使用XML装配一些bean,使用Spring基于Java的配置(JavaConfig) 来装配另一些bean,而将剩余的bean让Spring去自动发现。即便如此,我的建议是尽可能地使用自动配置的机制。显式配置越少越好。当你必须要显式配置bean的时候(比如,有些源码不是由你来维护的,而当你需要为这些代码配置bean的时候),我推荐使用类型安全并且比XML更加强大的JavaConfig。最后,只有当你想要使用便利的XML命名空间,并且在JavaConfig中没有同样的实现时,才应该使用XML。

 

1、自动化装配bean

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

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

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

例:创建可被发现的bean

(1)CompactDisc 接口

package soundsystem;

public interface CompactDisc {
  void play();
}

(2)带有@Component注解的CompactDisc实现类SgtPeppers

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。没有必要显式配置SgtPeppersbean, 因为这个类使用了@Component注解,所以Spring会为你把事情处理妥当。

       不过,组件扫描默认是不启用的。我们还需要显式配置一下Spring,从而命令它去寻找带有@Component注解的类,并为其创建bean。

(3)@ComponentScan注解启用了组件扫描

package soundsystem;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class CDPlayerConfig { 
}

       CDPlayerConfig类并没有显式地声明任何bean,只不过它使用了@ComponentScan注解,这个注解能够在Spring中启用组件扫描。

       如果没有其他配置的话,@ComponentScan默认 会扫描与配置类相同的包。因为CDPlayerConf ig类位于soundsystem包中,因此Spring将会扫描这个包以及这个包下的所有子包,查找带有@Component注解的类。这样的话,就能发现CompactDisc,并且会在Spring中自动为其创建一个bean。如果你更倾向于使用XML来启用组件扫描的话,那么可以使用Spring context 命名空间的元素。

(4)通过XML启用组件扫描




  

(5)测试组件扫描能够发现CompactDisc

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();
  }

}

       注解@ContextConfiguration会告诉它需要在CDPlayerConfig中加载配置。因为CDPlayerConfig类中包含 了@ComponentScan,因此最终的应用上下文中应该包含CompactDi scbean。

例:为组件扫描的bean命名

       Spring应用上下文中所有的bean都会给定一个ID。 在前面的例子中,尽管我们没有明确地为SgtPeppers bean设置ID,但Spring会根据类名为其指定一个ID。具体来讲,这个bean所给定的ID为sgtPeppers,也就是将类名的第一个字母变为小写。

       如果想为这个bean设置不同的ID,你所要做的就是将期望的ID作为值传递给@Component注解。比如说,如果想将这个bean标识为lonelyHeartsClub,那么你需要将SgtPeppers类的@Component注解配置为如下所示:

@Component(“lonelyHeartsClub”)
public class SgtPeppes implements CompactDisc {
...
}

       还有另外一种为bean命名的方式,这种方式不使用@Component注解,而是使用Java依赖注入规范(Java Dependency Injection)中所提供的@Named注解来为bean设置ID: .

例:

@Named(“lonelyHeartsClub”)
public class SgtPeppes implements CompactDisc {
...
}

       Spring支持将@Named作为@Component注解的替代方案。两者之间有一些细微的差异,但是在大多数场景中,它们是可以互相替换的。

例:设置组件扫描的基本包

       如果@ComponentScan没设置属性则它会默认以配置类所在的包作为基础包(base package)为了指定不同的基础包,你所需要做的就是在@ComponentScan的value属性中指明包的名称:

例:

@Configuration
@ComponetScan(“soundsystem”)
public class CDPlayerConfig { 
}

       可通过basePackages更加清晰表达设置的为基础包,当然可指定多个基础包。

例:

@Configuration
@ComponetScan(basePackages={“soundsystem”, “video”})
public class CDPlayerConfig { 
}

        在上面的例子中,所设置的基础包是以str ing类型表示的。这是可以的,但这种方法是类型不安全(not type-safe)的。如果你重构代码的话,那么所指定的基础包可能就会出现错误了。

        除了将包设置为简单的String类型之外,@ComponentScan还提供了另外一种方法,那就是将其指定为包中所包含的类或接口:

例:

@Configuration
@ComponetScan(basePackages={CDPlayer.class, DVDPlayer.class})
public class CDPlayerConfig { 
}

       尽管在上例中,用basePackageClasses 设置的是组件类,但是你可以考虑在包中创建一个用来进行扫描的空标记接口(marker interface ),通过标记接口的方式,你依然能够保持对重构友好的接口引用,但是可以避免引用任何实际的应用程序代码。

例:通过为bean添加注解实现自动装配

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

例:

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();
  }

}

       @Autowired不仅可以用在构造函数上,还可以用在属性和方法中。如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常。为了避免异常的出现,你可以将@Autowi red的required属性设置为false:

例:

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

       将required属性设置为false时,Spring会尝试执行自动装配,但是如果没有匹配的bean的话,Spring将 会让这个bean处于未装配的状态。但是,把required属性设置为false时,你需要谨慎对待。如果在你的代码中没有进行null检查的话,这个处于未装配状态的属性有可能会出现NullPointerException.

       如果有多个bean都能满足依赖关系的话,Spring将会抛出一个异常,表明没有明确指定要选择哪个bean进行自动装配。

       @Autowi red是Spring特有的注解。如果你不愿意在代码中到处使用Spring的特定注解来完成自动装配任务的话,那么你可以考虑将其替换为@Inject: .

例:

@Component
public class CDPlayer implements MediaPlayer {
  private CompactDisc cd;

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

  public void play() {
    cd.play();
  }

}

       @Inject注解来源于Java依赖注入规范,该规范同时还为我们定义了@Named注解。在自动装配中,Spring同时支持@Inject和@Autowired.尽管@Inject和@Autowired之间有着一些细微的差别, 但是在大多数场景下,它们都是可以互相替换的。

例:验证自动转配

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\n", 
        log.getLog());
  }

}

 

2、通过Java代码装配bean

       大多数场景都推荐自动化配置,但有时候自动化配置不能使用,比如在将第三方库中的组件装配到自己的应用中的时候。在这种情况下,你必须要采用显式装配的方式。在进行显式配置的时候,有两种可选方案: Java和XML。

       在进行显式配置时,JavaConfig是 更好的方案,因为它更为强大、类型安全并且对重构友好。因为它就是Java代码,就像应用程序中的其他Java代码一样。同时,JavaConfig 与其他的Java代码又有所区别,在概念上,它与应用程序中的业务逻辑和领域代码是不同的。尽管它与其他的组件一样都使用相同的语言进行表述,但JavaConfig是配置代码。这意味着它不应该包含任何业务逻辑,JavaConfig也不应该侵入到业务逻辑代码之中。尽管不是必须的,但通常会将JavaConfig放到单独的包中,使它与其他的应用程序逻辑分离开来,这样对于它的意图就不会产生困惑了。

例:创建配置类

package soundsystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CDPlayerConfig {
  
  @Bean
  public CompactDisc compactDisc() {
    return new SgtPeppers();
  }
  
  @Bean
  public CDPlayer cdPlayer(CompactDisc compactDisc) {
    return new CDPlayer(compactDisc);
  }

}

       创建JavaConfig类的关键在于为其添加@Configuration注解,@Configuration注解表明这个类是一个配置类,该类应该包含在Spring应用上下文中如何创建bean的细节。

       @Bean注解会告诉Spring这个方法将会返回一个对象, 该对象要注册为Spring应用上下文中的bean。方法体中包含了最终产生bean实例的逻辑。默认情况下,bean的ID与带有@Bean注解的方法名是一样的。如果要重命名的话可以用@Bean(name=”beanName”)。

        默认情况下,Spring中的bean都是单例的。如果我们有第二个CDPlayer也调用了相同的SgtPeppers bean,我们并没有必要为第二个CDPlayer bean创建完全相同的SgtPeppers实例。所以,Spring会拦截对sgtPeppers ()的调用并确保返回的是Spring所创建的bean,也就是Spring本身在调用sgtPeppers ()时所创建的CompactDiscbean。因此,两个CDPlayer bean会得到相同的SgtPeppers实例。

可以看到,通过调用方法来引用bean的方式有点令人困惑。其实还有一种理解起来更为简单的方式:

例:

@Bean
public CDP1ayer cdP1ayer (CompactDisc compactDisc) {
return new CDPlayer ( compactDisc) ;
}

       在这里,cdPlayer ()方法请求一个CompactDisc作为参数。当Spring调用cdPlayer ()创建CDPlayerbean的时候,它会自动装配一个CompactDisc到配置方法之中。然后,方法体就可以按照合适的方式来使用它。借助这种技术,cdPlayer ()方法也能够将CompactDisc注入到CDPlayer的构造器中,而且不用明确引用CompactDisc的@Bean方法。

        通过这种方式引用其他的bean通常是最佳的选择,因为它不会要求将CompactDisc声明到同一个配置类之中。在这里甚至没有要求CompactDisc必须要在JavaConfig中声明,实际上它可以通过组件扫描功能自动发现或者通过XML来进行配置。你可以将配置分散到多个配置类、XML文件以及自动扫描和装配bean之中,只要功能完整健全即可。不管CompactDi sc是采用什么方式创建出来的,Spring都 会将其传入到配置方法中,并用来创建CDPlayer bean.

         另外,需要提醒的是,我们在这里使用CDPlayer的构造器实现了DI功能,但是我们完全可以采用其他风格的DI配置。比如说,如果你想通过

        Setter方法注入CompactDisc的话,那么代码看起来应该是这样的:

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

 

3、通过XML装配bean

(1)创建XML配置规范

        最为简单的Spring XML配置如下所示:




(2)声明一个简单的

       要在基于XML的Spring配置中声明一个bean,我们要使用spring-beans模式中的另外- -个元素: 元素类似于JavaConfig中的@Bean注解。我们可以按照如"下的方式声明CompactDi scbean:

       这里声明了一个很简单的bean,创建这个bean的类通过class属性来指定的,并且要使用全限定的类名。

        因为没有明确给定ID,所以这个bean将会根据全限定类名来进行命名。在本例中,bean的D将 会是"soundsystem. SgtPeppers#0"。其中,“#0”是一个计数的形式,用来区分相同类型的其他bean。 如果你声明了另外一个SgtPeppers,并且没有明确进行标识,那么它自动得到的ID将会是“soundsystem. SgtPeppers#1"。

       尽管自动化的bean命名方式非常方便,但如果你要稍后引用它的话,那自动产生的名字就没有多大的用处了。因此,通常来讲更好的办法是借助id属性,为每个bean设置一个你自 己选择的名字:


        减少繁琐为了减少XML中繁琐的配置,只对那些需要按名字引用的bean (比如,你需要将对它的引用注入到另外一个bean中)进行明确地命名。

这个简 单bean声明的一些特征:

         第一件需要注意的事情就是你不再需要直接负责创建sgtPeppers的实例,在基于JavaConfig的配置中,我们是需要这样做的。当Spring发现这个元素时,它将会调用SgtPeppers的默认构造器来创建bean。在XML配置中,bean的创建显得更加被动,不过,它并没有JavaConfig那样强大,在JavaConfig配置方 式中,你可以通过任何可以想象到的方法来创建bean实例。

        另外一个需要注意到的事情就是,在这个简单的声明中,我们将bean的类 型以字符串的形式设置在了class属性中。谁能保证设置给class属性的值是真正的类呢?Spring的XML配置并不能从编译期的类型检查中受益。即便它所引用的是实际的类型,如果你重命名了类,会发生什么呢?借助IDE检查XML的合法性使用能够感知Spring功能的IDE,如Spring Tool Suite,能够在很大程度上帮助你确保Spring XML配置的合法性。

(3)借助构造器注入初始化bean

         在Spring XML配置中,只有- -种声明bean的方式:使用元素并指定class属性。Spring会 从这里获取必要的信息来创建bean。

但是,在XML中声明DI时,会有多种可选的配置方案和风格。具体到构造器注入,有两种基本的配置方案可供选择:

  • 元素
  • 使用Spring 3.0所引入的c-命名空间

       两者的区别在很大程度就是是否冗长烦琐。可以看到, 元素比使用c-命名空间会更加冗长,从而导致XML更加难以读懂。另外,有些事情可以做到,但是使用c-命名空间却无法实现。

a构造器注入bean引用

例如在XML中声明CDPlayer并通过ID引用SgtPeppers:


    

       当Spring遇到这个元素时,它会创建一个CDPlayer实例。 元素会告知Spring要将一个ID为compactDisc的bean引用传递到CDPlayer的构造器中。

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



...
< /beans>

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

        在这里,我们使用了c-命名空间来声明构造器参数,它作为元素的一个属性,下图2.1描述了这个属性名是如何组合而成的。

Spring之装配Bean_第1张图片

 

        属性名以“c:"开头,也就是命名空间的前缀。接下来就是要装配的构造器参数名,在此之后是“-ref", 这是一个命名的约定,它会告诉Spring,正在装配的是一个bean的引用, 这个bean的名字是compactDisc,而不是字面量“compactDisc"。

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

例:


     .
    

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

       如果要使用c-命名空间的话,这个例子又该是什么样子呢?第一种方案是引用构造器参数的名字: .

       可以看到,装配字面量与装配引用的区别在于属性名中去掉了“-ref"后缀。与之类似,我们也可以通过参数索引装配相同的字面量值,如下所示:

(c)装配集合


    
    
    
        
            Sgt. Pepper's Lonely Hearts C1ub Band
            with a Little Help from My Friends
            Lucy in the Sky with Di amonds
            Getting Better
            Fixing a Hole
            
        
    

       其中,元素是 的子元素,这表明一个包含值的列表将会传递到构造器中。其中,元素用来指定列表中的每个元素。

       与之类似,我们也可以使用元素替代,实现bean引用列表的装配。例如,假设你有一个Di scography类,它的构造器如下所示:

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

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


    
    
        
            
            
            
            
         
    

       当构造器参数的类型是java.util. List时,使用元素是合情合理的。尽管如此,我们也可以按照同样的方式使用元素:


    
    
    
        
            Sgt. Pepper's Lonely Hearts C1ub Band
            With a Little Help from My Friends
            Lucy in the Sky wi th Diamonds
            Getting Better
            Fixing a Ho1e
             .
        
    

       元素的区别不大,其中最重要的不同在于当Spring创建要装配的集合时,所创建的是java. util . set还是java.util.List。如果是Set的话,所有重复的值都会被忽略掉,存放顺序也不会得以保证。不过无论在哪种情况下,都可以用来装配List、set甚至数组。

       在装配集合方面, 比c-命名空间的属性更有优势。目前,使用c-命名空间的属性无法实现装配集合的功能。

 

4、设置属性

(1)

例:


    

       元素为属性的Setter方法所提供的功能与元素为构造器所提供的功能是一样的。 在本例中,它引用了ID为compactDisc的bean (通过ref属性),并将其注入到compactDisc属性中(通过setCompactDisc()方法) 。

       我们已经知道,Spring为 元素提供了c命名空间作为替代方案,与之类似,Spring提供了更加简洁的p-命名空间,作为元素的替代方案。为了启用p命名空间,必须要在XML文件中与其他的命名空间一起对其进行声明:


    
    ...

       我们可以使用p-命名空间,按照以下的方式装配compactDisc属性:


       p-命名空间中属性所遵循的命名约定与c-命名空间中的属性类似。下图阐述了p-命名空间属性是如何组成的。

Spring之装配Bean_第2张图片

       首先,属性的名字使用了"p:"前缀,表明我们所设置的是一个属性。接下来就是要注入的属性名。最后,属性的名称以“-ref"结尾,这会提示Spring要进行装配的是引用,而不是字面量。

(2)将字面量注入到属性中

       属性也可以注入字面量,这与构造器参数非常类似。


    
    
    
        
            Sgt. Pepper's Lonely Hearts C1ub Band
            With a Little Help from My Friends
            Lucy in the Sky with Di amonds
            Getting Better
            Fixing a Hole
            
        
    

        在这里,除了使用元素的value属性来设置title和artist,我们还使用了内嵌的元素来设置tracks属性,这与之前通过装配tracks是完全一样的。

       另外一种可选方案就是使用p-命名空间的属性来完成该功能:


    
         
            Sgt. Pepper's Lonely Hearts Club Band
            with a Little Help from My Friends
            Lucy in the Sky with Diamonds
            Getting Better
            Fixing a Hole
            
        
    

       与c-命名空间一样,装配bean引用与装配字面量的唯区别在于是否带有“-ref"后缀。如果没有“-ref"后缀的话,所装配的就是字面量。但需要注意的是,我们不能使用p-命名空间来装配集合,没有便利的方式使用p-命名空间来指定一个值(或bean引用)的列表。但是,我们可以使用Spring util-命名空间中的一些功能来简化BlankDiscbean。

       首先,需要在XML中声明util-命名空间及其模式:



< /beans>

       util-命名空间所提供的功能之一就是元素,它会创建一个列表的bean。借助,我们可以将磁道列表转移到BlankDisc bean之外,并将其声明到单独的bean之中,如下所示:

       现在,我们能够像使用其他的bean那样,将磁道列表bean注入到BlankDisc bean的tracks属性中:

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

Spring之装配Bean_第3张图片

 

5、导入和混合配置

(1)在JavaConfig中应用XML配置

例:

package soundsystem;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CDConfig {
  @Bean
  public CompactDisc compactDisc() {
    return new SgtPeppers();
  }
}

       compactDisc ()方法已经从CDPlayerConfig中移除掉了,我们需要有一种方式将这两个类组合在一起。一种方法就是在CDPlayerConfig中使用@Import注解导入CDConfig:

package soundsystem;
import org. spr ingf ramework. context. annotation. Bean;
import org. spr ingf r amework. context。annotation. Configuration;
import org. spr ingf ramework. context . annotation. Import;

@Configuration
@Import (CDConfig.class}
public class CDP1ayerConfig {
@Bean
public CDP1ayer cdPlayer (CompactDisc compactDisc) {
    return new CDP1ayer (compactDisc) ;
}

       或者采用一个更好的办法,也就是不在CDPlayerConfig中使用@Import,而是创建一个更高级别的SoundSystemConfig,在这个类使用@ Import将两个配置类组合在一起:

package soundsystem;
import org. spr ingframework. context . annotation. Configuration;
import org. springfr amework. context . annotation. Import; 
@Configuration
@Import ( {CDP1ayerConfig . class, CDConfig .c1ass})
public class SoundSystemConfig {
}

       不管采用哪种方式,我们都将CDPlayer的配置与BlankDisc的配置分开了。现在,我们假设(基于某些原因)希望通过XML来配置BlankDisc,如下所示: .


        
            <1ist>
                Sgt. Pepper's Lonely Hearts Club Band
                With a Little Help from My Friends
                Lucy in the Sky with Diamonds
                Getting Better
                Fixing a Hole
                < !-- .. .other tracks omitted for brevity. .. -->
            
    

       现在BlankDisc配置在了XML之中,我们该如何让Spring同时加载它和其他基于Java的配置呢?答案是@ ImportResource注解,假设BlankDisc定义在名为cd-config. xml的文件中,该文件位于根类路径下,那么可以修改SoundSystemConfig,让它使用@ ImportResource注解,如下所示:

package soundsystem;
import org. spr ingf ramework. context . annotat ion. Conf iguration;
import org. spr ingframework . context. annotation. Import;
import org. spr ingframnework. context . annotat ion. Impor tResource;
@Conf iguration
@Import (CDP1ayerConfig. class)
@ImportResource (" classpath:cd-config. xm1")
public class SoundSystemConfig {
}

       两个bean——配 置在JavaConfig中的CDPlayer以及配置在XML中BlankDisc——都会被加载到Spring容器之中。因为CDPlayer中带有@Bean注解的方法接受一个CompactDi sc作为参数,因此BlankDisc将会装配进来,此时与它是通过XML配置的没有任何关系。

(2)在XML配置中引用JavaConfig

         在XML中import>元素只能导入其他的XML配置文件,并没有XML元素能够导入JavaConfig类。 但是,有一个你已经熟知的元素能够用来将Java配置导入到XML配置中:元素。为了将JavaConfig类导入到XML配置中,我们可以这样声明bean:



            
            

       采用这样的方式,两种配置——其中一个使用XML描述,另一个使用Java描述——被组合在了一起。类似地,你可能还希望创建一个更高层次 的配置文件,这个文件不声明任何的bean,只是负责将两个或更多的配置组合起来。例如,你可以将CDConfig bean从之前的XML文件中移除掉,而是使用第三个配置文件将这两个组合在一起:


    
            
            

        不管使用JavaConfig还是使用XML进行装配,我通常都会创建一个根配置(root configuration),也就是这里展现的这样,这个配置会将两个或更多的装配类和/或XML文件组合起来。在根配置中启用组件扫描(通过或@ComponentScan)。

 

你可能感兴趣的:(Spring)