简单模拟mybatis的MapperScan

简单模拟mybatis的MapperScan一、问题描述在mybatis中,mapper通常是一个接口,但是我们却可以直接通过这个接口调用方法。按道理来说接口是不能直接调用方法的,只有实现类才能调用接口。但在下面的代码中,我们直接调用applicationContext.getBean(TestMapper.class).list(“”),就可以查询我们的数据库。也就是说applicationContext.getBean(TestMa…

大家好,又见面了,我是你们的朋友全栈君。

一、问题描述

在mybatis中,mapper通常是一个接口,但是我们却可以直接通过这个接口调用方法。按道理来说接口是不能直接调用方法的,只有实现类才能调用接口。但在下面的代码中,我们直接调用applicationContext.getBean(TestMapper.class).list(“”),就可以查询我们的数据库。
也就是说applicationContext.getBean(TestMapper.class)拿到的是一个代理对象并存在spring容器中,只不过这些都由@MapperScan这个注解帮我们实现了。接下来我们自己写一个简单的scan,拿到sql语句。

public interface TestMapper {
    @Select("SELECT * FROM test")
    public List<Map<String,Object>> list(String str);
}
public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        applicationContext.getBean(TestMapper.class).list("");
}
@Configuration
@ComponentScan("com.stay")
@MapperScan("com.stay.dao")
public class AppConfig {
    @Bean
    public DataSource dataSource(){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("xxx");
        dataSource.setUrl("xxx");
        return dataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setLogImpl(Log4jImpl.class);
        sqlSessionFactoryBean.setConfiguration(configuration);
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }
}

在这里插入图片描述

二、分析

第一步:将TestMapper接口变成一个对象。
第二步:这个对象必须实现了TestMapper接口。
第三步:把这个对象放入spring容器中。
第一、二步可以使用我们的动态代理,jdk动态代理基于接口,符合我们的需求。
第三步需要把我们的动态代理对象放到spring容器中,这里需要把一个class转成bd,再注册到spring容器中。
1、如果将TestMapper直接注入的话,spring容器是创建不出来的,它是一个接口。
2、怎样才能把我们生成的动态代理给注册到spring容器中。
这里我们通过实现ImportBeanDefinitionRegistrar接口,动态注册给spring,并修改beanDefinition的BeanClass让它变成一个factoryBean,在getObject方法中,返回我们的代理对象。(这里有个知识点FactoryBean,大家可以去了解下)。

三、代码实现

1、自定义注解TestScan

@Retention(RetentionPolicy.RUNTIME)
@Import(MyImportBeanDefinitionRegistrar.class)
public @interface TestScan {
}

2、实现ImportBeanDefinitionRegistrar接口,动态注册beanDefinition到spring容器。

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(TestMapper.class);
        GenericBeanDefinition beanDefinition = (GenericBeanDefinition)builder.getBeanDefinition();
        //因为factoryBean.getObject方法返回的是代理对象,所以我们需要将TestMapper.class传进去
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(TestMapper.class.getName());
        //动态修改beanClass为FactoryBean
        beanDefinition.setBeanClass(MyFactoryBean.class);
        //将beanDefinition注册到spring容器中
        registry.registerBeanDefinition("testMapper",beanDefinition);
    }
}

3、实现FactoryBean和InvocationHandler接口。FactoryBean实际会创建2个bean,一个是MyFactoryBean对象本身,通过&+beanName来获取,一个是getObject返回的对象,通过当前的beanName来获取。而当我们执行testMapper的list方法的时候,实际上是执行了实现InvocationHandler 接口的invoke方法。

public class MyFactoryBean implements FactoryBean,InvocationHandler {

    Class clazz;
    public MyFactoryBean(Class clazz){
        this.clazz = clazz;
    }

    public Object getObject() throws Exception {
        Class[] clazzs = new Class[]{clazz};
        //jdk动态代理
        Object proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(), clazzs, this);
        return proxy;
    }

    public Class<?> getObjectType() {
        return clazz;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy");
        Method method1 = proxy.getClass().getInterfaces()[0].getMethod(method.getName(), String.class);
        Select select = method1.getDeclaredAnnotation(Select.class);
        //打印sql语句
        System.out.println(select.value()[0]);
        System.out.println("执行sql查询.....");
        return null;
    }
}

4、将MapperScan换成TestScan

@Configuration
@ComponentScan("com.stay")
@TestScan
public class AppConfig {

    @Bean
    public DataSource dataSource(){
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUsername("root");
        dataSource.setPassword("xxx");
        dataSource.setUrl("xxx");
        return dataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setLogImpl(Log4jImpl.class);
        sqlSessionFactoryBean.setConfiguration(configuration);
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }
}

5、输出结果
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/138914.html原文链接:https://javaforall.net

(1)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 墙裂推荐9个在线图片压缩网站[通俗易懂]

    墙裂推荐9个在线图片压缩网站[通俗易懂]转载自:https://www.zcool.com.cn/article/ZNTQzNDYw.html?switchPage=on1.Tinypng网址:https://tinypng.com/Tinypng可以说是很受大家欢迎的一个图片压缩站点,不管对于前端工程师或者设计师来说都是一个不错的图片压缩工具。Tinypng的操作方式也十分的简单,上传、压缩、下载,流程十分的简单,网站不仅仅支…

    2022年6月18日
    33
  • 动静分离架构[通俗易懂]

    动静分离架构[通俗易懂]1.应用场景了解更多,根据具体场景选用不用的技术进行架构优化. 2.学习/操作 一、静态页面 静态页面,是指互联网架构中,几乎不变的页面(或者变化频率很低),例如: 首页等html页面 js/css等样式文件 jpg/apk等资源文件 静态页面,有与之匹配的技术架构来加速,例如: CDN ngi…

    2022年4月29日
    45
  • CSS样式表的引入方式

    CSS样式表的引入方式CSS初识CSS(CascadingStyleSheets)美化样式CSS通常称为CSS样式表或层叠样式表(级联样式表),主要用于设置HTML页面中的文本内容(字体、大小、对齐方式等)、图片的外形(宽高、边框样式、边距等)以及版面的布局等外观显示样式。CSS以HTML为基础,提供了丰富的功能,如字体、颜色、背景的控制及整体排版等CSS的优点1.内容与表现分离。2.网页的表现统一,容易修改。3.丰富的样式,使得页面布局更加灵活4.减少网页的代码量,增加网页的浏览速度。5.运用独立于页面

    2022年7月14日
    17
  • springboot多环境配置文件_Springboot教程

    springboot多环境配置文件_Springboot教程第一步:三个配置文件,分别是默认配置application.yaml、开发配置application-dev.yaml、生产配置application-pro.yaml第二步:SpringBoot默认加载的是application.yaml,想要默认加载其他配置文件,需要在application.yaml中配置:这样加载的就是生产环境的配置了,打包打的也是application-pro.yaml文件。本地开发的时候也是加载的pro文件。第三步:想要打包的时候用pro文件,IDE开发的时候用的

    2022年9月26日
    2
  • xtrabackup部署以及使用

    xtrabackup部署以及使用

    2021年11月27日
    43
  • jenkins 邮件_jmeter测试报告生成

    jenkins 邮件_jmeter测试报告生成前言前面已经实现在jenkins上展示html的测试报告,接下来只差最后一步,把报告发给你的领导,展示你的劳动成果了。安装EmailExtensionPlugin插件jenkins首页-

    2022年7月31日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号