spring beandefinition,解释spring框架中bean的生命周期
目录
前言的载入和解析的合并源码分析总结写在前面
注:本文章使用的跳羚版本为发布,其弹簧版本为发布
前言
书接上文,BeanDefinition注册到国际奥委会容器后,紧接着就是要使用豆了,要使用必须先要获取豆子,这里我们就以DefaultListableBeanFactory #获取bean方法来引出本次讨论的内容:BeanDefinition的合并
通过前面的章节我们了解到了BeanDefinition,那什么是的载入和解析的合并呢?为什么要进行合并呢?带着这个问题,我们到源码中去找找答案。
为了使源码逻辑有个参照,这里先给出一个案例,在分析源码时将这个案例也代入进去方便我们理解源码
BeanDefinition的合并源码分析
实体类
@Datapublic类超级用户实现可序列化的{私有字符串地址;公共超级用户(字符串地址){ this . address=address } public super User(){ } } @ Data @ ToString(call super=true)public class User扩展超级用户{私有字符串名称私有整数年龄;公共用户(){ }公共用户(字符串名称,整数年龄){ this.name=namethis.age=年龄;}}基于GenericBeanDefinition注册有层次的豆
public class genericbeanditiondemo { public static void main(String[]args){ AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext();//父bean定义genericbean定义根bean定义=new genericbean定义();rootbean定义。setbean类(超级用户。类);//设置参数MutablePropertyValues属性值=new MutablePropertyValues();属性值。addpropertyvalue( address ,地址);rootbean定义。设置属性值(属性值);//子bean定义genericbean定义childbean定义=new genericbean定义();childbean定义。setbean类(用户。类);//设置构造参数ConstructorArgumentValues argumentValues=new ConstructorArgumentValues();参数值。addindexdargumentvalue(0, 0我就是我);参数值。addindexdargumentvalue(1,18);childbean定义。setconstructorargumentvalues(参数值);childbean定义。设置父名称(超级用户);//类型相同时以子类为主childbean定义。设置primary(真);上下文。是
gisterBeanDefinition("superUser", rootBeanDefinition); context.registerBeanDefinition("user", childBeanDefinition); context.refresh(); User user = context.getBean("user", User.class); System.out.println(user); SuperUser superUser = context.getBean("superUser", SuperUser.class); System.out.println(superUser); context.close(); }}在分析源码时我们要有侧重点,这里会将不太相关的逻辑一带而过。
AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {//将name解析为beanName,如果传入的是alias,根据aliasMap进行转换,我们在前面介绍过了final String beanName = transformedBeanName(name);Object bean;// 如果是单例BeanObject sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {//省略日志输出// 这里的逻辑是根据beanName判断是否为FactoryBea,并采用相应方式去处理bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}//如果不是单例对象else {// 对原型对象进行验证,如果当前beanName已经在创建中了 抛出异常if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// 获取父BeanFactory,前面我们介绍过了 BeanFactory允许有层级,可已存在父BeanFactoryBeanFactory parentBeanFactory = getParentBeanFactory();//如果存在父BeanFactory 去父BeanFactory中查找beanif (parentBeanFactory != null && !containsBeanDefinition(beanName)) {//省略去父BeanFactory查找Bean的过程}//typeCheckOnly默认为false ,这里将beanName放到alreadyCreated集合中 表示该Bean正在创建中if (!typeCheckOnly) {markBeanAsCreated(beanName);}try { // 这里来到了我们要重点关注的地方了,bd的合并 ⭐️final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);//如果存在依赖Bean,需要进行依赖查找String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {// 省略dependsOn 依赖查找代码}// 这里的if..else if .. else 是根据scope取值来的//scope=singleton时if (mbd.isSingleton()) {//省略单实例Bean创建过程}//scope=prototype时else if (mbd.isPrototype()) {//省略Prototype Bean创建过程}//scope=request、application、session时else {// 省略其他Scope Bean的创建过程}if (requiredType != null && !requiredType.isInstance(bean)) {//省略类型转换代码}// 返回创建的Beanreturn (T) bean;}
上面的方法实现比较长、比较复杂,这里只对重要的地方进行些注释说明并将与本次讨论无关的代码先行进行注释。
下面就进入到BeanDefinition的合并逻辑了
//假设beanName=userprotected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {// 检查缓存,若存在直接返回RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);if (mbd != null) {return mbd;} //getBeanDefinition(beanName)==>实际上去DefaultListableBeanFactory.beanDefinitionMap中根据key查找BeanDefinition,这在注册阶段已经放到beanDefinitionMap了。return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));}
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)throws BeanDefinitionStoreException {return getMergedBeanDefinition(beanName, bd, null);}//根据上面的举例可知beanName=user,bd是User类的BeanDefinition,containingBd=nullprotected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)throws BeanDefinitionStoreException {synchronized (this.mergedBeanDefinitions) {RootBeanDefinition mbd = null;// 尝试从缓存中拿if (containingBd == null) {mbd = this.mergedBeanDefinitions.get(beanName);}if (mbd == null) { //如果当前BeanDefinition没有指定parentName,说明其不存在父BeanDefinition,不需要合并。以RootBeanDefinition形式展现if (bd.getParentName() == null) {// 如果bd是RootBeanDefinition类型,直接类型转换if (bd instanceof RootBeanDefinition) {mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();}else { //通过bd属性构造RootBeanDefinitionmbd = new RootBeanDefinition(bd);}}else {// 走到这里说明存在parentName,当前bd需要与其父bd合并BeanDefinition pbd;try { //得到父BeanNameString parentBeanName = transformedBeanName(bd.getParentName()); //!beanName.equals(parentBeanName) 条件成立 说明当前beanName属于子bdif (!beanName.equals(parentBeanName)) { //递归地以父bd名称 查找父BeanDefinition。之所以递归地查找,是因为 可能此时的parentBeanName还有父,实体类存在多重继承关系pbd = getMergedBeanDefinition(parentBeanName);}else { //走到这里,说明beanName.equals(parentBeanName),很有可能是父bd查找BeanDefinition时走来的。 //获取父BeanFactory,BeanFactory也是有层次的,有父子关系的,可参见ConfigurableBeanFactory#setParentBeanFactoryBeanFactory parent = getParentBeanFactory();if (parent instanceof ConfigurableBeanFactory) {pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);}else {throw new NoSuchBeanDefinitionException(parentBeanName,"Parent name " + parentBeanName + " is equal to bean name " + beanName +": cannot be resolved without an AbstractBeanFactory parent");}}}catch (NoSuchBeanDefinitionException ex) {throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,"Could not resolve parent bean definition " + bd.getParentName() + "", ex);}// pbd是父BeanDefinition,由其构造为RootBeanDefinitionmbd = new RootBeanDefinition(pbd); //bd是子BeanDefinition,主要是继承父类的属性,并覆盖与父类同名的属性,有兴趣的可以看一下overrideFrom方法实现mbd.overrideFrom(bd);}// 如果父bd未指定scope,则设置默认值if (!StringUtils.hasLength(mbd.getScope())) {mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);}//由于containingBd=null 这里就不看了if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {mbd.setScope(containingBd.getScope());}if (containingBd == null && isCacheBeanMetadata()) {this.mergedBeanDefinitions.put(beanName, mbd);}}//最终返回根据当前beanName找到的bdreturn mbd;}}
分析了上面的源码,我们试着总结一下:
1、如果不存在parentName,即不需要被合并,直接将bd转为RootBeanDefinition 返回即可
2、如果存在parentName
先根据parentName 找到父bd,若实体存在多级继承关系,则需要递归地查找。将父bd转为RootBeanDefinition,并将子bd与父bd进行合并设置一些其他属性
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注盛行IT的更多内容!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。