人们总是一边追逐一边回味。既要研究大型分布式框架,单机的优秀框架也不能错过。
一个框架的概览,在于入口,即配置项的解析;在于描述性配置,即如何识别和管理 bean;在于代理,即被管理的 bean 被代理成有什么样行为的类。
每次使用 mybatis,都会引入 mybatis-spring 包,并且设置两个bean‘,SqlSessionFactoryBean 和 MapperScanConfigurer,并且把 SqlSessionFactoryBean 当作属性配置类,注入 MapperScanConfigurer。
SqlSessionFactoryBean 主要是设置 mapper xml文件包路径和 mybatis 配置文件属性。
1.MapperScannerConfigurer.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry b)。第一步从 applicationContext 取出属性给成员变量(eg: basePackage、sqlSessionTemplateBeanName)赋值。第二步调用ClassPathMapperScanner.Scan(basePackage) 扫描 basePackage 中类文件。
2.ClassPathMapperScanner.Scan(basePackage),调用的是父类 ClassPathBeanDefinitionScanner.Scan(basePackage),父类回调子类的 doScan(basePackage)。doScan(basePackage) 第一步获取父类 Scan 扫描后的 Set 。第二步,对 BeanDefinition 进行处理,增加属性 SqlSessionFactory 和 SqlSessionTemplate 等。
3.ClassPathMapperScanner.processBeanDefinitions(beanDefinitions),即在 步骤2 doScan() 方法中调用,处理扫描 mapper 接口得到的 beanDefinition,接口是没法实例化的,所以在这个方法中,会把 beanDefinition 原有的 beanClass 属性替换为 MapperFactoryBean.class 。即 spring 最终会把扫描到的 mapper 接口实例化成这个类。
1。MapperFactoryBean.checkDaoConfig(),这个方法在父类 DaoSupport 实现的 InitializingBean.afterPropertiesSet() 方法中回调,这个方法主要作用,是调用 MapperRegistry.addMapper(mapperInterface), 把 mapper interface 注册到 MapperRegistry 中的 HashMap
2。MapperFactoryBean 是一个工厂 bean,在调用 getObject() 时,会从 MapperRegistry 中,根据 mapper interface 取出 MapperProxyFactory,然后调用 MapperProxyFactory.newInstance() 返回 MapperProxy 实例。
3.MapperProxy 实现了 InvocationHandler,最终在 mapper interface 方法被调用时,会调用这个代理类进行具体方法的执行。
1.MapperProxy 在执行 invoke(Object,Method,Object[]) 方法时,会从维护的 map 中找对应方法的 MapperMethodInvoker,然后具体的执行托给 MapperMethodInvoker。
2.Invoker 有两种,一种是 java8 之后才有的 default 方法,转为 DefaultMethodInvoker,使用 MethodHandler.bindTo(object).invokeWithArgument(args) 反射调用。一种是正常的接口方法,转为 PlainMethodInvoker ,使用 MapperMethod 进行方法的执行。
3.MapperMethod.execute(SqlSession, Object[]),增删改查都是使用参数中的 SqlSessionTemplate进行操作。
Optional.ofNullable(param).map(Function<? super T, ? extends U>).orElse();
其中 Function super T, ? extends U 是指方法对象。
方法对象指:被 T 类型对象调用处理对象本身,返回 R 类型对象。
还有类中嵌入私有的静态内部类实现内部接口,不同的条件,使用不同的静态内部类。
spring-mybatis 通过解析配置中的包路径,扫描路径下的文件,使用工厂 bean,让接口在运行时,有不同的表现。