This post has been featured on http://www.baeldung.com/java-weekly-184.
1. IMPLEMENTING A CUSTOM SPRING BOOT STARTER FOR CXF AND SWAGGER
Consider this scenario, the development team has increased over the last few years, software releases and deployment takes more time, that quick fix or feature couldn’t be delivered this Sprint because the deliverable now includes many changes that haven’t been signed off by QA and it might take another month to do so.
This seems like a good opportunity to break up the big Java monolithic application into multiple services or for that legacy set of applications in which business logic is duplicated to be refactored or rewritten, each by a small team benefiting from more frequent releases, easier to understand a small piece of functionality, having a low impact on other services, promoting ownership and accountability, etc..
Assuming for instance, it has been decided to implement the APIs using Spring Boot, Apache CXF and Swagger along with logging, metrics, security, etc. and maybe packaging the service in a Docker image, how do we setup this up for a dozen or more services? Do we create a baseline project to be copied and pasted for each service? Do we create a custom Maven archetype? What are other options?
This post covers how to create a custom Spring Boot starter for Apache CXF 3.1.x and Swagger 2 as the starting point to create services with a common set of dependencies and functionality also providing Spring beans auto-configuration to reduce explicit beans definition.
- 1. IMPLEMENTING A CUSTOM SPRING BOOT STARTER FOR CXF AND SWAGGER
- 2. REQUIREMENTS
- 3. CREATE asimio-api-springboot-starter, A SPRING BOOT STARTER FOR CXF AND SWAGGER
- 4. PACKAGE asimio-api-springboot-starter modules
- 5. CREATE asimio-api-starter-demo DEMO SERVICE
- 6. RUN asimio-api-starter-demo DEMO SERVICE
- 7. SOURCE CODE
- 8. REFERENCES
We are going to create two projects, asimio-api-springboot-starter, the custom Spring Boot starter which will auto-configure CXF and Swagger-related beans and asimio-api-starter-demo, a demo using asimio-api-springboot-starter.
- Java 7 or 8.
- Maven 3.3.x
- Familiarity with Spring Framework.
3. CREATE asimio-api-springboot-starter, A SPRING BOOT STARTER FOR CXF AND SWAGGER
asimio-api-springboot-starter will be setup as a multi-module Maven project where the modules artifactIds follow Spring’s suggested naming convention:
- asimio-api-springboot-starter-parent: Manages dependencies version.
- asimio-cxf-swagger-springboot-autoconfigure: Manages the dependencies this starter provides and defines, auto-configures beans.
- asimio-cxf-swagger-springboot-starter: Brings in asimio-cxf-swagger-springboot-autoconfigure, Spring Boot(web, actuator, log4j2), CXF and Swagger dependencies.
3.1 CREATE asimio-api-springboot-starter-parent PARENT POM MAVEN MODULE
A regular parent
pom.xml defining its modules and dependencies management to ease artifacts upgrade.
3.2 CREATE asimio-cxf-swagger-springboot-autoconfigure MAVEN MODULE
This Maven child module is the main artifact of the asimio-api-springboot-starter Spring Boot starter, where all the beans are defined and auto-configured. Here is a snippet of its
AsimioApiAutoConfiguration.java, the meat and potatoes of this module, where the beans are defined and auto-configured depending on some auto-configuration criteria, more on this later.
As explained in Microservices using Spring Boot, Jersey, Swagger and Docker, @Configuration annotation marks this class will provide beans managed by the Spring container, swagger2Feature and jsonProvider in this case.
@EnableConfigurationProperties enables support for @ConfigurationProperties-annotated beans, AsimioApiProperties.java in this case, allowing an instance of AsimioApiProperties to be injected in other beans.
@ConditionalOnClass, @ConditionalOnMissingBean and other @Conditional annotations are used to constrain when the auto-configuration should be applied. In the case of AsimioApiAutoConfiguration.java, swagger2Feature and jsonProvider beans will be auto-configured if Swagger2Feature.class and JacksonJsonProvider.class are found in the classpath (remember the artifacts where these classes reside were included as optional) and the consumer of this starter didn’t explicitly define such beans.
Frequently used conditional annotations:
|Condition||Matches when the annotation args|
|ConditionalOnClass||Classes are in the classpath.|
|ConditionalOnMissingClass||Classes are not in the classpath.|
|ConditionalOnBean||Bean classes and/or names are included contained in the bean factory.|
|ConditionalOnMissingBean||Bean classes and/or names are not included contained in the bean factory.|
|ConditionalOnProperty||Properties have a specific value or the property is not in the environment.|
|ConditionalOnExpression||SpEL evaluates to true.|
AsimioApiProperties.java, which allows setting custom properties in files like
application.properties, etc.. A usage example is included in asimio-api-starter-demo:
The last part of this Maven module is to enable auto-configuration of the Spring context, this is done in
3.3 CREATE asimio-cxf-swagger-springboot-starter MAVEN MODULE
This is an extract of the third Maven child module’s
It’s including the dependencies this starter provides, artifacts that were included in asimio-cxf-swagger-springboot-autoconfigure but now they are not optional, meaning whoever uses this starter will have these artifacts in the classpath and will meet one of the conditions for the beans to be auto-configured.
We can also optionally define which dependencies this starter provides via
4. PACKAGE asimio-api-springboot-starter modules
For asimio-api-starter-demo to be able to use this custom Spring Boot starter we first need to make it available in the local
.m2 folder or have a CI server to build it and deploy it to a Maven repository manager:
5. CREATE asimio-api-starter-demo DEMO SERVICE
A demo application using asimio-cxf-swagger-springboot-starter custom Spring Boot starter gets simpler than the one described in Implementing APIs using Spring Boot, Apache CXF and Swagger:
The only important dependency that needs to be included, it would pull all the dependencies provided by asimio-cxf-swagger-springboot-starter.
Demo starter main class
The resource interface with JAX-RS and Swagger annotations
The resource implementation
HelloResourceImpl.java classes are being scanned at application startup via @SpringBootApplication annotation.
A demo starter properties file,
What’s interesting here is the asimioApi-related properties, those are the properties that get converted into a AsimioApiProperties bean and injected in a AsimioApiAutoConfiguration bean to auto-configure CXF and Swagger.
6. RUN asimio-api-starter-demo DEMO SERVICE
This application can be run from your IDE as a regular Java application or from command line:
Sending a request to the
|Hello API version in URL (GET method)||/api/v1/hello/<name>|
|Hello API version in Access header (GET method)||/api/hello/<name>|
|Swagger JSON doc||/api/swagger.json|
And that’s it for this Spring Boot custom starter for CXF and Swagger, a similar starter could be enhanced with logging, metrics, profiling, etc., anything that services might have in common.
Earlier this month this blog covered Implementing APIs using Spring Boot, Apache CXF and Swagger and this post details the benefits of using a custom Spring Boot starter to provide a common set of dependencies and functionality, beans auto-configuration and more. Definitely an improvement, but we would still need to create a new Spring Boot project and manually include the starter dependency and add configuration properties.
Wouldn’t it be better to also provide a Maven archetype that would take care of the service generation? Or better yet, wouldn’t it be really productive to not only generate the new service including the custom Spring Boot starter but also add it to a Git repo, create a CI pipeline, etc. through a shell command or clicking a button? Stay tuned, go ahead and sign up to the newsletter to receive updates from this blog when content like this is available.
Thanks for reading and as always, feedback is appreciated.
7. SOURCE CODE
Accompanying source code for this blog post can be found at: