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容器中的状态不一致。
未完待~~~