- Spring Reading Directory
We’ve read some of the source code for getBean in the last article. If you get an instance from the singleton pool, you check whether that instance is a FactoryBean. If it is a FactoryBean, then all you really need to get is the object returned by getObject. Moving on, what does Spring do if it doesn’t get an instance from the singleton pool?
The singleton pool did not get the Bean
// The code above is omitted --
// The singleton pool did not get the Bean
else {
// Specifies whether the prototype bean is being created. If so, throw an exception
Spring does not support cyclic dependencies for prototype beans
/ / the current is creating the prototype of the Bean will be placed in the ThreadLocal prototypesCurrentlyInCreation
/ / 1.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
/ / 2,
// Get the parent BeanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
// The parent of the current container exists and there is no BeanDefinition in the current container.
if(parentBeanFactory ! =null && !containsBeanDefinition(beanName)) {
// Resolve the user-specified bean name to the canonical name, concatenating the ampersand
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
// recursive search
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if(args ! =null) {
// Delegation to parent with explicit args.
// There are arguments, which delegate to the parent to find according to the specified name and explicit arguments
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if(requiredType ! =null) {
// No args -> delegate to standard getBean method.
// No arguments -> delegate to the parent to look up by the specified name and type
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
// Delegate the parent to search by the specified name.
return(T) parentBeanFactory.getBean(nameToLookup); }}/ / 3.
// Marks the specified bean as created (or to be created).
// typeCheckOnly The upper input is false
Hasbeandefinitionreader () hasBeanCreationStarted()
// The markBeanAsCreated method adds data to the alreadyCreated Set
if(! typeCheckOnly) { markBeanAsCreated(beanName); }try {
/ / 4.
// Get the combined RootBeanDefinition
// If the specified BeanName is a child Bean, the attributes of the parent class will be merged
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// Check the given merge bean definition
checkMergedBeanDefinition(mbd, beanName, args);
// Ensure that the bean on which the current bean depends is initialized. First load the bean specified by DependsOn
/ / XML notation
//<bean class="com.gongj.bean.Person" id="person" depends-on="user"></bean>
//<bean class="com.gongj.bean.User" id="user" depends-on="person"></bean>
// Note writing
//@DependsOn("user")
// Get the names of all dependent beans of the current Bean. For example, the current beanName is A, which depends on B
String[] dependsOn = mbd.getDependsOn(); DependsOn is a dependsOn for B
if(dependsOn ! =null) {
for (String dep : dependsOn) {
// Check whether beanName(A) is also dependent on deP (B)
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// There are two maps
DependentBeanMap, key = dep(B), value = LinkedHashSet (A... Rely on the
DependenciesForBeanMap, key is beanName(A), value is A LinkedHashSet, beanName(A) is dependent on the deP (B) bean
registerDependentBean(dep, beanName);
try {
// Generate the dependent bean first
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex); }}}/ / 5,
// Create the bean according to Scope
// Create an instance object of the singleton Bean
if (mbd.isSingleton()) {
// Using an anonymous inner class, create Bean instance objects and register dependent objects
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// If the creation fails, explicitly destroy the given bean from the container
destroySingleton(beanName);
throwex; }});// sharedInstance can be a FactoryBean if it is a FactoryBean
// Then all you really need is the object returned by getObject
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
/ / 6,
// Create the prototype pattern Bean instance object
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
/ / will create Bean tags to create the current operation is prototypesCurrentlyInCreation this property
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
/ / create a complete, removed from prototypesCurrentlyInCreation beanName
afterPrototypeCreation(beanName);
}
// prototypeInstance can be a FactoryBean, if it is a FactoryBean,
// Then all you really need is the object returned by getObject
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// If the lifecycle scope of the Bean to be created is not Singleton, nor prototype
// Fetch the life cycle from this.scopes. Get (scopeName); Instantiate the Bean
// For example, the life cycle of request and session
/ / 7,
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
/ / will create Bean tags to create the current operation is prototypesCurrentlyInCreation this property
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
/ / create a complete, removed from prototypesCurrentlyInCreation beanNameafterPrototypeCreation(beanName); }});// scopedInstance can be a FactoryBean, if it is a FactoryBean,
// Then all you really need is the object returned by getObject
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); }}}catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throwex; }}Copy the code
- 1. :
Spring
First of all checkbeanName
Whether inprototypesCurrentlyInCreation
,prototypesCurrentlyInCreation
Is aThreadLocal
, stores the prototype that is currently being createdbeanName
The collection,Spring
Prototype not supportedbean
So one is thrownBeanCurrentlyInCreationException
The exception. - 2, : Get the parent container, if the current container’s parent container exists and the current container does not have the specified name
BeanDefinition
Try to get the bean instance from the parent container. - 3, : Whether to get the instance for type checking. will
beanName
joinalreadyCreated
In the Set collection, stores already created or in process of being createdbeanName
And callclearMergedBeanDefinition
Method to delete the merge bean definition for the specified bean and set stale to true. Stale is true before bean merging. - 4, : will
GernericBeanDefinition
convertRootBeanDefinition
, if specifiedbeanName
A child Bean merges the attributes of its parent. If the current bean has a dependent bean, the dependent bean is recursively instantiated or thrown if it is interdependentBeanCreationException
The exception. - 5. If
Bean
The scope of issingleton
, creates an instance object of the singleton Bean. Here Spring calls an overloadedgetSingleton(String beanName, ObjectFactory<? > singletonFactory)
Method implements the Bean loading.
public Object getSingleton(String beanName, ObjectFactory
singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// Get the instance from the singleton pool
Object singletonObject = this.singletonObjects.get(beanName);
// If no instance exists, create a singleton bean instance
if (singletonObject == null) {
// The current singleton is being destroyed, throwing an exception
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!) ");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
/ / is created in the current beanName added to the singletonsCurrentlyInCreation,
/ / singletonsCurrentlyInCreation is a Set
// Indicates that these singleton beans are normally created and cannot be created again until they are completed
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// singletonFactory is a lambda expression passed in from the outside
Call createBean()
// Create a singleton bean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throwex; }}catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); }}throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
/ / will be removed from just is creating beanName singletonsCurrentlyInCreation
afterSingletonCreation(beanName);
}
// Add the created singleton bean to the singleton pool singletonObjects
// and the singleton registeredSingletons
// Clear level 2 and level 3 caches
if(newSingleton) { addSingleton(beanName, singletonObject); }}returnsingletonObject; }}Copy the code
- 6: if
Bean
The scope of isprototype
, the prototype pattern Bean instance object is created. Direct callcreateBean
Method, prototype mode, every timegetBean
Creates a new object instance. - 7: If the Bean is not scoped
singleton
和prototype
, fromthis.scopes.get(scopeName)
Get the scope and instantiate the Bean.
Type checking
Just look at it.
// Check that the desired type matches the type of the actual bean instance
if(requiredType ! =null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw newBeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); }}Copy the code
The data object
// The name of the prototype bean currently being created
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<>("Prototype beans currently in creation");
// The bean defines the object with the key beanName
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
// Merge RootBeanDefinition with key beanName
private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
// Store beanName that has been created or is being created
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
/ / the singleton pool
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// The singleton factory cache, Bean name to ObjectFactory, this reference information will be removed from the secondary cache once the final object is created (via objectFactory.getobject ())
private finalMap<String, ObjectFactory<? >> singletonFactories =new HashMap<>(16);
// Store a reference to the original Bean created early in the Bean creation process. Note that this is the original Bean, which is an object created using a factory method or constructor.
// Once the object is finally created, this reference information will be removed from the tertiary cache
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// The name of the bean currently excluded in the creation check
private final Set<String> inCreationCheckExclusions =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
// The name of the bean currently being created, indicating that the bean is being created normally and cannot be created again until it has been created
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
// Registered singleton beanName
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
Copy the code
The next article will start to read the source code of createBean.
- If you have any questions or errors in this article, please feel free to comment. If you find this article helpful, please like it and follow it.