文章目录
- 目的
- 实现注解
- 代理
- 声明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 {// 创建数据库连接(此处使用示例数据库信息)}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 这里可以拦截不同的方法来实现不同的crud操作if (method.isAnnotationPresent(Insert.class)) {// 获取注解中的 SQLInsert insert = method.getAnnotation(Insert.class);String sql = insert.value();// 从参数中获取 User 对象,这里可以执行SQLUser 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;}@Overridepublic T getObject() throws Exception {MapperProxy proxy = new MapperProxy();//生成代理类return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(),new Class<?>[]{mapperInterface},proxy);}@Overridepublic 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;}@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 扫描包路径下的 Mapper 接口,注册到容器ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false) {@Overrideprotected 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);}}@Overridepublic void postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory beanFactory) throws BeansException {// 不需要实现这个方法}
}
启动类
@Configuration
public class AppConfig {@Beanpublic 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 Setterspublic 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;}
}