前言: 本文将重点讲解Mybatis-spring的执行过程,对比mybatis和Mybatis-spring的流程差异,以及Mybatis-spring一级缓存失效的原因(文章方法15),和spring自动注入的原理和哪些属性不会自动装配的讲解。
解析mybatis-spring源码
启动流程
-
Mybatis配置类中的MapperScan
@Configuration @EnableTransactionManagement @MapperScan(basePackages = DataSourceConfiguration.PACKAGE, sqlSessionFactoryRef = DataSourceConfiguration.SQL_SESSION_FACTORY) public class DataSourceConfiguration {}
-
MapperScan中加了@Import注解
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented @Import({MapperScannerRegistrar.class}) @Repeatable(MapperScans.class) public @interface MapperScan{}
-
MapperScannerRegistrar类解析
-
在扫描到数据源配置类(如
DataSourceConfiguration
)时,扫描其@import
注入的类,mybatis注入了一个MapperScannerConfigurer
类,他是继承了BeanDefinitionRegistryPostProcessor
接口的类。 -
注册完这个类后,spring再次扫描
ImportBeanDefinitionRegistrar
这个的时候,会执行MapperScannerConfigurer
的postProcessBeanDefinitionRegistry
方法。 -
MapperScannerRegistrar
在构造MapperScannerConfigurer
的bd时,将解析@MapperScan
的参数,例如basePackages = DataSourceConfiguration.PACKAGE, sqlSessionFactoryRef = DataSourceConfiguration.SQL_SESSION_FACTORY
等,将其设置到MapperScannerConfigurer
的bd中
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware { void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) { // 生成MapperScannerConfigurer类的bd BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); builder.addPropertyValue("processPropertyPlaceHolders", true); // bd设置 解析加@MapperScan 填入的数据 Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass"); if (!Annotation.class.equals(annotationClass)) { builder.addPropertyValue("annotationClass", annotationClass); } Class<?> markerInterface = annoAttrs.getClass("markerInterface"); if (!Class.class.equals(markerInterface)) { builder.addPropertyValue("markerInterface", markerInterface); } Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator"); if (!BeanNameGenerator.class.equals(generatorClass)) { builder.addPropertyValue("nameGenerator", BeanUtils.instantiateClass(generatorClass)); } Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean"); if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) { builder.addPropertyValue("mapperFactoryBeanClass", mapperFactoryBeanClass); } String sqlSessionTemplateRef = annoAttrs.getString("sqlSessionTemplateRef"); if (StringUtils.hasText(sqlSessionTemplateRef)) { builder.addPropertyValue("sqlSessionTemplateBeanName", annoAttrs.getString("sqlSessionTemplateRef")); } String sqlSessionFactoryRef = annoAttrs.getString("sqlSessionFactoryRef"); if (StringUtils.hasText(sqlSessionFactoryRef)) { builder.addPropertyValue("sqlSessionFactoryBeanName", annoAttrs.getString("sqlSessionFactoryRef")); } List<String> basePackages = new ArrayList<>(); basePackages.addAll( Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList())); basePackages.addAll(Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText) .collect(Collectors.toList())); basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName) .collect(Collectors.toList())); if (basePackages.isEmpty()) { basePackages.add(getDefaultBasePackage(annoMeta)); } String lazyInitialization = annoAttrs.getString("lazyInitialization"); if (StringUtils.hasText(lazyInitialization)) { builder.addPropertyValue("lazyInitialization", lazyInitialization); } String defaultScope = annoAttrs.getString("defaultScope"); if (!AbstractBeanDefinition.SCOPE_DEFAULT.equals(defaultScope)) { builder.addPropertyValue("defaultScope", defaultScope); } builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages)); // 注册的名字是importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index; // 加@MapperScan类的配置类名#MapperScannerRegistrar#index registry.registerBeanDefinition(beanName, builder.getBeanDefinition()); } }
-
-
MapperScannerConfigurer.postProcessBeanDefinitionRegistry
的执行明确一点 这是由上面 MapperScannerRegistrar注入的MapperScannerConfigurer。
他被spring运行的时机是在invokeBeanFactoryPostProcessors处理BeanDefinitionRegistry的最后部分
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { while (reiterate) { reiterate = false; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (String ppName : postProcessorNames) { if (!processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate = true; } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); // 这里去执行MapperScannerConfigurer.postProcessBeanDefinitionRegistry() invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); currentRegistryProcessors.clear(); } }
他创建了一个扫描器,去注册所有的XXXMapper接口到bd中,其中接口对应的实体类都是被代理出来的
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { if (this.processPropertyPlaceHolders) { processPropertyPlaceHolders(); } // 创建一个解析器ClassPathMapperScanner // 数据由MapperScannerRegistrar创建MapperScannerConfigurer的bd时设置的 ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); scanner.setAddToConfig(this.addToConfig); scanner.setAnnotationClass(this.annotationClass); scanner.setMarkerInterface(this.markerInterface); scanner.setSqlSessionFactory(this.sqlSessionFactory); scanner.setSqlSessionTemplate(this.sqlSessionTemplate); scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName); scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName); scanner.setResourceLoader(this.applicationContext); scanner.setBeanNameGenerator(this.nameGenerator); scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass); if (StringUtils.hasText(lazyInitialization)) { scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization)); } if (StringUtils.hasText(defaultScope)) { scanner.setDefaultScope(defaultScope); } scanner.registerFilters(); // 扫描所有的XXXMapper接口(此处传入的是XXXMapper的包名字符串) // 函数解析5 scanner.scan( StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS)); }
-
扫描类父类的
ClassPathBeanDefinitionScanner.doScan()
public int scan(String... basePackages) { // 记录扫描前注册bd的数量 int beanCountAtScanStart = this.registry.getBeanDefinitionCount(); // 扫描(传入的是XXXMapper的包名数组) // 调用的是子类ClassPathMapperScanner.doScan this.doScan(basePackages); if (this.includeAnnotationConfig) { AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); } // 返回扫描注册bd的数量 return this.registry.getBeanDefinitionCount() - beanCountAtScanStart; }
-
调用扫描类
ClassPathMapperScanner.doScan()
调用父类(方法7)去注册那几个XXXMapper的接口bd,并将bd返回,为了设置这几个bd对应的代理对象
public Set<BeanDefinitionHolder> doScan(String... basePackages) { // 这里返回的是函数7注册进spring的XXXXMapper(就那几个接口)的bd的Set集合 Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { LOGGER.warn(() -> "No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { // 重点在这里,是处理这几个接口bd的实体代理对象 processBeanDefinitions(beanDefinitions); } return beanDefinitions; }
-
再次进入父类的
ClassPathBeanDefinitionScanner.doScan()
这里面就是扫描包下的类加入registry 并返回bd
扫描的就是那几个XXXMapper接口;
在这里他先将bd注册后,还用set保存起来,为了后面设置这几个接口bd的实体对象(代理对象)
protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet(); String[] var3 = basePackages; int var4 = basePackages.length; for(int var5 = 0; var5 < var4; ++var5) { String basePackage = var3[var5]; Set<BeanDefinition> candidates = this.findCandidateComponents(basePackage); Iterator var8 = candidates.iterator(); while(var8.hasNext()) { BeanDefinition candidate = (BeanDefinition)var8.next(); ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { this.postProcessBeanDefinition((AbstractBeanDefinition)candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition)candidate); } if (this.checkCandidate(beanName, candidate)) { BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); // 注册bd 这里注册了XXXXMapper接口的bd this.registerBeanDefinition(definitionHolder, this.registry); } } } // 将注册的XXXXMapper接口的bd返回 return beanDefinitions; }
-
扩展XXXMapper的bd
ClassPathMapperScanner.processBeanDefinitions()
这里面就是要给接口设置实例化对象,这样在使用接口执行操作的时候才能操作实例化对象;
由于在这里使用动态代理,无法拿到动态代理的对象,无法放入spring容器中,所以使用了FactoryBean对象去处理。
这里使用的是MapperFactoryBean.class
这里设置了MapperFactoryBean属性值的注入方式为
AUTOWIRE_BY_TYPE
这里扩展一下spring的自动装配,在AbstractBeanDefinition.class下有如下几个标志:
int AUTOWIRE_NO = 0;
表示不自动注入,但标记@Autowire的会自动注入;int AUTOWIRE_BY_NAME = 1;
通过属性的名字的方式查找JavaBean依赖的对象调用set方法为其注入;那具体什么属性需要装配,见方法10的解析int AUTOWIRE_BY_TYPE = 2;
通过属性的类型的方式查找JavaBean依赖的对象调用set方法为其注入;int AUTOWIRE_CONSTRUCTOR = 3;
通过属性的构造方法装配,无需set方法;
自动注入的标签区别
- @Resource 通过 byName 方式自动装配
- @Autowired 通过ByType 方式自动装配
- @Autowired 和@Qualifier 可以实现ByName的效果
如果Spring中有2个类型相同的Bean在通过@Autowired会报错 我们可以通过@Qualifier 标签来进行区分
为了通用性,构造方法应该是这个接口的class
从而可以返回一个代理对象
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) { AbstractBeanDefinition definition; BeanDefinitionRegistry registry = getRegistry(); for (BeanDefinitionHolder holder : beanDefinitions) { definition = (AbstractBeanDefinition) holder.getBeanDefinition(); boolean scopedProxy = false; // 这里是false不进入 bd都是XXXMapper if (ScopedProxyFactoryBean.class.getName().equals(definition.getBeanClassName())) { definition = (AbstractBeanDefinition) Optional .ofNullable(((RootBeanDefinition) definition).getDecoratedDefinition()) .map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(() -> new IllegalStateException( "The target bean definition of scoped proxy bean not found. Root bean definition[" + holder + "]")); scopedProxy = true; } String beanClassName = definition.getBeanClassName(); LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName + "' mapperInterface"); // the mapper interface is the original class of the bean // but, the actual class of the bean is MapperFactoryBean // 设置FactoryBean构造函数的参数 definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59 // setBeanClass MapperFactoryBean.class; definition.setBeanClass(this.mapperFactoryBeanClass); definition.getPropertyValues().add("addToConfig", this.addToConfig); boolean explicitFactoryUsed = false; if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) { definition.getPropertyValues().add("sqlSessionFactory", new RuntimeBeanReference(this.sqlSessionFactoryBeanName)); explicitFactoryUsed = true; } else if (this.sqlSessionFactory != null) { definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory); explicitFactoryUsed = true; } if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) { if (explicitFactoryUsed) { LOGGER.warn( () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."); } definition.getPropertyValues().add("sqlSessionTemplate", new RuntimeBeanReference(this.sqlSessionTemplateBeanName)); explicitFactoryUsed = true; } else if (this.sqlSessionTemplate != null) { if (explicitFactoryUsed) { LOGGER.warn( () -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored."); } definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate); explicitFactoryUsed = true; } if (!explicitFactoryUsed) { LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'."); // 在这里设置了FactoryBean属性值注入方式 definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); } definition.setLazyInit(lazyInitialization); if (scopedProxy) { continue; } if (ConfigurableBeanFactory.SCOPE_SINGLETON.equals(definition.getScope()) && defaultScope != null) { definition.setScope(defaultScope); } if (!definition.isSingleton()) { BeanDefinitionHolder proxyHolder = ScopedProxyUtils.createScopedProxy(holder, registry, true); if (registry.containsBeanDefinition(proxyHolder.getBeanName())) { registry.removeBeanDefinition(proxyHolder.getBeanName()); } registry.registerBeanDefinition(proxyHolder.getBeanName(), proxyHolder.getBeanDefinition()); } } }
-
MapperFactoryBean.class
用于生成XXXMapper.class 的代理对象,具体看方法11
这里面继承了
SqlSessionDaoSupport
这个对象不一般,具体看方法10的解析public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { // 传入的接口XXXMapper.class private Class<T> mapperInterface; private boolean addToConfig = true; public MapperFactoryBean() { // intentionally empty } // 构造函数 传入的接口XXXMapper.class public MapperFactoryBean(Class<T> mapperInterface) { this.mapperInterface = mapperInterface; } // 返回代理对象 这个 代理对象见*方法11* @Override public T getObject() throws Exception { return getSqlSession().getMapper(this.mapperInterface); } // 返回生成对象的类型 也就是传入的接口XXXMapper.class @Override public Class<T> getObjectType() { return this.mapperInterface; } // 在实例化的时候会调用 @Override protected void checkDaoConfig() { super.checkDaoConfig(); notNull(this.mapperInterface, "Property 'mapperInterface' is required"); Configuration configuration = getSqlSession().getConfiguration(); if (this.addToConfig && !configuration.hasMapper(this.mapperInterface)) { try { // String mappedStatementId = this.type.getName() + "." + method.getName(); // 这里 configuration会将接口中的sql语句解析封装成MappedStatement, 其中id就是包名+方法名 configuration.addMapper(this.mapperInterface); } catch (Exception e) { logger.error("Error while adding the mapper '" + this.mapperInterface + "' to configuration.", e); throw new IllegalArgumentException(e); } finally { ErrorContext.instance().reset(); } } } }
-
父类 SqlSessionDaoSupport.class和DaoSupport.class
DaoSupport在创建bean的过程中会调用SqlSessionDaoSupport的checkDaoConfig方法
而MapperFactoryBean中又重写了checkDaoConfig方法,所以在实例化MapperFactoryBean的时候会调用MapperFactoryBean.checkDaoConfig(),当中就是解析sql语句封装MappedStatement对象。
public abstract class SqlSessionDaoSupport extends DaoSupport { @Override protected void checkDaoConfig() { notNull(this.sqlSessionTemplate, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required"); } // 见set方法 public SqlSession getSqlSession() { return this.sqlSessionTemplate; } // 这里sqlSessionTemplate的值是在初始化bean的时候赋值的 // this.sqlSessionTemplate.getSqlSessionFactory()就是调用方法11里的sqlSessionFactory public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { if (this.sqlSessionTemplate == null || sqlSessionFactory != this.sqlSessionTemplate.getSqlSessionFactory()) { this.sqlSessionTemplate = createSqlSessionTemplate(sqlSessionFactory); } } } // DaoSupport.class public abstract class DaoSupport implements InitializingBean { protected final Log logger = LogFactory.getLog(this.getClass()); public DaoSupport() { } // Spring实例化Bean后会执行afterPropertiesSet // 由于是抽象方法这里都将调用子类的实现 public final void afterPropertiesSet() throws IllegalArgumentException, BeanInitializationException { this.checkDaoConfig(); try { this.initDao(); } catch (Exception var2) { throw new BeanInitializationException("Initialization of DAO failed", var2); } } protected abstract void checkDaoConfig() throws IllegalArgumentException; protected void initDao() throws Exception { } }
-
调用SqlSessionTemplate.class中的getMapper()->Configuration.getMapper()
- 这个类中的sqlSessionFactory,在mybatis配置类中通过SqlSessionFactoryBean.class创建了bean并注册进spring中。这里直接自动装配,返回的是DefaultSqlSessionFactory.class 他实现了SqlSessionFactory接口
@Configuration @EnableTransactionManagement @MapperScan(basePackages = DataSourceConfiguration.PACKAGE, sqlSessionFactoryRef = DataSourceConfiguration.SQL_SESSION_FACTORY) public class DataSourceConfiguration { // ****** @Bean(name = DataSourceConfiguration.SQL_SESSION_FACTORY) public SqlSessionFactory initSqlSessionFactory() throws Exception { // SqlSessionFactory是一个接口,实际返回是DefaultSqlSessionFactory SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(initDataSource()); ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mapper/*.xml")); sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage); return sqlSessionFactoryBean.getObject(); } }
DefaultSqlSessionFactory.class
中维护了一个属性Configuration,Configuration属性里面有jdbc的链接信息以及Map<String, MappedStatement> mappedStatements;这个map就是装着sql语句和id。- getMapper()实际调用的是Configuration中的getMapper()
- SqlSessionTemplate的构造方法中定义了一个sqlSessionProxy对象代理了一个SqlSession对象,他是最终执行sql的地方,这里可参考后面的方法15
public class SqlSessionTemplate implements SqlSession, DisposableBean { // 这个sqlSessionFactory实际上在你配置mybatis的配置类时 定义了@Bean返回的是sqlSessionFactory private final SqlSessionFactory sqlSessionFactory; // 构造方法 public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required"); notNull(executorType, "Property 'executorType' is required"); this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; // 代理对象,真正的王者在这里 this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class }, new SqlSessionInterceptor()); } @Override public <T> T getMapper(Class<T> type) { return getConfiguration().getMapper(type, this); } @Override public Configuration getConfiguration() { return this.sqlSessionFactory.getConfiguration(); } } public class Configuration { // ...... protected final MapperRegistry mapperRegistry; protected final Map<String, MappedStatement> mappedStatements; // 构造函数 public Configuration{ // ...... this.mapperRegistry = new MapperRegistry(this); } // 这里调用的是mapperRegistry的getMapper public <T> T getMapper(Class<T> type, SqlSession sqlSession) { return this.mapperRegistry.getMapper(type, sqlSession); } }
-
调用MapperRegistry的getMapper()方法
这里通过mapperProxyFactory创建了一个代理对象,由MapperProxy进行实际的操作
public class MapperRegistry { private final Configuration config; private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap(); public MapperRegistry(Configuration config) { this.config = config; } // 这个type就是那个XXXMapper的接口 public <T> T getMapper(Class<T> type, SqlSession sqlSession) { MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type); if (mapperProxyFactory == null) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } else { try { return mapperProxyFactory.newInstance(sqlSession); } catch (Exception var5) { throw new BindingException("Error getting mapper instance. Cause: " + var5, var5); } } } } public class MapperProxyFactory<T> { private final Class<T> mapperInterface; private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap(); public MapperProxyFactory(Class<T> mapperInterface) { this.mapperInterface = mapperInterface; } public Class<T> getMapperInterface() { return this.mapperInterface; } public Map<Method, MapperMethodInvoker> getMethodCache() { return this.methodCache; } // 创建代理对象并返回 代理对象的实现方法由mapperProxy实现 protected T newInstance(MapperProxy<T> mapperProxy) { return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy); } public T newInstance(SqlSession sqlSession) { MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache); return this.newInstance(mapperProxy); } }
执行过程
-
MapperProxy的具体代理过程
就是当我们调用XXXMapper接口的数据库操作方法时,他会创建一个MapperMethod对象,最终会调用MapperMethod中的execute方法。
创建MapperMethod时传入了XXXMapper接口,调用方法,Configuration。具体
class MapperMethod { private final MapperMethod.SqlCommand command; private final MapperMethod.MethodSignature method; public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) { this.command = new MapperMethod.SqlCommand(config, mapperInterface, method); this.method = new MapperMethod.MethodSignature(config, mapperInterface, method); } public Object execute(SqlSession sqlSession, Object[] args){ //.... } }
public class MapperProxy<T> implements InvocationHandler, Serializable { private static final long serialVersionUID = -4724728412955527868L; private static final int ALLOWED_MODES = 15; private static final Constructor<Lookup> lookupConstructor; private static final Method privateLookupInMethod; private final SqlSession sqlSession; private final Class<T> mapperInterface; private final Map<Method, MapperProxy.MapperMethodInvoker> methodCache; public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperProxy.MapperMethodInvoker> methodCache) { this.sqlSession = sqlSession; this.mapperInterface = mapperInterface; this.methodCache = methodCache; } //proxy是我们之前的sqlSessionTemplate //这里执行的是 this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession); public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { return Object.class.equals(method.getDeclaringClass()) ? method.invoke(this, args) : this.cachedInvoker(method).invoke(proxy, method, args, this.sqlSession); } catch (Throwable var5) { throw ExceptionUtil.unwrapThrowable(var5); } } // 执行这里 // new MapperProxy.PlainMethodInvoker(new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration())); private MapperProxy.MapperMethodInvoker cachedInvoker(Method method) throws Throwable { try { MapperProxy.MapperMethodInvoker invoker = (MapperProxy.MapperMethodInvoker)this.methodCache.get(method); return invoker != null ? invoker : (MapperProxy.MapperMethodInvoker)this.methodCache.computeIfAbsent(method, (m) -> { if (m.isDefault()) { try { return privateLookupInMethod == null ? new MapperProxy.DefaultMethodInvoker(this.getMethodHandleJava8(method)) : new MapperProxy.DefaultMethodInvoker(this.getMethodHandleJava9(method)); } catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException var4) { throw new RuntimeException(var4); } } else { // 执行这里 创建了一个MapperMethod对象 return new MapperProxy.PlainMethodInvoker(new MapperMethod(this.mapperInterface, method, this.sqlSession.getConfiguration())); } }); } catch (RuntimeException var4) { Throwable cause = var4.getCause(); throw (Throwable)(cause == null ? var4 : cause); } } // 内部子类 private static class PlainMethodInvoker implements MapperProxy.MapperMethodInvoker { private final MapperMethod mapperMethod; public PlainMethodInvoker(MapperMethod mapperMethod) { this.mapperMethod = mapperMethod; } // 具体调用的是这里 调用MapperMethod的execute方法 public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable { return this.mapperMethod.execute(sqlSession, args); } } }
-
MapperMethod的execute()方法
这里面我们挑一个executeForMany(), 他们最终都是调用sqlSession对象的方法,也就是前面的SqlSessionTemplate对象中的方法
public Object execute(SqlSession sqlSession, Object[] args) { Object result; Object param; switch(this.command.getType()) { case INSERT: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.insert(this.command.getName(), param)); break; case UPDATE: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.update(this.command.getName(), param)); break; case DELETE: param = this.method.convertArgsToSqlCommandParam(args); result = this.rowCountResult(sqlSession.delete(this.command.getName(), param)); break; case SELECT: if (this.method.returnsVoid() && this.method.hasResultHandler()) { this.executeWithResultHandler(sqlSession, args); result = null; } else if (this.method.returnsMany()) { result = this.executeForMany(sqlSession, args); } else if (this.method.returnsMap()) { result = this.executeForMap(sqlSession, args); } else if (this.method.returnsCursor()) { result = this.executeForCursor(sqlSession, args); } else { param = this.method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(this.command.getName(), param); if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) { result = Optional.ofNullable(result); } } break; case FLUSH: result = sqlSession.flushStatements(); break; default: throw new BindingException("Unknown execution method for: " + this.command.getName()); } if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) { throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ")."); } else { return result; } } // 这里看execute调用的最终执行方法 // 这里调用的是sqlSession的方法 private <E> Object executeForMany(SqlSession sqlSession, Object[] args) { Object param = this.method.convertArgsToSqlCommandParam(args); List result; if (this.method.hasRowBounds()) { RowBounds rowBounds = this.method.extractRowBounds(args); result = sqlSession.selectList(this.command.getName(), param, rowBounds); } else { result = sqlSession.selectList(this.command.getName(), param); } if (!this.method.getReturnType().isAssignableFrom(result.getClass())) { return this.method.getReturnType().isArray() ? this.convertToArray(result) : this.convertToDeclaredCollection(sqlSession.getConfiguration(), result); } else { return result; } }
-
转到SqlSessionTemplate.selectList()方法
SqlSessionTemplate中定义sqlSessionProxy代理对象,调用sqlSessionProxy的方法去执行DefaultSqlSession的方法,最后关闭了sqlSession导致了MyBatis的一级缓存失效,因为这里不关闭session,spring没有其他地方关闭了。
mybatis的执行sql是调用DefaultSqlSession去执行的,而spring是通过代理对象再去执行DefaultSqlSession
public class SqlSessionTemplate implements SqlSession, DisposableBean { // 这个sqlSessionFactory实际上在你配置mybatis的配置类时 定义了@Bean返回的是sqlSessionFactory private final SqlSessionFactory sqlSessionFactory; // 构造方法 public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required"); notNull(executorType, "Property 'executorType' is required"); this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; // 代理对象,真正的调用在这里 this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class }, new SqlSessionInterceptor()); } @Override public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { return this.sqlSessionProxy.selectList(statement, parameter, rowBounds); } // 子对象 他是执行sql的最终的地方 private class SqlSessionInterceptor implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 这里的sqlsession应该就是DefaultSqlSession对象 SqlSession sqlSession = getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator); try { Object result = method.invoke(sqlSession, args); if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) { // force commit even on non-dirty sessions because some databases require // a commit/rollback before calling close() sqlSession.commit(true); } return result; } catch (Throwable t) { Throwable unwrapped = unwrapThrowable(t); if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) { // release the connection to avoid a deadlock if the translator is no loaded. See issue #22 closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); sqlSession = null; Throwable translated = SqlSessionTemplate.this.exceptionTranslator .translateExceptionIfPossible((PersistenceException) unwrapped); if (translated != null) { unwrapped = translated; } } throw unwrapped; } finally { if (sqlSession != null) { // 结束时关闭了sqlsession,所以导致spring中mybatis的一级缓存失效 closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); } } } } }
对象的自动装配
在上述mybatis的分析中,实际上很多类的属性未加@Autowire都会自动注入对象的,那么到底那些属性会被自动注入呢?
spring会自动扫描属性,把getXXX(),setXXX(),isXXXX()都会当作属性。(Kotlin 是用的isXXX())
如果属性值没有set方法或者手动设置不注入或者是简单类型则则不注入
简单类型:枚举,字符,数字,日期,URI/URL,class等类型;都不会装配
public static boolean isSimpleValueType(Class<?> type) { return Void.class != type && Void.TYPE != type && (ClassUtils.isPrimitiveOrWrapper(type) || Enum.class.isAssignableFrom(type) || CharSequence.class.isAssignableFrom(type) || Number.class.isAssignableFrom(type) || Date.class.isAssignableFrom(type) || Temporal.class.isAssignableFrom(type) || URI.class == type || URL.class == type || Locale.class == type || Class.class == type); }
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory {
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
Set<String> result = new TreeSet(); // 需要装配的属性集合
PropertyValues pvs = mbd.getPropertyValues();
// 这里可以获取到所有的属性
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
PropertyDescriptor[] var6 = pds;
int var7 = pds.length;
for(int var8 = 0; var8 < var7; ++var8) {
PropertyDescriptor pd = var6[var8];//属性描述器
// 进行自动装配的判断
// pd.getWriteMethod()是判断有没有set方法
if (pd.getWriteMethod() != null && !this.isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) && !BeanUtils.isSimpleProperty(pd.getPropertyType())) {
result.add(pd.getName());
}
}
return StringUtils.toStringArray(result);
}
}