Spring source code analysis - FactoryBean obtains Bean process

1. FactoryBean

FactoryBeanIt is Springone of the core interfaces provided by the framework to create objects that are complex or cannot be created through the default constructor. In this case, by implementing FactoryBeanthe interface, you can customize the instantiation Beanprocess, including Beanthe object type, initialization, destruction, etc.

In application scenarios, you can use to FactoryBeanintegrate third-party frameworks, open source libraries, or handle some special business needs, and let Beanus flexibly control the control.

For example: by FactoryBeanencapsulating the logic of object creation, the user is not aware of it, and can IOCbe obtained from the container normally Bean.

If you want to get FactoryBeanitself, you can beanNameadd a &symbol in front of , which we will experience later in the source code analysis.

Here are FactoryBeanthe components of :

public interface FactoryBean<T> {
    
    
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
	
    @Nullable
    T getObject() throws Exception;

    @Nullable
    Class<?> getObjectType();

    default boolean isSingleton() {
    
    
        return true;
    }
}

Corresponding to the description of the three core methods:

  • isSingleton(): Gets whether the instance FactoryBeancreated by Beanis a singleton or a prototype, the default is a singleton.
  • T getObject(): Get the instance FactoryBeancreated by Bean, if isSingletonthe scope is singleton, the instance will be cached.
  • Class<?> getObjectType(): Get the type FactoryBeanto be created by Bean.

The following is a simple experience FactoryBeanof using:

@Component
public class FactoryBeanTest implements FactoryBean {
    
    

    @Override
    public Object getObject() throws Exception {
    
    
        return new TestABC();
    }

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

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

    /**
     * 实际Bean
     */
    public static class TestABC{
    
    
    
    }
}

test:

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext context = new AnnotationConfigApplicationContext("com.example.demo.bean");
        System.out.println(context.getBean("factoryBeanTest"));
        System.out.println(context.getBean("&factoryBeanTest"));
    }
}

insert image description here

It can be seen that if it &starts with the symbol, what is obtained is FactoryBeanitself.

Let's analyze from the perspective of source code, how to deal with in the process of context.getBeanobtaining .BeanFactoryBean

Two, source code interpretation

In the previous article of this column Bean, the source code analysis of the creation process was carried out. If you understand it, you should know that the actual Beancreation logic is in AbstractBeanFactorythe doGetBeanmethod. Here is also doGetBeanthe method. If Beanyou don’t know the creation process, you can also refer to the following article:

Spring source code analysis - Bean creation process and resolution of circular dependencies

In doGetBeanthe method, it will first go to the singleton pool to find out whether it exists, and if it exists, it will use getObjectForBeanInstanceto get the final Beaninstance:

insert image description here

If there is none in the singleton pool at this time, perform the following Beaninstance initialization process, and also use to getObjectForBeanInstanceobtain the final Beaninstance after the instantiation is completed

insert image description here

This method may seem inconspicuous, but it actually FactoryBeanplays a key role in the method. Let's mainly look at getObjectForBeanInstancethe method below:

protected Object getObjectForBeanInstance(
		Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    
    
	// Don't let calling code try to dereference the factory if the bean isn't a factory.
	// 当前bean的名称是否是工厂模式, 主要判断名称是否以 & 开头,如果是以 & 开头,说明当前获取的是 FactoryBean 本身
	if (BeanFactoryUtils.isFactoryDereference(name)) {
    
    
		// 如果是 NullBean 直接返回
		if (beanInstance instanceof NullBean) {
    
    
			return beanInstance;
		}
		// 如果不是 FactoryBean 的话则抛出异常
		if (!(beanInstance instanceof FactoryBean)) {
    
    
			throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
		}
		if (mbd != null) {
    
    
			mbd.isFactoryBean = true;
		}
		// 返回 FactoryBean 自身
		return beanInstance;
	}

	// Now we have the bean instance, which may be a normal bean or a FactoryBean.
	// If it's a FactoryBean, we use it to create a bean instance, unless the
	// caller actually wants a reference to the factory.
	// 当前的 bean实例不是 FactoryBean,则直接返回
	if (!(beanInstance instanceof FactoryBean)) {
    
    
		return beanInstance;
	}

	// 是 FactoryBean 的情况下
	Object object = null;
	if (mbd != null) {
    
    
		mbd.isFactoryBean = true;
	}
	else {
    
    
		// 从缓存中获取
		object = getCachedObjectForFactoryBean(beanName);
	}
	if (object == null) {
    
    
		// 转为 FactoryBean 类型
		FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
		// Caches object obtained from FactoryBean if it is a singleton.
		if (mbd == null && containsBeanDefinition(beanName)) {
    
    
			mbd = getMergedLocalBeanDefinition(beanName);
		}
		boolean synthetic = (mbd != null && mbd.isSynthetic());
		// 获取 FactoryBean 实际的 Bean
		object = getObjectFromFactoryBean(factory, beanName, !synthetic);
	}
	return object;
}

In this method, the first step is to namejudge . If it &starts with , it means that the current acquisition is FactoryBeanitself. If it Beanis neither NullBeannor , FactoryBeanonly an error is reported.

If it is not of the type below FactoryBean, just return the current instance directly.

The following logic must be FactoryBeanof the type. If it does not exist in the cache, the method is finally called getObjectFromFactoryBeanto obtain it Bean. The following shows the method:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    
    
    // 如果 FactoryBean 里的 Bean 是单例模型, 并且单例池中存在
    if (factory.isSingleton() && containsSingleton(beanName)) {
    
    
        // 对单例池加锁
        synchronized (getSingletonMutex()) {
    
    
            //尝试从缓冲中获取Bean
            Object object = this.factoryBeanObjectCache.get(beanName);
            // 如果缓存中不存在
            if (object == null) {
    
    
                // 从 FactoryBean 中的 getObject() 获取 Bean
                object = doGetObjectFromFactoryBean(factory, beanName);
                // Only post-process and store if not put there already during getObject() call above
                // (e.g. because of circular reference processing triggered by custom getBean calls)
                // 再次尝试获取缓存
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
    
    
                    // 如果缓存存在使用缓存中的Bean
                    object = alreadyThere;
                } else {
    
    
                    // 缓存中依然不存在,是否需要触发后通知
                    if (shouldPostProcess) {
    
    
                        if (isSingletonCurrentlyInCreation(beanName)) {
    
    
                            // Temporarily return non-post-processed object, not storing it yet..
                            return object;
                        }
                        beforeSingletonCreation(beanName);
                        try {
    
    
                            object = postProcessObjectFromFactoryBean(object, beanName);
                        } catch (Throwable ex) {
    
    
                            throw new BeanCreationException(beanName,
                                    "Post-processing of FactoryBean's singleton object failed", ex);
                        } finally {
    
    
                            afterSingletonCreation(beanName);
                        }
                    }
                    // 加入缓存
                    if (containsSingleton(beanName)) {
    
    
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            // 返回实际的 Bean
            return object;
        }
    } else {
    
    
        // 如果不是单例模式 或 单例池中不存在
        // 从 FactoryBean 中获取 Bean
        Object object = doGetObjectFromFactoryBean(factory, beanName);
        // 是否需要触发后通知
        if (shouldPostProcess) {
    
    
            try {
    
    
                object = postProcessObjectFromFactoryBean(object, beanName);
            } catch (Throwable ex) {
    
    
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
            }
        }
        // 返回实际的 Bean
        return object;
    }
}

There are two branches here, whether FactoryBeanthe Beanis a singleton or not, that is, isSingletonthe method is trueor false, if it is a singleton, try to factoryBeanObjectCacheget the cache object through , from here we can see that the singleton cache of in exists FactoryBeanin , not the singleton pool of .BeanfactoryBeanObjectCacheSpring

In this method, the actual acquisition Beanis through doGetObjectFromFactoryBeanthe method. If it is a singleton mode, Beanput it factoryBeanObjectCacheinto the cache. If it is not a singleton, it will directly return the obtained one Bean. See doGetObjectFromFactoryBeanthe method below:

private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
    
    
    Object object;
    try {
    
    
        // 是否有安全管理
        if (System.getSecurityManager() != null) {
    
    
            AccessControlContext acc = getAccessControlContext();
            try {
    
    
                object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
            } catch (PrivilegedActionException pae) {
    
    
                throw pae.getException();
            }
        } else {
    
    
            // 调用 FactoryBean 中的 getObject 获取实际 Bean。
            object = factory.getObject();
        }
    } catch (FactoryBeanNotInitializedException ex) {
    
    
        throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    } catch (Throwable ex) {
    
    
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    }

    // Do not accept a null value for a FactoryBean that's not fully
    // initialized yet: Many FactoryBeans just return null then.
    if (object == null) {
    
    
        if (isSingletonCurrentlyInCreation(beanName)) {
    
    
            throw new BeanCurrentlyInCreationException(
                    beanName, "FactoryBean which is currently in creation returned null from getObject");
        }
        object = new NullBean();
    }
    return object;
}

It is more intuitive here, and the final instance is obtained by calling the method FactoryBeanof .getObjectBean

Guess you like

Origin blog.csdn.net/qq_43692950/article/details/131109087