Spring装配Bean有三种主要方式:自动装配、基于Java显示配置和基于XML显示配置。建议使用的是自动装配,一是简单快捷,二是显示配置维护麻烦。但是显示配置在有些场景下是必须的或者高效的,例如想讲第三方库的组件装配到自己的应用中,肯定不能去把第三方的组件类加上注释;或者需要维护别人写的代码,但是他用的是显示配置,如果不了解就无从下手,所以也应该了解spring的显示配置方式。
1. 自动装配
用CD和CD播放器举例:spring如何将一个CD类,通过配置装配到CD播放器中。
@Component声明组件
通过UML图可以看到,需要做的是把SgtPeppers注入到CDplayer中,所以将这两个类看成是一个组件,spring通过一番操作将他们组合在一起,无论如何将他们组合在一起,第一步我们先把他们都声明成spring能认识的组件,肯定不会错。spring声明组件用的就是@Component。
@Component
public class SgtPeppers implements CompactDisc {
private String title = "White Horse";
private String artist = "Talyor Swift";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
@Autowired自动装配注解
和SgtPeppers声明成为组件略微不同的是,CDplayer需要将SgtPeppers注入到其中。所以需要有一个让spring知道,SgtPeppers需要注入到CDplayer,我们常用的注入方式有构造器注入或者是setter方法注入,spring注入的方式也一样,只是通过@Autowired注解让其注入自动完成。
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
@Autowired(required=false)
public CDPlayer(CompactDisc cd){
this.cd = cd;
}
@Override
public void play() {
cd.play();
}
}
要注意的是:@Autowired可以注释任何方法,有了这个注释spring会试图创建一个注释了的bean,但如果没有找到bean则会报出异常为了避免异常将@Autowired(required=false)添加false,但添加false避免该异常后,如果没有进行null检查会报NullPointExeception。
@ComponentScan扫描组件
刚才创建了两个组件,但是组件扫描默认是不开启的,所以需要我们显示地配置一下spring,先尝试用一个java类来定义spring的装配规则。
/**
* 如果没有其他配置,spring通过以下配置会扫描CDPlayerConfig
* 所处类下的包的所有子包
/**
@Configuration
@ComponentScan
public class CDPlayerConfig {
}
但如果想要扫描多个基础包呢?
//扫描多个基础包
@Configuration
@ComponentScan(basePackages={"soundsystem","video"})
public class CDPlayerConfig {
}
上述方法扫描的基础包采用String类型的包名,类型不安全,改进采用包下的一个组件类:
@Configuration
@ComponentScan(baseClasses={CDPlayer.class,DVDPlayer.class})
public class CDPlayerConfig {
}
当然你可能还会想到,通过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:context="http://www.springframework.org/schema/context"
xmlns:c="http://www.springframework.org/schema/c"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="soundsystem" />
</beans>
2. JavaConfig装配Bean
当需要将第三方库中的组件装配到应用中时,是没有办法在他的类上添加@Component或者@Autowired的,所以可以采用java和xml,先来看java代码配置。
利用java进行配置,我们把用于配置spring的java类成为JavaConfig,他和普通的java类其实是没有多大区别的,但是作为一个配置类,最好遵循以下几个原则,当然不是强制的:
- JavaConfig放在同一个包下
- 配置代码不侵入业务代码
还是以上面的CD为例,原本的组件类不再申明为一个组件,去掉@Component,即假设他们是第三方库中的代码,我们无法添加注解
public class SgtPeppers implements CompactDisc {
private String title = "White Horse";
private String artist = "Talyor Swift";
@Override
public void play() {
System.out.println("Playing " + title + " by " + artist);
}
}
那么配置代码中就要做相应改变,配置代码去掉@ComponentScan,并且用@Bean来申明JavaBean
@Configuration
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers(){
return new SgtPeppers();
}
/*@Bean
public CDPlayer cdplayer(CompactDisc compactDisc){
return new CDPlayer(compactDisc);
}*/
@Bean
public CDPlayer cdplayer(){
return new CDPlayer(sgtPeppers());
}
}
这里Bean的注入有两种方法,上面注释掉的是通过参数注入,而下面没有注释的是通过调用方法注入,两种方法都可以但是通过参数注入更加直观,也更加常用。值得注意的是,@Bean的注解可以使用任何必要的Java功能来返回一个bean实例。
3. XML装配Bean
还是那句话,推荐使用自动装配和JavaConfig,但是不可避免会用到XML的方式进行spring的配置,因为我们会需要维护别人的代码啊。
XML申明一个Bean
<bean id="compactDisc" class="soundsystem.SgtPeppers" />
其中id是这个bean的别名,一般都会起别名,如果没有id属性,别名默认为“soundsystem.SgtPeppers#0”,#0用于计算区别于其他的Bean。
如果申明一个Bean的过程中需要注入其他的对象,或者对象,可以采用两种方法:一种是采用构造器注入,一种是采用方法注入,两两组合所以有四种实例化的方式:
1. 构造器注入对象
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<constructor-arg ref="compactDisc" />
</bean>
还可以采用c名称空间,引入名称空间是为了简写
<bean id="cdPlayer"
class="soundsystem.CDPlayer"
c:_-ref="compactDisc" />
2. 构造器注入普通属性
和注入对象稍微有一点差别
<bean id="compactDisc" class="soundsystem.BlankDisc"
<constructor-arg value="Sgt. Pepper's Lonely Hearts Club Band" />
<constructor-arg value="The Beatles" />
</bean>
名称空间写法
<bean id="compactDisc"
class="soundsystem.BlankDisc"
c:_0="Sgt. Pepper's Lonely Hearts Club Band"
c:_1="The Beatles">
</bean>
3. 方法注入对象
前面使用构造器注入,这里用setter方法注入,如果JavaBean是这样的,自动使用setter进行注入
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
@Autowired
public void CompactDisc(CompactDisc compactDisc){
this.CompactDisc = CompactDisc;
}
@Override
public void play() {
cd.play();
}
}
相应的XML用property属性来配置,和使用构造器注入是一样的
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<property name="compactDisc" ref="compactDisc" />
</bean>
当然也可以使用p名称空间
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<p:compactDisc-ref="compactDisc" />
4. 方法注入普通值
其实都以类似的方法,用P名称空间演示
<bean id="compactDisc"
class="soundsystem.BlankDisc"
p:title="Sgt. Pepper's Lonely Hearts Club Band"
p:artist="The Beatles">
</bean>
5. 注入集合不能用名称空间
名称空间可以简写,但是名称空间不能注入集合,集合的注入是这样的
<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>
4. 混合配置
最后是将JavaConfig的配置同XML配置相互结合如何使用,因为他们是互不排斥的
1. 在javaConfig中引用xml配置
所以会有两个需要装配的bean,一个是用过javaConfig装配,另一个是通过xml装配,然后我们用一个JavaConfig装配在一起
JavaConfig装配的Bean
@Configuration
public class CDConfig {
@Bean
public CompactDisc compactDisc() {
return new SgtPeppers();
}
}
Xml装配的Bean,XML文件名为cd-config.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>
通过@ImportResource注解,在javaConfig中引用xml文件
@Import引入JavaConfig文件
@Configuration
@Import(CDPlayerConfig.class)
@ImportResource("classpath:cd-config.xml")
public class SoundSystemConfig {
}
2. 在xml中引用JavaConfig配置
前面是使用@ImportResource注解,那么在XML中加载JavaConfig配置其实也类似:
<import resouse="cd-congig.xml"/>
<bean class="soundsystem.CDConfig">
介绍完了,给自己做个学习笔记,如有不对敬请指正。