Mapper接口的解析
@Mapper注解修饰的一个个mapper接口是怎么生效的,它是如何被Spring管理的呢?今天通过简单的配置来实现。
1)环境准备
package com.example.demo2.b03.mapper;import org.apache.ibatis.annotations.Mapper;/*** @author zhou* @version 1.0* @description TODO* @date 2025/10/5 22:51*/
@Mapper
public interface Mapper1 {
}
package com.example.demo2.b03.mapper;import org.apache.ibatis.annotations.Mapper;/*** @author zhou* @version 1.0* @description TODO* @date 2025/10/5 22:51*/
@Mapper
public interface Mapper2 {
}
上面提供了两个接口。
2)配置类
在config配置类里面配置下面两个bean,就可以把两个Mapper接口转换为被Spring管理的bean。
可以看到返回的bean是MapperFactoryBean<Mapper1>。
@Beanpublic MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory){MapperFactoryBean<Mapper1> factoryBean = new MapperFactoryBean<>(Mapper1.class);factoryBean.setSqlSessionFactory(sqlSessionFactory);return factoryBean;}
@Beanpublic MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory){MapperFactoryBean<Mapper2> factoryBean = new MapperFactoryBean<>(Mapper2.class);factoryBean.setSqlSessionFactory(sqlSessionFactory);return factoryBean;}
config配置类代码如下:
package com.example.demo2.b03;import com.alibaba.druid.pool.DruidDataSource;
import com.example.demo2.b03.component.Bean2;
import com.example.demo2.b03.mapper.Mapper1;
import com.example.demo2.b03.mapper.Mapper2;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;/*** @author zhou* @version 1.0* @description TODO* @date 2025/10/5 21:46*/
@Configuration
@ComponentScan("com.example.demo2.b03.component")
public class Config {public Bean2 bean2;@Beanpublic Bean1 bean1(){return new Bean1();}@Beanpublic SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();sqlSessionFactoryBean.setDataSource(dataSource);return sqlSessionFactoryBean;}@Bean(initMethod = "init")public DruidDataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl("jdbc:mysql://localhost:3306/test");dataSource.setUsername("root");dataSource.setPassword("root");return dataSource;}@Beanpublic MapperFactoryBean<Mapper1> mapper1(SqlSessionFactory sqlSessionFactory){MapperFactoryBean<Mapper1> factoryBean = new MapperFactoryBean<>(Mapper1.class);factoryBean.setSqlSessionFactory(sqlSessionFactory);return factoryBean;}@Beanpublic MapperFactoryBean<Mapper2> mapper2(SqlSessionFactory sqlSessionFactory){MapperFactoryBean<Mapper2> factoryBean = new MapperFactoryBean<>(Mapper2.class);factoryBean.setSqlSessionFactory(sqlSessionFactory);return factoryBean;}
}
这里复用了之前的配置类。新添加的两个bean需要传入SqlSessionFactory,它可以由我们上面配置的SqlSessionFactoryBean 产生。
3)主类代码:
package com.example.demo2.b03;import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.stereotype.Component;import java.io.IOException;
import java.util.Set;/*** @author zhou* @version 1.0* @description TODO* @date 2025/10/5 21:43*/
public class A05Application {private static final Logger log = LoggerFactory.getLogger(A05Application.class);public static void main(String[] args) throws IOException {GenericApplicationContext context = new GenericApplicationContext();context.registerBean("config", Config.class);/* context.registerBean(ConfigurationClassPostProcessor.class);//@ComponentScan @Bean @Import注解 @ImportResource注解context.registerBean(MapperScannerConfigurer.class,beanDefinition -> {beanDefinition.getPropertyValues().add("basePackage","com.example.demo2.b03.mapper");});*///context.registerBean(ComponentScanPostProcessor.class);context.registerBean(AtBeanPostProcessor.class);//初始化容器context.refresh();for (String name:context.getBeanDefinitionNames()){System.out.println(name);}//销毁容器context.close();}
}
4)运行结果
配置的两个Mapper接口被Spring管理,输出的bean的名字是@Bean注解下面方法的名字。Spring容器中存储的是MapperFactoryBean<T>。
Spring底层是通过这种方式来把mapper接口添加到Spring容器中。但是这种方法不能批量配置mapper接口,该如何改进呢?