Spring Bean详解

前言
对于使用Spring框架的开发人员来说,我们主要做的主要有两件事情:①开发Bean;②配置Bean;而Spring帮我们做的就是根据配置文件来创建Bean实例,并调用Bean实例的方法来完成“依赖注入”,可以把Spring容器理解成一个大型工厂,Bean就是该工厂的产品,工厂(Spirng容器)里能生产出来什么样的产品(Bean),完全取决于我们在配置文件中的配置。
容器中Bean的作用域
singleton 在整个Spring IoC 容器中,使用 singleton 定义的Bean将只有一个实例
prototype 原型模式,每次通过容器的getBean 方法获取prototype定义的Bean 时,都将产生一个新的Bean实例
request 对于每次HTTP请求,使用request定义的Bean都将产生一个新的实例,每次HTTP请求都将产生不同的Bean实例,该作用域仅在给予web的Spring ApplicationContext情形下有效
session 对于每次HTTP Session ,使用session定义的Bean都将产生一个新实例,该作用域仅在给予web的Spring ApplicationContext情形下有效
global session 每个全局得HTTP Session对应一个Bean实例,该作用域仅在给予web的Spring ApplicationContext情形下有效
比较常用的是singleton 和 prototype 两种作用域,对于singleton作用域,每次请求该Bean都将获得相同的实例,Spring容器负责跟踪监视Bean实例的状态,负责维护Bean实例的生命周期行为,如果一个Bean被设置成prototype作用域,程序每次请求该id的Bean,Spring都会创建一个新的Bean实例,然后返回给程序,在这种情况下,Spring容器仅仅使用new 关键字创建Bean实例,一旦创建成功,容器Spring不再对Bean的生命周期负责,也不会维护Bean实例的状态。
      如果不指定Bean的作用域,Spring默认使用singleton作用域。Java在常见Java实例时,需要进行内存申请,销毁实例是,需要完成垃圾回收,这些工作都会导致系统开销的增加。因此prototype作用域Bean 的创建销毁代价比较大。而singleton作用域的Bean 实例一旦创建成功,可以重复使用,因此,除非必要,否则避免将Bean作用域设置成prototype。
如果要使用 request,session,global session作用域的Bean,在配置Bean之前,还需要做少量的初始配置(将HTTP 请求banding到该提供服务的线程上,这使得具有request 和 session作用域的Bean实例能够在后面的调用链中被访问到),如果只是配置常规的作用域(singleton,prototype),则无须设置。如果Web 应用直接使用Spring MVC 作为MVC框架,即使用SpringDispatcherServlet 或DispatcherPorlet 来拦截所有用户请求,则无须设置,因为DispatcherServlet 和DispatcherPorlet已经处理了所有和请求有关的额状态处理。
容器中Bean的生命周期
Spring可以管理singleton作用域Bean的生命周期 ,Spring可以精确地知道singleton域bean何时被创建,何时初始化完成,以及容器何时准备销毁Bean实例。因为,对于singleton作用域的Bean,客户端的每次请求都返回同一个Bean实例,客户端代码不能控制Bean的销毁,它的生命周期都在Spring的掌握之中。这么一来,容器就可以管理实例化结束后(某些资源的申请)和销毁之前(进行某些资源的回收)的行为。管理Bean的生命周期行为主要有两个时机:注入依赖关系后,销毁实例之前;具体的管理方法如下
Spring提供两种方式在Bean全部属性设置成功后执行特定行为
     使用init-method 属性(代码污染小)
在类中编写一个方法,在属性中指定该方法在依赖关系设置完成后自动执行。
     实现InitializingBean接口(耦合较高)
            编写afterPropertiesSet()方法的具体实现
同理,若在Bean销毁之前,执行特定的方法,只需要①使用 destroy-method属性②实现DisposableBean接口(实现destroy()方法)
对于prototype作用域的Bean,Spring容器只负责Bean的创建 ,当容器创建实例完成后,Bean将完全交给客户端代码管理,容器不再负责其生命周期。每次客户端请求prototype作用域的Bean时,Spring容器都会产生一个全新的Bean实例交个客户端(prototype就是这么任性),Spring容器本省也不知道自己创建了多少个实例,更无从知道这些实例什么时候才会被销毁。
Spring 的 Bean 和 JavaBean比较
  1. 规范:Spring容器对Bean 没有特殊要求,不像JavaBean 一样遵循一些规范(为每个属性提供相应的setter 和 getter 方法),不过对于设值注入的Bean,一定要提供setter 方法。
  2. 作用:Spring 中的Bean 是 java 实例,java组件,它的作用几乎无所不包,任何应用组件都被称为Bean,而传统的Java应用中的JavaBean通常作为DTO(数据传输对象),来封装值对象,在各层之间传递数据。
  3. 生命周期:传统的JavaBean作为值对象传递,不接受任何容器管理其生命周期,Spring中的Bean有Spring管理其生命周期行为。
Spring 的Bean继承和java继承的区别
  1. Spring中子Bean和父Bean可以是不同的类型,而java中的继承子类只是父类的一种特殊类型。
  2. Spring中Bean的继承是实例之间的关系,主要表现为参数值的延续,而java终的继承是类之间的关系,主要表现为属性,方法的延续。
  3. Spring中子Bean不可做父Bean使用,不具备多态性,java中的子类实例完全可以做父类的实例使用
Bean 实例的创建方式及依赖配置
      大多数情况下,BeanFactory 直接通过new 关键字调用构造器来创建Bean 实例,而class属性指定了Bean实例的实现类。但这并不是实例化Bean的唯一方法。
创建Bean通常有以下三种方式
  1. 调用构造器创建Bean 实例
  2. 调用静态工厂方法创建Bean
  3. 调用实例工厂方法创建Bean
调用构造器创建Bean 实例     
调用构造器创建Bean实例是最常见的情况,,BeanFactory 将使用默认的构造器来创建Bean实例,该实例是个默认实例,Spring对Bean实例的所有属性执行默认初始化,即所有基本类型的值初始化为0或false,引用类型初始化为null,接下来BeanFactory会根据配置文件决定依赖关系,先实例化被依赖的Bean 实例,然后为Bean注入依赖关系,最后将一个完整的Bean实例返回给程序,该Bean实例化的所有属性,已经由Spring容器完成了初始化。
使用静态工厂方法创建Bean
使用静态工厂方法创建Bean实例时,class属性也必须指定,但此时class属性并不是指定Bean实例的实现类,而是 静态工厂类 ,Spring需要根据工厂类的工厂方法来创建Bean实例,除此之外,还需要使用factory-method 属性来指定 静态工厂方法名 ,Spring调用静态工厂方法(可能包含一组参数,若需要,使用元素传入)返回一个Bean实例,获得Bean实例后,Spring后面的处理步骤与采用普通方法创建Bean实例完全一样。
使用静态工厂方法创建Bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,将该静态工厂方法的凡湖值作为Bean实例。在这个过程中,Spring不再负责创建Bean实例,Bean实例的创建是用户提供的静态工厂类负责创建的。但是Spring容器依然可以管理Bean实例的依赖关系,生命周期。
使用实例工厂方法
实例工厂方法与静态工厂方法不同:调用静态工厂方法只需使用工厂类,调用实例工厂方法则必须使用工厂实例。采用实例工厂方法时,配置Bean实例的元素无需class属性,因为Spring容器不再直接实例化该Bean,Spring容器仅仅调用实例工厂的工厂方法,工厂方法负责创建Bean实例。采用实例工厂方法创建Bean时,需要为元素指定如下两个属性:factory-bean:该属性的值为工厂Bean的id.factory-method:该属性指定实例工厂的工厂方法。与静态工厂方法相似,如果需要调用工厂方法时传入参数,使用元素确定参数值。
静态工厂方法创建实例和工厂方法创建实例的异同点
调用实例工厂方法创建Bean,必须将实例工厂配置成Bean实例。而静态工厂方法创建Bean,则无需配置工厂Bean。
调用实例工厂方法创建Bean,必须使用factory-bean属性确定工厂Bean。而静态工厂方法创建Bean,则使用class 元素确定静态工厂类。
都需要factory-method 指定相应产生Bean实例的工厂方法。
工厂方法需要参数都可以使用元素指定参数。
Bean属性
   id="beanId"(1)
   name="beanName"(2)
   class="beanClass"(3)
   parent="parentBean"(4)
   abstract="true | false"(5)
   singleton="true | false"(6)
   lazy-init="true | false | default"(7)
    byName | byType | constructor | autodetect |default"(8)
   dependency-check = "none | objects | simple | all |default"(9)
   depends-on="dependsOnBean"(10)
   init-method="method"(11)
   destroy-method="method"(12)
   factory-method="method"(13)
  factory-bean="bean">(14)
(1)、id: Bean的唯一标识名。它必须是合法的XMLID,在整个XML文档中唯一。
(2)、name:用来为id创建一个或多个别名。它可以是任意的字母符合。多个别名之间用逗号或空格分开。
(3)、class:用来定义类的全限定名(包名+类名)。只有子类Bean不用定义该属性。
(4)、parent:子类Bean定义它所引用它的父类Bean。这时前面的class属性失效。子类Bean会继承父类Bean的所有属性,子类Bean也可以覆盖父类Bean的属性。注意:子类Bean和父类Bean是同一个Java类。
(5)、abstract(默认为”false”):用来定义Bean是否为抽象Bean。它表示这个Bean将不会被实例化,一般用于父类Bean,因为父类Bean主要是供子类Bean继承使用。
(6)、singleton(默认为“true”):定义Bean是否是Singleton(单例)。如果设为“true”,则在BeanFactory作用范围内,只维护此Bean的一个实例。如果设为“flase”,Bean将是Prototype(原型)状态,BeanFactory将为每次Bean请求创建一个新的Bean实例。
(7)、lazy-init(默认为“default”):用来定义这个Bean是否实现懒初始化。如果为“true”,它将在BeanFactory启动时初始化所有的SingletonBean。反之,如果为“false”,它只在Bean请求时才开始创建SingletonBean。
(8)、autowire(自动装配,默认为“default”):它定义了Bean的自动装载方式。
   1、“no”:不使用自动装配功能。
   2、“byName”:通过Bean的属性名实现自动装配。
   3、“byType”:通过Bean的类型实现自动装配。
   4、“constructor”:类似于byType,但它是用于构造函数的参数的自动组装。
   5、“autodetect”:通过Bean类的反省机制(introspection)决定是使用“constructor”还是使用“byType”。
(9)、dependency-check(依赖检查,默认为“default”):它用来确保Bean组件通过JavaBean描述的所以依赖关系都得到满足。在与自动装配功能一起使用时,它特别有用。
1、 none:不进行依赖检查。
2、 objects:只做对象间依赖的检查。
3、 simple:只做原始类型和String类型依赖的检查
4、all:对所有类型的依赖进行检查。它包括了前面的objects和simple。
(10)、depends-on(依赖对象):这个Bean在初始化时依赖的对象,这个对象会在这个Bean初始化之前创建。
(11)、init-method:用来定义Bean的初始化方法,它会在Bean组装之后调用。它必须是一个无参数的方法。
(12)、destroy-method:用来定义Bean的销毁方法,它在BeanFactory关闭时调用。同样,它也必须是一个无参数的方法。它只能应用于singletonBean。
(13)、factory-method:定义创建该Bean对象的工厂方法。它用于下面的“factory-bean”,表示这个Bean是通过工厂方法创建。此时,“class”属性失效。
(14)、factory-bean:定义创建该Bean对象的工厂类。如果使用了“factory-bean”则“class”属性失效。

你可能感兴趣的:(spring)