Mybatis MapperScannerConfigurer 自动扫描 将Mapper接口(也就是本文用的dao层下面的BookMapper)生成代理注入到Spring
原理是
Mybatis在与Spring集成的时候可以配置MapperFactoryBean来生成Mapper接口的代理. 例如
/**
* dataSource.
*/
@Bean(name = "dataSource")
public BasicDataSource dataSource() {
BasicDataSource dataSource = loadSource();
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
private BasicDataSource loadSource() {
BasicDataSource dataSourceJira = new BasicDataSource();
dataSourceJira.setDriverClassName(classname);
dataSourceJira.setInitialSize(datasourceInitialsize);
dataSourceJira.setMaxActive(datasourceMaxActive);
dataSourceJira.setMaxIdle(datasourceMaxIdle);
dataSourceJira.setMinIdle(datasourceMinIdle);
dataSourceJira.setMaxWait(datasourceMaxWait);
dataSourceJira.setMinEvictableIdleTimeMillis(datasourceMinEvicTimemillis);
dataSourceJira.setTimeBetweenEvictionRunsMillis(datasourceTimeBetweenEvicRunMillis);
dataSourceJira.setRemoveAbandoned(datasourceRemoveAbandoned);
dataSourceJira.setRemoveAbandonedTimeout(datasourceRemoveAbandonedTimeout);
dataSourceJira.setLogAbandoned(datasourceLogAbandoned);
dataSourceJira.setTestOnBorrow(datasourceTestOnBorrow);
dataSourceJira.setTestOnReturn(datasourceTestOnReturn);
dataSourceJira.setTestWhileIdle(datasourceTestwhileIdle);
dataSourceJira.setValidationQueryTimeout(600);
return dataSourceJira;
}
/**
sqlSessionFactoryBean
*/
@Bean(name = "sqlSessionFactoryName")
@ConditionalOnMissingBean // 当容器里没有指定的Bean的情况下创建该对象
public SqlSessionFactoryBean sqlSessionFactoryBean(
@Qualifier("dataSource") BasicDataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 设置数据源
sqlSessionFactoryBean.setDataSource(multipleDataSource);
// 设置mybatis的主配置文件
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource mybatisConfigXml = resolver.getResource("classpath:spring/sqlmap-config.xml");
sqlSessionFactoryBean.setConfigLocation(mybatisConfigXml);
return sqlSessionFactoryBean;
}
/**
* mapper接口的扫描器.
* @return mapperScannerConfigurer.
*/
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryName");
mapperScannerConfigurer.setBasePackage("com.davinqi.**.mapper");
return mapperScannerConfigurer;
}
Mybatis 创建了 MapperFactoryBean 的代理类实现了 .mapper 接口,并且注入到springBean容器中 。
public abstract class SqlSessionDaoSupport extends DaoSupport {
private SqlSession sqlSession;
private boolean externalSqlSession;
public SqlSessionDaoSupport() {
}
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
if (!this.externalSqlSession) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
}
}
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
this.sqlSession = sqlSessionTemplate;
this.externalSqlSession = true;
}
public SqlSession getSqlSession() {
return this.sqlSession;
}
protected void checkDaoConfig() {
Assert.notNull(this.sqlSession, "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
}
}
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
Assert.notNull(executorType, "Property 'executorType' is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
}
看到这: Proxy.newProxyInstance
大家应该都懂了,他就是使用的Jdk的动态代理。
MyBatis-Spring提供了一个MapperFactoryBean,可以将数据映射接口转为Spring Bean。果数据映射接口很多的话,需要在Spring的配置文件中对数据映射接口做配置,相应的配置项会很多了。
在Service中@Autowired的方法直接注入接口实例。在Spring的配置文件中可以采用以下所示的配置将接口转化为Bean。为了简化配置,在MyBatis-Spring中提供了一个转换器MapperScannerConfig它 继承了 Spring 的 BeanPostProcessor 后置处理器 这样在spring
容器启动时就可以加载Mybatis自动反射实现的类到容器中的Bean了。