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; } }
浙公网安备 33010602011771号