FactoryBean简介:

1)Spring中Bean包含两种一种是普通Bean,另外一种是FactoryBean。它们都受IOC容器管理,但是也有不同之处。

2)普通Bean与FactoryBean的区别:

a)普通的Bean只需要定义好,然后配置文件中定义并配置其依赖关系,就可以通过IOC容器的getBean获取到;

b)FactoryBean是实现了FactoryBean<T>接口的Bean,通过FactoryBean类的getBean方法直接获取到的并不是该FactoryBean实例,而是FactoryBean中方法getObject返回的对象。

c)FactoryBean的实例可以通过其他方法获取到,在通过getBean方法获取实例时在参数name前面加上“&”符号即可。

FactoryBean的接口定义如下:

public interface FactoryBean<T> {
//获取FactoryBean初始化的Bean实例
T getObject() throws Exception;
//获取Bean实例的类型
Class<?> getObjectType();
//判断是否是单例模式
default boolean isSingleton() {
return true;
}
}

示例:

定义Category.java

package com.dx.spring.beans.factorybean;

public class Category {
private Integer id;
private String name; public Integer getId() {
return id;
} public void setId(Integer id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Category(Integer id, String name) {
super();
this.id = id;
this.name = name;
} @Override
public String toString() {
return "Category [id=" + id + ", name=" + name + "]";
} }

定义CategoryFactoryBean.java

package com.dx.spring.beans.factorybean;

import org.springframework.beans.factory.FactoryBean;

public class CategoryFactoryBean implements FactoryBean<Category> {

    private String name;

    public void setName(String name) {
this.name = name;
} @Override
public Category getObject() throws Exception {
System.out.println(this.name);
return new Category(1, "java spring");
} @Override
public Class<?> getObjectType() {
return Category.class;
} @Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
} }

新建spring bean配置文件bean-factorybean.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="category" class="com.dx.spring.beans.factorybean.CategoryFactoryBean">
<property name="name" value="hello factorybean"></property>
</bean>
</beans>

添加测试类Client.java并测试:

package com.dx.spring.beans.factorybean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Client {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-factorybean.xml");
Category category = (Category) ctx.getBean("category");
System.out.println(category); CategoryFactoryBean categoryFactoryBean = (CategoryFactoryBean) ctx.getBean("&category");
System.out.println(categoryFactoryBean);
}
}

打印信息为:

hello factorybean
Category [id=1, name=java spring]
com.dx.spring.beans.factorybean.CategoryFactoryBean@1e397ed7

实现原理:

声明:以下参考《Spring源码学习--FactoryBean实现原理

当程序执行Category category = (Category) ctx.getBean("category");时,在AbstractBeanFactory中会进行一系列的操作:

getBean获取bean

    @Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}

doGetBean中获取bean实例

protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
.........//省略部分代码
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
.........//省略部分代码
return (T) bean;
}

getObjectForBeanInstance中会选择bean实例是普通的Bean还是FactoryBean,同时通过判断name中是否有&来选择判断是或者FactoryBean还是其getObject方法中获取的bean

protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
.........//省略部分代码
//判断bean类型是否是FactoryBean,或者name是否是以&开头,如果是则直接返回
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
//如果是则从getObjectFromFactoryBean中获取
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}

getObjectFromFactoryBean接下来会执行FactoryBean的getObject方法获取bean了。

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
.........//省略部分代码
Object object = doGetObjectFromFactoryBean(factory, beanName);
.........//省略部分代码
return object;
} private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
.........//省略部分代码
//调用Factory的getObject方法
object = factory.getObject();
.........//省略部分代码
return object;
}

Spring(十四):使用FactoryBean配置Bean的更多相关文章

  1. 跟着刚哥学习Spring框架--通过注解方式配置Bean(四)

    组件扫描:Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件. 特定组件包括: 1.@Component:基本注解,识别一个受Spring管理的组件 2.@Resposit ...

  2. 跟着刚哥学习Spring框架--通过XML方式配置Bean(三)

    Spring配置Bean有两种形式(XML和注解) 今天我们学习通过XML方式配置Bean 1. Bean的配置方式 通过全类名(反射)的方式   √ id:标识容器中的bean.id唯一. √ cl ...

  3. Spring学习记录(十)---使用FactoryBean配置Bean

    之前学了,配置bean可以用普通全类名配置.用工厂方法配置,FactoryBean又是什么呢 有时候配置bean要用到,IOC其他Bean,这时,用FactoryBean配置最合适. FactoryB ...

  4. Spring(二)--FactoryBean、bean的后置处理器、数据库连接池、引用外部文件、使用注解配置bean等

    实验1:配置通过静态工厂方法创建的bean  [通过静态方法提供实例对象,工厂类本身不需要实例化!] 1.创建静态工厂类 public class StaticFactory { private st ...

  5. Spring工厂方法(factory-bean)配置bean

    在spring的世界中, 我们通常会利用bean config file 或者 annotation注解方式来配置bean. 在第一种利用bean config file(spring xml)方式中 ...

  6. Spring 通过FactoryBean配置Bean

    1.实现FactoryBean接口 import org.springframework.beans.factory.FactoryBean; public class CarFactoryBean ...

  7. spring FactoryBean配置Bean

    概要: 实例代码具体解释: 文件夹结构 Car.java package com.coslay.beans.factorybean; public class Car { private String ...

  8. 12.Spring通过FactoryBean配置Bean

    为啥要使用FactoryBean: 在配置Bean的时候,需要用到IOC容器中的其它Bean,这个时候使用FactoryBean配置最合适. public class Car { private St ...

  9. Spring4.0学习笔记(7) —— 通过FactoryBean配置Bean

    1.实现Spring 提供的FactoryBean接口 package com.spring.facoryBean; import org.springframework.beans.factory. ...

随机推荐

  1. 一些收集的MikroTik RouterOS破解版虚拟机VMware

    会不定期更新,也许后续自己来做,现在是收集.持续关注这个分享链接即可. 链接:https://pan.baidu.com/s/1j7ciesPm1yAgCJ26dLJ8sg  密码:i64w

  2. 给Eclipse安装eUML2插件以及可能出现的依赖错误解决方案(转)

    eUML2是一款强大的,基于Eclipse应用程序的UML建模工具.开发者可以在UML开发过程中将模型转化为Java代码:确保软件质量和减少开发时间. 必备条件 Java runtime 1.5 or ...

  3. POJ 1386 Play on Words (有向图欧拉路径判定)

    Play on Words Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 8768   Accepted: 3065 Des ...

  4. CentOS 7.x,不重新编译 PHP,动态安装 imap 扩展

    先前的教程:PHP5不重新编译,如何安装自带的未安装过的扩展,如soap扩展? # 安装依赖包 yum install -y libc-client-devel /usr/local/src/cent ...

  5. 如何:声明、实例化和使用委托(C# 编程指南)

    委托的声明如下所示: C#   public delegate void Del<T>(T item); public void Notify(int i) { } C#   Del< ...

  6. WinForm多语言版本实战项目演练

    一.课程介绍 关于如何实现“WinForm多语言版本”网上有很多实现技术方案,可以说是“琳琅满目”,"包罗万象".俗话说的好:一千个读者就有一千个哈姆雷特!如果您工作中恰好也遇到这 ...

  7. ASP.NET Web API实践系列01,以ASP.NET Web Form方式寄宿

    创建一个空的ASP.NET Web Form项目. 右键项目,添加新项,创建Web API控制器类,TestController. 删除掉TestController默认的内容,编写如下: using ...

  8. C#编程(四十二)----------委托和事件

    委托和事件 委托是C#总比较重要的概念,学习C#爱这里最容易产生迷惑. 有些时候,犹豫我们在开发程序时对后续可能出现的要求及变化考虑不足而导致麻烦,这些新变化可能导致程序的重新编写,那能不能改变这种情 ...

  9. C#编程(十三)----------方法重载

    C#支持方法的重载---方法的几个版本有不同的签名即可(即,方法名相同,但是参数个数和/或类型不同).为了冲在方法,只需要声明同名单参数个数或类型不同的方法即可. 注意:两个方法不能仅在返回类型上有区 ...

  10. fastjson的日期格式化

    //SerializerFeature.WriteDateUseDateFormat 使用日期字段格式序列化(2017-01-01),而不是用时间戳表示日期 JSON.toJSONString(dat ...