SpringFramework核心技术一(IOC:Bean的分析)

简介: Bean的概述Spring IoC容器管理一个或多个bean。这些bean是使用您提供给容器的配置元数据创建的,例如,以XML 定义的形式 。

Bean的概述

Spring IoC容器管理一个或多个bean。这些bean是使用您提供给容器的配置元数据创建的,例如,以XML 定义的形式 。
在容器本身中,这些bean定义被表示为BeanDefinition 对象,其中包含以下元数据(以及其他信息):


一、下面来看一下BeanDefinition

这里写图片描述

1.1

详细看一下BeanDefinition接口里面讲的有那些东西
首先来看一下,用的比较多的Spring表示范围Scope中的prototype与singleton区别

1.1.1 singleton作用域

当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例。
这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时候,spring的IOC容器中只会存在一个该bean。

1.1.1 prototype作用域

prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。
不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。)

1.1.1.1 关于scope=”prototype”没写的问题

项目中对一个表的增删该操作是用一个action,这个action拥有add,update,delete,save等方法, 添加和修改是共用一个页面,当页面得到id时代表进行的修改操作,反之是添加操作。如果在配置spring的bean时,忘了写scope=”prototype” ,所以每次添加时都显示最后一次访问过的记录。scope=”prototype” 会在该类型的对象被请求时创建一个新的action对象,如果没有配置scope=”prototype”则添加的时候不会新建一个action,它仍然会保留上次访问的过记录的信息 ,所以,webwork的Action不是线程安全的,要求在多线程环境下必须是一个线程对应一个独立的实例,则不能使用singleton。所以,我们在Spring配置Webwork Action Bean时,需要加上属性scope=”prototype”或singleton=”false”。
singleton模式指的是对某个对象的完全共享,包括代码空间和数据空间,说白了,如果一个类是singleton的,假如这个类有成员变量,那么这个成员变量的值是各个线程共享的(有点类似于static的样子了),当线程A往给变量赋了一个值以后,线程B就能读出这个值。
因此,对于前台Action,肯定不能使用singleton的模式,必须是一个线程请求对应一个独立的实例。推而广之,只要是带数据成员变量的类,为了防止多个线程混用数据,就不能使用singleton。对于我们用到的Service、Dao,之所以用了singleton,就是因为他们没有用到数据成员变量,如果谁的Service需要数据成员变量,请设置singleton=false。 有状态的bean都使用Prototype作用域,而对无状态的bean则应该使用singleton作用域。

二、看一下BeanDefinition的源码

/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory.config;

import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.lang.Nullable;

/**
 * A BeanDefinition describes a bean instance, which has property values,
 * constructor argument values, and further information supplied by
 * concrete implementations.
 * 一个bean的定义就是描述一个bean的实例,这个bean有属性值,构造参数的值
 * 这个bean的实现会提供更多的信息
 *
 * <p>This is just a minimal interface: The main intention is to allow a
 * {@link BeanFactoryPostProcessor} such as {@link PropertyPlaceholderConfigurer}
 * to introspect and modify property values and other bean metadata.
 * 这个BeanDefinition仅仅只是一个最简洁的接口,它主要的目的是为了允许BeanFactoryPostProcessor和PropertyPlaceholderConfigurer
 * 去反省和定义属性值和一些其他的元数据
 *
 * @author Juergen Hoeller
 * @author Rob Harrop
 * @since 19.03.2004
 * @see ConfigurableListableBeanFactory#getBeanDefinition
 * 通过ConfigurableListableBeanFactory可以获取到bean的属性定义对应的值
 * @see org.springframework.beans.factory.support.RootBeanDefinition
 * @see org.springframework.beans.factory.support.ChildBeanDefinition
 */
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    /**
     * SCOPE范围
     */
    /**
     * Scope identifier for the standard singleton scope: "singleton".
     * scope范围标识符的单例singleton由字符串"singleton"表示。
     * <p>Note that extended bean factories might support further scopes.
     * @see #setScope
     */
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    /**
     * Scope identifier for the standard prototype scope: "prototype".
     * prototype由字符串prototype表示
     * <p>Note that extended bean factories might support further scopes.
     * @see #setScope
     */
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;


    /**
     * Role角色
     */
    /**
     * Role hint indicating that a {@code BeanDefinition} is a major part
     * of the application. Typically corresponds to a user-defined bean.
     * 角色应用
     */
    int ROLE_APPLICATION = 0;

    /**
     * Role hint indicating that a {@code BeanDefinition} is a supporting
     * part of some larger configuration, typically an outer
     * {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
     * {@code SUPPORT} beans are considered important enough to be aware
     * of when looking more closely at a particular
     * {@link org.springframework.beans.factory.parsing.ComponentDefinition},
     * but not when looking at the overall configuration of an application.
     * 角色支持
     */
    int ROLE_SUPPORT = 1;

    /**
     * Role hint indicating that a {@code BeanDefinition} is providing an
     * entirely background role and has no relevance to the end-user. This hint is
     * used when registering beans that are completely part of the internal workings
     * of a {@link org.springframework.beans.factory.parsing.ComponentDefinition}.
     * 角色的基础构造
     */
    int ROLE_INFRASTRUCTURE = 2;


    // Modifiable attributes

    /**
     * Set the name of the parent definition of this bean definition, if any.
     * 设置父类Bean的定义名称
     */
    void setParentName(@Nullable String parentName);

    /**
     * Return the name of the parent definition of this bean definition, if any.
     * 获取父类Bean的名字
     */
    @Nullable
    String getParentName();

    /**
     * Specify the bean class name of this bean definition.
     * <p>The class name can be modified during bean factory post-processing,
     * typically replacing the original class name with a parsed variant of it.
     * @see #setParentName
     * @see #setFactoryBeanName
     * @see #setFactoryMethodName
     * 设定bean的类的名字
     */
    void setBeanClassName(@Nullable String beanClassName);

    /**
     * Return the current bean class name of this bean definition.
     * <p>Note that this does not have to be the actual class name used at runtime, in
     * case of a child definition overriding/inheriting the class name from its parent.
     * Also, this may just be the class that a factory method is called on, or it may
     * even be empty in case of a factory bean reference that a method is called on.
     * Hence, do <i>not</i> consider this to be the definitive bean type at runtime but
     * rather only use it for parsing purposes at the individual bean definition level.
     * @see #getParentName()
     * @see #getFactoryBeanName()
     * @see #getFactoryMethodName()
     * 获取bean的类的名字
     */
    @Nullable
    String getBeanClassName();

    /**
     * Override the target scope of this bean, specifying a new scope name.
     * @see #SCOPE_SINGLETON
     * @see #SCOPE_PROTOTYPE
     * 设置范围
     */
    void setScope(@Nullable String scope);

    /**
     * Return the name of the current target scope for this bean,
     * or {@code null} if not known yet.
     * 获取范围
     */
    @Nullable
    String getScope();

    /**
     * Set whether this bean should be lazily initialized.
     * <p>If {@code false}, the bean will get instantiated on startup by bean
     * factories that perform eager initialization of singletons.
     * 设置是否延迟加载bean
     */
    void setLazyInit(boolean lazyInit);

    /**
     * Return whether this bean should be lazily initialized, i.e. not
     * eagerly instantiated on startup. Only applicable to a singleton bean.
     * 获取这个bean是否需要延迟加载
     */
    boolean isLazyInit();

    /**
     * Set the names of the beans that this bean depends on being initialized.
     * The bean factory will guarantee that these beans get initialized first.
     * 设置这个bean,它的依赖的bean需要被初始化
     */
    void setDependsOn(@Nullable String... dependsOn);

    /**
     * Return the bean names that this bean depends on.
     * 返回这个bean所依赖的其他bean的名字
     */
    @Nullable
    String[] getDependsOn();

    /**
     * Set whether this bean is a candidate for getting autowired into some other bean.
     * <p>Note that this flag is designed to only affect type-based autowiring.
     * It does not affect explicit references by name, which will get resolved even
     * if the specified bean is not marked as an autowire candidate. As a consequence,
     * autowiring by name will nevertheless inject a bean if the name matches.
     * 设置这个Bean为自动装配的候选bean
     */
    void setAutowireCandidate(boolean autowireCandidate);

    /**
     * Return whether this bean is a candidate for getting autowired into some other bean.
     * 获取这个Bean是否是其他Bean的自动装配的候选人
     */
    boolean isAutowireCandidate();

    /**
     * Set whether this bean is a primary autowire candidate.
     * <p>If this value is {@code true} for exactly one bean among multiple
     * matching candidates, it will serve as a tie-breaker.
     * 设置这个Bean是否为主要需要自动装配的候选bean
     */
    void setPrimary(boolean primary);

    /**
     * Return whether this bean is a primary autowire candidate.
     * 获取这个Bean是否是需要首先自动装配的Bean
     */
    boolean isPrimary();

    /**
     * Specify the factory bean to use, if any.
     * This the name of the bean to call the specified factory method on.
     * @see #setFactoryMethodName
     * 设置需要使用的工厂bean
     */
    void setFactoryBeanName(@Nullable String factoryBeanName);

    /**
     * Return the factory bean name, if any.
     * 获取工厂Bean的名字
     */
    @Nullable
    String getFactoryBeanName();

    /**
     * Specify a factory method, if any. This method will be invoked with
     * constructor arguments, or with no arguments if none are specified.
     * The method will be invoked on the specified factory bean, if any,
     * or otherwise as a static method on the local bean class.
     * @see #setFactoryBeanName
     * @see #setBeanClassName
     * 设置工厂方法
     */
    void setFactoryMethodName(@Nullable String factoryMethodName);

    /**
     * Return a factory method, if any.
     * 获取工厂方法
     */
    @Nullable
    String getFactoryMethodName();

    /**
     * Return the constructor argument values for this bean.
     * <p>The returned instance can be modified during bean factory post-processing.
     * @return the ConstructorArgumentValues object (never {@code null})
     * 获取这个Bean的构造方法的参数值
     */
    ConstructorArgumentValues getConstructorArgumentValues();

    /**
     * Return if there are constructor argument values defined for this bean.
     * 获取这个bean是否有构造方法的参数值
     * @since 5.0.2
     */
    default boolean hasConstructorArgumentValues() {
        return !getConstructorArgumentValues().isEmpty();
    }

    /**
     * Return the property values to be applied to a new instance of the bean.
     * <p>The returned instance can be modified during bean factory post-processing.
     * @return the MutablePropertyValues object (never {@code null})
     * 获取属性值
     */
    MutablePropertyValues getPropertyValues();

    /**
     * Return if there are property values values defined for this bean.
     * @since 5.0.2
     * 获取这个Bean是否设置了属性值
     */
    default boolean hasPropertyValues() {
        return !getPropertyValues().isEmpty();
    }


    // Read-only attributes

    /**
     * Return whether this a <b>Singleton</b>, with a single, shared instance
     * returned on all calls.
     * @see #SCOPE_SINGLETON
     * 获取这个Bean是否是单例的
     */
    boolean isSingleton();

    /**
     * Return whether this a <b>Prototype</b>, with an independent instance
     * returned for each call.
     * @since 3.0
     * @see #SCOPE_PROTOTYPE
     * 这个Bean是否是Prototype(
     */
    boolean isPrototype();

    /**
     * Return whether this bean is "abstract", that is, not meant to be instantiated.
     * 这个Bean是否是抽象的
     */
    boolean isAbstract();

    /**
     * Get the role hint for this {@code BeanDefinition}. The role hint
     * provides the frameworks as well as tools with an indication of
     * the role and importance of a particular {@code BeanDefinition}.
     * @see #ROLE_APPLICATION
     * @see #ROLE_SUPPORT
     * @see #ROLE_INFRASTRUCTURE
     * 获取Role角色的值
     */
    int getRole();

    /**
     * Return a human-readable description of this bean definition.
     * 获取描述
     */
    @Nullable
    String getDescription();

    /**
     * Return a description of the resource that this bean definition
     * came from (for the purpose of showing context in case of errors).
     * 获取资源的描述
     */
    @Nullable
    String getResourceDescription();

    /**
     * Return the originating BeanDefinition, or {@code null} if none.
     * Allows for retrieving the decorated bean definition, if any.
     * <p>Note that this method returns the immediate originator. Iterate through the
     * originator chain to find the original BeanDefinition as defined by the user.
     * 获取原始的BeanDefinition
     */
    @Nullable
    BeanDefinition getOriginatingBeanDefinition();

}

三、配置Bean的工厂接口

可以在里面,对Bean的作用范围等信息进行配置
这里写图片描述

四、Bean的定义主要有以下几个方面

表1.bean的定义

属性 解释
实例化Bean
名称 给Bean命名
范围 Bean的范围
构造函数参数 依赖注入
属性 依赖注入
自动装配的模式 自动装配的合作者
延迟加载模式 延迟加载Bean
初始化方法 初始化回调
销毁方法 销毁方法的回调

注意:
除了包含有关如何创建特定bean的信息的bean定义之外,这些ApplicationContext实现还允许用户注册在容器外部创建的现有对象。这是通过getBeanFactory()返回BeanFactory实现的方法访问ApplicationContext的BeanFactory来完成的DefaultListableBeanFactory。DefaultListableBeanFactory 支持通过方法该登记registerSingleton(..)和 registerBeanDefinition(..)。但是,典型的应用程序只能通过元数据bean定义来定义bean。

Bean元数据和手动提供的单例实例需要尽早注册,以便容器在自动装配和其他自省步骤中正确推理它们。虽然重写现有的元数据和现有的单例实例在某种程度上受到支持,但在运行时注册新的Bean(与实时访问工厂同时)并未得到正式支持,并且可能导致并发访问异常和/或bean容器中的状态不一致。

未完待~~~

目录
相关文章
|
8月前
|
XML 存储 设计模式
Spring高手之路11——BeanDefinition解密:构建和管理Spring Beans的基石
本文对BeanDefinition进行全面深入的探讨,涵盖BeanDefinition的接口方法、主要信息、类型以及生成过程等方面内容。旨在帮助读者全面理解BeanDefinition的各方面知识,并能够熟练应用。文章通俗易懂,具有很强的指导意义。
65 0
Spring高手之路11——BeanDefinition解密:构建和管理Spring Beans的基石
|
9月前
|
XML Java 测试技术
Spring高手之路8——Spring Bean模块装配的艺术:@Import详解
本文将带你深入探索Spring框架的装配机制,以及它如何使你的代码更具模块化和灵活性。我们首先介绍Spring手动装配的基础知识,然后进一步解析@Import注解在模块装配中的关键角色。文章涵盖从导入普通类、配置类,到使用ImportSelector和ImportBeanDefinitionRegistrar进行动态和选择性装配等多个层次,旨在帮助读者全面理解和掌握Spring的装配技术。
238 0
Spring高手之路8——Spring Bean模块装配的艺术:@Import详解
|
10月前
|
缓存 Java 开发者
Spring高手之路6——Bean生命周期的扩展点:BeanPostProcessor
在本篇文章中,我们将深入探讨Spring框架中的重要组件——BeanPostProcessor。首先,我们将了解其设计理念和目标,然后通过实际的例子学习如何基础使用它,如何通过BeanPostProcessor改变Bean的初始化结果以及如何利用它修改Bean的属性。最后,我们将深入理解后置处理器在Bean生命周期中的作用和执行时机,帮助读者更好地理解和使用这个强大的工具。
69 1
Spring高手之路6——Bean生命周期的扩展点:BeanPostProcessor
|
10月前
|
XML 缓存 Java
Spring高手之路5——彻底掌握Bean的生命周期
在这篇文章中,我们将深入研究Spring Framework的核心部分——Spring Bean的生命周期。我们将探讨初始化和销毁方法,了解如何使用@PostConstruct和@PreDestroy注解,以及实现InitializingBean和DisposableBean接口。我们还将详细讨论原型Bean的生命周期,并最后总结Spring中控制Bean生命周期的三种方式。无论你是Spring新手,还是想进一步提高你的Spring技能,这篇文章都能给你提供有价值的 insights。
358 2
Spring高手之路5——彻底掌握Bean的生命周期
|
XML 存储 Java
《Spring核心技术》第6章:深度解析@PropertySource注解
沉淀,成长,突破,帮助他人,成就自我。
238 0
《Spring核心技术》第6章:深度解析@PropertySource注解
|
XML 存储 Java
【Spring专题】「原理系列」全方面解析SpringFramework的Bean对象的深入分析和挖掘指南
【Spring专题】「原理系列」全方面解析SpringFramework的Bean对象的深入分析和挖掘指南
128 0
【Spring专题】「原理系列」全方面解析SpringFramework的Bean对象的深入分析和挖掘指南
|
Java 程序员 容器
《Spring核心技术》第3章:深度解析@Bean注解
沉淀,成长,突破,帮助他人,成就自我。
122 0
《Spring核心技术》第3章:深度解析@Bean注解
|
Java Spring
Spring技术原理之Bean生命周期
Spring技术原理之Bean生命周期
98 0
Spring技术原理之Bean生命周期
|
XML Java 数据库连接
Spring之路(14)--bean的生命周期
本文目录 1. 何为生命周期 2. 何为作用域 3. 四种作用域具体语法 4. 延迟初始化及其作用 5. 指定bean先后加载顺序 6. bean的创建与销毁回调 7. 总结
161 0
|
XML JSON Java
Spring之路(7)--提高公司管理效率(使用注解快速定义bean)
本文目录 1. 效率非常重要! 2. xml效率很一般 3. 为何用注解会比xml效率高? 4. 注解与xml本质都是元数据 5. 使用注解定义bean的实例 5.1 创建包 5.2 创建spring.xml配置文件 5.3 通过注解定义bean 5.4 开始运行 5.5 验证工作,定义两个重复的bean
100 0