文档章节

Spring创建bean的三种方式

爱宝贝丶
 爱宝贝丶
发布于 2017/02/14 17:57
字数 2583
阅读 221
收藏 1

      在Spring中,有三种方式创建一个bean:在xml中进行显示的配置,在java中进行显示的配置,隐式的bean发现机制和自动装配。这三种方式各有各的优点,但也有其不足:

一、使用自动装配创建bean

      Spring主要从两个角度来实现自动化装配:①组件扫描;②自动装配。组件扫描指的是Spring会自动扫描指定包及其子包下的所有bean,并将其放入spring容器中进行管理,而自动装配则是指对于有相互依赖关系的bean,Spring会将其自动装配到目标bean中,如将repository层的bean自动装配到service层中。

      自动装配的方式创建bean主要是使用一个被专门用来当做配置的接口(或类)来实现的。配置接口上主要使用两个注解:@Configuration和@ComponentScan。@Configuration来标注该接口是用于定义配置的,而@ComponentScan则是用于指定扫描的bean的文件夹的,默认情况下Spring会扫描该配置接口所在包及其子包下的所有bean。以下是一段配置接口的示例代码:

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

@Configuration
@ComponentScan
public interface CDPlayerConfig {
}

      上述代码定义了Spring查找bean的方式,而创建bean则可以使用@Component注解来实现,该注解可以传一个参数value,用来指定要创建的bean的名称,默认使用类名并且首字母小写。以下代码演示了如何使用@Component创建一个bean:

public interface CompactDisc {
  void play();
}
@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);
  }
}

      这样Spring就可以自动创建一个SgtPeppers的实例,并且将其放到Spring容器中进行管理,另外我们也可以使用@Named注解来创建一个bean。

      上面只是讲了如何创建一个bean,而自动装配还有另一方面的概念:依赖注入。其是指Spring会将一个bean所依赖的bean自动装配进来。依赖注入是通过@Autowired或@Resource来实现的,当一个bean需要另一个bean作为其属性的时候,其只需要声明该bean的一个变量,并且对该属性使用@Autowired或@Resource标注一下即可。以下是一个依赖注入的实例:

@Component
public class CDPlayer implements MediaPlayer {
  @Autowired
  private CompactDisc compactDisc;

  public void setCompactDisc(CompactDisc compactDisc) {
    this.compactDisc = compactDisc;
  }

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

      这里Spring就会在bean容器中查找CompactDisc实例,即sgtPeppers,并将其注入进来。以下是一段测试代码,用来验证这里的bean都创建了,并且也都注入进来了:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = CDPlayerConfig.class)
public class CDPlayerTest {
  @Autowired
  private CompactDisc cd;

  @Autowired
  private CDPlayer cdPlayer;

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

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

二、在java中进行显示的配置

      这种方式创建bean则不需要进行组件扫描了,其是通过在配置类中通过方法显示的创建一个bean,该方法则需要使用@Bean注解进行标识。如下是一段在java配置中显示的声明bean的代码:

@Configuration
public class CDPlayerConfig {
  @Bean
  public CompactDisc sgtPeppers() {
    return new SgtPeppers();
  }


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

      如上的代码中去掉了@ComponentScan注解,并且在配置类中使用@Bean注解显示的声明了CompactDisc和CDPlayer的两个实例,这两个实例的名称默认情况下是和方法名称是一样的。这里需要说明的是,①在@Bean标注的方法上如果有参数,那么Spring会自动在容器中查找是否有参数类型的bean,并将其注入进来;②如果不使用参数的方式注入依赖的bean,可以使用调用方法的方式,如下代码演示了如何调用方法注入bean:

@Configuration
public class CDPlayerConfig {
  @Bean
  public CompactDisc sgtPeppers() {
    return new SgtPeppers();
  }

  @Bean
  public CDPlayer cdPlayer() {
    return new CDPlayer(sgtPeppers());
  }
}

      上面的代码中,在创建CDPlayer类型的bean时会调用一次sgtPeppers()方法,而在创建CompactDisc类型的bean时也会调用一次该方法,这样会造成Spring容器中有两个同类型的bean,这与Spring的bean都是单例的相悖,为了避免这个问题,Spring会拦截创建CDPlayer类型的bean时调用的sgtPeppers()方法,而直接从容器中获取该bean并将其返回。

      这里需要注意的一点是,这种方式相对于第一种方式需要对每个bean都进行显示声明,但是其有自己的优点,对于一些额外的类库中的类,我们无法在其中加入Spring的注解,但是却要将其加入到Spring容器中进行管理,那么我们就可以通过这种方式来显示的声明这些类的bean。因而,在项目中我们可以通过将第一种方式和第二种方式结合使用来创建和管理bean。

三、xml中进行显示的配置

      在xml文件中配置bean是Spring最先使用的一种方式,在该xml文件中主要是一个<beans></beans>标签,其有一个子标签<bean></bean>,所有的bean的声明都是在<bean>子标签中声明的。<bean>标签主要有两个属性:id和class。id用来指定要声明的bean的名称,如果没指定则创建的bean的默认名称为class属性的值加上#数字,class属性则是用来指定要创建的类(包含包名)的。如下是一段使用xml创建bean的基本配置:

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="compactDisc" class="soundsystem.SgtPeppers"/>
</beans>

      这样就创建了一个名称为compactDisc的SgtPeppers类型的对象。如果要创建的对象的构造器中有参数,我们有两种方式对其进行注入。一种是使用<bean>标签的子标签<constructor-arg>标签,其有两个属性ref和value,如果参数为其他的bean类型,那么就用ref指向其他的bean的id即可,如果参数为基本数据类型,那么就用value执行基本数据类型的值即可。以下是一段示例配置:

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="compactDisc" class="soundsystem.BlankDisc">
        <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band"/>
        <constructor-arg value="The Beatles"/>
    </bean>
</beans>

      这里也可以使用c-命名空间的方式对构造器的参数进行注入,对于引用数据类型,其格式为c:argName-ref,对于基本数据类型,其格式为c:argName,这里argName为参数名称。以下是使用这种方式的示例配置:

<?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:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="compactDisc" class="chapter2.example1.soundsystem.BlankDisc" 
          c:title="Sgt. Pepper's Lonely Hearts Club Band" c:artist="The Beatles"/>    

    <bean id="cdPlayer" class="chapter2.example1.soundsystem.CDPlayer" c:cd-ref="compactDisc"/>
</beans>

      对于一个类的创建,并不一定所有的参数都是必须的,因而Spring提供了一种属性注入的方式,属性注入则必须要求该类中有一个该属性的set方法,比如setCompactDisc,属性名在配置文件中的名称为该set方法后半部分首字母小写的形式。属性注入参数的方式和构造器注入的方式非常类似,其也有两种方式进行注入,即<bean>标签下的<property>子标签和p-命名空间。以下是进行属性注入的示例:

<?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:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="compactDisc" class="soundsystem.BlankDisc" 
          c:title="Sgt. Pepper's Lonely Hearts Club Band" c:artist="The Beatles"/>

    <bean id="cdPlayer" class="soundsystem.CDPlayer">
        <property name="compactDisc" ref="compactDisc"/>
    </bean>
</beans>
<?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:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="compactDisc" class="soundsystem.BlankDisc" 
          c:title="Sgt. Pepper's Lonely Hearts Club Band" c:artist="The Beatles"/>

    <bean id="cdPlayer" class="soundsystem.CDPlayer"
          p:compactDisc-ref="compactDisc"/>
</beans>

      对于使用子标签和使用命名空间进行的属性注入,在基本数据类型和基本对象类型的处理上基本相似,但是如果参数为集合,那么命名空间将无法处理,而只能使用子标签的方式来进行集合参数的注入,以下是一段示例配置:

<?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:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="compactDisc" class="soundsystem.BlankDisc">
        <constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band"/>
        <!--<constructor-arg><null/></constructor-arg>-->
        <constructor-arg value="The Beatles"/>
        <constructor-arg ref="trackList"/>
    </bean>

    <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>
    </util:list>
</beans>

      以上就是Spring创建bean的三种方式的介绍,可以看出,使用xml进行显示的配置这种方式比较复杂,而且因为其使用的是字符串,这不是类型安全的,使用JavaConfig则只能创建少量的bean,但是其可以为第三方库的类创建bean,而使用隐式的bean发现机制和自动装配则可以扫描大量的bean,但其不能将第三方库的bean收录到Spring容器中,因为第三方库的代码中不能添加Spring的注解。总而言之,后两种方式是现在比较常用的方式,并且可以结合起来使用,以实现对bean的控制。

© 著作权归作者所有

共有 人打赏支持
爱宝贝丶
粉丝 136
博文 76
码字总数 255947
作品 0
武汉
程序员
Spring实战 (一) 一切从Bean开始

Spring可以做很多事情,但是归根究底.Spring的核心仅仅是依赖注入(DI)/控制反转(IoC)和面向切面编程(AOP)而已.Spring的一切都是基于这2点 Spring的一切都是从Bean开始的.什么是Bean?凡是被Spr...

kenshiro
2013/09/05
0
0
《Spring5学习》 01 装配Bean之自动化装配

Spring的自动化装配就便利性方面远远优于其他装配方法,这也是业界目前主要采用的Bean装配机制。Spring基于组建扫描和自动装配实现自动化装配,能将用户的显示配置降到最低。以下通过一段代码...

老韭菜
08/05
0
0
spring循环依赖的三种方式

1.构造器参数循环依赖 对象间在构造函数中有相互依赖,通过构造函数注入 constructor-arg 启动是会报循环依赖错误 2.setter方式单例,默认方式 spring先通过无参构造方法创建bean,然后通过s...

素雷
08/08
0
0
Spring IOC 容器源码分析 - 创建原始 bean 对象

1. 简介 本篇文章是上一篇文章(创建单例 bean 的过程)的延续。在上一篇文章中,我们从战略层面上领略了方法的全过程。本篇文章,我们就从战术的层面上,详细分析方法中的一个重要的调用,即...

coolblog.xyz
06/06
0
0
2014-03-09 Spring的学习(1)------Spring管理Bean(实例化Bean)

1.搭建与测试Spring的开发环境 PS: Spring-beans-2.5.xsd (为使在Beans.xml操作顺畅) Perferences--->MyEclipse--->Files and Editors---->XML--->XML Catalog--->add User Specified Entrie......

查封炉台
2014/03/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OSX | SafariBookmarksSyncAgent意外退出解决方法

1. 启动系统, 按住⌘-R不松手2. 在实用工具(Utilities)下打开终端,输入csrutil disable, 然后回车; 你就看到提示系统完整性保护(SIP: System Integrity Protection)已禁用3. 输入reboot回车...

云迹
今天
4
0
面向对象类之间的关系

面向对象类之间的关系:is-a、has-a、use-a is-a关系也叫继承或泛化,比如大雁和鸟类之间的关系就是继承。 has-a关系称为关联关系,例如企鹅在气候寒冷的地方生活,“企鹅”和“气候”就是关...

gackey
今天
4
0
读书(附电子书)|小狗钱钱之白色的拉布拉多

关注公众号,在公众号中回复“小狗钱钱”可免费获得电子书。 一、背景 之前写了一篇文章 《小狗钱钱》 理财小白应该读的一本书,那时候我才看那本书,现在看了一大半了,发现这本书确实不错,...

tiankonguse
今天
4
0
Permissions 0777 for ‘***’ are too open

异常显示: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: UNPROTECTED PRIVATE KEY FILE! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ......

李玉长
今天
5
0
区块链10年了,还未落地,它失败了吗?

导读 几乎每个人,甚至是对通证持怀疑态度的人,都对区块链的技术有积极的看法,因为它有可能改变世界。然而,区块链技术问世已经10年了,我们仍然没有真正的用上区块链技术。 几乎每个人,甚...

问题终结者
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部