java - Spring 中的改造自动配置

标签 java spring-boot retrofit2

我目前正在为 Retrofit 2 编写 Spring Boot 自动配置。我想做的是编写某种接口(interface)构建器,它能够实例化一个带有一些 Autowiring 注释的接口(interface),就像 Spring Data 对存储库所做的那样。由于我找不到任何关于如何做到这一点的资源(或者是否可以使用 Spring 来完成),我想询问您对此的想法。下面是我想要实例化的接口(interface)。
我对 @Repository 的替换是 @Retrofit 其余的只是您为任何 Retrofit 存储库编写的“普通”代码。

我想要 Autowiring 的接口(interface)类型:

@Retrofit
public interface Api {

    @GET("usernames")
    String[] getUsernames();
}

Autowiring 的示例:

@SpringBootApplication
public class TestApplication {

    @Autowired
    private Api api;

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

    @Bean
    CommandLineRunner runner() {
        return args -> {
            System.out.println(api.getUsernames());
        };
    }
}

最佳答案

正如我所说,我找到了解决问题的方法。

首先,我们需要一个由 Spring Boot 加载的自动配置类 - 如所述 here - 添加文件 META-INF/spring.factories ,内容如下所示。此自动配置加载一个注册器,该注册器本身通过组件提供程序搜索带有 @Retrofit 注释的类。最后,注册器为每个可以找到的实例创建 RetrofitFactoryBean 实例,同时该工厂 bean 创建 Retrofit 代理本身。

自动配置

@Configuration
@Import(RetrofitRegistrar.class)
public class RetrofitAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public Retrofit retrofit() {
        return new Retrofit.Builder().build();
    }
}

META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
spring.retrofit.RetrofitAutoConfiguration

导入的注册商

public class RetrofitRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

    @Setter
    private BeanFactory beanFactory;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
            BeanDefinitionRegistry registry) {
        List<String> basePackages = AutoConfigurationPackages.get(this.beanFactory);
        RetrofitComponentProvider provider = new RetrofitComponentProvider(registry);
        basePackages.stream()
                .map(provider::findCandidateComponents)
                .flatMap(Set::stream)
                .forEach(comp -> register(comp, registry));
    }

    private void register(BeanDefinition component, BeanDefinitionRegistry registry) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.
                rootBeanDefinition(RetrofitFactoryBean.class);
        builder.addConstructorArgValue(component.getBeanClassName());
        registry.registerBeanDefinition(
                component.getBeanClassName().toLowerCase(), builder.getBeanDefinition());
    }
}

组件提供商

class RetrofitComponentProvider extends ClassPathScanningCandidateComponentProvider {

    @Getter
    private BeanDefinitionRegistry registry;

    public RetrofitComponentProvider(BeanDefinitionRegistry registry) {
        super(false);

        Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
        this.registry = registry;

        addIncludeFilter(new AnnotationTypeFilter(Retrofit.class, true, true));
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return true;
    }
}

工厂 bean

@Component
@RequiredArgsConstructor
public class RetrofitFactoryBean extends AbstractFactoryBean<Object> {

    @Getter
    private final Class<?> objectType;
    private final retrofit2.Retrofit retrofit;

    @Override
    protected Object createInstance() throws Exception {
        return retrofit.create(objectType);
    }
}

@Getter@Setter@RequiredArgsConstructor 注释由 ProjectLombok 提供。

关于java - Spring 中的改造自动配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45774870/

相关文章:

mysql - 使用 SpringBootData、MySql 5.7 和查询空间

android - Android单元测试改造失败

android - 如何创建用于模拟改造的 ResponseBody 实例

java - Retrofit2 : Error Handling

java - 性能问题 System.out.println ("log information ")或使用 log4j 记录器文件?

java - 我的加密程序需要帮助

spring - Thymeleaf 获取当前登录的用户名作为字符串

java - 在运行时,有没有办法检查哪个 API/ Controller 方法导致 Spring Boot 应用程序中的当前执行点?

java - android从2个不同的文件读取

java - 如何在 Android Q (API 29) 上将文件保存到公共(public)(外部)存储?