Chapter 3: DefaultListableBeanFactory of spring bean (7)

Keywords: Spring

Preface

DefaultListableBeanFactory is the last subclass of beanFactory system, the only operation class and the only implementation. DefaultListableBeanFactory inherits AbstractAutowireCapableBeanFactory and implements the ConfigurableListableBeanFactory interface.

Interpreting variables

allowBeanDefinitionOverriding variable

allowBeanDefinitionOverriding is a pit. DefaultListableBeanFactory overrides the allowAliasOverriding method of the parent class simpleliasregistry. The overridden allowAliasOverriding method is the allowBeanDefinitionOverriding used. If you want to modify the allowBeanDefinitionOverriding variable, you need to consider the behavior of simpleliasregistry deeply.

private boolean allowBeanDefinitionOverriding = true;
public boolean isAllowBeanDefinitionOverriding() {
		return this.allowBeanDefinitionOverriding;
}
protected boolean allowAliasOverriding() {
	return isAllowBeanDefinitionOverriding();
}

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
	oldBeanDefinition = this.beanDefinitionMap.get(beanName);
	if (oldBeanDefinition != null) {
		if (!isAllowBeanDefinitionOverriding()) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
												   "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
												   "': There is already [" + oldBeanDefinition + "] bound.");
		}
	}
	......
			
}

unscramble

  1. Modify allowBeanDefinitionOverriding, and note the behavior of simpleliasregistry
  2. The role of allowBeanDefinitionOverriding is to allow a name to have multiple beandefinitions

dependencyComparator variable

private Comparator<Object> dependencyComparator;

unscramble

See details. Chapter 2 Section 1 in depth interpretation of the comparator of spring core

resolvableDependencies

private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<Class<?>, Object>(16);


public void registerResolvableDependency(Class<?> dependencyType, Object autowiredValue) {
		Assert.notNull(dependencyType, "Dependency type must not be null");
		if (autowiredValue != null) {
			if (!(autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue))) {
				throw new IllegalArgumentException("Value [" + autowiredValue +"] does not implement specified dependency type [" + dependencyType.getName() + "]");
			}
			this.resolvableDependencies.put(dependencyType, autowiredValue);
		}
}

AbstractApplicationContext

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);
}

unscramble

Resolvable dependencies are used to hold your own beans in spring. In this way, system beans and business beans are isolated, like spring, which is not done thoroughly.

beanDefinitionMap property

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);

Save the implementation class of BeanDefinition,

allBeanNamesByType property and singletonBeanNamesByType variable

private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);

private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64);

public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
		if (!isConfigurationFrozen() || type == null || !allowEagerInit) {
			return doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, allowEagerInit);
		}
		Map<Class<?>, String[]> cache =
				(includeNonSingletons ? this.allBeanNamesByType : this.singletonBeanNamesByType);
		String[] resolvedBeanNames = cache.get(type);
		if (resolvedBeanNames != null) {
			return resolvedBeanNames;
		}
		resolvedBeanNames = doGetBeanNamesForType(ResolvableType.forRawClass(type), includeNonSingletons, true);
		if (ClassUtils.isCacheSafe(type, getBeanClassLoader())) {
			cache.put(type, resolvedBeanNames);
		}
		return resolvedBeanNames;
	}

When the getBeanNamesForType method is called, the result will be cached in allBeanNamesByType or singletonBeanNamesByType. getBeanNamesForType parameter type corresponds to all beannames of class type

beanDefinitionNames and manualSingletonNames variables

private volatile List<String> beanDefinitionNames = new ArrayList<String>(256);

private volatile Set<String> manualSingletonNames = new LinkedHashSet<String>(16);

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {

		if (hasBeanCreationStarted()) {
			// Cannot modify startup-time collection elements anymore (for stable iteration)
			synchronized (this.beanDefinitionMap) {
				this.beanDefinitionMap.put(beanName, beanDefinition);
				List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
				updatedDefinitions.addAll(this.beanDefinitionNames);
				updatedDefinitions.add(beanName);
				this.beanDefinitionNames = updatedDefinitions;
				if (this.manualSingletonNames.contains(beanName)) {// beanName with beanDefinitionNames cannot exist in manualSingletonNames
					Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
					updatedSingletons.remove(beanName);
					this.manualSingletonNames = updatedSingletons;
				}
			}
		}
		
}

public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
	super.registerSingleton(beanName, singletonObject);

	if (hasBeanCreationStarted()) {
		// Cannot modify startup-time collection elements anymore (for stable iteration)
		synchronized (this.beanDefinitionMap) {
			if (!this.beanDefinitionMap.containsKey(beanName)) {
				Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames.size() + 1);
				updatedSingletons.addAll(this.manualSingletonNames);
				updatedSingletons.add(beanName);
				this.manualSingletonNames = updatedSingletons;
			}
		}
	}
	else {
		// Still in startup registration phase
		if (!this.beanDefinitionMap.containsKey(beanName)) {
			this.manualSingletonNames.add(beanName);
		}
	}

	clearByTypeCache();
}

beanDefinitionNames saves the names of all beandefinitions, and manualSingletonNames saves the beanDefinitionNames of all singletons. Notice that beanDefinitionNames declare volatile

Posted by anon_amos on Thu, 09 Jan 2020 11:00:04 -0800