Skip to content

spring boot starters

Eric F. Alsheimer edited this page Jan 19, 2018 · 7 revisions

Spring Boot Starters

Alternative Baeldung Notes

These notes are converting the Pro Spring version (journal-based) to Lab48-versioned (Swagger-based). They are meant to be followed AFTER being written and will not be followed during.

This wiki will describe how Spring and Spring Boot implements a pattern for reusable components: AutoConfiguration.

Custom Spring Boot Module

A Spring module is a potential dependency. Applications choose which modules they require. Some example modules are web, beans, test, and AOP.

The spring-boot-starter-<module> lets the Spring Boot engine auto-configure the application based on dependencies that the defined starter brings to the application.

In this example, the SwaggerServer app is useful and we want to make it possible to embed a version of it in any Spring Boot application. We want to create a SwaggerServer starter pom.xml file. This will lead to three modules:

  • spring-boot-swagger-server: The original Swagger application.
  • swagger-server-spring-boot-starter: The definition of the swagger-server module. Every time you want to include part of the swagger-server in a new application, you need to use this starter.
  • swagger-server-spring-boot-autoconfigure: This project brings the swagger-server to life because it creates a special auto-configuration to set everything up when another project includes swagger-server-spring-boot-starter.

Create the Swagger Server

Use your command-line tool to spin up a new Swagger Server. Note that the default namespace is io.swagger and that will play an important part of fitting this all together.

mvn spring-boot:run should run the application no problem. Navigate to localhost:8080/system-metadata.json for confirmation.

The swagger-server-spring-boot-starter Project

Now we define a starter that any new project will use. This should be a sidelong sibling to the swagger-server folder.

mkdir swagger-server-spring-boot-starter

Make a pom.xml file in the folder and make it look like so:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>

        <groupId>io.swagger</groupId>
        <artifactId>swagger-server-spring-boot-starter</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>

        <name>swagger-server-spring-boot-starter</name>
        <description> Spring Boot Swagger Server Starter</description>

        <properties>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <java.version>1.8</java.version>
        </properties>

        <dependencies>
                <dependency>              
                        <groupId>io.swagger</groupId>              
                        <artifactId>swagger-server-spring-boot-autoconfigure</artifactId>              
                        <version>0.0.1-SNAPSHOT</version>              
                </dependency>              
        </dependencies>                                                        

        <build>
                <plugins>
                        <plugin>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-maven-plugin</artifactId>
                        </plugin>
                </plugins>
        </build>

</project>

This POM has only one dependency and that hasn't been built yet. Otherwise, this starter is complete. The AutoConfiguration is the most important part.

Note that the name of the project is -spring-boot-starter, and the autoconfigure is -spring-boot-autoconfigure.

The swagger-server-spring-boot-autoconfigure Project

This is a proper project and one that the book creates with initializr. We don't need persistence with the Swagger project, so our initializr will look a little different.

$ mkdir journal-spring-boot-autoconfigure
$ cd journal-spring-boot-autoconfigure
$ spring init -x -d=web,data-rest -g=io.swagger -a=swagger-server-spring-boot-autoconfigure --package-name=io.swagger -name=swagger-server-spring-boot-autoconfigure

In the resulting pom.xml file, we need to add a journal version as well as dependencies for spring-boot-autoconfigure, spring-boot-configuration-processor, and our spring-boot-swagger-server.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>

        <groupId>io.swagger</groupId>
        <artifactId>swagger-server-spring-boot-autoconfigure</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>

        <name>swagger-server-spring-boot-autoconfigure</name>
        <description>Demo project for Spring Boot</description>

        <parent>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>1.3.3.RELEASE</version>
                <relativePath/> <!-- lookup parent from repository -->
        </parent>

        <properties>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <java.version>1.8</java.version>
->              <journal.version>0.0.1-SNAPSHOT</journal.version>              
        </properties>

        <dependencies>
->              <dependency>              
->                      <groupId>org.springframework.boot</groupId>              
->                      <artifactId>spring-boot-autoconfigure</artifactId>              
->              </dependency>              

->              <dependency>              
->                      <groupId>io.swagger</groupId>              
->                      <artifactId>spring-boot-journal</artifactId>              
->                      <version>${journal.version}</version>              
->              </dependency>              

                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-data-jpa</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-data-rest</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-thymeleaf</artifactId>
                </dependency>
                <dependency>                                                        
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-web</artifactId>
                </dependency>
                <dependency>
                        <groupId>com.h2database</groupId>
                        <artifactId>h2</artifactId>
                        <scope>runtime</scope>
                </dependency>
                <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <scope>runtime</scope>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-test</artifactId>
                        <scope>test</scope>
                </dependency>

->             <dependency>              
->                      <groupId>org.springframework.boot</groupId>              
->                      <artifactId>spring-boot-configuration-processor</artifactId>              
->                      <optional>true</optional>              
->              </dependency>              
        </dependencies>

        <build>
                <plugins>
                        <plugin>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-maven-plugin</artifactId>
                        </plugin>
                </plugins>
        </build>

</project>

This next file is the most important, it's the SwaggerServerAutoConfiguration class. Now in the book they extend a RepositoryRestMvcConfiguration, but I think ours looks more like the Baeldung version, so here's a modified copy of that:

@Configuration
@ConditionalOnClass(SwaggerServer.class)
public class SwaggerServerAutoConfiguration {
 
    @Bean
    @ConditionalOnMissingBean
    @Controller
public class SystemMetadataApiController implements SystemMetadataApi {

    private static final Logger log = LoggerFactory.getLogger(SystemMetadataApiController.class);

    private final ObjectMapper objectMapper;

    private final HttpServletRequest request;

    @org.springframework.beans.factory.annotation.Autowired
    public SystemMetadataApiController(ObjectMapper objectMapper, HttpServletRequest request) {
        this.objectMapper = objectMapper;
        this.request = request;
    }

    public ResponseEntity<SystemMetadataResponse> systemMetadata() {
        String accept = request.getHeader("Accept");
        if (accept != null && accept.contains("application/json")) {
            try {
                return new ResponseEntity<SystemMetadataResponse>(objectMapper.readValue("{  \"buildVersion\" : \"buildVersion\",  \"buildTimestamp\" : \"buildTimestamp\",  \"status\" : \"status\"}", SystemMetadataResponse.class), HttpStatus.NOT_IMPLEMENTED);
            } catch (IOException e) {
                log.error("Couldn't serialize response for content type application/json", e);
                return new ResponseEntity<SystemMetadataResponse>(HttpStatus.INTERNAL_SERVER_ERROR);
            }
        }

        return new ResponseEntity<SystemMetadataResponse>(HttpStatus.NOT_IMPLEMENTED);
    }

}
}

Clone this wiki locally