Spring beans 是那些形成 Spring 应用的主干的 java 对象。它们被 Spring IOC 容器初始化,装配,和管理。这些 beans 通过容器中配置的元数据创建。比如,以 XML 文件中 的形式定义。
一个 Spring Bean 的定义包含容器必知的所有配置元数据,包括如何创建一个 bean,它的生命周期详情及它的依赖。
这里有三种重要的方法给 Spring 容器提供配置元数据。
XML 配置文件。
基于注解的配置。
基于 java 的配置。
Spring 配置文件是个 XML 文件,这个文件包含了类信息,描述了如何配置它们,以
及如何相互调用。
Spring 基于 xml 注入 bean 的几种方式
1. Set 方法注入;
2. 构造器注入:
①通过 index 设置参数的位置;
②通过 type 设置参数类型;
3. 静态工厂注入;
4. 实例工厂;
当定义一个 在 Spring 里,我们还能给这个 bean 声明一个作用域。它可以通过 bean定义中的 scope 属性来定义。如,当 Spring 要在需要的时候每次生产一个新的 bean实例,bean 的 scope 属性被指定为 prototype。另一方面,一个 bean 每次使用的时候必须返回同一个实例,这个 bean 的 scope 属性 必须设为 singleton。
Spring 框架支持以下五种 bean 的作用域:
singleton : bean 在每个 Spring ioc 容器中只有一个实例。
prototype:一个 bean 的定义可以有多个实例。
request:每次 http 请求都会创建一个bean,该作用域仅在基于web的SpringApplicationContext 情形下有效。
session:在一个 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于web 的 Spring ApplicationContext 情形下有效。
global-session:在一个全局的 HTTP Session 中,一个 bean 定义对应一个实例。该作用域仅在基于 web 的 Spring ApplicationContext 情形下有效。
注意: 缺省的 Spring bean 的作用域是 Singleton。使用 prototype 作用域需要慎重的思考,因为频繁创建和销毁 bean 会带来很大的性能开销。
不是,Spring 框架中的单例 bean 不是线程安全的。
spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。
实际上大部分时候 spring bean 无状态的(比如 dao 类),所有某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model对象),那就要开发者自己去保证线程安全了,最简单的就是改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于new Bean()了,所以就可以保证线程安全了。
有状态就是有数据存储功能。
无状态就是不会保存数据。
在一般情况下,只有无状态的 Bean 才可以在多线程环境下共享,在 Spring中,绝大部分 Bean 都可以声明为 singleton 作用域,因为 Spring 对一些Bean 中非线程安全状态采用ThreadLocal 进行处理,解决线程安全问题。
ThreadLocal 和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用“时间换空间”的方式,仅提供一份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。而ThreadLocal 采用了“空间换时间”的方式。
ThreadLocal 会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal 提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进 ThreadLocal。
bean 在 Spring 容器中从创建到销毁经历了若干阶段,每一阶段都可以针对 Spring
正如你所见,在 bean 准备就绪之前,bean 工厂执行了若干启动步骤。 我们对上图进行详细描述:
Spring 对 bean 进行实例化;
Spring 将值和 bean 的引用注入到 bean 对应的属性中;
如果 bean 实现了 BeanNameAware 接口,Spring 将 bean 的 ID 传递给setBean-Name()方法;
如果 bean 实现了 BeanFactoryAware 接口,Spring 将调用setBeanFactory()方法,将 BeanFactory 容器实例传入;
如果 bean 实现了 ApplicationContextAware 接口,Spring 将调用setApplicationContext()方法,将 bean 所在的应用上下文的引用传入进来;
如果 bean 实现了 BeanPostProcessor 接口,Spring 将调用它们的post-ProcessBeforeInitialization()方法;
如果 bean 实现了 InitializingBean 接口,Spring 将调用它们的after-PropertiesSet()方法。类似地,如果 bean 使用 initmethod 声明了初始化方法,该方法也会被调用;
如果 bean 实现了 BeanPostProcessor 接口,Spring 将调用它们的post-ProcessAfterInitialization()方法;
此时,bean 已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
如果 bean 实现了 DisposableBean 接口,Spring 将调用它的 destroy()接口方法。同样,如果 bean 使用 destroy-method 声明了销毁方法,该方法也会被调用。
现在你已经了解了如何创建和加载一个 Spring 容器。但是一个空的容器并没有太大的价值,在你把东西放进去之前,它里面什么都没有。为了从 Spring 的 DI(依赖注入)中受益,我们必须将应用对象装配进 Spring 容器中。
有两个重要的 bean 生命周期方法,第一个是 setup , 它是在容器加载bean 的时候被调用。第二个方法是 teardown 它是在容器卸载类的时候被调用。
bean 标签有两个重要的属性(init-method 和 destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct 和@PreDestroy)。
在 Spring 框架中,当一个 bean 仅被用作另一个 bean 的属性时,它能被声明为一个内部 bean。内部 bean 可以用 setter 注入“属性”和构造方法注入“构造参数”的方式来实现,内部 bean 通常是匿名的,它们的 Scope 一般是 prototype。
Spring 提供了以下四种集合类的配置元素(配置标签):
①该标签用来装配可重复的list值
②该标签用来装配没有重复的set值
③该标签用来注入键和值可以为任何类型的键值对
④该标签支持注入键和值都是字符串类型的键值对