Spring源码学习(二)mybatis和spring整合

spring和mybatis整合

问题:
1.mybatis为什么未实例化接口但是可以调用接口的方法?
2.mybatis如何实现把bean交给spring管理的?

代码

常规整合框架编码

/**
 * dao
 */
public interface IndexDao {
	@Select({"select * from dao"})
	public List<Map<String,Object>> list();
}

public interface IndexDao1 {
	@Select("select * from dao1")
	public List<Map<String,Object>> list();
}

public interface IndexDao2 {
	@Select("select * from dao2")
	public List<Map<String,Object>> list();
}

/**
 * service
 */
@Component
public class IndexService {

	//从spring容器当中拿出来自动注入
	//对象  不是接口
	@Autowired
	IndexDao indexDao;

	@Autowired
	IndexDao1 indexDao1;

	@Autowired
	IndexDao2 indexDaon2;

	public List<Map<String,Object>> list(){
		//查询数据库
		indexDao.list();
		indexDao1.list();
		indexDaon2.list();
		return null;
	};
}

自定义编码

​ 模拟mybatis每个接口生成代理对象

public class CustomSqlSession {
	/**
	 * 模拟mybatis产生代理对象
	 * 符合需求的对象
	 * 1、代理
	 * 2、这个对象能够具备的功能 查询数据库 --执行对应sql
	 * @param clazz
	 * @return
	 */
	public Object getMapper(Class clazz){
		//他的底层源码会去重写toString 没有实现
		Object proxy = Proxy.newProxyInstance(CustomSqlSession.class.getClassLoader(), 
                                              new Class[]{clazz}, new CustomInvocationHandler());
		return  proxy;
	}

	class CustomInvocationHandler implements InvocationHandler {
		//所有代理对象的功能  查询数据 执行对应方法的sql语句
		//1、得到sql语句
		//2、conn ---执行sql语句
		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			//判断有没有加这个注解
			if (method.isAnnotationPresent(Select.class)) {
				//得到这个注解对象
				Select select = method.getAnnotation(Select.class);
				//调用value方法得到注解里面的value的值--sql
				String sql = select.value()[0];
				System.out.println("jdbc conn ");
				System.out.println("execute query :" + sql);
			}
			if (method.getName().equals("toString")){
				return  proxy.getClass().getName();
			}
			return null;
		}
	}
}

​ 定义一个FactoryBean来生产CustomSqlSession代理对象

public class CustomFactoryBean implements FactoryBean{

	Class mapperInterface;

	public CustomFactoryBean(){
		System.out.println("create CustomFactoryBean.");
	}

	public CustomFactoryBean(Class mapperInterface){
		this.mapperInterface=mapperInterface;
	}

	@Override
	public Object getObject() throws Exception {
		CustomSqlSession  customSqlSession = new CustomSqlSession();
		//mybatis返回出来的代理对象
		Object mapper = customSqlSession.getMapper(mapperInterface);
		//FactoryBean  return mapper对象会存到spring容器当中
		return mapper;
	}

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

	public void setMapperInterface(Class mapperInterface) {
		this.mapperInterface = mapperInterface;
	}
}

​ 需要把所有的接口生成的bean注入到spring容器中,所以需要生成对于的beanDefinition对象,然后把beanDefinition对象放入到map(缓存)中(spring中 bean的实例化就是根据beanDefinition对象),所以需要定义一个Registrar,把beanDefinition放入map中。

public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// 源码为 spring scan 扫描出所有符合目录下条件的类,简化为自定义集合
		List<Class> list = new ArrayList<>();
		list.add(IndexDao.class);
		list.add(IndexDao1.class);
		list.add(IndexDao2.class);

		// 生成dao对于的beanDefinition 放入到map中,后需要bean的实例化就是通过这个map(缓存)
		for (Class aClass : list) {
			BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomFactoryBean.class);
			AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
			// 属性赋值
			beanDefinition.getPropertyValues().add("mapperInterface",aClass);
			// beanName
			String beanName=(aClass.getSimpleName().substring(0,1).toLowerCase())+aClass.getSimpleName().substring(1);
			// 注入到spring容器中
			registry.registerBeanDefinition(beanName,beanDefinition);
		}
	}
}

​ CustomImportBeanDefinitionRegistrar本身也是个bean需要被管理,需要注入到容器。

@Configuration
@ComponentScan("com.shadow")
@Import(CustomImportBeanDefinitionRegistrar.class)
public class AppConfig {

}

测试

public class TestIndex {
	public static void main(String[] args) {
		//显示的去得到applicationContext对象
		//书写格式
		AnnotationConfigApplicationContext applicationContext
				= new AnnotationConfigApplicationContext(AppConfig.class);
		IndexService bean = applicationContext.getBean(IndexService.class);
		bean.list();
    }
}
/**
 *create CustomFactoryBean.
 *create CustomFactoryBean.
 *create CustomFactoryBean.
 *jdbc conn 
 *execute query :select * from dao
 *jdbc conn 
 *execute query :select * from dao1
 *jdbc conn 
 *execute query :select * from dao2
 */

@Import注解

新建一个ImportConfig,在类上面加上@Configuration,加上@Configuration是为了能让Spring 扫描到这个类,并且直接通过@Import引入TestA类

import bean注入spring的三种方式

// 直接导入类
@Import({TestA.class})
@Configuration
public class ImportConfig {
}

// 通过ImportSelector 方式导入的类
public class SelfImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.test.importdemo.TestC"};
    }
}

@Import({SelfImportSelector.class})
@Configuration
public class ImportConfig {
}

// 通过ImportBeanDefinitionRegistrar 方式导入的类
public class SelfImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition root = new RootBeanDefinition(TestD.class);
        registry.registerBeanDefinition("testD", root);
    }
}
@Import({SelfImportBeanDefinitionRegistrar.class})
@Configuration
public class ImportConfig {
}

总结:

1.一个dao接口会通过动态代理来生成动态代理对象(sqlsession)

2.需要定义一个factoryBean来管理动态代理对象 sqlsessionFactory

3.需要把sqlsessionFactory,放入到bean的初始化的定义对象,即生成对应的BeanDefinition

4.ImportBeanDefinitionRegistrar来把BeanDefinition放入缓存中,用来后续的初始化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值