Chapter 3: FactoryBeanRegistrySupport of spring bean (4)

Preface

From the name of the FactoryBeanRegistrySupport class, we can see that FactoryBeanRegistrySupport is responsible for the registration and support of FactoryBean. If you want to know about FactoryBean, please read the interpretation of FactoryBean in spring bean.

Source code interpretation

public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {

	//  Cache the objects of singleton FactoryBean from getObject
	private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<String, Object>(16);

	// Get obejccttpye from factoryBean.getObjectType().
	protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
		try {
			if (System.getSecurityManager() != null) {
				return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
					@Override
					public Class<?> run() {
						return factoryBean.getObjectType();
					}
				}, getAccessControlContext());
			}
			else {
				return factoryBean.getObjectType();
			}
		}
		catch (Throwable ex) {
			// Thrown from the FactoryBean's getObjectType implementation.
			logger.warn("FactoryBean threw exception from getObjectType, despite the contract saying " +
					"that it should return null if the type of its object cannot be determined yet", ex);
			return null;
		}
	}

// Get objects from the cache via beanName
	protected Object getCachedObjectForFactoryBean(String beanName) {
		Object object = this.factoryBeanObjectCache.get(beanName);
		return (object != NULL_OBJECT ? object : null);
	}

	//  After calling getCachedObjectForFactoryBean, the getObjectFromFactoryBean method will be called only when the recognition result is empty
	//
	protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		if (factory.isSingleton() && containsSingleton(beanName)) {
			synchronized (getSingletonMutex()) {// Get lock in DefaultSingletonBeanRegistry
				Object object = this.factoryBeanObjectCache.get(beanName);// At the time of concurrency, thread A and B inject into A(FactoryBean). When thread A registers, it does not,
				if (object == null) {// When A thread registers, if not, it gets the object from FactoryBean
					object = doGetObjectFromFactoryBean(factory, beanName);// Get object from FactoryBean
					// 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);// Why is the answer given in the above English
					if (alreadyThere != null) {
						object = alreadyThere;
					}
					else {
						if (object != null && shouldPostProcess) {
							try {
								object = postProcessObjectFromFactoryBean(object, beanName);// Process objects from FactoryBean
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
						}
						this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));//Save in cache
					}
				}
				return (object != NULL_OBJECT ? object : null);
			}
		}
		else {
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			if (object != null && shouldPostProcess) {
				try {
					object = postProcessObjectFromFactoryBean(object, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
				}
			}
			return object;
		}
	}

	// Call FactoryBean.getObject() method
	private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
			throws BeanCreationException {

		Object object;
		try {
			if (System.getSecurityManager() != null) {
				AccessControlContext acc = getAccessControlContext();
				try {
					object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
						@Override
						public Object run() throws Exception {
								return factory.getObject();
							}
						}, acc);
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				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 && isSingletonCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(
					beanName, "FactoryBean which is currently in creation returned null from getObject");
		}
		return object;
	}


	protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
		return object;
	}


	protected FactoryBean<?> getFactoryBean(String beanName, Object beanInstance) throws BeansException {
		if (!(beanInstance instanceof FactoryBean)) {
			throw new BeanCreationException(beanName,
					"Bean instance of type [" + beanInstance.getClass() + "] is not a FactoryBean");
		}
		return (FactoryBean<?>) beanInstance;
	}
	// Overriding the removesignleton method of DefaultSingletonBeanRegistry
	protected void removeSingleton(String beanName) {
		super.removeSingleton(beanName);
		this.factoryBeanObjectCache.remove(beanName);
	}

	protected AccessControlContext getAccessControlContext() {
		return AccessController.getContext();
	}

}

summary

FactoryBeanRegistrySupport is relatively simple in general. But there are still many details

  • FactoryBeanRegistrySupport does not cache the FactoryBean object, but the returned result after calling FactoryBeangetObject()
  • FactoryBean can also be divided into singleton and non singleton. This is mainly to see the return of FactoryBean.isSingleton(). If false is non singleton, then true is singleton
  • After calling getCachedObjectForFactoryBean, the getObjectFromFactoryBean method will be called only when the recognition result is empty
  • FactoryBeanRegistrySupport uses the lock in DefaultSingletonBeanRegistry when processing singleton factoryBean
  • FactoryBeanRegistrySupport overrides the removesignleton method of DefaultSingletonBeanRegistry
  • The postProcessObjectFromFactoryBean method of FactoryBeanRegistrySupport can be overridden. The function of the postProcessObjectFromFactoryBean method is to process the object from FactoryBean.getObject()
  • Objects obtained from FactoryBean will not enter the bean life cycle and monitoring

Tags: Spring

Posted on Sun, 09 Feb 2020 13:37:09 -0500 by nikefido