首页 > 编程语言 >【Mybatis】【三】源码分析- MapperFactoryBean 的创建过程以及 Mapper 接口代理的生成过程详解

【Mybatis】【三】源码分析- MapperFactoryBean 的创建过程以及 Mapper 接口代理的生成过程详解

时间:2024-03-02 21:11:29浏览次数:22  
标签:Mapper object MapperFactoryBean mbd 创建 beanName 源码 null

1  前言

本节我们续前两节(调试查看Mapper接口生成过程源码分析 Mapper生成注入入口分析)的内容,看下 MapperFactoryBean 是如何代理掉我们的 @Mapper 接口的。

上节我们看到我们的 Mapper 接口的 BeanDefinition, 已经放进 spring 的上下文中了,也就是在 BeanFactory 的 BeanDefinitionMap 里了哈。它的形式是 FactoryBean 的,这时当我们的 Service 或者某个 Bean 有依赖于我们的 Mapper 接口,这时候就会创建 Bean,或者没有任何 Bean 依赖 Mapper 的情况下,因为 BeanDefinition 的 lazyInit 为 false,所以 spring 也会在刷新完上下文的最后面,把所有非懒加载的单例的 Bean 都给创建出来。

所以不管有没有依赖,我们每个 Mapper 的 BeanDefinition 都会创建 Bean,那我们就一步步来看看创建过程。这就涉及到 Bean 的生命周期咯。

还有大家放心看,我都是一步一步调试边理解边思考然后才写的哈,就这节我都调试了不下一百次。

2  源码分析

2.1  找入口

从哪看起呢?我有个 Service 是依赖 Mapper 的:

所以我就在 BeanFactory 的 doGetBean 打了个断点:

它从哪来呢?应该是从创建 Service 的时候,populateBean 发现它的属性依赖,进行 Bean的装配来的,看 debug 来源确实是这样。

所以我们就从 BeanFactory 的 doGetBean() 开始看起吧。顺便复习下 FactoryBean 形式的创建过程哈。

2.2  源码分析

我就拿我这个 accountMapper 来看哈,我们进入到 doGetBean(),来看看 accountMapper 的创建:

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
    // 转换 Bean 的名字,主要是当获取 FactoryBean 本身的时候 &开头的处理,这里可以不用管 我们这里 name = accountMapper
    String beanName = this.transformedBeanName(name);
    // 我们第一次来获取 此时为空
    Object sharedInstance = this.getSingleton(beanName);
    Object bean;
    if (sharedInstance != null && args == null) {
        ...
    } else {
        // false
        if (this.isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
        ...
        if (!typeCheckOnly) {
            this.markBeanAsCreated(beanName);
        }
        try {
            // 获取 BeanDefinition  这个获取的是 AccoutMapper 的 BeanDefinition 加工后的 MapperFactoryBean 类型的 BeanDefinition 哈
            RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
            this.checkMergedBeanDefinition(mbd, beanName, args);
            String[] dependsOn = mbd.getDependsOn();
            String[] var11;
            // 无 dependsOn 依赖 略过
            if (dependsOn != null) {
                ...
            }
            // 是单例的进来
            if (mbd.isSingleton()) {
                sharedInstance = this.getSingleton(beanName, () -> {
                    try {
                        // 进来创建 Bean --注意我们这里创建出来的 bean 是 MapperFactoryBean 对象
                        return this.createBean(beanName, mbd, args);
                    } catch (BeansException var5) {
                        this.destroySingleton(beanName);
                        throw var5;
                    }
                });
                // 这里如果是普通 Bean 则返回自身,如果是 FactoryBean 则调用 FactoryBean 的 getObject() 方法进行对象的创建哈
          // 那我们这里就是调用 MapperFactoryBean 的 getObject() 方法来创建我们的 Mapper 的代理对象哈
                bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            } else if (mbd.isPrototype()) {
                ...
            } else {
                ...
            }
        } catch (BeansException var26) {
            this.cleanupAfterBeanCreationFailure(beanName);
            throw var26;
        }
    }
    ...
}

好,那我们这里就重点看两部分:

(1)createBean()方法中 MapperFactoryBean 对象的创建过程

(2)getObjectForBeanInstance()方法中,MapperFactoryBean 创建 Mapper 代理对象的过程

2.2.1  MapperFactoryBean  对象创建过程

那我们继续看 createBean(),看看创建过程:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    RootBeanDefinition mbdToUse = mbd;
    // resolvedClass 即 MapperFactoryBean.class
    Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
    ...
    Object beanInstance;
    try {
        // 执行相关后置处理器
        beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
        if (beanInstance != null) {
            return beanInstance;
        }
    } catch (Throwable var10) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);
    }

    try {
        // 创建 Bean
        beanInstance = this.doCreateBean(beanName, mbdToUse, args);
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    } catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {
        throw var7;
    } catch (Throwable var8) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);
    }
}

这里边没什么特别的处理,主要是执行后置处理器,然后我们继续看 doCreateBean()方法:

// beanName 就是 accountMapper mbd 就是 Bean定义信息
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    // 是单例的
    if (mbd.isSingleton()) {
        // 先从缓存中拿,这里要注意了,你会发现它有值?纳闷不?咦什么时候创建的呢?它哪来的?
        instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
    }
    // 是空的话,进行创建
    if (instanceWrapper == null) {
        instanceWrapper = this.createBeanInstance(beanName, mbd, args);
    }
    Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
        mbd.resolvedTargetType = beanType;
    }
    // 执行后置处理器
    synchronized(mbd.postProcessingLock) {
        if (!mbd.postProcessed) {
            try {
                this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            } catch (Throwable var17) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
            }
            mbd.postProcessed = true;
        }
    }
    ...
    Object exposedObject = bean;
    try {
        // 属性填充
        this.populateBean(beanName, mbd, instanceWrapper);
        // 初始化
        exposedObject = this.initializeBean(beanName, exposedObject, mbd);
    } catch (Throwable var18) {
        if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
            throw (BeanCreationException)var18;
        }

        throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
    }
    ...
}

我们熟悉的 doCreateBean,最重要的三步,实例化对象、属性填充、初始化。

我在调试还发现一个疑问,就是我是第一次获取 accoutMapper,怎么从 factoryBeanInstanceCache 这个缓存中获取的居然不是空值呢?它又是什么时候进去的呢?

这个问题暂时保留下,因为我还没理解透彻,只是大概估计是它来源于 BeanFactory 的 allowFacoryBeanInit,所以提前把 FactoryBean 类型的对象提前创建出来,放进了 factoryBeanInstanceCache 缓存里。

想一个问题,我们的 Mapper 接口肯定有多个,它都是从 MapperFactoryBean 对象创建出来的,那么这些 MapperFactoryBean 对象是用的同一个?还是各是各的?

从结果上来看,每个 Mapper 接口都有各自的 MapperFactoryBean 对象。

它的实例化,会提前创建好,放进 factoryBeanInstanceCache 缓存里,它的 key 是每个 mapper 接口的 bean 名字,如我的 accountMapper、userMapper哈。

接下来MapperFactoryBean 的属性填充,这里你就会发现有一个小问题或者小细节。

如果你调试的话或者在看后续 MapperFactoryBean 的getObject()方法里,会根据 sqlSessionTemplate来创建,那么对象里的 sqlSessionTemplate 什么时候有值的呢?或者会发现在创建的过程中,会伴随着 SqlSessionFactory 、MybatisProperties、MybatisAutoConfiguration SqlSessionTemplate 的创建等,你还会发现创建完,咦它的sqlSessionTemplate 怎么就有值了呢?

大概能猜到是属性填充进来的,那么我看一下 MapperFacoryBean 构造器也没有它,也没有装配,倒是有几个 set 方法:

// mapperFactoryBean 继承了 SqlSessionDaoSupport
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {}
public abstract class SqlSessionDaoSupport extends DaoSupport {
    private SqlSessionTemplate sqlSessionTemplate;
    public SqlSessionDaoSupport() {
    }
   // 设置 sqlSessionFactory
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) {
            this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory);
        }

    }
    protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
    public final SqlSessionFactory getSqlSessionFactory() {
        return this.sqlSessionTemplate != null ? this.sqlSessionTemplate.getSqlSessionFactory() : null;
    }
    // 设置 sqlsessionTemplate
    public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }
}

嘿嘿,其实来源于它的 BeanDefinition,也是我上节没注意到的一个细节:

definition.setAutowireMode(2);

就是这个装配模式,他会根据你类里的 set 方法,来进行设置。我们这里复习下这个装配模式类型:

Autowiring mode:表示自动装配的模式,用一个整形变量来表示
0:表示 no(不装配)
1:表示 byName(按名称装配)根据类的属性字段进行填充
2:表示 byType(按类型装配) 根据 set 方法进行填充
3:表示 constructor(根据构造函数装配) 构造器的填充

好啦。

初始化就跟正常的 Bean 一样了,我这里最后把整个过程画个图捋一下:

2.2.2  MapperFactoryBean 创建 Mapper 代理过程

我们接着 2.2.1 的 getObjectForBeanInstance()方法看起:

// beanInstance 此时是 MapperFactoryBean 对象 name = beanName = accountMapper 
protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    // 不是 & 开头 不获取 FactoryBean 对象本身
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        } else if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
        } else {
            if (mbd != null) {
                mbd.isFactoryBean = true;
            }

            return beanInstance;
        }
    } else if (!(beanInstance instanceof FactoryBean)) {
        return beanInstance;
    } else {
        // 走到这里
        Object object = null;
        if (mbd != null) {
            mbd.isFactoryBean = true;
        } else {
            // 第一次缓存中获取为空
            object = this.getCachedObjectForFactoryBean(beanName);
        }

        if (object == null) {
            FactoryBean<?> factory = (FactoryBean)beanInstance;
            if (mbd == null && this.containsBeanDefinition(beanName)) {
                mbd = this.getMergedLocalBeanDefinition(beanName);
            }
            // getObjectFromFactoryBean 创建
            boolean synthetic = mbd != null && mbd.isSynthetic();
            object = this.getObjectFromFactoryBean(factory, beanName, !synthetic);
        }

        return object;
    }
}

继续 getObjectFromFactoryBean() 方法:

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    if (factory.isSingleton() && this.containsSingleton(beanName)) {
        synchronized(this.getSingletonMutex()) {
            Object object = this.factoryBeanObjectCache.get(beanName);
            if (object == null) {
                object = this.doGetObjectFromFactoryBean(factory, beanName);
                Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
                if (alreadyThere != null) {
                    object = alreadyThere;
                } else {
                    if (shouldPostProcess) {
                        if (this.isSingletonCurrentlyInCreation(beanName)) {
                            return object;
                        }
                        this.beforeSingletonCreation(beanName);
                        try {
                            object = this.postProcessObjectFromFactoryBean(object, beanName);
                        } catch (Throwable var14) {
                            throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed",
                        } finally {
                            this.afterSingletonCreation(beanName);
                        }
                    }
                    if (this.containsSingleton(beanName)) {
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }
            }
            return object;
        }
    } else {
        Object object = this.doGetObjectFromFactoryBean(factory, beanName);
        if (shouldPostProcess) {
            try {
                object = this.postProcessObjectFromFactoryBean(object, beanName);
            } catch (Throwable var17) {
                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", var17);
            }
        }
        return object;
    }
}

不用细看,最后落点都是 doGetObjectFromFactoryBean 这个方法:

private Object doGetObjectFromFactoryBean(FactoryBean<?> factory, String beanName) throws BeanCreationException {
    Object object;
    try {
        if (System.getSecurityManager() != null) {
            AccessControlContext acc = this.getAccessControlContext();
            try {
                object = AccessController.doPrivileged(factory::getObject, acc);
            } catch (PrivilegedActionException var6) {
                throw var6.getException();
            }
        } else {
            // 找到我们熟悉的字眼,就是它 getObject()
            object = factory.getObject();
        }
    } catch (FactoryBeanNotInitializedException var7) {
        throw new BeanCurrentlyInCreationException(beanName, var7.toString());
    } catch (Throwable var8) {
        throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", var8);
    }
    if (object == null) {
        if (this.isSingletonCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject");
        }
        object = new NullBean();
    }
    return object;
}

嘿嘿,终于到我们的 MapperFactoryBean 对象的 getObject()方法了:

// MapperFactoryBean
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
    public SqlSession getSqlSession() {
        return this.sqlSessionTemplate;
    }
    public T getObject() throws Exception {
     // getSqlSession()就是拿到2.2.1里设置的 sqlSessionTemplate
        return this.getSqlSession().getMapper(this.mapperInterface);
    }
}
// SqlSessionTemplate
public class SqlSessionTemplate implements SqlSession, DisposableBean {
   // 最后就是通过 configuration 里获取的,这就跟我之前的文章衔接上了哈 
    public <T> T getMapper(Class<T> type) {
        return this.getConfiguration().getMapper(type, this);
    }
}

然后我们进入 Configuration 看看代理的创建:

// Configuration
public class Configuration {
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        // 交给内部的 mapperRegistry 创建
        return this.mapperRegistry.getMapper(type, sqlSession);
    }
}
// MapperRegistry
public class MapperRegistry {
    private final Configuration config;
    private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();

    public MapperRegistry(Configuration config) {
        this.config = config;
    }
    // 创建 Mapper 代理
    public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
        MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
        if (mapperProxyFactory == null) {
            throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
        } else {
            try {
          // 交给工厂创建
                return mapperProxyFactory.newInstance(sqlSession);
            } catch (Exception var5) {
                throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
            }
        }
    }
}
// MapperProxyFactory 工厂
public class MapperProxyFactory<T> {
    protected T newInstance(MapperProxy<T> mapperProxy) {
       // JDK代理方式创建
      return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
  }
  public T newInstance(SqlSession sqlSession) {
     // MapperProxy 增强器
      MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
      return this.newInstance(mapperProxy);
  }
}

顺着上一个图,我们完善下整个过程:

3  小结

好啦,本节我们主要看了 MapperFactoryBean 对象的创建过程,以及创建 Mapper 代理的过程(到configuration截至)。有一个重要的小细节也是上节没注意到的 BeanDefinition 的 autowirwMode = 2,根据方法的注入设置 SqlSessionTemplate 属性值哈。有理解不对的地方欢迎指正。

标签:Mapper,object,MapperFactoryBean,mbd,创建,beanName,源码,null
From: https://www.cnblogs.com/kukuxjx/p/18047342

相关文章

  • 网狐核心源码阅读分析
    框架结构网狐服务器整体上分为4个部分:中转服务器,房间服务器,大厅服务器,sqlserver数据库。其中大厅服务器主要负责帐号管理器:管理用户选择服务器登录地址,校验用户数据等。必需与中转服务器保持长连接,用于更新获取最新数据。房间服务器:用于加载处理每款子游戏逻辑与公共游戏逻辑(例......
  • 直播app系统源码,Android端如何实现禁止截屏或录屏
    直播app系统源码,Android端如何实现禁止截屏或录屏引言相信大家在使用某些平台应用的时候,都会有限制的规定。通常情况下,录屏、截图软件都可以在手机的运行过程中进行录屏、截图,普通的平台也不会阻止录屏、截图软件运行。但是在直播app系统源码的某些比较敏感的业务上镜上面......
  • 直播系统app源码,Android端与屏幕相关的几个注意事项
    直播系统app源码,Android端与屏幕相关的几个注意事项Android端的宽屏适配、禁止截屏和保持屏幕常亮,是直播系统app源码开发时需要注意的三个重要事项。宽屏适配越来越多的手机厂商趋向于全面屏设计,屏幕比例均超过过去常见的16:9比例。超大屏幕比例的设计对于AndroidAp......
  • Vue源码解读:响应式原理
    Vue一大特点就是数据响应式,数据的变化会作用于视图而不用进行DOM操作。原理上来讲,是利用了Object.defifineProperty(),通过定义对象属性setter方法拦截对象属性的变更,从而将属性值的变化转换为视图的变化。在Vue初始化时,会调用initState,它会初始化props,methods,data,......
  • Vue源码解读:手写一个简易版Vue
    Vue源码解读:手写一个简易版Vue</h1><divclass="clear"></div><divclass="postBody"><divid="cnblogs_post_body"class="blogpost-bodycnblogs-markdown">MVVM......
  • ConcurrentHashMap 核心源码解析
    废话不多说,直接看代码类名与HashMap很相似,数组、链表结构几乎相同,都实现了Map接口,继承了AbstractMap抽象类,大多数的方法也都是相同的publicclassConcurrentHashMap<K,V>extendsAbstractMap<K,V>implementsConcurrentMap<K,V>,Serializable核心方法Node方法......
  • Vue源码解读(预):手写一个简易版Vue
    Vue源码解读(预):手写一个简易版Vue MVVM设计模式,是由MVC、MVP等设计模式进化而来,M-数据模型(Model),VM-视图模型(ViewModel),V-视图层(View)。MVVM的核心是ViewModel层,它就像是一个中转站(valueconverter),负责转换Model中的数据对象来让数据变得更容易管理和使用,该层向上与视......
  • Eureka源码分析
     注册中心1、Register:服务注册  当Eureka客户端向EurekaServer注册时,它提供自身的元数据,比如IP地址、端口,运行状况指示符URL,主页等    1.1、服务端注册    会拉取配置的注册中心地址,向附近注册服务注册    1.2、客户端注册客户端第一次续约会失败,因......
  • 龙哥量化:通达信(副图)筹码线起爆指标公式源码
    如果您需要代写公式,请联系我。龙哥QQ:591438821龙哥微信:Long622889这是个副图公式,如果需要改成选股公式,我随时在线 筹码密集度:(COST(90+(100-90)/2)-COST((100-90)/2))/(COST(90+(100-90)/2)+COST((100-90)/2))+CLOSE,COLORYELLOW,LINETHICK2;X_1:=REF(HHV(筹码密集度,......
  • 龙哥量化:通达信(副图)选股公式源码均线、macd、skdj、kdj、rsi、dmi、cci,vol共振
    如果您需要代写公式,请联系我。龙哥QQ:591438821龙哥微信:Long622889 这个公式是几个指标的共振。新建一个条件选股公式,新建一个副图公式,都用下面的源码; {取消的股票 }T1:=IF(NAMELIKE('ST'),0,1)ANDIF(NAMELIKE('*'),0,1);T2:=NOT(CODELIKE('688'));T3:=NOT(CODELI......