原理:
- FactoryBean的自定义对象
- jdk动态代理Mapper接口对象
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
context.refresh();
UserService userService = (UserService)context.getBean("userService");
userService.test();
}
}
@CondorHeroMapperScan("com.athome.tulin.springmybatis.mapper")
@ComponentScan("com.athome.tulin.springmybatis")
public class AppConfig {
@Bean
public SqlSessionFactory sqlSessionFactory() throws IOException {
System.out.println("4.依赖注入MemberMapper需要先创建对象………AppConfig…………SqlSessionFactory………");
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
}
@Component
public class UserService {
public UserService() {
System.out.println("3.…………创建UserService…………");
}
//如何把mybatis生成的UserMapper的代理对象赋值给UserMapper
@Autowired
private UserMapper userMapper;
@Autowired
private OrderMapper orderMapper;
@Autowired
private MemberMapper memberMapper;
public void test(){
System.out.println("7.……UserService…test…");
System.out.println(userMapper.selectById());
System.out.println(orderMapper.selectById());
System.out.println(memberMapper.selectById());
}
}
public interface MemberMapper {
@Select("select 'member' ")
String selectById();
}
public interface OrderMapper {
@Select("select 'order' ")
String selectById();
}
public interface UserMapper {
@Select("select 'user' ")
String selectById();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(CondorHeroImportBeanDefinitionRegistrar.class)
public @interface CondorHeroMapperScan {
String value();
}
public class CondorHeroFactoryBean implements FactoryBean {
private Class mapperInterface;
private SqlSession sqlSession;
public CondorHeroFactoryBean(Class mapperInterface) {
this.mapperInterface = mapperInterface;
}
/**
* 从容器查找SqlSessionFactory 并获取sqlSession 赋值于sqlSession
* 扫描的时候有 beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
* 那他就会自动找set方法
* @param sqlSessionFactory
*/
public void setSqlSession(SqlSessionFactory sqlSessionFactory) {
System.out.println("5.……setSqlSession……");
sqlSessionFactory.getConfiguration().addMapper(mapperInterface);
this.sqlSession = sqlSessionFactory.openSession();
}
@Override
public Object getObject() throws Exception {
//动态代理获取UserMapper接口对象
System.out.println("6.……getObject……");
return sqlSession.getMapper(mapperInterface);
}
@Override
public Class<?> getObjectType() {
return mapperInterface;
}
}
public class CondorHeroImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
System.out.println("1.……registerBeanDefinitions……");
//1.获取注解上的指定路径
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(CondorHeroMapperScan.class.getName());
String path = (String)annotationAttributes.get("value");
//2.扫描
CondorHeroBeanDefinitionScanner scanner = new CondorHeroBeanDefinitionScanner(registry);
scanner.addIncludeFilter(new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return true;
}
});
scanner.scan(path);
}
}
public class CondorHeroBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
public CondorHeroBeanDefinitionScanner(BeanDefinitionRegistry registry) {
super(registry);
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
//只关心接口(判断是否是接口)
return beanDefinition.getMetadata().isInterface();
}
/**
* 扫描路径并得到beanDefinition
* @param basePackages
* @return
*/
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
System.out.println("2.……doScan……");
Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
for (BeanDefinitionHolder beanDefinitionHolder: beanDefinitionHolders) {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition)beanDefinitionHolder.getBeanDefinition();
//设置值
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());
//设置名称
beanDefinition.setBeanClassName(CondorHeroFactoryBean.class.getName());
//将MapperFactoryBean的注入模型设置为By-Type。也就是说,MapperFactoryBean中的setXxx中的属性会从容器中来进行查找
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
return beanDefinitionHolders;
}
}
运行结果是:
1.……registerBeanDefinitions……
2.……doScan……
3.…………创建UserService…………
4.依赖注入MemberMapper需要先创建对象………AppConfig…………SqlSessionFactory………
5.……setSqlSession……
6.……getObject……
5.……setSqlSession……
6.……getObject……
5.……setSqlSession……
6.……getObject……
7.……UserService…test… user order member
MapperScannerConfigurer
类型的BeanDefinitionprivate void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
String beanClassName = definition.getBeanClassName();
LOGGER.debug(() -> "Creating MapperFactoryBean with name '" + holder.getBeanName() + "' and '" + beanClassName
+ "' mapperInterface");
// the mapper interface is the original class of the bean
// but, the actual class of the bean is MapperFactoryBean
//设置值
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
//设置名称
definition.setBeanClass(this.mapperFactoryBeanClass);
definition.getPropertyValues().add("addToConfig", this.addToConfig);
boolean explicitFactoryUsed = false;
if (StringUtils.hasText(this.sqlSessionFactoryBeanName)) {
definition.getPropertyValues().add("sqlSessionFactory",
new RuntimeBeanReference(this.sqlSessionFactoryBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionFactory != null) {
definition.getPropertyValues().add("sqlSessionFactory", this.sqlSessionFactory);
explicitFactoryUsed = true;
}
if (StringUtils.hasText(this.sqlSessionTemplateBeanName)) {
if (explicitFactoryUsed) {
LOGGER.warn(
() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate",
new RuntimeBeanReference(this.sqlSessionTemplateBeanName));
explicitFactoryUsed = true;
} else if (this.sqlSessionTemplate != null) {
if (explicitFactoryUsed) {
LOGGER.warn(
() -> "Cannot use both: sqlSessionTemplate and sqlSessionFactory together. sqlSessionFactory is ignored.");
}
definition.getPropertyValues().add("sqlSessionTemplate", this.sqlSessionTemplate);
explicitFactoryUsed = true;
}
if (!explicitFactoryUsed) {
LOGGER.debug(() -> "Enabling autowire by type for MapperFactoryBean with name '" + holder.getBeanName() + "'.");
//将MapperFactoryBean的注入模型设置为By-Type。也就是说,MapperFactoryBean中的setXxx中的属性会从容器中来进行查找
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
}
definition.setLazyInit(lazyInitialization);
}
}
public class MapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {}
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
@Override
public Class<T> getObjectType() {
return this.mapperInterface;
}
注意:这里的getObject调用时机是,在创建的对象依赖了Mapper对象就会去创建该Mapper对象,此时通过MapperFactoryBean去获取
这一步是程序员自己定义一个SqlSessionFactory,例如:
@CondorHeroMapperScan("com.athome.tulin.springmybatis.mapper")
@ComponentScan("com.athome.tulin.springmybatis")
public class AppConfig {
@Bean
public SqlSessionFactory sqlSessionFactory() throws IOException {
System.out.println("4.依赖注入MemberMapper需要先创建对象………AppConfig…………SqlSessionFactory………");
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
}
这里定义的SqlSessionFactory 会赋值于2.10的sqlSessionTemplate
至此:业务类中的引入Mapper对象就复制成功。
@Autowired
private OrderMapper orderMapper;
即:这时候的orderMapper就 是赋值了代理对象的对象是有值 的。