我们使用Spring框架所做的就是两件事:开发Bean、配置Bean。对于Spring矿建来说,它要做的就是根据配置文件来创建Bean实例,并调用Bean实例的方法完成“依赖注入”。
Bean通常被定义在配置文件当中,Bean实例化由Spring的Ioc容器进行管理,Bean的实例可以通过Beanfactory进行访问,实际上大部分J2EE应用,Bean是通过ApplicationContext来访问的,ApplicationContext是BeanFactory的子接口,功能要比BeanFactory强大许多。
ApplicationContext
- 读取Bean定义文件
- 维护Bean之间的依赖关系
- 国际化的支持
- 资源文件的读取getRource()方法可以轻松读取Rource对象
- 事件传播
- 多配置文件加载
Bean 的定义
基本组成
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- 定义第一个Bean实例:bean1 -->
<bean id="bean1" class="com.Bean1" />
<!-- 定义第二个Bean实例:bean2 -->
<bean id="bean2" class="com.Bean2" />
</bean>
id:用来指明bean的标识符,这个标识符具有唯一性,Spring对bean的管理以及bean之间这种依赖关系都需要这个属性
class: 指明该bean的具体实现类,这里不能是接口(可以是接口实现类)全路径包名.类名
Bean在Spring容器中两种行为(通过scope来设置默认不写为singelton)
singleton:单实例模式(默认,构造方法为private),整个Spring的容器中只有一个共享实例存在(singleton)
non-singelton:每次请求该bean,Spring容器都会新建立一个bean实例,然后返回给程序(request,session,prototype)
创建Bean步骤
创建XML文件—-写入配置信息—生成Bean类—-加入Bean到配置文件
注入Bean
-ref元素进行标识
Ref元素通常有两个属性:
bean:指定不在同一个XML文件中的bean的id
<bean id="test" class="com.pb.test">
<property name="user">
<ref bean="其他的bean的id"/>
</property>
</bean>
</bean>
value和ref的区别:
使用ref元素,可以让Spring在部署时验证依赖的Bean是否真实存在
使用value元素,进行指定仅在创建Bean实例时做验证,会导致错误的延时出现,而且还会带来额外的类型转制开销
集合注入(了解 list,map, props,set)
<bean id="test" class="com.pb.test">
<property name="lists">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
</bean>
<bean id="test" class="com.pb.test">
<property name="map">
<map>
<entry key="key1">
<value>value1</value>
</entry>
<entry key="key2">
<value>key2</value>
</entry>
</map>
</property>
</bean>
<bean id="test" class="com.pb.test">
<property name="props">
<props>
<prop key="key1">value1</prop>
<prop key="key2">value2</prop>
</props>
</property>
</bean>
<bean>
< property name ="interest" >
< set >
< value > 唱歌 </ value >
< value > 跳舞 </ value >
< value > 书法 </ value >
</ set >
</ property >
</bean>
容器中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比较
- 规范:Spring容器对Bean 没有特殊要求,不像JavaBean 一样遵循一些规范(为每个属性提供相应的setter 和 getter 方法),不过对于设值注入的Bean,一定要提供setter 方法。
- 作用:Spring 中的Bean 是 java 实例,java组件,它的作用几乎无所不包,任何应用组件都被称为Bean,而传统的Java应用中的JavaBean通常作为DTO(数据传输对象),来封装值对象,在各层之间传递数据。
- 生命周期:传统的JavaBean作为值对象传递,不接受任何容器管理其生命周期,Spring中的Bean有Spring管理其生命周期行为。
Spring 的Bean继承和java继承的区别
Spring中子Bean和父Bean可以是不同的类型,而java中的继承子类只是父类的一种特殊类型。
Spring中Bean的继承是实例之间的关系,主要表现为参数值的延续,而java终的继承是类之间的关系,主要表现为属性,方法的延续。
Spring中子Bean不可做父Bean使用,不具备多态性,java中的子类实例完全可以做父类的实例使用
Bean 实例的创建方式及依赖配置
大多数情况下,BeanFactory 直接通过new 关键字调用构造器来创建Bean 实例,而class属性指定了Bean实例的实现类。但这并不是实例化Bean的唯一方法。
创建Bean通常有以下三种方式
- 调用构造器创建Bean 实例
- 调用静态工厂方法创建Bean
- 调用实例工厂方法创建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调用静态工厂方法(可能包含一组参数,若需要,使< constructor-arg…/>元素传入)返回一个Bean实例,获得Bean实例后,Spring后面的处理步骤与采用普通方法创建Bean实例完全一样。
使用静态工厂方法创建Bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,将该静态工厂方法的凡湖值作为Bean实例。在这个过程中,Spring不再负责创建Bean实例,Bean实例的创建是用户提供的静态工厂类负责创建的。但是Spring容器依然可以管理Bean实例的依赖关系,生命周期。
使用实例工厂方法
实例工厂方法与静态工厂方法不同:调用静态工厂方法只需使用工厂类,调用实例工厂方法则必须使用工厂实例。采用实例工厂方法时,配置Bean实例的< bean../>元素无需class属性,因为Spring容器不再直接实例化该Bean,Spring容器仅仅调用实例工厂的工厂方法,工厂方法负责创建Bean实例。采用实例工厂方法创建Bean时,需要为< bean../>元素指定如下两个属性:factory-bean:该属性的值为工厂Bean的id.factory-method:该属性指定实例工厂的工厂方法。与静态工厂方法相似,如果需要调用工厂方法时传入参数,使用< constructor-arg…/>元素确定参数值。
静态工厂方法创建实例和工厂方法创建实例的异同点:
调用实例工厂方法创建Bean,必须将实例工厂配置成Bean实例。而静态工厂方法创建Bean,则无需配置工厂Bean。
调用实例工厂方法创建Bean,必须使用factory-bean属性确定工厂Bean。而静态工厂方法创建Bean,则使用class 元素确定静态工厂类。
都需要factory-method 指定相应产生Bean实例的工厂方法。
工厂方法需要参数都可以使用< constructor-art…/>元素指定参数。