7.2.2 使用Spring管理Bean
Spring
核心容器的理论很简单:Spring
核心容器就是一个超级大工厂,所有的对象(包括数据源、Hibernate
、Session Factory
等基础性资源)都会被当成Spring
核心容器管理的对象—— Spring
把容器中的
一切对象统称为Bean
Spring
容器中的Bean
,与以前听过的Java Bean
是不同的。不像Java Bean
,必须遵守一些特定的规范,而Spring
对Bean
没有任何要求。只要是一个Java
类, Spring
就可以管理该Java
类,并将它当成Bean
处理。
对于Spring
框架而言,一切Java
对象都是Bean
.
程序示例
项目结构
1 | E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\springQs |
Axe.java
下面程序先定义一个简单的类。
1 | package org.crazyit.app.service; |
从上面代码可以看出,该Axe
类只是一个最普通的Java
类,简单到令人难以置信——但这也是前面所介绍的, Spring
对Bean
类没有任何要求,只要它是个Java
类即可。
什么是依赖
下面再定义一个简单的Person
类,该Person
类的useAxe()
方法需要调用Axe
对象的chop()
方法,这种A对象需要调用B对象方法的情形,被称为依赖
。下面是依赖Axe
对象的Person
类的源代码。
Person.java
1 | package org.crazyit.app.service; |
使用Spring
框架之后, Spring
核心容器是整个应用中的超级大工厂,所有的Java
对象都交给Spring
容器管理,这些由Spring
容器管理的Java
对象被统称为Spring
容器中的Bean
.
Spring如何管理Bean
现在的问题是:Spring
容器怎么知道管理哪些Bean
呢?答案是XML
配置文件(也可用注解,后面会介绍), Spring
使用XML
配置文件来管理容器中的Bean
。因此,接下来为该项目增加XML
配置文件, Spring
对XML
配置文件的文件名没有任何要求,读者可以随意指定。
beans.xml
1 |
|
上面的配置文件很简单,该配置文件的根元素是<beans>
,根元素主要就是包括多个<bean>
元素,每个<bean>
元素定义一个Bean
。上面配置文件中一共定义了4个Bean
,其中前两个Bean
是本示例提供的Axe
和Person
类;而后两个Bean
则直接使用了JDK
提供的java.util.Date
和javax.swing.JFrame
.
再次强调:Spring
可以把”一切Java
对象”当成容器中的Bean
,因此不管该Java
类是JDK
提的,还是第三方框架提供的,抑或是开发者自己实现的类都可以使用Spring
管理。只要是个Java
类,并将它配置在XML
配置文件中, Spring
容器就可以管理它。
元素说明
实际上,配置文件中的<bean>
元素默认以反射方式
来调用该类无参数的构造器
,以如下元素为例:
1 | <bean id="person" class="org.crazyit.app.service.Person"> |
Spring
框架解析该<bean>
元素后将可以得到两个字符串:
- 解析
<bean>
元素的id
属性得到的idStr
的值为"person"
- 解析
<bean>
元素的class
属性得到classStr
的值为"org.crazyit.app.service Person"
也就是说, Spring
底层会执行形如以下格式的代码
1 | String idStr=...;//解析`<bean>`元素的`id`属性得到的`idStr`的值为`"person"` |
上面代码就是最基本的反射代码(实际上Spring
底层代码会更完善一些), Spring
框架通过反射根据<bean>
元素的class
属性指定的类名创建了一个Java
对象,并以<bean>
元素的id
属性的值为key
,将该对象放入Spring
容器中—这个Java
对象就成为了Spring
容器中的Bean
.
每个<bean>
元素默认驱动Spring
调用该类无参数的构造器
来创建实例,并将该实例作为Spring
容器中的Bean
。
通过上面的反射代码还可以得到一个结论:在Spring
配置文件中配置Bean
时,class
属性的值必须是Bean
实现类的完整类名
(必须带包名),不能是接口
,不能是抽象类
(除非有特殊配置),否则Spring
无法使用反射创建该类的实例.
元素说明
上面配置文件中还包括一个<property>
子元素,<property>
子元素通常用于作为<bean>
元素的子元素,它驱动Spring
在底层以反射执行一次setter
方法。其中:
<property>
的name
属性值决定执行哪setter
方法,<property>
的value
或ref
属性决定执行setter
方法的传入参数:- 如果传入参数是
基本类型及其包装类
、String
等类型,则使用value
属性指定传入参数 - 如果以容器中其他
Bean
作为传入参数,则使用ref
属性指定传入参数。
- 如果传入参数是
Spring
框架只要看到<property>
子元素, Spring
框架就会在底层以反射方式执行一次setter
方法。何时执行这个setter
方法呢?该Bean
一旦创建处理, Spring
会立即根据<property>
子元素来执行setter
方法。也就是说,<bean>
元素驱动Spring
调用构造器创建对象; <property>
子元素驱动Spring
执行setter
方法,这两步是先后执行的,中间几乎没有任何间隔。
以上面配置文件中的如下配置为例:
1 | <bean id="person" class="org.crazyit.app.service.Person"> |
上面配置中<property>
元素的
name
属性值为axe
,该元素将驱动Spring
以反射方式执行person
这个Bean
的setAxe()
方法;ref
属性值为axe
,该属性值指定以容器中名为axe
的Bean
作为执行setter
方法的传入参数.
也就是说, Spring
底层会执行形如以下格式的代码
1 | //解析`<property>`元素的name属性得到该字符串的值为"axe" |
上面代码就是最基本的反射代码(实际上Spring
底层代码会更完善一些),Spring
框架通过反射根据<property>
元素的name
属性决定调用哪个setter
方法,并根据value
或ref
决定调用setter
方法的传入参数。
如果不想真正理解Spring
框架的底层机制,则只要记住:每个property>
元素默认驱动Spring
调用一次setter
方法.
理解了Spring
配置文件中<bean>
元素的作用:默认驱动Spring
在底层调用无参数的构造器创建对象.
就能猜到上面配置中4个<bean>
元素产生的效果:Spring
会依次创建org.crazyit.app.service.Person
、org.crazyit.app.service.Axe
、 javax.Swing.JFrame
、java.uti.Date
这4个类的对象,并把它们当成容器中的Bean
。
其中id
为person
的<bean>
元素还包括一个<property>
子元素,因此Spring
会在创建完personBean
之后,立即以容器中id
为axe
的Bean
作为参数来调用personBean
的settAxe
方法—这样会导致容器中id
为axe
的Bean
被赋值给person
对象的axe
实例变量。
使用ApplicationContext接口创建Spring容器
接下来程序就可通过Spring
容器来访问容器中的Bean
, ApplicationContext
是Spring
容器最常用的接口,该接口有如下两个实现类。
ClassPathXmlApplicationContext
:从类加载路径下
搜索配置文件,并根据配置文件来创建Spring
容器FileSystemXmlApplicationContext
:从文件系统的相对路径或绝对路径下去搜索配置文件,并根据配置文件来创建Spring
容器。
对于Java
项目而言,类加载路径总是稳定的,因此通常总是使用ClassPathXmlApplicationContext
创建Spring
容器。
下面是本示例的主程序代码
1 | package lee; |
上面程序中main方法里的
第1行代码创建了Spring
容器,
第2行代码通过Spring
容器获取id
为person
的Bean
(Spring
容器中的Bean
,就是Java
对象。)
使用getBean方法从Spring容器获取Bean
Spring
容器获取Bean
对象主要有如下两个方法。
方法 | 描述 |
---|---|
Object getBean(String id) |
根据容器中Bean 的id 来获取指定Bean ,获取Bean 之后需要进行强制类型转换 . |
T getBean(String name, Class<T> requiredType) |
根据容器中Bean 的id 来获取指定Bean ,但该方法带一个泛型参数,因此获取Bean 之后无须进行强制类型转换 。 |
上面程序使用的是带泛型参数的getBean()
方法,所以通过该方法获取Bean
之后无须进行强制类型转换获得Bean
(即Java
对象)之后,即可通过该对象来调用方法
、访问实例变量
(如果访问权限允许)总之,原来怎么使用Java
对象,现在还怎么使用这个获取到的Bean
。
编译、运行该程序,即可看到如下输出:
1 | 我打算去砍点柴火! |
使用Spring不用自己创建对象
从上面的运行结果可以看出,使用Spring
框架之后最大的改变之一是:程序不再使用new
调用构造器创建Jaa
对象,所有的Java
对象都由Spring
容器负责创建。
原文链接: 7.2.2 使用Spring管理Bean