apisdk-starter Spring拓展点实现部分
- 使用springboot的EnableAutoConfiguration和Import触发Spring扫描组件扫描原始类,得到所有BeanDefinition
- 拓展FactoryBean,构造函数的参数为原始类的Class
- 遍历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整合。