TypechoJoeTheme

Clover 的博客

统计
登录
用户名
密码
/
注册
用户名
邮箱

CloverYou

日出于东却落于西,相识人海却散于席。

手撸Spring整合MyBatis玩具

2022-01-02
/
0 评论
/
28 阅读
/
正在检测是否收录...
01/02

源码在我GitHub上,有兴趣可以去观望一下:传送门

这个只是个玩具、玩具、玩具,正经的还得看官方提供的整合包
先说下这个玩具的问题所在吧!====>>> 无法提交事务和无法关闭SqlSession,嗯嗯嗯~~~

开始吧~~


难点

若想使用Spring容器提供的强大功能,例如:Autowired,那么就需要让Spring容器将其管理。

没整合之前,每次都需要通过SqlSessionFactory将其创建,一个两个还好,写多了整个人都麻了...

所以我就想,能不能在service层直接注入呢?

让Spring注入的话就得注册到容器,Dao层数量和命名都无法确定,怎么注册Bean呢?..嘶~~~

嗯。。。使用工厂模式加上自动扫包好像能实现..

说干就干...

@Configuration
public class MyBatisSqlSessionFactory implements Serializable {

    private static final long serialVersionUID = 7157094465332447639L;

    /**
     * MyBatis配置文件路径
     */
    private static final String MYBATIS_CONFIG_PATH = "mybatis-config.xml";

    /**
     * 注册一个全局SqlSessionFactory组件
     */
    @Bean
    public SqlSessionFactory getSqlSessionFactory() throws IOException {
        System.out.println("getSqlSessionFactory");
        try (InputStream configStream = getConfigStream()) {
            return new SqlSessionFactoryBuilder().build(configStream);
        }
    }

    /**
     * 懒加载Bean工厂
     * @param daoClass Bean类型
     * @param <T> Bean类型
     */
    @Bean
    public static <T> T getMapping(Class<T> daoClass) {
        SpringUtils springUtils = new SpringUtils();
        SqlSessionFactory bean = springUtils.getBean(SqlSessionFactory.class);
        SqlSession sqlSession = bean.openSession();
        return sqlSession.getMapper(daoClass);
    }

    /**
     * 获取配置文件文件流
     * @return 文件流
     */
    public InputStream getConfigStream() throws IOException {
        return Resources.getResourceAsStream(MYBATIS_CONFIG_PATH);
    }

}

嗯?我该怎么为getMapping注册为懒加载呢???还有Class<T> daoClass我该怎么拿到当前getBean时要找的类型呢?

嘶~~~

嘶~~~

嘶~~~

更换方案

翻了翻ClassPathXmlApplication源码,启动的时候它去执行了个后置处理器org.springframework.beans.factory.config.BeanFactoryPostProcessor。这个处理器需要实现一个postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory),这个ConfigurableListableBeanFactory就是那个还未启动完成的容器。嗯嗯嗯...

它里面有一个registerSingleton方法,可以注册单实例Bean,可我需要注册多实例...先不管了

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory)
  throws BeansException {
  this.configurableListableBeanFactory = configurableListableBeanFactory;
  if (factory == null) {
    factory = configurableListableBeanFactory.getBean(SqlSessionFactory.class);
  }
  RegisterMyBatisFactory registerMyBatisFactory = configurableListableBeanFactory.getBean(
    RegisterMyBatisFactory.class);

  if (registerMyBatisFactory == null) return;
  String mapperPackage = registerMyBatisFactory.getPackage();
  // 获取指定包下所有class
  List<Class<?>> allClass = getClassByPackage(mapperPackage);
  // 通过@Mapper过滤无效class
  List<Class<?>> interfaceByWithMyBatis = getInterfaceByMapper(allClass);
  // 将所有Mapper注册到IOC中
  registerMyBatis(interfaceByWithMyBatis);
}
  • this.configurableListableBeanFactory = configurableListableBeanFactory; 保存这个容器
  • RegisterMyBatisFactory registerMyBatisFactory = configurableListableBeanFactory.getBean(RegisterMyBatisFactory.class); 这里定义了个接口,通过这个借口拿到Dao所在的包。

    /**
     * mybatis,将其注册在容器中,整合器就可以获取到指定包名
     */
    public interface RegisterMyBatisFactory {
    
      /**
       * 获取mapper所在的包
       */
      String getPackage();
    
    }
  • List<Class<?>> allClass = getClassByPackage(mapperPackage); 通过包名找这个包下所有的类,这个方法就不说了,就一个普通的文件查找而已。有兴趣就拉源码吧!
  • List<Class<?>> interfaceByWithMyBatis = getInterfaceByMapper(allClass);需要过滤没有用的类,也就是说可能不是Dao。通过MyBatis提供的@Mapper注解来识别了,懒得自己写注解,先把功能实现。就一个简简单单的反射

    /**
     * 通过指定注解获取接口
     * @return 过滤结果
     */
    private List<Class<?>> getInterfaceByMapper(List<Class<?>> clazz) {
      return clazz.stream().filter(aClass -> {
        if (!aClass.isInterface()) return false;
        Mapper annotation = aClass.getAnnotation(Mapper.class);
        return annotation != null;
      }).collect(Collectors.toList());
    }
  • registerMyBatis(interfaceByWithMyBatis); 接下来就将过滤后的Mapper注册到容器中了。如果是注册的多实例Bean,那么就可以通过切面去搞定这个事务问题。

    /**
     * 将MyBatis注册到IOC
     */
    private void registerMyBatis(List<Class<?>> mappers) {
      mappers.forEach(clazz -> {
        SqlSession sqlSession = factory.openSession();
        Object mapper = sqlSession.getMapper(clazz);
        configurableListableBeanFactory.registerSingleton(clazz.getName(), mapper);
      });
    }

使用演示

Dao层用@Mapper标注

@Mapper
public interface EmployeeDao extends GenericDao<Employee> {...}

service层直接注入。

@Service
public class EmployeeServiceImpl implements Serializable, EmployeeService {

    private static final long serialVersionUID = 1863674392751816610L;

    @Autowired
    private EmployeeDao employeeDao;
}

现在就可以了.....

{"id":1,"empName":"Clover","gender":0,"email":"cloveryou.ctong@qq.com"}
SpringMvc随笔
朗读
赞(0)
版权属于:

Clover 的博客

本文链接:

https://www.ctong.top/index.php/archives/72/(转载时请注明本文出处及文章链接)

评论 (0)
CloverYou
日出于东却落于西,相识人海却散于席。
88 文章数
11 评论量
IP信息

人生倒计时

今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月

最新回复

  1. 缓存一致性 - 点击领取
    2022-01-06
  2. 宝宝
    2022-01-02

标签云