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;  
    }  

 

posted @ 2018-05-25 22:37  cctext  阅读(720)  评论(0编辑  收藏  举报