Spring整合MyBatis的底层原理是什么

Spring整合MyBatis的底层原理分为以下几点:1、Mybatis如何生成代理对象;2、Spring中如何声明一个bean;3、模拟代理对象转化Spring的bean过程。其中,Mybatis如何生成代理对象在org.mybatis:mybatis.jar包中给我们提供了一些方法。

Spring整合MyBatis的底层原理是什么-Worktile社区

一、Mybatis如何生成代理对象

在 org.mybatis:mybatis.jar包中给我们提供了一些方法。下面代码是运用mybatis来生成代理对象。

public class MybatisTest {
    public static void main(String[] args) throws IOException {
            // 1. 创建SqlSessionFactoryBuilder对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            // 2. 加载SqlMapConfig.xml配置文件
            InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
            // 3. 创建SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
            // 4. 创建SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 5.执行sql
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);// 获得一个(动态代理)UserMapper接口的实现类对象
            System.out.println(userMapper.selectById());
            // 6.释放资源
            sqlSession.close();
        }
    }

二、Spring中如何声明一个bean

定义bean分为两种方式:

名列前茅种:声明式,例如:我们通常使用的@Bean注解,@Service注解,@Component注解等等。

第二种:编程式 ,运用BeanDefinition来创建一个bean,下面看代码:

public class User {
    public void fff(){
        System.out.println("初始化方法");
    }
}
    public static void main(String[] args) {
        //使用AnnotationConfigApplicationContext可以实现基于Java的配置类加载Spring的应用上下文。避免使用application.xml进行配置。相比XML配置,更加便捷。
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AppConfig.class);
 
        //获取beanDefinition对象
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        //创建User类的bean
        beanDefinition.setBeanClass(User.class);
        beanDefinition.setScope("prototype"); //bean单例模式改为原型模式
        beanDefinition.setInitMethodName("fff"); //设置bean的初始化方法
        //设置bean的名称
        applicationContext.registerBeanDefinition("xxx",beanDefinition);
        applicationContext.refresh();
          /**
         * 打印结果
         * 初始化方法
         * com.example.service.User@3b94d659
         * 初始化方法
         * com.example.service.User@24b1d79b
         * 初始化方法
         * com.example.service.User@68ceda24
         */
        System.out.println(applicationContext.getBean("xxx"));
        System.out.println(applicationContext.getBean("xxx"));
        System.out.println(applicationContext.getBean("xxx"));
 
 
 
//        UserService userService = applicationContext.getBean(UserService.class);
//        userService.test();
    }

通过上述代码我们可以使用BeanDefinition来创建一个bean。但是如果我的User类如果是一个接口通过BeanDefinition就不能实现了。我们可以通过FactoryBean来创建bean。

在下面代码:由于beanDefinition.setBeanClass(FactoryBeanTest.class);这行代码我们创建的是FactoryBeanTest.class这个类型的bean,但是FactoryBeanTest 类实现了FactoryBean这个接口最后返回给我们一个User类型的bean。这样我们就实现了动态的获取bean。

public class FactoryBeanTest implements FactoryBean {
    //getObject方法返回的bean,会放到spring容器里面去
    @Override
    public Object getObject() throws Exception {
        return new User();
    }
    //getObjectType方法是返回bean的类型
    @Override
    public Class<?> getObjectType() {
        return null;
    }
}
public class TestApplication {
    public static void main(String[] args) {
        //使用AnnotationConfigApplicationContext可以实现基于Java的配置类加载Spring的应用上下文。避免使用application.xml进行配置。相比XML配置,更加便捷。
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AppConfig.class);
        //获取beanDefinition对象
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        //创建User类的bean
        beanDefinition.setBeanClass(FactoryBeanTest.class);
        //设置bean的名称
        applicationContext.registerBeanDefinition("xxx",beanDefinition);
        applicationContext.refresh();
        System.out.println(applicationContext.getBean("xxx"));
 
    }
}

三、模拟代理对象转化Spring的bean过程

首先我们通过Proxy.newProxyInstance方法去模拟一个代理对象,然后通过FactoryBean将这个代理对象放入SpringBean容器中。然后通过调用UserService.test方法我们可以发现:在执行UserService.test方法时会调用userMapper代理对象的selectById())的方法,

那么在调用代理对象时会先调用代理对象的代理逻辑里面也就是invoke方法,然后再去调用代理对象的selectById())的方法。

这样我们就做到了将mybatis的代理对象转化位bean放入到spring容器中。

public class FactoryBeanTest implements FactoryBean {
 
    @Override
    public Object getObject() throws Exception {
        /**
         * 参数:类加载器,代理的接口,代理的逻辑
         */
        Object proxyInstance = Proxy.newProxyInstance(FactoryBeanTest.class.getClassLoader(), new Class[]{UserMapper.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method.getName());
                return null;
            }
        });
        return proxyInstance;
    }
 
    @Override
    public Class<?> getObjectType() {
        return UserMapper.class;
    }
}
/**
 * 在spring boot中设置的IOC容器中设置包扫描
 */
@ComponentScan("com.example.*")
@Configuration
public class AppConfig {
}
public class TestApplication {
    public static void main(String[] args) {
        //使用AnnotationConfigApplicationContext可以实现基于Java的配置类加载Spring的应用上下文。避免使用application.xml进行配置。相比XML配置,更加便捷。
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(AppConfig.class);
        //获取beanDefinition对象
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        //创建User类的bean
        beanDefinition.setBeanClass(FactoryBeanTest.class);
        //设置bean的名称
        applicationContext.registerBeanDefinition("xxx",beanDefinition);
        applicationContext.refresh();
       UserService userService = applicationContext.getBean(UserService.class);
       userService.test();
    }
}

来源:本文为CSDN博主「愉悦滴帮主)」的原创文章
原文链接:https://blog.csdn.net/qq_45065241/article/details/117526487

延伸阅读

MapperScannerConfigure底层工作原理 

MapperScannerConfigurer 支 持 过 滤 由 指 定 的 创 建 接 口 或 注 解 创 建 映 射 器 。我们可以自己定义MapperScannerConfigurer 这个注解,指定扫描路径,就不需要MapperScan这个注解了。这时新版本提供的一种方式。

package com.example.config;
 
import com.example.service.ScanTest;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;
 
/**
 * 在spring boot中设置的IOC容器中设置包扫描
 */
@ComponentScan("com.example.*")
@ScanTest("com.example.dao")
@Configuration
public class AppConfig {
    @Bean
    public MapperScannerConfigurer configurer(){
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setBasePackage("com.example.dao");
        return configurer;
    }
    
    
    @Bean
    public DataSource dataSource(){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/login?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("admin");
        return dataSource;
    }
    @Bean
    public SqlSessionFactory sqlSessionFactory(){
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        try {
            return sessionFactory.getObject();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
 
}

接下来让我们看一下MapperScannerConfigurer类的源码 看看是如何自动扫描的。 

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    if (this.processPropertyPlaceHolders) {
      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.registerFilters();
    scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
  }

文章标题:Spring整合MyBatis的底层原理是什么,发布者:小编,转载请注明出处:https://worktile.com/kb/p/37282

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小编小编认证作者
上一篇 2023年2月7日 下午3:58
下一篇 2023年2月7日 下午4:42

相关推荐

  • devops中文叫什么

    DevOps即开发运维一体化,是一组过程、方法与系统的统合,旨在促进开发(Dev)与操作维护(Ops)的协同工作。1、改善沟通与协作、2、自动化软件交付过程、3、提升产品上线速度、4、确保系统质量与可靠性,其中1、改善沟通与协作对促进团队效率有着至关重要的意义,通过消除隔阂与误解,确保团队间信息的准…

    2024年3月26日
    7100
  • 什么是 Smurf 攻击

    Smurf 攻击是分布式拒绝服务 (DDoS) 攻击的一种形式,该攻击会导致计算机网络停止服务。Smurf 程序通过利用互联网协议 (IP) 和互联网控制消息协议 (ICMP) 的漏洞来实现其目的。 什么是 Smurf 攻击 Smurf 攻击是分布式拒绝服务 (DDoS) 攻击的一种形式,该攻击会导…

    2022年11月7日
    1.0K00
  • 现在业界主要使用php的哪个框架

    现在业界主要使用php的框架有以下几个:1、Yii;2、CodeIgniter;3、CakePHP;4、PHPDevShell;5、Akelos;6、Symfony;7、Prado;8、 Zend;9、ZooP;10、 QPHP。Yii是一个基于组件的高性能的PHP的框架,用于开发大规模Web应用。…

    2023年2月19日
    57700
  • 产品经理应如何提高沟通技巧

    开篇直接回答:提高沟通技巧的途径有:1、明确沟通目的、2、精通产品知识、3、倾听和反馈、4、了解受众、5、练习非语言沟通、6、处理冲突、7、持续学习和训练。在这其中,精通产品知识对于产品经理至关重要,因为只有对自己管理的产品有深刻理解,产品经理才能够清楚地表达产品的功能、优势和开发进度,并且能够针对…

    2023年12月19日
    28700
  • 计算机网络技术和移动应用开发有哪些区别

    计算机网络技术和移动应用开发区别有:1、技术特点;2、平台和设备;3、应用场景;4、技能要求。计算机网络技术涉及到在计算机之间传输数据和信息的技术。计算机网络技术涉及到在计算机之间传输数据和信息的技术。 一、技术特点 二、平台和设备 三、应用场景 四、技能要求 延伸阅读 边缘计算和移动应用开发的结合…

    2023年7月30日
    59000
  • 研发考核制度方案

    研发考核制度方案应围绕以下三个核心部分展开:1、明确的考核目标与指标体系、2、全面的考核方法与流程、3、公正的结果应用与反馈机制。 其中,2、全面的考核方法与流程是确保考核效果的关键所在。这部分需确保考核的过程具有客观性和公正性,能够全方位、多维度地评价研发人员的表现和贡献。 一、考核目标与指标体系…

    2024年1月10日
    22500
  • mysql常用命令

    MySQL是一款流行的开源关系型数据库管理系统,它支持标准的SQL(结构化查询语言)。MySQL的常用命令可以分为:数据定义语言(DDL),包括创建、修改、删除数据库和表等;数据操作语言(DML),包括插入、更新、删除数据等;数据查询语言(DQL),包括查询数据等。这些命令可以帮助用户有效管理和操作…

    2023年5月15日
    44700
  • DevOps项目中如何处理版本控制

    在DevOps项目管理中,版本控制是核心组成部分,以确保代码的持续集成和交付。版本控制体系需兼顾效率与安全,包括但不限于:1、选择合适的版本控制系统、2、制定详细的分支策略、3、确保提交准则的一致性、4、应用自动化构建与测试、5、持续集成的实践、6、版本发布与回退策略的制定。其中,分支策略起到了枢纽…

    2024年1月2日
    22400
  • 设计与管理的关系是怎样的

    设计与管理之间的联系紧密无间,1)相互依存、2)相云辅助、3)相互影响。设计不单纯只是外观的创作过程,它还包括了规划、策略与实用性等方面,这都需要良好的管理来支撑。在这样的互动下,管理工作也会受到设计思维的影响,尤其在决策、团队协作与资源分配上。详细来说,设计推动管理向着更加人性化、创新性发展,它促…

    2024年1月9日
    37400
  • vip域名注册有什么优势

    vip域名注册有什么优势:1、知名度广泛;2、品相好;3、适用性广泛。其中,知名度广泛是指,任何人都知道它的含义,简单易懂,符合国人的思维和选择的特征。VIP域名是中国乃至世界范围内,最受瞩目、最令人期待的域名之一。 一、知名度广泛 任何人都知道它的含义,简单易懂,符合国人的思维和选择的特征 二、品…

    2023年6月3日
    28900

发表回复

登录后才能评论
注册PingCode 在线客服
站长微信
站长微信
电话联系

400-800-1024

工作日9:30-21:00在线

分享本页
返回顶部