mybaits3 源码深度解析-mybatis与spring 整合

  • mybaits spring 实现原理
  • spring 容器启动过程

Spring 中常见类介绍

1 BeanDefinition 用于封装 spring bean 的配置信息

2 BeanDefinitionRegistry 用于存放解析后的BeanDefinition对象,spring 提供了扩展机制,允许用户在 spring 框架启动时动态的往BeanDefinitionRegistry容器中注册对象

3 BeanFactory 是 Spring 的Bean 工厂,负责 Bean 创建和属性注入

4 BeanFactoryPostProcessor 是 spring 提供的扩展机制,用于在所有 Bean 配置信息解析完成后,修改 Bean 工厂信息.例如向BeanDefinitionRegistry注册BeanDefinition对象

5 ImportBeanDefinitionRegistrar接口作用于 Spring 解析 Bean 的配置阶段,当解析@Configuration 注解时调用. 需要配合@Import 注解使用

6 BeanPostProcessor Bean 的后置处理器.在 Bean 初始化方法(init-method 属性指定的方法或者 afterPropertiesSet()方法)调用前后,会执行 BeanPostProcessor的拦截逻辑

7 ClassPathBeanDefinitionScanner 是BeanDefinition扫描器,能够对象指定包下的 Class 进行扫描,将 Class 转换为BeanDefinition对象注册到BeanDefinitionRegistry 容器中

8 FactoryBean 是 Spring 中的工厂 bean,通常用于处理 spring 中配置较为复杂或者由动态代理生成的 Bean 实例.

实现了该接口的 Bean 不能作为普通的 Spring bean 使用而是作为单个对象的工厂.

当通过 Bean 名称获取 FactoryBean 实例时,获取到的并不是FactoryBean对象本身,而是FactoryBean对象 getObject()方法返回的对象

  • BeanDefinition 用于封装 spring bean 的配置信息,spring bean 配置方式有 3 种:
//1 xml 方式配置 <beans> <bean id="myService" class="com.acme.services.MyServiceImpl"/> </beans> //2 java 注解, 如:@Service @Component //3 java config 方式 (spring 3.0 开始支持) @Configuration public class AppConfig { @Bean public MyService myService() { return new MyServiceImpl(); } }

Spring 容器在启动的时候,首先会对 Bean 的配置进行解析,把 Bean 的配置信息转换为BeanDefinition对象.

BeanDefinition是一个接口,通过不同的实现类来描述不同方式配置的 Bean 信息

  • BeanFactoryPostProcessor 是 spring 提供的扩展机制,用于在所有 Bean 配置信息解析完成后,修改 Bean 工厂信息.例如向BeanDefinitionRegistry注册BeanDefinition对象
@FunctionalInterface public interface BeanFactoryPostProcessor { /** * 解析完Bean 配置并且注册到BeanDefinitionRegistry容器后, * * 就会获取BeanFactoryPostProcessor接口的所有实现类,调用所有BeanFactoryPostProcessor对象的postProcessBeanFactory()方法 * @param beanFactory * @throws BeansException */ void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException; }
  • BeanPostProcessor Bean 的后置处理器.在 Bean 初始化方法(init-method 属性指定的方法或者 afterPropertiesSet()方法)调用前后,会执行 BeanPostProcessor的拦截逻辑
public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }

spring 容器启动过程

  1. 解析所有Bean 配置信息,包括 xml 配置,java 注解以及 java config方式配置的 Bean,把 Bean 的配置信息转换为BeanDefinition对象.,注册到 BeanDefinitionRegistry容器中
  2. BeanDefinitionRegistry获取实现了BeanFactoryPostProcessor接口的 Bean 定义,然后实例化 Bean.调用所有BeanFactoryPostProcessor对象的 postProcessBeanFactory()方法
  3. 根据 BeanDefinitionRegistry 容器中的BeanDefinition对象.实例化所有的单例 bean,并且对 bean 的属性进行填充
  4. 执行所有实现了BeanPostProcessor接口的postProcessBeforeInitialization()方法
  5. 执行bean的初始化方法(初始化方法: 包括配置bean的 init-method方法或者通过实现 InitializingBean接口重写的afterPropertiesSet()方法)
  6. 执行所有实现了BeanPostProcessor接口的postProcessAfterInitialization()方法

mybatis 与 spring 整合

  • mybatis-spring 中文文档 http://mybatis.org/spring/zh/index.html
  • 什么是 MyBatis-Spring?

MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。它将允许 MyBatis 参与到 Spring 的事务管理之中,创建映射器 mapper 和 SqlSession 并注入到 bean 中,以及将 Mybatis 的异常转换为 Spring 的 DataAccessException

  • 要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:一个 SqlSessionFactory 和至少一个数据映射器类。
// 1 引入 MyBatis-Spring 依赖,只需要在类路径下包含 mybatis-spring-2.0.7.jar 文件和相关依赖即可 <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.7</version> </dependency> // java config 方式配置 SqlSessionFactory,MapperScannerConfigurer @Configuration @MapperScan("org.mybatis.spring.sample.mapper") //扫描 mapper 文件 public class MyBatisConfig { @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource()); return factoryBean.getObject(); } @Bean public SqlSessionTemplate sqlSession() throws Exception { return new SqlSessionTemplate(sqlSessionFactory()); } } 

mybatis-spring 中 Mapper 动态代理对象注册过程

  • mybatis-spring 模块提供了@MapperScan注解,该注解用于扫描指定包下的 Mapper 接口并创建 Mapper 动态代理对象
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented //通过@Import 导入 BeanDefinition 注册类 MapperScannerRegistrar @Import({MapperScannerRegistrar.class}) public @interface MapperScan { //扫描包路径 String[] value() default {}; //扫描包路径 String[] basePackages() default {}; //扫描Mapper 接口对应的 class 对象 Class<?>[] basePackageClasses() default {}; //bean 名称生成策略 Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; //只扫描 某种注解修饰的类或者接口 Class<? extends Annotation> annotationClass() default Annotation.class; //只扫描某种类型的子类型 Class<?> markerInterface() default Class.class; //指定使用哪个sqlSessionTemplate对象 String sqlSessionTemplateRef() default ""; String sqlSessionFactoryRef() default ""; Class<? extends MapperFactoryBean> factoryBean() default MapperFactoryBean.class; }

@MapperScan注解通过@Import 导入 BeanDefinition 注册类 MapperScannerRegistrar

public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware { private ResourceLoader resourceLoader; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //工具类,用于获取MapperScan注解属性值 AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName())); // 创建spring ClassPathMapperScanner对象 ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); ... 配置了xxx 属性则赋值给ClassPathMapperScanner对象 scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef")); scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef")); List<String> basePackages = new ArrayList<String>(); for (String pkg : annoAttrs.getStringArray("value")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (String pkg : annoAttrs.getStringArray("basePackages")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) { basePackages.add(ClassUtils.getPackageName(clazz)); } scanner.registerFilters(); //扫描路径下的 java 接口 bean 注册到 spring 容器 scanner.doScan(StringUtils.toStringArray(basePackages)); //...接下来去学习 spring 吧 } }

spring 学习文档:

  • spring 官方文档中文版 https://www.springcloud.cc/spring-reference.html
  • Spring Framework 5 中文文档 https://www.cntofu.com/book/95/index.html
  • mybatis-spring 中文文档 http://mybatis.org/spring/zh/index.html

发表回复

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