我们自己实现mapper创建工厂代理类:
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(这样就可以解决代码写死的情况)
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; } }
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; } }
创建完成mapper后,我们需要把mapper交给ioc管理
请区别 添加注解或者配置,将类交个Spring管理,由Spring为我们创建对象
,mapper是由mybatis通过动态代理创建的
@Configuration @ComponentScan("top.dzou.mybatis") public class Appconfig { @Bean public UserMapper userMapper(){ return (UserMapper) MySessionFactoryProxy.getMapper(UserMapper.class); } }
每一个都要创建一个@bean注解,不切实际,想想Spring怎么实现的?
类似下面写法:
使用我们自己的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中 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 {}
它导入了一个 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中进行注册
整个过程主要分为
重点: