JavaEE「二」Spring 中的 Bean 管理
2.1 BeanFactory 接口
Spring 的核心功能就是实现对 Bean 的管理,比如 Bean 的注册、注入、依赖等。而 Spring 容器提供了依赖注入这个特征,以实现 Spring 容器对 Bean 的管理,而且使用 IoC 实现了对 Bean 的配置与实际应用代码的隔离。其中,Core Container 模块的核心概念就是 BeanFactory,它是所有 Spring 应用的核心。因为 Spring 的核心模型就是 Bean 模型,所以需要在管理 Spring Bean 的基础上保证 Spring 应用的运行。
BeanFactory
接口是 Bean 容器设计中基本的职责定义接口,定义了按照名称、参数、类型等几个维度获取、判断 Bean 实例的职能。
HierarchicalBeanFactory
只是对 BeanFactory
进行了扩展,定义了父容器(Parent BeanFactory)及判断当前 Bean 的名称是否在当前 Bean 工厂中等。
ConfigurableBeanFactory
提供了设置父容器接口、指定类加载器的职能,并且为当前容器工厂设计 Bean 的定制型的解析处理器、类型处理器等,主要目的是实现对 BeanFactory 的可配置性。
AutowireCapableBeanFactory
提供了 Bean 的创建、注入职能,并且提供了对 Bean 初始化前后的扩展性处理职能,主要职责是处理在当前工厂中注册的 Bean 实例并使其达到可用状态。
ListableBeanFactory
实现了对 Bean 实例的枚举,以及对有某些共同特征的 Bean 的管理,并且按照 Bean 名称、Bean 实例、Bean 类型获取 Bean 实例。
ConfigurableListableBeanFactory
除了集成了 ListBeanFactory
、AutowireCapableBeanFactory
、ConfigurableBeanFactory
这些接口的所有职能,还扩展了修改 Bean 定义信息和分析 Bean 的功能,并且实现了预实例化单例 Bean 及冻结当前工厂配置等功能。
AbstractBeanFactory
实现了对基本容器功能定义的模板式封装和实现,同时实现了对 Bean 信息的注册,但是对 Bean 的创建及 Bean 定义描述信息相关的处理使用了抽象化处理的方式并交由继承者实现。
AbstractAutowireCapableBeanFactory
主要解决 Bean 之间的依赖和注入问题,其中实现了 Bean 的创建方法。因为 Bean 并不是孤立存在的,很有可能存在 Bean 的相互依赖关系,所以只有在解决 Bean 的依赖的前提下,才能实现 Bean 实例的创建。这也就是 AbstractBeanFactory 不能直接创建 Bean 方法的原因。
DefaultListableBeanFactory
提供了对 Bean 容器的完全成熟的默认实现,可以直接对外使用。
在 Spring Context 模块中,许多依赖 BeanFactory
的场景都通过 DefaultListableBeanFactory
类来实现对 Bean 的管理、注入、依赖解决、创建、销毁等功能。
XmlBeanFactory
继承 DefaultListableBeanFactory
并且内部持有 XmlBeanDefinition Reader
属性(该属性用来实现对 XML 文件定义的 Bean 描述信息的加载、解析和处理)的 Bean 工厂容器。
2.2 装配 Bean
在 Spring 中允许我们通过 XML 或者 Java 配置文件装配 Bean .
Spring 容器不单单只有一个,可以归为两种类型
- Bean 工厂,BeanFactory【功能简单】
- 应用上下文,ApplicationContext【功能强大,一般我们使用这个】
2.2.1 通过 Resource 获取 BeanFactory
步骤
- 加载 Spring 配置文件
- 通过 XmlBeanFactory + 配置文件来创建 IOC 容器
//加载Spring的资源文件 |
2.2.2 类路径下 XML 获取 ApplicationContext
直接通过 ClassPathXmlApplicationContext 对象来获取
// 得到IOC容器对象 |
在 Spring 中总体来看可以通过四种方式来配置对象:
- 使用 XML 文件配置
- 使用注解来配置
- 使用 JavaConfig 来配置
- groovy 脚本 DSL
2.3 XML 配置方式
在上面我们已经可以得到 IOC 容器对象了。接下来就是在 applicationContext.xml 文件中配置信息【让 IOC 容器根据 applicationContext.xml 文件来创建对象】
首先我们先有个 JavaBean 的类:
public class User { |
以前我们是通过 new User 的方法创建对象的....
User user = new User(); |
现在我们有了 IOC 容器,可以让 IOC 容器帮我们创建对象了。在 applicationContext.xml 文件中配置对应的信息就行了
<!--使用bean节点来创建对象id属性标识着对象name属性代表着要创建对象的类全名--> |
通过 IOC 容器对象获取对象:在外界通过 IOC 容器对象得到 User 对象
// 得到IOC容器对象 |
上面我们使用的是 IOC 通过无参构造函数来创建对象,我们来回顾一下一般有几种创建对象的方式:
- 无参构造函数创建对象
- 带参数的构造函数创建对象
- 工厂创建对象
- 静态方法创建对象
- 非静态方法创建对象
使用无参的构造函数创建对象我们已经会了,接下来我们看看使用剩下的 IOC 容器是怎么创建对象的。
2.3.1 带参数的构造函数创建对象
首先,JavaBean 就要提供带参数的构造函数:
public User(String id, String username) { |
接下来,关键是怎么配置 applicationContext.xml 文件了。
<bean id="user" class="User"> |
在 constructor 上如果构造函数的值是一个对象,而不是一个普通类型的值,我们就需要用到 ref 属性了,而不是 value 属性
比如说:我在 User 对象上维护了 Person 对象的值,想要在构造函数中初始化它。因此,就需要用到 ref 属性了
<bean id="person" class="Person"></bean> |
2.3.2 工厂静态方法创建对象
首先,使用一个工厂的静态方法返回一个对象
public class Factory { |
配置文件中使用工厂的静态方法返回对象
<!--工厂静态方法创建对象,直接使用class指向静态类,指定静态方法就行了--> |
2.3.3 工厂非静态方法创建对象
首先,也是通过工厂的非非静态方法来得到一个对象
public class Factory { |
配置文件中使用工厂的非静态方法返回对象
<!--首先创建工厂对象--> |
2.3.4 c 名称空间
我们在使用 XML 配置创建 Bean 的时候,如果该 Bean 有构造器,那么我们使用 <constructor-arg>
这个节点来对构造器的参数进行赋值...
<constructor-arg>
未免有点太长了,为了简化配置,Spring 来提供了 c 名称空间...
要想 c 名称空间是需要导入 xmlns:c="http://www.springframework.org/schema/c"
的
<bean id="userService" class="bb.UserService" c:userDao-ref=""> |
c 名称空间有个缺点:不能装配集合,当我们要装配集合的时候还是需要 <constructor-arg>
这个节点
2.3.5 装载集合
如果对象上的属性或者构造函数拥有集合的时候,而我们又需要为集合赋值,那么怎么办?
在构造函数上,普通类型
<bean id="userService" class="bb.UserService" > |
在属性上,引用类型
<property name="userDao"> |
2.4 注解方式
自从 jdk5 有了注解这个新特性,我们可以看到 Struts2 框架、Hibernate 框架都支持使用注解来配置信息...
通过注解来配置信息就是为了简化 IOC 容器的配置,注解可以把对象添加到 IOC 容器中、处理对象依赖关系,我们来看看怎么用吧:
使用注解步骤:
- 1)先引入 context 名称空间
- xmlns:context="http://www.springframework.org/schema/context"
- 2)开启注解扫描器
<context:component-scan base-package=""></context:component-scan>
- 第二种方法:也可以通过自定义扫描类以 @CompoentScan 修饰来扫描 IOC 容器的 bean 对象。如下代码:
//表明该类是配置类 |
在使用 @ComponentScan () 这个注解的时候,在测试类上需要 @ContextConfiguration 这个注解来加载配置类...
- @ContextConfiguration 这个注解又在 Spring 的 test 包下..
创建对象以及处理对象依赖关系,相关的注解:
- @ComponentScan 扫描器
- @Configuration 表明该类是配置类
- @Component 指定把一个对象加入 IOC 容器 --->@Name 也可以实现相同的效果【一般少用】
- @Repository 作用同 @Component; 在持久层使用
- @Service 作用同 @Component; 在业务逻辑层使用
- @Controller 作用同 @Component; 在控制层使用
- @Resource 依赖关系
- 如果 @Resource 不指定值,那么就根据类型来找,相同的类型在 IOC 容器中不能有两个
- 如果 @Resource 指定了值,那么就根据名字来找
测试代码:UserDao
package aa; |
userService
package aa; |
userAction
package aa; |
测试
package aa; |
2.5 通过 JavaConfig 方式
怎么通过 java 代码来配置 Bean 呢?
- 编写一个 java 类,使用 @Configuration 修饰该类
- 被 @Configuration 修饰的类就是配置类
编写配置类:
.springframework.context.annotation.Configuration |
使用配置类创建 bean:
- 使用 @Bean 来修饰方法,该方法返回一个对象。
- 不管方法体内的对象是怎么创建的,Spring 可以获取得到对象就行了。
- Spring 内部会将该对象加入到 Spring 容器中
- 容器中 bean 的 ID 默认为方法名
.springframework.context.annotation.Configuration |
- 测试代码:要使用 @ContextConfiguration 加载配置类的信息【引入 test 包】
package bb; |
2.6 三种方式混合使用?
注解和 XML 配置是可以混合使用的,JavaConfig 和 XML 也是可以混合使用的...
如果 JavaConfig 的配置类是分散的,我们一般再创建一个更高级的配置类(root),然后使用 @Import 来将配置类进行组合 如果 XML 的配置文件是分散的,我们也是创建一个更高级的配置文件(root),然后使用 <import>
来将配置文件组合
在 JavaConfig 引用 XML
- 使用 @ImportResource ()
在 XML 引用 JavaConfig
- 使用
<bean>
节点就行了