zoukankan      html  css  js  c++  java
  • Spring的BeanFactory是什么?

    什么是BeanFactory?

    提到Spring,总是让人第一时间想起IOC容器,而IOC容器的顶层核心接口就是我们的BeanFactory,如果能够理解BeanFactory的体系结构想必能让我们对Spring整体脉络有更加清晰的认知,所以,本文的探究方向主要为以下几点:

    • BeanFactory的体系结构是怎样的?
    • Bean的元信息从何而来?
    • BeanFactory生产Bean的过程是怎样的?

    BeanFactory的体系结构

    我们先来看看有哪些子类实现了它吧

    在这里插入图片描述
    其中ApplicationContext这一块已在上篇文章有详细说明,而DefaultListableBeanFactory这个底层实现类便理所当然的成为了我们此次探究的出发点,为了让我们有个更好的观感,以下是纯粹的BeanFactoryUML图:

    在这里插入图片描述
    我们可以看到DefaultListableBeanFactory实现的接口有:

    • SingletonBeanRegistry: 定义了对单例缓存池相关的操作,如将bean注册到单例缓存池中
    • ConfigurableBeanFactory: 可配置的BeanFactory,定义了各种各样的配置能力,如bean的作用域,bean的classLoader,添加bean的后置处理器,设置bean的创建状态,销毁bean等等
    • AutowireCapableBeanFactory: 能进行自动装配的BeanFactory,这可能是我们最为熟悉的BeanFactory,定义了自动装配的类型(byName/byType),createBean, autowireBean, 自动装配属性, populateBean, initializeBean, 对于与bean生命周期相关的方法都将在这里体现
    • ListableBeanFactory: 对BeanFactory的增强,定义了一系列根据beanType获取bean或者beanName的方法
    • ConfigurableListableBeanFactory: 对ConfigurableBeanFactory的增强,定义了忽略bean的类型、缓存bean定义、预实例化单例bean等方法
    • BeanDefinitionRegistry: bean定义注册器,定义了与bean定义相关的方法

    如果说以上的接口体现了DefaultListableBeanFactory具备的功能,那么它所继承的一系列类就是这些功能的实现:

    • DefaultSingletonBeanRegistry: 单例bean注册器,定义了三级缓存,其实就是三个Map属性
    • FactoryBeanRegistrySupport: 提供对FactoryBean的支持
    • AbstractBeanFactory: 实现了一系列操作IOC容器的功能,但最终的createBean依旧交由子类AbstractAutowireCapableBeanFactory完成
    • AbstractAutowireCapableBeanFactory: 实现了创建bean的功能,所有与创建bean的相关的功能都在这里
    • DefaultListableBeanFactory: 在以上父类的功能基础上实现了ConfigurableBeanFactoryBeanDefinitionRegistry接口,定义了一些存放Bean定义相关信息的Map

    看到这里,想必对DefaultListableBeanFactory已经有一个大致的了解了,那么问题来啦,我们应该怎么从容器中获取一个bean呢?是不是只要通过BeanDefinitionRegistry注册一个bean定义,再通过AutowireCapableBeanFactory去createBean就完成了呢?就像下面这样:

    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    RootBeanDefinition beanDefinition = new RootBeanDefinition(Wheel.class);
    beanFactory.registerBeanDefinition("wheel",beanDefinition);
    beanFactory.getBean("wheel", Wheel.class);
    

    Bean的元信息从何而来?

    我们现在已经知道DefaultListableBeanFactory的大致功能了,我们发现当我们想要创建一个Bean的时候,总是离不开一个名词:Bean定义,那么这个Bean定义究竟是什么呢?

    BeanDefinition其实是一个接口,并不是一个具体的类,我们也可以看一下它的UML图:

    在这里插入图片描述
    可以发现这里使用了模板方法的设计模式扩展了许多的子类,其中我们最常用的为RootBeanDefinition,它主要包含的属性如下:
    在这里插入图片描述

    我们向容器中注册的Bean定义的信息大概就是如此,当BeanFactory生产Bean时,便可以通过beanClass清楚的知道Bean的类是什么,作用域是怎样,是否懒加载,init方法是什么等等等等

    咦,如果一个最简单的bean,好像可以直接通过反射就搞定了耶~

    具体结构已经清楚了,那我们来看一下注册过程吧

    先从Demo看起

    public static void main(String[] args) {
        //创建一个DefaultListableBeanFactory实例
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //创建一个BeanDefinition
        RootBeanDefinition beanDefinition = new RootBeanDefinition(Wheel.class);
        //将BeanDefinition注册到容器中
        beanFactory.registerBeanDefinition("wheel",beanDefinition);
    }
    
    public static class Wheel {
    }
    

    创建BeanDefinition

    public RootBeanDefinition(@Nullable Class<?> beanClass) {
        //初始化父类
        super();
        //将beanClass赋值给this.BeanClass
        setBeanClass(beanClass);
    }
    

    初始化父类

    //将其中一部分属性赋予默认值
    autowireCandidate = true;
    primary = false;
    
    protected AbstractBeanDefinition() {
        this(null, null);
    }
    protected AbstractBeanDefinition(@Nullable ConstructorArgumentValues cargs, @Nullable MutablePropertyValues pvs) {
        this.constructorArgumentValues = cargs;
        this.propertyValues = pvs;
    }
    

    将BeanDefinition注册到容器中

    //除去校验逻辑,注册时只做了这两步操作
    this.beanDefinitionMap.put(beanName, beanDefinition);
    this.beanDefinitionNames.add(beanName);
    

    看到这里,大家伙可能会充满疑问?what? 就这样?没有填充属性的步骤吗?嘿嘿,BeanFactory是一个纯粹的工厂,只负责生产Bean,是没有装配(设计)BeanDefinition的功能的,专业的事还是交给专业的人做,设计的事情还是交由ApplicationContext完成的。

    那在ApplicationContext中是怎么完成一个BeanDefinition的呢?还记得预启动将配置类注册到容器中时有这样一段代码吗?以下代码为AnnotatedBeanDefinitionReader#doRegisterBean中的摘要部分:

    <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
                            @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
    	//.......代码
        //处理普通的bean定义注解,@Lazy @Primary @DependsOn @Role @Description
        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
        //......代码
       
    } 
    

    而非配置的Bean是通过在预启动时注册的配置类后置处理器ConfigurationClassPostProcessor#processConfigBeanDefinitions中完成的,以下代码为ClassPathBeanDefinitionScanner#doScan中的摘要部分,详细调用链将在后面的文章进行说明

    //传入我们配置类的包路径
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    		for (String basePackage : basePackages) {
                //寻找到所有标识了@Component注解的BeanDefinition
    			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    			for (BeanDefinition candidate : candidates) {
    				//....省略代码
    				if (candidate instanceof AbstractBeanDefinition) {
                        //处理BeanDefinition
    					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    				}
    				if (candidate instanceof AnnotatedBeanDefinition) {
     //处理普通的bean定义注解,@Lazy @Primary @DependsOn @Role @Description
                        AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
    				}
                    //...省略代码
                    //将BeanDefinition注册到容器中
                    registerBeanDefinition(definitionHolder, this.registry);
                }
    	}
    

    处理BeanDefinition

    protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
    	//设置默认值
        beanDefinition.applyDefaults(this.beanDefinitionDefaults);
        //这里默认为空
        if (this.autowireCandidatePatterns != null) {
            beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
        }
    }
    

    设置默认值

    public void applyDefaults(BeanDefinitionDefaults defaults) {
        //默认为null
        Boolean lazyInit = defaults.getLazyInit();
        if (lazyInit != null) {
            setLazyInit(lazyInit);
        }
        //默认为0
        setAutowireMode(defaults.getAutowireMode());
        //默认为0
        setDependencyCheck(defaults.getDependencyCheck());
        //默认为null
        setInitMethodName(defaults.getInitMethodName());
        setEnforceInitMethod(false);
        //默认为null
        setDestroyMethodName(defaults.getDestroyMethodName());
        setEnforceDestroyMethod(false);
    }
    

    处理普通的bean定义注解

    public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
        processCommonDefinitionAnnotations(abd, abd.getMetadata());
    }
    
    static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
        	//从元数据中取出该注解的属性列表,不为空说明有标识该注解
    		AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
    		if (lazy != null) {
    			abd.setLazyInit(lazy.getBoolean("value"));
    		}
    		else if (abd.getMetadata() != metadata) {
    			lazy = attributesFor(abd.getMetadata(), Lazy.class);
    			if (lazy != null) {
    				abd.setLazyInit(lazy.getBoolean("value"));
    			}
    		}
    		//判断元数据中是否有该注解
    		if (metadata.isAnnotated(Primary.class.getName())) {
    			abd.setPrimary(true);
    		}
    		AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
    		if (dependsOn != null) {
    			abd.setDependsOn(dependsOn.getStringArray("value"));
    		}
    		AnnotationAttributes role = attributesFor(metadata, Role.class);
    		if (role != null) {
    			abd.setRole(role.getNumber("value").intValue());
    		}
    		AnnotationAttributes description = attributesFor(metadata, Description.class);
    		if (description != null) {
    			abd.setDescription(description.getString("value"));
    		}
    	}
    

    attributesFor(metadata, Lazy.class)

    static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, Class<?> annotationClass) {
        return attributesFor(metadata, annotationClass.getName());
    }
    static AnnotationAttributes attributesFor(AnnotatedTypeMetadata metadata, String annotationClassName) {
        //metadata为beanClass的注解元数据,存放了该类所配置的所有注解
        //annotationClassName为需要寻找的注解名称
        return AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(annotationClassName, false));
    }
    default Map<String, Object> getAnnotationAttributes(String annotationName,
                                                        boolean classValuesAsString) {
        //遍历元数据中的所有注解
        MergedAnnotation<Annotation> annotation = getAnnotations().get(annotationName,
                                                                       null, MergedAnnotationSelectors.firstDirectlyDeclared());
        //不存在则返回null,否则返回一个map
        if (!annotation.isPresent()) {
            return null;
        }
        return annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, true));
    }
    

    以上为扫描@Component注解类进行解析元数据填充属性的逻辑,在配置类中以@Bean方式注册的BeanDefinition填充属性过程在ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(configClasses)

    BeanFactory生产Bean的过程是怎样的?

    现在,我们已经知道了一个BeanDefinition的具体结构以及是如何产生并注册到BeanFactory的,那么BeanFactory又是如何使用它生产Bean的呢?以下附上createBean的粗略流程图,具体细节将放在IOC容器启动流程中详细说明

    在这里插入图片描述

    那么关于BeanFactory的相关内容就到这里了,希望大家有所收获,下篇将正式进入Spring IOC容器的启动流程!

    准备花个30天时间,系统的来整理一下我对spring源码的认识:

    Spring 源码系列
    1. Spring源码分析之 IOC 容器预启动流程(已完结)
    2. Spring源码分析之BeanFactory体系结构(已完结)
    3. Spring源码分析之BeanFactoryPostProcessor调用过程(已完结)
    4. Spring源码分析之Bean的创建过程
    5. Spring源码分析之什么是循环依赖及解决方案
    6. Spring源码分析之AOP从解析到调用
    7. Spring源码分析之事务管理(上),事物管理是spring作为容器的一个特点,总结一下他的基本实现与原理吧
    8. Spring源码分析之事务管理(下) ,关于他的底层事物隔离与事物传播原理,重点分析一下
    Spring Mvc 源码系列
    1. SpringMvc体系结构
    2. SpringMvc源码分析之Handler解析过程
    3. SpringMvc源码分析之请求链过程
    Mybatis 源码系列

    暂定


    追更,可扫下面的二维码,分享纯粹为了乐趣,也有一种成就感吧,笔者这篇文章先就到这
    在这里插入图片描述

  • 相关阅读:
    map方法,以及filter方法的使用
    detach与remove区别,以及detach保留被删除的元素数据,使用
    jQuery 文档操作
    javascript 清空数组的方法
    jquery遍历数组的方式
    Oracle表空间不足处理
    css 文本超出2行就隐藏并且显示省略号
    Vim中的寄存器
    spacemacs怎样配置编辑器显示行号?
    Docker考前突击
  • 原文地址:https://www.cnblogs.com/tomakemyself/p/13794069.html
Copyright © 2011-2022 走看看