Slide 1

Slide 1 text

@snicoll @brianclozel #springboot De zéro à héros avec Spring Boot Stéphane Nicoll & Brian Clozel Spring team Pivotal

Slide 2

Slide 2 text

@snicoll @brianclozel #springboot Hello! @snicoll @brianclozel [snicoll,bclozel]@pivotal.io

Slide 3

Slide 3 text

@snicoll @brianclozel #springboot Agenda • Part #1: Booting sequence • [slides] a short intro to Spring Boot • [live coding] building an app from scratch • — ☕️ break — • Part #2: More on Spring Boot • Boot autoconfig and starters • Externalized configuration

Slide 4

Slide 4 text

Part #1: Booting sequence let’s work one hour on a Spring Boot application

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

@snicoll @brianclozel #springboot Spring Boot lets you pair-program with the Spring team. “ Josh Long, @starbuxman

Slide 8

Slide 8 text

@snicoll @brianclozel #springboot Introduction to Spring Boot • Single point of focus • Getting started quickly with Spring • Common non-functional requirements for a "real" application • Exposes a lot of useful features by default • Gets out of the way quickly if you want to change defaults • An opportunity for Spring to be opinionated

Slide 9

Slide 9 text

@snicoll @brianclozel #springboot ಠ_ಠ Spring Boot is NOT • A prototyping tool • Only for embedded container apps • Sub-par Spring experience • For Spring beginners only

Slide 10

Slide 10 text

@snicoll @brianclozel #springboot Installation • Requirements: • JDK6+ • Maven 3.2+ / Gradle 1.12+ • Tools: • Spring Tool Suite • IntelliJ IDEA • spring CLI (from https://start.spring.io or gvm)

Slide 11

Slide 11 text

@snicoll @brianclozel #springboot Getting started quickly @RestController class HomeController { @RequestMapping("/") String home() { 'Hello Devoxx France' } } $ spring run app.groovy

Slide 12

Slide 12 text

@snicoll @brianclozel #springboot What just happened? import ... @Grab(“org.springframework.boot:spring-boot-starter-web:1.2.3.RELEASE") @EnableAutoConfiguration @RestController class HomeController { @RequestMapping("/") String home() { "Hello Devoxx France"; } public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }

Slide 13

Slide 13 text

@snicoll @brianclozel #springboot Let’s write some code!

Slide 14

Slide 14 text

@snicoll @brianclozel #springboot Now with Java @RestController public class HomeController { @Value("${conference.name:devoxx}") private String conference; @RequestMapping("/") public String home() { return "Hello " + conference; } } curl http://localhost:8080/

Slide 15

Slide 15 text

@snicoll @brianclozel #springboot First integration test @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = DemoApplication.class) @WebIntegrationTest(randomPort = true) public class HomeControllerIntegrationTest { @Value("${local.server.port}") private int port; @Test public void runAndInvokeHome() { String url = "http://localhost:" + port + "/"; String body = new RestTemplate() .getForObject(url, String.class); assertThat(body, is("Hello devoxx")); } }

Slide 16

Slide 16 text

@snicoll @brianclozel #springboot Add spring-data-jpa org.springframework.boot spring-boot-starter-data-jpa com.h2database h2 runtime

Slide 17

Slide 17 text

@snicoll @brianclozel #springboot Add a Speaker Entity @Entity public class Speaker { @GeneratedValue @Id private Long id; private String firstName; private String lastName; private String twitter; @Column(columnDefinition = "TEXT") private String bio; public Speaker(String firstName, String lastName, String twitter) { // initialize attributes } // getters and setters }

Slide 18

Slide 18 text

@snicoll @brianclozel #springboot Add a Speaker Repository public interface SpeakerRepository extends CrudRepository { Speaker findByTwitter(String twitter); Collection findByLastName(String lastName); }

Slide 19

Slide 19 text

@snicoll @brianclozel #springboot Test that repository @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = DemoApplication.class) public class SpeakerRepositoryTest { @Autowired private SpeakerRepository speakerRepository; @Test public void testFindByTwitter() throws Exception { Speaker stephane = speakerRepository.save( new Speaker("Stephane", "Nicoll", "snicoll")); assertThat(speakerRepository.findByTwitter("snicoll").getId(), is(stephane.getId())); } }

Slide 20

Slide 20 text

@snicoll @brianclozel #springboot Add spring-data-rest org.springframework.boot spring-boot-starter-data-rest

Slide 21

Slide 21 text

@snicoll @brianclozel #springboot RESTful repository public interface SpeakerRepository extends CrudRepository { @RestResource(path = "by-twitter") Speaker findByTwitter(@Param("id") String twitter); Collection findByLastName(@Param("name") String lastName); }

Slide 22

Slide 22 text

@snicoll @brianclozel #springboot Add spring-security org.springframework.boot spring-boot-starter-security

Slide 23

Slide 23 text

@snicoll @brianclozel #springboot Spring Security config @Configuration public class SecurityConfig extends GlobalAuthenticationConfigurerAdapter { @Override public void init(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("hero").password("hero").roles("HERO", "USER").and() .withUser("user").password("user").roles("USER"); } }

Slide 24

Slide 24 text

@snicoll @brianclozel #springboot Fix our web test @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = DemoApplication.class) @WebIntegrationTest(randomPort = true) public class HomeControllerIntegrationTest { @Value("${local.server.port}") private int port; @Test public void runAndInvokeHome() { String url = "http://localhost:" + port + "/"; String body = new TestRestTemplate("user", "user") .getForObject(url, String.class); assertThat(body, is("Hello devoxx")); } }

Slide 25

Slide 25 text

@snicoll @brianclozel #springboot Enabling @Secured @Configuration @EnableGlobalMethodSecurity(securedEnabled = true) public class SecurityConfig extends GlobalAuthenticationConfigurerAdapter { @Override public void init(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("hero").password("hero").roles("HERO", "USER").and() .withUser("user").password("user").roles("USER"); } }

Slide 26

Slide 26 text

@snicoll @brianclozel #springboot Securing an endpoint @RestController public class HomeController { @Value("${conference.name:devoxx}") private String conference; @RequestMapping("/") @Secured("ROLE_HERO") public String home() { return "Hello " + conference; } }

Slide 27

Slide 27 text

@snicoll @brianclozel #springboot Add spring-boot-actuator org.springframework.boot spring-boot-starter-actuator

Slide 28

Slide 28 text

@snicoll @brianclozel #springboot Adding a Health Indicator @Bean public HealthIndicator devoxxHealthIndicator() { return () -> { if (new Random().nextBoolean()) { return Health.up().build(); } else { return Health.down().withDetail("Boooo",42).build(); } }; }

Slide 29

Slide 29 text

@snicoll @brianclozel #springboot Add remote shell org.springframework.boot spring-boot-remote-shell

Slide 30

Slide 30 text

@snicoll @brianclozel #springboot Best experience with PaaS • Spring Boot features get a lot done for 12factor.net • PaaS friendly: fast startup, devops oriented $ mvn package $ cf push devoxx -p target/devoxx-0.0.1-SNAPSHOT.jar $ cf scale devoxx -i 4

Slide 31

Slide 31 text

Part #2: More on Boot Explaining the key concepts behind Boot and how to use them in your application

Slide 32

Slide 32 text

@YourTwitterHandle @YourTwitterHandle @snicoll @brianclozel #springboot Not only web Apps

Slide 33

Slide 33 text

@snicoll @brianclozel #springboot All types of apps • web • command line • batch • redis/gemfire/jpa/elasticsearch • integration • JMS, AMQP • etc

Slide 34

Slide 34 text

@snicoll @brianclozel #springboot Quick example

Slide 35

Slide 35 text

@snicoll @brianclozel #springboot Command Line apps @Component public class Startup implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("Hello World!"); } }

Slide 36

Slide 36 text

@YourTwitterHandle @YourTwitterHandle @snicoll @brianclozel #springboot AutoConfiguration and Starters

Slide 37

Slide 37 text

@snicoll @brianclozel #springboot Starter POMs org.springframework.boot spring-boot-starter-web • standard POM / gradle files: define dependencies • many available: batch, integration, web, ampq… • starter data-jpa = spring-data-jpa + JSR-303 + hibernate compile("org.springframework.boot:spring-boot-starter-web")

Slide 38

Slide 38 text

@snicoll @brianclozel #springboot @EnableAutoConfiguration • attempts to autoconfigure your app • backs off as you define your own beans • Regular @Configuration classes, @Conditional* annotations @Configuration @ComponentScan @EnableAutoConfiguration public class MyApplication { } @SpringBootApplication public class MyApplication { }

Slide 39

Slide 39 text

@snicoll @brianclozel #springboot Spring 4 @Conditional @Configuration @Conditional(CustomCondition.class) public class AppConfiguration { // @Bean methods } // defined in Boot @ConditionalOnClass(ObjectMapper.class) @ConditionalOnMissingBean("aBeanName")

Slide 40

Slide 40 text

@snicoll @brianclozel #springboot Writing your own starter • Add support for X in Boot with a PR! • Distribute a client lib in your company • Standardize usage of component X in a platform • [your use case here]

Slide 41

Slide 41 text

@snicoll @brianclozel #springboot Let’s write some code!

Slide 42

Slide 42 text

@snicoll @brianclozel #springboot New autoconfig project org.springframework.boot spring-boot-autoconfigure • Create a new hello-service-auto-configuration project • Only one mandatory dependency • Should contain specific dependencies and autoconfiguration classes

Slide 43

Slide 43 text

@snicoll @brianclozel #springboot Add custom service interface public interface HelloService { String sayHello(); } • This is the part that we’re trying to auto-configure • In a typical use case, this interface comes from a 3rd party lib

Slide 44

Slide 44 text

@snicoll @brianclozel #springboot Create a default impl. public class ConsoleHelloService implements HelloService { public String sayHello() { System.out.println("Hello Console"); } } • This default implementation will be shipped with the autoconfig project but should not be used if the application provides one.

Slide 45

Slide 45 text

@snicoll @brianclozel #springboot AutoConfig class example @Configuration @ConditionalOnClass(HelloService.class) public class HelloServiceAutoConfiguration { @ConditionalOnMissingBean @Bean public HelloService helloService() { return new ConsoleHelloService(); } }

Slide 46

Slide 46 text

@snicoll @brianclozel #springboot Declare AutoConfigs META-INF/spring.factories: org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ demo.hello.HelloServiceAutoConfiguration // one can order AutoConfigurations // with those annotations @AutoConfigureBefore @AutoConfigureAfter

Slide 47

Slide 47 text

@snicoll @brianclozel #springboot Back to main project • Add our autoconfig project as a dependency in our main project org.test.devoxx hello-service-auto-configuration ...

Slide 48

Slide 48 text

@snicoll @brianclozel #springboot Replace the Startup class @Component public class Startup implements CommandLineRunner { @Autowired private HelloService helloService; @Override public void run(String... args) throws Exception { helloService.sayHello(); } } • Our command line app now uses a Hello Service • running this will use the default implementation

Slide 49

Slide 49 text

@snicoll @brianclozel #springboot Override default impl. @Bean
 public HelloService helloService() {
 return () -> 
 LoggerFactory.getLogger(DemoApplication.class)
 .info("Hello from logs");
 } • Add a @Bean definition in our DemoApplication class • We provide our own impl, so the default one won’t be created

Slide 50

Slide 50 text

@YourTwitterHandle @YourTwitterHandle @snicoll @brianclozel #springboot Externalized Configuration

Slide 51

Slide 51 text

@snicoll @brianclozel #springboot Externalized Configuration • Goal: same code, different environments • properties and YAML formats • Dozens of out-of-the-box configuration keys • Supports inheritance/overriding • Type safe configuration with @ConfigurationProperties • IDE support with configuration metadata

Slide 52

Slide 52 text

@snicoll @brianclozel #springboot Adding properties @RestController public class HomeController { @Value("${conference.name:devoxx}") private String conference; //... } # application.yml example conference: name: devoxx france

Slide 53

Slide 53 text

@snicoll @brianclozel #springboot Per-Profile config values # application.yml - default profile server: address: 192.168.1.100 --- spring: profiles: development server: address: 127.0.0.1 --- spring: profiles: production server: address: 192.168.1.120

Slide 54

Slide 54 text

@snicoll @brianclozel #springboot Per-Profile config values # application.properties server.address=192.168.1.100 # application-development.properties server.address=127.0.0.1 # application-production.properties server.address=192.168.1.120

Slide 55

Slide 55 text

@snicoll @brianclozel #springboot Configuration priority 1.Command line arguments. 2.JNDI attributes from java:comp/env. 3.Java System properties (System.getProperties()). 4.OS environment variables. 5.application-{profile}.properties or application-{profile}.yml 6.application.properties or application.yml 7.@PropertySource annotations on your @Configuration classes. 8.Default properties (specified using SpringApplication.setDefaultProperties).

Slide 56

Slide 56 text

@snicoll @brianclozel #springboot Logging • Logback, Log4J, Log4J2, java.util.Logging • Logback with colored output • Default is INFO (use « -- debug » on the command line) • CONSOLE by default (can configure a file output) logging: file: logs/application_log level: ROOT: WARN org.example: INFO org.example.acme: DEBUG

Slide 57

Slide 57 text

@snicoll @brianclozel #springboot Let’s write some code!

Slide 58

Slide 58 text

@snicoll @brianclozel #springboot Update our starter public class ConsoleHelloService implements HelloService { @Value("${hello.target:console}") private String target; public String sayHello() { System.out.println("Hello " + this.target); } } • Delete the @Bean HelloService in the application • Update the default one with a property attribute

Slide 59

Slide 59 text

@snicoll @brianclozel #springboot Override that prop value # application.yml example hello: name: devoxx france java -jar devoxx-0.0.1-SNAPSHOT.jar \ --hello.name=Foo • set that property value with a application.yml key • or a command line argument!

Slide 60

Slide 60 text

@snicoll @brianclozel #springboot Type safe properties @ConfigurationProperties("hello") public class HelloProperties { private String prefix = "Hello "; @NotNull private String target; // getters and setters }

Slide 61

Slide 61 text

@snicoll @brianclozel #springboot Enable Config Properties @EnableConfigurationProperties(HelloProperties.class) @Configuration @ConditionalOnClass(HelloService.class) public class HelloServiceAutoConfiguration {

Slide 62

Slide 62 text

@snicoll @brianclozel #springboot Update Starter impl public class ConsoleHelloService implements HelloService { @Autowired private HelloProperties properties; @Override public void run(String... strings) throws Exception { System.out.println(properties.getPrefix() + properties.getTarget()); }

Slide 63

Slide 63 text

@snicoll @brianclozel #springboot Generate config metadata org.springframework.boot spring-boot-configuration-processor true • annotation processor that generates meta-data • uses Javadoc to build keys descriptions • default values detected • manual declaration allowed

Slide 64

Slide 64 text

@snicoll @brianclozel #springboot Document properties @ConfigurationProperties("hello") public class HelloProperties { /** * Prefix of welcome message. */ private String prefix = "Hello "; /** * Target of welcome message. */ @NotNull private String target; // getters and setters }

Slide 65

Slide 65 text

@YourTwitterHandle @YourTwitterHandle @snicoll @brianclozel #springboot Focus on Web Applications

Slide 66

Slide 66 text

@snicoll @brianclozel #springboot Serving static resources # in classpath classpath:/static/** classpath:/public/** classpath:/resources/** classpath:/META-INF/resources/** # in WAR files src/main/webapp/ static/ public/

Slide 67

Slide 67 text

@snicoll @brianclozel #springboot Template Engines • Thymeleaf • Groovy Markup Template • JMustache • Freemarker • Velocity

Slide 68

Slide 68 text

@snicoll @brianclozel #springboot Example: Thymeleaf • Templates picked up from classpath:/templates • Useful configuration keys: • spring.thymeleaf.prefix • spring.thymeleaf.cache • Backs off when creating custom Beans

Slide 69

Slide 69 text

@snicoll @brianclozel #springboot Error Handling • /error handles errors in a sensible way (HTML, JSON, etc) • Customize or extend with ErrorAttributes or an « error » view • Create dedicated error pages with
 EmbeddedServletContainerCustomizer

Slide 70

Slide 70 text

@snicoll @brianclozel #springboot Let’s write some code!

Slide 71

Slide 71 text

@snicoll @brianclozel #springboot Create a SpeakerController @Controller public class SpeakerController { private final SpeakerRepository speakerRepository; @Autowired public SpeakerController(SpeakerRepository speakerRepository) { this.speakerRepository = speakerRepository; } @RequestMapping("/ui/speakers/{id}") public String show(@PathVariable Long id, ModelMap model) { Speaker speaker = speakerRepository.findOne(id); if (speaker == null) { throw new SpeakerNotFoundException(); } model.put("speaker", speaker); return "speakers/show"; } @ResponseStatus(HttpStatus.NOT_FOUND) public static class SpeakerNotFoundException extends RuntimeException { } }

Slide 72

Slide 72 text

@snicoll @brianclozel #springboot Create a template View speaker

Stephane Nicoll

Sample Biography.

Slide 73

Slide 73 text

@YourTwitterHandle @YourTwitterHandle @snicoll @brianclozel #springboot Deploying Boot Apps

Slide 74

Slide 74 text

@snicoll @brianclozel #springboot Creating a WAR file @SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } } war

Slide 75

Slide 75 text

@snicoll @brianclozel #springboot Embedded server config • Registering Filters with @Bean methods • using application properties, configure: • ports • SSL • compression • and more • Configure Connectors with Java API

Slide 76

Slide 76 text

@snicoll @brianclozel #springboot Use Undertow instead org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-undertow

Slide 77

Slide 77 text

@snicoll @brianclozel #springboot http://spring.io powered by github.com/spring-io/sagan

Slide 78

Slide 78 text

@snicoll @brianclozel #springboot Microservices? SPRING Toolbox for building Microservices/Cloud native apps • Distributed configuration • service registration and discovery • Load-balancing, circuit breakers and more!

Slide 79

Slide 79 text

@snicoll @brianclozel #springboot Spring at Devoxx France • Hands-on Lab « Microservices Bootcamp »
 13:30-16:30 - Paris 221M
 with Josh Long and Sébastien Deleuze
 • Modern Enterprise Java architectures with Spring 4.1
 Thursday 13:00-13:50 - Amphi bleu
 with Juergen Hoeller and Stéphane Nicoll
 • The Spring BOF
 Thursday 19:30-20:30 - Neuilly 251

Slide 80

Slide 80 text

@snicoll @brianclozel #springboot Spring conferences http://springio.net http://springone2gx.com

Slide 81

Slide 81 text

@YourTwitterHandle @YourTwitterHandle @snicoll @brianclozel #springboot Q & A