一、装配的3种方式(3种方式可以交叉使用)
1、在XML中进行显式配置
2、在Java中进行显式配置
3、隐式的bean发现机制和自动装配(推荐)
二、自动装配bean(方式1)
1、声明bean
使用@Component注解定义bean
@Component("name") 将类定义为组件并命名,可以不命名,默认组件id为将类名第一个字母改为小写。
@Named("name") 大多数情况下与@Component("name")相同,注解来源于 Java 依赖注入规范。
@Component
public class SgtPeppers implements CompactDisc{
private String title = "title";
private String artist = "artist";
public void play(){
System.out.print("Playing "+title+" by "+ artist);
}
}
2、开启组件扫描
寻找带有@Component注解的类,为其创建bean
方式1:java
@Configuration
@ComponentScan
public class CDPlayerConfig {
//这里没有任何显式配置
//在接下来的java配置这里将添加配置关系
}
a、@Configuration:表明这是一个配置类
b、@ComponentScan:启用组件扫描,默认扫描与配置类相同的包及子包,查找带有@Component注解的类
如果需要设置自定义扫描不同的包:
(1)@ComponentScan(“com.xxx.xxx”) :即给value属性赋值
(2)@ComponentScan(basePackages=“com.xxx.xxx”)
@ComponentScan(basePackages={“com.a.xxx”,"com.b.xxx"}) :复数形式
(3)前2种类型不安全(重构时基础包可能发生变更)
@ComponentScan(basePackageClasses={a.class,b.class}) :这些类所在的包将会作为组件扫描基础包;
方式2:xml
在xml中配置<context:component-scan base-package=”com.xxx.xx“>
3、装配bean
@Autowired:Sping特有注解,根据类型匹配,可以装配在类的任意方法上;
@Inject:来源于Java依赖注入规范,和@Autowired差别很小;
匹配规则:
(1)如果只有一个bean匹配,装配这个bean
(2)如果没有匹配的bean,抛异常(加required=false不会抛)
(3)多个bean满足,抛异常
@Component
public class CDPlayer implements MediaPlayer {
private CompactDisc cd;
// 表明当spring创建CDPlayer bean时会通过构造器来进行实例化
// 并且会传入一个可设置给CompactDisc的bean
// 构造方法
@Autowired
public CDPlayer(CompactDisc cd){
this.cd = cd;
}
// setter方法
@Autowired(required = false)
public void setCompactDisc(CompactDisc cd){
this.cd = cd;
}
// 普通方法
@Autowired
public void insertDisc(CompactDisc cd){ // 什么时候创建bean呢??
this.cd = cd;
}
}
// 创建CDPlayer bean时自动注入CompactDisc,以上3种方式均可,和方法名无关。无需显式调用
四、通过java代码装配bean-方式2
如果将第三方组件装配到自己应用中,无法通过添加@Component和@Autowired注解,需要使用显式配置:Java和xml;
1、创建配置类:添加@Configuration注解
2、声明bean:使用@Bean注解
@Bean:返回的对象将注册为上下文中的bean,默认bean id与@Bean注解的方法名一样,此处即sgtPeppers;
@Bean(name=“stupid”):重命名id为stupid
(@Bean = @Component + @ComponentScan+@Autowired)
// 去掉了ComponentScan,不使用组件扫描,使用显式配置创建bean
@Configuration
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();// 方法体内容可以随意编排,最终返回对象都将作为bean
}
}
3、装配bean:
// 去掉了ComponentScan,不适用组件扫描,使用显式配置创建bean
@Configuration
public class CDPlayerConfig {
@Bean
public CompactDisc sgtPeppers() {
return new SgtPeppers();// 方法体内容可以随意编排,最终返回对象都将作为bean
}
@Bean
public CDPlayer cdPlayer() {
// sgtPeppers()有添加注解@Bean,Spring会拦截所有对它的调用,并返回该方法创建的bean,
而不是每次对其进行实际调用
return new CDPlayer(sgtPeppers());
}
// 当Spring调用cdPlayer()创建CDPlayer bean时会自动装配一个CompactDisc到方法中
// 这种方式不会要求CompactDisc声明到同一个配置类中,可以通过组件扫描或xml方法都行
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc) {
return new CDPlayer(compactDisc);
}
}
问题:cdPlayer()、sgtPeppers()在什么时候被调用的?自动or手动? spring容器启动时自动
五、xml装配bean-方式3
1、声明bean
<beans ...>
<!--class属性:全限定类名,存在风险当实际类名称变更,此处无法验证 -->
<bean class="com.sankuai.m" />
<!-- 没有明确指定id,默认根据全限定名命名,此处即”com.sankuai.m#0"
#0用来区分相同类型其他bean,如果另外声明这个类的bean并且没有明确标识,
自动得到的id将是”com.sankuai.m#1"->
<!--id属性:指定bean名称 -->
<bean id="t" class="com.sankuai.t" />
</beans>
2、装配bean
构造器注入bean引用:
(1)<constructor-arg>元素
<bean id="t" class="com.sankuai.t" >
<contructor-arg ref = "cc"> <!--cc为其他bean的id -->
</bean>
(2)Spring 3.0引入的c-命名空间
a、xml顶部声明c-命名空间和模式
b、使用
<!--
”c:“ - 命名空间前缀
”cd“:要装配的构造器参数名称,有点鸡肋
”-ref“:代表装配bean的引用
-->
<bean id="t" class="com.sankuai.t"
c:cd-ref = "cc"/>
<!--
"_0":表示第一个构造器参数
-->
<bean id="t" class="com.sankuai.t"
c:_0-ref = "cc"/>
<!--
"_":此处构造器只有一个参数,可以省略索引号
-->
<bean id="t" class="com.sankuai.t"
c:_-ref = "cc"/>
注入字面量:
public class BlankDisc implements CompactDisc{
private String title;
private String artist;
public BlankDisc(String title,String artist){
this.title=title;
this.artist=artist;
}
public void play(){
System.out.println("xxx");
}
}
装配方式:
<!--使用value,不用ref -->
<bean id="compactDisc" class="soundsystem.BlankDisc">
<constructor-arg value="lonely hearts club band"/>
<constructor-arg value="The Beatles"/>
</bean>
<!--去掉了 -ref,使用"_参数名"-->
<bean id="compactDisc" class="soundsystem.BlankDisc"
c:_title="lonely hearts club band"
c:_artist="The Beatles"/>
</bean>
<!-- 参数名转换为索引号 -->
<bean id="compactDisc" class="soundsystem.BlankDisc"
c:_0="lonely hearts club band"
c:_1="The Beatles"/>
</bean>
<!-- 只有一个参数,省略索引号 -->
<bean id="compactDisc" class="soundsystem.BlankDisc"
c:_="lonely hearts club band"/>
</bean>
注入集合:
P56页,目前c-命名空间无法装配集合
3、设置属性
注入bean引用:
(1)<property> 方式
<!-- 引用id为compactDisc的bean(通过ref属性),将其注入到compactDisc
属性中(通过setCompactDisc方法) -->
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<property name="compactDisc" ref="compactDisc"/>
</bean>
问题:上面 @Autowired属性的作用是?自动注入compactDisc属性
(2)p-命名空间
a、xml顶部声明
b、使用
<!--
"p:":前缀
"compactDisc":属性名
-->
<bean id="cdPlayer" class="soundsystem.CDPlayer"
p:compactDisc-ref="compactDisc">
</bean>
注入字面量:
(1)<property> 方式
<!-- 相对于引用,将ref改为value-->
<bean id="cdPlayer" class="soundsystem.CDPlayer">
<property name="compactDisc" value="value xxxx"/>
</bean>
(2)p-命名空间
<bean id="cdPlayer" class="soundsystem.CDPlayer"
p:title="title value xxx"
p:artist="artist value xxx">
<property name="age" value="333" />
</bean>
和构造器一样,注入字面量和引用的区别在于是否带有ref;