Spring-Mybatis源码分析

来源:互联网 发布:光影魔术手mac版下载 编辑:程序博客网 时间:2024/05/30 23:50

首先给出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);


阅读全文
0 0
原创粉丝点击