第02章-装配Bean
1. Spring配置的可选方案
- 在XML中进行显式配置;
- 在Java中进行显式配置;
- 隐式的bean发现机制和自动装配。
2. 自动化装配bean
Spring从两个角度来实现自动化装配:
Spring从两个角度来实现自动化装配:
组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
自动装配(autowiring):Spring自动满足bean之间的依赖。
2.1 创建可被发现的bean
使用了@Component注解。这个简单的注解表明该类会作为组件类,并告知Spring要为这个类创建bean。
组件扫描默认是不启用的。我们还需要显式配置一下Spring,从而命令它去寻找带有@Component注解的类,并为其创建bean。
启用组件扫描
- 基于Java @ComponentScan注解启用了组件扫描
@Configuration
@ComponentScan(basePackages="soundsystem","video")
public class CDPlayerConfig {
}
如果没有其他配置的话,@ComponentScan默认会扫描与配置类相同的包。(通过一个空标记接口(remark interface)来这这个工作,是一个很好的实践。)
2.2 设置组件扫描的基础包
上面的例子中,所设置的基础包是以String类型表示的。我认为这是可以的,但这种方法是类型不安全(not type-safe)的。除了将包设置为简单的String类型之外,@ComponentScan还提供了另外一种方法,那就是将其指定为包中所包含的类或接口:
@Configuration
@ComponentScan(basePackageClasses = {CDPlayer.class})
public class CDPlayerConfig {
}
basePackages属性被替换成了basePackageClasses。同时,我们不是再使用String类型的名称来指定包,为basePackageClasses属性所设置的数组中包含了类。这些类所在的包将会作为组件扫描的基础包。
- 通过XML启用组件扫描
<context:component-scan base-package="soundsystem" />
2.3 通过为bean添加注解实现自动装配
为了声明要进行自动装配,我们可以借助Spring的@Autowired注解.
@Autowired注解不仅能够用在构造器上,还能用在属性的Setter方法上。
@Autowired
public void setCompactDisc(CompactDisc cd) {
this.cd=cd;
}
如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常。为了避免异常的出现,你可以将@Autowired的required属
性设置为false:
@Autowired(required = false)
public CDPlayer(CompactDisc cd){
this.cd=cd;
}
3. 通过Java代码装配bean
你想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加@Component和@Autowired注解的,因此就不能使用自动化装配的方案了。 在这种情况下,你必须要采用显式装配的方式。在进行显式配置的时候,有两种可选方案:Java和XML。
JavaConfig是配置代码。这意味着它不应该包含任何业务逻辑,JavaConfig也不应该侵入到业务逻辑代码之中。尽管不是必须的,但通常会将JavaConfig放到单独的包中,使它与其他的应用程序逻辑分离开来,这样对于它的意图就不会产生困惑了。
- 声明简单的bean
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();
}
- 借助JavaConfig实现注入
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
通过这种方式引用其他的bean通常是最佳的选择,因为它不会要求将CompactDisc声明到同一个配置类之中。在这里甚至没有要求CompactDisc必须要在JavaConfig中声明,实际上它可以通过组件扫描功能自动发现或者通过XML来进行配置。
- 使用方法替代构造器的注入
需要提醒的是,我们在这里使用CDPlayer的构造器实现了DI功能,但是我们完全可以采用其他风格的DI配置。比如说,如果你想通过Setter方法注入CompactDisc的话,那么代码看起来应该是这样的:
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
CDPlayer cdPlayer = new CDPlayer(compactDisc);
cdPlayer.setCompactDisc(compactDisc);
return cdPlayer;
}
4. 通过XML装配bean
- 声明一个简单的
<bean>
<bean class="soundsystem.SgtPeppers"/>
- 借助构造器注入初始化bean
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc"/>
</bean>
- 使用方法替代构造器的注入
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<property name="compactDisc" ref="compactDisc"/>
</bean>
<bean>
<bean class="soundsystem.SgtPeppers"/>
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc"/>
</bean>
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<property name="compactDisc" ref="compactDisc"/>
</bean>
<property>
元素为属性的Setter方法所提供的功能与<constructor-arg>
元素为构造器所提供的功能是一样的。
- 将字面量注入到属性中
有Java对象如下:
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
private List<String> tracks;
public BlankDisc(String title, String artist, List<String> tracks) {
this.title = title;
this.artist = artist;
this.tracks = tracks;
}
public void play() {
System.out.println("Playing " + title + " by " + artist);
for (String track : tracks) {
System.out.println("-Track: " + track);
}
}
}
可用以下xml将字面值(String
、List<String>
)注入到属性中:
<bean id="compactDisc"
class="soundsystem.properties.BlankDisc">
<property name="title" value="Sgt. Pepper's Lonely Hearts Club Band" />
<property name="artist" value="The Beatles" />
<property name="tracks">
<list>
<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>
<value>She's Leaving Home</value>
<value>Being for the Benefit of Mr. Kite!</value>
<value>Within You Without You</value>
<value>When I'm Sixty-Four</value>
<value>Lovely Rita</value>
<value>Good Morning Good Morning</value>
<value>Sgt. Pepper's Lonely Hearts Club Band (Reprise)</value>
<value>A Day in the Life</value>
</list>
</property>
</bean>
5. 导入和混合配置
5.1 在JavaConfig中引用XML配置
- Java配置
@Configuration
public class CDPlayerConfig {
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
- XML配置
<bean id="compactDisc"
class="soundsystem.BlankDisc"
c:_0="Sgt. Pepper's Lonely Hearts Club Band"
c:_1="The Beatles">
<constructor-arg>
<list>
<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>
<!-- …other tracks omitted for brevity… -->
</list>
</constructor-arg>
</bean>
以上xml配置中使用了c命名空间
,这里_0,_1相当与第一个参数和第二个参数。
- 在Java配置中引入XML配置
两个bean——配置在JavaConfig中的CDPlayer以及配置在XML中BlankDisc——都会被加载到Spring容器之中。代码如下:
@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig {
}
@Configuration
public class CDPlayerConfig {
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
<bean id="compactDisc"
class="soundsystem.BlankDisc"
c:_0="Sgt. Pepper's Lonely Hearts Club Band"
c:_1="The Beatles">
<constructor-arg>
<list>
<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>
<!-- …other tracks omitted for brevity… -->
</list>
</constructor-arg>
</bean>
以上xml配置中使用了c命名空间
,这里_0,_1相当与第一个参数和第二个参数。
两个bean——配置在JavaConfig中的CDPlayer以及配置在XML中BlankDisc——都会被加载到Spring容器之中。代码如下:
@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig {
}
@Import将两个配置类组合在一起;
@ImportResource可在JavaConfig中引入XML配置;
以上代码是利用一个新的Java配置类,引入了已有的Java配置类以及XML配置文件。当然也可以在已有的Java配置类中直接引入XML配置文件。
5.2 在XML配置中引用JavaConfig
- Java配置
@Configuration
public class CDConfig {
@Bean
public CompactDisc compactDisc() {
return new SgtPeppers();
}
}
- XML配置
<bean id="cdPlayer"
class="soundsystem.CDPlayer"
c:cd-ref="compactDisc" />
- 在XML配置中引入Java配置
<bean class="soundsystem.CDConfig" />
<bean id="cdPlayer"
class="soundsystem.CDPlayer"
c:cd-ref="compactDisc" />
以上代码是在已有的XML配置文件中引入Java配置类,当然可以建立一个新的XML引入已有的XML配置文件和已有的Java配置类,如:
<bean class="soundsystem.CDConfig"/>
<import resource="cdplayer-config.xml"/>
XML配置文件应用已有XML配置文件使用<import resource>
标签。
注意
不管使用JavaConfig还是使用XML进行装配,我通常都会创建一个根配置(root configuration),也就是这里展现的这样,这个配置会将两个或更多的装配类和/或XML文件组合起来。我也会在根配置中启用组件扫描(通过<context:component-scan>
或@ComponentScan)。
Spring 3的一些内容
1、装配wiring,即创建应用对象之间的协作关系的行为,者也是依赖注入的本质。
2、创建Spring配置
从Sring3.0开始,Spring容器提供了两种配置Bean的方式:
3、典型的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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
beans命名空间不是唯一的Spring命名空间,Spring核心框架自带了10个命名空间配置,如下:
4、当Spring容器加载Bean时,Spring使用反射来创建Bean。
5、覆盖Spring默认的单例配置:Spring Bean默认都是单例,但有时我们每次都需要获得唯一的Bean实例,比如每个人的门票要唯一:
我们只需要配置Bean的scope属性为prototype即可:
1
Spring提供的作用域选项:
6、初始化和销毁Bean
Auditorium(舞台)要保证做的最先和最后两件事情:
开灯,关灯。
需要在Bean中使用init-method和destory-method属性:
当有很多上下文定义的Bean有相同名字的初始化方法和销毁方法时,可以直接在上层beans元素中声明default-init-method和default-destory-method属性,从而避免每一个都要设置一遍的问题。
最小化Spring XML配置——
Bean的自动装配(autowiring);
Bean的自动检测(autodiscovery);
一、自动装配Bean属性
1、 4种类型的自动装配
byName——把与Bean的属性具有相同名字(或ID)的其他Bean自动装配到Bean的对应属性中,名字不匹配则不装配;
byType——把与Bean的属性具有相同类型的其他Bean自动装配到Bean的对应属性中,类型不匹配则不装配;
constructor——把与Bean的构造器入参具有相同类型的其他Bean自动装配到Bean构造器的对应入参中;
autodetect——首先尝试使用constructor自动装配,若失败,再尝试使用byType进行自动装配。
2、byName
原来的装配是这样的:
当bean的id属性和property属性的name一致时,通过配置autowire属性皆可以自动装配instrument了,修改后的文件如下:
3、byType自动装配
byType自动装配的工作方式类似于byName,只不过不再是匹配属性的名字而是检查属性的类型。
若Instrument类型有多个Bean,Spring就会抛出异常,为解决这个为,需要标识首选的Bean或者取消某个Bean的自动装配候选资格:
首选Bean
设置Bean的primary属性为true。但是不幸的是所有的bean的默认primary都是true,因此只能将非首选的Bean的primary属性设置为false:
取消Bean候选资格
排除某些Bean是,可设置这些Bean的autowire-candidate属性为false:
4、constructor自动装配
通过构造器注入来配置Bean,我们可以移除元素,由Spring在应用上下文中自动选择Bean注入到构造器入参中:
与byType一样,当发现多个Bean匹配某个构造器入参时,Spring依旧报出异常。
5、最佳自动装配
首选constructor自动装配,若没有发现与构造器相匹配的Bean时,Spring将尝试使用byType自动装配。
6、默认自动装配
当需要为上下文中的每一个Bean配置相同的上述自动装配autowire属性,可以在根目录增加一个default-autowire属性:
该属性默认none,标示所有Bean都不使用自动装配,除非Bean自己配置了autowire属性。
另外,种配置的autowire属性可以覆盖根元素的默认自动装配策略——混合策略。
混合策略对构造器有所限制:不能混合使用constructor自动装配策略和元素。
二、使用注解装配
注解方式允许更细粒度的自动装配,可以选择性地标注某一个属性来对其应用自动装配。
Spring容器默认禁止注解装配,最简单的启用方式是使用Spring的context命名空间配置中的元素。
注解,可以为Spring属性、方法和构造器进行自动装配,因此要写在这些的上方一行。
1、@Autowired
对属性的setter方法进行标注:
Spring会尝试对该方法执行byType自动装配。
除了setter方法,@Autowired可以标注需要自动装配Bean引用的任何方法、构造器。
甚至可以使用@Autowired直接标注属性,并删除setter方法:
但是,简单的@Autowired标注有两种麻烦——没有bean或者多个bean:
没有bean
当属性是可选的,而bean不存在时,可以使用required属性:
@Autowired(required=false)
多个bean【限定歧义性的依赖】
为帮助@Autowired鉴别哪一个Bean才是我们想要的,可配合使用Spring的@Qualifier注解,该注解可以包含一个字符串作为Bean的标识(标识不一定是id)。
如将一个id为guitar的乐器装配到instrument属性中:
注意,上述的guitar可以在xml中对的id属性设置;
另外,可以不用id属性,而是在中以qualifier子元素(子元素vs属性)中写明,或者在Guitar类上标注:
若是Qualifier含义不是那么明确或者范围过大,可以自定义Qualifier接口,以代替Qualifier:
2、借助@Inject实现基于标准的自动装配
JCP(Java Community Process)发布Java依赖注入规范——JSR-330,@Inject注解是JSR-330的核心部件。
》note: JDK中并没有JSR-330的实现,需要下载响应的jar依赖包http://mvnrepository.com/artifact/javax.inject/javax.inject
@Inject
和@Autowired一样,@Inject可以自动装配属性、方法和构造器,但是没有required属性,即@Inject注解所标注的依赖关系必须存在,否则会报出异常。
与@Autowired对应的@Qualifier类似,@Inject对应@Name注解。
@Inject本身也有@Qualifier注解,但是不推荐使用,而是推荐自定义限定器注解。
3、在注解中使用表达式
String类型以及基本类型的属性,可以直接通过@Value的方式填入值。但是这相当于硬编码,与直接写在代码中没多大区别,因此不推荐使用,如一首歌名Eruption:
但是@Value可以使用SpEL表达式,获取系统属性,功能强大:
三、自动检测Bean
= +自动检测和定义Bean。
自动检测可以免去的定义,是的Spring应用中的大多数甚至所有Bean实现定义【厉害啊】和装配。
元素即负责Spring的自动检测Bean和定义Bean。
【vs ,该元素有助于消除Spring配置中的和元素,但是依旧需要显示定义】
使用代替 元素:
那么,哪些类需要注册为Spring的Bean呢?
1、为自动检测标注Bean
默认地,查找使用“构造型(stereotype)”注解所标注的类,这些特殊的注解如下:
如,对一个类注解@Component:
那么Spring扫描到Guitar,会自动将它注册为Spring Bean,该Bean的ID默认为无限定类名(何为无限定?)——guitar。
2、过滤组件扫描
通过为配置和子元素,我们可以随意调整扫描行为。如自动注册所有的Instrument实现类:
的type和expression属性一起协作来定义组件扫描策略。
不过,默认的基于注解的过滤策略是最经常用的。
四、使用Spring基于Java的配置
1、创建基于Java的配置
Spring的Java配置可以不用XML就可以编写大多数的Spring配置,但是还是需要极少量的XML来启动Java配置。就是说,XML总要有的。
Spring在base-package指定的包内查找使用@Configuration注解所标注的所有类。
2、定义一个配置类
使用@Configuration注解的Java类,就等价于XML配置中的元素,可以在改类内部定义@Bean方法了。
声明的方法示例如下,将得到ID为方法名的Bean:
优点:Spring的基于Java的配置中,并没有String属性,Bean的ID和类型都被是否方法签名的一部分,所以可以进行编译期检查来确保Bean的类型是合法类型,并且Bean的ID是唯一的。
vs XML配置:Bean的类型和ID都是由String属性标示的,String标识符的缺点是它们无法进行编译期检查,如果重命名了Juggler类,或许会忘记修改相应的XML配置!
智能:其他Bean的声明调用另一个Bean时,Spring都会拦截该方法的调用,并尝试在应用上下文中查找该Bean,而不是让方法创建一个新的实例。
源码
自动配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-autoconfig
Java配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-javaconfig
XML配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-xmlconfig
混合配置:https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_02/stereo-mixedconfig
第02章-装配Bean的更多相关文章
- 第2章—装配Bean—通过java代码装配bean
通过java代码装配bean 在进行显式装配的时候,有两种选型方案:java和XML配置,这里先介绍java的配置方式. 2.3.1创建配置类 先复习下上一章的配置内容: @Configurati ...
- SpringInAction读书笔记--第2章装配Bean
实现一个业务需要多个组件相互协作,创建组件之间关联关系的传统方法通常会导致结构复杂的代码,这些代码很难被复用和单元测试.在Spring中,对象不需要自己寻找或创建与其所关联的其它对象,Spring容器 ...
- Spring in Action --- 第二章 装配Bean
Spirng配置的可选方案 在XML中进行显示配置 在Java中进行显示配置 隐式的bean发现机制和自动装配 bean装配 1. 在希望被扫描到的类上加注解 @Component 2. 基于不同的配 ...
- 第2章—装配Bean—通过XML装配Bean
通过XML装配Bean 尽管我们在生成Bean的过程中可以用到很多方法,但我们依然需要Spring的XML配置来完善更多的需求,下面就来介绍下XML装配Bean的过程是怎样的. 3.1创建XML配 ...
- 第2章—装配Bean—自动化装配Bean
自动化装配Bean 2.1.Spring配置可选方案 装配是依赖注入DI的本质,Spring提供了以下三种注入的装配机制: 在XMl中进行显式配置 在java中进行显式配置 隐式的Bean发现机制 ...
- 第02章 IOC和bean的配置
第02章 IOC容器和Bean的配置 1.IOC和DI ①IOC(Inversion of Control):反转控制. 在应用程序中的组件需要获取资源时,传统的方式是组件主动的从容器中获取所需要的资 ...
- #Spring实战第二章学习笔记————装配Bean
Spring实战第二章学习笔记----装配Bean 创建应用对象之间协作关系的行为通常称为装配(wiring).这也是依赖注入(DI)的本质. Spring配置的可选方案 当描述bean如何被装配时, ...
- Spring入门篇——第4章 Spring Bean装配(下)
第4章 Spring Bean装配(下) 介绍Bean的注解实现,Autowired注解说明,基于java的容器注解说明,以及Spring对JSR支持的说明 4-1 Spring Bean装配之Bea ...
- Spring入门篇——第3章 Spring Bean装配(上)
第3章 Spring Bean装配(上) 介绍Bean的作用域.生命周期.Aware接口.自动装配和Resource等内容. 3-1 Spring Bean装配之Bean的配置项及作用域 从上至下依次 ...
随机推荐
- weblogic控制台的启动与禁用
在一些安全漏洞扫描中,经常会扫描发现,使用weblogic管理控制台,会有个中危的漏洞. http://192.168.10.46:7001/console/login/LoginForm.jsp W ...
- 洛谷 4106 / bzoj 3614 [HEOI2014]逻辑翻译——思路+类似FWT
题目:https://www.luogu.org/problemnew/show/P4106 https://www.lydsy.com/JudgeOnline/problem.php?id=3614 ...
- Swift app中的Crash捕获与处理
1. 为什么会Crash 常见的Crash原因有:访问已经被释放的内存,数组越界,使用!解包值为nil的变量.当遇到这些情况时,说明应用已经遇到了很严重的非预期错误,无法再继续运行.操作系统检测到这些 ...
- PHP 16 个编程法则
HP是最好的编程语言.对于PHP开发者来说,掌握一些编程法则是十分重要的.而在PHP中,以双下划线(__)开头的方法称为魔术方法,它们扮演着非常重要的角色. 常用的魔术方法包括: -__constru ...
- phantomjs 安装和试用
准备学习casperjs, 发现官网上说 it’s an extremely useful companion to PhantomJS, 所以决定下把它下来试试.下载安装(win7)没什么可说的, ...
- NoSuchBeanDefinitionException: No bean named 'shiroFilter' is defined
以前运行正常的项目,过了一段时间再运行时出问题,打开链接无反应,无法访问Tomcat,空白页面. 经检查发现,在Tomcat log中有报错: NoSuchBeanDefinitionExceptio ...
- WP10通过StreamSocket连接C++服务器
注:当服务端和手机模拟器运行在一台机器时,会有奇怪错误.将服务端放在其它机器上更改客户端连接地址,运行正常.或者直接用本机modern调试也可以. 实例化一个对象 StreamSocket _clie ...
- 分布式爬虫搭建系列 之二-----神器PyCharm的安装
这里我们使用PyCharm作为开发工具,以下过程摘抄于:http://blog.csdn.net/qq_29883591/article/details/52664478 作者:陌上行走 Pytho ...
- VS2010调用halcon的时候出现试图加载格式不正确的程序(this.hWindowControl1 = new HalconDotNet.HWindowControl();)
[重要错误修改] /// <summary> /// 设计器支持所需的方法 - 不要 /// 使用代码编辑器修改此方法的内容. /// </summary> private v ...
- leetcode804
int uniqueMorseRepresentations(vector<string>& words) { map<char, string> st; st.ins ...