Spring:Beans

Spring配置概述

在使用Spring提供的各项丰富而神奇的功能前,必须在SpringIOC容器中装配好Bean,并建立Bean和Bean间的关联关系。

Spring容器高层视图

要使得应用程序中的Spring容器成功启动,需要同时具备以下三方面的条件:

  • Spring框架的类包都已经放到应用程序的类路径下。
  • 应用程序为Spring提供了完备的Bean配置信息。
  • Bean的类都已经放到应用程序的类路径下。

Spring启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配好Bean间的依赖关系,为上层应用提供准备就绪的运行环境。

Bean配置信息是Bean的元数据信息,由以下4个方面组成:

  • Bean的实现类。
  • Bean的属性信息。
  • Bean的依赖关系。Spring根据依赖关系配置完成Bean之间的装配。
  • Bean的行为配置。如生命周期范围以及生命周期各过程的回调函数等。

Spring元数据信息在Spring容器中的内部对应物是由一个个的BeanDefinition形成的Bean注册表,Spring实现了Bean元数据信息内部表示和外部定义的解耦。Spring支持多种形式的Bean定义:

  • XML配置。
  • 注解配置。
  • Java类配置。
  • Groovy动态语言配置。

1566653709900

Bean基本配置

一个简单的Bean的配置如这样:<bean id = "Foo" class ="com.smart.Foo"/>

一般情况下一个Bean对应配置文件当中一个<bean>,通过容器的getBean("foo")即可获得对应的bean,而class指定了实现类。

Bean的命名

一般情况下id在IOC容器中必须是唯一的,但是可以定义多个不同的name,如果不指定id与name之一,则会将全限定名作为Bean的名称。

DI

  • 属性注入、构造函数注入、工厂注入。

注入方式

属性注入

属性注入要求Bean提供一个默认的构造函数,并为需要注入的属性提供对应的Setter方法。Spring首先调用Bean默认的构造函数实例化Bean,然后通过反射的方式调用Setter方法注入属性值。

例如:

1
2
3
<bean id ="" class ="">
<property name ="maxSpeed"><value>200</value></property>
</bean>

构造函数注入

保证一些必要的属性在Bean实例化时就得到设置,确保Bean在实例化后就可以使用。

工厂方法注入

是DI和单实例设计思想的主要实现方法。

1
2
<bean id = "carFactory" class = "">
<bean id = "xx" factory-method = "carFactory">

注入参数详解

引用其他Bean

bean可以通过<ref>元素引用其他Bean,建立起对其他bean的依赖。

当实例化时,Spring保证该Bean依赖的其他Bean已经初始化。

1
2
3
4
5
<bean id = "boss" class = "">
<property name = "car">
<ref bean="car"></ref>
</property>
</bean>

ref可以通过以下三个属性引用容器中的其他Bean:

  • bean:通过该属性可以引用同意容器或父容器中的Bean,是最常见的方式。
  • local:只能引用同一配置文件中定义的bean。
  • parent:引用父容器中的Bean。

内部Bean

内部Bean不能被其他Bean引用。

1
2
3
4
5
6
<bean id = "boss" class = "">
<property name = "car">
<bean class = "">
</bean>
</property>
</bean>

方法注入

bean间的关系

<bean>元素标签间也可以建立类似于ref间的依赖关系。

继承

如果多个类拥有相同的方法和属性,则可以引入一个父类,在父类中定义这些类的共同的方法和属性,以消除重复的代码。即多个bean当中存在同样的配置信息,允许定义一个父bean。

1
<bean id = "" class = "" parent = "">

依赖

在某些情况下,Bean间依赖关系并没有那么明显,因此使用ref并不合适。

某些情况下Bean A希望在Bean B加载并完成系统参数设置后再启动,则必须保证Bean B在Bean A前初始化。可以depends-on属性显式指定Bean前置依赖的Bean。

1
<bean id = "manag" class = "" depends-on = "otherBean">

引用

如果一个bean要引用另一个bean的id值则可以如下配置:

1
<bean id = "car" p:userId = "user" scope = "prototype">

如此设置没有建立依赖关系。

整合多个配置文件

基于注解的配置

@Component等价于<bean id = “userDao” class = “ “>

@Component

@Service

@Controller

自动装配Autowired

@Autowired实现Bean的依赖注入,其默认按类型匹配的方式在容器中查找匹配的Bean,当有且仅有一个匹配的Bean,则将其注入@Autowired标注的变量。

required属性,如果当Autowired找不到相应的Bean,则会抛出NoSuchBeanDefinitionException,如果希望不要抛出异常,则设置@Autowired(required = false)

@Qualifier指定注入Bean的名称。

@Autowired可以标注类的方法入参:

1
2
3
4
5
6
7
8
@Autowired//注入LogDao
public void setLogDao(LogDao log){
this.logDao = log;
}

public void init(@Qualifier("userDao")UserDao user){

}

也可以标注集合类:

1
2
@Autowired//注入所有类型为Plugin的类。
private List<Plugin> plugins;

也可以延迟加载,即配置注解@Lazy。

作用范围Scope

@Scope(“prototype”)标注在类上。

Bean作用域

作用域对Bean的生命周期和创建方式产生影响。

  • singleton。
    • 单例作用域,Spring环境下使用AOP和LocalThread对非线程安全的变量进行了特殊处理,使得这些非线程安全的类变成了线程安全的类,因此在实际应用中,大部分Bean都能以单实例的方式运行。
  • prototype。非单例作用域的Bean。
    • <bean id = "boss" class = "Boss" scope = "prototype">如此引用下每次通过getBean("boss")获得的都是一个全新的实例。
    • Spring启动时不初始化,并在初始化后不再管理其生命周期。

与Web相关,使用WebApplication时可用,并需要一些额外的配置:

  • request。对应一个Http请求和生命周期,每次调用完成后即销毁。
  • session。作用域跨越整个HTTP session,所有HTTP共享。
  • globalSession。

FactoryBean

参考