一
1. 创建应用对象之间协作关系的行为通常程序装配,这也是依赖注入的本质
2. spring装配bean的三种机制 , 通常显示的配置越少越好,当必须显示配置bean的时候,推荐使用比xml更加强大的javaConfig,只有当你想使用便利的xml命名空间的时候,才应该使用xml
①:通过xml中进行显示配置
②:在java中进行显示的配置
③:隐式的bean发现机制和自动装配
3. 自动化装配bean :spring从2个角度来实现自动化装配,组件扫描和自动装配组合在一起,能够将显示配置降到最低
①组件扫描(component scanning) spring会自动发现应用上下文中所创建的bean
②:自动装配(autowiring):spring会自动满足bean之间的依赖
③:创建可被发现的bean示例
--接口
package package2;
public interface CompactDis {
void play();
}
--实现类
package package2;
import org.springframework.stereotype.Component;
//注明是组件类 告知spring要为这个类创建bean
//组件扫描默认是不启用的,所以需要显示配制一下spring,命令它去寻找带有@Component注解的类,并为其创建bean
@Component
public class Sgtprppers implements CompactDis{
private String title="这是标题";
private String artist="The Beatles";
@Override
public void play() {
System.out.println(title+"==="+artist);
}
}
--java版启动自动扫描
package package2;
import org.springframework.context.annotation.ComponentScan;
//@ComponentScan java配置启用组件扫描的方式
//如果没有其他配置的话,默认扫描的是与配置类相同的包及子包下带有@Component的注解类,自动为其创建bean
Configuration
@ComponentScan
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"
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="package2"/>
</beans>
--test
//使用了springJunit4ClassRunner,测试开始的时候自动创建spring应用上下文
@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration 需要在哪加载配置java版本 @ContextConfiguration(classes=CDPlayerConfig.class)
//@ContextConfiguration("classpath:spring.xml") xml版本
@ContextConfiguration(classes = CDPlayerConfig.class)
public class TestCd {
@Autowired
private CompactDis compactDis;
@Test
public void test() {
Assert.notNull(compactDis);
}
}
二
- 为组件扫面的bean命名,sping应用上下文中的所有的bean都会给一个id,当没有明确表明的时候,sping默认会把类名首字母小写当做id
//为bean命名
@Component("指定的名称")
@Named("指定的名称")//java依赖注入规范中所提供
- 设置组件扫面的基础包
@ComponentScan("需要扫描的包名")
//如果想要更加清晰的表明所设置的是基础包,可以通过basePackages属性进行配置,这里设置的基础包是String类型的,如果包名改变就会出现错误
@ComponentScan(basePackages="需要扫描的包名")
@ComponentScan(basePackages={"扫描包1","扫描包2"})
//可以通过设置包中所包含的类,这些类所所在的包将会作为组件扫描的基础包
@ComponentScan(basePackageClasses={配置类1.class,配置类2.class})
三
- 通过为bean添加注解实现自动装配
package package2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CDPlayer implements MediaPlayer{
private CompactDisc cd;
//当Autowired注解添加到构造方法的时候,表明当Spring创建CDPlayer bean的时候 会通过这个构造器进行实例化
// 并且会传入一个可设置给CompactDisc类型的bean
//@Autowired 和Inject(来源Java依赖注入规范)效果类似
@Autowired
public CDPlayer(CompactDisc cd) {
this.cd = cd;
}
public void play(){
cd.play();
}
//Autowired注解不进可以用在构造器上,还能用在属性的Setter方法上
//不管是构造器、Setter方法 还是其它方法,Spring都会尝试满足方法参数上所声明的依赖
//当只有一个bean匹配依赖需求的时候,这个bean会被装配起来,没有匹配的bean的时候会抛出异常,为了避免异常的出现,设置属性required=false
//当required=false 的时候 spring会尝试自动装配,但是没有匹配的bean的话,spring会让这个bean处于未装配状态,如果存在多个将会抛出异常 表示没有明确指定用哪个bean装配
@Autowired(required = false)
public void setCd(CompactDisc cd) {
this.cd = cd;
}
}
- 通过java代码装配bean
①:尽管在许多场景下都可以使用自动装配,但是有的时候需要明确配置,例如 将第三方组件装配到应用中,这时候是没有办法使用自动装配的.显示的声明bean的时候有2中方式 java代码和xml
②带有@bean注解的方法可以采用任何必要的java功能来产生bean实例,构造器和set方法只是@Bean的2个简单样例
//@Bean会告诉spring这个方法返回一个对象,该对象要注册为spring应用上下文中的bean
@Bean
public CompactDis sgtPeppers(){
return new sgtPeppers();
}
//默认情况下 bean的id与带有@Bean注解的方法名是 一样的 可以通过name进行重新命名
@Bean(name="ss")
public CompactDis sgtPeppers(){
return new sgtPeppers();
}
//这个方法并没有使用默认的构造器创建实例,而是调用了需要传入对象来构造实例
//bean默认是单例的
//这种是通过方法调用
@Bean
public CDPlayer cdPlayer(){
return new CDPlayer(sgtPeppers())
}
//当做参数调用
@Bean
public CDPlayer cdPlayer(CompactDis compactDis){
return new CDPlayer(compactDis)
}
- 通过xml装配bean
<!-- bean标签类似于JavaConfig中@Bean注解 class是全限定的类名 -->
<bean id="sgtprppers" class="package2.Sgtprppers"/>
<!--当没有指定id的时候 这个bean将会根据全限定名来进行命名"package2.Sgtprppers#1 有2个就是 package2.Sgtprppers#2
在基于JavaConfig的配置中我们需要直接负责创建bean的实例,在xml中默认调用构造器创建不用人为干预
-->
<bean class="package2.Sgtprppers"/>
<!--当spring遇到这个bean元素的时候,她会创建一个CDPlayer实例
<constructor-arg ref="compactDis"/> 元素会告知spring将要一个id为compactDis的bean引用传递到CDPlayer构造器中
作为替代方案可以使用spring的C-命名空间 必须引入标题头 xmlns:c="http://www.springframework.org/schema/c"
-->
<bean id ="cdPlayer" class="package2.CDPlayer">
<constructor-arg ref="compactDis"/>
</bean>
<!--使用c-命名空间和声明构造参数
属性名 c:开头 也就是命名空间的前缀 接下来就是要装配的构造器参数名 然后-ref 最后引用的bean id
-->
<bean id ="cd" class="package2.CDPlayer" c:cd-ref="compactDis"/>
<!--优化版
将参数吗替换成参数的索引,防止改参数名报错 因为xml中不允许数字作为属性的第一个字符,因为必须添加下划线作为前缀
当只有一个参数的时候可以 直接写c:_-ref
-->
<bean id ="cd2" class="package2.CDPlayer" c:_0-ref="compactDis"/>
- 将字面量注入到构造器中
private String title;
private List<String> tracks;
<!--
因为是构造参数必须要声明它 可以传null 当调用方法的时候就会出现空指针异常
-->
<bean id="balkDiscList" class="package2.BalkDiscList">
<constructor-arg value="xxx"/>
<constructor-arg><null/></constructor-arg>
</bean>
<!--给List赋值 预制类似我们也可以使用<ref>元素替代<value>,实现bean引用列表的装配
<list>
<red bean="xxx1"/>
<red bean="xxx2"/>
<list>
set与list赋值区别不大 但是set会忽略重复的值,存放顺序不能保证
-->
<bean id="balkDiscList1" class="package2.BalkDiscList">
<constructor-arg value="xxx"/>
<constructor-arg>
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</constructor-arg>
- 设置属性
public class CDPlayer {
//
private CompactDis compactDis;
@Autowired
public void setCompactDis(CompactDis compactDis) {
this.compactDis = compactDis;
}
public void play(){
compactDis.play();
}
}
<!--在创建bean的时候不会报错 但是调用方法的时候会报空指针异常 因为没有注入调用的那个属性-->
<bean id="cdPlayer" class="package2.CDPlayer"/>
<!--property元素为属性的set方法提供与constructor-arg 元素相同的功能
此处可以使用p标签 引入头 xmlns:p="http://www.springframework.org/schema/p"
p标签与c标签类似
-->
<bean id="cdPlayer2" class="package2.CDPlayer">
<property name="compactDis" ref="compactDis"></property>
</bean>
<!--
p标签使用规则
p:compactDis(属性名)-ref(注入bean引用)="所注入bean的id"
-->
<bean id="cdPlayer2" class="package2.CDPlayer" p:compactDis-ref="compactDis"></bean>
- 设置属性的字面量
public class BalkDiscList {
private String title;
private List<String> tracks;
public void setTitle(String title) {
this.title = title;
}
public void setTracks(List<String> tracks) {
this.tracks = tracks;
}
}
<!-- p标签与c标签一样 没有ref的是给字面量赋值
我们不能使用p:标签来装配集合 但是我们可以使用 spring util-命名空间来简化
引入标签头 xmlns:util="http://www.springframework.org/schema/util"
-->
<bean id="really" class="package2.BalkDiscList">
<property name="title" value="xxx"/>
<property name="tracks">
<list>
<value>1</value>
<value>2</value>
</list>
</property>
</bean>
<!--使用util标签-->
<util:list id="trackList">
<value>1</value>
<value>2</value>
</util:list>
<bean id="really" class="package2.BalkDiscList" p:title="xxx" p:tracks="trackList"/>
- spring util-命名空间中的元素
<util:constant> 引入某个类型的public static域,并将器暴露为bean
<util:list> 创建一个java.util.List类型的bean,其中包含值和引用
<util:map> 创建一个java.util.Map类型的bean,其中包含值和引用
<util:properties> 创建一个java.util.properties类型的bean
<util:properties-path> 引用一个bean的属性(或内嵌属性),并将其暴露为bean
<util:set> 创建一个java.util.Set类型的bean,其中包含值和引用
- 导入和混合配置
在spring应用中,尽管可能会同时使用自动化和显示配置,即便你更喜欢通过javaConfig实现显示配置,但是有的时候XML确是最佳的方案
关于混合配置,第一件事需要了解就是自动装配时,它并不在意要装配的bean来自哪里
@Configuration
public class CDConfig {
@Bean
public CompactDis compactDis() {
return new SgtPeppers();
}
}
//compactDis()方法已经移除,我们需要将两个类组合到一起
//一种是使用@Import注解导入 CDConfig
//或者采用一种更高级的方法 去创建一个更高级别的配置 同时引入这两个配置类@Import({CDConfig.class,CDPlayerConfig.class})
@Configuration
@Import(CDConfig.class)
public class CDPlayerConfig {
@Bean
public CDPlayer cdPlayer(CompactDis compactDis){
return new CDPlayer(compactDis);
}
}
//当一个类配置在xml中 一个是通过javaConfig配置的时候 可以类中使用注解@ImportResource("classpath:xml文件名")