BeanFactory and FactoryBean, I’m sure many of you who have just read the Spring source code are wondering why they look so similar and what they are used for. BeanFactory is the Spring Bean factory’s top-level interface. It is also known as the SpringIOC container. It defines the IOC container’s specifications and common methods and manages all Spring beans.

Let’s start with FactoryBean and what it does: It’s a Bean, but it’s not just a Bean. It is a factory Bean that produces or decorates object generation, similar to the Factory and decorator patterns in design patterns. It can produce an object when needed, and not just itself, it can return an instance of any Bean.


The above explanation is a bit abstract, so let’s take a look at how FactoryBeans are used in Spring. We all know that Bean in the Spring we will by the Spring IOC container management, there is a very important method in AbstractApplicationContext: Refresh (), which initializes all beans by calling getBean() when the project starts or restarts. This getBean() will eventually point to the getBean() method in AbstractBeanFactory.

In AbstractBeanFactory, getBean() ends up calling doGetBean(), either by name or by type. The doGetBean() method starts with the name beanName and instance sharedInstance, which is too long. Just stick the first two lines here.

String beanName = this.transformedBeanName(name);
Object sharedInstance = this.getSingleton(beanName);
Copy the code

TransformedBeanName (name) removes the ‘&’ before name to get the Bean’s real name, while getSingleton(beanName) is an instance of the Bean taken from the parent singletonObjects container. In Spring there are many such containers, such as the beanDefinitionMap DefaultListableBeanFactory, it is the place where the IOC container really save Bean, it is a HashMap. Similarly the factoryBeanObjectCache FactoryBeanRegistrySupport etc.

Back to doGetBean () method, take after sharedInstance, behind a pile of operation done singleton, many cases such as judgment, will eventually go to this. The getObjectForBeanInstance (), a key part in this method, enter the method code.

protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        if(! (beanInstanceinstanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(this.transformedBeanName(name), beanInstance.getClass()); }}if (beanInstance instanceofFactoryBean && ! 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);
            }
            booleansynthetic = mbd ! =null && mbd.isSynthetic();
            object = this.getObjectFromFactoryBean(factory, beanName, ! synthetic); }return object;
    } else {
        returnbeanInstance; }}Copy the code

In the code above, there are two judgments are beanInstance instanceof FactoryBean and BeanFactoryUtils isFactoryDereference (name), The former determines whether beanInstance is an instance of a FactoryBean or its subclasses, while the latter determines whether name is not null and begins with an &.

    public static boolean isFactoryDereference(@Nullable String name) {
        returnname ! =null && name.startsWith("&");
    }
Copy the code

Return the instance object beanInstance directly if it does not belong to an instance of a FactoryBean or subclass of it, or if the name begins with &, otherwise it goes into the if branch. The various if.. in the if branch. = = null judgments is in order to improve the performance, let’s watch: key part only pick object = this. GetObjectFromFactoryBean (factory, beanName,! synthetic); Keep tracking down the code.

protected Object getObjectFromFactoryBean(FactoryBean<? > factory, String beanName,boolean shouldPostProcess) {
    if (factory.isSingleton() && this.containsSingleton(beanName)) {
        synchronized(this.getSingletonMutex()) {
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                object = this.doGetObjectFromFactoryBean(factory, beanName);
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if(alreadyThere ! =null) {
                    object = alreadyThere;
                } else {
                    if (shouldPostProcess) {
                        if (this.isSingletonCurrentlyInCreation(beanName)) {
                            return object;
                        }
                        this.beforeSingletonCreation(beanName);
                        try {
                            object = this.postProcessObjectFromFactoryBean(object, beanName);
                        } catch (Throwable var14) {
                            throw new BeanCreationException(beanName, 
                                                            "Post-processing of FactoryBean's singleton object failed", var14);
                        } finally {
                            this.afterSingletonCreation(beanName); }}if (this.containsSingleton(beanName)) {
                        this.factoryBeanObjectCache.put(beanName, object); }}}returnobject; }}else {
        Object object = this.doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) {
            try {
                object = this.postProcessObjectFromFactoryBean(object, beanName);
            } catch (Throwable var17) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", var17); }}returnobject; }}Copy the code

A lot of judgments have been made here, so let’s just pick the key parts. Here is a personal thought, ** look at the source code if we have been looking for all the details that will let us get deeper and deeper, into the details of the bottomless pit, a little not to keep the divine brain circuit can not keep up with the circle. We have to learn to find the key part of the source code, understand the main process and the purpose of the source code that part on the line. Once we have a good understanding of Spring as a whole, it becomes clear to look back at the code we didn’t understand before. * * in the method above both on the surface if at the bottom of the branch or else, the key part is the object = this. DoGetObjectFromFactoryBean (factory, beanName) this code calls, continue to point in.

private Object doGetObjectFromFactoryBean(FactoryBean
        factory, String beanName) throws BeanCreationException {
    Object object;
    try {
        if(System.getSecurityManager() ! =null) {
            AccessControlContext acc = this.getAccessControlContext();
            try {
                object = AccessController.doPrivileged(factory::getObject, acc);
            } catch (PrivilegedActionException var6) {
                throwvar6.getException(); }}else{ object = factory.getObject(); }}catch (FactoryBeanNotInitializedException var7) {
        throw new BeanCurrentlyInCreationException(beanName, var7.toString());
    } catch (Throwable var8) {
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", var8);
    }
    if (object == null) {
        if (this.isSingletonCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName, 
                                                       "FactoryBean which is currently in creation returned null from getObject");
        }
        object = new NullBean();
    }
    return object;
}
Copy the code

There is a key line of code in this method: object = factory.getobject (); This factory is the beanInstance we passed in. After going all the way around, the getBean method returns the getObject method that we implement the FactoryBean interface definition.

A FactoryBean is a FactoryBean that produces or decorates the generation of objects. A Bean that implements the FactoryBean interface actually gets the object returned by getObject() from the Bean name, not the Bean instance itself. If you want to get an instance of the Bean itself, you need to prefix the name with an am&.

In general, Spring uses the class attribute of reflection to specify that the implementation class instantiates beans. In some cases, the process of instantiating beans is complicated and requires a lot of configuration information to be provided in. The flexibility of configuration is limited, and coding may yield a simple solution. Spring provides a org. Springframework. Beans. Factory. FactoryBean factory class interface, users can customize by implementing the interface logic instantiation of the bean. The FactoryBean interface plays an important role in the Spring framework. Spring itself provides over 70 FactoryBean implementations. They hide the details of instantiating complex beans for the benefit of upper-layer applications. Starting with Spring3.0, factorybeans began to support generics, that is, interface declarations changed to the form of factorybeans


The starting address: www.guitu18.com/post/2019/0…

Now that the principle is clear, let’s verify the above process with a code test that starts by defining a Bean to implement the FactoryBean interface.

@Component
public class MyBean implements FactoryBean {
    private String message;
    public MyBean(a) {
        this.message = "Initialize instance by constructor";
    }
    @Override
    public Object getObject(a) throws Exception {
        MyBean myBean = new MyBean();
        myBean.message = "Create an instance from FactoryBean.getobject ()";
        It is not necessary to return an instance of MyBean itself; it can be an instance of any other object
        return myBean;
    }
    @Override
    publicClass<? > getObjectType() {return MyBean.class;
    }
    public String getMessage(a) {
        returnmessage; }}Copy the code

MyBean implements two methods of the FactoryBean interface. GetObject () returns an instance of any object. Here the test returns MyBean itself and assigns a value to the Message field before returning. We also assign a value to message in the constructor. The test code then gets the Bean instance by name, prints the message content, and then gets the instance by ‘&’+ name and prints the message content.

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class FactoryBeanTest {
    @Autowired
    private ApplicationContext context;
    @Test
    public void test(a) {
        MyBean myBean1 = (MyBean) context.getBean("myBean");
        System.out.println("myBean1 = " + myBean1.getMessage());
        MyBean myBean2 = (MyBean) context.getBean("&myBean");
        System.out.println("myBean2 = " + myBean2.getMessage());
        System.out.println("myBean1.equals(myBean2) = "+ myBean1.equals(myBean2)); }}Copy the code
MyBean1 = instantiate myBean2 by factoryBean.getobject () = instantiate myBean1.equals(myBean2) by constructor =false
Copy the code

Through testing, we found that the value of message in the two obtained instances is different, and the reference of the two objects is different. This article ends with all that I’ve said about FactoryBeans.