理解mybatis 里的mapper 实现原理

目的

主要想搞明白,mybatis 是如何通过只通过声明一个mapper 接口,就能实现crud 操作了

实现注解

@Retention(RetentionPolicy.RUNTIME)
public @interface Mapper {
}

@Retention(RetentionPolicy.RUNTIME)
public @interface Insert {
    String value();
}

代理

public class MapperProxy implements InvocationHandler {

    public MapperProxy() throws Exception {
        // 创建数据库连接(此处使用示例数据库信息)
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 这里可以拦截不同的方法来实现不同的crud操作
        if (method.isAnnotationPresent(Insert.class)) {
            // 获取注解中的 SQL
            Insert insert = method.getAnnotation(Insert.class);
            String sql = insert.value();

            // 从参数中获取 User 对象,这里可以执行SQL
            User user = (User) args[0];
            sql = sql.replace("#{name}", "'" + user.getName() + "'");


            System.out.println(sql);
        }
        return null;
    }
}

public class MapperProxyFactory<T> implements FactoryBean<T> {
    private Class<T> mapperInterface;

    public MapperProxyFactory(Class<T> mapperInterface) {
        this.mapperInterface = mapperInterface;
    }
    
    @Override
    public T getObject() throws Exception {
        MapperProxy proxy = new MapperProxy();
        //生成代理类
        return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(),
                new Class<?>[]{mapperInterface},
                proxy);
    }

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

  
}

声明mapper

@Mapper
public interface UserMapper {
    @Insert("INSERT INTO User (name) VALUES (#{name})")
    void insertUser(User user);
}

扫描类

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor {
    private String basePackage;

    public void setBasePackage(String basePackage) {
        this.basePackage = basePackage;
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // 扫描包路径下的 Mapper 接口,注册到容器
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition metadataReader)  {
                return true;
            }
        };
        scanner.addIncludeFilter(new AnnotationTypeFilter(Mapper.class));
        for (BeanDefinition beanDefinition : scanner.findCandidateComponents(basePackage)) {
            GenericBeanDefinition definition = (GenericBeanDefinition) beanDefinition;
            String beanClassName = definition.getBeanClassName();

            // 设置为 MapperFactoryBean 代理类
            definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
            definition.setBeanClass(MapperProxyFactory.class);

            // 注册 Bean 到 Spring 容器
            registry.registerBeanDefinition(beanClassName, definition);
        }
    }

    @Override
    public void postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 不需要实现这个方法
    }
}


启动类

@Configuration
public class AppConfig {

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        configurer.setBasePackage("com.demo.ma.mapper"); // 设置扫描包路径
        return configurer;
    }
}

public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        UserMapper userMapper = context.getBean(UserMapper.class);
        // 测试调用
        userMapper.insertUser(new User(1,"aa"));
        context.close();
    }
}

public class User {
    private Integer id;
    private String name;

    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    // Getters and Setters
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wending-Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值