描述
Spring Bean定义的三种方式:
- 基于XML的配置
- 基于注解的配置,在类中加入如下注解通过包扫描加载注册bean:
@Component:当对组件的层次难以定位的时候使用这个注解
@Controller:表示控制层的组件
@Service:表示业务逻辑层的组件
@Repository:表示数据访问层的组件
- 基于Java类的配置:
- 使用@Configuration注解需要作为配置的类,表示该类将定义Bean的元数据
- 使用@Bean注解相应的方法,该方法名默认就是Bean的名称,该方法返回值就是Bean的对象。
下面跟踪源码查看spring基于Java类的配置定义bean的加载注册流程
Java类配置的模型
- @Configuration描述的类模型ConfigurationClass
final class ConfigurationClass {
/**
* 注解元数据
*/
private final AnnotationMetadata metadata;
/**
* 资源信息
*/
private final Resource resource;
/**
* bean定义的名称
*/
@Nullable
private String beanName;
/**
* import 注解导入的配置类(被@Configuration注解的类)集合
*/
private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);
/**
* 配置类下被@Bean注解的方法结合
*/
private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
/**
* 跳过的方法名集合
*/
final Set<String> skippedBeanMethods = new HashSet<>();
}
ConfigurationClass 类主要用于描述被@Configuration注解的配置类的信息,我们在spring中定义的配置类,会被spring首先解析成BeanDefinition,然后spring会根据此BeanDefinition创建配置类对应的ConfigurationClass
如下类,spring会生成对应的ConfigurationClass模型
@Configuration
@Import({ SessionRouteConfig.class })
@EnableConfigurationProperties({ ServiceInstanceProperties.class, SessionProperties.class })
public class GatewayConfiguration {
@Bean
@ConditionalOnMissingBean
SessionFilterPredicateFactory sessionFilterPredicateFactory() {
return new DefaultSessionFilterPredicateFactory();
}
}
- 配置类中被@Bean注解的方法模型BeanMethod
final class BeanMethod extends ConfigurationMethod {
public BeanMethod(MethodMetadata metadata, ConfigurationClass configurationClass) {
super(metadata, configurationClass);
}
@Override
public void validate(ProblemReporter problemReporter) {
if (getMetadata().isStatic()) {
// static @Bean methods have no constraints to validate -> return immediately
return;
}
if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
if (!getMetadata().isOverridable()) {
// instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
problemReporter.error(new NonOverridableMethodError());
}
}
}
}
BeanMethod 用于描述配置类下被@Bean修饰的方法的模型,spring会BeanMethod 模型创建方法返回类的BeanDefinition,并将其注册到bean定义注册中心,以达到bean定义的加载注册,如上例中sessionFilterPredicateFactory方法,spring会生成对应的BeanMethod 模型与之对应。
java配置定义bean加载解析入口
// 类 ConfigurationClassPostProcessor
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
/**
* 从注册表中的配置类派生进一步的bean定义。
* Derive further bean definitions from the configuration classes in the registry.
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
//处理配置类的bean定义
processConfigBeanDefinitions(registry);
}
/**
* Build and validate a configuration model based on the registry of
* {@link Configuration} classes.
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//存在配置类bean定义的集合,用于存储所有被@Configuration注解的类
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//获取bean定义注册中心的bean定义名称集合
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
//遍历名称根据名称在注册中心获取当前名称的BeanDefinition
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//校验当前bean定义是否为配置类
//判断当前的bean定义是否为存在精简或者完整的配置类标识,当存在此标识时标识已被处理过
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
//检测bean定义是否已经被处理
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//检测给定的bean定义是否是描述的配置类
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//将配置类的bean定义添加到configCandidates
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//配置类bean定义的集合为空时不做任何处理直接返回
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
//配置类bean定义的集合 排序
// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
//检测获取命名生成策略器
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
//创建配置类的解析器,解析每个@Configuration注解的类
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
//准备解析的bean定义集合
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
//处理完成的模型的集合
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//解析bean定义,生成ConfigurationClass模型
parser.parse(candidates);
//校验ConfigurationClass模型
parser.validate();
//获取解析到的ConfigurationClass模型集合
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
//当前处理的模型中移除已经处理的的模型
configClasses.removeAll(alreadyParsed);
//读取模型并根据内容创建bean定义
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//加载创建模型中的所有bean定义
this.reader.loadBeanDefinitions(configClasses);
//当前模型集合添加到已处理集合中
alreadyParsed.addAll(configClasses);
candidates.clear();
//判断注册中心中注册表是否存在新增数据,如果有新增数据,重新遍历获取新增数据解析
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
}
}
类 ConfigurationClassPostProcessor 为spring对@Configuration解析处理的后置处理器。
- ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,此接口是BeanFactoryPostProcessor的扩展接口,在BeanFactoryPostProcessor执行流程笔记中分析过,允许在正常的BeanFactoryPostProcessor执行检测开始之前注册更多的自定义bean。也就是说BeanDefinitionRegistryPostProcessor的方法postProcessBeanDefinitionRegistry可以在后置处理器执行前自定义注册更多的BeanDefinition
ConfigurationClassPostProcessor 的postProcessBeanDefinitionRegistry方法完成的功能如下:
- 遍历bean定义注册器中所有的bean定义查找配置bean定义(元数据中含有@Configuration注解的bean定义)
- 通过配置类解析器ConfigurationClassParser 根据配置bean定义创建配置模型ConfigurationClass和BeanMethod
//解析bean定义,生成ConfigurationClass模型
parser.parse(candidates);
//校验ConfigurationClass模型
parser.validate();
- 根据配置类模型转换器ConfigurationClassBeanDefinitionReader根据配置类模型创建配置类中的BeanDefinition并注册到BeanDefinition注册中心
//读取模型并根据内容创建bean定义
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//加载创建模型中的所有bean定义
this.reader.loadBeanDefinitions(configClasses);
配置类解析器ConfigurationClassParser
配置类解析器ConfigurationClassParser 根据配置类的BeanDefinition生成配置类模型数据ConfigurationClass与BeanMethod
解析主方法parse
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
for (BeanDefinitionHolder holder : configCandidates) {
//循环遍历配置类的bean定义,解析生成对应的ConfigurationClass模型
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
processDeferredImportSelectors();
}
此方法最终调用doProcessConfigurationClass方法对ConfigurationClass创建初始化
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// 递归处理配置类的成员嵌套类
processMemberClasses(configClass, sourceClass);
//处理配置类上的@PropertySource注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
}
}
//处理配置类上的@ComponentScan注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
//处理配置类上的@Import注解
processImports(configClass, sourceClass, getImports(sourceClass), true);
//处理配置类上的@ImportResource注解
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
//处理配置类里@Bean注解的方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
return null;
}
doProcessConfigurationClass 方法依次完成如下功能:
- 递归处理配置类的成员嵌套类
- 处理配置类上的@PropertySource注解
- 处理配置类上的@ComponentScan注解
- 处理配置类上的@Import注解
- 处理配置类上的@ImportResource注解
- 处理配置类里@Bean注解的方法
- 处理接口上的默认方法
- 处理配置类的父类,如果有的话
最后spring 通过ConfigurationClassParser类将一个配置类的bean定义,解析成完整的ConfigurationClass(配置数据模型)
配置类模型转换bean定义
ConfigurationClassBeanDefinitionReader 会根据配置类模型ConfigurationClass读取创建BeanDefinition,并将BeanDefinition注册到bean定义注册表中。
加载配置中的BeanDefinition入口loadBeanDefinitions方法:
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
//遍历ConfigurationClass依次加载注册配置的bean定义
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
loadBeanDefinitions 通过调用loadBeanDefinitionsForConfigurationClass加载注册bean定义
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (configClass.isImported()) {
//将ConfigurationClass本身的bean定义注册到注册中心
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// 遍历BeanMethod
//根据BeanMethod 创建bean定义,此方法根据配置类中被@Bean注解的方法生成bean定义
//将生成的bean定义注册到注册中心
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//加载来自ImportedResources的bean定义并注册
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//加载来自Import的bean定义并注册
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
loadBeanDefinitionsForConfigurationClass 根据ConfigurationClass 创建其配置的bean定义,并将其注册到bean定义注册中心
接下来整体梳理下@Configuration配置的bean定义加载解析流程:
- 在spring完成基于注解配置bean定义的扫描注册后,通过后置处理器,获取到注册表中所有的bean定义。
- 遍历bean定义生成含有@Configuration注解的bean定义的集合。
- 根据配置类bean定义集合通过配置类解析器ConfigurationClassParser生成ConfigurationClass集合。
- 根据ConfigurationClass集合通过ConfigurationClassBeanDefinitionReader类加载注册配置里的bean定义。