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. Tesseract OCR简单实用介绍

    做字符识别,不能不了解google的Tesseract-OCR,但是如何在自己的工程中使用其API倒是语焉不详,官网上倒是很详尽地也很啰嗦地介绍如何重新编译生成适合自己平台的lib和dll,经过近些天 ...

  2. 在fork的项目里同步别人新增分支的方法

    # 1.将项目B clone 到本地 git clone -b master 项目B的git地址 # 2.将项目A的git地址,添加至本地的remote git remote add upstream ...

  3. 使用 IntraWeb (18) - 基本控件之 TIWImage、TIWImageFile、TIWImageList

    TIWImage //用于显示资源中的图片, 设计时通过 Picture 载入图片到资源 TIWImageFile //用于显示给定路径或地址的图片 TIWImageList //它继承于 TImag ...

  4. android 的几个黄色警告解决办法(转)

    转自:http://my.eoe.cn/864234/archive/5162.html 1:Handler 1 2 3 4 5 6 7 8 // This Handler class should ...

  5. C#中执行Dos命令

    //dosCommand Dos命令语句 public string Execute(string dosCommand) { ); } /// <summary> /// 执行DOS命令 ...

  6. nRF51 DK : nRF51822 Development Kit for Bluetooth Smart, ANT and 2.4GHz applications.

    KEY FEATURES • Affordable, Rapid prototyping and development solution for nRF51 Series SoCs • Kit su ...

  7. RabbitMQ高级指南:从配置、使用到高可用集群搭建

    本文大纲: 1. RabbitMQ简介 2. RabbitMQ安装与配置 3. C# 如何使用RabbitMQ 4. 几种Exchange模式 5. RPC 远程过程调用 6. RabbitMQ高可用 ...

  8. DM6467开发领航-开发坏境安装

  9. Ubuntu 14.04 用户如何安装 VLC 2.2.0

    http://www.linuxidc.com/Linux/2014-03/98913.htm http://www.videolan.org/vlc/#download VLC 是一款自由开源.跨平 ...

  10. Oracle数据库(一)

    Oracle 是一个数据库管理系统,是Oracle公司的核心产品.其在数据安全性与安整性控制方面的优越性能,以及跨操作系统.跨硬件平台的数据操作能力.基于“客户端/服务    器”(Client/Se ...