spring-mybatis 整合分析
spring-mybatis 的整合流程
- 载入配置jar
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>
- 配置datasource 和 sqlsessionFactoryBean
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
return factoryBean.getObject();
}
- 创建mapper 接口
public interface UserMapper {
@Select("SELECT * FROM users WHERE id = #{userId}")
User getUser(@Param("userId") String userId);
}
- 将接口注入到容器中
@Bean
public UserMapper userMapper() throws Exception {
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory());
return sqlSessionTemplate.getMapper(UserMapper.class);
}
- 交给mapperFactory bean 注入到容器
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
然后我们就可以像普通的IOC容器中的bean进行调用;
- 使用mapperScan("")扫描我们接口,交给spring管理
原理分析
- 接口是如何注入到容器?
我们知道只有将实体类或者抽象类注入到容器,接口是无法注入到容器中。spring-mybatis 是如何将接口注入到容器。
这里很明显可以通过动态代理进行,生成实体类进行注入;
public class MapperProxy<T> implements InvocationHandler, Serializable {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
}
}
- userMapper 接口是通过 MapperFactoryBean注入到bean容器
在 postBeanFactoryProcesser() 改了class为MapperFactoryBean,
在注册的过程中将@mapperScan扫描的接口改为,MapperFactoryBean,将其注册到容器中;
构造函数任然是原本的构造函数参数,然后通过动态代理在MapperFactoryBean,实例化userMapper;
把注入模型改为 by_type, 给父类sqlSession进程set方法赋值,不改为by_name 是为容错处理,避免配错;
适应工厂bean进行注入,可以隐藏配置的代码;
sqlSessionFactoryBean,会解析全局配置文件进行缓存;
然后通过动态代理在MapperFactoryBean 的 getObject()生成代理对象;
- 我没并没有配置代理类的注解(@Bean,@Service),也没有进行扫描,他是如何注入的;
我们知道spring将bean注入容器的 可以使用 @Bean,
@service 等 + @ComponentScan(""), 或者 @Import进行注入;
// 通过在注册器中,构造bean定义并通过import导入,spring整合mybatis
@import(value = {ImportBeanDifinitionRegister.class})
可以实现一个bean定义的注册类,将需要的bean注册到容器;
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
if (this.processPropertyPlaceHolders) {
this.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.registerFilters();
scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
}
Spring 中循环依赖是如何解决?
spring中单利支持循环依赖。
怎么关闭spring的循环依赖?
spring 在初始化的时候完成依赖注入
singlonObjects cache 单利缓存池 容器
为什么要先get singlonObjects
判断对象是否在创建中
为什么有三级缓存?
网友评论