前言: 本文将重点讲解Mybatis-spring的执行过程,对比mybatis和Mybatis-spring的流程差异,以及Mybatis-spring一级缓存失效的原因(文章方法15),和spring自动注入的原理和哪些属性不会自动装配的讲解。
解析mybatis-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);
}
}