Preface
Let's first look at the interface definition.
public interface FactoryBean<T> { /** * Return object instance */ @Nullable T getObject() throws Exception; /** * Returns the object type. */ @Nullable Class<?> getObjectType(); /** * Is the object of the factory management a singleton? */ default boolean isSingleton() { return true; } }
As can be seen from the interface definition, the beans that implement this interface are not the main functions, and the objects created by getObject() are the key points. So here we can guess that you could use FactoryBean to create some beans with more complex instantiation processes.
Registration of FactoryBean
The processing logic of FactoryBean is in the AbstractBeanFactory.doGetBean method
protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException { //Get the bean name final String beanName = transformedBeanName(name); Object bean; //Omit part of content //Here is the processing of FactoryBean, which will be expanded below. bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); //Omit part of content return (T) bean; }
Take a look at the specific logic. Here we need to notice that Spring has a hidden rule for bean name, and all bean names at the beginning are FactoryBean by default.
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { // If bean Name starts with factory reference if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } // If the name starts with & and the bean Instance is not a FactoryBean type, an exception is thrown if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); } } // If the bean Instance is not of FactoryBean type, return the bean Instance directly // Or the name starts with & and returns directly to the bean Instance, indicating that we want to get an instance of FactoryBean if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } Object object = null; if (mbd == null) { object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // At this point, the bean Instance is a FactoryBean type, and the name does not start with &; this is the case with our s amp le project, and it is also the most common and frequently used case. // Strongly convert bean Instance to FactoryBean type FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // Get the instance objects we need from the cache if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); // Calling the getObject method of FactoryBean to create the instance objects we need object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { //Processing for singletons if (factory.isSingleton() && containsSingleton(beanName)) { synchronized (getSingletonMutex()) { Object object = this.factoryBeanObjectCache.get(beanName); if (object == null) { //Get it through factory.getObject object = doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this.factoryBeanObjectCache.get(beanName); if (alreadyThere != null) { 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)) { //Store the acquired object in factoryBeanObjectCache singleton cache map this.factoryBeanObjectCache.put(beanName, object); } } } return object; } } else { //Non-singleton processing, obtained directly through factory.getObejct, and then returned to the user 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); } } return object; } }
Method of generating bean object:
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((PrivilegedExceptionAction<Object>) factory::getObject, acc); } catch (PrivilegedActionException pae) { throw pae.getException(); } } else { object = factory.getObject();//Generated object } } 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;}
Implementation of Spring
There are many bean s that implement this interface in Spring, but what we are most familiar with and most importantly is that I mentioned in my previous article that ProxyFactoryBean is the key point to realize AOP technology. Let's review it briefly.
public Object getObject() throws BeansException { initializeAdvisorChain(); if (isSingleton()) { return getSingletonInstance(); } else { if (this.targetName == null) { logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } return newPrototypeInstance(); } } private synchronized Object getSingletonInstance() { if (this.singletonInstance == null) { this.targetSource = freshTargetSource(); if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) { // Rely on AOP infrastructure to tell us what interfaces to proxy. Class<?> targetClass = getTargetClass(); if (targetClass == null) { throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy"); } setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader)); } // Initialize the shared singleton instance. super.setFrozen(this.freezeProxy); this.singletonInstance = getProxy(createAopProxy()); } return this.singletonInstance; }