Spring Boot 2.x

the small things

 

Highlights of the new release

  • A Java 8 baseline, and Java 9 support.
  • Reactive web programming support with Spring WebFlux/WebFlux.fn.
  • Auto-configuration and starter POMs for reactive Spring Data Cassandra, MongoDB, Couchbase and Redis.
  • Support for embedded Netty.
  • HTTP/2 for Tomcat, Undertow and Jetty.
  • Kotlin support.
  • A brand new actuator architecture, with support for Spring MVC, WebFlux and Jersey.
  • Micrometer based metrics with exporters for Atlas, Datadog, Ganglia, Graphite, Influx, JMX, New Relic, Prometheus, SignalFx, StatsD and Wavefront.
  • Quartz scheduler support.
  • Greatly simplified security auto-configuration.

Spring Boot 2.0

#springboot2.0

Converters for Duration type

app.timeout=180s
@ConfigurationProperties("app")
class AppProperties {

    private Duration timeout;    

    ...
}
@DurationUnit(ChronoUnit.SECONDS)
app.timeout=P3Y6M4DT3H3M3S

#springboot2.0

Updated Default 'create-drop' Handling

spring.jpa.hibernate.ddl-auto=create-drop

Embedded DB without schema manager

spring.jpa.hibernate.ddl-auto=none

otherwise

#springboot2.0

New namespaces

spring.jdbc.template
spring.jdbc.template.fetch-size=-1
spring.jdbc.template.max-rows=-1
spring.jdbc.template.query-timeout=1s

#springboot2.0

New namespaces

spring.data.web
spring.data.web.pageable.default-page-size=20
spring.data.web.pageable.max-page-size=2000
spring.data.web.pageable.one-indexed-parameters=false

#springboot2.0

New starters

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-json</artifactId>
</dependency>

#springboot2.0

New starters

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.module</groupId>
  <artifactId>jackson-module-parameter-names</artifactId>
</dependency>

#springboot2.0

class Person {
    // mandatory fields
    private final String name;
    private final String surname;
    
    // optional fields
    private String nickname;

    // no annotations are required if preconditions are met (details below)
    public Person(String name, String surname) {
        this.name = name;
        this.surname = surname;
    }

    public String getName() {
        return name;
    }

    public String getSurname() {
        return surname;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
}

#springboot2.0

Actuator endpoints

GET request to /actuator/scheduledtasks

{
  "cron" : [ {
    "runnable" : {
      "target" : "com.example.Processor.processOrders"
    },
    "expression" : "0 0 0/3 1/1 * ?"
  } ],
  "fixedDelay" : [ {
    "runnable" : {
      "target" : "com.example.Processor.purge"
    },
    "initialDelay" : 5000,
    "interval" : 5000
  } ]
}

#springboot2.0

Actuator endpoints

POST request to /actuator/loggers/{logger.name}

$ curl 'http://localhost:8080/actuator/loggers/com.example' -i -X POST \
    -H 'Content-Type: application/json' \
    -d '{"configuredLevel":"debug"}'
$ curl 'http://localhost:8080/actuator/loggers/com.example' -i -X POST \
    -H 'Content-Type: application/json' \
    -d '{}'

#springboot2.0

the largest of the smallest

#springboot2.0

Spring Boot 2.1

#springboot2.1

Bean overriding

@Component
class ComponentOne {
	@Bean
	public BeanService beanService() { ... }
}

@Component
class ComponentTwo {
	@Bean
	public BeanService beanService() { ... }
}

#springboot2.1

Bean overriding

INFO 33228 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'beanService' with a different definition: replacing [... defined in class path resource [com/example/demo/ComponentOne.class]] with [... defined in class path resource [com/example/demo/ComponentTwo.class]]

#springboot2.1

Bean overriding

WARN 36724 --- [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException
spring.main.allow-bean-definition-overriding=true

Converters for DataSize type

app.attachement-size=10MB
@ConfigurationProperties("app")
class AppProperties {

    private DataSize attachementSize;    

    ...
}

#springboot2.1

Converters for Duration type

#springboot2.1

@Value("${app.timeout:10s}")
private Duration timeout;

Profile Expression

#springboot2.1

production & (us-east | eu-central)

Works only for:

  • @Profile annotation
  • Multi-profile YAML Documents
  • Logback configuration using <springProfile>
server:
	address: 127.0.0.1
---
spring:
	profiles: production & eu-central
server:
	address: 192.168.1.120

Task scheduling

#springboot2.1

@Configuration
@EnableScheduling
public class AppSchedulingConfiguration implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = 
                new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(1);
        threadPoolTaskScheduler.setThreadNamePrefix("app-scheduler-");
        threadPoolTaskScheduler.initialize();
        taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
    }
}

Task scheduling

#springboot2.1

spring.task.scheduling.pool.size=1
spring.task.scheduling.thread-name-prefix=app-scheduler-

Task execution

#springboot2.1

@Configuration
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setMaxPoolSize(1);
        executor.setQueueCapacity(1);
        executor.setThreadNamePrefix("app-task-");
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

Task execution

#springboot2.1

spring.task.execution.pool.allow-core-thread-timeout=true
spring.task.execution.pool.core-size=1
spring.task.execution.pool.keep-alive=60s
spring.task.execution.pool.max-size=1
spring.task.execution.pool.queue-capacity=1
spring.task.execution.thread-name-prefix=app-task- 

Logging Groups

#springboot2.1

logging.group.tomcat=org.apache.catalina,org.apache.coyote,org.apache.tomcat
logging.level.tomcat=TRACE
logging.group.web=org.springframework.core.codec,org.springframework.http,\ 
  org.springframework.web

logging.group.sql=org.springframework.jdbc.core,org.hibernate.SQL

Bootstrap mode for JPA setup

#springboot2.1

@EnableJpaRepositories(bootstrapMode = BootstrapMode.DEFERRED)



spring.data.jpa.repositories.bootstrap-mode=lazy

#springboot2.1

New starter

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>

#springboot2.1

Micrometer Tags

@Bean
public MeterRegistryCustomizer<MeterRegistry> configure(
        @Value("${app.name}") String name) {
    return new MeterRegistryCustomizer<MeterRegistry>()
    {
        @Override
        public void customize(final MeterRegistry registry)
        {
            registry.config().commonTags("application", name);
        }
    };
}
management.metrics.tags.application=app-name

Spring Boot 2.2*

Lazy initialization

#springboot2.2.0.M1

spring.main.lazy-initialization=true

Task execution and scheduling

#springboot2.2.0.M1

spring.task.execution.shutdown.await-termination=true
spring.task.execution.shutdown.await-termination-period=10s
spring.task.scheduling.shutdown.await-termination=true
spring.task.scheduling.shutdown.await-termination-period=10s

Test Application Arguments

#springboot2.2.0.M1

@RunWith(SpringRunner.class)
@SpringBootTest(args = "--app.test=one")
public class ApplicationArgumentsExampleTests {

    @Autowired
    private ApplicationArguments args;

}

Spring Boot 2.x - The small things

By Arkadiusz Jurasz

Spring Boot 2.x - The small things

  • 486