开发者使用spring框架主要做两件事:1.开发Bean;2.配置Bean。
IoC的本质是:根据配置文件来创建Bean实例,并调用Bean实例的方法完成”依赖注入”。
1.Bean的基本定义和Bean别名
<beans.../>
元素是spring配置文件的根元素,有如下属性:
- default-lazy-init:指定
<beans.../>
元素下配置的所有Bean默认的延迟初始化行为。 - default-merge:指定该
<beans.../>
元素下配置的所有Bean默认的merge行为。 - default-autowire:指定该
<beans.../>
元素下配置的所有Bean默认的自动装配行为。 - default-autowire-candidates:指定该
<beans.../>
元素下配置的所有Bean默认是否作为自动装配的候选Bean。 - default-init-method:指定
<beans.../>
元素下配置的所有Bean默认的初始化方法。 - default-destroy-method:指定
<beans.../>
元素下配置的所有Bean默认的回收方法。
<beans.../>
元素下所能指定的属性都可以在每个<bean.../>
子元素中指定—将属性名去掉default即可。
定义Bean时,通常需要指定两个属性:
- id:Bean的id属性在spring容器中应该是唯一的。
- class:指定该Bean的具体实现类,这里不能是接口。
- name:用于为Bean实例指定别名。
<alias.../>
元素为已有的Bean指定别名。
- name:该属性指定一个Bean实例的标识名,表明将为该Bean实例指定别名。
- alias:指定一个别名。
2.容器中Bean的作用域
- singleton:单例模式,在整个Spring IoC容器中,singleton作用域的Bean将只生成一个实例。
- prototype:每次通过容器的getBean()方法获取prototype作用域的Bean时,都将产生一个新的Bean实例。
- request:对于一个HTTP请求,request作用域的Bean将只生成一个实例。
- session:对于一次HTTP会话,session作用域的Bean将只生成一个实例。
- global session:每个全局的HTTP Session对应一个Bean实例。
如果不指定Bean的作用域,spring默认使用singleton作用域。
spring配置文件通过scope属性指定Bean的作用域。
request和session作用域只在Web应用中才有效,并且必须在Web应用中增加额外配置才会生效。为了让request和session两个作用域生效,必须将HTTP请求对象绑定到为该请求提供服务的线程上,这使得具有request和session作用域的Bean实例能够在后面的调用链中被访问到。
在Web应用的web.xml文件中增加如下Listener配置,该Listener负责使request作用域生效。
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
3.配置依赖
对于singleton作用域的Bean,如果没有强行取消其预初始化行为,系统会在创建spring容器时预初始化所有的singleton Bean,与此同时,该Bean所依赖的Bean也被一起实例化。
BeanFactory和ApplicationContext实例化容器中Bean的时机不同:前者等到程序需要Bean实例时才创建Bean;而后者在容器创建ApplicationContext实例时,会预初始化容器中的所有singleton Bean。
spring可以把任何Java类都部署在spring容器中—只要该Java类具有相应的构造器,可以为任何Java对象注入任何类型的属性—只要该Java对象为该属性提供了对应的setter方法即可。
创建实例的Java对象底层机制:
Class targetClass = Class.forName("");
Object bean = targerClass.newInstance();
<property.../>元素的底层机制:
String_setName1 = "set" + "Aa";
Mehod setMethod1 = targetClass.getMethod(setName1,aVal.getClass());
setMethod1.invoke(bean,aVal);
4.设置普通属性值
<value.../>
元素用于指定基本类型及其包装、字符串类型的参数值,spring使用XML解析器来解析出这些数据,然后利用java.beans.PropertyEditor完成类型转换:从java.lang.String类型转换为所需的参数值类型。
5.配置合作者Bean
如果需要为Bean设置的属性值是容器中的另一个Bean实例,则应该使用<ref.../>
元素。使用<ref.../>
元素时可指定一个bean属性,该属性用于引用容器中其他Bean实例的id属性值。
6.使用自动装配注入合作者Bean
spring的自动装配可通过<beans.../>
元素的default-autowire属性指定,该属性对配置文件中的所有Bean起作用;也可通过<bean.../>
元素的autowire属性指定,该属性只对该Bean起作用。
- no:不使用自动装配。显示配置合作者能够得到更清晰的依赖关系。
- byName:根据setter方法名进行自动装配。spring容器查找容器中的全部Bean,找到id与setter方法名去掉set前缀,并小写首字母后同名的Bean来完成注入。如果没有找到匹配的Bean实例,则Spring不会进行任何注入。
- byType:根据setter方法的形参类型来自动装配。spring容器查找容器中的全部Bean,如果正好有一个Bean类型与setter方法的形参类型匹配,就自动注入这个Bean;如果找到对个这样的Bean,就抛出一个异常;如果没找到,则什么都没有发生。
- constructor:与byType类似,区别是用于自动匹配构造器的参数。
- autodetect:spring容器根据Bean内部结构,自行决定使用construtor或byType策略。
7.注入嵌套Bean
如果某个Bean所依赖的Bean不想被spring容器直接访问,则可以使用嵌套Bean。由于容器不能获取嵌套Bean,因此它不需要指定id属性。
<bean id="" class="">
<property name="">
<bean class=""/>
</property>
</bean>
spring框架的本质就是通过XML配置文件来驱动Java代码。
8.注入集合值
<bean id="" class="">
<property name="">
<list>
<value>小学</value>
<value>初中</value>
<value>高中</value>
</list>
</property>
</bean>
<bean id="" class="">
<property name="">
<map>
<entry key="原始社会" value="yuanshi"/>
<entry key="农业社会" value-ref=""/>
</map>
</property>
</bean>
<bean id="" class="">
<property name="">
<props>
<prop key="血压">正常</prop>
<prop key="身高">180</prop>
</props>
</property>
</bean>
<bean id="" class="">
<property name="">
<set>
<value>普通字符串</value>
<bean class=""/>
<list>
<value>20</value>
<set>
<value type="int">30</value>
</set>
</list>
</set>
</property>
</bean>
spring IoC容器将支持集合的合并,子Bean中的集合属性值可以从其父Bean的集合属性继承和覆盖而来。子Bean的集合属性的最终值是父Bean、子Bean合并后的最终结果,而且子Bean集合中的元素可以覆盖父Bean集合中对应的元素。
<bean id="parent" abstract="true" class="">
<property name="admin1">
<props>
<prop key="admin">admin</prop>
<prop key="user">root</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="admin1">
<!--指定了merge="true"将会把parent Bean的集合属性合并到 child Bean中-->
<props merge="true">
<prop key="pass">0408</prop>
<prop key="user">root</prop>
</props>
</property>
</bean>
9.组合属性
spring支持组合属性的方式。例如:使用配置文件为形如foo.bar.name的属性设置参数值。为Bean的组合属性设置参数值时,除最后一个属性之外,其他属性值都不允许为null。
public class ExampleBean{
private Person person = new Person();
public Person getPerson(){
return this.person;
}
}
Person类里有一个String类型的name成员变量
<bean id="exampleBean" class="">
<property name="person.name" value="猴子"/>
</bean>
对于这种注入组合属性值的形式,每个<property.../>
元素依然是让spring执行一次setter方法,但它不再是直接调用该Bean的setter方法,而是需要先调用getterfangfa,然后再去调用setter方法。
exampleBean.getPerson().setName("猴子");
10.spring的Bean和JavaBean
spring容器对Bean没有特殊要求,甚至不要求该Bean像标准的JavaBean—必须为每个属性提供对用的setter和getter方法。spring中的Bean是Java实例、Java组件;而传统Java应用中的JavaBean通常作为DTO(数据传输对象),用来封装值对象,在各层之间传递数据。
建议spring容器中的Bean应满足如下几个原则:
- 尽量为每个Bean实现类提供无参数的构造器。
- 接受构造注入的Bean,则应提供对应的、带参数的构造函数。
- 接受设值注入的Bean,则应提供对应的setter方法,并不要求提供对应的getter方法。
传统的JavaBean和spring中的Bean存在如下区别:
- 用处不同:传统的JavaBean更多的是作为值对象传递参数;spring的Bean用处几乎无所不包,任何应用组件都被称为Bean。
- 写法不同:传统的JavaBean作为值对象,要求每个属性都提供setter和getter方法;但spring的Bean只需为接受设值注入的属性提供setter方法即可。
- 生命周期不同:传统的JavaBean作为值对象传递,不接受任何容器管理其生命周期;spring中的Bean由spring管理其生命周期行为。