mybatis与spring集成源码分析

思考spring能帮助用户干什么

	管理各种各样的bean,包括创建,获取等生命周期。
	简化用户的调用。

思考spring启动流程中,bean被创建过程中有哪些对外接口提供扩展

	在SqlSessionFactoryBean中能看到实现了Bean的3个对外接口,FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener。
	在BeanDefinitionRegistryPostProcessor中实现了4个对外接口,BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware。
	其中FactoryBean是用来获取Bean对象的,BeanDefinitionRegistryPostProcessor是用来注册管理bean的。

mybatis使用的关键步骤

  1. 创建会话工厂,用来解析配置文件。
  2. 创建会话和执行器,包装插件等。
  3. 创建mapper接口代理对象
  4. 执行代理对象invoke方法

spring集成步骤

  1. 引入mybatis-spring的jar包
  2. 在spring配置文件中注册SqlSessionFactoryBean,这个类从名字来看,就是为了创建SqlSessionFactory会话工厂的。
    它实现了FactoryBean的getObject方法,如下:
public SqlSessionFactory getObject() throws Exception {
        if (this.sqlSessionFactory == null) {
            this.afterPropertiesSet();
        }

        return this.sqlSessionFactory;
    }
public void afterPropertiesSet() throws Exception {
        Assert.notNull(this.dataSource, "Property 'dataSource' is required");
        Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
        Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
        this.sqlSessionFactory = this.buildSqlSessionFactory();
    }

在buildSqlSessionFactory方法中的最后一句,返回了sqlSessionFactory的实例。

return this.sqlSessionFactoryBuilder.build(targetConfiguration);
  1. 由于mybaits提供的默认实现DefaultSqlSession是非线程安全的,需要每次执行会话前创建新的SqlSession实例,而spring默认是单例,因此mybatis-spring用SqlSessionTemplate来替代DefaultSqlSession。在实例化SqlSessionTemplate的时候,创建了一个代理类。
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
        Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
        Assert.notNull(executorType, "Property 'executorType' is required");
        this.sqlSessionFactory = sqlSessionFactory;
        this.executorType = executorType;
        this.exceptionTranslator = exceptionTranslator;
        this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
    }

由SqlSessionTemplate的内部类SqlSessionInterceptor来代理执行。

private class SqlSessionInterceptor implements InvocationHandler {
        private SqlSessionInterceptor() {
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);

            Object unwrapped;
            try {
                Object result = method.invoke(sqlSession, args);
                if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
                    sqlSession.commit(true);
                }

                unwrapped = result;
            } catch (Throwable var11) {
                unwrapped = ExceptionUtil.unwrapThrowable(var11);
                if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
                    SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                    sqlSession = null;
                    Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
                    if (translated != null) {
                        unwrapped = translated;
                    }
                }

                throw (Throwable)unwrapped;
            } finally {
                if (sqlSession != null) {
                    SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                }

            }

            return unwrapped;
        }
    }

getSqlSession方法中会将SqlSession管理在ThreadLocal中

private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal("Transactional resources");

这样,对于每次请求,都时线程安全的。

  1. 在spring配置文件中注册MapperScannerConfigurer,用来扫描接口映射。它实现了BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,用来向IoC中注册每个接口bean的实例。接口不能被直接注入使用,那么肯定接口的对象肯定会被替换成实现类。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        if (this.processPropertyPlaceHolders) {
            this.processPropertyPlaceHolders();
        }

        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.setAddToConfig(this.addToConfig);
        scanner.setAnnotationClass(this.annotationClass);
        scanner.setMarkerInterface(this.markerInterface);
        scanner.setSqlSessionFactory(this.sqlSessionFactory);
        scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
        scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
        scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
        scanner.setResourceLoader(this.applicationContext);
        scanner.setBeanNameGenerator(this.nameGenerator);
        scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
        if (StringUtils.hasText(this.lazyInitialization)) {
            scanner.setLazyInitialization(Boolean.valueOf(this.lazyInitialization));
        }

        scanner.registerFilters();
        scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
    }
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        if (beanDefinitions.isEmpty()) {
            LOGGER.warn(() -> {
                return "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.";
            });
        } else {
            this.processBeanDefinitions(beanDefinitions);
        }

        return beanDefinitions;
    }

在processBeanDefinitions方法中看到,definition.setBeanClass(this.mapperFactoryBeanClass);接口对象被替换成为MapperFactoryBean对象,而MapperFactoryBean又继承了SqlSessionDaoSupport类,SqlSessionDaoSupport又包含SqlSessionTemplate属性。

因此在调用注入的接口对象,实际上被SqlSessionTemplate的代理类所替代。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值