使用FactoryBean接口实现自定义bean初始化
本文所要介绍的FactoryBean是Spring中定义的一个接口,当把它的实现类定义为BeanFactory中的一个bean,我们在获取其对应的bean时实际上获取的是FactoryBean所包含的那个对象,而不是它本身。我们先来看一下FactoryBean的定义。
public interface FactoryBean<T> { /** * 获取实际要返回的bean对象。 * @return * @throws Exception */ T getObject() throws Exception; /** * 获取返回的对象类型 * @return */ Class<?> getObjectType(); /** * 是否单例 * @return */ boolean isSingleton(); }
我们可以看到FactoryBean是使用了泛型的,表示其对应产生的Bean是什么类型的对象。我们来看一个实现。
public class UserFactoryBean implements FactoryBean<User> { private User user; @Override public User getObject() throws Exception { if (user == null) { synchronized (this) { if (user == null) { User user = new User(); user.setId(1); user.setName("张三"); this.user = user; } } } returnuser; } @Override public Class<?> getObjectType() { return User.class; } @Override public boolean isSingleton() { return true; } }
上面代码中定义了一个UserFactoryBean,用以产生一个单例的User对象。可以看到,我们在getObject()方法中使用了同步块来保证产生的bean永远是同一个对象。其实这个并不是必须的。在初始化时BeanFactory调用FactoryBean创建bean时就是同步的,而且BeanFactory创建bean时默认是单例的,也就意味着FactoryBean的getObject方法在BeanFactory中定义为单例的时候只会调用一次。但有一种情况例外,那就是如果定义bean时指定了“lazy-init=true”时,那就意味着该bean只有在用到的时候才会进行初始化,这个时候如果刚好两个线程同时需要使用,就会出现在两个线程中同时调用FactoryBean的getObject方法进行bean的初始化,如不加控制就会出现两个实例。为保证只有一个实例,getObject方法内部需要是同步的。
此外,需要注意的是FactoryBean的isSingleton方法返回结果表示当前FactoryBean产生的bean是否是单例形式,即每次请求getObject()方法返回的是否都是同一个bean对象。其实FactoryBean更多的是在Spring内部使用,isSingleton只是用来表示当前返回的bean对象是否可以用BeanFactory缓存的一个标志。
上面示例对象的Spring配置文件如下:
<bean id="userFactoryBean" class="com.xxx.spring.factorybean.UserFactoryBean" lazy-init="false"/>
对于一个FactoryBean接口实现类定义的bean其实Spring将实例化两个bean,一个是FactoryBean本身对应的bean,另一个是FactoryBean产生的对象对应的bean。所以当我们在通过注解方式注入一个FactoryBean实例对应的bean时,既可以把它当做一个FactoryBean进行注入,也可以把它当做一个对应产生的实例进行注入。而如果是自己直接从ApplicationContext中获取的话,则直接通过FactoryBean实现类定义的bean名称获取到的是FactoryBean实现类产生的对象。如在上面示例中,如果我们通过ApplicationContext的getBean(“userFactoryBean”)获取到的就将是对应产生的User对象,如果我们需要获取到对应的FactoryBean本身,则可以在对应的FactoryBean实现类定义的bean名称前加上“&”进行获取,如上如果我们要获取到UserFactoryBean本身,则可以通过ApplicationContext的getBean(“&userFactoryBean”)。如果是通过类型获取,就可以直接通过User类型或者UserFactoryBean类型获取到对应的bean对象了。
(注:本文是基于Spring3.1.0所写)
相关推荐
4.6 自定义bean 的性质. 69 4.6.1 生命周期回调. 69 4.6.1.1 初始化回调 70 4.6.1.2 销毁回调.. 70 4.6.1.3 默认的初始化和销毁方法 71 4.6.1.4 组合生命周期机制.. 72 4.6.1.5 启动...
3.3.4. 延迟初始化bean 3.3.5. 自动装配(autowire)协作者 3.3.6. 依赖检查 3.3.7. 方法注入 3.4. Bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. Singleton beans和prototype-bean的...
3.3.4. 延迟初始化bean 3.3.5. 自动装配(autowire)协作者 3.3.6. 依赖检查 3.3.7. 方法注入 3.4. Bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. Singleton beans和prototype-bean的...
3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.6.1. 设置Bean使自动装配失效 3.3.7. 依赖检查 3.3.8. 方法注入 3.3.8.1. Lookup方法注入 3.3.8.2. 自定义方法的替代方案 3.4. bean的作用域 3.4.1. ...
3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.7. 依赖检查 3.3.8. 方法注入 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. 其他作用域 3.4.4. 自定义作用域 ...
3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.7. 依赖检查 3.3.8. 方法注入 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. 其他作用域 3.4.4. 自定义作用域 ...
每个 bean 的定义都可以是 POJO (用类名和 JavaBean 初始化属性定义) 或 FactoryBean。FactoryBean 接口为使用 Spring 框架构建的应用程序添加了一个间接的级别。 IOC 示例 理解控制反转最简单的方式就是看它的...
2.7 自定义Bean初始化和析构 72 2.7.1 问题 72 2.7.2 解决方案 72 2.7.3 工作原理 72 2.8 用Java Config简化XML配置 77 2.8.1 问题 77 2.8.2 解决方案 77 2.8.3 工作原理 77 2.9 使Bean感知容器 ...
2.7 自定义Bean初始化和析构 72 2.7.1 问题 72 2.7.2 解决方案 72 2.7.3 工作原理 72 2.8 用Java Config简化XML配置 77 2.8.1 问题 77 2.8.2 解决方案 77 2.8.3 工作原理 77 2.9 使Bean感知容器 ...
spring3.1中文参考文档,南磊翻译,现在有4章,目录如下: 第一部分 Spring framework概述............................2.5.3.2 使用组件定义bean的元数据..............................................................