文档章节

Spring创建bean的三种方式

张旭峰
 张旭峰
发布于 2017/02/14 17:57
字数 2583
阅读 101
收藏 0
点赞 0
评论 0

      在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的控制。

© 著作权归作者所有

共有 人打赏支持
张旭峰
粉丝 79
博文 61
码字总数 207334
作品 0
武汉
程序员
Spring AOP中自我调用的问题

前几天在做项目的时候同事说,在使用AOP进行拦截的时候发现有些方法有时候能输出拦截的日志有时候不输出拦截的日志。发现在单独调用这些方法的时候是有日志输出,在被同一个类中的方法调用的...

木叶之荣 ⋅ 2017/05/21 ⋅ 0

Spring IOC知识点一网打尽!

前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 单例模式你会几种写法? 工厂模式理解了没有? 在刷Spring书籍的时候花了点时间去学习了单例模式和工...

Java3y ⋅ 05/22 ⋅ 0

Spring之IoC(控制反转)和DI(依赖注入)

1.IoC的概念 IoC:通过容器去控制业务对象之间的依赖关系。控制权由应用代码中转到了外部容器,控制权的转移就是反转。控制权转移的意义是降低了类之间的耦合度。 Spring中将IoC容器管理的对...

Java攻城玩家 ⋅ 05/28 ⋅ 0

Spring中关于bean的作用域与生命周期

在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什...

忻胜霄 ⋅ 06/07 ⋅ 0

spring梳理(二) 基于注解的方式注册bean

我们知道,如果想要将bean交由spring容器管理,就需要首先将bean注册在spring容器中,而bean可以通过xml或者注解的方式进行注册,基于xml的配置一般是通过、等xml标签进行配置,然后由sprin...

wyn_lin ⋅ 05/25 ⋅ 0

IOC/AOP工具 - jBeanBox

jBeanBox是一个微形但功能较齐全的IOC/AOP工具适用于JAVA7+,利用了Java的初始化块实现的Java配置代替XML。jBeanBox采用Apache License 2.0开源协议。 其他一些IOC/AOP框架的问题: 1)Sprin...

yong9981 ⋅ 2016/07/25 ⋅ 14

Spring BeanFactory和FactoryBean

Spring BeanFactory和FactoryBean 1、BeanFactory BeanFactory定义了 IOC 容器的最基本形式,并提供了 IOC 容器应遵守的的最基本的接口,也就是 Spring IOC所遵守的最底层和最基本的编程规范...

秋风醉了 ⋅ 04/16 ⋅ 0

Spring与SpringMVC的容器关系分析

Spring与SpringMVC的容器关系分析 结论: Spring(springContext.xml)容器配置,排除所有@controller 的Bean <context:component-scan base-package="com.service,com.util,com.dao" > Spri......

LYQ1990 ⋅ 2016/05/24 ⋅ 0

Spring温故而知新 - bean的装配

按条件装配bean 就是当满足特定的条件时Spring容器才创建Bean,Spring中通过@Conditional注解来实现条件化配置bean package com.sl.ioc;import org.springframework.context.annotation.Bean;...

Java-老刘 ⋅ 05/07 ⋅ 0

Spring系列之Spring常用注解总结

传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、事物,这么做有两个缺点: 1、如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大;如果按需求分开.xml文件,那么...

HJCui ⋅ 05/29 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JavaScript零基础入门——(八)JavaScript的数组

JavaScript零基础入门——(八)JavaScript的数组 欢迎大家回到我们的JavaScript零基础入门,上一节课我们讲了有关JavaScript正则表达式的相关知识点,便于大家更好的对字符串进行处理。这一...

JandenMa ⋅ 今天 ⋅ 0

sbt网络问题解决方案

转自:http://dblab.xmu.edu.cn/blog/maven-network-problem/ cd ~/.sbt/launchers/0.13.9unzip -q ./sbt-launch.jar 修改 vi sbt/sbt.boot.properties 增加一个oschina库地址: [reposit......

狐狸老侠 ⋅ 今天 ⋅ 0

大数据,必须掌握的10项顶级安全技术

我们看到越来越多的数据泄漏事故、勒索软件和其他类型的网络攻击,这使得安全成为一个热门话题。 去年,企业IT面临的威胁仍然处于非常高的水平,每天都会看到媒体报道大量数据泄漏事故和攻击...

p柯西 ⋅ 今天 ⋅ 0

Linux下安装配置Hadoop2.7.6

前提 安装jdk 下载 wget http://mirrors.hust.edu.cn/apache/hadoop/common/hadoop-2.7.6/hadoop-2.7.6.tar.gz 解压 配置 vim /etc/profile # 配置java环境变量 export JAVA_HOME=/opt/jdk1......

晨猫 ⋅ 今天 ⋅ 0

crontab工具介绍

crontab crontab 是一个用于设置周期性被执行的任务工具。 周期性执行的任务列表称为Cron Table crontab(选项)(参数) -e:编辑该用户的计时器设置; -l:列出该用户的计时器设置; -r:删除该...

Linux学习笔记 ⋅ 今天 ⋅ 0

深入Java多线程——Java内存模型深入(2)

5. final域的内存语义 5.1 final域的重排序规则 1.对于final域,编译器和处理器要遵守两个重排序规则: (1)在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用...

江左煤郎 ⋅ 今天 ⋅ 0

面试-正向代理和反向代理

面试-正向代理和反向代理 Nginx 是一个高性能的反向代理服务器,但同时也支持正向代理方式的配置。

秋日芒草 ⋅ 今天 ⋅ 0

Spring 依赖注入(DI)

1、Setter方法注入: 通过设置方法注入依赖。这种方法既简单又常用。 类中定义set()方法: public class HelloWorldOutput{ HelloWorld helloWorld; public void setHelloWorld...

霍淇滨 ⋅ 昨天 ⋅ 0

马氏距离与欧氏距离

马氏距离 马氏距离也可以定义为两个服从同一分布并且其协方差矩阵为Σ的随机变量之间的差异程度。 如果协方差矩阵为单位矩阵,那么马氏距离就简化为欧氏距离,如果协方差矩阵为对角阵,则其也...

漫步当下 ⋅ 昨天 ⋅ 0

聊聊spring cloud的RequestRateLimiterGatewayFilter

序 本文主要研究一下spring cloud的RequestRateLimiterGatewayFilter GatewayAutoConfiguration @Configuration@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMi......

go4it ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部