Mapper的实现方式

在使用mybatis时,我们可以看到用mapper接口直接调用数据库语句。这不是很奇怪吗?首先是接口怎么可能能spring注入,接口没有构造方法,spring中肯定没有这个bean对象。

其实他这边用了动态代理。

        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Config.class);
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        beanDefinition.setBeanClass(WxyFactoryBean.class);
        annotationConfigApplicationContext.registerBeanDefinition("aaa",beanDefinition);//进行注册beanDefinition       
        System.out.println(annotationConfigApplicationContext.getBean("aaa"));//
        System.out.println(annotationConfigApplicationContext.getBean("&aaa"));
复制代码
//实现FactoryBean接口
public
class WxyFactoryBean implements FactoryBean { @Override public Object getObject() throws Exception { People people = new People(); return people; } @Override public Class<?> getObjectType() { return People.class; } }
复制代码

wxy.People@1a84f40f
mybatis.WxyFactoryBean@6b419da

 

可以看到WxyFactoryBean实现了FactoryBean,这时候他生产出了2个bean对象,一个是WxyFactoryBean本身、一个是People对象。但是aaa指的是People对象,&aaa指的是WxyFactoryBean对象。

这个现在目前还是无法看出是动态代理的痕迹。先别急,这个是想让我们有一定的基础,认识到FactoryBean对象的作用。

 

复制代码
public class WxyFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        Object instance = Proxy.newProxyInstance(WxyFactoryBean.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 instance;
    }

    @Override
    public Class<?> getObjectType() {
        return UserMapper.class;
    }
}
复制代码
复制代码
@Component
public class UserService {

    @Autowired
    private UserMapper userMapper;//是一个接口类

    public void test(){
        System.out.println(userMapper.selectById());
    }

}
复制代码

过程虽然简陋了点,但是实现userMapper注入的本质就是这样,在WxyFactoryBean 的getObject方法中使用UserMapper动态代理。

可以看mybatis中文官网中的介绍,这里的MapperFactoryBean指的就是WxyFactoryBean,UserMapper就是我们的UserMapper。

springboot的集成中,就有了<artifactId>mybatis-spring</artifactId>用来解决这个问题。就是用来替代WxyFactoryBean,但是还不仅仅于此,可以看继续下面。

 

 

==================================

但是因为要把具体的Mapper类(UserMapper)写死传进来,这样明显是不符合的,如果在创建一个OrderMapper,就又要写一个FactoryBean了。所以需要对他进行改进。

首先是Mapper不能写死,所以需要有一个扫描类,这样可以将所有的Mapper扫描进来。

 

 

复制代码
public class WxyMapperScanner extends ClassPathBeanDefinitionScanner {
    public WxyMapperScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        //将接口给扫描出来  并获取到
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        for (BeanDefinitionHolder beanDefinitionHolder:beanDefinitionHolders){
            BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
            //调用构造方法将参数传入
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
            beanDefinition.setBeanClassName(WxyFactoryBean.class.getName());
        }
        return beanDefinitionHolders;
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isInterface();//将接口给返回出来
    }
}
复制代码
复制代码
public class WxyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
    }

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        String path = "mapper";
        WxyMapperScanner wxyMapperScanner = new WxyMapperScanner(registry);

        wxyMapperScanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                return true;
            }
        });

        wxyMapperScanner.scan(path);

    }
}
复制代码
复制代码
public class WxyFactoryBean implements FactoryBean {
    private Class mapperClass;

    private SqlSession sqlSession;

    public WxyFactoryBean(Class mapperClass) {
        this.mapperClass = mapperClass;
    }

    @Autowired
    public void setSqlSession(SqlSessionFactory sqlSessionFactory) {
        this.sqlSession = sqlSessionFactory.openSession();
    }

    @Override
    public Object getObject() throws Exception {

        return sqlSession.getMapper(mapperClass);
    }

    @Override
    public Class<?> getObjectType() {
        return mapperClass;
    }
}
复制代码

 

posted @   WXY_WXY  阅读(186)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示