题外话:学java 就要看源码,为什么要看源码?可以从中学到各位大佬的思想啊,看看大佬们是怎么写代码的?哈哈,谁TM想看源码啊,还不是被逼的!!!因为要打怪升级啊!@#¥%……&*
说重点,这篇文章分析下我们熟悉的优秀springFramework框架是怎么加载bean和管理bean的~
————————————————
在开始之前,先看一下这篇文章大概会涉及到的内容,如有不清晰的地方后续补充完善,我用思维导图展示一下
引入案例
首先,我们我们知道spring加载bean有两种方式,一种是通过beanFactory类,另外一种是我们常用的ApplicationContext,我们先以基本的BeanFactory来获取bean。
定义一个bean类
public class Person {
private String name = "wuxiaojun";
private int age ;
//省略get/set...
}
定义资源文件 beanFactoryTest.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<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
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="person" class="org.springframework.wmj.Person" />
</beans>
测试类MyBeanFactoryTest.java
@SuppressWarnings("deprecation")
public class MyBeanFactoryTest {
@Test
public void testSimpleLoad() {
//1、beanFactory
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(
"wmjbeans/beanFactoryTest.xml"));
Person person = (Person) beanFactory.getBean("person");
assertEquals("wuxiaojun", person.getName());
System.out.println("beanFactory===>"+person.getName());
/*
//2、ApplicationContext
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
"wmjbeans/beanFactoryTest.xml");
Person person = (Person) ctx.getBean("person");
assertEquals("wuxiaojun", person.getName());
System.out.println("ClassPathXmlApplicationContext===>"+person.getName());
*/
}
}
一、第一部分
Spring加载bean是一个相当复杂的过程,这里我把它拆分两个部分,分别从加载配置到内存中,和加载Bean两个部分进行讲起。
1、读取配置文件
执行上面案列中testSimpleLoad方法,spring就两句代码,具体干了什么事?我们不妨先通过时序图,通过整体来把控全局,或许稍微容易理解一些(可能第一遍完全看不懂,结合代码多看几遍),我们从new XmlBeanFactory说起,下面是该过程执行的时序图:
Spring核心都在定义的xml文件中,首先肯定要拿到对应的xml资源文件new ClassPathResource(“beanFactoryTest.xml”)得到resource对象。跟踪进去看看代码里面写了什么
public XmlBeanFactory(Resource resource) throws BeansException {
//调用自身构造函数
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
//再次调用父类构造函数
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
主要做一件事,就是通过资源文件来加载BeanDefinitions,在这里我们看见上图中的loadBeanDefinitions了,下面再结合时序图看看XmlBeanDefinitionReader类中loadBeanDefinitions具体做了什么
通过图我们知道,方法最终目的是为了得到BeanDefinition,我们结合下面代码
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//对resource进行编码,通过返回编码后的resource对象
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
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());
}
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();
}
}
}
代码逻辑还算清晰,首先对resource进行编码,然后将编码后的encodedResource作为参数继续调用loadBeanDefinitions(EncodedResource encodedResource),在这个方法里,忽略异常捕获信息的话,只做了一件事,就是通过encodedResource获取资源inputStrea,根据inputStrea得到inputSource,如果有主动对encodedResource有设置编码的话,就是用我们设置的编码。但是很遗憾,并没有我们想要看的结果,最终通过doLoadBeanDefinitions方法干活去了~
看看doLoadBeanDefinitions做了什么事
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//根据资源文件获取xml的document文档
Document doc = doLoadDocument(inputSource, resource);
//注册BeanDefinitions,返回注册成功的definitions个数
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}catch{
//省略异常捕获信息...
}
}
是的,这个方法又没干活,只讲具体的干活的分派给另外两个方法,结合我的注释应该很好理解,下面来我们逐一分析,先看doLoadDocument(inputSource, resource)如何加载doc的
2、获取Document对象
直接进入doLoadDocument()方法
/**
* Actually load the specified document using the configured DocumentLoader.
* @param inputSource the SAX InputSource to read from
* @param resource the resource descriptor for the XML file
* @return the DOM Document
* @throws Exception when thrown from the DocumentLoader
* @see #setDocumentLoader
* @see DocumentLoader#loadDocument
*/
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
该方法中有两点要注意,首先是通过 getEntityResolver() 获取到参数EntityResolver,何为EntitiResolver?官网这样解释:如果SAX应用程序需要实现自定义处理外部实体,则必须实现此接口并使用setEntityResolver方法向SAX驱动器注册一个实例。也就是说,对于解析一个XML,SAX首先读取该XML文档上的声明,根据声明去寻找相应的DTD定义,以便对文档进行一个验证。默认的寻找规则,即通过网络(实现上就是声明的DTD的URL地址)来下载相应的DTD声明,并进行认证。下载的过程漫长,而且当网络中断或不可用的时候,这里会报错,就是因为相应的DTD声明没有被找到的原因。
因为本编具体只分析Spring-bean相关内容,这里暂不具体分析XML文档结构相关知识,在这我们只要知道定义一个XML有DTD和XSD两种声明方式就ok了,可以了解下DTD和XSD相关知识。
其次,getValidationModeForResource(resource) 就是用来获取XML的验证模式的,具体如何获取,是通过读取XML文件,查看XML内容中是否包含XSD或者DTD来判断XML的验证模式,这部分代码比较简单,就不贴了
我们具体看看document是如何被加载的,跟踪到DefaultDocumentLoader类中去
/**
* Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
* XML parser.
*/
@Override
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isTraceEnabled()) {
logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
这里并没有特别之处,Spring首先创建DocumentBuilderFactory,再通过DocumentBuilderFactory创建DocumentBuilder,进而解析inputSource来返回Document对象。
3、注册BeanDefinition
得到document对象后,我们就可以根据document来获取注册BeanDefinitions了,我们再次回到registerBeanDefinitions(doc, resource)方法中
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//通过反射创建一个documentReader实例
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//获取注册前的BeanDefinition个数
int countBefore = getRegistry().getBeanDefinitionCount();
//注册BeanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//返回此次注册的BeanDefinition的个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
这个方法很简单,根据注释也都能看明白,我们主要看看第三步注册BeanDefinition,
BeanDefinitionDocumentReader 是个接口,其子类实现在DefaultBeanDefinitionDocumentReader类中,在这个类中我们来寻找答案
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
@SuppressWarnings("deprecation") // for Environment.acceptsProfiles(String...)
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
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.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//注册前置处理
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
//注册后置处理
postProcessXml(root);
this.delegate = parent;
}
一大段代码,我们只关心的只有最后面三行,前面一大串是Spring对Profile的支持,Profile是Spring用来针对不同环境对不同的配置提供支持的,这里不具体分析,大家可以谷歌一下“profile配置”了解。
看了源码发现preProcessXml(root);和postProcessXml(root);这两句方法里面是空的,什么也没有,有人认为这是多余的两句代码,其实不然。这里正是体现Spring作为一个开放式架构的优秀之处,他可以提供给开发者自由的拓展功能,在有必要的时候继承DefaultBeanDefinitionDocumentReader类,重写这两个方法,提供我们自定义的功能。
我们看看核心方法 parseBeanDefinitions(root, this.delegate)
/**
* Parse the elements at the root level in the document:
* "import", "alias", "bean".
* @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;
if (delegate.isDefaultNamespace(ele)) {
//解析默认标签
parseDefaultElement(ele, delegate);
}
else {
//解析自定义标签
delegate.parseCustomElement(ele);
}
}
}
}
else {
//解析自定义标签
delegate.parseCustomElement(root);
}
}
在Spring的配置文件中,有我们常见的一些标签,比如:import、alias、bean、beans,再或者如果我们使用了自己定义的一别标签,比如:s:person、s:age、s:name,当然使用自定义标签时,需要在xml文档中加上我们自己的命名空间。
这个方法里,就是对Spring使用到的标签的解析,我们就看默认标签的解析
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);//解析import标签
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);//解析alias标签
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);//解析bean标签
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
doRegisterBeanDefinitions(ele);//解析beans标签
}
}
默认标签的解析分为import、alias、bean、beans;对于beans标签及配置文件的最高父标签,采用深度优先遍历的方式,再次进入parseBeanDefinitions方法中进入解析。
这里只分析较为复杂的bean标签的解析,其他的标签类似
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 对bean标签的默认属性和子标签进行处理,将其封装为一个BeanDefinition对象,并放入BeanDefinitionHolder中
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
// 进行自定义属性或自定义子标签的装饰
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 注册当前的BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 调用注册了bean标签解析完成的事件处理逻辑
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
这里我们直接进入BeanDefinitionParserDelegate.decorateBeanDefinitionIfRequired()方法中:
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) {
BeanDefinitionHolder finalDefinition = definitionHolder;
// 处理自定义属性
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
// 处理自定义子标签
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
可以看到,自定义属性和自定义子标签的解析都是通过decorateIfRequired()方法进行的,如下是该方法的定义:
public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
// 获取当前自定义属性或子标签的命名空间url
String namespaceUri = getNamespaceURI(node);
// 判断其如果为spring默认的命名空间则不对其进行处理
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
// 获取当前命名空间对应的NamespaceHandler对象
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) {
// 对当前的BeanDefinitionHolder进行装饰
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {
return decorated;
}
}
else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
}
else {
// A custom namespace, not to be handled by Spring - maybe "xml:...".
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}
decorateIfRequired()方法首先会获取当前自定义属性或子标签对应的命名空间url,然后根据该url获取当前命名空间对应的NamespaceHandler处理逻辑,并且调用其decorate()方法进行装饰,如下是该方法的实现:
@Nullable
public BeanDefinitionHolder decorate(
Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
// 获取当前自定义属性或子标签注册的BeanDefinitionDecorator对象
BeanDefinitionDecorator decorator = findDecoratorForNode(node, parserContext);
// 调用自定义的BeanDefinitionDecorator.decorate()方法进行装饰
return (decorator != null ? decorator.decorate(node, definition, parserContext) : null);
}
如下是findDecoratorForNode()的实现
@Nullable
private BeanDefinitionDecorator findDecoratorForNode(Node node, ParserContext parserContext) {
BeanDefinitionDecorator decorator = null;
// 获取当前标签或属性的局部键名
String localName = parserContext.getDelegate().getLocalName(node);
// 判断当前节点是属性还是子标签,根据情况不同获取不同的Decorator处理逻辑
if (node instanceof Element) {
decorator = this.decorators.get(localName);
}
else if (node instanceof Attr) {
decorator = this.attributeDecorators.get(localName);
}
else {
parserContext.getReaderContext().fatal(
"Cannot decorate based on Nodes of type [" + node.getClass().getName() + "]", node);
}
if (decorator == null) {
parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionDecorator for " +
(node instanceof Element ? "element" : "attribute") + " [" + localName + "]", node);
}
return decorator;
}
对于BeanDefinitionDecorator处理逻辑的查找,可以看到,其会根据节点的类型进行判断,根据不同的情况获取不同的BeanDefinitionDecorator处理对象。
历经千辛万苦,我们终于封装了一个BeanDefinition对象,接下来回到上文中的processBeanDefinition()方法中可以注册BeanDefinition了,下来就好理解了,注册完成通知解析完成的事件处理监听器发出通知。
分析了这么多,我们先来小结一下,以上过程中,无非分为三个阶段
1. 读取配置文件
2. 获取xml的验证模式,并根据验证模式得到document文档对象
3. 解析spring标签,注册beanDefinition
是的,以上只是完成了基本的资源文件的读取,和beanDefinition的注册,也就是执行完new XmlBeanFactory("resource”)后Spring干的事。
二、第二部分
这里开始,将要进入重点bean的加载部分,即代码 Person person = (Person) beanFactory.getBean(“person”) 的逻辑…你,准备好了吗!!
好了,直接上代码
AbstractBeanFactory.java
//---------------------------------------------------------------------
// Implementation of BeanFactory interface
//---------------------------------------------------------------------
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
/**
* Return an instance, which may be shared or independent, of the specified bean.
* @param name the name of the bean to retrieve
* @param requiredType the required type of the bean to retrieve
* @param args arguments to use when creating a bean instance using explicit arguments
* (only applied when creating a new instance as opposed to retrieving an existing one)
* @param typeCheckOnly whether the instance is obtained for a type check,
* not for actual use
* @return an instance of the bean
* @throws BeansException if the bean could not be created
*/
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 1、转换提取对应的beanName
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//2、尝试从缓存中加载单例
Object sharedInstance = getSingleton(beanName);
//3、得到 bean 的实例 beanInstance
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//返回对应的实例,有时候存在诸如BeanFactory的情况并不是直接返回实例本身而是返回指定方法返回的实例
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 4、原型模式的依赖检查
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
//5、检测parentBeanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
//如果BeanDefinitionMap中也就是已经加载的类中不包括beanName则尝试从parentBeanFactory 中检测
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);
}
//递归到BeanFactory中寻找
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);
}
}
//如果不是仅仅做类型检查则是创建bean,这里要进行记录
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 6、转换成RootBeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 7、寻找依赖 优先加载依赖的bean
String[] dependsOn = mbd.getDependsOn();
//若存在依赖的bean则需要递归实例化依赖的bean
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);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
// 8、根据不同的scope 准备创建 bean
// 单列bean
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
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);
}
// 原型 bean(new一个)
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);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 其他Scope类型的bean(Request、Session、Global session)
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 {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
// // 9、类型转换 检查需要的类型是否符合bean的实际类型,如果不符合需要进行类型转换
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
不看不知道,一看 原来Spring就一句getBean,就做了这么多事!~
结合我的注释,可以将上面加载bean的逻辑大概划分为9个步骤,下面依次来讲下这9个小步骤。
老规矩,代码太多,容易绕晕,我们还是先从整体来把握,来明确我们最后想要的结果。我们先来看下整个getBean的逻辑时序图。
结合时序图,再一步一步分析代码。
1、 转换对应beanName
也许有人不理解对应的beanName是什么意思,传入参数name不就是beanName吗?其实不是,这里传入参数name也有可能是别名,也有可能是FactoryBean,所以需要一系列的解析。解析如下:
//AbstractBeanFactory.java
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
/*
BeanFactoryUtils.java
去除BeanFactory修饰符,也就是如果name=“&aa”,首先去除& 而使name=“aa”
*/
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
/*
SimpleAliasRegistry.java
取指定的alias所表示的最终beanName,如别名A指向B的bean,则返回B,若别名A指向别名B,别名B又指向C的bean,则返回C
*/
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
2、从缓存中加载单例
单例在Spring同一个容器中只会被创建一次,后续再获取bean,就直接从单例缓存中获取。这里也是尝试加载,如果加载不成功再次尝试从singletonFactories中加载。因为在创建单列bean的时候会存在依赖注入,而在创建依赖的时候为了避免循环依赖,在Spring中创建bean的原则是不等bean创建完就会将创建的bean的ObjectFactory提早曝光到缓存中,一旦下一个bean创建的时候需要依赖上一个bean则直接使用ObjectFactory。(这里涉及到循环依赖相关的知识点,有空我也整理一下相关知识)
//DefaultSingletonBeanRegistry.java
@Override
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
这里因为涉及到循环依赖的检测,会涉及到许多变量的存储。先解释一下方法的大概内容,首先尝试从singletonObjects里获取实例,获取不到的话再从earlySingletonObjects里获取,如果还是获取不到,在尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后再调用ObjectFactory的getObject来创建bean,并放到earlySingletonObjects里面去,同时从singletonFactories里面remove掉这个ObjectFactory。
这里涉及到存储bean的不同map,可能有点崩溃,大致各map存放的bean如下:
- singletonObjects:保存BeanName和创建bean实例之间的关系,ben name–>bean instance
- singletonFactories:保存beanName和创建bean工厂之间的关系,ben name–>ObjectFactory
- earlySingletonObjects:也是保存beanName和创建bean实例之间的关系,与>singletonObjects不同在于,当一个单例bean被放到这里面之后,那么当bean还在创建>过程中,就可以通过getBean方法获取到了,其目的是用来检测循环依赖。
- registeredSingletons:用来保存当前所有已注册的bean
3、bean的实例化
如果从缓存中得到bean的原始状态,则需要对bean进行实例化。这里说明一下,缓存中记录的只是原始bean的状态,并不是我们最终想要的bean。例如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法中返回的bean。
也就是说,我们得到bean的实例后要做的第一件事就是调用这个方法来检测一下正确性,其实就是检测当前的bean是否是FactoryBean类型的bean,如果是,那么就该调用对应的FactoryBean实例中的getObject()作为返回值。而getObjectForBeanInstance就是完成这个工作的。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
//若name是工厂相关(以&为前缀)
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
//且又不是FactoryBean类型,则校验不通过
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
}
//现在我们有了bean实例,这个实例可能是正常的bean或者是FactoryBean
//如果是FactoryBean,我们使用它创建实例,
//但如果用户想要直接获取工厂实例而不是工厂的getObject方法对应的实例,那么传入的name应该加前缀&
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
//加载FactoryBean
Object object = null;
if (mbd == null) {
//先尝试从缓存中加载
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 经过上面判断我们知道这个beanInstance一定是FactoryBean类型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
//将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition
//如果指定beanName是子bean的话同时合并父类相关的属性
mbd = getMergedLocalBeanDefinition(beanName);
}
//是否用户定义的而不是程序本身定义的
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
我们梳理一下上面代码:
1)对FactoryBean正确性进行验证
2)对非FactoryBean不做任何处理
3)对bean进行转换
4)将从Factory中解析bean的工作委托给 getObjectFromFactoryBean方法了
这就是上面代码的逻辑,无非是多了一些辅助判断,下面我们看看getObjectFromFactoryBean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
//单例模式
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
//标记singletonBean正在创建中
beforeSingletonCreation(beanName);
try {
//调用ObjectFactory的后处理器
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
//将标记singletonBean正在创建中的状态移除
afterSingletonCreation(beanName);
}
}
//放到缓存中去
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
在这个方法里,我们还是没有看到想要的代码,这里似乎只做了一件事如果返回的bean是单例,就要保证全局唯一,同时也因为单例,不必重复加载,可以使用缓存来提高性能,就是将加载过的bean放进缓存,方便下次调用。我们到委托的doGetObjectFromFactoryBean方法里去看看
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
//需要权限验证
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
//直接调用getObject
object = factory.getObject();
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
这里我们终于看到那句代码 object = factory.getObject(); 是的,就是它。
讲到这里,有点需要注意下,在getObjectFromFactoryBean方法中,当执行完object = doGetObjectFromFactoryBean(factory, beanName);后,就已经得到我们想要的结果了,那下面还有一大串代码是干嘛的,通过注释我们知道是对ObjectFactory的后处理器,对于Spring的后处理器,大概意思是在Spring获取bean后,尽可能的保证初始化后都会调用注册的BeanPostProcessor的postProcessAfterInitialization方法进行处理,在实际的开发中我们可以针对此对自己的特殊业务进行设计,这不也即就是Spring的高明之处吗,说他是可扩展的优秀框架也不为过!(面向对象的设计)
4、原型模式的依赖检查
只有在单例情况下才会尝试解决循环依赖,如果A中有B的属性,B中有A的属性,那么当依赖注入的时候,会产生当A还未创建完成的时候因为对于B的创建再次返回创建A造成循环依赖,也就是isPrototypeCurrentlyInCreation(beanName)的判断为true。
这里会涉及到Spring中循环依赖的知识点,对于循环依赖,Spring分以下两种情况
- 构造器循环依赖,这种依赖是无法解决的,只能通过抛出异常来处理
- setter循环依赖,可以处理
当然,对依赖的处理只是限于单例的情况下,对原型模式的bean,spring是无法解决的,所以才有了这一步骤,对原型模式的依赖检查。
5、检测parentBeanFactory
从代码上看,如果缓存中没有数据的话,直接转到父类工厂上去加载,这是为什么呢?
看看判断条件:parentBeanFactory != null && !containsBeanDefinition(beanName)。parentBeanFactory 为空,则其他都是浮云,这个没什么可说,但是!containsBeanDefinition(beanName)就 比较重要,他是在检查如果当加载的XML配置文件中不包含beanName所对应的配置,就只能到parentBeanFactory 去尝试加载,然后再去递归调用getBean方法。
6、转换成RootBeanDefinition
将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition。
因为从XML配置文件中读取到的Bean信息是存储在GenericBeanDefinition中的,所有的Bean后续处理都是针对于RootBeanDefinition,所以这里需要进行转换,同时,如果父类bean不为空的话,则会一并合并父类的属性。
7、寻找依赖
因为bean的初始化过程很可能会用到某些属性,而某些属性很可能是动态配置的,且配置成依赖于其他的bean,那么这个时候就有必要先加载依赖的bean,所以在Spring加载Bean中,在初始化某一个bean的时候会先初始化这个bean所对应的依赖。
8、针对不同的scope进行bean的创建
在Spring中存在着不同的scope,默认的scope是single,但是还有些其他的如prototype、request之类的,在这里,Spring会根据不同的scope配置进行初始化策略。
8.1获取单例bean
经过在前面的分析,我们已经知道Spring获取一个单例bean会先从缓存中获取,但是若缓存中不存在,那么就要从头开始加载了,而Spring使用getSingleton的重载方法实现了bean的加载过程。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
//同步全局变量
synchronized (this.singletonObjects) {
//首先检查对应的bean是否已经加载过,因为singleton模式其实就是复用以创建的bean
Object singletonObject = this.singletonObjects.get(beanName);
//如果为空才进行singleton的bean的初始化
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 {
//初始化bean
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;
}
}
以上代码中实际上是创建获取bean前后做的一些准备及处理操作,而正真获取单例bean其实是在用回调方法中实现的,其实现逻辑在ObjectFactory类的singletonFactory中实现的。我们先来看看上面代码大致做了哪些内容:
1)检查缓存是否已经加载过
2)若没有加载,则记录beanName的正在加载状态
3)加载单例前记录bean正在加载的状态
这一步是在beforeSingletonCreation方法中实现的,跟踪进去,貌似方法中什么也没做,实际上不是的,之所以这样想,实际上你可能忽略了this.singletonsCurrentlyInCreation.add(beanName)这句代码,是的,正是这句话,将当前bean正在加载的状态记录到了singletonsCurrentlyInCreation中。protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && >!this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
4)通过调用参数传入的ObjectFactory的个体Object方法实例化bean
4)通过调用参数传入的ObjectFactory的个体Object方法实例化bean
5)加载单例后的处理方法
同步骤3一样,当bean加载结束后也要记录bean加载完成的状态,实际上就是从缓存中将正在加载bean的状态移除掉,即 if 条件中this.singletonsCurrentlyInCreation.remove(beanName)所做的事。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过程中所记录的各种辅助状态
protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } }
7)返回处理结果
以上就是加载bean的整体逻辑,但是我们还没有开始对bean加载功能开始探索,我们下面开始看看回调中的创建bean是怎么回事!先回顾一下之前的定义,也就是ObjectFactory中的createBean方法,这里才是核心。
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;
}
});
8.2、准备创建bean
跟踪了这么多Spring的代码,我们发现一个规律,在函数中真正干货的方法其实都是以do开头的,在这里似乎也不例外,createBean只是提供了一个入口,不过我们可以先看看这里做了哪些事。
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
//锁定class,根据设置的class属性或者根据className来解析class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
//准备以及验证覆盖方法
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// 给BeanPostProcessors一个机会来返回代理来替代真正的实例
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);
}
try {
// 我们要关注的方法 创建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
代码量不是很多,大致说明下步骤
1)根据设置的class属性或者根据className来解析Class
2)对override属性进行标记及验证
3)应用初始化的前后处理器,解析指定bean是否存在初始化前的短路操作
4)创建bean
我们不指望能在一个方法中完成所有复杂逻辑,上面代码中我们重点关注第4步doCreateBean方法中bean的创建,其他步骤大家有兴趣可以看下代码了解。
8.3、创建bean
做了前面的准备之后,这里才开始对bean进行创建,一起看下下面复杂的代码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable 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.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;
}
}
// 是否需要提早曝光条件:单例 & 允许循环依赖 & 当前bean正在创建中
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");
}
//为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//对bean进行属性填充,将各个属性值注入,其中,可能存在依赖于其他的bean的属性,则会递归初始化bean
populateBean(beanName, mbd, instanceWrapper);
//调用初始化方法,比如init-method
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);
//earlySingletonReference 只有在检测到循环依赖的情况下才会不为空
if (earlySingletonReference != null) {
//如果exposedObject 在初始化方法中没有被改变,也就是没有被增强
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);
}
}
// 因为bean创建后,其所依赖的bean一定是创建的
// actualDependentBeans不为空则表示当前bean创建后其依赖的bean却没有全部创建完成
// 也就是说存在循环依赖
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 " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
// 根据 scope 注册 bean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
之所以说它是一段复杂的代码,是因为这一部分最为关键,还是老规矩,看看整个函数的概要思路,整个过程大概可以分为八步:
1)如果是单例,则首先要清除缓存(remove)
2)实例化bean,将BeanDefinition转换为BeanWrapper
3)MergedBeanDefinitionPostProcessors的应用(抱歉,这一步我还没搞懂,留个标记,日后回来看看)
4)依赖处理
在Spring中会有循环依赖的情况,例如,A中有B的属性,而B中又含有A属性时,就会构成一个循环依赖。Spring在处理循环依赖的时候,是通过中间缓存来解决的,并且Spring只解决单例中的循环依赖
5)属性填充,将所有的属性填充到bean中实例中
6)循环依赖检查
上面提到,Spring中只解决单列中的循环依赖,而对于prototype的bean,Spring没有解决,能做的就是抛出异常。
7)注册DisposableBean
如果配置了destory-methd,这里需要注册以便于在销毁bean的时候调用
8)完成创建并返回
这里 由于 加载实例化bean过于复杂,也比较重要,为了突出重点,我就单独在另外一篇博文中做详细介绍:Spring源码阅读▶㈡bean的实例化,这里不再赘述。
9、类型转换
当走到这里返回bean基本已经结束了,通常对该方法的调用参数requiredType是为空的,但是也有可能存在这样的情况。返回的bean是String,但是requiredType是Integer类型,那么这时候类型转换就起作用了,他的功能是将返回的bean转换为requiredType所对应的类型。
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
//类型转换
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
代码就是这些,有点复杂,还是要多看~
————————————————————————————————
(完)