咱们分析的时候先本身猜想实现方式再对比mybatis的源码实现方式spring
咱们本身实现mapper建立工厂代理类:sql
public class MySessionFactoryProxy {
public static Object getMapper(Class c){
Class[] classes = new Class[]{c};
//动态代理获取mapper
Object o = Proxy.newProxyInstance(MySessionFactoryProxy.class.getClassLoader(), classes, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//解析sql
//执行sql
Select annotation = method.getAnnotation(Select.class);
String sql = annotation.value()[0];//一个注解可能有多个sql语句
System.out.println("sql:"+sql);
return null;
}
});
return o;
}
}复制代码
那么由谁来调用这个getMapper方法呢,毫无疑问是mybatis,这个时候须要一个工厂bean,用来调用该方法,每次调用,建立一个factoryBean,传入一个mapper类,来建立该mapper(这样就能够解决代码写死的状况)springboot
public class MyMapperFactoryBean<T> implements FactoryBean<T> {
//实例化的时候传入
public MyMapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
//使用全局变量存储不一样的mapper类
private Class<T> mapperInterface;
public T getObject() throws Exception {
System.out.println("get mapper");
return (T) MySessionFactoryProxy.getMapper(mapperInterface);
}
public Class<?> getObjectType() {
return this.mapperInterface;
}
}复制代码
再看mybatis的实现mybatis
public class MapperRegistry {
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
//主要调用
return mapperProxyFactory.newInstance(sqlSession);
}复制代码
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
//主要方法以下
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
}复制代码
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
private Class<T> mapperInterface;
public MapperFactoryBean(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public T getObject() throws Exception {
return this.getSqlSession().getMapper(this.mapperInterface);
}
public Class<T> getObjectType() {
return this.mapperInterface;
}
public void setMapperInterface(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return this.mapperInterface;
}
}
复制代码
与咱们建立的大致一致app
建立完成mapper后,咱们须要把mapper交给ioc管理函数
请区别
添加注解或者配置,将类交个Spring管理,由Spring为咱们建立对象
,mapper是由mybatis经过动态代理建立的源码分析
本身建立对象交给Spring管理测试
@Configuration
@ComponentScan("top.dzou.mybatis")
public class Appconfig {
@Bean
public UserMapper userMapper(){
return (UserMapper) MySessionFactoryProxy.getMapper(UserMapper.class);
}
}复制代码
每个都要建立一个@bean注解,不切实际,想一想Spring怎么实现的?ui
相似下面写法:this
使用咱们本身的mapper工厂代理类建立mapper
<bean id="roleMapper" class="top.dzou.mybatis.mapper_to_spring.my_mybatis.MyMapperFactoryBean">
<property name="mapperInterface" value="top.dzou.mybatis.mapper_to_spring.RoleMapper"/>
</bean>
<bean id="userMapper" class="top.dzou.mybatis.mapper_to_spring.my_mybatis.MyMapperFactoryBean">
<property name="mapperInterface" value="top.dzou.mybatis.mapper_to_spring.UserMapper"/>
</bean>
</beans>复制代码
这样的代码是否是很熟悉,可是这样任然要配置不少的bean,咱们想到了springboot中使用的mapperscan注解
MyMapperScan
,包括一个包,在MapperScan注解上导入mapper导入类,把包下面的所有建立并放到spring中 这里咱们须要知道的是Spring建立bean的时候是先加载类并建立BeanDefinition
,在经过BeanDefinition建立相应的bean,咱们由于mapper
咱们本身实现:
根据basePackages导入mapper
//导入ImportBeanDefinitionRegister
@Import(MyBeanDefinitionRegister.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMapperScan {
String[] basePackages() default {};
}
复制代码
使用Spring注册bean时使用的ImportBeanDefinitionRegistrar注册mapper
public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
//class->beanDefinition->map->bean
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
//获取包信息并把包中类所有注册动态添加到beanDefinition参数中
{
//伪代码
basePackages = 获取包名下的所用mapper类,保存到集合basePackages
baseName = 从mapper类获取beanName
}
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(MyMapperFactoryBean.class);
BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(basePackages);
beanDefinitionRegistry.registerBeanDefinition(beanName,beanDefinition);
}
}复制代码
@Configuration
@ComponentScan("top.dzou.mybatis.mapper_to_spring")
@MyMapperScan(basePackages = "top.dzou.mapper_to_spring.mapper")//自定义mapper扫描注解
public class Appconfig {}复制代码
咱们看一下mybatis怎么实现的
它导入了一个MapperScannerRegistrar
扫描注册mapper的类
@Import({MapperScannerRegistrar.class})
public @interface MapperScan {复制代码
咱们能够看到它实现了ImportBeanDefinitionRegistrar
的bean定义导入注册类,实现了具体的registerBeanDefinitions
注册bean定义的方法,把包下的mapper所有添加到一个集合中,而后把这个集合进行注册到ioc中,和咱们的想法基本一致
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
List<String> basePackages = new ArrayList();
basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("value")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll((Collection)Arrays.stream(annoAttrs.getStringArray("basePackages")).filter(StringUtils::hasText).collect(Collectors.toList()));
basePackages.addAll((Collection)Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName).collect(Collectors.toList()));
builder.addPropertyValue("basePackage", StringUtils.collectionToCommaDelimitedString(basePackages));
registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
}复制代码
它使用一个集合保存了全部的mapper类,并把他们放在一个beanDefinition中进行注册
整个过程主要分为
重点: