BeanDefinitionRegistry
BeanDefinition registered interface in the Spring, the realization of common DefaultListableBeanFactory and GenericApplicationContext. Take a look at its interface listing:
public interface BeanDefinitionRegistry extends AliasRegistry {
// Register a BeanDefinition instance in the registry
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
// Remove the BeanDefinition with the BeanName from the registry
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// Get BeanDefinition from the registry via beanName
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// Check whether the BeanDefinition of the beanName is currently registered
boolean containsBeanDefinition(String beanName);
// Get the names of all currently registered BeanDefinitions
String[] getBeanDefinitionNames();
// Get the number of beanDefinitions currently registered
int getBeanDefinitionCount(a);
// Whether beanName is occupied
boolean isBeanNameInUse(String beanName);
}
Copy the code
UML
SimpleBeanDefinitionRegistry
BeanDefinitionRegistry is a simple implementation that provides registration capabilities, but does not provide factory-level capabilities. It can be used as a simple example for test use.DefaultListableBeanFactory
:Spring’s first factory class that can run independently, not only has container registration, but also is a full-featured Bean factory.GenericApplicationContext
: The Spring generic context requires more custom implementations.
DefaultListableBeanFactory registration function
Future review
Mentioned above, BeanDefinitionReader after call BeanDefinitionHolder bdHolder = delegate. ParseBeanDefinitionElement (ele); After, can call BeanDefinitionReaderUtils. RegisterBeanDefinition (bdHolder, getReaderContext (.) getRegistry ()); Method to register the BeanDefinition.
DefaultListableBeanFactory will register after BeanDefinition into a ConcurrentHashMap stored in the Map, the Key for beanName, the Value of BeanDefinition.
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
Copy the code
Entry to registration
There is introduced into two parameters, bdHolder as BeanDefinition wrapper, getReaderContext () getRegistry () for DefaultListableBeanFactory. Why is DefaultListableBeanFactory? Because Spring passes the container itself as a parameter when it instantiates XmlBeanDefinitionReader, this can also be called a delegate in design mode.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
Copy the code
DefaultListableBeanFactory multiple functions
DefaultListableBeanFactory itself is not only used as a factory, but also can be used as a registry, resource loader.
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
/ / here are the embodiment of entrust DefaultListableBeanFactory as structure parameters was introduced into the XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
Copy the code
Into the constructor, found DefaultListableBeanFactory here has served for the function of the registry.
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
Copy the code
Register BeanDefinition- Register name and aliases
public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
// Inject the name of the BeanDefinition and BeanDefinition itself into the container
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
// If the BeanDefinition has an alias, then register the alias
String[] aliases = definitionHolder.getAliases();
if(aliases ! =null) {
for(String alias : aliases) { registry.registerAlias(beanName, alias); }}}Copy the code
DefaultListableBeanFactory#registerBeanDefinition
Note the already reached the DefaultLististableBeanFactory registerBeanDefinition, the registry point to an DefaultLististableBeanFactory above. Here’s the main logic
-
- Check whether it is an instance of AbstractBeanDefinition. If so, check whether the BeanDefinition has a declaration method that requires overrides. If so, create a proxy class for the proxy.
-
- from
beanDefinitionMap
To try to get the BeanDefinition of the beanName.
- from
-
- if
beanDefinitionMap
Check if BeanDefinition is allowed to override. If allowed, update operations are performed with PUT.
- if
-
- If from
beanDefinitionMap
If not, verify that it is a new BeanDefinition. Check to see if the bean in the factory is in the created phase. If so, verify that it is a way to dynamically register the bean. usesynchronized
rightbeanDefinitionMap
Lock it up and let it goput
Operation, and then update in turnbeanDefinitionNames
And from themanualSingletonNames
(Manually register the list of names of singletons, in order of registration.) Remove the beanName
- If from
-
- If the BeanDefinition already exists and is in the singleton cache, proceed
resetBeanDefinition
This is a recursive process that clears the merged BeanDefinition cache, removes the BeanName from the singleton cache, and tells the processor to reset.
- If the BeanDefinition already exists and is in the singleton cache, proceed
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
// Check whether this beanDefinition is an instance of AbstractBeanDefinition
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
// Check whether the look up and replace methods exist and their arguments are valid. If so, proceed with the BeanDefinition
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex); }}// Get the BeanDefinition instance from the registry
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if(existingDefinition ! =null) {
// Whether to allow BeanDefinition overridden, container configuration
if(! isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]"); }}else if(! beanDefinition.equals(existingDefinition)) {if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]"); }}else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]"); }}// Place beanName as the key and BeanDefinition as the value in the container map
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
// Whether to start creating an instance of the bean. If the instance already exists, this time it is dynamic
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
// Lock the registry
synchronized (this.beanDefinitionMap) {
/ / update the beanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
// Create a list with length beanDefinitionNames+1
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
// Store beanDefinitionName first
updatedDefinitions.addAll(this.beanDefinitionNames);
// Store the incremental beanName sequentially
updatedDefinitions.add(beanName);
// Update the entire BeanDefinitionNames
this.beanDefinitionNames = updatedDefinitions;
/ / remove the BeanName, from the single example BeanName list if this contains the BeanName manualSingletonNames, perform the remove operationremoveManualSingletonName(beanName); }}else {
// Still in startup registration phase
// Start phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
// Clear the beanName list frozen during registration, a volatile String array, and Spring memory optimization operations
this.frozenBeanDefinitionNames = null;
}
// Check whether the BeanDefinition exists and exists in IOC
if(existingDefinition ! =null || containsSingleton(beanName)) {
// Reset the registered BeanDefinition cache
// Includes the parent class of BeanDefinition and the merged BeanDefinition cache, mergeBeanDefinition
// Spring merges Bean properties with parent properties
resetBeanDefinition(beanName);
}
else if(isConfigurationFrozen()) { clearByTypeCache(); }}Copy the code
DefaultListableBeanFactory#resetBeanDefinition
protected void resetBeanDefinition(String beanName) {
// Remove the merged bean definition for the given bean, if already created.
// If this beanName has been merged,remove the merged beanDefinition
clearMergedBeanDefinition(beanName);
// Remove corresponding bean from singleton cache, if any. Shouldn't usually
// be necessary, rather just meant for overriding a context's default beans
// (e.g. the default StaticMessageSource in a StaticApplicationContext).
// Remove the beanName from the singleton cache
destroySingleton(beanName);
// Notify all post-processors that the specified bean definition has been reset.
/ / notify MergedBeanDefinitionPostProcessor, this special beanDefinition has been reset
for (BeanPostProcessor processor : getBeanPostProcessors()) {
if (processor instanceofMergedBeanDefinitionPostProcessor) { ((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName); }}// Reset all bean definitions that have the given bean as parent (recursively).
// Find the bd in the container that is different from the current beanName and check whether paretName is the same as the current beanName.
// If the parent bean is cleared, the child bean should also be reset
for (String bdName : this.beanDefinitionNames) {
if(! beanName.equals(bdName)) { BeanDefinition bd =this.beanDefinitionMap.get(bdName);
// Ensure bd is non-null due to potential concurrent modification
// of the beanDefinitionMap.
if(bd ! =null && beanName.equals(bd.getParentName())) {
If the bean has child beans, continue to clean upresetBeanDefinition(bdName); }}}}Copy the code
The flow chart
conclusion
- The registration of BeanDefinition is shown as the following
DefaultListableBeanFactory
In thebeanDefinitionMap
Add a BeanDefinition to. - BeanDefinitionReader delegates the registration function to
DefaultListableBeanFactory
Register. The registry performs construction injection at initialization. - During registration, Spring verifies that BeanDefinition overwriting is allowed.
- Spring supports dynamic registration of BeanDefinitions after factory Bean instances are created.