一、Spring 装配Bean
1.1 Spring配置的可选方案
Spring提供了三种主要的装配机制:
- 在XML中进行显式配置。
- 在Java中进行显式配置。
- 隐式的bean发现机制和自动装配。
在很多场景下,选择哪种方案很大程度上就是个人喜好的问题,你尽可以选择自己最喜欢的方式。
1.2 自动化装配bean
Spring从两个角度来实现自动化装配:
- 组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。
- 自动装配(autowiring):Spring自动满足bean之间的依赖。
1)创建可被发现的bean
@Component 注解表明一个类会作为组件类,并告知Spring要为这个类创建bean
package mine;
public interface Fruit {
String getName();
String color();
}
import org.springframework.stereotype.Component;
@Component
public class Apple implements Fruit{
@Override
public String getName() {
return "Apple";
}
@Override
public String color() {
return "Red";
}
}
2)启用组件扫描(二选一)
使用基于Java的spring配置
@Configuration用于定义配置类, @ComponentScan 默认扫描该类所在的包下所有的配置类
package mine;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class MyApplicationContext {
}
通过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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!-- 自动扫描 -->
<context:component-scan base-package="mine" />
</beans>
3)为组件扫描的bean命名
@Component默认是将类名的第一个字母变为小写,也可以通过一下方式自定义一个名称
@Component("myApple")
public class Apple implements Fruit{
}
还可以使用Java依赖注入规范中的@Named注解来为bean设置ID,首先需要引入如下maven配置
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
import javax.inject.Named;
@Named
public class Apple implements Fruit{
}
4) 设置组件扫描的基础包
@ComponentScan默认情况只扫描配置类所在的包,你可以通过指定包名来设置你要扫描的包
@Configuration
// 方法一
@ComponentScan(basePackages = {"package1","package2"})
public class MyApplicationContext {
}
@Configuration
// 方法二,这些类所在的包将会作为组件扫描的基础包。
@ComponentScan(basePackageClasses = {Apple.class, Fruit.class})
public class MyApplicationContext {
}
5)通过为bean添加注解实现自动装配
自动装配就是让Spring自动满足bean依赖的一种方法,在满足依赖的过程中,会在Spring应用上下文中寻找匹配某个bean需求的其他bean。为了声明要进行自动装配,我们可以借助Spring的@Autowired注解。
@Autowired
public static Apple apple;
@Autowired注解可以用在类的任何方法上,不管是构造器、Setter方法还是其他的方法,Spring都会尝试满足方法
参数上所声明的依赖。
如果没有匹配的bean,那么在应用上下文创建的时候,Spring会抛出一个异常。为了避免异常的出现,你可以将@Autowired的
required属性设置为false:
@Autowired(required = false)
1.3 通过Java代码装配bean
尽管在很多场景下通过组件扫描和自动装配实现Spring的自动化配置是更为推荐的方式,但有时候自动化配置的方案行不通,因此需要明确配置Spring。比如说,你想要将第三方库中的组件装配到你的应用中,在这种情况下,是没有办法在它的类上添加@Component和@Autowired注解的,因此就不能使用自动化装配的方案了。
1)创建配置类
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyApplicationContext {
}
2)声明简单的bean
@Bean注解会告诉Spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文中的bean。方法体中包含了最终产生bean实例的逻辑。默认情况下,bean的ID与带有@Bean注解的方法名是一样的,可以通过name属性设置一个不同的名称。,带有@Bean注解的方法可以采用任何必要的Java功能来产生bean实例,默认情况下,Spring中的bean都是单例的。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackageClasses = {Apple.class, Fruit.class})
public class MyApplicationContext {
// 声明一个简单的bean
@Bean
public Apple apple(){
return new Apple();
}
// 为bean显示声明一个名称
@Bean(name = "myApple")
public Apple getApple(){
return new Apple();
}
}
1.4 通过XML装配bean
1)创建XML配置文件:applicationContext.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<!-- 自动扫描 -->
<context:component-scan base-package="mine" />
</beans>
2)声明一个简单的<bean>
class的值为类的全限定名,因为没有明确给定ID,所以这个bean将会根据全限定类名来进行命名。在本例中,bean的ID将会是“mine.Apple#0”。其中,“#0”是一个计数的形式,用来区分相同类型的其他bean。如果你声明了另外一个Apple,并且没有明确进行标识,那么它自动得到的ID将会是“mine.Apple#1”。
<bean class="mine.Apple"/>
手动指定一个bean名称
<bean id="myApple" class="mine.Apple" />
3)借助构造器注入初始化bean
在Spring XML配置中,只有一种声明bean的方式:使用<bean>元素并指定class属性。Spring会从这里获取必要的信息来创建bean。
但是,在XML中声明DI时,会有多种可选的配置方案和风格。具体到构造器注入,有两种基本的配置方案可供选择:
- <constructor-arg>元素
- 使用Spring 3.0所引入的c-命名空间
使用<constructor-arg>元素会告知Spring要将一个ID为beanID的bean引用传递到mine.Apple的构造器中。
<bean class="mine.Apple">
<constructor-arg ref="beanID" />
</bean>
使用Spring 3.0所引入的c-命名空间。
<bean class="mine.Apple" c:name-ref="myApple"/>
4) 将字面量注入到构造器中
假设有如下示列
public class Apple implements Fruit{
private String name;
private String color;
public Apple(){
}
public Apple(String name, String color) {
this.name = name;
this.color = color;
}
@Override
public String getName() {
return name;
}
@Override
public String color() {
return color;
}
}
配置如下(二选一)
<bean class="mine.Apple">
<constructor-arg value="Apple"/>
<constructor-arg value="Red"/>
</bean>
<bean class="mine.Apple" c:name="Apple" c:color="Red"/>
5)装配集合
加入有如下示列代码
public class Apple implements Fruit{
private String name;
private String color;
private List<String> type;
public Apple(){
}
public Apple(String name, String color, List<String> type) {
this.name = name;
this.color = color;
this.type = type;
}
@Override
public String getName() {
return name;
}
@Override
public String color() {
return color;
}
}
传入null
<bean class="mine.Apple">
<constructor-arg value="Apple"/>
<constructor-arg value="Red"/>
<constructor-arg><null/></constructor-arg>
</bean>
为集合传值,其中如果集合是Object类型的话,我们也可以使用<ref bean/>替换<value>
<bean class="mine.Apple">
<constructor-arg value="Apple"/>
<constructor-arg value="Red"/>
<constructor-arg>
<list>
<value>type one</value>
<value>type two</value>
</list>
</constructor-arg>
</bean>
6)设置属性
使用 <property>元素设置
<bean class="mine.Apple">
<property name="name" value="Apple" />
<property name="color" value="Apple" />
<property name="type">
<list>
<value>type one</value>
<value>type two</value>
</list>
</property>
</bean>
使用p命名空间
<util:list id="AppleType">
<value>apple one</value>
<value>apple two</value>
</util:list>
<bean class="mine.Apple" p:color="" p:name="" p:type-ref="AppleType" />
7) 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:property-path | 引用一个bean的属性(或内嵌属性),并将其暴露为bean |
util:set | 创建一个java.util.Set类型的bean,其中包含值或引用 |
1.5 导入和混合配置
1)使用@Import导入其他配置类
@Configuration
@Import(Apple.class)
@ComponentScan(basePackageClasses = {Apple.class, Fruit.class})
public class MyApplicationContext {
}
2)在JavaConfig中引用XML配置
要在Java配置类中使用XML配置需要用到@ImportResource注解
@Configuration
@Import(Apple.class)
@ImportResource("classpath:xml_name.xml")
@ComponentScan(basePackageClasses = {Apple.class, Fruit.class})
public class MyApplicationContext {
}
3)在XML中引入其他XML文件
<import resource="applicationContext.xml" />
4)在XML配置中引用JavaConfig
只需要为Java创建一个bean即可
<bean class="mine.MyApplicationContext"/>