撸一撸Spring Framework-IoC-BeanDefinition

BeanFactory篇中,我们说过,容器启动时,BeanFactory会从配置元信息中加载beanDefinition,并将其注册到BeanDefinitionRegistry中,之后创建、管理bean的工作,都要依赖于beanDefinition

接下来我就先从如下这个简单的demo入手,让大家对beanDefinition有个感性的认识

public static void main(String[] args) {
    //通过xml创建、启动容器
	GenericXmlApplicationContext applicationContext=new GenericXmlApplicationContext("classpath:bean.xml");
    //从容器获取bean
	System.out.println(applicationContext.getBean("user"));
}

(为了减少大家阅读代码的负担、更好的突出重点,我在摘录源码时会省略一些对理解主题无关紧要的源码,省略处用"。。。"表示)

1、容器启动过程中加载beanDefinition,注册beanDefinition

public class GenericXmlApplicationContext extends GenericApplicationContext {

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

	public GenericXmlApplicationContext(String... resourceLocations) {
		load(resourceLocations);
		refresh();
	}

	//委托XmlBeanDefinitionReader从xml resource中加载beanDefinition
	public void load(Resource... resources) {
		this.reader.loadBeanDefinitions(resources);
	}
}

//沿着委托链XmlBeanDefinitionReader→DefaultBeanDefinitionDocumentReader→BeanDefinitionParserDelegate,跟到BeanDefinitionParserDelegate中
public class BeanDefinitionParserDelegate {
	//解析xml中的<bean>标签,创建BeanDefinition、并初始化
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {
		。。。
		String className = null;
		//获取<bean>的class属性
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}
		String parent = null;
		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
			parent = ele.getAttribute(PARENT_ATTRIBUTE);
		}

		try {
			//创建BeanDefinition
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			//通过xml DOM解析<bean>各类属性			
			//解析<bean>的scope、abstract、lazyInit、autowireMode、dependsOn、initMethod、destroyMethod等属性
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

			parseMetaElements(ele, bd);
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			
			//解析<bean>的constructor-arg属性
			parseConstructorArgElements(ele, bd);
			//解析<bean>的property属性
			parsePropertyElements(ele, bd);
			parseQualifierElements(ele, bd);

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

			return bd;
		}
		。。。
	}
	
	//拿到BeanDefinition后,为其生成beanName以及别名
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
		//解析出<bean>的id,以及name(别名)属性(name可以指定多个,以逗号分隔),id和name的作用可以认为是一样的,都可以用作从容器查找beanDefinition以及bean的key
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}
		
		String beanName = id;
		
		//这里调的就是上面解析beanDefinition的方法
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			。。。
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			//将beanDefinition、id、别名封装为一个BeanDefinitionHolder对象
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}
}

//随后将解析到的BeanDefinition注册到BeanDefinitionRegistry
public abstract class BeanDefinitionReaderUtils{
	public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

		String beanName = definitionHolder.getBeanName();
		//将BeanDefinition注册到BeanDefinitionRegistry,以beanName(对应<bean>的id属性)为注册的key
        //这里的registry实际上就是我们开始创建的GenericXmlApplicationContext对象
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				//建立id到别名的映射关系,后续如果通过别名获取beanDefinition或者bean,则先通过映射关系拿到id
				registry.registerAlias(beanName, alias);
			}
		}
	}
}

//registerBeanDefinition方法的实现在GenericXmlApplicationContext的父类GenericApplicationContext中
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
	private final DefaultListableBeanFactory beanFactory;
	
	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {
        //对应我们前面说的,ApplicationContext会将所有beanDefinition、bean操作委托给DefaultListableBeanFactory
		this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
	}
    
    @Override
	public void registerAlias(String beanName, String alias) {
		this.beanFactory.registerAlias(beanName, alias);
	}
}

//DefaultListableBeanFactory维护了一个Map<String, BeanDefinition> beanDefinitionMap和一个Map<String, String> aliasMap属性,分别用于维护beanName→beanDefinition、alias→beanName的映射关系
//代码就不贴了,多了看着费劲。。

好了,此时容器已经启动完毕,beanDefinition也已就绪,可以创建bean对象了

2、接下来就看看从容器获取bean时(getBean),容器如何使用beanDefinition完成bean的创建工作

//从applicationContext.getBean开始沿着调用链跟到AbstractBeanFactory中
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
	protected <T> T doGetBean(
			String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
			throws BeansException {

		String beanName = transformedBeanName(name);
		Object beanInstance;

		。。。

		//通过beanName获取合并后的RootBeanDefinition(先从BeanDefinitionRegistry中获取原beanDefinition,再合并为RootBeanDefinition)
        //关于RootBeanDefinition,更多信息请见代码块下方补充说明
		RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);

		。。。

		// Create bean instance.
		if (mbd.isSingleton()) {
			sharedInstance = getSingleton(beanName, () -> {
				try {
					//使用合并后的RootBeanDefinition创建bean
					return createBean(beanName, mbd, args);
				}
				catch (BeansException ex) {					
					destroySingleton(beanName);
					throw ex;
				}
			});
			beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
		}
		。。。
		return adaptBeanInstance(name, beanInstance, requiredType);
	}			
}

RootBeanDefinition的补充说明:

RootBeanDefinition是各种BeanDefinition在运行时的统一视图,不论从配置元信息中加载的是哪种类型的BeanDefinition(xml中的<bean>对应的GenericBeanDefinition、@Bean对应的ConfigurationClassBeanDefinition、@Component对应的ScannedGenericBeanDefinition),后续都会被合并为RootBeanDefinition
对于没有parent的beanDefinition来说,合并操作等同于copy
如果beanDefinition设置了parent,就会将父beanDefinition的属性合并到子beanDefinition

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {

	//实例化bean的策略
	private InstantiationStrategy instantiationStrategy;
	
	public AbstractAutowireCapableBeanFactory() {
		super();
		ignoreDependencyInterface(BeanNameAware.class);
		ignoreDependencyInterface(BeanFactoryAware.class);
		ignoreDependencyInterface(BeanClassLoaderAware.class);
		if (NativeDetector.inNativeImage()) {
			this.instantiationStrategy = new SimpleInstantiationStrategy();
		}
		else {
			//不要被类名误导,只在有必要的时候,才会真正使用cglib为bean动态生成子类,在子类实现代理逻辑,然后使用这个子类创建bean实例,否则还是通过常规的反射方式来实例化
            //关于CglibSubclassingInstantiationStrategy,更多内容请见代码块下方的补充说明			
			this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
		}
	}
	
	protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
				
		//实例化bean
		//最终调用下方的instantiateBean方法返回一个BeanWrapper对象,BeanWrapper负责完成bean属性的填充工作
		BeanWrapper instanceWrapper =createBeanInstance(beanName, mbd, args);
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
	
		// 初始化bean实例
		Object exposedObject = bean;
		try {
			//bean属性填充(根据beanDefinition中定义的propertyValues)
            //不论bean的属性是什么类型,通过xml定义bean时,只能使用字符串字面量来对属性赋值,BeanWrapper首先要将字符串字面量转换为bean属性实际对应的类型,然后通过反射的方式给bean赋值
            //BeanWrapper内容比较多,详细内容请参考下一篇文章https://blog.csdn.net/wb_snail/article/details/121570120
			populateBean(beanName, mbd, instanceWrapper);
			
            //bean初始化,包括相关aware接口回调、BeanPostProcessor接口前置方法回调、初始化方法回调(bean实现了InitializingBean、或者beanDefinition中定义了initMethod)、BeanPostProcessor接口后置方法回调
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		
		。。。
	}
	
	
	protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
		try {
			//委托上述instantiationStrategy实例化bean
			Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
			
			//通过InstantiationStrategy实例化出的bean只是一个半成品,还要经过属性填充、初始化等工作才能变成完整的bean,这里将bean封装到BeanWrapper,后续就由BeanWrapper负责bean的属性填充工作
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}
	
//上述的getInstantiationStrategy().instantiate实际调用的是CglibSubclassingInstantiationStrategy的父类SimpleInstantiationStrategy的instantiate方法
public class SimpleInstantiationStrategy implements InstantiationStrategy {
	
	//bean实例化(根据beanDefinition中的信息)
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// 若beanDefinition中不含methodOverrides,通过常规的反射方式来实例化
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class<?> clazz = bd.getBeanClass();
					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 {
							//通过beanDefinition中的beanClass属性找到对应的构造器
							constructorToUse = clazz.getDeclaredConstructor();
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			//通过构造器反射创建bean对象
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// 若beanDefinition中包含methodOverrides,使用cglib创建子类代理对象
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}
}

CglibSubclassingInstantiationStrategy的补充说明: 

前面说了,只在有必要的时候,CglibSubclassingInstantiationStrategy才会真正使用cglib技术创建一个子类代理对象,否则还是通过常规的反射方式来实例化,这里的"有必要的时候"指的是beanDefinition添加了MethodOverride时

  • 若通过xml加载beanDefinition,<bean>标签中添加了lookup-method或replaced-method属性,就会被解析为MethodOverride对象,添加到加载出的beanDefinition中
  • 若通过@Component注解(及其派生注解)加载beanDefinition,类中某个方法上添加了@Lookup,就会被解析为MethodOverride对象,添加到加载出的beanDefinition中

MethodOverride有两个实现类,代表两种不同的override方式

  • LookupOverride:创建时要指定一个beanName,其代理逻辑会用该beanName查找IoC容器中的bean,作为方法的真实返回值,所以LookupOverride只能做简单的返回值替换
  • ReplaceOverride:配置时也要指定一个beanName,不过这个beanName对应的是我们自定义的MethodReplacer类的beanName,其代理逻辑会用该beanName查找IoC容器中的methodReplacer对象,调用它的reimplement方法,所以ReplaceOverride可以做任意替换
    public interface MethodReplacer {
    	/**
    	 * 替换指定方法
    	 * @param obj 要代理的bean对象
    	 * @param method 要代理的方法
    	 * @param args 调用被代理方法的参数
    	 */
    	Object reimplement(Object obj, Method method, Object[] args) throws Throwable;
    }
  • xml中的ookup-method以及@Component注解类中的@Lookup就对应LookupOverride,而ReplaceOverride只有xml中的replaced-method与之对应,没有注解方式可对应

总结下上述过程:

  • 容器启动过程中,委托XmlBeanDefinitionReader从配置元信息(上述例子中是xml文件)中加载beanDefinition,并将xml中<bean>标签的各种属性解析为beanDefinition的属性,随后将beanDefinition注册到DefaultListableBeanFactory
  • 从容器获取bean时,首先从DefaultListableBeanFactory拿到对应的beanDefinition、合并为RootBeanDefinition
  • 然后使用InstantiationStrategy进行bean的实例化(获取rootBeanDefinition中的className,通常是通过反射方式创建实例,当beanDefinition中定义了MethodOverrides时,使用cglib动态生成子类,并创建子类实例作为bean实例)
  • 此时的bean只是个半成品,还需要经历属性填充、初始化两道工序才算完整。BeanWrapper就负责属性填充工作,它首先将String字面量转换为bean属性实际类型值,然后通过反射的方式将给bean的属性赋值
  • 最后一步就是bean的初始化工作,包括相关aware接口回调、BeanPostProcessor接口前置方法回调、初始化方法回调(bean实现了InitializingBean、或者beanDefinition中定义了initMethod)、BeanPostProcessor接口后置方法回调,此时完整的bean就出炉了

除了从静态的配置元信息中加载beanDefinition外,spring还支持动态注册beanDefinition的机制,当然了,不论是静态还是动态,最终都是调用BeanDefinitionRegistry#registerBeanDefinition(String beanName, BeanDefinition beanDefinition)完成注册,所以理论上只要我们能拿到BeanDefinitionRegistry实例,就可以动态注册。但要注意注册的时机,要在容器开始创建bean之前,因为bean一旦生成,其@Autowire就已经处理完毕,这时候再注册beanDefinition就没法通过依赖注入来使用了(可以通过依赖查找的方式使用,但我们往往不会这样做))

有如下两种方式,允许我们在容器开始创建bean之前拿到BeanDefinitionRegistry实例,进行beanDefinition的注册

//实现BeanDefinitionRegistryPostProcessor接口
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        builder.addPropertyValue("id","001");
        builder.addPropertyValue("name","bobo");
        AbstractBeanDefinition userBeanDefinition=builder.getBeanDefinition();
        registry.registerBeanDefinition("user",userBeanDefinition);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        //do nothing
    }
}

//实现BeanFactoryPostProcessor接口
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        builder.addPropertyValue("id","001");
        builder.addPropertyValue("name","bobo");
        AbstractBeanDefinition userBeanDefinition=builder.getBeanDefinition();
        //BeanDefinitionRegistry的运行时实例就是DefaultListableBeanFactory
        BeanDefinitionRegistry registry=(DefaultListableBeanFactory)beanFactory;
        registry.registerBeanDefinition("user",userBeanDefinition);
    }
}

我们在MyBeanDefinitionRegistryPostProcessor中断点,通过调用栈看看它何时被容器调起

标红的refresh方法大家应该比较熟悉,是容器启动的入口,BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor在容器启动的早期就会被回调,前者略早于后者,此后又经历了很多步骤,才会开始开始处理bean,后续会在spring容器生命周期中详细讲述

上面的例子是通过xml来加载beanDefinition,通过注解(@Configuration+@Bean、@ComponentScan+@Component(及其派生注解如@Controller、@Service、@Repository))加载beanDefinition的过程虽然稍有不同(后续容器启动过程会详细说明),但beanDefinition的加载、注册时机依然是容器启动时

2、

写个demo

从BeanDefinition变成bean的过程

猜你喜欢

转载自blog.csdn.net/wb_snail/article/details/121315081