撸一撸Spring Framework-IoC系列文章目录
在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.youkuaiyun.com/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的加载、注册时机依然是容器启动时