初体验

@Import是Spring提供的一个注解,通过此注解可以向IOC容器中导入一些组件

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {

	/**
	 * {@link Configuration @Configuration}, {@link ImportSelector},
	 * {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.
	 */
	Class<?>[] value();

}

该注解有三种导入组件的方法:

  • 直接import一个bean。
  • 通过ImportSelector批量导入组件。
  • 使用ImportBeanDefinitionRegistrar,导入BeanDefinition到BeanDefinitionRegistry中。

下面演示其第三种用法:

@Import({MainConfig.MyImportBeanDefinitionRegistrar.class})
@Configuration
public class MainConfig {

	/**
	 * BeanDefinitionRegistry:bean定义信息注册中心
	 * @author wen.jie
	 * @date 2021/9/24 9:35
	 */
	static class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
		public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
			RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
			rootBeanDefinition.setBeanClass(Cat.class);
			registry.registerBeanDefinition("tomcat", rootBeanDefinition);
		}
	}
}

public class Cat {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Cat{" +
				"name='" + name + '\'' +
				'}';
	}
}

//主测试方法
	public static void main(String[] args) {
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
		Cat cat1 = applicationContext.getBean(Cat.class);
		System.out.println(cat1);
	}

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

从结果上看,我们定义了一个配置类MainConfig,通过MyImportBeanDefinitionRegistrar导入了Cat的bean定义信息,然后我们通过applicationContext.getBean(Cat.class)就能获取到bean实例了。

BeanDefinitionRegistry和BeanDefinition

BeanDefinition相当于工厂创建Bean的图纸,图纸上包含着bean的name、bean是否是懒加载、bean依赖的其他bean等相关信息,而BeanDefinition需要注册到BeanDefinitionRegistry中,那么BeanDefinitionRegistry就相当于存放BeanDefinition的档案库,当spring应用初始化时候,先把所有图纸保存到档案库后,然后IOC容器从档案库中拿到图纸,根据图纸创建不同的bean。

前置知识:介绍Spring的一些接口

核心接口BeanFactory

BeanFactory接口是Spring IOC容器的顶级接口!

接口的继承树大致如下:

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

先看BeanFactory的方法:该接口中有一系列的getBean方法,通过getBean方法来获取bean对象。

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

有点类似与工厂方法设计模式。

再来看它的三大子接口:HierarchicalBeanFactoryListableBeanFactoryAutowireCapableBeanFactory

HierarchicalBeanFactory

HierarchicalBeanFactory:Hierarchical意味有层次的。

内部有一个getParentBeanFactory方法,用于获取父容器。

而在它的子接口ConfigurableBeanFactory中有一个setParentBeanFactory方法,用于设置父容器的方法。

看到这里,不由的想到springmvc中著名的父子容器,是的,springmvc中父子容器底层就跟ConfigurableBeanFactory有关(这里就不去找具体的代码了)。

所以至此我们知道HierarchicalBeanFactory及其子接口提供了定义父子工厂(或者叫做父子容器)的功能。

AutowireCapableBeanFactory

1.通过接口名字,也能想到该接口拥有自动装配的能力。

2.它真正的作用在于整合其它框架,例如Junit和Quartz,这里不再详细介绍该接口。

ListableBeanFactory

下面详细介绍该接口。

先看该接口定义的方法:一眼看到三个方法跟BeanDefinition有关系。

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

我们知道想要获取Spring容器中所有的BeanNames(即调用getBeanDefinitionNames方法),然后再通过BeanName去找到所有已经在容器中注册的Bean。

所以ListableBeanFactory跟BeanDefinitionRegistry有很大的关系。

下面看ListableBeanFactory的子类:(部分无关紧要的实现类和抽象类以及省略)

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

先看ClassPathXmlApplicationContextFileSystemXmlApplicationContext这两个类,一个是根据类路径的xml创建容器,一个是根据系统文件xml路径创建容器。我们先去找它的getBeanDefinitionNames方法实现,子类没有实现,那就去父类中找。

最后在AbstractApplicationContext类中找到实现。这里先调用getBeanFactory()方法返回了一个BeanFactory,那我们可以大胆猜测这个返回的BeanFactory的子类,很有可能就是我们前面说到的档案馆。

	@Override
	public String[] getBeanDefinitionNames() {
		return getBeanFactory().getBeanDefinitionNames();
	}

再看getBeanFactory方法:抽象方法,但是返回了一个ConfigurableListableBeanFactory接口

	@Override
	public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

这个接口只有一个主要实现DefaultListableBeanFactory(另一个实现XmlBeanFactory已经过时了),那么DefaultListableBeanFactory就有可能是我们说的档案馆,里面存放了所有bean的定义信息。

那是不是这样呢?我们可以再看GenericXmlApplicationContextAnnotationConfigApplicationContext类,在这两个类中没有找到DefaultListableBeanFactory的影子,但是它们都继承了GenericApplicationContext,而这个类组合了DefaultListableBeanFactory,并且实现了上面提到的getBeanFactory方法,返回了组合的DefaultListableBeanFactory

	private final DefaultListableBeanFactory beanFactory;
	
	@Override
	public final ConfigurableListableBeanFactory getBeanFactory() {
		return this.beanFactory;
	}

DefaultListableBeanFactory

DefaultListableBeanFactory实现了BeanDefinitionRegistry接口。

上面说到DefaultListableBeanFactory就是bean定义信息的档案馆,那么它是怎么管理的呢?对于java来说,保存数据可以用List、Set、Map、Queue、数组等,那我们就可以看看它的成员变量有哪些。

	/** Map from dependency type to corresponding autowired value. */
	private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

	/** Map of bean definition objects, keyed by bean name. */
	//保存所有bean定义信息的map
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

	/** Map from bean name to merged BeanDefinitionHolder. */
	private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);

	/** Map of singleton and non-singleton bean names, keyed by dependency type. *///所有bean的名字
	private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);

	/** Map of singleton-only bean names, keyed by dependency type. */ //单例bean的名字
	private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);

	/** List of bean definition names, in registration order. */ //所有已经注册bean定义信息的名字
	private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

	/** List of names of manually registered singletons, in registration order. */
	private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);

	/** Cached array of bean definition names in case of frozen configuration. */
	@Nullable
	private volatile String[] frozenBeanDefinitionNames;

这里面有两个比较重要的成员变量跟BeanDifinition有关。

  • beanDefinitionMap

这个map的key是String类型,但是这里我们无法猜测这个key究竟存的是什么信息,但是value是BeanDefinition,就是存放所有bean图纸的地方。

我们往下看之前测试时候调用的registerBeanDefinition方法:这里调用的put方法,key就是bean的名字,所以我们根据bean的名字就能获取到Bean

	@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 existingDefinition = this.beanDefinitionMap.get(beanName);//先从beanDefinitionMap中获取一遍,检查定义信息是否存在
		if (existingDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			//省略了一些日志输出判断
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
			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<>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					removeManualSingletonName(beanName);
				}
			}
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (existingDefinition != null || containsSingleton(beanName)) {
			resetBeanDefinition(beanName);
		}
		else if (isConfigurationFrozen()) {
			clearByTypeCache();
		}
	}
  • beanDefinitionNames

上面写过的registerBeanDefinition方法中,同时会把beanName给add到beanDefinitionNames中。

源码解析

下面进行调试源码,看看BeanDefinitionRegistry是如何加载的,然后IOC容器是在哪一步通过图纸创建Bean的?

测试

Person.class

public class Person {

	String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
    
    public Person() {
        
    }

	@Override
	public String toString() {
		return "Person{" +
				"name='" + name + '\'' +
				'}';
	}
}

spring.xml

<?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 class="com.wj.spring.bean.Person" name="person">
		<property name="name" value="wj"/>
	</bean>
</beans>

主方法:

public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    Person bean = applicationContext.getBean(Person.class);
    System.out.println(bean);
}

BeanDefinition注册到BeanDefinitionRegistry

直接打在ClassPathXmlApplicationContext类中的refresh方法。

refresh中有一个obtainFreshBeanFactory方法,直接获取刷新好的bean工厂,并且返回值是ConfigurableListableBeanFactory,是DefaultListableBeanFactory的父类。那么这个类的初始化应该就在obtainFreshBeanFactory方法中。

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

obtainFreshBeanFactory方法有两步,第一步refreshBeanFactory刷新工厂,第二步getBeanFactory

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

进入refreshBeanFactory方法:第一次加载,hasBeanFactory为false,跳过。

然后下面直接 createBeanFactory(),并且把创建好的DefaultListableBeanFactory赋值给了成员变量。

	/**
	 * This implementation performs an actual refresh of this context's underlying
	 * bean factory, shutting down the previous bean factory (if any) and
	 * initializing a fresh bean factory for the next phase of the context's lifecycle.
	 */
	@Override
	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			//创建档案馆(保存所有bean定义信息的位置)
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			//加载bean的定义信息
			loadBeanDefinitions(beanFactory);
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

先看createBeanFactory方法,这个方法比较简单,直接new了一个DefaultListableBeanFactory,并返回。

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

debug继续往下走,先设置了id,然后又自定义了一些属性,这些都是无关紧要的。

但是后面有一个loadBeanDefinitions方法,根据名字也知道是加载bean定义信息,这就是我们需要关心的地方,debug走进去。

这里先创建一个xml的BeanDefinition读取器,然后使用该读取器加载BeanDefinitions。

	@Override
	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);    //创建一个xml的BeanDefinition读取器

		// 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);//初始化BeanDefinition读取器
		loadBeanDefinitions(beanDefinitionReader);//加载BeanDefinition
	}

进入loadBeanDefinitions方法:这里XmlBeanDefinitionReader会调用自己的loadBeanDefinitions方法

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

该方法中继续调用重载的loadBeanDefinitions方法

	@Override
	public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
		Assert.notNull(locations, "Location array must not be null");
		int count = 0;
		for (String location : locations) {//逐个加载配置文件
			count += loadBeanDefinitions(location);
		}
		return count;
	}

	@Override
	public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(location, null);
	}

继续往后走:先用资源加载器加载资源,然后继续调用重载的loadBeanDefinitions方法

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

debug继续往后走:

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

这里用EncodedResource包装了原resource对象,典型的装饰器设计模式。

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

后面读取到xml的文件流,然后调用doLoadBeanDefinitions方法

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

doLoadBeanDefinitions方法如下,先把xml读取到Document中,这个Document是w3C提供的,这里不再详细介绍。我们只需要知道document是一个文档,包含了spring.xml文件中的信息。

后面调用了registerBeanDefinitions方法。

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

继续往下看:这里创建了一个bean定义信息的文档读取器,然后使用读取器去注册bean定义信息。

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

调用doRegisterBeanDefinitions方法:

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

再看doRegisterBeanDefinitions方法:这里先创建一个BeanDefinitionParserDelegate,从名字上我们知道,这是一个代理类,用于解析BeanDefinition信息

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

前面先初始化BeanDefinitionParserDelegate,后面调用parseBeanDefinitions方法

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

parseDefaultElement方法中会解析一些标签:import、alias、bean、beans,因为xml中我只写了bean标签,所以走到解析bean的这一步:

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

调用processBeanDefinition方法,里面有比较重要的两步。

  • delegate.parseBeanDefinitionElement:通过调用代理类的parseBeanDefinitionElement方法返回了BeanDefinitionHolder
  • BeanDefinitionReaderUtils.registerBeanDefinition:通过调用BeanDefinitionReaderUtils的注册beanDefinition方法,通过方法名也知道,这一步是将获取到的bean定义信息注册到BeanDefinitionRegistry中,而上一步中获取到的BeanDefinitionHolder中就包含了BeanDefinition
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);//将解析完的标签信息全部封装到Holder中
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.
				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));
		}
	}

先看BeanDefinitionParserDelegate是怎么获取BeanDefinitionHolder的。

	//最后parseBeanDefinitionElement方法调用的是这个重载方法
	@Nullable
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		String id = ele.getAttribute(ID_ATTRIBUTE);//获取bean标签id属性
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//获取bean标签name属性

		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
            //切割nameAttr
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            //把切割后的字符串add到aliases中
			aliases.addAll(Arrays.asList(nameArr));
		}

		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isTraceEnabled()) {
				logger.trace("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}

		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
		//解析BeanDefinition,并返回BeanDefinition
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
            //下面这个if中,对beanName进行一系列判断,这个不是重点
			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.isTraceEnabled()) {
						logger.trace("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);
            //将beanDefinition信息、beanName、alias信息全部封装到BeanDefinitionHolder中并返回
            //这就验证了我们之前的猜想:BeanDefinitionHolder中封装了beanDefinition信息
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}
		return null;
	}

很容易得到上面代码的重点:AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);,这个就是解析BeanDefinition的代码,源码如下:

	@Nullable
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {

		this.parseState.push(new BeanEntry(beanName));

		String className = null;
        //获取className属性
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
        ////获取parent属性
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
            //创建BeanDefinition(GenericBeanDefinition)
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			//解析bean标签的属性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            //解析description标签内容
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
			//meta标签
			parseMetaElements(ele, bd);
            //lookup-method标签
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //replaced-method标签
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			//constructor-arg标签
			parseConstructorArgElements(ele, bd);
            //property标签
			parsePropertyElements(ele, bd);
            //qualifier标签
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

            //最后将BeanDefinition返回
			return bd;
		}
		catch (ClassNotFoundException ex) {
			error("Bean class [" + className + "] not found", ele, ex);
		}
		catch (NoClassDefFoundError err) {
			error("Class that bean class [" + className + "] depends on not found", ele, err);
		}
		catch (Throwable ex) {
			error("Unexpected failure during bean definition parsing", ele, ex);
		}
		finally {
			this.parseState.pop();
		}

		return null;
	}

至于怎么解析具体标签的就不去看了,都是类似的代码。

我们在bean标签能设置什么属性,能写什么子标签,都是源码中决定的了。

再看BeanDefinitionReaderUtils.registerBeanDefinition()方法,这里直接调用BeanDefinitionRegistryregisterBeanDefinition方法注册bean的定义信息。

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

registerBeanDefinition方法前面讲过了,这里就不说了。至此BeanDefinition注册BeanDefinitionRegistry的代码大致说完。

根据BeanDefinition加载bean

(关于spring怎么加载bean的这里不细讲)

那么Spring是怎么根据BeanDefinition加载bean的呢,可能代码不太好找,我们直接将断点打在Person类的构造器上。

方法调用栈如下:

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

点过去,发现调用的是refresh中的finishBeanFactoryInitialization(beanFactory);方法

一直往后点,点到preInstantiateSingletons方法,发现是在DefaultListableBeanFactory类中调用的,就是我们前面说的档案库。

preInstantiateSingletons方法中有这么一段

		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		//遍历所有非懒加载的bean
		for (String beanName : beanNames) {
            //获取到bean的BeanDefinition信息
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
            //不是抽象的 && 是单例的 && 非懒加载的
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                //是否是FactoryBean
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
                    //我们这里不是,所以调用了getBean这一行
                    //因为Person的构造器在getBean中调用,所以 不是抽象的 && 是单例的 && 非懒加载的bean会在这里通过getBean创建bean的实例对象
					getBean(beanName);
				}
			}
		}

继续往后走,会走到doGetBean

//根据beanName获取到之前已经注册的BeanDefinition信息
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//前置检查
checkMergedBeanDefinition(mbd, beanName, args);

// Guarantee initialization of beans that the current bean depends on.
//获取当前bean所dependsOn的bean,并先实例化当前bean所依赖的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 new BeanCreationException(mbd.getResourceDescription(), beanName,
                                            "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
        }
    }
}

// Create bean instance.
//当前bean是单例的
if (mbd.isSingleton()) {
    //调用getSingleton
    sharedInstance = getSingleton(beanName, () -> {
        try {
            //调用createBean
            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;
        }
    });
    beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

先看getSingleton方法:这个方法在DefaultSingletonBeanRegistry类中,这个类存放了所有的单例bean

	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
            //判断是否已经注册过了
			if (singletonObject == null) {
				if (this.singletonsCurrentlyInDestruction) {
					throw new BeanCreationNotAllowedException(beanName,
							"Singleton bean creation not allowed while singletons of this factory are in destruction " +
							"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
				}
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
                    //调用getObject方法
					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;
		}
	}

查看createBean,后面会调用doCreateBean方法,这个方法中调用的createBeanInstance

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

createBeanInstance调用instantiateBean

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

调用instantiate方法

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

instantiate方法如下:

	@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class<?> clazz = bd.getBeanClass();//通过BeanDefinition获取bean的Class
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(
									(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
						}
						else {
							constructorToUse = clazz.getDeclaredConstructor();//通过反射获取构造器
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			return BeanUtils.instantiateClass(constructorToUse);//通过构造器创建Bean
		}
		else {
			// Must generate CGLIB subclass.
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

Bean的热加载

那知道了这些原理有什么作用呢?

当然是有作用的了。

在部分复杂的业务中,可能会让我们热加载一些Spring bean,比如在Spring应用运行过程中,动态加载一些bean或者卸载一些bean。

举例如下:我这里使用的是Spring boot做测试,当然其他的spring应用也行。

下面有一个TestService类,未被Spring容器所管理。

/**
 * @author wen.jie
 * @date 2021/9/24 15:45
 */
@Slf4j
public class TestService {

    public TestService(){
        log.info("TestService init");
    }

    public void doService() {
        log.info("TestService doService");
    }
}

我们知道调用getBean方法是,如果bean没有实例化时,会先从BeanDefinition信息中实例化bean。那么我们想要动态加载bean,只需要手动把bean定义信息加载到BeanDefinitionRegistry中;同理想要卸载bean只需要从BeanDefinitionRegistry删除掉就行了,BeanDefinitionRegistry已经提供了removeBeanDefinition方法去删除bean的定义信息。

代码实现如下:

/**
 * @author wen.jie
 * @date 2021/9/24 15:46
 */
@SpringBootTest
public class ApplicationTest {

    @Autowired
    ApplicationContext applicationContext;

    @Test
    public void test() {
        //获取DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
        //生成BeanDefinitionBuilder
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(TestService.class);
        //获取BeanDefinition
        AbstractBeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        //注册bean定义信息
        defaultListableBeanFactory.registerBeanDefinition("testService", beanDefinition);
        TestService bean = applicationContext.getBean(TestService.class);
        bean.doService();

        //移除定义信息
        defaultListableBeanFactory.removeBeanDefinition("testService");
        TestService bean2 = applicationContext.getBean(TestService.class);
        bean2.doService();
    }
}

运行结果如下:

Spring源码分析:BeanDefinitionRegistry和BeanDefinition

先开始我们注册bean定义信息了,然后通过getBean就能获取到TestService,后面我们移除了它的BeanDefinition,所以再次getBean就找不到该bean了。

相关文章:

  • 2021-08-11
  • 2022-01-16
  • 2019-10-08
  • 2021-05-10
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-01-26
猜你喜欢
  • 2021-12-12
  • 2022-12-23
  • 2021-12-01
  • 2022-12-23
  • 2021-06-15
  • 2022-01-15
  • 2022-01-09
相关资源
相似解决方案