持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
第三方框架整合Spring之FactoryBean(一)
前言
首先介绍一下FactoryBean, FactoryBean是Spring提供的定制实例化Bean的一个接口, Spring IOC容器初始化依赖注入过程中会通过FactoryBean的getObject()方法的到一个自定义的bean对象
那这个接口有什么用, 怎么用呢?
用过Mybaits的小伙伴们肯定都对Mybaits Mapper产生过疑惑, 这个Mapper是一个接口, 为什么可以直接使用Spring的@Autowired注解进行属性注入, 怎么实例化的, 中间到底发生了什么?
我们使用的时候在启动类上加了@MapperScan注解, 那@MapperScan注解到底干了啥事呢?
我们来看一下, 里面似乎只是引入了一个MapperScannerRegistrar,
下面我们来分析一下MapperScannerRegistrar到底干了什么, 我们截取关键部分代码
这里粗略的解读一下registerBeanDefinitions方法做了哪些事
- 定义为一个
MapperFactoryBean的FactoryBean - 实现
ImportBeanDefinitionRegistrar接口 - 调用Spring的包扫描, 得到相关的
BeanDefinitionHolder - 通过BeanDefinitionHolder设置Mapper的
BeanDefinition(Bean的定义信息)
ps: MapperFactoryBean的getObject方法通过动态代理的方式生成了一个代理类(这个不是本文重点, 本文主要将如何与Spring进行整合)
看起来与Spring进行整合的关键步骤已经很清晰, 接下来我们按照以上步骤来实现一个与Spring进行整合的demo
代码
- 定义一个MyMapperFactoryBean类实现FactoryBean接口, getObject()方法使用JDK动态代理生成一个对象, 可以看出该对象打印了下请求参数
public class MyMapperFactoryBean<T> implements FactoryBean {
private Class<T> interfaceType;
public MyMapperFactoryBean(Class<T> interfaceType) {
this.interfaceType = interfaceType;
}
@Override
public Object getObject() {
// 这里使用JDK动态代理生成一个代理类, 打印一下方法调用参数
return Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{interfaceType}, (proxy, method, args) -> {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
Object result = JSON.toJSONString(args);
System.out.println("方法[" + method.getName() + "]被调用, 参数" + result);
return args;
});
}
@Override
public Class<?> getObjectType() {
return interfaceType;
}
}
- 定义一个MyMapperScannerRegistrar类实现ImportBeanDefinitionRegistrar接口
public class MyMapperScannerRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
doScan(registry, importingClassMetadata);
}
/**
* 扫描获取需要整合的类
*/
private void doScan(BeanDefinitionRegistry registry, AnnotationMetadata importingClassMetadata) {
AnnotationAttributes mapperScanAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
if (mapperScanAttrs != null) {
ClassPathMapperScan scanner = new ClassPathMapperScan(registry);
scanner.doScan(mapperScanAttrs.getStringArray("value"));
}
}
/**
* ClassPathMapperScanner 直接从Mybatis中将关键代码复制过来
* 注意这里将源码中的许多代码删掉了
*/
public class ClassPathMapperScan extends ClassPathBeanDefinitionScanner {
public ClassPathMapperScan(BeanDefinitionRegistry registry) {
super(registry, false);
}
@Override
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
// 调用父类的doScan方法获取BeanDefinitionHolder
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);
if (!beanDefinitions.isEmpty()) {
// 填充Bean定义信息
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}
private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
String beanClassName = definition.getBeanClassName();
definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
definition.setBeanClass(MyMapperFactoryBean.class);
definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
}
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}
@Override
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) {
if (super.checkCandidate(beanName, beanDefinition)) {
return true;
} else {
return false;
}
}
}
}
- 定义一个MapperScan注解
@Retention(RetentionPolicy.RUNTIME)
@Import(MyMapperScannerRegistrar.class)
public @interface MapperScan {
String[] value() default {};
}
- 定义几个Mapper
public interface BaseMapper {
}
public interface TestMapper01 extends BaseMapper{
Object test01(String content);
}
public interface TestMapper02 extends BaseMapper{
Object test02(String content);
Object test03(String content);
}
测试
测试自定义mapper注入, 如图, 可以看到我们自定义的Mapper成功的注入到Spring容器中
总结
通过查看MapperScannerRegistrar源码, 我们get到一个新技能(与Spring整合),
后续我会通过几个与Spring整合的实用的小工具来加深这方便的理解和使用!!!