zhiyuan0 2020-04-14
我们知道spring对bean的管理,我们可以通过多种方式将bean添加进spring中进行管理其中包括:
一:bean交由spring管理
mybatis通过@MapperScan标签完成对接口mapper的注入,我们依次点击@MapperScan->@Import(MapperScannerRegistrar.class)->MapperScannerRegistrar implements ImportBeanDefinitionRegistrar通过重写registerBeanDefinitions这个方法完成bean的注入。部分相关代码如下:
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { ...for (String pkg : annoAttrs.getStringArray("basePackages")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); ...scanner.doScan(StringUtils.toStringArray(basePackages)); } @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) { for (BeanDefinitionHolder holder : beanDefinitions) { definition = (GenericBeanDefinition) holder.getBeanDefinition(); ... // the mapper interface is the original class of the bean but, the actual class of the bean is MapperFactoryBean definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName()); definition.setBeanClass(this.mapperFactoryBean.getClass()); }
二:MapperFactoryBean:MapperFactoryBean->SqlSessionDaoSupport->DaoSupport->InitializingBean(在bean实例化前执行checkDaoConfig方法)
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> { public MapperFactoryBean(Class<T> mapperInterface) { this.mapperInterface = mapperInterface; }//把接口类型传入factoryBean便于代理对象的产生 @Override protected void checkDaoConfig() { ... configuration.addMapper(this.mapperInterface)->mapperRegistry.addMapper(type)->parser.parse()(完成一些注解解析及sql生成等) ... } } @Override public T getObject() throws Exception { //getSqlSession()->SqlSessionTemplate 在MapperFactoryBean实例化过程中,会首先根据mybatis-spring-boot-autoconfigure中META-INF/spring.factories中的内容获取到MybatisAutoConfiguration这个配置类类名。在后续的bean创建过 程中,MybatisAutoConfiguration类的对象会被创建成一个继承了FactoryBean的代理对象放到bean工厂中 MybatisAutoConfiguration中SqlSessionTemplate sqlSessionFactory两个类的的生成是@Bean注解来生成 return getSqlSession().getMapper(this.mapperInterface);->>> public T newInstance(SqlSession sqlSession) { final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } } } public class MapperProxy<T> implements InvocationHandler, Serializable { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { ... return method.invoke(this, args); ... return mapperMethod.execute(sqlSession, args); } } public Object execute(SqlSession sqlSession, Object[] args) { Object result; switch (command.getType()) { case INSERT: { Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.insert(command.getName(), param)); break; } ... case SELECT: if (method.returnsVoid() && method.hasResultHandler()) { executeWithResultHandler(sqlSession, args); result = null; } else if (method.returnsMany()) { result = executeForMany(sqlSession, args); ... } private <E> Object executeForMany(SqlSession sqlSession, Object[] args) { ... result = sqlSession.<E>selectList(command.getName(), param); ... } //sqlSession为SqlSessionTemplate @Override public <E> List<E> selectList(String statement, Object parameter) { return this.sqlSessionProxy.<E> selectList(statement, parameter);//执行invoke方法 } private class SqlSessionInterceptor implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { SqlSession sqlSession = getSqlSession( ... } finally { if (sqlSession != null) { closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);//mybatis结合spring时一级缓存失效原因 } } } }