Java-第十五部分-源码解读-自定义Spring整合Mybatis

196 阅读2分钟

源码解读全文

自定义整合Mybatis

  • 整个过程是为service注入mapper的代理对象,让mybatis生成的代理对象成为一个Bean
  • Mybatis解析注解上的sql语句,并生成实际的调用业务

自定义业务类

  • OrderMapper
public interface OrderMapper {
    @Select("select name from bank where money = #{money}")
    public String getUserName(int money);
}
  • UserMapper
public interface UserMapper {
    @Select("select name from bank where money = #{money}")
    public String getUserName(int money);
}
  • UserService
@Component
public class UserService {
    @Autowired
    private UserMapper userMapper; //注入代理对象 由mybatis生成
    @Autowired
    private OrderMapper orderMapper;
    public void test() {
        System.out.println(userMapper.getUserName(2200));
        System.out.println(orderMapper.getUserName(1500));
    }
}

自定义工厂类

  • InitFactoryBean,实际负责生成mapper的代理类
//能够自定义让一个对象成为一个Bean对象的工厂,beanName为工厂首字母小写的形式
//&工厂首字母小写,可以获取实际的工厂类
public class InitFactoryBean implements FactoryBean {
    private SqlSession sqlSession;
    //表明返回的是那个Mapper的代理对象
    private Class mapperClass;

    public InitFactoryBean(Class mapperClass) {
        this.mapperClass = mapperClass;
    }
    @Autowired
    //通过SqlSessionFactory 为 SqlSession 注入
    //属于Mybatis的部分,可以将mapper接口,转换成代理类,可以解析注解的sql语句
    public void setSqlSession(SqlSessionFactory sqlSessionFactory) {
        sqlSessionFactory.getConfiguration().addMapper(mapperClass);
        this.sqlSession = sqlSessionFactory.openSession();
    }
    @Override
    public Object getObject() throws Exception {
        //可以处理返回 mybatis生成的代理对象
        return sqlSession.getMapper(mapperClass);
    }
    @Override
    public Class<?> getObjectType() {
        return mapperClass;
    }
}

BeanDifinition注册器

  • InitImportBeanDefinitionRegistrar
/**
 * 自定义BeanDifinition注册器,进行BeanDifinition注册
 * Spring 发现该注入的配置实现了ImportBeanDefinitionRegistrar,会调用registerBeanDefinitions
 */
public class InitImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        //获取扫描路径
        //通过Spring获取到注解的属性
        Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(InitScan.class.getName());
        String path = (String) annotationAttributes.get("value");
        //扫描器
        InitScanner initScanner = new InitScanner(registry);
        //过滤器
        initScanner.addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                return true;
            }
        });
        initScanner.scan(path);

        //自定义一个BeanDefinition 并注册到上下文中
        //AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
        //beanDefinition.setBeanClass(InitFactoryBean.class);
        //指定构造方法的参数
        //beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserMapper.class);
        //registry.registerBeanDefinition("userMapper", beanDefinition);
    }
}

自定义注解

  • InitScan配合扫描器InitScanner,获取Mapper的包名
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
//导入BeanDefinitionRegistrar,加载Mybatis的Mapper工厂
@Import(InitImportBeanDefinitionRegistrar.class)
public @interface InitScan {
    String value() default "";
}

扫描器

  • InitScanner
//扫描接口
public class InitScanner extends ClassPathBeanDefinitionScanner {
    public InitScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }
    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        //是接口才能被扫描,过滤调不是接口的
        return beanDefinition.getMetadata().isInterface();
    }

    @Override
    //Spring 内部会将这个方法生成的 BeanDefinition放入容器中
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        //先调用doScan进行扫描,由于上面已经不过滤接口了,这里就能扫描到
        //需要将扫出来的接口,转换为工厂类,才能真正形成mapper的代理类
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
            //获取扫描到的mapper,并先设置为工厂类的构造参数
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
            //再设置为工厂的类
            beanDefinition.setBeanClassName(InitFactoryBean.class.getName());
        }
        return beanDefinitionHolders;
    }
}

配置类

  • AppConfig
@ComponentScan("com.java")
//标注mapper的包
@InitScan("com.java.mapper")
public class AppConfig {
    @Bean
    //生成 SqlSessionFactory Bean 需要配置数据源
    public SqlSessionFactory sqlSessionFactory() throws IOException {
        InputStream is = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        return sqlSessionFactory;
    }
}

使用

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.test();
        //获取的getObject返回的Bean
        //System.out.println(applicationContext.getBean("initFactoryBean"));
        //获取FactoryBean
        //System.out.println(applicationContext.getBean("&initFactoryBean"));
    }
}