Spring-Mybatis源码分析

xiaoxiao2021-02-28  93

首先给出Spring-mybatis的配置文件

<!-- 配置数据源 --> <bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"> <property name="driverClass" value="${DriverClasses}" /> <property name="jdbcUrl" value="${ecology.url}" /> <property name="username" value="${ecology.user}" /> <property name="password" value="${ecology.password}" /> <property name="idleConnectionTestPeriod" value="60" /> <property name="idleMaxAge" value="240" /> <property name="maxConnectionsPerPartition" value="30" /> <property name="minConnectionsPerPartition" value="10" /> <property name="partitionCount" value="1" /> <property name="acquireIncrement" value="5" /> <property name="statementsCacheSize" value="100" /> <property name="releaseHelperThreads" value="3" /> </bean> <!-- 配置数据工厂 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 自动扫描mapper.xml文件 --> <property name="configLocation" value="classpath:cn/resources/mybatis-cfg.xml" /> <property name="mapperLocations" value="classpath:cn/resources/mapper/*Mapper.xml" /> <property name="dataSource" ref="dataSource" /> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> <property name="basePackage" value="cn.belle.mapper"></property> </bean> mybatis-cfg.xml

<configuration> <settings> <!-- 启用自动将数据库字段和pojo中的字段做驼峰式的匹配 --> <setting name="mapUnderscoreToCamelCase" value="true"/> <!-- 懒加载模式 --> <setting name="lazyLoadingEnabled" value="false" /> <!-- JdbcType enumeration. Most common are: NULL, VARCHAR and OTHER --> <setting name="jdbcTypeForNull" value="NULL" /> <setting name="defaultStatementTimeout" value="30" /> </settings> </configuration> 核心类是MapperScannerConfigurer

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware这个类实现了BeanDefinitionRegistryPostProcessor这个抽象接口,让Spring容器在加载时执行postProcessBeanDefinitionRegistry方法

1 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { 2 if (this.processPropertyPlaceHolders) { 3 processPropertyPlaceHolders(); 4 } 5 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.registerFilters(); 17 scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); 18 }可以看到 scanner设置了大量属性,并且最后执行了scan方法

public int scan(String[] basePackages) /* */ { /* 224 */ int beanCountAtScanStart = this.registry.getBeanDefinitionCount(); /* */ /* 226 */ doScan(basePackages); /* */ /* */ /* 229 */ if (this.includeAnnotationConfig) { /* 230 */ AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); /* */ } /* */ /* 233 */ return this.registry.getBeanDefinitionCount() - beanCountAtScanStart; /* */ } doScan(注意这里不要搞错了,之前我就搞错了,这里的scan应该是子类的sacn)

  public Set<BeanDefinitionHolder> doScan(String[] basePackages) /*     */   { /* 164 */     Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); /*     */      /* 166 */     if (beanDefinitions.isEmpty()) { /* 167 */       this.logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); /*     */     } else { /* 169 */       processBeanDefinitions(beanDefinitions); /*     */     } /*     */      /* 172 */     return beanDefinitions; /*     */   } 首先调用了父类的doScan

Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);父类的doScan protected Set<BeanDefinitionHolder> doScan(String... basePackages) /* */ { /* 245 */ Assert.notEmpty(basePackages, "At least one base package must be specified"); /* 246 */ Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet(); /* 247 */ for (String basePackage : basePackages) { /* 248 */ Set<BeanDefinition> candidates = findCandidateComponents(basePackage); /* 249 */ for (BeanDefinition candidate : candidates) { /* 250 */ ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); /* 251 */ candidate.setScope(scopeMetadata.getScopeName()); /* 252 */ String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); /* 253 */ if ((candidate instanceof AbstractBeanDefinition)) { /* 254 */ postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName); /* */ } /* 256 */ if ((candidate instanceof AnnotatedBeanDefinition)) { /* 257 */ AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate); /* */ } /* 259 */ if (checkCandidate(beanName, candidate)) { /* 260 */ BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); /* 261 */ definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); /* 262 */ beanDefinitions.add(definitionHolder); /* 263 */ registerBeanDefinition(definitionHolder, this.registry); /* */ } /* */ } /* */ } /* 267 */ return beanDefinitions; /* */ }

该方法主要做了以下操作: 1)扫描basePackage下面的java文件 2)解析扫描到的java文件 3)调用各个在上一步骤注册的过滤器,执行相应的方法。 4)为解析后的java注册bean,注册方式采用编码的动态注册实现。 5)构造MapperFactoryBean的属性,mapperInterface,sqlSessionFactory等等,填充到BeanDefinition里面去。 做完这些,MapperFactoryBean对象也就构造完成了,扫描方式添加dao的工作也完成了。

然后是processBeanDefinitions

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) /* */ { /* 177 */ for (BeanDefinitionHolder holder : beanDefinitions) { /* 178 */ GenericBeanDefinition definition = (GenericBeanDefinition)holder.getBeanDefinition(); /* */ /* 180 */ if (this.logger.isDebugEnabled()) { /* 181 */ this.logger.debug("Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + definition /* 182 */ .getBeanClassName() + "' mapperInterface"); /* */ } /* */ /* */ /* */ /* 187 */ definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); /* 188 */ definition.setBeanClass(this.mapperFactoryBean.getClass()); /* */ /* 190 */ definition.getPropertyValues().add("addToConfig", Boolean.valueOf(this.addToConfig)); /* */ /* 192 */ boolean explicitFactoryUsed = false; /* 193 */ if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) { /* 194 */ definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName)); /* 195 */ explicitFactoryUsed = true; /* 196 */ } else if (this.sqlSessionFactory != null) { /* 197 */ definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory); /* 198 */ explicitFactoryUsed = true; /* */ } /* */ /* 201 */ if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) { /* 202 */ if (explicitFactoryUsed) { /* 203 */ this.logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."); /* */ } /* 205 */ definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName)); /* 206 */ explicitFactoryUsed = true; /* 207 */ } else if (this.sqlSessionTemplate != null) { /* 208 */ if (explicitFactoryUsed) { /* 209 */ this.logger.warn("Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."); /* */ } /* 211 */ definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate); /* 212 */ explicitFactoryUsed = true; /* */ } /* */ /* 215 */ if (!explicitFactoryUsed) { /* 216 */ if (this.logger.isDebugEnabled()) { /* 217 */ this.logger.debug("Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."); /* */ } /* 219 */ definition.setAutowireMode(2); /* */ } /* */ } /* */ }最关键的两行

definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); definition.setBeanClass(this.mapperFactoryBean.getClass()); 到这里动态注册的过程已经实现,dao层的接口已经全部被改造成MapperFactoryBean

所以最终我们还是要分析MapperFactoryBean的实现原理!

MapperFactoryBean继承了SqlSessionDaoSupport类,SqlSessionDaoSupport类继承DaoSupport抽象类,DaoSupport抽象类实现了InitializingBean接口,因此实例个MapperFactoryBean的时候,都会调用InitializingBean接口的afterPropertiesSet方法。

public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException /* */ { /* 44 */ checkDaoConfig(); /* */ /* */ try /* */ { /* 48 */ initDao(); /* */ } /* */ catch (Exception ex) { /* 51 */ throw new BeanInitializationException("Initialization of DAO failed", ex); /* */ } /* */ } MapperFactoryBean重写了checkDaoConfig方法

protected void checkDaoConfig() /* */ { /* 74 */ super.checkDaoConfig(); /* */ /* 76 */ Assert.notNull(this.mapperInterface, "Property 'mapperInterface' is required"); /* */ /* 78 */ Configuration configuration = getSqlSession().getConfiguration(); /* 79 */ if ((this.addToConfig) && (!configuration.hasMapper(this.mapperInterface))) { /* */ try { /* 81 */ configuration.addMapper(this.mapperInterface); /* */ } catch (Exception e) { /* 83 */ this.logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e); /* 84 */ throw new IllegalArgumentException(e); /* */ } finally { /* 86 */ ErrorContext.instance().reset(); /* */ } /* */ } /* */ } 然后通过spring工厂拿对应的bean的时候:

public T getObject() /* */ throws Exception /* */ { /* 96 */ return getSqlSession().getMapper(this.mapperInterface); /* */ } 这里的SqlSession是SqlSessionTemplate,SqlSessionTemplate的getMapper方法:

public <T> T getMapper(Class<T> type) /* */ { /* 319 */ return getConfiguration().getMapper(type, this); /* */ } Configuration的getMapper方法,会使用MapperRegistry的getMapper方法:

public <T> T getMapper(Class<T> type, SqlSession sqlSession) { /* 717 */ return this.mapperRegistry.getMapper(type, sqlSession); /* */ }getMapper

*/ public <T> T getMapper(Class<T> type, SqlSession sqlSession) /* */ { /* 45 */ MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type); /* 46 */ if (mapperProxyFactory == null) { /* 47 */ throw new BindingException("Type " + type + " is not known to the MapperRegistry."); /* */ } /* */ try { /* 50 */ return mapperProxyFactory.newInstance(sqlSession); /* */ } catch (Exception e) { /* 52 */ throw new BindingException("Error getting mapper instance. Cause: " + e, e); /* */ } /* */ } newInstance

protected T newInstance(MapperProxy<T> mapperProxy) /* */ { /* 47 */ return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[] { this.mapperInterface }, mapperProxy); /* */ } /* */ 这里就出现了动态代理

mapperProxy的源码

public class MapperProxy<T> /* */ implements InvocationHandler, Serializable 它的invoke

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable /* */ { /* 45 */ if (Object.class.equals(method.getDeclaringClass())) { /* */ try { /* 47 */ return method.invoke(this, args); /* */ } catch (Throwable t) { /* 49 */ throw ExceptionUtil.unwrapThrowable(t); /* */ } /* */ } /* 52 */ MapperMethod mapperMethod = cachedMapperMethod(method); /* 53 */ return mapperMethod.execute(this.sqlSession, args); /* */ } 这两行相信大家已经很熟悉了

MapperMethod mapperMethod = cachedMapperMethod(method); /* 53 */ return mapperMethod.execute(this.sqlSession, args);

转载请注明原文地址: https://www.6miu.com/read-67985.html

最新回复(0)