Spring源码解析-8、BeanFactory与FactoryBean

BeanFactory与FactoryBean区别

BeanFactory:IOC容器,管理Bean。
FactoryBean:就是一个Bean,由IOC容器管理,与普通Bean的区别就是 在IOC里容器里通过ID获取的是FactoryBean中getObject方法返回的对象,如果要获取FactoryBean 本身,需要加上&。FactoryBean一般用于获取实例化比较复杂的Bean,比如List/Set/Map等。

FactoryBean接口介绍


public interface FactoryBean<T> {
//获取对象
    T getObject() throws Exception;
//获取对象类型
    Class<?> getObjectType();
//是否单例
    boolean isSingleton();
}

如何获取FactoryBean本身?

在ID前加&

从依赖注入的源码里看下

关于FactoryBean在依赖注入里的使用主要看AbstractBeanFactory的getObjectForBeanInstance,在doGetBean中被调用

protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
//如果name开头&,但又不是factoryBean就报错
        if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(this.transformedBeanName(name), beanInstance.getClass());
            //如果是FactoryBean,且name开头不为bean,那就取getObject
        } else if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
            Object object = null;
            if (mbd == null) {
                object = this.getCachedObjectForFactoryBean(beanName);
            }

            if (object == null) {
                FactoryBean<?> factory = (FactoryBean)beanInstance;
                if (mbd == null && this.containsBeanDefinition(beanName)) {
                    mbd = this.getMergedLocalBeanDefinition(beanName);
                }

                boolean synthetic = mbd != null && mbd.isSynthetic();
                object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
            }


            return object;
        } else {
        //否则返回自身
            return beanInstance;
        }
    }

这个方法就三个判断:
1、如果不是factoryBean 但是name开头为&,那么报错
2、如果是FactoryBean,并且name开头不为&,就取FactoryBean的getObject方法
3、如果是FactoryBean,并且name开头为&,那么返回FactoryBean本身。

FactoryBean代码案例

Spring提供了很多FactoryBean,比如ListFactoryBean用来实例化List对象,SetFactoryBean用来实例化Set对象,ProxyFactoryBean用来获取AOP的代理对象。
下面来自己使用一下FactoryBean:

public class User {
    private String name;
    private int age;
    private String sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return String.format("name:%s,age:%s,sex:%s",name,age,sex);
    }
}

-----------------------------------------------------------------------
public class UserFactoryBean implements FactoryBean<User> {

    private String userInfo;

    @Override
    public User getObject() throws Exception {
        String[] userArray = userInfo.split(",");
        User user = new User();
        user.setName(userArray[0]);
        user.setAge(Integer.valueOf(userArray[1]));
        user.setSex(userArray[2]);
        return user;
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public String getUserInfo() {
        return userInfo;
    }

    public void setUserInfo(String userInfo) {
        this.userInfo = userInfo;
    }
}
-----------------------------------------------------------------------

<?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="user" class="com.raycloud.dmj.data.utils.UserFactoryBean">
     <property name="userInfo" value="yang,25,male"/>
 </bean>
</beans>

-----------------------------------------------------------------------

 public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        System.out.println( context.getBean("user"));
        System.out.println( context.getBean("&user"));


    }

输出:
name:yang,age:25,sex:male
com.raycloud.dmj.data.utils.UserFactoryBean@3dd54e44

猜你喜欢

转载自blog.csdn.net/qq_28605513/article/details/85617876