I am currently making a Kotlin client generator according to the swagger specification. Naturally, the question arose how to write a library for Spring.
Why should the library depend on Spring?
In practice, I have all applications on Spring Boot. Therefore, not only from Spring, but also from Spring Boot. If there is a case that something else is needed, then you can use another generator.
Which versions should I choose?
You need to choose low enough versions so that the application updates them up, and not the library updates the application. Naturally, the major versions must be the same, otherwise there is no compatibility.
How to log?
Starting from Java version 9, there is such a logging class: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/System.Logger.html
How do I create a library correctly and how does it differ from an application?
- Dependencies as in the application
- Build in jar
- Publishing to the maven repository
- There is no @Application class
- You can simply create beans, or you can use conditions
Auto-configuring bins
To make it all work, you need to create a class(s) with the @Configuration annotation and write its full name in resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
: then Spring Boot will find it and use it to auto-configure our library.
The application can disable the autoconfiguration class through the annotation @EnableAutoConfiguration(exclude=)
or through the property spring.autoconfigure.exclude
Next: what conditions can be used. Conditions can be applied to individual @Bean methods within a class, or to the entire class.
A component is created if there is another component
For example, if we find the drivers of a database, we configure the client library for it.
Creating a component if OtherService already exists (for example, in the project):
@Component
@ConditionalOnBean(OtherService::class)
@RegisterReflectionForBinding(SomeRequest::class, SomeResponse::class)
SomeRequest and SomeResponse are also registered for correct serialization (this is for the case of native assemblies, this is not necessary without native assemblies, but it is better if the library supports native assemblies).
The component is created if specified in the configuration
For example, if it is not said not to create. This is our most common case: by default, we create it, but we give you the opportunity to disable it if, for example, only model classes are needed from us (or some more complicated configuration).
There are other options for conditions (https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/condition/package-summary.html). The most interesting one is ConditionalOnProperty, i.e. it is enabled via configuration.
The component is created if there is no such bean yet
This is convenient for cases of some basic beans. For example, we can create a WebClient if it is not created in the application. Abstract `@ConditionalOnMissingBean'.
The component is created if an annotation is used
An example of an annotation:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyApiClientConfiguration.class)
public @interface EnableMyApiClient {}
In fact, this is a link to our configuration class, just through an annotation.
I don’t like this method: if the library is included in dependencies, then let it be configured, and if it is not necessary in rare cases, then it is disabled via @EnableAutoConfiguration(exclude=)
.