# 我们的Mapper 是一个接口 此时 在我们Service 注入了这个接口; 并且进行sql执行; 在Mybatis中 它会使用代理 进行接口实现; 并且最终把该对象的实现类 注入到这里来; 我们现在这里并没做这个类的实现; 现在执行肯定是报错的; 我们该如何把这个接口变成Bean呢? 答:使用FactoryBean 进行对象的创建. 我们知道 Spring内部使用了Cglib代理 所以不能代理接口;
========================================================================================
/**
- auth :huf
*/
@Component
public class HufFatoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
Object object = Proxy.newProxyInstance(HufFatoryBean.class.getClassLoader(), new Class[]{StudentMapper.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName());
return null;
}
});
return object;
}
@Override
public Class<?> getObjectType() {
return StudentMapper.class;
}
}
这样我们就可以通过FactoryBean 再利用 JDK 代理; 把接口变成对象 并且注入到容器中;
为什么是null 因为我Factory返回出来就是Null;
我们继续扩展; 假设我们有多个Mapper 一个StudentMapper 一个 TeacherMapper … 多个Mapper.那怎么办?
===================================================================================================================================
答: 我们把FactoryBean 变成 BeanDefinition 就可以了; 以下是演进展示;
我们先把HufFatoryBean 写活; 通过构造方法传入即将要代理的类Class. 这样 我们就可以只用一个FactoryBean 进行全部Mapper的代理.
/**
- auth :huf
*/
@Component
public class HufFatoryBean implements FactoryBean {
private Class clazz;
public HufFatoryBean(Class clazz) {
this.clazz = clazz;
}
@Override
public Object getObject() throws Exception {
Object object = Proxy.newProxyInstance(HufFatoryBean.class.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName());
return null;
}
});
return object;
}
@Override
public Class<?> getObjectType() {
return clazz;
}
}
然后 我们注册BeanDefinition
=================================================================
/**
-
Application启动类;
-
auth : huf
*/
public class ApplictionMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext ap = new AnnotationConfigApplicationContext();
ap.register(AppConfig.class);
创建一个beanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
传入我们的FactoryBean
beanDefinition.setBeanClass(HufFatoryBean.class);
通过构造方法 把Student传入
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(StudentMapper.class);
注册BeanDefinition 把创建好的 BeanDefinition 传入进去;
ap.registerBeanDefinition(“studentMapper”,beanDefinition);
-------------------------以下也是一样
AbstractBeanDefinition beanDefinition1 = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition1.setBeanClass(HufFatoryBean.class);
beanDefinition1.getConstructorArgumentValues().addGenericArgumentValue(TeacherMapper.class);
ap.registerBeanDefinition(“teacherMapper”,beanDefinition1);
启动
ap.refresh();
StudentService studentService = (StudentService) ap.getBean(“studentService”);
studentService.test();
}
}
这里 同学们应该都理解了吧? 到这里 其实思路就已经出来了; 我们不可能以这种方式去加载BeanDefinition; 以下 我介绍2种加载BeanDefinition的方式; 其实以前说过 再之前的篇章里边; 这里我写一次;
第二种BeanDefinitionRegistryPostProcessor
==================================================================================================
/**
- auth : huf
*/
public class HufBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
创建一个beanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
传入我们的FactoryBean
beanDefinition.setBeanClass(HufFatoryBean.class);
通过构造方法 把Student传入
beanDefinition.getConstructorArgumentValues().addGenericArgumentValu
e(StudentMapper.class);
注册BeanDefinition 把创建好的 BeanDefinition 传入进去;
ap.registerBeanDefinition(“studentMapper”,beanDefinition);
-------------------------以下也是一样
AbstractBeanDefinition beanDefinition1 = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition1.setBeanClass(HufFatoryBean.class);
beanDefinition1.getConstructorArgumentValues().addGenericArgumentValue(TeacherMapper.class);
ap.registerBeanDefinition(“teacherMapper”,beanDefinition1);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
这样是否是合理很多? 我们场景再继续往下深入一下; 如果我们之后想加一个Mapper 我们还得再这里写多一个BeanDefinition 是不是又突然觉得不太合理了?
===============================================================================================================================================
答: 我们可以利用 Scan 扫描的方式 进行Mapper扫描. 凡是再某个包下面的所有接口 我都认为它是Mapper 是否OK? 我们定义一个注解;
现在我们注入了扫描 我们会发现 之前用的BeanDefinitionRegistryPostProcessor 无法拿到我们的配置;我们就引出了另外一个
第三种ImportBeanDefinitionRegistrar
============================================================================================
这样 我们在配置文件中 可以通过@Inport(HufImportBeanDefinitionRegistrar.class) Spring捕捉到配置文件中的Import后 就可以调度这个方法 把BeanDefinition 加入容器中去; 这样我们继续改造我们的HufImportBeanDefinitionRegistrar 让他通过扫描的方式得到所有MapperClass 然后通过工厂的方式 生产BeanDefinition 注册到容器中; 以下是改造后的代码:
/**
-
auth : huf
*/
public class HufImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(HufMapperScan.class.getName());
String path = MapUtils.getString(annotationAttributes,“value”);
//Spring 原生扫描的方式 因为我们使用的是接口 所以我们必须继承这个类 并且进行改造
// ClassPathBeanDefinitionScanner scan = new ClassPathBeanDefinitionScanner(registry);
// scan.scan(path);
创建自己的MapperBeanDefinitionScanner
HufMapperBeanDefinitionScanner scanner = new HufMapperBeanDefinitionScanner(registry);
该步骤是为了在扫描其中 如果有@Component 才会加入到容器 默认false 我改成true 就是 不管有没有 都是Bean
scanner.addIncludeFilter(new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return true;
}
});
scanner.scan(path);
}
}
HufMapperBeanDefinitionScanner
==========================================================================================
中间的doScan方法重写 是为了什么? 我们通过path路径扫描到的 是Mapper本身 并不是Factory 现在我们变成Factory 所以要从写Scan 方法 这时候 我们得到的BeanDefinition 就是我们想要的了; 这样我们的扫描组件就写完了