springboot mybatis mapper 注入原理浅析
spring+mybatis是我们常用的开发组合,一般情况,我们只需要写一个Mapper接口 加上@Mapper注解就可以使用了,
那么他的工作原理是什么呢?
标准mybatis调用应该是这样的流程
1 //读取配置 2 InputStream config = Resources.getResourceAsStream("mybatis-config.xml"); 3 //根据配置创建SessionFactory 4 SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(config); 5 //创建session 6 SqlSession ss = ssf.openSession(); 7 //获取Mapper执行具体操作 8 CommonMapper mapper=ss.getMapper(CommonMapper.class); 9 Skt skt= mapper.getSktById("123"); 10 //关闭session 11 ss.close();
那么我们的Mapper代理对象肯定是封装了这些内容的,且看源码:
1#注册bean 从MapperScan开始1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.TYPE}) 3 @Documented 4 @Import({MapperScannerRegistrar.class}) //这里是入口 5 @Repeatable(MapperScans.class) 6 public @interface MapperScan { 7 }
2#MapperScannerRegistrar.registerBeanDefinitions 里面调用了 MapperScannerConfigurer
1 void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) { 2 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); 3 //下面是添加各种注解上带的参数 4 builder.addPropertyValue("processPropertyPlaceHolders", true); 5 Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass"); 6 if (!Annotation.class.equals(annotationClass)) { 7 builder.addPropertyValue("annotationClass", annotationClass); 8 } 9 10 Class<?> markerInterface = annoAttrs.getClass("markerInterface"); 11 if (!Class.class.equals(markerInterface)) { 12 builder.addPropertyValue("markerInterface", markerInterface); 13 } 14 15 Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator"); 16 if (!BeanNameGenerator.class.equals(generatorClass)) { 17 builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass)); 18 } 19 20 Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean"); 21 if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) { 22 builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass); 23 } 24 25 String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef"); 26 if (StringUtils.hasText(sqlSessionTemplateRef)) { 27 builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef")); 28 } 29 30 String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef"); 31 if (StringUtils.hasText(sqlSessionFactoryRef)) { 32 builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef")); 33 } 34 35 List<String> basePackages = new ArrayList(); 36 basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList())); 37 basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList())); 38 basePackages.addAll((Collection)Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList())); 39 if (basePackages.isEmpty()) { 40 basePackages.add(getDefaultBasePackage(annoMeta)); 41 } 42 43 String lazyInitialization = annoAttrs.getString("lazyInitialization"); 44 if (StringUtils.hasText(lazyInitialization)) { 45 builder.addPropertyValue("lazyInitialization", lazyInitialization); 46 } 47 48 String defaultScope = annoAttrs.getString("defaultScope"); 49 if (!"".equals(defaultScope)) { 50 builder.addPropertyValue("defaultScope", defaultScope); 51 } 52 53 builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages)); 54 registry.registerBeanDefinition(beanName, builder.getBeanDefinition()); 55 }
3# MapperScannerConfigurer.postProcessBeanDefinitionRegistry 调用mapper扫描器
1 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { 2 if (this.processPropertyPlaceHolders) { 3 this.processPropertyPlaceHolders(); 4 } 5 //创建此种扫描器,更具packge路径扫描bean 6 ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); 7 scanner.setAddToConfig(this.addToConfig); 8 scanner.setAnnotationClass(this.annotationClass); 9 scanner.setMarkerInterface(this.markerInterface); 10 scanner.setSqlSessionFactory(this.sqlSessionFactory); 11 scanner.setSqlSessionTemplate(this.sqlSessionTemplate); 12 scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName); 13 scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName); 14 scanner.setResourceLoader(this.applicationContext); 15 scanner.setBeanNameGenerator(this.nameGenerator); 16 scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass); 17 if (StringUtils.hasText(this.lazyInitialization)) { 18 scanner.setLazyInitialization(Boolean.valueOf(this.lazyInitialization)); 19 } 20 21 if (StringUtils.hasText(this.defaultScope)) { 22 scanner.setDefaultScope(this.defaultScope); 23 } 24 25 scanner.registerFilters(); 26 scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n")); 27 }
4#ClassPathMapperScanner.processBeanDefinitions 动态添加MapperFactoryBean
1 private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { 2 BeanDefinitionRegistry registry = this.getRegistry(); 3 Iterator var4 = beanDefinitions.iterator(); 4 5 while(var4.hasNext()) { 6 BeanDefinitionHolder holder = (BeanDefinitionHolder)var4.next(); 7 AbstractBeanDefinition definition = (AbstractBeanDefinition)holder.getBeanDefinition(); 8 boolean scopedProxy = false; 9 if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) { 10 definition = (AbstractBeanDefinition)Optional.ofNullable(((RootBeanDefinition)definition).getDecoratedDefinition()).map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> { 11 return new IllegalStateException("The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]"); 12 }); 13 scopedProxy = true; 14 } 15 16 String beanClassName = definition.getBeanClassName(); 17 LOGGER.debug(() -> { 18 return "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName + "' mapperInterface"; 19 }); 20 21 //这里设置构造时传出Mapper接口类型 22 definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); 23 //这里设置MapperFactoryBean 24 definition.setBeanClass(this.mapperFactoryBeanClass); 25 definition.getPropertyValues().add("addToConfig", this.addToConfig); 26 definition.setAttribute("factoryBeanObjectType", beanClassName); 27 boolean explicitFactoryUsed = false; 28 if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) { 29 definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName)); 30 explicitFactoryUsed = true; 31 } else if (this.sqlSessionFactory != null) { 32 definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory); 33 explicitFactoryUsed = true; 34 } 35 36 if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) { 37 if (explicitFactoryUsed) { 38 LOGGER.warn(() -> { 39 return "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."; 40 }); 41 } 42 43 //添加各种参数 如果有
definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName)); 44 explicitFactoryUsed = true; 45 } else if (this.sqlSessionTemplate != null) { 46 if (explicitFactoryUsed) { 47 LOGGER.warn(() -> { 48 return "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."; 49 }); 50 } 51 52 definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate); 53 explicitFactoryUsed = true; 54 } 55 56 if (!explicitFactoryUsed) { 57 LOGGER.debug(() -> { 58 return "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."; 59 });
//可以设置自动注入模式哦,设置完后MapperBeanFactory里面的属性统统根据类型自动注入(如果不重复) 60 definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); 61 } 62 63 definition.setLazyInit(this.lazyInitialization); 64 if (!scopedProxy) { 65 if ("singleton".equals(definition.getScope()) && this.defaultScope != null) { 66 definition.setScope(this.defaultScope); 67 } 68 69 if (!definition.isSingleton()) { 70 BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true); 71 if (registry.containsBeanDefinition(proxyHolder.getBeanName())) { 72 registry.removeBeanDefinition(proxyHolder.getBeanName()); 73 } 74 75 registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition()); 76 } 77 } 78 } 79 80 }
5# MapperFactoryBean 的实现
1 public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { // 实现了 FactoryBean 接口(关键) 2 private Class<T> mapperInterface; 3 private boolean addToConfig = true; 4 5 public MapperFactoryBean() { 6 } 7 8 public MapperFactoryBean(Class<T> mapperInterface) { //上一步就是指定用这个来构造bean的 9 this.mapperInterface = mapperInterface; 10 } 11 12 protected void checkDaoConfig() { 13 super.checkDaoConfig(); 14 Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required"); 15 Configuration configuration = this.getSqlSession().getConfiguration(); 16 if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) { 17 try { 18 configuration.addMapper(this.mapperInterface); 19 } catch (Exception var6) { 20 this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", var6); 21 throw new IllegalArgumentException(var6); 22 } finally { 23 ErrorContext.instance().reset(); 24 } 25 } 26 27 } 28 29 public T getObject() throws Exception { 30 return this.getSqlSession().getMapper(this.mapperInterface); //这里有返回了Mapper 是不是似曾相识,没错 就是那个啦 31 } 32 33 public Class<T> getObjectType() { 34 return this.mapperInterface; 35 } 36 37 public boolean isSingleton() { 38 return true; 39 } 40 41 public void setMapperInterface(Class<T> mapperInterface) { 42 this.mapperInterface = mapperInterface; 43 } 44 45 public Class<T> getMapperInterface() { 46 return this.mapperInterface; 47 } 48 49 public void setAddToConfig(boolean addToConfig) { 50 this.addToConfig = addToConfig; 51 } 52 53 public boolean isAddToConfig() { 54 return this.addToConfig; 55 } 56 } 57 58 public abstract class SqlSessionDaoSupport extends DaoSupport { 59 private SqlSessionTemplate sqlSessionTemplate; 60 61 public SqlSessionDaoSupport() { 62 } 63 64 //这里是自动注入的 beandDefine的时候可以设置哦 65 public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { 66 if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) { 67 this.sqlSessionTemplate = this.createSqlSessionTemplate(sqlSessionFactory); 68 } 69 70 } 71 72 protected SqlSessionTemplate createSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { 73 return new SqlSessionTemplate(sqlSessionFactory); 74 } 75 76 public final SqlSessionFactory getSqlSessionFactory() { 77 return this.sqlSessionTemplate != null ? this.sqlSessionTemplate.getSqlSessionFactory() : null; 78 } 79 80 public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { 81 this.sqlSessionTemplate = sqlSessionTemplate; 82 } 83 84 public SqlSession getSqlSession() { 85 return this.sqlSessionTemplate; 86 } 87 88 public SqlSessionTemplate getSqlSessionTemplate() { 89 return this.sqlSessionTemplate; 90 } 91 92 protected void checkDaoConfig() { 93 Assert.notNull(this.sqlSessionTemplate, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required"); 94 } 95 }
搞完收工!