第三方框架整合Spring之FactoryBean(一)

87 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

第三方框架整合Spring之FactoryBean(一)

前言

首先介绍一下FactoryBean, FactoryBean是Spring提供的定制实例化Bean的一个接口, Spring IOC容器初始化依赖注入过程中会通过FactoryBean的getObject()方法的到一个自定义的bean对象

那这个接口有什么用, 怎么用呢?

用过Mybaits的小伙伴们肯定都对Mybaits Mapper产生过疑惑, 这个Mapper是一个接口, 为什么可以直接使用Spring的@Autowired注解进行属性注入, 怎么实例化的, 中间到底发生了什么?

我们使用的时候在启动类上加了@MapperScan注解, 那@MapperScan注解到底干了啥事呢? 我们来看一下, 里面似乎只是引入了一个MapperScannerRegistrar, 下面我们来分析一下MapperScannerRegistrar到底干了什么, 我们截取关键部分代码

微信图片_20220530093158.png

这里粗略的解读一下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容器中

微信图片_20220530093544.png

总结

通过查看MapperScannerRegistrar源码, 我们get到一个新技能(与Spring整合),
后续我会通过几个与Spring整合的实用的小工具来加深这方便的理解和使用!!!