Spring(十四):使用FactoryBean配置Bean
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的更多相关文章
- 跟着刚哥学习Spring框架--通过注解方式配置Bean(四)
		组件扫描:Spring能够从classpath下自动扫描,侦测和实例化具有特定注解的组件. 特定组件包括: 1.@Component:基本注解,识别一个受Spring管理的组件 2.@Resposit ... 
- 跟着刚哥学习Spring框架--通过XML方式配置Bean(三)
		Spring配置Bean有两种形式(XML和注解) 今天我们学习通过XML方式配置Bean 1. Bean的配置方式 通过全类名(反射)的方式 √ id:标识容器中的bean.id唯一. √ cl ... 
- Spring学习记录(十)---使用FactoryBean配置Bean
		之前学了,配置bean可以用普通全类名配置.用工厂方法配置,FactoryBean又是什么呢 有时候配置bean要用到,IOC其他Bean,这时,用FactoryBean配置最合适. FactoryB ... 
- Spring(二)--FactoryBean、bean的后置处理器、数据库连接池、引用外部文件、使用注解配置bean等
		实验1:配置通过静态工厂方法创建的bean [通过静态方法提供实例对象,工厂类本身不需要实例化!] 1.创建静态工厂类 public class StaticFactory { private st ... 
- Spring工厂方法(factory-bean)配置bean
		在spring的世界中, 我们通常会利用bean config file 或者 annotation注解方式来配置bean. 在第一种利用bean config file(spring xml)方式中 ... 
- Spring 通过FactoryBean配置Bean
		1.实现FactoryBean接口 import org.springframework.beans.factory.FactoryBean; public class CarFactoryBean ... 
- spring FactoryBean配置Bean
		概要: 实例代码具体解释: 文件夹结构 Car.java package com.coslay.beans.factorybean; public class Car { private String ... 
- 12.Spring通过FactoryBean配置Bean
		为啥要使用FactoryBean: 在配置Bean的时候,需要用到IOC容器中的其它Bean,这个时候使用FactoryBean配置最合适. public class Car { private St ... 
- Spring4.0学习笔记(7) —— 通过FactoryBean配置Bean
		1.实现Spring 提供的FactoryBean接口 package com.spring.facoryBean; import org.springframework.beans.factory. ... 
随机推荐
- Spring使用注解方式注入多例的方式
			目前Spring+Netty的开发方式这么火热,想把Netty注册成Spring组件就一定得用多例的方式,我不由得想吐槽明明这么常见的需求网上相关博客都少的很,这里给出Spring使用注解注入多例的方 ... 
- ARM JTAG 20P to Cortex JTAG 10P
- VS2015 Offline Help Content is now available in 10 more languages!
			https://blogs.msdn.microsoft.com/devcontentloc/2015/10/21/vs2015-offline-help-content-is-now-availab ... 
- Linux内存管理学习1 —— head.S中的段页表的建立
			作者 彭东林 pengdonglin137@163.com 平台 TQ2440 Qemu+vexpress-ca9 Linux-4.10.17 概述 在Linux自解压完毕后,开始执行arch/arm ... 
- Android 数据存储01之SharedPreferences
			Android 数据存储01之SharedPreferences 版本 修改内容 日期 修改人 V1.0 原始版本 2013/2/20 skywang 1 SharedPreferences概括 Sh ... 
- Linux tar包相关命令
			tar [-j|-z][cv][-f 新建的文件名] filename... <==打包与压缩 tar [-j|-z][tv][-f 新建的文件名] <==查看文件名 tar [-j| ... 
- 数据访问:Implementing Efficient Transactions
			An OLTP scenario is characterized by a large number of concurrent operations that create, update, an ... 
- “finally block does not complete normally”的警告解决
			但是,java里面不是可以保证finally一定会执行的么,为什么不可以在finally块做return??? 细细看道来: debug一下这个函数,就会惊讶的发现, 里面抛出的异常会被finally ... 
- win7 64位系统及开发环境重装后的总结
			前言 话说来这家公司之后就一直使用这个系统,现在感觉这系统跑的实在是有点慢了,运行,调试各种浪费时间呀,不过也用了将近20个月了,这也可以说是我用的最久的一个系统了.由于新项目即将拉开战幕,所以自己趁 ... 
- XCode的The argument is invalid
			google查了一下,没找到解决的方法.有一篇blog应该有写怎么解决,可惜是wordpress.com的站点,打不开,网页快照也看不了- 后来回忆了一下操作步骤,只是添加了cocos2dx的 ... 
