栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Springboot Objectprovider性质小探

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Springboot Objectprovider性质小探

目录

引例:HTTPMessageConverters与Objectprovider

试用Objectprovider

ObjectProvider与DependOn注解

源码分析


Springboot版本:2.5.1

引例:HTTPMessageConverters与Objectprovider

HTTPMessageConverter在RestController中扮演重要角色,具体来讲,配合相关注解,其能够将输入、输出的Java对象转化为Json序列串,当然,也能够依据不同的Converter将Java对象转换为其他消息形式例如XML。

不少教程曾有提及使用FastJson代替原有序列化工具类的配置方法,例如:

@Bean
    FastJsonHttpMessageConverter fastJsonHttpMessageConverte(ObjectProvider books){
        final FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setDateFormat("yyyy-MM-dd");
        converter.setFastJsonConfig(fastJsonConfig);
        return converter;
    }

但是,这些教程均没有交代如此配置能够生效的原因。

笔者的研究思路是寻找网上关于HTTPMessageConverter的源码分析贴,结果发现FastJson配置类之所以能被正确加载,与“Objectprovider”相关:

方法org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration中,ObjectProvider作为Bean实例messageConverters的构造函数的参数被使用,且没有用到autowired注解:

    @Bean
    @ConditionalOnMissingBean
    public HttpMessageConverters messageConverters(ObjectProvider> converters) {
        return new HttpMessageConverters((Collection)converters.orderedStream().collect(Collectors.toList()));
    }

//相应的构造方法:

    public HttpMessageConverters(Collection> additionalConverters)             
    {
        this(true, additionalConverters);
    }

Spring官方文档 里对于@Autowired注解可省略的场合,是这么说的:

If a bean has more than one constructor, you’ll need to mark the one you want Spring to use with @Autowired

而上述代码中Bean messageConverters只有一个构造方法,因此@Autowired并非必需。

但是,什么时候一个Bean需要多个构造方法,又如何在创建Bean时,调用对应地构造方法呢?这个问题有待另作讨论。


通过Debug,确认此处的ObjectProvider加载了包括FastJson在内的自定义messageConverters Bean。此外,这里我们发现ObjectProvider能够把满足条件的多个Bean实例一并提供出来。

试用Objectprovider

ObjectProvider与DependOn注解

在上文的Debug过程中我们同时发现ObjectProvider载入Bean的时点位于单例Bean messageConverters被getBean载入时,不难想到一个问题:如果ObjectProvider载入了一个未被初始化完成的Bean,岂不就非法访问了吗?

为了模拟这一情况,我对实验代码进行少许修改,修改了FastJson配置类的构造参数、使用了DependsOn注解。使得Bean实体book2的加载依赖于fastJson加载,也就是说,其会晚于fastJson类加载:

@DependsOn("converter")
    @Bean
    Book book2(){
        Book ret =  new Book();
        ret.setId(222);
        ret.setName("Book2");
        ret.setAuthor("fff");
        return ret;
    }


    @Bean(name="converter")
    FastJsonHttpMessageConverter fastJsonHttpMessageConverte(ObjectProvider books){
        final FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setDateFormat("yyyy-MM-dd");
        converter.setFastJsonConfig(fastJsonConfig);
        return converter;
    }

使用相同的Debug方法,发现抛出了一个循环依赖异常,凭直觉来看,ObjectProvider应该是在这个时点进行了book2的实例化操作。在下一部分中我将展示相关源码以证明猜测的正确性。

源码分析

继承ObjectProvider接口的非抽象类只有DependencyObjectProvider一个,下面开始分析与上述性质相关的逻辑。

org.springframework.beans.factory.support.DefaultListableBeanFactory.DependencyObjectProvider#orderedStream

public Stream orderedStream() {
            return this.resolveStream(true);
        } 

org.springframework.beans.factory.support.DefaultListableBeanFactory.DependencyObjectProvider#resolveStream

private Stream resolveStream(boolean ordered) {
            DependencyDescriptor descriptorToUse = new DefaultListableBeanFactory.StreamDependencyDescriptor(this.descriptor, ordered);

            // 获取指定类型的Bean
            Object result = DefaultListableBeanFactory.this.doResolveDependency(descriptorToUse, this.beanName, (Set)null, (TypeConverter)null);

            return result instanceof Stream ? (Stream)result : Stream.of(result);
        } 

org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency

主要关注这两组语句:

String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this, requiredType, true, descriptor.isEager());
String[] var12 = candidateNames;
int var14 = candidateNames.length;
for(int var16 = 0; var16 < var14; ++var16) {
            String candidate = var12[var16];
            if (!this.isSelfReference(beanName, candidate) && this.isAutowireCandidate(candidate, descriptor)) {
                this.addCandidateEntry(result, candidate, descriptor, requiredType);
            }
        }

org.springframework.beans.factory.support.DefaultListableBeanFactory#addCandidateEntry

主要关注该函数的第3个if-else分支:

 beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
 candidates.put(candidateName, beanInstance instanceof NullBean ? null : beanInstance);

org.springframework.beans.factory.config.DependencyDescriptor#resolveCandidate 

public Object resolveCandidate(String beanName, Class requiredType, BeanFactory beanFactory) throws BeansException {
        return beanFactory.getBean(beanName);
    }

对于单例类型的Bean,resolveCandidate函数会调用getBean指令以获取相应的Bean,getBean中的相关逻辑则会保证该Bean被实例化。

结论:DependencyObjectProvider在获取满足条件的单例Bean过程中,会对其进行实例化操作。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号