Reputation: 48
I'm trying to create system like @Repository.
I have lots of interfaces like:
@Client(uri = "http://example.com", username = "httpBasicUsername", password = "httpBasicPassword")
public interface RequestRepository {
@Request(method = Method.POST, uri = "/mono")
Mono<Response> ex1(Object body);
@Request(method = Method.POST, uri = "/flux")
Flux<Response> ex2(Object body);
}
Right now, I'm creating bean with using this function:
@Bean
public RequestRepository requestRepository(WebClient.Builder builder) {
return (RequestRepository) Proxy.newProxyInstance(
RequestRepository.class.getClassLoader(),
new Class[]{RequestRepository.class},
new MyDynamicInvocationHandler(builder)
);
}
But I have lots of these interfaces. For every new interface I need to create another bean function. But I don't want to do that.
Is there a way to say spring (spring boot) if there is @Client annotation then create bean like this etc?
Upvotes: 1
Views: 3811
Reputation: 48
I've solved with creating custom interface scanner.
For more details: https://stackoverflow.com/a/43651431/6841566
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({InterfaceScanner.class})
public @interface InterfaceScan {
String[] value() default {};
}
public class InterfaceScanner implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Map<String, Object> annotationAttributes = metadata.getAnnotationAttributes(InterfaceScan.class.getCanonicalName());
if (annotationAttributes != null) {
String[] basePackages = (String[]) annotationAttributes.get("value");
if (basePackages.length == 0)
basePackages = new String[]{((StandardAnnotationMetadata) metadata)
.getIntrospectedClass().getPackage().getName()};
ClassPathScanningCandidateComponentProvider provider =
new ClassPathScanningCandidateComponentProvider(false, environment) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata meta = beanDefinition.getMetadata();
return meta.isIndependent() && meta.isInterface();
}
};
provider.addIncludeFilter(new AnnotationTypeFilter(Client.class));
for (String basePackage : basePackages)
for (BeanDefinition beanDefinition : provider.findCandidateComponents(basePackage))
registry.registerBeanDefinition(
generateName(beanDefinition.getBeanClassName()),
getProxyBeanDefinition(beanDefinition.getBeanClassName()));
}
}
}
@InterfaceScan
@SpringBootApplication
public class ExampleApplication {
...
}
Upvotes: 1