本文参考了https://my.oschina.net/kaywu123/blog/614325?p={{totalPage}}
首先看看测试源码结构:
就这么简单。一共四个文件,
SimpleMain是项目入口:
SimpleMain.java
package chak;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import java.io.IOException;
public class SimpleMain {
public static void main(String[] args) throws IOException {
ClassPathResource resource = new ClassPathResource("spring-context.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);
//MyComponent是自己写的测试类
MyComponent component = factory.getBean("myComponent", MyComponent.class);
component.method();
}
}
MyComponent.java是一个简单的POJO对象,只有一个method()方法打印一串"Hello World"。这里就不列出来了。
logback.xml是日志,方便我们看到运行情况,但是因为我们这里是直接研究源代码,其实要这个日志也没什么用,可以选择无视之。
spring-context.xml是beans的定义文件。是整个spring项目的核心配置文件,虽然在这里它变得异常简单:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd"
default-lazy-init="true">
<bean class="chak.MyComponent" name="myComponent"/>
</beans>
仅仅定义了一个bean。
很好,这就是我们要准备的所有代码。然后让我们深入spring内部,看看这个麻雀的五脏是如何运转的。
在开始之前,可以先来一句提纲携领的话总结整个过程: 先注册BeanDefinition,再获取Bean。
某种程度上,从这句话里也可以看到ioc的一点影子。大家总说的IoC其实本质上就实现了一个功能,帮我们的应用程序去管理众多的对象(也就是bean),当我们需要用到某一个对象的时候,我们只需要直接跟IoC容器(BeanFactory)拿就可以,而不再关心构造这个bean需要什么依赖。但是为什么IoC可以帮我们去管理bean呢?实际上就是因为我们通过别的手段告诉它要怎样组织一个容器,而这个组织容器的过程,在我们这个简单的Demo里,就是注册BeanDefinition。
好了,我也相信,看完上面那句话你当然还是不清楚Spring的原理,所以下面让我们通过代码来体会这句话到底概括了什么。
SimpleMain.java 中 main()方法第一行:
ClassPathResource resource = new ClassPathResource("spring-context.xml");
利用xml文件名构造了一个ClassPathResource对象,这个资源对象在稍后将作为BeanDefinitionReader解析的根据。
第二行:
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
这里引入了一个关键的对象: DefaultListableBeanFactory。看字面名称,他是一个可枚举(列举)的[Listable],Bean工厂(即IoC容器,Bean容器)[BeanFactory]的默认实现[Default]。而实际上,除了BeanFactory这一支,DefaultListableBeanFactory还有另一条重要的继承线,来自于AliasRegistry实际上主要是BeanDefinitionRegistry。这条线赋予了它可以动态注册BeanDefinition进Factory的功能。
有了构造Factory的接口,自然而然会想到的就是谁来使用它呢?又是怎样使用的呢?
接着看main()方法第三行
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
将上面的factory对象拿去构造了一个XmlBeanDefinitionReader实例,而构造函数实际上是这样的:public XmlBeanDefinitionReader(BeanDefinitionRegistry registry)。也就是说这里只用到了DefaultListableBeanFactory的其中一条继承线上的特性——注册BeanDefinition。
在XmlBeanDefinitionReader的构造方法中,我们传进去了一个BeanDefinitionRegistry(同时也是ioc容器本身)。
具体来说,构造方法是这样的:
XmlBeanDefinitionReader.java
/**
* Create new XmlBeanDefinitionReader for the given bean factory.
* @param registry the BeanFactory to load bean definitions into,
* in the form of a BeanDefinitionRegistry//简而言之,传进来的registry就是最终要承载beanDefinition的容器
*/
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
而实际上在实例化过程中做了实事的是父类的构造方法
/**
* Create a new AbstractBeanDefinitionReader for the given bean factory.
* <p>If the passed-in bean factory does not only implement the BeanDefinitionRegistry
* interface but also the ResourceLoader interface, it will be used as default
* ResourceLoader as well. This will usually be the case for
* {@link org.springframework.context.ApplicationContext} implementations.
* <p>If given a plain BeanDefinitionRegistry, the default ResourceLoader will be a
* {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}.
* <p>If the passed-in bean factory also implements {@link EnvironmentCapable} its
* environment will be used by this reader. Otherwise, the reader will initialize and
* use a {@link StandardEnvironment}. All ApplicationContext implementations are
* EnvironmentCapable, while normal BeanFactory implementations are not.
* @param registry the BeanFactory to load bean definitions into,
* in the form of a BeanDefinitionRegistry
* @see #setResourceLoader
* @see #setEnvironment
*/
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// Determine ResourceLoader to use.
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {//没错,从 DefaultListableBeanFactory类图就可以看出,
//它并没有继承ResourceLoader接口,所以在這使用
//默认的PathMatchingResourcePatternResolver作为资源装载器
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// Inherit Environment if possible
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {//同样,DefaultListableBeanFactory也没有继承EnvironmentCapable接口,
//所以这里也使用默认的StandardEnviroment作为环境
this.environment = new StandardEnvironment();
}
}
初始化到這了就完成了,其实就做了两件事:
- 把registry绑定到reader上,作为后续解析出来的beanDefinition的承载器;
- 初始化resourceLoader和enviroment,后续才能从环境中读取Resource
然后就是第四行:
reader.loadBeanDefinitions(resource);
也很容易理解,就是从上面我们定义的"spring-context.xml"资源里,解析出定义bean的BeanDefinition实例,并把它保存到reader所绑定的registry里面。
通过类图,我们可以看到main()方法第四行所调用的loadBeanDeinitions(resource : Resource) : int 方法是在BeanDefinitionReader中定义的基础方法,入参为定义bean的资源,返回成功加载的beanDefinition的数量。 但是在这里,XmlBeanDefinitionReader没有直接在这个方法里实现加载功能,而是通过定义一个doLoadBeanDefinitions(inputSource : InputSource, resource : Resource) : int方法来为所有这些loadBeanDefinitions(Resource/String/Resource.../String...)装载方法服务——其中就有第四行所用的loadBeanDeinitions(resource : Resource) : int
XmlBeanDefinitionReader.java
/*添加一些资源修饰属性,包括此资源的字符集,
*编码类型等(虽然在这里最后实际上还是用了默认值)
*/
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
//这里的resourceCurrentlyBeingLoaded是线程变量,
//用来记录当前线程正在加载的Resource
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {//正在加载的Resource中包含当前资源,说明存在循环import
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//这里是将资源传给doLoadBeanDefinitions()进行真正的解析,
//但是笔者很好奇为什么要在这里把一个对象拆开为InputSource和Resource,
//直接把EncodeResource或者Resource传给下面的方法不就ok了么?
//总感觉这里这样的写法不够优雅.有哪位同学如果知道这样设计的原因麻烦告知下(mail:mr_djzhu@163.com)
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);//加载完成(或者失败)后,从正在加载资源集合中删除当前资源
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//正如XmlBeanDefinitionReader名字定义的那样,
//这是一个xml解析器(reader),所以固然要把输入的资源解析成可读的org.w3c.dom.Document
//但是这里不打算展开如何得到这个Document的过程,要提醒一下的就是这里的解析不仅仅做了解析xml的工作,
//还利用DTD或XSD对xml进行了校验.如果有同学深入研究可以注意一下.
Document doc = doLoadDocument(inputSource, resource);
//有了document,接下来要做的肯定就是读取它的信息并构造注册beanDefinition
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//获取BeanDefinitionDocumentReader,这里要注意一下别绕晕了,
//现在这个方法所在类本身是XmlBeanDefinitionDocumentReader,
//它是一个可以解析xml文件并注册相关definition的类(他可以解析xml资源文件本身得到Document);
//而BeanDefinitionDocumentReader接口只关心如何解析Document,实例化并注册beanDefinition.
//从这个角度可以把后者理解成一个简单的工具类.
//这里用到的是此接口的默认实现DefaultBeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//获取当前registry(IoC)容器已注册的BeanDefinition数量,当前第一次调用肯定就是0
int countBefore = getRegistry().getBeanDefinitionCount();
//实例化和注册beanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//获取此次注册新增的beanDefinition数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
然后解析Document的接力棒就传到了DefaultBeanDefinitionDocumentReader手中,继续往下看:
作为一个目的单纯的工具类,DefaultBeanDefinitionDocumentReader仅实现了一个DefinitionDocumentReader接口,这个接口也很只是单纯地定义了一个方法:
BeanDefinitionDocumentReader.java
/**
* SPI for parsing an XML document that contains Spring bean definitions.
* Used by {@link XmlBeanDefinitionReader} for actually parsing a DOM document.
* 实际上解析DOM Document的接口
*/
public interface BeanDefinitionDocumentReader {
/**
* Read bean definitions from the given DOM document and
* register them with the registry in the given reader context.
* @param doc the DOM document
* @param readerContext the current context of the reader
* (includes the target registry and the resource being parsed)
* @throws BeanDefinitionStoreException in case of parsing errors
*/
void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
throws BeanDefinitionStoreException;
}
DefaultBeanDefinitionDocumentReader.java
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
//保留了当前的delegate,实际上在这里就是null
BeanDefinitionParserDelegate parent = this.delegate;
//创建了一个委托类,由它去解析具体的某一个beanDefinition
this.delegate = createDelegate(getReaderContext(), root, parent);
//下面的代码主要为<beans>节点的profile属性服务,如果不是<beans>那就跳过此步骤
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles ["
+ profileSpec + "] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
preProcessXml(root);//解析前操作,在默认的实现中未做任何事情,如果子类想自定义前置方法,可覆写之
parseBeanDefinitions(root, this.delegate); //实际解析BeanDefinition
postProcessXml(root);//解析后操作,在默认的实现中未做任何事情,如果子类想自定义前置方法,可覆写之
//重置delegate(这里其实感觉有点多此一举,因为delegate本身是private变量,
//且没有提供任何方法可以set它的值,所以实际上它永远都是null.
//如有高人看到了如此设计的深意,请赐教mail:mr_djzhu@163.com)
this.delegate = parent;
}
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext,
Element root, BeanDefinitionParserDelegate parentDelegate) {
//默认的实现选用BeanDefinitionParserDelegate来解析,如果需要自定义的解析器,可覆写此方法
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root, parentDelegate);
return delegate;
}
/**
* Parse the elements at the root level in the document:
* "import", "alias", "bean". //解析root级别(即beans下来的一级)的元素
* @param root the DOM root element of the document
*/
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {//遍历所有节点
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
//如果是默认的节点则用parseDefaultElement()进行解析,
//默认的节点包括import,alias,bean和嵌套的beans
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate);
}
else {
//如果非默认节点,例如<context:annotation-config>,
//则需要用delegate自带的解析方法来解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
先来看看默认的节点是怎么解析的:
DefaultBeanDefinitionDocumentReader.java
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//bean节点比较简单,也比较有代表性,下面来详细看看
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//嵌套的beans节点,递归调用doRegisterBeanDefinitions()来解析它
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
* //真正到了解析注册的地方,分三步走:1.解析 2.装饰 3.注册
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//1.这里终于解析出了一个BeanDefinitionHolder,里面包含了BeanDefinition的全部信息以及一些冗余信息
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
//2.把上面的bdHolder做一层装饰
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
//3.将装饰过的bdHolder里面的BeanDefinition注册到registry里
BeanDefinitionReaderUtils
.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
解析注册BeanDefinition的最后三步走,一步一步来看:
第一步,解析:
BeanDefinitionParserDelegate.java
/**
* Parses the supplied {@code <bean>} element. May return {@code null}
* if there were errors during parse. Errors are reported to the
* {@link org.springframework.beans.factory.parsing.ProblemReporter}.
*/
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
/**
* Parses the supplied {@code <bean>} element. May return {@code null}
* if there were errors during parse. Errors are reported to the
* {@link org.springframework.beans.factory.parsing.ProblemReporter}.
*/
//containingBean指已存在的BeanDeinition,这里是null
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele,
BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);//获取bean-id
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//获取bean-name
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
//如果采用分割别名方式定义的bean-name属性,在这里把所有的别名解析出来
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr,
MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
//优先把bean-id属性赋值给beanName,如果没有id则取第一个aliases的值作为beanName
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) {
检查beanName和aliases是否跟当前register中已有的beanName冲突,
//如果不冲突则把其名字记录到this.usedNames : HashSet<String>中
checkNameUniqueness(beanName, aliases, ele);
}
//真正最后解析xml标签内属性的方法就在这里.方法创建了一个Entity用以
//保存从Document解析出来的BeanDefinition属性,具体方法实现比较直接也比较简单枯燥,
//这里就点到为止,不再深入这方面的细节.有兴趣的朋友可以自行研究.
//总而言之,通过这个方法我们就已经获取了一个BeanDefinition.
//尽管它叫Abstract-
AbstractBeanDefinition beanDefinition
= parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
//如果<bean>节点没有制定任何id或name属性,下面给他生成一个默认的名字
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);
//拼装BeanDefinitionHolder对象
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
第二步,装饰(省略)
第三步, 注册:
这里又用到了一个工具类:BeanDefinitionReaderUtils,这个类提供了一系列注册dbHolder到registry的静态方法
BeanDefinitionReaderUtils.java
/**
* Register the given bean definition with the given bean factory.
* @param definitionHolder the bean definition including name and aliases
* @param registry the bean factory to register with
* @throws BeanDefinitionStoreException if registration failed
*/
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
//看到这里实际上调用的还是registry本身的方法registerBeanDefinition(beanName,beanDefinition).
//如果你还记得前面的代码,应该知道我们这里用到的registry是DefaultListableBeanFactory.
//所以下面又要回到DefaultListableBeanFactory的registerBeanDefinition方法
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
DefaultListableBeanFactory.java
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap
= new ConcurrentHashMap<String, BeanDefinition>(256);
//---------------------------------------------------------------------
// Implementation of BeanDefinitionRegistry interface
//---------------------------------------------------------------------
@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");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
//先看看map中有没有同名beanDefinition
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {//不允许overriding beanDefinition,抛异常
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
//判断新的beanDefinition角色值要小于(才合法)旧的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 + "]");
}
}
//在实现equals方法时,会定义怎样的两个实例是相等的.如果两个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 + "]");
}
}
else {//排除完以上所有情况,认为这样的override是正常的,只打了一段debug日志
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
//把beanDefinition扔进map中
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {//下面只是一些更细节的操作,本质上就是把beanDefinitino扔进map里,没别的了.
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
至此,注册阶段完成.在registry(即我们这里的DefaultListableBeanFactory)实例中,已经有从xml读取进来的bean定义--beanDefinition
下面开始,main()方法的第五行,从registry中获取bean:
MyComponent component = factory.getBean("myComponent", MyComponent.class); //MyComponent是自己写的测试类
首先看到的是这里调用的方法是由BeanFactory接口定义,AbstractBeanFactory抽象类实现的. 类似实现的方法还有以下几个:
//---------------------------------------------------------------------
// Implementation of BeanFactory interface
//---------------------------------------------------------------------
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
会发现,所有的getBean()方法实现最终都是调用了doGetBean()方法,这里是从BeanFactory获取Bean的入口,也即是依赖注入的入口,所以在这里会涉及到Spring-IoC两种不同的Bean构造模式(单例和原型);防止循环定义Bean的判断;定义并保存bean创建状态等。这里我们撇开细节暂且不看,在我们这个简单的main()方法Demo中,只涉及到对一个简单单例Bean的第一次创建。所以,我们忽略细节,看看一个最普通的
bean是怎样被创建出来的:
AbstractBeanFactory.java
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//获取beanName
final String beanName = transformedBeanName(name);
Object bean;
// 获取单例实例
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
//省略代码...
//通过单例实例sharedInstance获取bean。注意这里有可能是bean本身;
//也有可能是通过sharedInstance生成的新的bean实例(当sharedInstance时一个FactoryBean的时候)
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
//如果当前目标bean属于正在创建的原型模式的bean,我们认为这是循环定义bean,抛异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
//下面的代码负责判断父beanFactory不为空,且当前factory中没有制定的bean,
//则将创建bean的工作委托给父beanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
//把beanName写入alreadyCreated : Set<String>标记为已创建
markBeanAsCreated(beanName);
}
try {
//A root bean definition represents the merged bean definition that backs
//a specific bean in a Spring BeanFactory at runtime. It might have been
//created from multiple original bean definitions that inherit from each other,
//typically registered as GenericBeanDefinitions.
//A root bean definition is essentially the 'unified' bean definition view at runtime.
//以上是javadoc中对RootBeanDefinition的定义:一句话总结就是运行时唯一的beanDefinition。
//因为我们有可能在彼此为继承关系的若干个BeanFactory中注册多个同名的bean,
//通过此方法可以对这种情况做一定的处理,此处暂不深入
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查mbd,在当前类的实现当中只判断了对应的bean指向的类不能为abstract
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
//...遍历当前bean,确保所有依赖的bean都被初始化
}
}
// Create bean instance.
if (mbd.isSingleton()) {//单例模式,这是我们重点分析的
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {//构造一个工厂来生产bean
@Override
public Object getObject() throws BeansException {
try {
//实际上最终调用的还是AbstractBeanFactory抽象类中定义的createBean方法
//而当前实现此抽象方法的是AbstractAutowireCapableBeanFactory,
//下面接着看AbstractAutowireCapableBeanFactory
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;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
//省略代码...
//当scope既非singleton也非prototype时,做特殊的初始化
}
catch (IllegalStateException ex) {
//省略代码...
}
}
}
catch (BeansException ex) {
//创建失败,将beanName从alreadyCreated去除
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
}
AbstractAutowireCapableBeanFactory.java
//---------------------------------------------------------------------
// Implementation of relevant AbstractBeanFactory template methods
//---------------------------------------------------------------------
/**
* Central method of this class: creates a bean instance,
* populates the bean instance, applies post-processors, etc.
* 创建bean实例,调用后置方法的核心入口
* @see #doCreateBean
*/
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// Make sure bean class is actually resolved at this point, and
// clone the bean definition in case of a dynamically resolved Class
// which cannot be stored in the shared merged bean definition.
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
//省略代码...
//准备和校验方法覆盖
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
//这里主要判断bean有没有配置前置/后置处理器,如果有,则返回一个代理对象
//resolveBeforeInstantiation的javadoc : Apply before-instantiation post-processors,
//resolving whether there is a before-instantiation shortcut for the specified bean.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
//正式创建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
AbstractAutowireCapableBeanFactory.java
/**
* Actually create the specified bean. Pre-creation processing has already happened
* at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
* <p>Differentiates between default bean instantiation, use of a
* factory method, and autowiring a constructor.
* 正式创建bean实体,Pre-creation已经在上一个方法中被执行了
* 这里只处理通过工厂方法或者构造函数创建bean的情况。
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a new instance of the bean
* @throws BeanCreationException if the bean could not be created
* @see #instantiateBean
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//没有任何缓存,在这里创建bean实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
// Allow post-processors to modify the merged bean definition.
//post-processors处理,如果有定义的话。我们这里没定义,所以忽略
//忽略代码...
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//处理循环依赖问题,这里没有这样的情况
//忽略代码...
// Initialize the bean instance. //bean实例初始化
Object exposedObject = bean;
try {
//填充beanDefinition中定义的properties到BeanWrapper中
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//Initialize the given bean instance,
//applying factory callbacks as well as init methods and bean post processors.
//调用factory回调方法,调用bean post-processors等。这里暂且忽略
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);
}
}
//还是循环依赖的问题,代码没跑到这里同样先忽略(这里忽略的东西有点多... 回头得补上)
//忽略代码...
// Register bean as disposable.
//根据不同的scope把创建出来的bean实例放到处理标记为已处理的bean的缓存池。
//比如这里scope=singletons,则把bean放到当前registry的disposableBeans : Map<String:Object>中
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
doCreateBean方法本身非常庞杂,处理了包括创建BeanWrapper,post-processors处理,填充properties,处理循环依赖等问题。但罗马非一日建成,代码也不需要一天看完,我们暂且刨去一些高级的“细枝末节”,只关注创建beanWrapper的核心方法,其实就只有一个:
instanceWrapper = createBeanInstance(beanName, mbd, args);//真实创建beanWrapper的方法
AbstractAutowireCapableBeanFactory.java
/**
* Create a new instance for the specified bean, using an appropriate instantiation strategy:
* factory method, constructor autowiring, or simple instantiation.
* 创建一个bean实例,可用的实例化策略有:factory method,constructor autowiring
* 和 simple instantiation.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return BeanWrapper for the new instance
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
* @see #instantiateBean
*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// Make sure bean class is actually resolved at this point.
//获取bean所定义的类
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//首先判断指定的类是public,且有public的构造函数
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers())
&& !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
if (mbd.getFactoryMethodName() != null) {
//如果beanDefinition中有定义factoryMethod,则按照工厂策略来创建bean,这里显然不是
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
//面对多次创建同一个bean实例,这里会直接通过缓存中的构造方法来创建,这里第一次创建,忽略之...
//省略代码...
// 当指定构造方法的入参为非空时,需要从一众构造方法中选择一个,
//这里我们使用没有入参的默认构造函数,所以也忽略之...
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
//最后是我们需要的,使用没有传入参数的构造方法
return instantiateBean(beanName, mbd);
}
AbstractAutowireCapableBeanFactory.java
/**
* Instantiate the given bean using its default constructor.
* 使用默认的构造函数创建bean实例
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @return BeanWrapper for the new instance
*/
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {//如有必要,做安全校验,这里没有
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
}, getAccessControlContext());
}
else {
//首先获取了当前registry的实例化策略实例,然后传参进去实例化bean。
//注意当前registry默认使用的策略是new CglibSubclassingInstantiationStrategy(),
//而它继承了SimpleInstantiationStrategy类,
//实际上我们使用的还是SimpleInstantiationStrategy.instantiate()
//只有在我们需要通过cglib创建代理类时(比如aop机制)才会用到前者
//这里继续看后者的instantiate()方法
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
//利用创建出来的纯粹bean实例封装成BeanWrapper。
//可能有同学会好奇,既然有了bean还需要BeanWrapper做什么呢?答案是初始化bean属性。还记得前面的
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (bd.getMethodOverrides().isEmpty()) {//没有override方法
//注意这里是java.lang.reflect.Constructor,也就是说控制权到了java底层反射机制手中
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();//获取BeanDefinition中的Class
if (clazz.isInterface()) {
//如果class是一个借口,那么没戏了,不能用java默认的反射机制来创建实例
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {//有权限控制,那就判断权限
constructorToUse = AccessController
.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
@Override
public Constructor<?> run() throws Exception {
//在这里获取无入参的构造方法
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
//在这里获取无入参的构造方法
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
//把构造方法写入BeanDefinition的缓存中,以后再实例化这个bean就可以跳过获取构造方法的步骤了
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
//利用构造方法创建实例。实际上BeanUtils.instantiateClass还可以接受入参,它是这样定义的:
//public static <T> T instantiateClass(Constructor<T> ctor, Object... args)
//这里创建的是空参数的实例
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
//有override方法,就需要通过可供子类覆写的方法instantiateWithMethodInjection来实例化
//这里子类就是CglibSubclassingInstantiationStrategy
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
再往下深入就是BeanUtils.instantiateClass()方法利用java的反射机制创建实例的过程。本文就不再深入了,到这里。我们就把spring创建bean的过程大致地过了一遍。有了这样的一个框架式的印象,如果我们需要深入了解spring的某一个具体特性,就可以再回到某一个代码的细节处,继续研究。这在稍后的文章中会举一些例子来介绍。
以上。