Spring前言中已经介绍了Bean组件在Spring中的重要性,本文将详细讲解Bean组件。
Bean组件在Spring中的实现无外乎 : Bean的定义、Bean的解析、Bean的创建
所以本文目录如下:
如何知道 Spring是如何定义Bean的呢?
以XML配置注入Bean方式为例:
如上图所示,在applicationContext.xml配置一个Bean,当启动Spring IOC容器时会将 person 这个bean注入到容器中。
既然可以将XML中的配置Bean注入的IOC中,那么这个过程中肯定会将XML转为Bean。那么从 XML----> Bean 这个过程肯定会出现Bean的定义。
经过翻阅源码找到 xml ----> Bean 转换过程代码:
//入口方法,只传入xml中定义的bean数据
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
//调用目标解析方法
return parseBeanDefinitionElement(ele, null);
}
//目标解析方法
@Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List < String > aliases = new ArrayList < >();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//将XML转为IOC可以识别的Bean
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
} else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]");
}
} catch(Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
如上图代码所示,
真正将xml中配置的bean转为 IOC可以识别的Bean方法为 : parseBeanDefinitionElement(ele, beanName, containingBean);
而该方法最终会调用 BeanDefinitionReaderUtils.createBeanDefinition(parentName, className,classLoader) 方法:
public static AbstractBeanDefinition createBeanDefinition(@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {
//创建新的IOC Bean对象
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
} else {
bd.setBeanClassName(className);
}
}
return bd;
}
如上图所示,Spring最终创建了 GenericBeanDefinition 对象来接收XML中配置的 person bean 对象 。
到这一步总算找到了Spring中Bean定义的实现类。那么关于Bean的定义,就以GenericBeanDefinition 为源头查找顶级类。
以GenericBeanDefinition 为源头查找到的UML图如下:
根据UML图可以知道 在Spring中是以 BeanDefinition 来定义Bean的。前面已经知道将 xml转为Bean过程中是实例化了一个GenericBeanDefinition 对象,所以GenericBeanDefinition 是BeanDefinition的一个默认实现类 。
//Spring 官方文档:关于BeanDefinition默认实现类
GenericBeanDefinition 是一站式Bean定义组件,可以满足任何要求的Bean定义。
读取配置后生成的就是GenericBeanDefinition。而Spring在创建Bean的时候用的其RootBeanDefinition。
RootBeanDifinition主要由 GenericBeanDefinition 以及 父BeanDefinition合并来的。
可以看到 GenericBeanDefinition 的 getParentName()方法会返回 parentBeanName,而 RootBeanDefinition 的 getParentName始终返回的是 null。
同时上文也提到了,如果提前知道父子BeanDefinition,就直接使用 RootBeanDefinition和ChildBeanDefinition(自定义标签解析的时候)
Bean的定义中已经引用了部分Bean解析的代码。以XML配置Bean方式为例,Bean的解析主要是将 :
XML Bean ----> BeanDefinition
以XML解析Bean为例,解析入口为:
@Override protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException,
IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
如上图所示,Bean的解析是从实例化一个 XmlBeanDefinitionReader 对象开始的。那么以 XmlBeanDefinitionReader对象为源头找顶级类。
以 XmlBeanDefinitionReader对象为源头找顶级类UML图如下:
Bean解析过程非常复杂,以XML配置Bean方式为例,其核心思想就是:
定义好XML配置规则 ----> 配置 XML -----> 将XML中配置Bean转为Spring中对于的Bean包装对象。
public static void main(String[] args) throws IOException {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Person person = (Person) applicationContext.getBean("person");
}
如上图所示,通过 applicationContext.getBean 获得 person对象。首先会到 AbstractApplicationContext中
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
getBeanFactiry()入口方法会到 AbstractRefreshableApplicationContext 中:
@Override public final ConfigurableListableBeanFactory getBeanFactory() {
synchronized(this.beanFactoryMonitor) {
if (this.beanFactory == null) {
throw new IllegalStateException("BeanFactory not initialized or already closed - " + "call 'refresh' before accessing beans via the ApplicationContext");
}
return this.beanFactory;
}
}
如上图所示,要获得 person对象首先要获得一个 ConfigurableListableBeanFactory 对象(实际上获取的是其实现类DefaultListableBeanFactory) ,然后调用该对象的 getBean()方法获得 person 对象。
以 ConfigurableListableBeanFactory 接口为源头向上寻找顶级类,UML如下图所示:
如上图所示,Bean的创建是典型的工厂模式,顶级接口是BeanFactory ,并且 DefaultListableBeanFactory 是 BeanFactory的默认实现类。
BeanFactory顾名思义是一个工厂类,是用来生产 Bean的,定义如下:
既然BeanFactory是用来创建Bean的,那么就创建一个试试看:
public static void main(String[] args) throws IOException {
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
Person person = (Person) beanFactory.getBean("person");
System.out.println(person);
}
Spring 中使用BeanFactory获取Bean的体现:
1. Spring的设计基本上都是以 顶级接口为依托,根据不同功能划分接口。当一个实现需要集合多个功能时,Spring会使用接口继承。Spring在规划好接口之后一般都会有 Abstract 抽象类 穿插在具体实现类之上。
具体步骤:
设计顶级接口(细粒度) -----> 根据功能组合接口 ------> Abstract 抽象 -----> 具体实现
2. 我们平时开发习惯常量维护在一个常量类中或者枚举中,但是在Spring中并没有这样做。Spring将常量定义在各自的接口中或者抽象类中,在真的实现类中就很少有常量出现了。在Java中一个接口代表了一个标准,Spring将常量定义在接口中应该也是使常量具有标准。
建造者设计模式
建设者设计模式是属于创建对象模式三剑客的第一种模式。该模式用于简化复杂对象的构造。
在Spring中,我们可以在
org.springframework.beans.factory.support.BeanDefinitionBuilder
类中检索这个逻辑,这是一个允许我们以编程方式定义bean的类。
优点:
使用建造者模式可以使客户端不必知道产品内部组成的细节。
具体的建造者类之间是相互独立的,这有利于系统的扩展。
具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响。
缺点:
建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,
则不适合使用建造者模式,因此其使用范围受到一定的限制。
如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
单例模式 + 工厂模式 创建Singleton对象
Spring通过 单例模式 + 工厂模式 方式创建IOC中的Bean对象
其中单例模式使用 双端检索 + ConcurrentHashMap 方式实现单例模式,
在单例模式中需要创建Bean时,直接调用 ObjectFactory 生成Bean。
Spring源码如下:
public Object getSingleton(String beanName, ObjectFactory < ?>singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized(this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet < >();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch(IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
} catch(BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException: this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
} finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
以上就是本文 《深入理解Spring原理》 02-Bean核心组件详解 的全部内容,
上述内容如有不妥之处,还请读者指出,共同探讨,共同进步!
@author : [email protected]