mybatis架构:https://www.jianshu.com/p/15781ec742f(引用这位大佬的)
个人总结:
public static void main(String[] args) throws IOException {
String resource = "Mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
List<Map<String, Object>> maps = mapper.testQuery();
List<Map<String, Object>> maps1 = mapper.testQuery();
TestMapper mapper1 = sqlSession2.getMapper(TestMapper.class);
List<Map<String, Object>> maps2 = mapper1.testQuery();
}
mybatis通过:
String resource = "Mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
构建一个SqlSessionFactory
默认使用实现DefaultSqlSessionFactory,SqlSessionManager虽然也是它的子类,但是是利用装饰者模式装饰SqlSessionFactory,添加
private final SqlSession sqlSessionProxy;
字段进行SqlSession的管理:
new SqlSessionFactoryBuilder().build(inputStream);传入的是读取Mybatis-config.xml的输入流,其实就是利用mybatis的配置文件,生成一个
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
利用XMLConfigBuilder .parse()生成Configuration(解析XML,生成mybatis的配置信息)
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
而DefaultSqlSessionFactory的唯一属性进行Configuration
SqlSession sqlSession = sqlSessionFactory.openSession();
这个获得一个SqlSession,利用SqlSession去获得Mapper,然后去执行方法
其实不是SqlSession去执行的,二十交给执行器Executor去执行sql
Executor的继承体系:
Executor根据下面的不同类型生成不同的处理,每个处理有不同作用:
public enum ExecutorType {
SIMPLE, REUSE, BATCH
}
ExecutorType.SIMPLE:这个执行器类型不做特殊的事情。它为每个语句的每次执行创建一 个新的预处理语句。
ExecutorType.REUSE:这个执行器类型会复用预处理语句。
ExecutorType.BATCH:这个执行器会批量执行所有更新语句,也就是jdbc addBatch API的 facade模式。
你们可以自己去看对应的类的源码哈。
咱们在看这个的源码
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
sqlSession.getMapper(TestMapper.class);方法转交org.apache.ibatis.session.Configuration#getMapper》》org.apache.ibatis.binding.MapperRegistry#getMapper》》org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.session.SqlSession)》》(T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
其实到最后生成一个代理对象MapperProxy<T>
MapperProxy<T>实现了InvocationHandler,所以最后是利用jDK的动态代理生成一个代理对象。
后面的内容我就不说了前面引用的文章里面有。
补充一点,mybatis 的一级缓存和二级缓存
引用大佬的文章:https://tech.meituan.com/2018/01/19/mybatis-cache.html
Spring 整合Mybatis
spring 怎么扫描 mapper beanDefinition
与其说spring 整合Mybatis不如说Mybatis整合(有历史的缘故,自己百度)
我们在整合的时候会在配置类上加上一个注解@MapperScan,这个注解的用处就大了啦,
所有的Mapper扫面就是因为这个注解才会被扫描到spring bean里面去,咱们进去看这个注解的源码:
这里标注的@Import(MapperScannerRegistrar.class)导入了一个类,这个类的bean什么时候加载的大家自己去看我的Aop源码解析里面哈,跟那个差不多。
咱们在进去这个里面看源码:
因为这个MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口,所以在bean扫描@Import或得MapperScannerRegistrar得信息,然后加载bean的时候回去执行:
org.springframework.context.annotation.ImportBeanDefinitionRegistrar#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.beans.factory.support.BeanNameGenerator)
方法,咱们在看org.mybatis.spring.annotation.MapperScannerRegistrar#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry)
源码:
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes mapperScanAttrs = AnnotationAttributes
.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
if (mapperScanAttrs != null) {
registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry,
generateBaseBeanName(importingClassMetadata, 0));
}
}
void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs,
BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
builder.addPropertyValue("processPropertyPlaceHolders", true);
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);
}
builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);z这里面又注册了一个MapperScannerConfigurer的BeanDefinitionBuilder,再看MapperScannerConfigurer的源码:
因为实现了BeanDefinitionRegistryPostProcessor,所以在启动的时候回去先去实例化MapperScannerConfigurer,然后调用:
org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
再看MapperScannerConfigurer#postProcessBeanDefinitionRegistry做了什么:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
if (this.processPropertyPlaceHolders) {
processPropertyPlaceHolders();
}
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));
}
scanner.registerFilters();
scanner.scan(
StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);生成了一个
ClassPathMapperScanner,然后调用ClassPathMapperScannerdoScan(String... basePackages)
public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {}
ClassPathScanningCandidateComponentProvider就是spring里面用来扫描bean的,并且
ClassPathMapperScanner重写了
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
用来判断可以扫描接口,也就是mapper
咱们在看org.mybatis.spring.mapper.ClassPathMapperScanner#doScan方法:
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
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 {
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
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
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
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() + "'.");
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
definition.setLazyInit(lazyInitialization);
}
}
其实就是利用spring扫描出mapper的BeanDefinitionHolder,然后在在org.mybatis.spring.mapper.ClassPathMapperScanner#processBeanDefinitions进行变更一下:
definition.setBeanClass(this.mapperFactoryBeanClass); private Class<? extends MapperFactoryBean> mapperFactoryBeanClass = MapperFactoryBean.class; z这里设置bean的类型为MapperFactoryBean(实现了FactoryBean,实现了org.springframework.beans.factory.FactoryBean#getObject)利用getObject()获取对象
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
到这里是不是很熟悉了,上面有分析过哈。
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);这个设置根据类型加载bean哈,也是重要点。
到这里面基本上就可以知道mapper beanDefinition 是怎么存到spring的bean工厂里面的啦。
spring 获取 mapper 对像
其实上面已经分析到了MapperFactoryBean#getObject的方法了,怎么获取就简单了
1.spring 在利用org.springframework.context.support.AbstractApplicationContext#getBean(java.lang.String, java.lang.Class<T>)
TestMapper testMapper = applicationContext.getBean("testMapper", TestMapper.class);
的时候,回去判断beanDefinition 的类型是不是FactoryBean,如果是的话就调用
org.springframework.beans.factory.FactoryBean#getObject)获取对象。
那不又回到我们开始的地方了。
具体可以自己打断点跟踪哈。