spring 装配bean
spring装配bean的三种机制
- 在XML中进行显示配置
- 在Java中进行显示配置
- 隐式的bean发现机制和自动装配
自动化装配bean
Spring从两个角度来实现自动化装配
- 组件扫描:Spring会自动发现应用上下文中所创建的bean
- 自动装配:Spring自动满足bean之间的依赖
Spring中有4种类型的组件自动扫描注释类型
- @Component – 指示自动扫描组件。
- @Repository – 表示在持久层DAO组件。
- @Service – 表示在业务层服务组件。
- @Controller – 表示在表示层控制器组件。
开启自动组件扫描
1 xml显式配置
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="com.yiibai.customer" />
</beans>
2 注解式配置
@Configuration
@ComponentScan
public calss CDPlayerConfig(){
}
CDPlayerConfig中并没有显式地声明任何bean,只不过它是用来@ComponentScan注解,这个注解能够在spring中弃用组件扫描
如果没有其他配置的话,@ComponentScan默认会扫描域配置类相同的包
无论注解式配置或者xml显示配置,我们都可以明确地设置扫描的基础班
<!-- 使用Annotation自动注册Bean,只扫描@Controller -->
<!-- base-package 如果多个,用“,”分隔 -->
<context:component-scan base-package="com.digitalpublishing.sage.dc.controller" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
@ComponentScan(basePackages={"controller","service"})
创建可被发现的bean
创建POJO 加上注解@Component
组件扫描默认是不启用的,我们需要显示配置一下Spring,从而命令他去需找导游@Component注解的类
,并为其创建bean
通过为bean添加注解实现自动装配
@Autowired注解不仅能够用在构造器上,还能用在属性的Setter方法上
在spring初始化之后,它会尽可能去满足bean的依赖,不管是构造器,setter方法还是在其他的方法,spring都会尝试满足方法参数上所声明的依赖
假如有且只有一个bean匹配依赖需求的话,那么这个bean将会被装配进来
如果没有匹配的bean,那么在应用上下文创建的时候,spring会抛出一个以上,为了避免异常的出现,你可以将@Autoeired的required属性设置为false
但如果将required属性设置为false时,spring会尝试执行自动装配,但是如果没有匹配的bean的话,spring将会让这个bean处于未装配的状态.如果在你的代码中没有进行null检查的话,这个处于未装配状态的属性可能会导致空指针异常
尽管很多场景下通过组件扫描和自动装配实现spring的自动化配置是更为推荐的方式,但如果你想要将第三方库中的组件装配到你的应用总,在这种情况下,是没有办法在它的类上添加@Component和@Autowired注解的,因此就不能使用自动化装配的方案了
这种情况下,你必须要采用显式装配的方式,在显式配置的时候,有两种可选方案
- java
- xml
通过Java代码装配bean
进行显式配置是,JavaConfig是更好的方案,它更强大,类型安全并且对重构友好
因为它就是Java代码,就像应用程序中的其他Java代码一样
但JavaConfig与其他的Java代码又有所区别,JavaConfig是配置大妈,这意味着它不应该包含任何业务逻辑,JavaConfig也不应侵入到业务逻辑代码中,其应放到单独的保重,使它与其他的应用程序逻辑分离开来
创建配置类
创建配置类,为其添加@Configuration注解,@Configuration注解表明这个类是一个配置类,该类应该包含在spring应用上下文中如何创建bean的细节
声明简单的bean
要在JavaConfig中声明bean,我们需要编写一个方法,这个方法会创建所需类型的实例,然后给这个方法添加@Bean注解
@Bean注解会告诉spring这个方法将会返回一个对象,该对象要注册为spring应用上下文中的bean,方法体中包含了最终产生bean实例的逻辑
@Configuration
public class CDPlayerConfig{
@Bean
public CompactDisc sgtPeppers(){
return new SgtPeppers();
}
}
借助JavaConfig实现注入
@Configuration
public class CDPlayerConfig{
@Bean
public CompactDisc sgtPeppers(){
return new SgtPeppers();
}
@Bean
public CDPlayer cDPlayer(){
return new CDPlayer()(sgtPeppers());
}
}
cDPlayer()方法像sgtPeppers()方法一样,同样使用了@Bean注解,这表明这个方法会创建一个bean实例并将其注册到spring应用上下文中,所创建的beanID为cdPlayer,与方法的名字相同
cDPlayer()的方法体与sgtPeppers()稍微有些区别,在这里并没有使用默认的构造器构建实例,而是调用了需要传入CompactDisc对象的构建器来创建CDPlayer实例
看起来,CompactDisc是荣国调用sgtPeppers()得到的,但情况并非如此,因为sgtPeppers()方法上添加了@Bean注解,spring将会拦截所有对他的调用,并确保直接返回该方法所创建的bean,而不是每次都对其进行实际的调用
通过xml装配bean
创建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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context">
</beans>
声明一个简单的
<bean id="demoController" class="soundsystem.CDPlayer" />
这里声明了一个很简单的bean,创建这个bean的类通过class属性来指定的,并且要使用全限定的类名
借助构造器注入初始化的bean
在springxml配置中,只有一种声明bean的方式:使用
xml声明DI时,具体到构造器注入,有梁总节本配置方案选择
- 使用spring3.0所引入的c-命名空间
<bean id="cdPlayer" class="soundsystem.CDPlayer"
<constructor-arg ref="copactDisc" />
</bean>
当spring遇到这个
c-命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cdPlayer" class="soundsystem.CDPlayer"
c:cd-ref="compactDisc" />
</beans>
也可以直接注入值
将字面量注入到构造器中
我们不止可以将对象的引用装配到依赖于它们的其他对象之中,而且可以用一个字面量值来配置对象
例如:
//POJO
public class BlankDisc {
private String title;
private String artist;
public BlankDisc(String title,String artist){
this.title = title;
this.artist = artist;
}
public void play(){
System.out.println("playing" + title + "by" ++ artist);
}
}
<bean id="cdPlayer" class="soundsystem.CDPlayer" >
<constructor-arg value="sgt.Pepper's lonely hearts clue band" />
<constructor-arg value="The Beatles" />
</bean>
使用value属性,通过该属性表明给定的值要以字面量的形式注入到构造器中
c-命名空间
第一种,引用构造器参数的名字
<bean id="demoController" class="soundsystem.CDPlayer" >
<c:_title="sgt.Pepper's lonely hearts clue band" />
<c:_artist=="The Beatles" />
</bean>
第二中,通过参数索引装配相同的字面量值
<bean id="demoController" class="soundsystem.CDPlayer" >
<c:_0="sgt.Pepper's lonely hearts clue band" />
<c:_1=="The Beatles" />
</bean>
xml不允许摸个元素的多个属性具有相同的名字,因此,如果有两个或更多的构造器参数的话,我们不能简单地使用下划线进行标识.但是如果只有一个构造参数的话,就可以
装配集合 c-命名空间无法作答
//POJO
public class BlankDisc {
private String title;
private String artist;
private List<String> tracks;
public BlankDisc(String title,String artist){
this.title = title;
this.artist = artist;
this.tracks = tracks;
}
public void play(){
System.out.println("playing" + title + "by" ++ artist);
}
}
<bean id="cdPlayer" class="soundsystem.CDPlayer" >
<constructor-arg value="sgt.Pepper's lonely hearts clue band" />
<constructor-arg value="The Beatles" />
<constructor-arg><null/></constructor-arg>
</bean>
因为增加了一个tarcts属性,在声明bean的时候 我们必须给出声明,最简单的方法就是将列表设置为null,因为它是要给构造器参数,我们必须给出声明,所以采用上述方式传递null给他
但更好的解决办法是提供一个列表
例如:
<bean id="cdPlayer" class="soundsystem.CDPlayer" >
<constructor-arg value="sgt.Pepper's lonely hearts clue band" />
<constructor-arg value="The Beatles" />
<constructor-arg>
<list>
<value>sgt.Pepper's lonely hearts clue band</value>
<value>A</value>
<value>B</value>
</list>
</constructor-arg>
</bean>
也可以用
<bean id="cdPlayer" class="soundsystem.CDPlayer" >
<constructor-arg value="sgt.Pepper's lonely hearts clue band" />
<constructor-arg value="The Beatles" />
<constructor-arg>
<list>
<ref bean="sagtPepers"/>
<ref bean="A"/>
<ref bean="B"/>
</list>
</constructor-arg>
</bean>
设置属性 (setter注入)
<bean id="cdPlayer" class="soundsystem.CDPlayer" >
<property name="compactDisc" ref="compactDisc" />
</bean>
//<property>元素为属性的setter方法提供的功能,与<constructor-arg>元素为构造器所提供的功能一样
//在本例中,它引用了ID为compactDisc的bean(通过ref属性),并将期注入到compactDisc属性中(通过setCompactDisc()方法).