Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系。但作为开发人员,需要告诉spring创建哪些bean并且如何装配。spring提供了三种主要的装配机制:
- 在xml中进行显示配置
- 在java中进行显示配置
- 隐式的bean发现机制和自动装配
自动化装配bean
使用@component 注解创建可被spring发现的bean。例如:
package springdemo.test1.entity.impl; import org.springframework.stereotype.Component; import springdemo.test1.entity.ICar; @Component public class AudiCar implements ICar{ String carName = "audi"; @Override public void drive() { System.out.println(carName + "is running"); } }
AudiCar使用了@Component注解,spring通过启用组件扫描,会自动寻找带有@Component注解的类,并为其创建bean。
启用组件扫描有两种方式:
- 使用java配置
- 使用xml启用
java配置启用:
package springdemo.test1.entity.config; import org.springframework.context.annotation.ComponentScan;
@Configuration @ComponentScan public class CarConfig { }
类CarConfig使用@ComponentScan注解启用组件扫描,默认会扫描与配置类相同的包。
可以发现CarConfig和AudiCar在不同的包中(方便管理),因此还需要配置扫描的基础包:
- 直接设置value属性
@Configuration @ComponentScan("impl") public class CarConfig { }
- 使用basePackages属性设置
@Configuration @ComponentScan(basePackages="impl") public class CarConfig { }
- 使用basePackages属性设置多个
@Configuration @ComponentScan(basePackages= {"impl","config"}) public class CarConfig { }
- 使用basePackageClasses,会设置这些类所在的包为扫描基础包
@Configuration @ComponentScan(basePackageClasses= {ICar.class,CarConfig.class}) public class CarConfig { }
使用xml启用:
<context:component-scan base-package="springdemo.test1.entity.impl" />
通过为bean添加注解实现自动装配 (@Autowired)
package springdemo.test1.entity.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import springdemo.test1.entity.ICar; import springdemo.test1.entity.IEngine; @Component public class AudiCar implements ICar{ String carName = "audi"; private IEngine engine; @Autowired public AudiCar(IEngine engine) { this.engine = engine; } @Override public void drive() { engine.output(); System.out.println(carName + "is running"); } }
@Autowired注解不仅能够用在构造器上,还能用在属性的setter方法上。
@Autowired public void setIEngine(IEngine engine) { this.engine = engine; }
在spring初始化bean之后,它会尽可能得去满足bean的依赖。不管是构造器、setter方法还是其他方法,spring都会尝试满足方法参数上所声明的依赖。假如有且只有一个bean匹配依赖需求的话,那么这个bean将会被装配进来。
通过java代码装配bean
使用@Configuration 注解创建配置类,该类应该包含spring应用上下文中如何创建bean的细节。
要在javaconfig中声明bean,只需要编写一个方法,该方法会创建所需类型的实例,然后给该方法添加@Bean注解
@Configuration public class CarConfig2 { @Bean public IEngine setIEngine() { return new AudiEngine(); } }
至于该方法中如何产生bean实例,只受java语言的限制。
借助javaConfig实现注入
@Configuration public class CarConfig2 { @Bean public IEngine setIEngine() { return new AudiEngine(); } @Bean public ICar getCar() { return new AudiCar(setIEngine()); } }
总之,使用javaConfig配置bean和装配依赖关注两点就好:一是使用@Configuration 注解创建配置类,二是使用@Bean注解完成bean的创建逻辑和依赖的注入。
使用xml来装配bean
在spring配置文件中使用<bean>元素声明bean:
<bean id="iEngine" class="springdemo.test1.entity.impl.AudiEngine"/>
用xml方式声明bean的一些特征:
- 自己不用直接负责创建bean实例了,在基于javaConfig的配置中,需要自行创建bean,当spring发现<bean>元素时,他会调用AudiEngine的默认构造器来创建。
- 设置给cless属性的值是字符串,不能从编译期检查中知晓类型字符串是否正确。(不过目前IDE都能做检查,鼠标在字符串上,按住ctr看是否能跳转)
在xml中配置bean,只有一种可选方式,就是使用<bean>元素并指定class属性,spring会自行创建bean。
但是在xml中声明DI时,有两种依赖注入的方式:
- 构造器注入
- 属性注入
构造器注入
使用<constructor-arg ref=""/> 实现构造器注入
<bean id="iEngine" class="springdemo.test1.entity.impl.AudiEngine"/> <bean id="iCar" class="springdemo.test1.entity.impl.AudiCar"> <constructor-arg ref="iEngine"/> </bean>
使用spring3.0所引入的c-命名空间 实现构造器注入
<bean id="iCar" class="springdemo.test1.entity.impl.AudiCar" c:engine-ref="iEngine"/>
以“c:”开头,即命名空间前缀,接下来是要装配的构造器的参数名,在此之后是“-ref”,表明装配的是一个引用。
属性注入
<bean id="iCar" class="springdemo.test1.entity.impl.AudiCar">
<property name="engine" ref="iEngine"/>
</bean>
同样也有“p-”命名空间属性注入风格:
<bean id="iCar" class="springdemo.test1.entity.impl.AudiCar" p:engine-ref="iEngine"/>
p-命名空间的约定同c-命名空间的约定一样。
注意:如果注入的不是bean引用,而是字面量。
<constructor-arg value=""/> <bean c:_0="123" c:_1="456"/>
<property name="engine" value=""/> <bean p:_0="123" p:_1="456"/>
导入和混合配置
首先要说的是自动装配时,它并不在意要装配的bean来自哪里,自动装配的时候会考虑spring容器中的所有bean,不管它是在javaConfig中或是在xml中声明的还是通过组件扫描获取到的。
如何在javaConfig中引用xml配置
@ImportResource("classpath:applicationContext-bean.xml")
另外javaConfig的配置也可以通过@Import(CarConfig.class) 注解进行整合
如何在xml中引用javaConfig配置
使用<bean>元素将javaConfig配置类声明为xml中的bean即可。
同样地,xml配置文件自身的整合可以使用元素<import resource=""/>
<import resource="engine.xml"/>