5.3 Getting objects from instances of bean s
In the getBean method, getObjectForBeanInstance is a high-frequency method used whether beans are obtained from the cache or loaded according to different scope policies.In summary, the first step after we get an instance of a bean is to call this method to check for correctness, which is actually to check if the current bean is a FactoryBean type bean, and if so, call getObject() in the corresponding FactoryBean instance of the bean as the return value.
Whether beans are retrieved from the cache or loaded through different scope policies, they are the most primitive state of the beans and are not necessarily the beans we ultimately want.For example, if we need to process factory beans, what we get here is the initial state of the factory beans, but what we really need is the beans returned from the factory-method method defined in the factory beans, and the getObjectForBeanInstance method does that.
1 protected Object getObjectForBeanInstance( 2 Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { 3 4 //If specified name Is factory related(with&As prefix)And beanInstance And it's not FactoryBean Type fails validation 5 if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { 6 throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance. getClass()); 7 } 8 9 //Now we have one bean Instance, which may be normal bean Or FactoryBean 10 //If it is FactoryBean We use it to create instances, but if the user wants to get the factory instance directly instead of the factory's getObject Method's corresponding instance is then passed in name Prefixes should be added& 11 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils. IsFactory Dereference(name)) { 12 return beanInstance; 13 } 14 15 //Load FactoryBean 16 Object object = null; 17 if (mbd == null) { 18 //Attempt to load from cache bean 19 object = getCachedObjectForFactoryBean(beanName); 20 } 21 if (object == null) { 22 //It's clear here beanInstance By all means FactoryBean type 23 FactoryBean<?> factory = (FactoryBean<?>) beanInstance; 24 //containsBeanDefinition Testing beanDefinitionMap In other words, check for definitions in all loaded classes beanName 25 if (mbd == null && containsBeanDefinition(beanName)) { 26 //Will store XML Configuration file GernericBeanDefinition Convert to RootBeanDefinition,If specified BeanName Yes child Bean Will also combine attributes of the parent class 27 mbd = getMergedLocalBeanDefinition(beanName); 28 } 29 //Is it user defined, not the application itself 30 boolean synthetic = (mbd != null && mbd.isSynthetic()); 31 object = getObjectFromFactoryBean(factory, beanName, !synthetic); 32 } 33 return object; 34 }
From the code above, there is actually no important information about this method, mostly auxiliary code and some functional judgments, while the real core code is delegated to getObjectFromFactoryBean. Let's take a look at the work done in getObjectForBeanInstance.
(1) Verify the correctness of FactoryBean.
(2) Do not handle non-FactoryBean s at all.
(3) Convert bean s.
(4) Delegate the work of parsing bean s from Factory to getObjectFromFactoryBean.
1 protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) { 2 //If singleton mode 3 if (factory.isSingleton() && containsSingleton(beanName)) { 4 synchronized (getSingletonMutex()) { 5 Object object = this.factoryBeanObjectCache.get(beanName); 6 if (object == null) { 7 object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess); 8 this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT)); 9 } 10 return (object != NULL_OBJECT ? object : null); 11 } 12 } 13 else { 14 return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess); 15 } 16 }
Unfortunately, we still don't see the code we want to see. One thing we do in this method is to ensure that the returned bean s are globally unique if they are singular. Also, because they are singular, we don't have to create them again. Instead, we can use caches to improve performance.That is, if it has already been loaded, it should be recorded for the next reuse, otherwise it will be obtained directly.
In the doGetObjectFromFactoryBean method, we finally see what we want to see, which is object = factory.getObject(). Yes, that's the code. Our journey is like peeling onions, layer by layer, to the innermost code implementation, albeit very simple.
1 private Object doGetObjectFromFactoryBean( 2 final FactoryBean factory, final String beanName, final boolean shouldPostProcess) 3 throws BeanCreationException { 4 5 Object object; 6 try { 7 //Privilege validation is required 8 if (System.getSecurityManager() != null) { 9 AccessControlContext acc = getAccessControlContext(); 10 try { 11 object = AccessController.doPrivileged(new PrivilegedExceptionAction< Object>() { 12 public Object run() throws Exception { 13 return factory.getObject(); 14 } 15 }, acc); 16 } 17 catch (PrivilegedActionException pae) { 18 throw pae.getException(); 19 } 20 } 21 else { 22 //Direct Call getObject Method 23 object = factory.getObject(); 24 } 25 } 26 catch (FactoryBeanNotInitializedException ex) { 27 throw new BeanCurrentlyInCreationException(beanName, ex.toString()); 28 } 29 catch (Throwable ex) { 30 throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex); 31 } 32 if (object == null && isSingletonCurrentlyInCreation(beanName)) { 33 throw new BeanCurrentlyInCreationException( 34 beanName, "FactoryBean which is currently in creation returned null from getObject"); 35 } 36 37 if (object != null && shouldPostProcess) { 38 try { 39 //call ObjectFactory Postprocessor 40 object = postProcessObjectFromFactoryBean(object, beanName); 41 } 42 catch (Throwable ex) { 43 throw new BeanCreationException(beanName, "Post-processing of the FactoryBean's object failed", ex); 44 } 45 } 46 47 return object; 48 }
The method of invoking FactoryBean has been described above. If a bean is declared as a FactoryBean type, it is not the FactoryBean that is extracted when it is extracted, but the Bean returned by the corresponding getObject method in the FactoryBean, which is exactly what the doGetObjectFromFactoryBean does.However, we can see that in the above method, besides calling object = factory.getObject() to get the desired result, we did not return directly, but did some post-processing next. What is this for?So we track the postProcessObjectFromFactoryBean method that enters the AbstractAutowireCapableBeanFactory class:
1 protected Object postProcessObjectFromFactoryBean(Object object, String beanName) { 2 return applyBeanPostProcessorsAfterInitialization(object, beanName); 3 } 4 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) 5 throws BeansException { 6 7 Object result = existingBean; 8 for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { 9 result = beanProcessor.postProcessAfterInitialization(result, beanName); 10 if (result == null) { 11 return result; 12 } 13 } 14 return result; 15 }
* We haven't touched much on the use of post processors yet, and a lot of space will be used in subsequent chapters. Here, we only need to understand that one of the rules for getting beans in Spring is to make sure that all beans are initialized and then invoke the postProcessAfterInitialization method of the registered BeanPostProcessor.Processing, in the actual development process, you can design your own business logic for this feature.
Reprinted at: https://my.oschina.net/u/1590001/blog/268202