Spring 3.x+版本支持使用@Configuration和@Bean注解来提供基于 Java 的配置。
如果使用基于java的配置,可以使用@MapperScan注解来扫描映射Mapper接口类。
@MapperScan(value = "org.springframework.orm.mapper", sqlSessionFactoryRef = "sqlSessionFactoryBean") // 通过Bean注解注入自定义构建的SqlSessionFactoryBean对象 @Bean public SqlSessionFactoryBean sqlSessionFactoryBean() throws Exception { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); sqlSessionFactoryBean.setDataSource(dataSource()); sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() .getResources("T1Mapper.xml")); sqlSessionFactoryBean.setTypeAliasesPackage("org.springframework.orm.entity"); return sqlSessionFactoryBean; }
value:指定mapper接口类包路径
sqlSessionFactoryRef:指定SqlSessionFactoryBean对象名
MapperScan进一步解析
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented // 通过spring import注解方式加载 @Import(MapperScannerRegistrar.class) public @interface MapperScan {
@Import 是被用来整合所有在@Configuration注解中定义的bean配置
这里MapperScannerRegistrar实现了ImportBeanDefinitionRegistrar接口注入bean,再通过import注解导入加载。
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 获取注解 AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName())); // 扩展spring中ClassPathBeanDefinitionScanner类将类扫面成BeanDefinition ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
// 扫描包路径集 List
basePackages = new ArrayList
(); for (String pkg : annoAttrs.getStringArray("value")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (String pkg : annoAttrs.getStringArray("basePackages")) { if (StringUtils.hasText(pkg)) { basePackages.add(pkg); } } for (Class
clazz : annoAttrs.getClassArray("basePackageClasses")) { basePackages.add(ClassUtils.getPackageName(clazz)); } // 注册相关filter scanner.registerFilters(); // 扫描 scanner.doScan(StringUtils.toStringArray(basePackages));
scanner.doScan中将实现mapper扫描映射
// 通过spring提供的方法将mapper接口类扫描转换成BeanDefinitionHolder集合 Set
beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) { logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration."); } else { // 再根据BeanDefinitionHolder做相关处理 processBeanDefinitions(beanDefinitions); } return beanDefinitions;
processBeanDefinitions方法中会设置mapper注入对应实现的bean等配置
private MapperFactoryBean
mapperFactoryBean = new MapperFactoryBean
definition.setBeanClass(this.mapperFactoryBean.getClass())此处设置mapper接口对应的实现类为MapperFactoryBean类。
MapperFactoryBean类实现了FactoryBean功能,最后实际执行的bean对象是通过getObject方法获取。
public T getObject() throws Exception { // 此处使用了动态代理 return getSqlSession().getMapper(this.mapperInterface); }
protected T newInstance(MapperProxy
mapperProxy) { // 通过MapperProxy生成mapper接口执行的代理对象 return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public T newInstance(SqlSession sqlSession) { // MapperProxy就是实际的目标对象,也就是代理对象 final MapperProxy
mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); }
到此处为止,可以看到mybatis加载的mapper接口对应的实现目标类都是MapperProxy对象。
SqlSessionTemplate类中执行具体操作是再次使用了一次代理
this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; this.sqlSessionProxy = (SqlSession) newProxyInstance( SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class }, new SqlSessionInterceptor());
sqlSessionProxy代理对象是在SqlSessionTemplate对象构造方法时指定的
...... public void select(String statement, ResultHandler handler) { this.sqlSessionProxy.select(statement, handler); } public void select(String statement, Object parameter, ResultHandler handler) { this.sqlSessionProxy.select(statement, parameter, handler); } ......
SqlSessionInterceptor代理类
private class SqlSessionInterceptor implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 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) { closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); } } } }
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/219792.html原文链接:https://javaforall.net
