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
- Spring-Mybatis源码分析
- mybatis-spring 源码分析MapperScannerConfigurer
- Spring整合MyBatis(二)源码分析
- Spring整合MyBatis(二)源码分析
- Spring集成Mybatis配置与源码分析
- Mybatis源码分析之Spring与Mybatis整合MapperScannerConfigurer处理过程源码分析
- Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析
- Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析
- Mybatis结合Spring注解自动扫描源码分析
- Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析
- Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析
- Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析
- Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析
- Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析
- Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析
- Spring源码分析【8】-MyBatis注解方法不能重载
- mybatis-Spring ClassPathMapperScanner源码分析(自定义注解加载Bean)
- Spring与Mybatis整合的MapperScannerConfigurer处理过程源码分析
- MyBatis Generator 详解
- 案例实战:LightningChart集成Dynamotive汽车遥测软件|见证真正无与伦比的性能
- 完美兼容4.4及以上系统实现沉浸式状态栏
- JS中的bool
- hibernate four
- Spring-Mybatis源码分析
- pascal三角原理+zip用法-【leetcode119-pascal triangle2】
- mybatis级联之一对多的关系
- Android O要来了,大家准备好了吗?
- 解决$GLOBALS["HTTP_RAW_POST_DATA"]获取不到数据的问题
- 设计模式-单例模式
- Android MediaScanner 扫描流程
- hibernate笔记11 Hibernate查询方式
- 从 FingBugs的错误来看JAVA代码质量(一)