apisdk-starter自动装配组件之Spring拓展点

apisdk-starter Spring拓展点实现部分

  1. 使用springboot的EnableAutoConfiguration和Import触发Spring扫描组件扫描原始类,得到所有BeanDefinition
  2. 拓展FactoryBean,构造函数的参数为原始类的Class
  3. 遍历BeanDefinition,设置beanClass为拓展的FactoryBean的Class,构造参数是原始类的Class,这样FactoryBean会把原始类对象的生命周期交给spring管理,开发者可以通过@Resource完成依赖注入

自定义自动装配

注解

定义自动装配的注解,使用@Import指定装配的目标类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import({AccessorScannerRegistrar.class, AccessorConfig.class})
@EnableAutoConfiguration
public @interface OpenapiScan {
    // 扫描包路径
    String[] basePackages() default {};
}

AccessorScannerRegistrar触发Spring扫描

public class AccessorScannerRegistrar implements ImportBeanDefinitionRegistrar {
    private static final String BASE_PACKAGES = "basePackages";
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        List<String> basePackages = new ArrayList<>();
        // 获取自定义注解的所有属性
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(OpenapiScan.class.getName()));
        for (String pkg : attributes.getStringArray(BASE_PACKAGES)) {
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }
        if (!basePackages.isEmpty()) {
            // 调用 Spring api 触发指定路径的扫描
            ClassPathAccessorScanner classPathAccessorScanner = new ClassPathAccessorScanner(registry);
            classPathAccessorScanner.registerFilters();
            classPathAccessorScanner.doScan(StringUtils.toStringArray(basePackages));
        }
    }
}

自定义Spring路径扫描

ClassPathAccessorScanner实现了Spring的ClassPathBeanDefinitionScanner,借助Spring扫描所有的BeanDefinition,主要代码如下:

public class ClassPathAccessorScanner extends ClassPathBeanDefinitionScanner {
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        GenericBeanDefinition definition;
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            definition = (GenericBeanDefinition) beanDefinitionHolder.getBeanDefinition();
            // bean的名称
            String beanClassName = definition.getBeanClassName();
            // 设置 AccessorProxyBean,实现了 FactoryBean
            definition.setBeanClass(AccessorProxyBean.class);
            // 原始接口作为构造器的参数传入
            definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);
        }
        return beanDefinitionHolders;
    }
}

FactoryBean

FactoryBean是Spring开放给开发者使用的Api,使用它可以把对象交给Spring容器管理,它也是很多开源框架与Spring整合的入口,也可以用它完成配置属性的注入。

apisdk应用

AccessorProxyBean是所有开放接口实例化的入口,它实现了FactoryBean,触发了javassist、jdk动态代理完成各自的包装。

public class AccessorProxyBean<T> implements FactoryBean<T>, ApplicationContextAware, InitializingBean,
        ApplicationListener<ApplicationEvent> {
    /**
     * 原始 bean class
     */
    private Class<T> sourceClass;
    /**
     * 代理 bean
     */
    private T proxyBean;
    private AccessorFactory accessorFactory;
    
    public AccessorProxyBean(Class<T> sourceClass) {
        this.sourceClass = sourceClass;
    }
    @Override
    public T getObject() throws Exception {
        if (Objects.isNull(accessorFactory)) {
            afterPropertiesSet();
        }
        if (Objects.isNull(proxyBean)) {
            // 初始化 open api
            proxyBean = accessorFactory.create(sourceClass);
        }
        return proxyBean;
    }
}

property-placeholder应用

有时候开发者需要内置一些环境变量,并且在Bean初始化前完成,这时可以利用FactoryBean,配合property-placeholder完成环境变量的配置。

其他开源框架

Mybatis也是通过FactoryBean和Spring整合。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值