从Spring源码看Spring是如何实现HelloWorld

很多人想读Spring的源码都不知道从何看起,我个人的观点,大家知道我们学习一门语言的时候,都是开始于HelloWorld的编写,我觉的Spring的学习也可以开始于最简单的HelloWorld。

Spring实现HelloWorld

直接上代码

首先我们需要一个HelloWorld的实体类:

package org.xiomanixi.spring.analyse.bean;

/**
 * @program: spring_analyse
 * @description: Spring实现HelloWorld
 * @author: xiaomanixi 小码blog
 * @create: 2020-05-10 21:35
 **/

public class HelloWorld {
    private static final String HELLO_WORLD = "Hello World !";

    public String getHelloWorld(){
        return HELLO_WORLD;
    }
}

然后需要配置一个xml文件,用来配置bean:

<?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.xsd">

    <bean name="helloWorld" class="org.xiomanixi.spring.analyse.bean.HelloWorld"></bean>
</beans>

 最后需要一个测试类,我们通过xml来构造bean:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.xiomanixi.spring.analyse.bean.HelloWorld;

/**
 * @program: spring_analyse
 * @description: Spring实现HW测试类
 * @author: xiaomanixi 小码blog
 * @create: 2020-05-10 21:42
 **/

public class HelloWorldTest {

    public static void main(String[] args) {
        //读取xml配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("/hello_world.xml");

        //读取配置好的Bean
        HelloWorld helloWorld = (HelloWorld)context.getBean("helloWorld");

        //执行对象方法
        System.out.println(helloWorld.getHelloWorld());
    }
}

如果你是一个Java小白,会使用Spring就足够了,但是如果你是个Java爱好者,想要提升自己,谋求更好的发展,你就要好好研究一下这段代码了。

根据上面的实例,我们可以提出两个问题:

  1. ApplicationContext context = new ClassPathXmlApplicationContext("/hello_world.xml") 容器创建的时候做了什么?
  2. getBean 是如何实现的?

没错,其实就是Spring是如何构造容器并获取到对象的?我们来分析一下Spring的源代码。

ClassPathXmlApplicationContext源码解析

 首先来看ClassPathXmlApplicationContext的类继承关系,这样我们会有一个宏观的认识:

怎么查看ApplicationContext的构造过程呢,对于复杂的实现,最好的办法就是debug断点调试来看完整的执行路径。

ClassPathXmlApplicationContext构造器源码,断点调试进入AbstractXmlApplicationContext类

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}

public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}

这个方法的注释是: Create a new ClassPathXmlApplicationContext, loading the definitions from the given XML file and automatically refreshing the context. 创建一个xml上下文路径,加载路径,并自动刷新上下文。

我们通过super不断调用父类的构造器直到AbstractApplicationContext,查看AbstractApplicationContext构造器源码:

	/**
	 * Create a new AbstractApplicationContext with no parent.
	 */
	public AbstractApplicationContext() {
		this.resourcePatternResolver = getResourcePatternResolver();
	}

	/**
	 * Create a new AbstractApplicationContext with the given parent context.
	 * @param parent the parent context
	 */
	public AbstractApplicationContext(@Nullable ApplicationContext parent) {
		this();
		setParent(parent);
	}

其中 getResourcePatternResolver的作用是创建一个资源处理器:

protected ResourcePatternResolver getResourcePatternResolver() {
        return new PathMatchingResourcePatternResolver(this);
    }

到目前为止,ClassPathXmlApplicationContext已经有了两个资源加载器(一个由AbstractApplicationContext继承DefaultResourceLoader而来,一个是AbstractApplicationContext主动创建的PathMatchingResourcePatternResolver)
DefaultResourceLoader只能加载一个特定类路径的资源,PathMatchingResourcePatternResolver可以根据Ant风格加载多个资源。

每个父类的构造方法返回后调用AbstractRefreshableConfigApplicationContext的setConfigLocations(configLocations)方法,此方法的目的在于将占位符(placeholder)解析成实际的地址:主要构造方法是setConfigLocations,我们进入这个方法就到达了AbstractRefreshableConfigApplicationContext类:

public void setConfigLocations(@Nullable String... locations) {
		if (locations != null) {
			Assert.noNullElements(locations, "Config locations must not be null");
			this.configLocations = new String[locations.length];
			for (int i = 0; i < locations.length; i++) {
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}
		}
		else {
			this.configLocations = null;
		}
	}

这个方法的主要作用是设置配置文件路径,主要方法是resolvePath(解决路径)。进入resolvePath:

protected String resolvePath(String path) {
		return getEnvironment().resolveRequiredPlaceholders(path);
	}

其中getEnvironment获取环境参数:

@Override
	public ConfigurableEnvironment getEnvironment() {
		if (this.environment == null) {
			this.environment = createEnvironment();
		}
		return this.environment;
	}

getEnvironment()方法是由ConfigurableApplicationContext接口定义,在AbstractApplicationContext实现,其实就是判断environment 是否为空,不为空就创建一个StandardEnvironment,可获取的环境参数是系统参数或者是JVM参数,如下: 

关于 Environment的作用解释:Environment是什么

顺着代码继续走,可以发现解析占位符的核心方法是parseStringValue,实现如下:

protected String parseStringValue(
			String value, PlaceholderResolver placeholderResolver, @Nullable Set<String> visitedPlaceholders) {

		int startIndex = value.indexOf(this.placeholderPrefix);
		if (startIndex == -1) {
			return value;
		}

		StringBuilder result = new StringBuilder(value);
		while (startIndex != -1) {
			int endIndex = findPlaceholderEndIndex(result, startIndex);
			if (endIndex != -1) {
				String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
				String originalPlaceholder = placeholder;
				if (visitedPlaceholders == null) {
					visitedPlaceholders = new HashSet<>(4);
				}
				if (!visitedPlaceholders.add(originalPlaceholder)) {
					throw new IllegalArgumentException(
							"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
				}
				// Recursive invocation, parsing placeholders contained in the placeholder key.
				placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
				// Now obtain the value for the fully resolved key...
				String propVal = placeholderResolver.resolvePlaceholder(placeholder);
				if (propVal == null && this.valueSeparator != null) {
					int separatorIndex = placeholder.indexOf(this.valueSeparator);
					if (separatorIndex != -1) {
						String actualPlaceholder = placeholder.substring(0, separatorIndex);
						String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
						propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
						if (propVal == null) {
							propVal = defaultValue;
						}
					}
				}
				if (propVal != null) {
					// Recursive invocation, parsing placeholders contained in the
					// previously resolved placeholder value.
					propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
					result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
					if (logger.isTraceEnabled()) {
						logger.trace("Resolved placeholder '" + placeholder + "'");
					}
					startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
				}
				else if (this.ignoreUnresolvablePlaceholders) {
					// Proceed with unprocessed value.
					startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
				}
				else {
					throw new IllegalArgumentException("Could not resolve placeholder '" +
							placeholder + "'" + " in value \"" + value + "\"");
				}
				visitedPlaceholders.remove(originalPlaceholder);
			}
			else {
				startIndex = -1;
			}
		}
		return result.toString();
	}

Spring bean解析就在refresh方法,Spring所有的初始化都在这个方法中完成,该方法在AbstractApplicationContext实现:

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

根据注释得知prepareRefresh主要是准备工作,包括设置启动时间,是否激活标识位,初始化属性源(property source)配置。

/**
	 * Prepare this context for refreshing, setting its startup date and
	 * active flag as well as performing any initialization of property sources.
	 */
	protected void prepareRefresh() {
		// Switch to active.
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);
		this.active.set(true);

		if (logger.isDebugEnabled()) {
			if (logger.isTraceEnabled()) {
				logger.trace("Refreshing " + this);
			}
			else {
				logger.debug("Refreshing " + getDisplayName());
			}
		}

		// Initialize any placeholder property sources in the context environment.
		initPropertySources();

		// Validate that all properties marked as required are resolvable:
		// see ConfigurablePropertyResolver#setRequiredProperties
		getEnvironment().validateRequiredProperties();

		// Store pre-refresh ApplicationListeners...
		if (this.earlyApplicationListeners == null) {
			this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
		}
		else {
			// Reset local application listeners to pre-refresh state.
			this.applicationListeners.clear();
			this.applicationListeners.addAll(this.earlyApplicationListeners);
		}

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<>();
	}

下一步就是创建beanFactory,调用AbstractApplicationContext的obtainFreshBeanFactory方法获取obtainFreshBeanFactory 。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		return getBeanFactory();
	}

我们来看refreshBeanFactory在AbstractRefreshableApplicationContext中的具体实现:

@Override
	protected final void  refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) { //如果已经存在的BeanFactory则销毁
			destroyBeans();
			closeBeanFactory();
		}
		try {
                        //1、创建一个DefaultListableBeanFactory 
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());

                        //2、定制beanFactory,由AbstractRefreshableApplicationContext实现
			customizeBeanFactory(beanFactory);

                        //3、加载bean,由AbstractXmlApplicationContext实现
			loadBeanDefinitions(beanFactory);

			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

第2步定制bean,customizeBeanFactory方法具体实现:

protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
        if (this.allowBeanDefinitionOverriding != null) {
            beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        if (this.allowCircularReferences != null) {
            beanFactory.setAllowCircularReferences(this.allowCircularReferences);
        }
    }

加载bean的loadBeanDefinitions具体实现:

@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);
    }

 getBean源码解析

看了很多资料,网上一张图我觉的是Spring getBean实现的很好的原理逻辑示意图,给我们展示了一个完整的调用过程:

我们参考上图的调用链,结合代码断点调试,来看getBean的实现,getBean远没有我想象的那么简单。

首先是AbstractApplicationContext中:

@Override
	public Object getBean(String name) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name);
	}

调用了抽象beanFactory工厂,调用AbstractBeanFactory的getBean:

	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

我们来看doGetBean的实现:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        //会包括解析别名等操作
        final String beanName = transformedBeanName(name);
        Object bean;

        // 先检查单例列表中是否已经注册了这个bean
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        }
        else {
            // 检查bean是否并发被创建
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
            // 检查是否在父类工厂中,逻辑和这个差不多,这里省略....

           //标记bean正在被创建
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }
            try {
                //合并父类中的方法及属性,下面会细讲                      
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                //检查这个bean是否为抽象类
                checkMergedBeanDefinition(mbd, beanName, args);

                // 这里是为了保证获取的bean的依赖都需要先生成
                String[] dependsOn = mbd.getDependsOn();
                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 ex;
                        }
                    }
                }

                // 创建单例的bean,看下方的createBean方法
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                }

                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);
                }

                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;
            }
        }

        // 检查需要的类型和实际传参类型是否一致. 这里省略....
        return (T) bean;
    }

上面的代码什么意思呢?过程是这样的:

  • 获取实际的beanName,其中会处理带&号前缀的beanName,并解析别名。
  • 检查单例列表中是否存在该beanName的bean,若存在则无需走下面的创建bean的流程。
  • 若单例列表中并不存在此bean,则检查是否有并发创建。这里的判断只针对scope为prototype类型的bean。
  • 检查bean是否存在于父类工厂中,若存在,则走父类工厂的getBean流程。向上委托,保证容器中只会存在一个同名的bean。
  • 标记bean正在被创建。
  • 如果有父类,这里会递归合并父类的方法以及属性。并会用自己重写的方法覆盖其父类的方法。合并完成并检查这个bean的是否是抽象类。
  • 如果该bean上有注解@DependsOn,或者配置文件<bean depends-on="..."/>上配置有该属性,则需保证该bean的所有依赖需要先在容器内注册。
  • 分单例和原型以及其他scope类型来创建bean。
  • 检查需要的类型和生成的bean类型是否一致。
  • 返回创建好的bean。

其中重要的方法你注意到了吗,getSingleton方法,获取bean单例,实现如下:

	@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是一个缓存了beanName和bean的Map,若存在,直接返回。
  • 不存在,则检查是否这个bean是否正在创建的过程中,先检查earlySingletonObjects这个容器,这个容器里面放着的是已经构造完成但是没有注入属性的对象,若存在,也会直接返回。
  • 尝试着从singletonFactories中获取,然后调用getObject方法去获取对象。并将获取到的对象放到earlySingletonObjects容器中,然后从singletonFactories容器中移除。

这里这么设计是为了解决循环依赖的问题。若A依赖B,B依赖C,C又依赖A,这样三个bean就形成了一个环(这里只是针对set方法注入的bean,构造器注入还是会有循环依赖的问题而抛出异常的),spring会将创建的bean实例提前暴露在缓存中,一旦下一个bean创建的时候需要依赖上个bean,则直接使用ObjectFactory来获取bean。

doGetBean还需要注意这段代码:

	// Create bean instance.
				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);
				}

这里的getSingleton,是DefaultSingletonBeanRegistry类中实现的:

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);
                //定义异常
                ...
                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) {
                    //封装异常
                    ...
                }
                finally {
                    ...
                    afterSingletonCreation(beanName);
                }
                if (newSingleton) {
                    addSingleton(beanName, singletonObject);
                }
            }
            return singletonObject;
        }
    }
  • 因为singleton的bean只能存在一个,所以对singletonObjects这个缓存做加锁获取
  • 做循环依赖判断
  • beforeSingletonCreation(beanName);//也就是把这个beanName标记成正在创建中
  • 通过singletonFactory的方法获取bean --> 也就是调用createBean方法
  • afterSingletonCreation(beanName);//去除该beanName正在创建中的标记
  • 如果是新创建的singleton的bean的话,把他加入singletonObjects缓存中
  • 这个singletonObjects缓存也就是上面所说的三级缓存的中的第一级。

不管是singleton还是Prototype还是其他的scope,在从作用域中获取不到bean的情况下,都是调用的createBean。

我们看一下createBean的实现:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        RootBeanDefinition mbdToUse = mbd;

        // 要保证RootBeanDefinition的beanClass是存在的
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // 这一块没什么研究,注解意思是(检查所有带有override的方法是否都是存在的)
        try {
            mbdToUse.prepareMethodOverrides();
        }
        catch (BeanDefinitionValidationException ex) {
        }

        try {
            //这一块我猜测大概是看咱们自己有提供实例化的方法不,若有,则不会走下面的doCreateBean方法。
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        catch (Throwable ex) {
        }

        try {
            //创建bean的真正方法
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            }
            return beanInstance;
        }
        catch (Exception e){
           throw e;
        }
    }

穿件Bean的真正方法是doCreateBean,我们来看他的实现:

  • 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,真正构建时有分两种情况,jdk反射和cglib动态代理
                instanceWrapper = createBeanInstance(beanName, mbd, args);
            }
            final Object bean = instanceWrapper.getWrappedInstance();
            Class<?> beanType = instanceWrapper.getWrappedClass();
            if (beanType != NullBean.class) {
                mbd.resolvedTargetType = beanType;
            }
    
            // 允许后置处理器来修改这个BeanDefinition
            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;
                }
            }
    
            // 用来解决循环依赖问题的,上面已经有过详细解释了。看上面循环依赖模块
            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");
                }
                addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
            }
    
            // Initialize the bean instance.
            Object exposedObject = bean;
            try {
                //进行属性的注入,调用bean的set方法进行字段的初始化
                populateBean(beanName, mbd, instanceWrapper);
                //进行一些初始化方法的调用,比如afterPropertiesSet等等。
                exposedObject = initializeBean(beanName, exposedObject, mbd);
            }
            catch (Throwable ex) {
                if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                    throw (BeanCreationException) ex;
                }
            }
    
            if (earlySingletonExposure) {
                Object earlySingletonReference = getSingleton(beanName, false);
                if (earlySingletonReference != null) {
                    if (exposedObject == bean) {
                        exposedObject = earlySingletonReference;
                    }
                    //在出现循环依赖后,从earlySingletonObjects中获取的bean对象和initializeBean后
                    //的不一致,证明被后置处理器处理过了,前后bean不一致,需要抛出异常
                    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);
                            }
                        }
                        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.");
                        }
                    }
                }
            }
    
            // 注册bean的销毁方法
            try {
                registerDisposableBeanIfNecessary(beanName, bean, mbd);
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
            }
    
            return exposedObject;
        }
    

doCreateBean大概有以下步骤:

  • 调用createBeanInstance方法初始化bean实例,这里不包括属性的注入。
  • 调用合并bean的后置处理器修改这个bean的BeanDefinition的一些定义。即调用MergedBeanDefinitionPostProcessor的实现类的postProcessMergedBeanDefinition方法对BeanDefinition进行一些额外的处理。
  • 为早期的循环依赖做准备,将包装了bean的工厂方法塞到singletonFactories中。
  • 调用populateBean方法进行一些属性的注入。
  • 执行initializeBean方法进行一些初始化方法的调用,例如:afterPropertiesSet方法的调用。与此同时,其后置处理器有可能对指定的bean进行增强。
  • 如果出现了bean的增强,然后又有依赖它的类先生成,则需抛出异常。例如:对象A被增强了,得到A+对象,而此时对象B有依赖对象A,循环依赖时通过singletonFactories获取到的对象却是增强前的A对象,这时就会出现问题。如果不抛出异常,spring容器缓存的是A+对象,但是B引用的却是A,这样就会出现不可预测的问题。

来看createBeanInstance中调用的instantiateBean的实现:

	protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
		try {
			Object beanInstance;
			final BeanFactory parent = this;
			if (System.getSecurityManager() != null) {
				beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
						getInstantiationStrategy().instantiate(mbd, beanName, parent),
						getAccessControlContext());
			}
			else {
				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
			}
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}

这里是createBeanInstance方法中最终调用的方法,这里有三个流程:

  • 进行对象的构造,这里关注下CglibSubclassingInstantiationStrategy这个策略类,有继承SimpleInstantiationStrategy类,调用其instantiate可以调用对象的构造器进行对象的初始化,在BeanDefinition属性MethodOverrides不存在时,可以用jdk的反射进行获取对象,否则则必须使用cglib动态代理。
  • 用BeanWrapperImpl对生成的对象进行包装,并激活注册默认编辑器的属性。
  • 注册默认的编辑器,然后将ConversionService这个类的引用设置到BeanWrapper对象上。ConversionService是用来进行类型转换的,里面的属性converters用一个map维护着各种类型的转换器。

populateBean源码部分:

    protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        ......
        PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

        if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
            // 这里是根据bean名称进行依赖注入的
            if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
                autowireByName(beanName, mbd, bw, newPvs);
            }
            // 这里是根据bean的类型进行依赖注入的
            if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
                autowireByType(beanName, mbd, bw, newPvs);
            }
            pvs = newPvs;
        }
        ......
        if (pvs != null) {
//实际上注入属性值的方法,这里是populateBean方法的重点
            applyPropertyValues(beanName, mbd, bw, pvs);
        }
    }

这里注释下applyPropertyValues的部分源码:

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        MutablePropertyValues mpvs = null;
        List<PropertyValue> original;

        if (pvs instanceof MutablePropertyValues) {
            mpvs = (MutablePropertyValues) pvs;
            if (mpvs.isConverted()) {
                // 这里可以迅速返回。当这个PropertyValues对象中的值都是处理过后便可以触发。状态值会在下面几行代码设置。
                try {
                    bw.setPropertyValues(mpvs);
                    return;
                }
                catch (BeansException ex) {
                    throw new BeanCreationException(
                            mbd.getResourceDescription(), beanName, "Error setting property values", ex);
                }
            }
            original = mpvs.getPropertyValueList();
        }
        else {
            original = Arrays.asList(pvs.getPropertyValues());
        }

        TypeConverter converter = getCustomTypeConverter();
        if (converter == null) {
            converter = bw;
        }
        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

        // 这里是个深拷贝,解析所有引用的值。
        List<PropertyValue> deepCopy = new ArrayList<>(original.size());
        boolean resolveNecessary = false;
        for (PropertyValue pv : original) {
            if (pv.isConverted()) {
                deepCopy.add(pv);
            }
            else {
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
                //这里的resolveValueIfNecessary是一个需要关注的方法,有兴趣的小伙伴可以点进去看看,
                //里面封装了针对各种类型的属性的解析,例如List,Map,Set等等类型。
                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                Object convertedValue = resolvedValue;
                boolean convertible = bw.isWritableProperty(propertyName) &&
                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
                if (convertible) {
                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
                }
                //为了避免每次创建都去转换属性
                if (resolvedValue == originalValue) {
                //这里的触发条件必须为该属性得是有写权限的,并且里面不能带有“.”和“[”这个符号,这里我的理解是
                    //teacher.name以及student[1].name这样的propertyName便不能触发这个条件
                    if (convertible) {
                        pv.setConvertedValue(convertedValue);
                    }
                    deepCopy.add(pv);
                }
                else if (convertible && originalValue instanceof TypedStringValue &&
                        !((TypedStringValue) originalValue).isDynamic() &&
                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
                    //这一块的条件比上一个多了几个,源值必须是string类型,且不能是动态的,并且不能是集合和数组中的任意一个。
                    pv.setConvertedValue(convertedValue);
                    deepCopy.add(pv);
                }
                else {
                    //条件在这里触发后就不会打开快捷返回的开关了
                    resolveNecessary = true;
                    deepCopy.add(new PropertyValue(pv, convertedValue));
                }
            }
        }
        //设置converted状态值,供其组装属性时快捷返回。
        if (mpvs != null && !resolveNecessary) {
            mpvs.setConverted();
        }

        // 将我们深拷贝出来的值设置到包装类BeanWrapperImpl包装的对象上
        try {
            bw.setPropertyValues(new MutablePropertyValues(deepCopy));
        }
        catch (BeansException ex) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);
        }
    }

setPropertyValues方法的源码最终调用的是AbstractNestablePropertyAccessor类的setPropertyValue方法,在这里BeanWrapperImpl是它的实现类,从名字上看也能猜出来这个类是个处理嵌套属性的访问器。

    public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException {
        AbstractNestablePropertyAccessor nestedPa;
        try {
            //这里可以解析嵌套的属性
            nestedPa = getPropertyAccessorForPropertyPath(propertyName);
        }
        catch (NotReadablePropertyException ex) {
            throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
                    "Nested property in path '" + propertyName + "' does not exist", ex);
        }
        //这里获取到了最终解析到的属性名
        PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
       //给最终解析到的属性名赋值操作
        nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value));
    }

上面有个getPropertyAccessorForPropertyPath方法,点进去会发现他会有个解析“.”和“[]”的方法getNestedPropertySeparatorIndex,它的作用我举个例子来说明一下:一个班级有多个学生,我想设置某个学生的名字,班级是个Class对象,里面有属性:private Student[] students这里我想修改下student[2]的name属性,我就必须先用getStudent方法取出 Student[] 数组,然后再在 Student[] 数组中找到索引为2的Student,最后修改Student身上的name属性。

以上就是Spring的getBean的实现。

原创文章 81 获赞 1006 访问量 25万+

猜你喜欢

转载自blog.csdn.net/lyztyycode/article/details/106066634
今日推荐