Prototype Bean loading process
Previous article analyzes the Singleton Bean non-lazy loading of the entire loading process, in addition to the single case of non-Bean lazy loading, Spring There is also a Bean is the prototype (Prototype) of Bean, look at the definition of the way:
1 26 7 8 9
Generally speaking prototype Bean loading process and almost single cases Bean, look at the differences, in this step of the method AbstractBeanFactory of doGetBean:
1 else if (mbd.isPrototype()) { 2 // It's a prototype -> create a new instance. 3 Object prototypeInstance = null; 4 try { 5 beforePrototypeCreation(beanName); 6 prototypeInstance = createBean(beanName, mbd, args); 7 } 8 finally { 9 afterPrototypeCreation(beanName); 10 } 11 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 12 }
Line 6 createBean is the same as the prototype Bean instantiation main difference lies in the line 6, which is created directly bean, and singleton bean Let us compare:
1 if (mbd.isSingleton()) { 2 sharedInstance = getSingleton(beanName, new ObjectFactory() { 3 public Object getObject() throws BeansException { 4 try { 5 return createBean(beanName, mbd, args); 6 } 7 catch (BeansException ex) { 8 // Explicitly remove instance from singleton cache: It might have been put there 9 // eagerly by the creation process, to allow for circular reference resolution. 10 // Also remove any beans that received a temporary reference to the bean. 11 destroySingleton(beanName); 12 throw ex; 13 } 14 } 15 }); 16 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 17 }
It priority will try getSington, which is to try to get it from singletonObjects the bean exists, if there is a direct return to the bean object singletonObjects.
Next, we see that the difference between the prototype and create a single bean bean embodiment is further characterized by creating and row 5, line 9, look at the code line 5:
1 protected void beforePrototypeCreation(String beanName) { 2 Object curVal = this.prototypesCurrentlyInCreation.get(); 3 if (curVal == null) { 4 this.prototypesCurrentlyInCreation.set(beanName); 5 } 6 else if (curVal instanceof String) { 7 SetbeanNameSet = new HashSet (2); 8 beanNameSet.add((String) curVal); 9 beanNameSet.add(beanName); 10 this.prototypesCurrentlyInCreation.set(beanNameSet); 11 } 12 else { 13 Set beanNameSet = (Set ) CurVal; 14 beanNameSet.add (beanName); 15} 16}
This main point is that bean put before the creation of the current ThreadLocal beanName set to go, the aim is to ensure that multiple threads at the same time does not create the same bean. Then look at the code line 9 of the realization that the bean After creating what has been done:
1 protected void afterPrototypeCreation(String beanName) { 2 Object curVal = this.prototypesCurrentlyInCreation.get(); 3 if (curVal instanceof String) { 4 this.prototypesCurrentlyInCreation.remove(); 5 } 6 else if (curVal instanceof Set) { 7 SetbeanNameSet = (Set ) curVal; 8 beanNameSet.remove(beanName); 9 if (beanNameSet.isEmpty()) { 10 this.prototypesCurrentlyInCreation.remove(); 11 } 12 } 13 }
Well understood, it is to look at the current bean removed, so that other threads can create a bean. The first 11 lines of code do not read, meaning that if the bean implementation class is FactoryBean then call getObject () method to get real object.
byName source code implementation
Spring promising developers with Autowire (auto assembly) function, automatic assembly and most common is byName byType these two attributes. Since the object is to solve the automatic assembling due to injection
1 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || 2 mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 3 MutablePropertyValues newPvs = new MutablePropertyValues(pvs); 4 5 // Add property values based on autowire by name if applicable. 6 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { 7 autowireByName(beanName, mbd, bw, newPvs); 8 } 9 10 // Add property values based on autowire by type if applicable. 11 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { 12 autowireByType(beanName, mbd, bw, newPvs); 13 } 14 15 pvs = newPvs; 16 }
See line 6 to line 8 determines whether byName form, is executed byName autowiring codes; ~ line 11, line 13 determines whether byType form, is automatically executed byType assembly code. So first of all look at the code on line 7 byName achieve:
1 protected void autowireByName( 2 String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { 3 4 String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); 5 for (String propertyName : propertyNames) { 6 if (containsBean(propertyName)) { 7 Object bean = getBean(propertyName); 8 pvs.add(propertyName, bean); 9 registerDependentBean(propertyName, beanName); 10 if (logger.isDebugEnabled()) { 11 logger.debug("Added autowiring by name from bean name '" + beanName + 12 "' via property '" + propertyName + "' to bean named '" + propertyName + "'"); 13 } 14 } 15 else { 16 if (logger.isTraceEnabled()) { 17 logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName + 18 "' by name: no matching bean found"); 19 } 20 } 21 } 22 }
Space problem, with the layers of different codes, logical comb:
- Line 4, find the Bean is not a simple attribute properties, these words around a bit, meaning that the object is to find the property type of property, but not all types of objects will be found, such as the type CharSequence, Number Type, Date type, URL type, URI type, Locale type, Class type will be ignored, visible isSimpleProperty specific method of BeanUtils
- 5, lines - 7 lines, through all attributes are found, if the bean definition contains an attribute name, then the first instance of the name attribute corresponding bean
- Line 9 registerDependentBean, registered at the current bean depends bean, a bean for the destruction of the first to be destroyed before it depends on bean
Rest of the code are some of the play log, nothing to say.
byType source code implementation
Above that byName source code to achieve, let's look at byType source code to achieve:
1 protected void autowireByType( 2 String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { 3 4 TypeConverter converter = getCustomTypeConverter(); 5 if (converter == null) { 6 converter = bw; 7 } 8 9 SetautowiredBeanNames = new LinkedHashSet (4); 10 String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); 11 for (String propertyName : propertyNames) { 12 try { 13 PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName); 14 // Don't try autowiring by type for type Object: never makes sense, 15 // even if it technically is a unsatisfied, non-simple property. 16 if (!Object.class.equals(pd.getPropertyType())) { 17 MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); 18 // Do not allow eager init for type matching in case of a prioritized post-processor. 19 boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass()); 20 DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager); 21 Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter); 22 if (autowiredArgument != null) { 23 pvs.add(propertyName, autowiredArgument); 24 } 25 for (String autowiredBeanName : autowiredBeanNames) { 26 registerDependentBean(autowiredBeanName, beanName); 27 if (logger.isDebugEnabled()) { 28 logger.debug("Autowiring by type from bean name '" + beanName + "' via property '" + 29 propertyName + "' to bean named '" + autowiredBeanName + "'"); 30 } 31 } 32 autowiredBeanNames.clear(); 33 } 34 } 35 catch (BeansException ex) { 36 throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex); 37 } 38 } 39 }
Like before, the line 10 is found in the Bean property is the object type attributes.
Then it is to walk PropertyName, get property descriptors corresponding PropertyName, take note of Judgment and the corresponding Note 16 line: Do not attempt to automatically assemble Object type, it does not make sense, even from a technical point of view it is a non-simple object properties .
Line 18 through line 20 is skipped (not too clear is doing), the main source of the byType implemented method resolveDependency line 21, the method is a method to achieve this type of class DefaultListableBeanFactory AbstractAutowireCapableBeanFactory:
1 public Object resolveDependency(DependencyDescriptor descriptor, String beanName, 2 SetautowiredBeanNames, TypeConverter typeConverter) throws BeansException { 3 4 descriptor.initParameterNameDiscovery(getParameterNameDiscoverer()); 5 if (descriptor.getDependencyType().equals(ObjectFactory.class)) { 6 return new DependencyObjectFactory(descriptor, beanName); 7 } 8 else if (descriptor.getDependencyType().equals(javaxInjectProviderClass)) { 9 return new DependencyProviderFactory().createDependencyProvider(descriptor, beanName); 10 } 11 else { 12 return doResolveDependency(descriptor, descriptor.getDependencyType(), beanName, autowiredBeanNames, typeConverter); 13 } 14 }
Here I want to automatically determine what property is ObjectFactory.class assembly or javaxInjectProviderClass or the other, we are assembling the other, look at the code line to achieve 12:
1 protected Object doResolveDependency(DependencyDescriptor descriptor, Class type, String beanName, 2 SetautowiredBeanNames, TypeConverter typeConverter) throws BeansException { 3 4 Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); 5 if (value != null) { 6 if (value instanceof String) { 7 String strVal = resolveEmbeddedValue((String) value); 8 BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); 9 value = evaluateBeanDefinitionString(strVal, bd); 10 } 11 TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); 12 return converter.convertIfNecessary(value, type); 13 } 14 15 if (type.isArray()) { 16 ... 17 } 18 else if (Collection.class.isAssignableFrom(type) && type.isInterface()) { 19 ... 20 } 21 else if (Map.class.isAssignableFrom(type) && type.isInterface()) { 22 ... 23 } 24 else { 25 Map matchingBeans = findAutowireCandidates(beanName, type, descriptor); 26 if (matchingBeans.isEmpty()) { 27 if (descriptor.isRequired()) { 28 raiseNoSuchBeanDefinitionException(type, "", descriptor); 29 } 30 return null; 31 } 32 if (matchingBeans.size() > 1) { 33 String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor); 34 if (primaryBeanName == null) { 35 throw new NoSuchBeanDefinitionException(type, "expected single matching bean but found " + 36 matchingBeans.size() + ": " + matchingBeans.keySet()); 37 } 38 if (autowiredBeanNames != null) { 39 autowiredBeanNames.add(primaryBeanName); 40 } 41 return matchingBeans.get(primaryBeanName); 42 } 43 // We have exactly one match. 44 Map.Entry entry = matchingBeans.entrySet().iterator().next(); 45 if (autowiredBeanNames != null) { 46 autowiredBeanNames.add(entry.getKey()); 47 } 48 return entry.getValue(); 49 } 50 }
The result is the fourth line null do not read, to simplify the code Array assembly, Collection assembly code Map assembly are omitted, emphasis ordinary look at the assembling property. First Line 25 candidates obtain at automatic assembly:
1 protected MapfindAutowireCandidates( 2 String beanName, Class requiredType, DependencyDescriptor descriptor) { 3 4 String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( 5 this, requiredType, true, descriptor.isEager()); 6 Map result = new LinkedHashMap (candidateNames.length); 7 for (Class autowiringType : this.resolvableDependencies.keySet()) { 8 if (autowiringType.isAssignableFrom(requiredType)) { 9 Object autowiringValue = this.resolvableDependencies.get(autowiringType); 10 autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType); 11 if (requiredType.isInstance(autowiringValue)) { 12 result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue); 13 break; 14 } 15 } 16 } 17 for (String candidateName : candidateNames) { 18 if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) { 19 result.put(candidateName, getBean(candidateName)); 20 } 21 } 22 return result; 23 }
Code logic to sort out:
- First acquisition candidates bean name, by getBeanNamesForType DefaultListableBeanFactory method, that is looking at all of the definitions specified Type Bean implementation class or subclass
- Next type judgment line 7 to line 16 to automatic assembling is not to be automatically assembled correct type, the in [Analysis Spring source] before and after a single embodiment Bean initialize non lazy loading of some of the operations a Texts PrepareBeanFactory method when there is I said before, if the type to be automatically assembled is correct type, such as a a ResourceLoader, will generate a proxy instance for the type, specifically look at the implementation of the method AutowireUtils.resolveAutowiringValue line 10
- Normally, the code is 17, line 21 - line executed one by one to find what is determined corresponding to the BeanDefinition beanName, a judgment is not a candidate for automatic assembly, is the default, if
The autowire-candidate attribute is not set to false
Thus, to get the candidate class or subclass to achieve all the objects to be assembled to form a Map, Key is beanName, Value concrete Bean. Then look back at the logic after the acquisition Bean:
1 MapmatchingBeans = findAutowireCandidates(beanName, type, descriptor); 2 if (matchingBeans.isEmpty()) { 3 if (descriptor.isRequired()) { 4 raiseNoSuchBeanDefinitionException(type, "", descriptor); 5 } 6 return null; 7 } 8 if (matchingBeans.size() > 1) { 9 String primaryBeanName = determinePrimaryCandidate(matchingBeans, descriptor); 10 if (primaryBeanName == null) { 11 throw new NoSuchBeanDefinitionException(type, "expected single matching bean but found " + 12 matchingBeans.size() + ": " + matchingBeans.keySet()); 13 } 14 if (autowiredBeanNames != null) { 15 autowiredBeanNames.add(primaryBeanName); 16 } 17 return matchingBeans.get(primaryBeanName); 18 } 19 // We have exactly one match. 20 Map.Entry entry = matchingBeans.entrySet().iterator().next(); 21 if (autowiredBeanNames != null) { 22 autowiredBeanNames.add(entry.getKey()); 23 } 24 ... 25 }
Sort out the logic:
- If you get the Map is empty and the property must be injected, Throws
- If get a plurality of candidates in the Map, it is determined whether there
Configuration attribute is "primary = true", there are 13 lines of code execution took ~ on line 15, the first method is not the line 8 returns null, throw exception that description believed Spring be used more more familiar - If you get the Map is only one candidate, take it directly to the
By this way the whole process to achieve byType automatic assembly, automatic assembly process byType longer, more middle details, also need to look at to figure it out.
Finally note that all that is to be injected PropertyName -> PropertyValue after mapping are simply placed MutablePropertyValues get the last traversal by the method AbstractPropertyAccessor setPropertyValues class and one by one injection.
Get Bean examples of source code to achieve through FactoryBean
We know that can be achieved by FactoryBean interface rewrite getObject () method to achieve Bean customization process, this part we will look at how Spring source is achieved by obtaining Bean instance of FactoryBean. DoGetBean code is located directly create a single embodiment of the method of AbstractBeanFactory Bean this section:
1 // Create bean instance. 2 if (mbd.isSingleton()) { 3 sharedInstance = getSingleton(beanName, new ObjectFactory() { 4 public Object getObject() throws BeansException { 5 try { 6 return createBean(beanName, mbd, args); 7 } 8 catch (BeansException ex) { 9 // Explicitly remove instance from singleton cache: It might have been put there 10 // eagerly by the creation process, to allow for circular reference resolution. 11 // Also remove any beans that received a temporary reference to the bean. 12 destroySingleton(beanName); 13 throw ex; 14 } 15 } 16 }); 17 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 18 }
FactoryBean The first is to call the getObject () method and after a Bean is instantiated out to be an object, so it will execute the code 3, line 16 - line, analyzed before this code will not say. After the execution of line 17 methods:
1 protected Object getObjectForBeanInstance( 2 Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { 3 4 // Don't let calling code try to dereference the factory if the bean isn't a factory. 5 if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { 6 throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); 7 } 8 9 // Now we have the bean instance, which may be a normal bean or a FactoryBean. 10 // If it's a FactoryBean, we use it to create a bean instance, unless the 11 // caller actually wants a reference to the factory. 12 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { 13 return beanInstance; 14 } 15 16 Object object = null; 17 if (mbd == null) { 18 object = getCachedObjectForFactoryBean(beanName); 19 } 20 if (object == null) { 21 // Return bean instance from factory. 22 FactoryBean factory = (FactoryBean) beanInstance; 23 // Caches object obtained from FactoryBean if it is a singleton. 24 if (mbd == null && containsBeanDefinition(beanName)) { 25 mbd = getMergedLocalBeanDefinition(beanName); 26 } 27 boolean synthetic = (mbd != null && mbd.isSynthetic()); 28 object = getObjectFromFactoryBean(factory, beanName, !synthetic); 29 } 30 return object; 31 }
First line to the fifth line 7 beanName to determine what the "&" at the beginning of the implementation class and not FactoryBean, throw exception is not satisfied, because the "&" is the beginning of the implementation class of a bean definition FactoryBean beanName feature.
Then determines 12 line 14 - line, if:
- bean implementation class is not FactoryBean
- beanName with "&" at the beginning
In both cases, directly to the return generated bean object out, the rest of the process will not be executed.
Finally, the process went 16 th to the 30 line, the final call to getObject () method to achieve customization bean, performed first on line 28 methods:
1 protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) { 2 if (factory.isSingleton() && containsSingleton(beanName)) { 3 synchronized (getSingletonMutex()) { 4 Object object = this.factoryBeanObjectCache.get(beanName); 5 if (object == null) { 6 object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess); 7 this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT)); 8 } 9 return (object != NULL_OBJECT ? object : null); 10 } 11 } 12 else { 13 return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess); 14 } 15 }
Code ~ code, line 13, line 12, line 11 of the first line to the final is the same, the following paragraph call:
1 private Object doGetObjectFromFactoryBean( 2 final FactoryBean factory, final String beanName, final boolean shouldPostProcess) 3 throws BeanCreationException { 4 5 Object object; 6 try { 7 if (System.getSecurityManager() != null) { 8 AccessControlContext acc = getAccessControlContext(); 9 try { 10 object = AccessController.doPrivileged(new PrivilegedExceptionAction