解释:所谓装配就是把一个类需要的组件给它设置进去,英文就是wire,wiring;注解Autowire也叫自动装配。

目前Spring提供了三种配置方案:

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

就我个人而言,用XML和自动装配混搭最多,用Java代码进行装配用的最少,几乎不用。这三种配置方案提供的功能会有重叠,大部分都可以根据个人喜好来选择。Spring的配置风格是可以相互搭配的,三种方式可以共存。

三者的适用范围:

XML > JavaConfig > 注解

自动化装配bean

自动化装配最为便利,写的东西最少,用起来很快。要实现自动化装配可以从两个方面来看:

组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean

自动装配(autowiring):Spring自动满足bean之间的依赖

具体的步骤可以用下图来描述:

创建可被发现的bean

这里用CD播放器来先演示依赖注入(Dependency Inject)。

涉及到的类图如下:

CompactDisc接口

 package soundsystem;

 public interface CompactDisc {
void play();
}

CompactDisk接口的实现类: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);
}
}

开启组件扫描的Java配置类:CDPlayerConfig

 package soundsystem;

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

测试类:CDPlayerConfig

 package soundsystem;

 import org.junit.Test;
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;
import org.springframework.util.Assert; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes=CDPlayerConfig.class)
public class CDPlayerTest { @Autowired
private CompactDisc cd; @Test
public void cdShouldNotBeNull() {
Assert.notNull(cd, "inject failed");
}
}

只需简单几步即可实现依赖注入,很强大。

解释说明: 

给SgtPeppers用了@Component这个注解后,Spring会为这个类去创建bean。

组件扫描默认是不启用的,需要显式的配置Spring让其去寻找带有@Component注解的类,并为其创建bean。

开启组件扫描的任务是CDPlayerConfig来实现的,通过Java代码定义了Spring的装配规则。

如果没有其他的配置,@ComponentScan默认扫描与配置类相同的包。

@CDPlayerConfig类位于soundsystem包中,Spring将会扫描这个包和这个包下的所有子包。

如果用XML来开启组件扫描的话,可以使用<context:component-scan>元素:<context:component-scan base-package="soundsystem" />

测试类中用到了两个注解:SpringJUnit4ClassRunner会在测试的时候自动创建Spring的应用上下文,@ContextConfiguration会告诉它需要在CDPlayerConfig类中加载配置,然后类CDPlayerConfig中包含了@ComponentScan,所以上下文中会包含CompactDisc的bean。

为组件扫描的bean命名

Spring应用上下文中所有的bean都会有一个ID。如果想之前的例子那样没有明确的给出bean的ID,Spring会根据类名为其指定一个ID。第一个类名小写。

如果想为bean设置不同的ID,可以将期望的ID传给注解@Component。如下:

 package soundsystem;

 import org.springframework.stereotype.Component;

 @Component("lonelyHeartsClub")
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);
}
}

另一种是使用Java依赖注入规范所提供的@Named注解来为bean设置ID(几乎没用过),大多数场景可以替换使用。

可用的注解还有:@Service,@Repository等

设置组件扫描的基础包

对于包的扫描有以下几点可以记一下:

不设置任何属性:配置类所在的包为基包,会以配置类所在的包作为基础包(base package)来扫描组件。

只设置value:指定基包

设置basePackages属性:更明确的指定了基包,而且给定的字符串作为基包

设置basePackageClasses属性:明确地指定了类所在的包为基包

空标记接口:可以将实际的应用代码和配置代码分开

总结如下:

// 啥属性没有, 就是以CDPlayerConfig所在的类为基包
@Configuration
@ComponentScan
public class CDPlayerConfig { } // 指定了value属性, 以value指代的包为基包
@Configuration
@ComponentScan("soundsystem")
public class CDPlayerConfig { } // 明确指定了基包组
@Configuration
@ComponentScan(basePackages = "soundsystem")
public class CDPlayerConfig { } // 指定了类所在的包为基包, 可以用一个标记接口替换实际的应用类
@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class, DVDPlayer.class)
public class CDPlayerConfig { }

为bean添加注解实现自动装配

如果只是把类通过加上Component注解并进行了组件扫描来交给Spring管理,生成bean其实还不够。很多对象都会依赖其他对象协作完成任务。这样的话就需要一种方法能将组件扫描得到的bean和它们的依赖装配到一起,这就是自动装配。这里借助的是Spring的Autowired注解。

@Autowire注解不仅能用在构造器上还可以用在属性的setter方法上(不仅仅是setter方法,Autowired可以用在类的任何方法上)。

在Spring初始化了bean之后,它会尽可能地去满足bean的依赖。

如果没有匹配的bean,那么在应用上下文创建的时候Spring会抛出一个异常,为了避免异常可以将Autowired的required属性设置为false。这样的话Spring会尝试执行自动装配,但是如果没有匹配的bean的话,Spring将会让这个bean处于未装配的状态(如果没有装配的话,使用的时候可能会报NullPointerException)。

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

@Autowired是Spring的独有注解,你还可以使用@Inject和@Resource。

Java代码装配bean

还可以用Java代码来做配置,之前只是用Hibernate的时候用过类进行配置,我用的也比较少。可能是因为喜欢吧配置归配置,代码归代码吧。

组件扫描和自动装配的一个局限在于:有时候行不通。比如你要想在第三方的库中的组件装配到你的应用中,这种情况下是没法给它的类加上@Component和@Autowired注解的,这时候自动装配就用不了了。另一种就是用Java代码来配置。

优点:强大、类型安全,对重构友好,和普通的Java代码一样

注意:配置代码不应该侵入到业务逻辑代码中,最好是放在单独的包中,和其他的应用逻辑分开

创建配置类

创建JavaConfig类很简单:只需要为其添加@Configuration注解就可以了,就表明它是一个配置类。

声明简单的bean

要在JavaConfig中声明bean,需要编写一个方法,这个方法会创建所需类型的实例,然后给这个方法添加@Bean注解:

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

@Bean注解会告诉Spring这个方法会返回一个对象,该对象要注册为Spring应用上下文的bean。

默认情况下,bean的ID和带有@Bean注解的方法名一样,可以为Bean加上name属性,或者修改方法名来设置ID。

借助JavaConfig实现注入

通过Java代码组装的方法也比较别致。

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

要注意这里的sgtPeppers()不是普通的方法,而是加了Bean注解的方法,Spring会拦截对这个方法的所有调用,并确保返回该方法所创建的bean,而不是每次进行实际的调用。(这个有点意思呀,拦截)。

可以将SgtPeppers的实例注入到任意数量的其他bean之中。默认情况下Spring中的bean都是单例的。

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

上面是通常引用其他bean最佳的选择,因为它不会要求CompactDisc声明到同一个配置中,甚至不需要CompactDisc在JavaConfig中声明,只要Spring应用上下文中有就可以了。个人对于这种方法还是不太习惯。

XML装配bean

创建XML配置规范

XML文件中要以<beans>为根元素

声明一个简单的<bean>

 <bean class="soundsystem.SgtPeppers" />

如果没有给定明确的ID,bean将会根据全限定的类名来进行命名。本例中将会是:"soundsystem.SgtPeppers#0",其中"#0"是一个计数形式,如果声明了一个另外的SgtPeppers,那么它自动的到的ID回事"soundsystem.SgtPeppers#1"。

通产来讲最好的方法是借助id属性,为每一个bean设置一个合适的名字。

借助构造器注入初始化的bean

在XML中进行依赖注入的时候,往往有多种可选的配置方案和风格。

 <bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc" />
</bean>

如果不使用ref,而是使用value,则表示将字面量注入进去:

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

装配集合

这个就不具体讲了,到了要用的时候来查一下就可以,list,set和数组都可以装配,就是set使用的时候重复的值会被忽略掉,而且不能保证顺序。

设置属性

 <bean id="cdPlayer" class="soundsystem.CDPlayer">
<property name="compactDisc" ref="compactDisc" />
</bean>

属性也可以注入字面量,集合。

导入和混合配置

以上的三种装配方案可以混合使用,而且自动装配的时候不会介意你的bean来自于哪里。

JavaConfig导入其他的JavaConfig以及XML

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

或者采用更高级别的配置类来导入:

 @Configuration
@Import({CDPlayerConfig.class, CDConfig.class})
public class SoundSystemConfig { }

如果要导入XML配置的话:使用@ImportResource注解,使用相对于根类路径的地址

 @Configuration
@Import({CDPlayerConfig.class})
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig { }

XML配置中引用JavaConfig

XML可以用<import>标签导入其他的XML配置,用<bean class="soundsystem.CDConfig" />可以可以导入Java配置类。其实很简单的~

总结

Spring Bean装配学习的更多相关文章

  1. Spring Bean装配详解(五)

    装配 Bean 的概述 前面已经介绍了 Spring IoC 的理念和设计,这一篇文章将介绍的是如何将自己开发的 Bean 装配到 Spring IoC 容器中. 大部分场景下,我们都会使用 Appl ...

  2. Spring Bean装配(下)——注解

    @Repository,@Service,@Controller这三个注解是基于component定义的注解 component-scan:组件扫描 base-package:扫描这个下的所有类 &l ...

  3. Spring Bean装配(上)

    Bean:在spring的IOC里面,把配置到IOC容器里面的实体或者是对象都称为Bean Bean配置项 Bean的作用域 Bean的生命周期 Bean的自动装配 Resources&Res ...

  4. Spring入门篇——第4章 Spring Bean装配(下)

    第4章 Spring Bean装配(下) 介绍Bean的注解实现,Autowired注解说明,基于java的容器注解说明,以及Spring对JSR支持的说明 4-1 Spring Bean装配之Bea ...

  5. Spring入门篇——第3章 Spring Bean装配(上)

    第3章 Spring Bean装配(上) 介绍Bean的作用域.生命周期.Aware接口.自动装配和Resource等内容. 3-1 Spring Bean装配之Bean的配置项及作用域 从上至下依次 ...

  6. Spring Bean装配笔记

    Spring Bean装配笔记 Spring中的Bean是一个很重要的概念.Spring作为一个Bean容器,它可以管理对象和对象之间的依赖关系,我们不需要自己建立对象,把这部分工作全部转交给容器完成 ...

  7. spring Bean装配的几种方式简单介绍

    Spring容器负责创建应用程序中的bean同时通过ID来协调这些对象之间的关系.作为开发人员,我们需要告诉Spring要创建哪些bean并且如何将其装配到一起. spring中bean装配有两种方式 ...

  8. spring bean容器学习

    bean是Spring种最核心的东西 ,如果说Spring是个水桶的话,bean就是桶里面的水,桶里面没有水也就没有意义了. public class MyTestBean { private Str ...

  9. Spring Bean装配方式

    Spring装配机制 在xml中进行显示配置 在Java中进行显示配置 隐式bean发现机制和自动装配 自动化装配bean 组件扫描(component scanning),Spring会自动发现应用 ...

随机推荐

  1. “C++的数组不支持多态”?

    先是在微博上看到了个微博和云风的评论,然后我回了“楼主对C的内存管理不了解”. 后来引发了很多人的讨论,大量的人又借机来黑C++,比如: //@Baidu-ThursdayWang:这不就c++弱爆了 ...

  2. java 获取局域网中的全部主机名和IP地址

    DOS命令 命令 意义 net view 获取局域网中的全部主机名 ipconfig -all 获取本地IP,主机名,MAC地址 arp -a 获取本局域网中的全部IP地址和物理地址 ping -a ...

  3. nginx last 和break redirect 和 permanent

    一.last & break (1)last 和 break 当出现在location 之外时,两者的作用是一致的没有任何差异. 注意一点就是,他们会跳过所有的在他们之后的rewrite 模块 ...

  4. Python 文件 next() 方法

    描述 Python 3 中的 文件 对象不支持 next() 方法. Python 3 的内置函数 next() 通过迭代器调用 __next__() 方法返回下一项. 在循环中,next()方法会在 ...

  5. Oracle的执行计划(来自百度文库)

    如何开启oracle执行计划 http://wenku.baidu.com/view/7d1ff6bc960590c69ec37636.html怎样看懂Oracle的执行计划 http://wenku ...

  6. U811.1接口EAI系列之一--通用把XML传送给EAI处理方法--PowerBuilder语言

    1.前面配置参考:http://www.cnblogs.com/spring_wang/p/3393147.html 2.pb通用调EAI方法代码如下: //===================== ...

  7. 怎么安装预装的win8三星笔记本改win7再装Ubuntu问题[zz]

    随着科技的高速发展,人们对电脑的要求越来越高,对电脑系统的要求亦是,那些电脑自带的系统,很多时候已经无法满足人们的需求了,而为了满足自己的需求,人们往往会为电脑改装新系统,而本文要和大家一起分享的话题 ...

  8. 修复 dji spark 的 micro sd/tf 存储卡里不能正常播放的视频文件

    可能是因为 1.在没有正确的操作停止录像前,关掉了 spark 的电源 2.在 spark 没有完成视频存储前,关掉了 spark 的电源 总之在电脑里想查看存储卡里的视频时,发现居然无法播放,这就太 ...

  9. sql 优化 -- sql中的自定函数

    Long run sql: MERGE INTO INTITMRTNPARAM D USING ( SELECT A.INRFILENM,A.INRSTAT,A.INRDEPCD,A.INRITMCD ...

  10. SPI和RAM IP核

    学习目的: (1) 熟悉SPI接口和它的读写时序: (2) 复习Verilog仿真语句中的$readmemb命令和$display命令: (3) 掌握SPI接口写时序操作的硬件语言描述流程(本例仅以写 ...