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; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix