自己写的spring整合mybatis

86 阅读1分钟

自己写的spring整合mybatis,涉及到好多spring的知识,有助于我们理解spring框架,有助于我们在构思公司的框架的时候提供一些思路,所以有必要学习

1. 构建的enable注解

构建enable注解,通常和@Import注解一起使用

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MapperRegistrar.class)
public @interface EnableMapperScanner {

    String[] value() default {};
}

2. 扫描启动器

/**
 * 用来开启扫描,扫描需要代理的接口
 */
public class MapperRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
        // 1、获取 EnableMapperScanner 配置的包路径
        List<String> pkgList = parsePkgList(annotationMetadata);

        // 2、想办法调用扫描器进行扫描
        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.registerFilters();
        scanner.doScan(StringUtils.toStringArray(pkgList));
    }

    private List<String> parsePkgList(AnnotationMetadata annotationMetadata) {
        AnnotationAttributes annoAttrs =
                AnnotationAttributes.fromMap(annotationMetadata.getAnnotationAttributes(EnableMapperScanner.class.getName()));

        String[] basePkgs = annoAttrs.getStringArray("value");
        List<String> resultList = new ArrayList<>();
        for (String pkg : basePkgs) {
            if (StringUtils.isEmpty(pkg)) {
                continue;
            }
            resultList.add(pkg);
        }

        return resultList;
    }
}

3. 扫描器

扫到接口就


public class ClassPathMapperScanner extends ClassPathBeanDefinitionScanner {

    private MapperFactoryBean mapperFactoryBean = new MapperFactoryBean();

    public ClassPathMapperScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

    public void registerFilters(){
        addIncludeFilter(new TypeFilter() {
            @Override
            public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
                return true;
            }
        });
    }

    @Override
    public Set<BeanDefinitionHolder> doScan(String... basePackages) {
        // 1. 调用父类方法得到所有的BeanDefinition集合
        Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
        if (beanDefinitions == null || beanDefinitions.isEmpty()) {
            return beanDefinitions;
        }

        // 2. 针对BeanDefinition集合进行改造,目的是为了代理XxxMapper这样的接口类
        reProcessBeanDefinitions(beanDefinitions);
        return beanDefinitions;
    }

    private void reProcessBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
        for (BeanDefinitionHolder holder : beanDefinitions) {
            GenericBeanDefinition beanDefinition = (GenericBeanDefinition)holder.getBeanDefinition();

            beanDefinition.getConstructorArgumentValues()
                    .addGenericArgumentValue(beanDefinition.getBeanClassName());
            beanDefinition.setBeanClass(mapperFactoryBean.getClass());
            beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
        }
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        AnnotationMetadata metadata = beanDefinition.getMetadata();
        return metadata.isInterface();
    }


}

4. 代理器


public class MapperProxy implements InvocationHandler {

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 可以拿到方法名称,到 xml 里面拿到对应的 sql,再用最原始的方法操作数据库,StatementHandler
        // 也可以通过方法拿到方法上面的注解中的sql
        Map<String, Object> respMap = new HashMap<>();
        respMap.put("name", "roy");
        respMap.put("args", args);
        respMap.put("age", "18");
        return respMap;
    }
}

5. FactoryBean 实例

public class MapperFactoryBean<T> implements FactoryBean<T> {

    private Class<T> rawMapperClass;

    public MapperFactoryBean() {
    }

    public MapperFactoryBean(Class<T> rawMapperClass) {
        this.rawMapperClass = rawMapperClass;
    }

    @Override
    public T getObject() throws Exception {
        Object proxy = Proxy.newProxyInstance(
                rawMapperClass.getClassLoader(),
                new Class[]{rawMapperClass},
                new MapperProxy()
        );
        return (T) proxy;
    }

    @Override
    public Class<?> getObjectType() {
        return rawMapperClass;
    }
}

6. test

@RestController
public class ScannerController {

    @Autowired
    private UserMapper userMapper;

    @RequestMapping("/user")
    public Object getUserById(String userId){
        return userMapper.getUserById(userId);
    }
}

启动类

@SpringBootApplication
@EnableAspectJAutoProxy
@PropertySource(encoding = "UTF-8",
        ignoreResourceNotFound = true,
        value = {"file:/tmp/roy.properties"})
@EnableMapperScanner(value = {"com.roy.scanner.mapper"})
public class APP {

    public static void main(String[] args) {
        SpringApplication.run(APP.class, args);
    }

}