第三章 spring-bean之DefaultListableBeanFactory(7)

本文深入探讨了Spring框架中DefaultListableBeanFactory的核心作用及其实现细节,包括allowBeanDefinitionOverriding配置项的功能、依赖比较器(dependencyComparator)的使用、resolvableDependencies注册机制等。

前言

DefaultListableBeanFactory是beanFactory体系里面最后一个子类,也是唯一的操作类,唯一的实现。DefaultListableBeanFactory继承了AbstractAutowireCapableBeanFactory,实现了ConfigurableListableBeanFactory接口。

解读变量

allowBeanDefinitionOverriding变量

allowBeanDefinitionOverriding是一个坑,DefaultListableBeanFactory重写了父类SimpleAliasRegistry的allowAliasOverriding方法。重写的allowAliasOverriding方法就是使用的allowBeanDefinitionOverriding。如果要修改allowBeanDefinitionOverriding变量,需要深入的考虑SimpleAliasRegistry的行为。

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.");
		}
	}
	......
			
}

解读

  1. 修改allowBeanDefinitionOverriding,注意SimpleAliasRegistry的行为
  2. allowBeanDefinitionOverriding的作用是是否允许一个name有多个BeanDefinition
dependencyComparator变量
private Comparator<Object> dependencyComparator;

解读

细节请看第二章 一节spring-core之comparator深入解读

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);
}

解读

resolvableDependencies用来保存spring中自己的bean。这样隔离系统bean与业务bean,好像spring,没有做得彻底。

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

保存BeanDefinition的实现类,

allBeanNamesByType属性 与 singletonBeanNamesByType变量
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;
	}

当getBeanNamesForType方法被调用的时候,会把结果缓存到allBeanNamesByType或singletonBeanNamesByType里面。getBeanNamesForType参数type对应class类型的所有beanName

beanDefinitionNames与manualSingletonNames变量
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)) {// beanDefinitionNames 存在的beanName,就不能在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保存所有BeanDefinition的名字,manualSingletonNames保存了所有singleton的BeanDefinitionName。注意beanDefinitionNames声明了 volatile

转载于:https://my.oschina.net/u/1261452/blog/1922670

<think>嗯,用户现在遇到了Spring Boot权限管理中RoleConverter自动注入失败的问题,具体错误是Noqualifying beanof type'com.kucun.Config.RoleConverter'available。我需要仔细分析可能的原因,并提供解决方案。首先,用户提到的RoleConverter类没有被正确注入。根据Spring的依赖注入机制,这可能是因为RoleConverter没有被Spring容器管理,也就是没有添加必要的注解,比如@Component或者@Service。检查用户之前的代码,发现RoleConverter类可能没有这些注解,导致Spring无法识别并创建Bean。然后,用户提供的代码中RoleConverter使用了@PostConstruct来初始化ROLE_MAP,但如果没有被Spring管理,这个初始化方法也不会被执行。所以,第一步要确保RoleConverter类上有@Component或其他Spring的注解,这样Spring才能扫描到它并将其作为Bean管理。另外,用户提到的spring-beans-5.2.15.RELEASE版本可能存在依赖冲突。需要检查项目的依赖,确保所有Spring相关的库版本一致,避免因为版本不兼容导致Bean无法创建。例如,spring-context和spring-test的版本是否一致,是否有其他依赖引入了不同版本的Spring组件。还有可能的问题包括包扫描路径不正确。如果RoleConverter所在的包不在Spring Boot的主应用类所在的包或其子包下,Spring可能无法扫描到这个类。这时候需要在主应用类上添加@ComponentScan注解,明确指定扫描的包路径。 另外,用户提到的引用[4]中,使用了ApplicationContextAware来手动获取Bean,这可能是一种替代方案,但最好还是通过正确的注解和配置来解决自动注入的问题。不过可以作为备选方案提供给用户。此外,用户之前的配置中RoleConverter被注入到CustomUserDetailsService中,如果RoleConverter的Bean没有正确创建,这里就会抛出No qualifyingbean的错误。需要确保所有依赖RoleConverter的地方都正确引用了已注册的Bean。 最后,建议用户检查Maven依赖,确认是否有冲突,使用mvn dependency:tree查看依赖树,排除重复或冲突的版本。同时,检查日志中的异常信息,确认是否有其他导致Bean创建失败的原因,比如初始化时的异常等。</think>### 问题解决方案:RoleConverter自动注入失败 #### 一、核心原因分析 1. **Bean未被容器管理**:`RoleConverter`类未添加Spring组件注解(如`@Component`) 2. **包扫描范围错误**:类不在`@SpringBootApplication`主类所在包或其子包下 3. **依赖版本冲突**:`spring-beans-5.2.15.RELEASE`与其他Spring组件版本不兼容[^2] #### 二、具体修复步骤 ##### 1. 添加组件注解 ```java @Component // 新增注解 public class RoleConverter { // 原有代码不变 } ``` 此时Spring容器会自动扫描并创建Bean,解决`No qualifying bean`错误[^4] ##### 2. 配置包扫描路径(可选) ```java @SpringBootApplication @ComponentScan({"com.kucun.Config", "com.kucun"}) // 显式指定扫描包 public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` ##### 3. 验证依赖树 ```xml <!-- 确保所有Spring依赖版本一致 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.15.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.2.15.RELEASE</version> </dependency> ``` 使用命令检查依赖冲突: ```shell mvn dependency:tree -Dverbose ``` #### 三、验证测试用例 ```java @SpringBootTest public class RoleConverterTest { @Autowired private RoleConverter roleConverter; // 注入测试 @Test public void testConvert() { List<GrantedAuthority> authorities = roleConverter.convert(1); Assert.assertEquals("ROLE_ADMIN", authorities.get(0).getAuthority()); } } ``` 测试通过则表明注入成功[^1] #### 四、数学表达优化(权限位运算) 当使用位掩码方式时,权限值计算遵循: $$ \text{权限值} = \sum_{k=0}^{n}2^{k} \quad (\text{k为权限位}) $$ 例如同时具有ADMIN(1)和MANAGER(4)权限时: $$ 1 + 4 = 5 \Rightarrow (101)_2 $$ #### 五、备选解决方案 若仍无法解决,可采用引用[4]的ApplicationContextAware方式: ```java @Component public class RoleConverter implements ApplicationContextAware { // 原有代码 + 新增以下方法 private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext ctx) { context = ctx; } public static RoleConverter getInstance() { return context.getBean(RoleConverter.class); } } ``` 调用时使用`RoleConverter.getInstance().convert(roleCode)` --- ### 关联问题分析 | 问题现象 | 可能原因 | 解决方案 | |---------|---------|---------| | 注入失败 | Bean未定义 | 检查组件注解 | | 空指针异常 | 依赖版本冲突 | 统一Spring版本至5.2.15.RELEASE[^2] | | 权限转换错误 | 映射表未初始化 | 确认@PostConstruct生效 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值