首页 > 其他分享 >Spring中的容器和Bean

Spring中的容器和Bean

时间:2024-01-22 16:38:02浏览次数:16  
标签:容器 String Spring beanName bean Bean 单例 new

目录

1. Spring整体设计架构

image

1.1 BeanRegistry系列接口及BeanFactory接口关系

  • BeanFactory接口: 工厂模式定义了IOC容器的基本功能规范
  • BeanRegistry系列接口: 向IOC容器手工注册 BeanDefinition 对象的方法

image

1.1.1 BeanFactory接口

BeanFactory接口实现如下:

public interface BeanFactory {    
      
    //用于取消引用实例并将其与FactoryBean创建的bean区分开来。例如,如果命名的bean是FactoryBean,则获取将返回Factory,而不是Factory返回的实例。
    String FACTORY_BEAN_PREFIX = "&"; 
        
    //根据bean的名字和Class类型等来得到bean实例    
    Object getBean(String name) throws BeansException;    
    Object getBean(String name, Class requiredType) throws BeansException;    
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

    //返回指定bean的Provider
    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

    //检查工厂中是否包含给定name的bean,或者外部注册的bean
    boolean containsBean(String name);

    //检查所给定name的bean是否为单例/原型
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    //判断所给name的类型与type是否匹配
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    //获取给定name的bean的类型
    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    //返回给定name的bean的别名
    String[] getAliases(String name);

}

BeanFactory有三个子类接口,ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。

  • ListableBeanFactory接口:该接口定义了访问容器中 Bean 基本信息的若干方法,如查看Bean 的个数、获取某一类型 Bean 的配置名、查看容器中是否包括某一 Bean 等方法;
  • HierarchicalBeanFactory接口:父子级联 IoC 容器的接口,子容器可以通过接口方法访问父容器; 通过 HierarchicalBeanFactory 接口, Spring 的 IoC 容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的 Bean,但父容器不能访问子容器的 Bean。Spring 使用父子容器实现了很多功能,比如在 Spring MVC 中,展现层 Bean 位于一个子容器中,而业务层和持久层的 Bean 位于父容器中。这样,展现层 Bean 就可以引用业务层和持久层的 Bean,而业务层和持久层的 Bean 则看不到展现层的 Bean。
  • AutowireCapableBeanFactory接口:定义了将容器中的 Bean 按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法;

还有其他BeanFactory接口或者抽象类,均是此三个接口子类。

  • ConfigurableBeanFactory接口:继承自ConfigurableBeanFactory接口和SingletonBeanRegistry接口,增强了 IoC 容器的可定制性,它定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法;
  • ConfigurableListableBeanFactory接口:继承自ListableBeanFactory接口/AutowireCapableBeanFactory接口和ConfigurableBeanFactory接口,等于是继承了BeanFactory的全部三个子类接口及SingletonBeanRegistry接口。

1.1.2 BeanRegistry系列接口

最核心的接口有两个:

  • BeanDefinitionRegistry接口,实现类DefaultListableBeanFactory;
  • SingletonBeanRegistry接口,实现类DefaultSingletonBeanRegistry;

1.1.2.1 BeanDefinitionRegistry接口及DefaultListableBeanFactory实现类

BeanDefinitionRegistry接口定义了关于 BeanDefinition 的注册、移除、查询等一系列的操作。

public interface SingletonBeanRegistry {

    // 注册单例 Bean。其实就是将该 Bean 保存到一个专门存储单例 Bean 实例的Map中,Key是 beanName,Value是对应的单例 Bean 实例
    void registerSingleton(String beanName, Object singletonObject);

    // 通过 beanName 获取该单例 Bean 实例
    Object getSingleton(String beanName);

    // 通过 beanName 判断该单例 Bean 实例是否存在
    boolean containsSingleton(String beanName);

    // 返回所有单例 Bean 的名称
    String[] getSingletonNames();

    // 返回已注册的单例 Bean 实例数量
    int getSingletonCount();

    // 返回当前使用的单例锁,主要提供给外部协作者使用
    Object getSingletonMutex();
}

该接口有三个实现类:DefaultListableBeanFactory、GenericApplicationContext、SimpleBeanDefinitionRegistry,其中 GenericApplicationContext 底层调用的是 DefaultListableBeanFactory 中的实现方法。故,DefaultListableBeanFactory类是BeanDefinitionRegistry接口核心实现类。

核心代码如下:

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    
    ...
    
    // 存储所有的 BeanDefinition ,key 是 Bean 的名称。我们一直称呼的容器,底层就是这个 Map
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    // 存储所有 Bean 名称
    private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
    // 存储手动注册的单例 Bean 名称
    private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
    // 存储冻结的 BeanDefinition,留作后面缓存用
    private volatile String[] frozenBeanDefinitionNames;
    
    ...
    
    // 方法的入参为 Bean 名称和对应的 BeanDefinition
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {

        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");

        // 如果 beanDefinition 的实例为 AbstractBeanDefinition,则进行验证
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                // 验证:
                //     如果有重写方法,但是是工厂方法,则抛出异常,因为重写方法需要代理,而工厂方法无法代理;
                //     通过方法名称,判断 Bean 中该名称方法存在的数量,0:方法不存在,报错;1:方法非重载,overloaded 属性设为 false;
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition oldBeanDefinition;
        // 先从 beanDefinitionMap 中尝试获取 beanName 对应 BeanDefinition
        oldBeanDefinition = this.beanDefinitionMap.get(beanName);
        
        // 不为 null,则 beanName 对应的 BeanDefinition 已经存在
        if (oldBeanDefinition != null) {
            
            // 是否应允许覆盖 BeanDefinition,不允许则抛异常
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                        "': There is already [" + oldBeanDefinition + "] bound.");
            }
            
            /***************************** 若允许覆盖 *****************************/
            
            // 判断 Bean 的角色大小:
            //      0:用户定义的 Bean、1:来源于配置文件的 Bean、2:Spring 内部的 Bean;
            // 当原 BeanDefinition 角色小于新的 BeanDefinition 角色时,输出一个 warn 日志,提示 BeanDefinition 被覆盖
            else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            }
            // 当新 BeanDefinition 属性值不等于原 BeanDefinition 属性值时,输出 info 提示信息
            else if (!beanDefinition.equals(oldBeanDefinition)) {
                if (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            // 最后,输出 debug 日志信息:用等效的新 BeanDefinition 覆盖原 BeanDefinition
            else {
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + oldBeanDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            // 添加至 BeanDefinition 集合,并覆盖原 BeanDefinition
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        
        // Map 中无对应的 BeanDefinition,则直接注册
        else {
            // 已开始创建 Bean 
            if (hasBeanCreationStarted()) {
                synchronized (this.beanDefinitionMap) {
                    // 将 Bean 对应的 BeanDefinition 放入 beanDefinitionMap 中
                    this.beanDefinitionMap.put(beanName, beanDefinition);

                    // 创建新的 beanNames 集合,并将已缓存的 beanName 和新的 beanName 加入该集合
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;

                    // 在手动注册 Bean 的集合中,如果存在同名的 beanName,则将集合中同名的 beanName 删除
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            }
            // 仍处于启动注册阶段
            else {
                // 将当前 Bean 对应的 BeanDefinition 放入 beanDefinitionMap 中
                this.beanDefinitionMap.put(beanName, beanDefinition);
                // 将当前 beanName 放入 beanDefinitionNames
                this.beanDefinitionNames.add(beanName);
                // 删除手动注册 Bean 集合中同名的 beanName
                this.manualSingletonNames.remove(beanName);
            }

            // 将存储冻结 BeanDefinition 的 Map 置为 null
            this.frozenBeanDefinitionNames = null;
        }

        // 当前注册的 BeanDefinition 已在 beanDefinitionMap 中存在,或者其实例已在存储单例 Bean 的 Map 中存在
        if (oldBeanDefinition != null || containsSingleton(beanName)) {

            // 重置 BeanDefinition,主要做一些清理工作
            resetBeanDefinition(beanName);
        }
    }
}

执行完 registerBeanDefinition 方法后,Bean 的名称和对应的 BeanDefinition 就被放入了容器中,后续获取 Bean 也是从这个容器中获取。

当然,DefaultListableBeanFactory 还实现了 BeanDefinitionRegistry 接口的其它方法,如对 BeanDefinition 进行移除、判断是否存在、获取数量等操作,其实都是围绕 beanDefinitionMap 这个 Map 进行的,这里就不详细介绍。

1.1.2.2 SingletonBeanRegistry接口及DefaultSingletonBeanRegistry实现类

SingletonBeanRegistry接口统一操作单例 Bean 实例,通过该接口可直接对单例 Bean 的实例进行存储、注册等操作。这个接口其实和BeanDefinitionRegistry接口功能类似,但是其DefaultSingletonBeanRegistry实现类的扩展却解决了单例Bean间的循环依赖问题。

public interface SingletonBeanRegistry {

    // 注册单例 Bean。其实就是将该 Bean 保存到一个专门存储单例 Bean 实例的Map中,Key是 beanName,Value是对应的单例 Bean 实例
    void registerSingleton(String beanName, Object singletonObject);

    // 通过 beanName 获取该单例 Bean 实例
    Object getSingleton(String beanName);

    // 通过 beanName 判断该单例 Bean 实例是否存在
    boolean containsSingleton(String beanName);

    // 返回所有单例 Bean 的名称
    String[] getSingletonNames();

    // 返回已注册的单例 Bean 实例数量
    int getSingletonCount();

    // 返回当前使用的单例锁,主要提供给外部协作者使用
    Object getSingletonMutex();
}

DefaultSingletonBeanRegistry实现类核心代码如下,可以看到不仅用了三层缓存来解决Bean的循环依赖问题,还用其他缓存记录了Bean之间的关系及处于创建/销毁状态的Bean等。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

    /********** 1、定义的一些 Map 属性,用来保存单例 Bean 实例、 Bean 的依赖关系 **********/

    // 缓存单例 Bean 实例,Key 是 beanName,Value 是单例 Bean 实例
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    // 缓存 Bean 对应的 ObjectFactory 
    //      ObjectFactory 是获取 Bean 实例的工厂,只不过这里获取的 Bean 还未完全实例化,属于提早暴露的 Bean
    //      该属性在解决循环依赖时使用,后续会深入讨论
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    // 缓存 singletonFactories 属性中通过 ObjectFactory 创建的 Bean
    //      该属性也是在解决循环依赖时使用,后续会深入讨论
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    // 保存已注册的单例 Bean 名称
    private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

    // 保存当前正在创建的 Bean 的名称
    private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    // 保存当前从创建检查中排除的 Bean 的名称
    private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16));

    ...
    
    // 当前 Bean 是否处于销毁状态
    private boolean singletonsCurrentlyInDestruction = false;

    // 保存实现了 DisposableBean 接口的 Bean,在销毁 Bean 时,会回调该 Bean 中的 destory 方法
    private final Map<String, Object> disposableBeans = new LinkedHashMap<>();

    // 保存 Bean 的包含关系,key 是 Bean 的名称,value 是 Bean 里面包含的其它 Bean 名称集合
    private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);

    // 保存 Bean 的依赖关系:key 是 Bean 的名称,value 是依赖于该 Bean 的其它 Bean 名称集合
    private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

    // 保存 Bean 的依赖关系:key 是 Bean 的名称,value 是该 Bean 所依赖的其它 Bean 名称集合
    private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

    /******************************** 2、注册单例 Bean 实例及对应的实例工厂 ********************************/

    // 注册单例 Bean 实例
    @Override
    public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
        Assert.notNull(beanName, "Bean name must not be null");
        Assert.notNull(singletonObject, "Singleton object must not be null");
        
        synchronized (this.singletonObjects) {
            // 通过 beanName 获取 Map 中对应的单例 Bean 实例
            Object oldObject = this.singletonObjects.get(beanName);
            
            //  如果不为空,则抛出异常,因为单例已经存在,无法再次注册
            if (oldObject != null) {
                throw new IllegalStateException("Could not register object [" + singletonObject +
                        "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
            }
            
            // 为空,则进入 addSingleton 方法
            addSingleton(beanName, singletonObject);
        }
    }

    // 缓存单例 Bean 实例
    protected void addSingleton(String beanName, Object singletonObject) {
        synchronized (this.singletonObjects) {
            // 将单例 Bean 实例存放至 singletonObjects 集合
            this.singletonObjects.put(beanName, singletonObject);
            
            // 当 beanName 对应的 Bean 实例已被存放至 singletonObjects 集合时,singletonFactories 
            // 和 earlySingletonObjects 集合则不能再持有 beanName 对应的 ObjectFactory 和实例
            // 其中原因会在后续循环依赖的文章深入讨论
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            
            // 存储 Bean 名称
            this.registeredSingletons.add(beanName);
        }
    }

    // 缓存 Bean 对应的 ObjectFactory
    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(singletonFactory, "Singleton factory must not be null");
        synchronized (this.singletonObjects) {
            if (!this.singletonObjects.containsKey(beanName)) {
                this.singletonFactories.put(beanName, singletonFactory);
                this.earlySingletonObjects.remove(beanName);
                this.registeredSingletons.add(beanName);
            }
        }
    }

    /********************************* 3、获取单例 Bean 实例 *********************************/
    
    @Override
    public Object getSingleton(String beanName) {
        
        // 该方法较为复杂,在后续结合循环依赖的场景讨论
        
    }

    ...

    /***************************** 4、对单例 Bean 实例的基础操作 *****************************/

    // 删除单例 Bean 实例
    protected void removeSingleton(String beanName) {
        synchronized (this.singletonObjects) {
            this.singletonObjects.remove(beanName);
            this.singletonFactories.remove(beanName);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.remove(beanName);
        }
    }

    // 判断 beanName 对应的单例 Bean 实例时候存在
    @Override
    public boolean containsSingleton(String beanName) {
        return this.singletonObjects.containsKey(beanName);
    }

    // 返回所有单例 Bean 的 beanName
    @Override
    public String[] getSingletonNames() {
        synchronized (this.singletonObjects) {
            return StringUtils.toStringArray(this.registeredSingletons);
        }
    }

    // 返回单例 Bean 实例数量
    @Override
    public int getSingletonCount() {
        synchronized (this.singletonObjects) {
            return this.registeredSingletons.size();
        }
    }

    ...

    /*************************************** 5、 Bean 的状态 **************************************/

    // beanName 对应的 Bean 是否处于实例化阶段
    public boolean isCurrentlyInCreation(String beanName) {
        Assert.notNull(beanName, "Bean name must not be null");
        return (!this.inCreationCheckExclusions.contains(beanName) && isActuallyInCreation(beanName));
    }
    protected boolean isActuallyInCreation(String beanName) {
        return isSingletonCurrentlyInCreation(beanName);
    }
    public boolean isSingletonCurrentlyInCreation(String beanName) {
        return this.singletonsCurrentlyInCreation.contains(beanName);
    }

    // 单例 Bean 实例化前执行,将正要创建的 Bean 加入 singletonsCurrentlyInCreation 集合
    protected void beforeSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }

    // 单例 Bean 实例化后执行,从 singletonsCurrentlyInCreation 集合中移除已创建的 Bean 
    protected void afterSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
            throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
        }
    }

    ...

    /********************* 6、 存储 Bean 之间的关系、判断 Bean 之间的关系 *********************/
    
    // 保存具有包含关系的 Bean(内部类与外部类)
    public void registerContainedBean(String containedBeanName, String containingBeanName) {
        synchronized (this.containedBeanMap) {
            Set<String> containedBeans =
                    this.containedBeanMap.computeIfAbsent(containingBeanName, k -> new LinkedHashSet<>(8));
            if (!containedBeans.add(containedBeanName)) {
                return;
            }
        }
        registerDependentBean(containedBeanName, containingBeanName);
    }

    // 保存具有依赖关系的 Bean
    public void registerDependentBean(String beanName, String dependentBeanName) {
        String canonicalName = canonicalName(beanName);

        synchronized (this.dependentBeanMap) {
            Set<String> dependentBeans =
                    this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
            if (!dependentBeans.add(dependentBeanName)) {
                return;
            }
        }

        synchronized (this.dependenciesForBeanMap) {
            Set<String> dependenciesForBean =
                    this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
            dependenciesForBean.add(canonicalName);
        }
    }

    ...
    
    /***************************** 7、 销毁 Bean 的方法 *****************************/
    
    ...
}

1.2 ApplicationContext:IOC接口设计和实现

1.2.1 ApplicationContext整体类图

image

  • HierarchicalBeanFactory 和 ListableBeanFactory
    ApplicationContext 继承了 HierarchicalBeanFactory 和 ListableBeanFactory 接口,提供BeanFactory角色功能。

  • ApplicationEventPublisher

    • 使容器具备发布应用上下文事件的功能,如容器启动事件、关闭事件等。
    • 实现了 ApplicationListener 事件监听接口的 Bean 可以接收容器事件,并对事件进行响应处理。
    • AbstractApplicationContext 抽象实现类中存在 ApplicationEventMulticaster,负责保存所有监听器,通知监听者容器产生上下文事件。
  • MessageSource
    为应用提供 i18n 国际化消息访问的功能。

  • ResourcePatternResolver

    • 所有 ApplicationContext 实现类都提供类似于 PathMatchingResourcePatternResolver 的功能。
    • 可以通过带前缀的 Ant 风格的资源文件路径加载 Spring 的配置文件。
  • LifeCycle

    • LifeCycle 接口是 Spring 2.0 引入的,提供 start()stop() 两个方法,用于控制异步处理过程。
    • 在具体使用时,该接口被 ApplicationContext 实现及具体 Bean 实现。
    • ApplicationContext 会将 start/stop 的信息传递给容器中所有实现了该接口的 Bean,以管理和控制 JMX、任务调度等目的。

1.2.2 ApplicationContext接口的实现

在考虑ApplicationContext接口的实现时,关键的点在于,不同Bean的配置方式(比如xml,groovy,annotation等)有着不同的资源加载方式,这便衍生除了众多ApplicationContext的实现类。
image

第一,从类结构设计上看, 围绕着是否需要Refresh容器衍生出两个抽象类:

  • GenericApplicationContext: 是初始化的时候就创建容器,往后的每次refresh都不会更改
  • AbstractRefreshableApplicationContext: AbstractRefreshableApplicationContext及子类的每次refresh都是先清除已有(如果不存在就创建)的容器,然后再重新创建;AbstractRefreshableApplicationContext及子类无法做到GenericApplicationContext混合搭配从不同源头获取bean的定义信息。

第二, 从加载的源来看(比如xml,groovy,annotation等), 衍生出众多类型的ApplicationContext, 典型比如:

  • FileSystemXmlApplicationContext: 从文件系统下的一个或多个xml配置文件中加载上下文定义,也就是说系统盘符中加载xml配置文件。
  • ClassPathXmlApplicationContext: 从类路径下的一个或多个xml配置文件中加载上下文定义,适用于xml配置的方式。
  • AnnotationConfigApplicationContext: 从一个或多个基于java的配置类中加载上下文定义,适用于java注解的方式。
  • ConfigurableApplicationContext: 扩展于 ApplicationContext,它新增加了两个主要的方法: refresh()和 close(),让 ApplicationContext 具有启动、刷新和关闭应用上下文的能力。在应用上下文关闭的情况下调用 refresh()即可启动应用上下文,在已经启动的状态下,调用 refresh()则清除缓存并重新装载配置信息,而调用close()则可关闭应用上下文。

这些接口方法为容器的控制管理带来了便利,但作为开发者,我们并不需要过多关心这些方法。

第三, 更进一步理解:设计者在设计时AnnotationConfigApplicationContext为什么是继承GenericApplicationContext?

因为基于注解的配置,是不太会被运行时修改的,这意味着不需要进行动态Bean配置和刷新容器,所以只需要GenericApplicationContext。而基于XML这种配置文件,这种文件是容易修改的,需要动态性刷新Bean的支持,所以XML相关的配置必然继承AbstractRefreshableApplicationContext; 且存在多种xml的加载方式(位置不同的设计),所以必然会设计出AbstractXmlApplicationContext, 其中包含对XML配置解析成BeanDefination的过程。
那么为什么AnnotationWebConfigApplicationContext却是继承了AbstractRefreshableApplicationContext而不是GenericApplicationContext ? 因为用户可以通过ApplicationContextInitializer来设置contextInitializerClasses(context-param / init-param), 在这种情况下用户倾向于刷新Bean的,所以设计者选择让AnnotationWebConfigApplicationContext继承了AbstractRefreshableApplicationContext。
如下是源码中Spring设计者对它的解释。

* <p>As an alternative to setting the "contextConfigLocation" parameter, users may
 * implement an {@link org.springframework.context.ApplicationContextInitializer
 * ApplicationContextInitializer} and set the
 * {@linkplain ContextLoader#CONTEXT_INITIALIZER_CLASSES_PARAM "contextInitializerClasses"}
 * context-param / init-param. In such cases, users should favor the {@link #refresh()}
 * and {@link #scan(String...)} methods over the {@link #setConfigLocation(String)}
 * method, which is primarily for use by {@code ContextLoader}.

2. Spring IOC容器初始化流程

整体流程如下所示:
image

2.1. SpringApplication.run(Application.class, args),实际调用new SpringApplication(null, primarySources).run(args)。

构造函数和run的实现如下。

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
 	this.resourceLoader = resourceLoader;
 	Assert.notNull(primarySources, "PrimarySources must not be null");
 	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
 	this.webApplicationType = WebApplicationType.deduceFromClasspath();
 	this.bootstrapRegistryInitializers = new ArrayList<>(
 			getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
 	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
 	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
 	this.mainApplicationClass = deduceMainApplicationClass();
 }

可以看到SpringApplication类的构造方法主要是初始化应用类型(Reactive或Servlet)及通过SpringFactories机制实例化BootstrapRegistryInitializer、ApplicationContextInitializer及ApplicationListener的实现类。

	public ConfigurableApplicationContext run(String... args) {
 	long startTime = System.nanoTime();
 	DefaultBootstrapContext bootstrapContext = createBootstrapContext();
 	ConfigurableApplicationContext context = null;
 	configureHeadlessProperty();
 	SpringApplicationRunListeners listeners = getRunListeners(args);
 	listeners.starting(bootstrapContext, this.mainApplicationClass);
 	try {
 		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
 		ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
 		configureIgnoreBeanInfo(environment);
 		Banner printedBanner = printBanner(environment);
 		// 创建IOC容器
 		context = createApplicationContext();
 		context.setApplicationStartup(this.applicationStartup);
 		prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
 		// 刷新IOC容器
 		refreshContext(context);
 		afterRefresh(context, applicationArguments);
 		Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
 		if (this.logStartupInfo) {
 			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
 		}
 		listeners.started(context, timeTakenToStartup);
 		callRunners(context, applicationArguments);
 	}
 	catch (Throwable ex) {
 		handleRunFailure(context, ex, listeners);
 		throw new IllegalStateException(ex);
 	}
 	try {
 		Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
 		listeners.ready(context, timeTakenToReady);
 	}
 	catch (Throwable ex) {
 		handleRunFailure(context, ex, null);
 		throw new IllegalStateException(ex);
 	}
 	return context;
 }
run方法除了读取环境变量、创建ApplicationContext容器createApplicationContext等操作,最主要的便是刷新ApplicationContext容器refreshContext,并穿插SpringApplication监听的开始启动、启动完成、准备事件。

2.2 refreshContext(ConfigurableApplicationContext context)方法实现如下,实际上是调用的传入的IOC容器的refresh()方法。

	private void refreshContext(ConfigurableApplicationContext context) {
 	if (this.registerShutdownHook) {
 		shutdownHook.registerApplicationContext(context);
 	}
 	refresh(context);
 }

实际上会走到AbstractApplicationContext类的refresh()方法,代码如下。

	public void refresh() throws BeansException, IllegalStateException {
 	synchronized (this.startupShutdownMonitor) {
 		StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

 		// Prepare this context for refreshing.
 		prepareRefresh();

 		// Tell the subclass to refresh the internal bean factory.
 		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

 		// Prepare the bean factory for use in this context.
 		prepareBeanFactory(beanFactory);

 		try {
 			// Allows post-processing of the bean factory in context subclasses.
 			postProcessBeanFactory(beanFactory);

 			StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
 			// Invoke factory processors registered as beans in the context.
 			invokeBeanFactoryPostProcessors(beanFactory);

 			// Register bean processors that intercept bean creation.
 			registerBeanPostProcessors(beanFactory);
 			beanPostProcess.end();

 			// Initialize message source for this context.
 			initMessageSource();

 			// Initialize event multicaster for this context.
 			initApplicationEventMulticaster();

 			// Initialize other special beans in specific context subclasses.
 			onRefresh();

 			// Check for listener beans and register them.
 			registerListeners();

 			// Instantiate all remaining (non-lazy-init) singletons.
 			finishBeanFactoryInitialization(beanFactory);

 			// Last step: publish corresponding event.
 			finishRefresh();
 		}

 		catch (BeansException ex) {
 			if (logger.isWarnEnabled()) {
 				logger.warn("Exception encountered during context initialization - " +
 						"cancelling refresh attempt: " + ex);
 			}

 			// Destroy already created singletons to avoid dangling resources.
 			destroyBeans();

 			// Reset 'active' flag.
 			cancelRefresh(ex);

 			// Propagate exception to caller.
 			throw ex;
 		}

 		finally {
 			// Reset common introspection caches in Spring's core, since we
 			// might not ever need metadata for singleton beans anymore...
 			resetCommonCaches();
 			contextRefresh.end();
 		}
 	}
 }

这里使用的模板方法设计模式,规定了需要执行的动作,且部分方法又子类进行实现。

其中,BeanFactory初始化一系列方法会读取文件/注解等完成BeanDefinition的反序列化及注入到beanDefinitionMap中,而finishBeanFactoryInitialization(beanFactory)方法完成了Bean生命周期的初始化操作。

2.3 finishBeanFactoryInitialization(beanFactory)

finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory)方法实际调用的是AbstractApplicationContext类的实现,
由其中一行代码进入单例Bean的创建流程。

// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();

preInstantiateSingletons()则由DefaultListableBeanFactory类实现,代码如下。

	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		// 通过beanDefinitionNames列表获取Bean的名字列表
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		// 通过BeanName从Map<String, RootBeanDefinition>获取BeanDefinition
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 如果Bean不是抽象的 是单例的 非懒加载的那么进行加载
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			    // 工厂单例Bean的创建逻辑
				if (isFactoryBean(beanName)) {
				    // 工厂Bean会有FACTORY_BEAN_PREFIX(值为&)前缀
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				// 普通单例Bean的创建逻辑
				else {
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		// 针对于实现了SmartInitializingSingleton接口的Bean调用接口实现的方法
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
						.tag("beanName", beanName);
				SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
				smartInitialize.end();
			}
		}
	}

2.4 getBean(String name)

其实可以看到,无论是针对于工厂Bean还是普通Bean,获取的方法都是getBean(String name),源码如下。

public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

2.5 doGetBean方法

而doGetBean方法的源码如下。

// 参数typeCheckOnly:bean实例是否包含一个类型检查
protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

  // 解析bean的真正name,如果bean是工厂类,name前缀会加&,需要去掉
  String beanName = transformedBeanName(name);
  Object beanInstance;

  // Eagerly check singleton cache for manually registered singletons.
  Object sharedInstance = getSingleton(beanName);
  if (sharedInstance != null && args == null) {
    // 无参单例从缓存中获取
    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
  }

  else {
    // 如果bean实例还在创建中,则直接抛出异常
    if (isPrototypeCurrentlyInCreation(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
    }

    // 如果 bean definition 存在于父的bean工厂中,委派给父Bean工厂获取
    BeanFactory parentBeanFactory = getParentBeanFactory();
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
      // Not found -> check parent.
      String nameToLookup = originalBeanName(name);
      if (parentBeanFactory instanceof AbstractBeanFactory) {
        return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
            nameToLookup, requiredType, args, typeCheckOnly);
      }
      else if (args != null) {
        // Delegation to parent with explicit args.
        return (T) parentBeanFactory.getBean(nameToLookup, args);
      }
      else if (requiredType != null) {
        // No args -> delegate to standard getBean method.
        return parentBeanFactory.getBean(nameToLookup, requiredType);
      }
      else {
        return (T) parentBeanFactory.getBean(nameToLookup);
      }
    }

    if (!typeCheckOnly) {
      // 将当前bean实例放入alreadyCreated集合里,标识这个bean准备创建了
      markBeanAsCreated(beanName);
    }

    StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
        .tag("beanName", name);
    try {
      if (requiredType != null) {
        beanCreation.tag("beanType", requiredType::toString);
      }
      RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
      checkMergedBeanDefinition(mbd, beanName, args);

      // 确保它的依赖也被初始化了.
      String[] dependsOn = mbd.getDependsOn();
      if (dependsOn != null) {
        for (String dep : dependsOn) {
          if (isDependent(beanName, dep)) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
          }
          registerDependentBean(dep, beanName);
          try {
            getBean(dep); // 初始化它依赖的Bean
          }
          catch (NoSuchBeanDefinitionException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
          }
        }
      }

      // 创建Bean实例:单例
      if (mbd.isSingleton()) {
        sharedInstance = getSingleton(beanName, () -> {
          try {
            // 真正创建bean的方法
            return createBean(beanName, mbd, args);
          }
          catch (BeansException ex) {
            // Explicitly remove instance from singleton cache: It might have been put there
            // eagerly by the creation process, to allow for circular reference resolution.
            // Also remove any beans that received a temporary reference to the bean.
            destroySingleton(beanName);
            throw ex;
          }
        });
        beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
      }
      // 创建Bean实例:原型
      else if (mbd.isPrototype()) {
        // It's a prototype -> create a new instance.
        Object prototypeInstance = null;
        try {
          beforePrototypeCreation(beanName);
          prototypeInstance = createBean(beanName, mbd, args);
        }
        finally {
          afterPrototypeCreation(beanName);
        }
        beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
      }
      // 创建Bean实例:根据bean的scope创建
      else {
        String scopeName = mbd.getScope();
        if (!StringUtils.hasLength(scopeName)) {
          throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
        }
        Scope scope = this.scopes.get(scopeName);
        if (scope == null) {
          throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
        }
        try {
          Object scopedInstance = scope.get(beanName, () -> {
            beforePrototypeCreation(beanName);
            try {
              return createBean(beanName, mbd, args);
            }
            finally {
              afterPrototypeCreation(beanName);
            }
          });
          beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
        }
        catch (IllegalStateException ex) {
          throw new ScopeNotActiveException(beanName, scopeName, ex);
        }
      }
    }
    catch (BeansException ex) {
      beanCreation.tag("exception", ex.getClass().toString());
      beanCreation.tag("message", String.valueOf(ex.getMessage()));
      cleanupAfterBeanCreationFailure(beanName);
      throw ex;
    }
    finally {
      beanCreation.end();
    }
  }

  return adaptBeanInstance(name, beanInstance, requiredType);
}

2.6 getSingleton方法

	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// Quick check for existing instance without full singleton lock
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				synchronized (this.singletonObjects) {
					// Consistent creation of early reference within full singleton lock
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						singletonObject = this.earlySingletonObjects.get(beanName);
						if (singletonObject == null) {
							ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
							if (singletonFactory != null) {
								singletonObject = singletonFactory.getObject();
								this.earlySingletonObjects.put(beanName, singletonObject);
								this.singletonFactories.remove(beanName);
							}
						}
					}
				}
			}
		}
		return singletonObject;
	}

2.7 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)方法

实际上调用的是AbstractAutowireCapableBeanFactory类的实现,有一句核心代码。

Object beanInstance = doCreateBean(beanName, mbdToUse, args);

2.8 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

也是调用的AbstractAutowireCapableBeanFactory类的实现。

	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

标签:容器,String,Spring,beanName,bean,Bean,单例,new
From: https://www.cnblogs.com/kiper/p/17976507

相关文章

  • springboot升级到2.6.x和2.7.x 兼容hystrix
    一、pom.xml需要引入的依赖二、项目开启熔断器开关2.1注解方式2.2xml方式三、依赖类缺失问题四、版本匹配安全检查问题五、测试验证六、结论一、pom.xml需要引入的依赖1<!--springboot升级到2.6.7,同样适用于2.7.0,2.7.18等-->2<parent>3......
  • 如何检查 docker 容器日志大小并进行清理
    检查各容器日志大小:ls-lh$(find/var/lib/docker/containers/-name*-json.log)清空日志(需先进入到具体容器目录):cat/dev/null>*-json.log 限制容器日志大小(以配置日志文件最大为10MB,最多留存3个为例)1、在docker运行时添加参数:dockerrun-d\--log-optmax-si......
  • Kubernetes 中容器的退出状态码参考指南
    Kubernetes中容器的退出状态码参考指南云原生生态圈 2024-01-2208:10 发表于北京 听全文什么是容器退出码当容器终止时,容器引擎使用退出码来报告容器终止的原因。如果您是Kubernetes用户,容器故障是pod异常最常见的原因之一,了解容器退出码可以帮助您在排查时找到......
  • springboot自定义更换启动banner动画
    springboot自定义更换启动banner动画......
  • Spring注解是如何实现的?万字详解
    一、什么是Java注解1、Java注解(Annotations),首次出现在Java5中,是一种用于类、方法、变量、参数和Java包的特殊标记。在此之前,Java开发者通常依赖于文档、注释或命名约定来传达某些信息,这些方式并不是语言结构的一部分,因此不能被编译器或运行时环境所理解和利用。2、注解的出现......
  • 使用docker容器部署zabbix5.4
    1.创建自定义网络dockernetworkcreate--subnet172.20.0.0/16--ip-range172.20.240.0/20zabbix-net2.运行MySQL服务dockerrun--namemysql-server-t\-eMYSQL_DATABASE="zabbix"\-eMYSQL_USER="zabbix"\-e......
  • docker容器使用存储卷进行数据持久化
    1.将存储卷"test01"挂载到容器,若不存在则直接创建,默认权限为rw[root@centos201~]#dockercontainerrun-vtest01:/usr/share/nginx/html-d--nameweb01nginx:1.20.168f7609b7d72ba6e328605103cfb315b1a38aa2631ce69a576a228d1037300aa[root@centos201~]#[17:22:......
  • docker容器管理
    1.查看容器[root@centos201~]#dockerps#查看现有的容器列表。CONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMES6aab26123615nginx:1.16"nginx-g'daemonof…"52secondsagoUp51seconds8......
  • Go语言核心36讲 08 | container包中的那些容器
    我们在上次讨论了数组和切片,当我们提到数组的时候,往往会想起链表。那么Go语言的链表是什么样的呢?Go语言的链表实现在标准库的container/list代码包中。这个代码包中有两个公开的程序实体——List和Element,List实现了一个双向链表(以下简称链表),而Element则代表了链表中元素的结构......
  • 布局容器
             -list  harmonyOslist    forEachgrid网格布局   tab   ......