千家信息网

如何解析SpringFramework的@Configuration/@Import注解

发表于:2025-02-07 作者:千家信息网编辑
千家信息网最后更新 2025年02月07日,这篇文章主要介绍"如何解析SpringFramework的@Configuration/@Import注解",在日常操作中,相信很多人在如何解析SpringFramework的@Configurati
千家信息网最后更新 2025年02月07日如何解析SpringFramework的@Configuration/@Import注解

这篇文章主要介绍"如何解析SpringFramework的@Configuration/@Import注解",在日常操作中,相信很多人在如何解析SpringFramework的@Configuration/@Import注解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"如何解析SpringFramework的@Configuration/@Import注解"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

Spring版本是5.0.9.release,Springboot版本是2.0.3.release

Springboot中,Servlet web应用,使用的是AnnotationConfigServletWebServerApplicationContext,它的构造方法中实例化了AnnotatedBeanDefinitionReader,如下List-1,调用了AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry),如List-2所示:

List-1

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");    Assert.notNull(environment, "Environment must not be null");    this.registry = registry;    this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}

List-2

public static Set registerAnnotationConfigProcessors(        BeanDefinitionRegistry registry, @Nullable Object source) {    ...    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {        RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);        def.setSource(source);        beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));    }    ...

如List-2所示,ConfigurationClassPostProcessor转换为BeanDefinition,注册到registry中。ConfigurationClassPostProcessor实现了BeanFacotryPostProcessor接口,如果熟悉SpringIOC,应该知道这个的作用。

图1

AnnotationConfigServletWebServerApplicationContext继承了AbstractApplicationContext,AbstractApplicationContext的refresh()如下List-3所示,refresh()中调用了this.invokeBeanFactoryPostProcessors(beanFactory),接着调用了PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors()),从BeanFactory方法中获取所有BeanFactoryPostProcessor,之后调用BeanFactoryPostProcessor的postProcessBeanFactory()。

List-3

public void refresh() throws BeansException, IllegalStateException {    synchronized(this.startupShutdownMonitor) {        this.prepareRefresh();        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();        this.prepareBeanFactory(beanFactory);        try {            this.postProcessBeanFactory(beanFactory);            this.invokeBeanFactoryPostProcessors(beanFactory);            this.registerBeanPostProcessors(beanFactory);            this.initMessageSource();            this.initApplicationEventMulticaster();            this.onRefresh();            this.registerListeners();            this.finishBeanFactoryInitialization(beanFactory);            this.finishRefresh();        } catch (BeansException var9) {            if (this.logger.isWarnEnabled()) {                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);            }            this.destroyBeans();            this.cancelRefresh(var9);            throw var9;        } finally {            this.resetCommonCaches();        }    }}

回到ConfigurationClassPostProcessor,看它的postProcessBeanFactory(),调用了processConfigBeanDefinitions(),如下List-4,代码很多,不过看关键部分就好了,1处的ConfigurationClassUtils.checkConfigurationClassCandidate要重点看,这个方法中判断类上是否有Configuration/ComponentScan/Import/ImportResource注解,如果有这些注解,那么会加入到configCandidates中,循环处理configCandidates,交给ConfigurationClassParser.pase()进行解析。

List-4

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {    List configCandidates = new ArrayList<>();    String[] candidateNames = registry.getBeanDefinitionNames();    for (String beanName : candidateNames) {        BeanDefinition beanDef = registry.getBeanDefinition(beanName);        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||                ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {            if (logger.isDebugEnabled()) {                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);            }        }        //1        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));        }    }    // Return immediately if no @Configuration classes were found    if (configCandidates.isEmpty()) {        return;    }    // 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();    }    // Parse each @Configuration class    ConfigurationClassParser parser = new ConfigurationClassParser(            this.metadataReaderFactory, this.problemReporter, this.environment,            this.resourceLoader, this.componentScanBeanNameGenerator, registry);    Set candidates = new LinkedHashSet<>(configCandidates);    Set alreadyParsed = new HashSet<>(configCandidates.size());    do {        parser.parse(candidates);        parser.validate();        Set configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());        configClasses.removeAll(alreadyParsed);        // 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());        }        this.reader.loadBeanDefinitions(configClasses);        alreadyParsed.addAll(configClasses);        candidates.clear();        if (registry.getBeanDefinitionCount() > candidateNames.length) {            String[] newCandidateNames = registry.getBeanDefinitionNames();            Set oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));            Set 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());    // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());    }    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {        // Clear cache in externally provided MetadataReaderFactory; this is a no-op        // for a shared cache since it'll be cleared by the ApplicationContext.        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();    }}

自动装配中EnableXX注解上的Import引入的Selector的处理就是在这里处理的,有趣的是Selector返回的String[]中的值需要是类的完全路径累名,这是因为使用Class.forName()将String类型的beanName转换为对应的Class类型。

到此,关于"如何解析SpringFramework的@Configuration/@Import注解"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

注解 方法 学习 处理 更多 版本 类型 帮助 实用 有趣 接下来 代码 作用 关键 实例 就是 接口 文章 理论 知识 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 与时间服务器同步时出错 华为手机设置代理服务器 软件开发模拟游戏 网络技术转到本科后学什么专业 魔兽国服服务器人口 小米激光电视访问服务器失败 上海诚信网络技术咨询联系人 数据库面试题库 数据库一个中文字的长度 网络安全防控体系建设 网络安全接下来往哪个方向走 迁安媒体网络技术服务至上 大连豪森软件开发 中国网络安全法四十七条 易当网络安全海报 无法无服务器建立安全的连接 读心神探表情包 软件开发 无线网卡和服务器网卡差别 东城区定制软件开发指导 2021网络安全世界杯 做网页必须用买服务器吗 h3c虚拟服务器设置 无锡工程网络技术标准 网络安全是什么的安全 东软生成器连接不上数据库 校园网络安全app管理 文献被知名数据库收录情况怎么查 vbasql查询数据库时间 亿付云服务器是否合法的 突然断电电视连接不上服务器
0