1、Spring装配Bean的三种方式
1.1 自动化配置
Spring从两个角度实现自动化装配:
- 组件扫描: Spring自动发现应用上下文中所创建的bean;
- 自动扫描: Spring自动满足bean之间的依赖;
1.1.1 创建Bean
(1)创建bean: 创建类时使用 @Component 注解告知Spring为该类创建bean,若想为该bean设置ID值,则需要将期望的ID传给@Component注解。
@Component("期望的bean的ID")
public class TestBean(){
...
}
(2)启用组件扫描: 使用 @ComponentScan 注解在Spring中启用组件扫描,可以通过设置value属性来指定需要扫描的基础包(创建bean的包),若未给@ComponentScan注解设置属性,则其会按照默认规则,以配置类所在的包作为基础包来扫描组件。
//扫描基础包
@Configuration
@ComponentScan(basePackages = "指定的扫描的基础包名称")
public class TestBeanConfig(){
...
}
//扫描指定为包中所含的类或接口
@Configuration
@ComponentScan(basePackageClasses = 指定的扫描的类或接口)
public class TestBeanConfig(){
...
}
1.1.2 设置属性
使用 @Autowired注解实现自动装配(Spring自动满足bean依赖的一种方法,即在Spring应用的中寻找匹配某个bean需求的其他bean),当Spring中找不到匹配的bean时,会抛出异常,为了避免抛出异常,可以将required属性设为false。
@Component("otherBean")
public class OtherBean(){
...
}
//在testBean这个bean中使用构造函数时需要调用OtherBean这个bean,使用@Autowired实现自动装配
@Component("testBean")
public class TestBean(){
private OtherBean ob;
@Autowired
public TestBean(OtherBean ob){
this.ob = ob;
}
}
1.2 基于Java的显式配置
1.2.1 创建Bean
(1)使用@Bean注解产生bean:
告诉Spring该方法会返回一个对象,Spring要为该对象创建一个bean。
//Spring中为SetBean(继承了TestBean)创建一个bean
@Bean(name = "期望的bean的ID")
public TestBean setBean(){
return new SetBean();
}
1.2.2 设置属性
(1)使用@Configuration注解设置bean的属性:
表明该类为配置类,该类包含创建bean的细节。
@Configuration
public class TestBean(){
...
}
1.3 基于XML的显式配置
1.3.1 创建Bean
(1)声明< bean >:
//<bean id = "想要为bean命名的id" class = "需要创建的bean的类名">
<bean id = "testBean" class = "demo.TestBean" />
</bean>
(2)注入初始化bean:
- 使用<constructor - arg>元素:
使用ref进行引用,如下所示,当Spring遇到testBean时,会创建一个TestBean实例,<constructor - arg>会告知Spring将id为otherBean的bean引用传递到TestBean的构造函数中。
<bean id = "testBean" class = "demo.TestBean" />
<constructor-arg ref = "otherBean">
</bean>
- 使用c-命名空间(Spring3.0或更高)
1.3.2 设置属性
(1)< property >元素:
使用< property>元素为Setter方法进行依赖注入,如下所示,引用ID为otherBean的bean,将其注入到testBean的Setter方法中,使用value属性可以指定注入的内容。
<bean id = "testBean" class = "demo.TestBean" />
<property name = "otherBean" ref = "otherBean">
</bean>
//指定<property>元素的value属性
<bean id = "testBean" class = "demo.TestBean" />
<property name = "otherBean" value = "data">
</bean>
2、高级装配
2.1 环境与profile
2.1.1 配置profile bean
(1)在Java配置中profile:
可以使用 @Profile注解指定某一个bean属于哪一个profile,使用了该注解的bean只有在profile被激活时才会创建。
@Configuration
public class TestBean{
@Bean(destoryMethod = "shutdown")
@Profile("dev")
public OtherBean getBean(){
return new OtherBean();
}
}
(2)在XML中配置profile:
可以通过< beans >元素的profile属性设置或者在< beans >中嵌套< beans >元素
2.1.2 激活profile
Spring需要依赖两个独立的属性:spring.profiles.active和spring.profiles.default,如果设置了spring.profiles.active属性,那么它的值就会用来确定哪个profile是激活的,若未设置spring.profiles.active的值,则Spring会查找spring.profiles.default的值。
2.2 条件化的Bean
在带有@Bean注解的方法上使用 @Conditional注解可以实现bean的条件化配置,当给定的条件计算结果为true,该bean才会被创建。
//只有当Method计算结果为true,TestBean才会被创建
@Bean
@Conditional(GetMethod.class)
public TestrBean getBean(){
return new Method();
}
2.3 处理自动装配的歧义性
2.3.1 标示首选bean
在声明bean时,可以通过使用 @Primary注解将该bean设为首选bean;
//自动配置的bean
@Component
@Primary
public class TestBean{
...
}
//Java显式配置的bean
@Bean
@Primary
public TestBean testBean{
return new TestBean();
}
//XML配置的bean
<bean id = "testBean"
class = "com.test.TestBean"
primary = "true">
<bean/>
2.3.2 限定自动装配的bean
使用 @Qualifier注解对bean的使用进行限定,@Qualifier注解需要设置的参数就是想要注入的bean的ID;同时我们可以为bean设置自己的限定符(只需在bean声明上添加@Qualifier注解)。
//自动配置
@Component
@Qualifier("test")
public class TestBean{
...
}
//java显性配置
@Bean
@Qualifier("test")
public class TestBean{
...
}
2.4 bean的作用域
默认情况下,Spring中所有的bean都是作为以单例(singleton)的形式创建的,即不管给定的一个bean被注入到其他bean多少次,每次所注入的都是同一个实例。
Spring定义了多种作用域,可以基于这些作用域创建bean:
- 单例(Singleton): 在整个应用中,只创建一个bean的实例;
- 原型(Prototype): 每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例;
- 会话(Session): 在Web应用中,为每个会话创建一个bean实例;
- 请求(Request): 在Web应用中,为每个请求创建一个bean实例;
使用 @Scope注解可以对作用域进行选择,可以与@Component或@Bean一起使用;
2.5 运行时值注入
2.5.1 使用Spring表达式语言进行装配
Spring3引入了SpEL,它能够以一种强大和简洁的方式将值装配到bean属性和构造器参数中,在这个过程中所使用的表达式会在运行时计算得到值。
SpEL拥有很多特性,包含:
- 使用bean的ID来引用bean;
- 调用方法和访问对象的属性;
- 对值进行算术、关系和逻辑运算;
- 正则表达式表达;
- 集合操作;
SpEL表达式要放到#{...}
中,通过组件扫描创建bean时,在注入属性和构造器参数时,我们可以使用 @Value注解;在XML配置中,可以通过将SpEL表达式传入< property>或,< constructor-arg>的value属性中,或者将其作为p-命名空间或c-命名空间条目的值。若要在SpEL中访问类作用域的方法和常量,要依赖T()
运算符;T()
运算符的结果是一个Class对象,T()
运算符可以访问目标类型的静态方法和常量。