Spring Basics Training

https://andifalk.github.io/
spring-basics-training/ presentation/index.html

Andreas Falk

NovaTec Consulting GmbH

andreas.falk@novatec-gmbh.de
@NT_AQE, @andifalk

Workshop Organization

Agenda (1st half)

  1. Welcome
  2. History and Overview of Spring
  3. Spring Core Framework
  4. Coffee Break
  5. Microservices & Cloud Native Apps
  6. Spring Boot
  7. Lunch

Workshop Organization

Agenda (2nd half)

  1. Spring Data JPA
  2. Spring Web
  3. Coffee Break
  4. Spring Security
  5. Spring Testing
  6. What's new in Spring 5.0
  7. Feedback/End of Workshop

Hands-On Workshop

This workshop is a hands-on workshop, so you have to make your hands “dirty”!!

Requirements for completing the labs:

Hands-On Workshop

Use any Java IDE (Eclipse, IntelliJ, NetBeans, VS Code)

Recommended ones are:

Hands-On Workshop

All hands-on related code is on master branch at https://github.com/andifalk/spring-basics-training

You find lots of labs with two sub directories

  • initial: Code required to start a lab
  • complete: Complete code reference of a lab

Let's get Started!

A little bit of history

2002

Rod Johnson had an idea and wrote a book:
“J2EE Design & Development”

First source code available

2004

Published Spring 1.0

Java 1.3 & 1.4 compatible

2006-2009

Spring 2.x

Java 5 & 6 compatible

Java EE 5 compliant

2009-2013

Spring 3.x

Java 6 & 7 compatible

Java EE 6 compliant

Rod Johnson leaves Sping

Founded Pivotal

2014-2017

Spring 4.x

Java 7 & 8 compatible

Java EE 6 & 7 compliant

Published Spring Boot 1.0 (2014)

2018, 2019, ...

Spring 5.x

Spring Boot 2.0

Java 8+ compatible

Java EE 7+ compliant

Spring Overview

Spring IO Platform

Spring Boot

Spring Auto-Configuration

“Convention over Configuration”


https://projects.spring.io/spring-boot

Spring Boot

Build a working Spring App in 5 minutes


https://start.spring.io

Spring Cloud Data Flow

Successor of Spring XD

Toolkit for building data integration and real-time data processing pipelines

Pipelines consist of Spring Boot apps


https://start.spring.io

Spring Cloud

Patterns for Cloud-Native Applications

Configuration management

Service discovery

Circuit breakers


https://projects.spring.io/spring-cloud

Spring Integration

Implementation of well-known EAI Patterns

Integration with External Systems

ReST/HTTP, Twitter, EMail, JMS, FTP, ...


https://projects.spring.io/spring-integration

Spring Kafka

Developing Kafka-based messaging solutions

Adds Kafka support to Spring Integration


https://projects.spring.io/spring-kafka

Spring Batch

Developing batch processing applications

Chunk based processing

Start/Stop/Restart

Retry/Skip


https://projects.spring.io/spring-batch

Spring Web

Servlet-based Web (Spring MVC)

Reactive Web (Spring WebFlux)

Restful services

Thymeleaf, JSF, Tapestry, ...


https://projects.spring.io/spring-framework

Spring Data

Spring Data JDBC

JDBC based repositories

This is NOT an ORM

Support for @Query annotations


https://projects.spring.io/spring-data-jdbc

Spring Data JPA

Enhanced support for JPA based data access layers

Supports Hibernate, EclipseLink as JPA providers

Pagination support, dynamic query execution


https://projects.spring.io/spring-data-jpa

Spring Data JPA

Automatic Database Migrations


https://flywaydb.org
https://www.liquibase.org

Spring Data MongoDB

Data access for MongoDB document database

Mongo Template support

POJO centric model for interacting with a MongoDB DBCollection


https://projects.spring.io/spring-data-mongodb

Spring Data Redis

Redis Template support

Repository for key/value store


https://projects.spring.io/spring-data-redis

Spring Framework

Core spring functionality

Application context & Beans

Dependency Injection


https://projects.spring.io/spring-framework

Spring Framework

Version 3.2.x

“Legacy”

Supports Java 6 / 7

EOL: End of 2016


https://spring.io/blog/2015/06/15/spring-framework-3-2-x-eol-on-dec-31-2016

Spring Framework

Version 4.3.x

Long term version

Supports Java 6 / 7 / 8

EOL: 2020


https://github.com/spring-projects/spring-framework/wiki

Spring Framework

Version 5.0

Current version

Supports Java 8 / 9 / 10+


https://github.com/spring-projects/spring-framework/wiki

Spring Security

Authentication

SSO (OAuth2, OpenID Connect)

Authorization

Encryption


https://projects.spring.io/spring-security

Reactor

Reactive library for building non-blocking applications

Based on Reactive Streams Specification

Base library for Spring WebFlux (Spring 5)


https://projectreactor.io
https://www.reactive-streams.org

Cloud Platform Support

Azure Cloud

Google Cloud

Spring Cloud Pipelines

Don't reinvent CI/CD pipelines for each project

Provide templates with best practices for common deployment pipelines

Supports Jenkins and Concourse CI


https://cloud.spring.io/spring-cloud-pipelines

References

Spring Core Framework

Simplify Java (Kotlin) Development (Part 1)

Lightweight development with POJOs

Loose coupling through Dependency Injection

Lightweight Development

Plain Old Java Objects

vs.

Enterprise Java Beans (1.x)

EJB 1.1

Spring POJO

Dependency Injection (DI)

SOLID

Single Responsibility Principle

Open/Closed Principle

Liskov's Substitution Principle

Interface Segregation Principle

Dependency Inversion Principle

Dependency Inversion Principle

Depend on abstractions, not on concretions

Inversion of Control Patterns

Service Locator

Dependency Injection


https://martinfowler.com/articles/injection.html

JSR 330 Dependency Injection


                            <dependency>
                                <groupId>javax.inject</groupId>
                                <artifactId>javax.inject</artifactId>
                                <version>1</version>
                            </dependency>
                        

                            @Inject
                            public void setMyService(MyService myService) {
                               ...
                            }
                        

Spring Dependency Injection


                            @Autowired
                            public void setMyService(MyService myService) {
                               ...
                            }
                        

Spring Core Modules

Spring Core Module Libraries

Spring 5: Mapped as Java 9 Automatic Modules

Beans & Contexts

Application Context

Spring Bean Configuration

XML

Java Configuration

Annotations (Component Scan)

XML Configuration

A simple Spring Bean


                            public interface BeanOne {
                                String whoAmI();
                            }
                        

                            public class BeanOneImpl implements BeanOne {

                                private final BeanTwo beanTwo;

                                public BeanOneImpl(BeanTwo beanTwo) {
                                    this.beanTwo = beanTwo;
                                }

                                @Override
                                public String whoAmI() {
                                    return BeanOneImpl.class.getSimpleName()
                                                + ": " + beanTwo.whoAmI();
                                }
                            }
                        

XML Application Context


                            <beans>
                                <bean id="beanOne" class="com.example.beans.BeanOneImpl">
                                    <constructor-arg ref="beanTwo"/>
                                </bean>
                                <bean id="beanTwo" class="com.example.beans.BeanTwoImpl">
                                </bean>
                            </beans>
                        

                            public class XmlApplication {

                                public static void main(String[] args) {
                                    ApplicationContext ctx =
                                            new ClassPathXmlApplicationContext(
                                                "application.xml");
                                    BeanOne beanOne = ctx.getBean(BeanOne.class);
                                    beanOne.whoAmI();
                                }
                            }
                        

Java Configuration

Another simple Spring Bean


                            public interface BeanOne {
                                String whoAmI();
                            }
                        

                            public class BeanOneImpl implements BeanOne {
                                private final BeanTwo beanTwo;

                                @Autowired
                                public BeanOneImpl(BeanTwo beanTwo) {
                                    this.beanTwo = beanTwo;
                                }

                                @Override
                                public String whoAmI() {
                                    return BeanOneImpl.class.getSimpleName()
                                                + ": " + beanTwo.whoAmI();
                                }
                            }
                        

Java Application Context


                            @Configuration
                            public class ApplicationConfiguration {
                                @Bean
                                public BeanOne beanOne() {
                                    return new BeanOneImpl(beanTwo());
                                }
                                @Bean
                                public BeanTwo beanTwo() {
                                    return new BeanTwoImpl(...);
                                }
                            }
                        

                            public class JavaApplication {

                                public static void main(String[] args) {
                                    ApplicationContext ctx
                                            = new AnnotationConfigApplicationContext(
                                                    ApplicationConfiguration.class);
                                    BeanOne beanOne = ctx.getBean(BeanOne.class);
                                    beanOne.whoAmI();
                                }
                            }
                        

Component Scan Configuration

Another simple Spring Bean


                            public interface BeanOne {
                                String whoAmI();
                            }
                        

                            @Component
                            public class BeanOneImpl implements BeanOne {
                                private final BeanTwo beanTwo;

                                @Autowired
                                public BeanOneImpl(BeanTwo beanTwo) {
                                    this.beanTwo = beanTwo;
                                }
                                @Override
                                public String whoAmI() {
                                    return BeanOneImpl.class.getSimpleName()
                                                + ": " + beanTwo.whoAmI();
                                }
                            }
                        

Java Application Context


                            @ComponentScan(basePackages = "com.example")
                            @Configuration
                            public class ApplicationConfiguration {
                            }
                        

                            public class JavaApplication {

                                public static void main(String[] args) {
                                    ApplicationContext ctx
                                            = new AnnotationConfigApplicationContext(
                                                    ApplicationConfiguration.class);
                                    BeanOne beanOne = ctx.getBean(BeanOne.class);
                                    beanOne.whoAmI();
                                }
                            }
                        

Annotations

@Component

@Configuration

@Service

@Repository

@Controller

@RestController

Spring Annotation Programming Model

Composed Annotations


                            @Transactional
                            @Service
                            @Target(TYPE)
                            @Retention(RUNTIME)
                            @Documented
                            public @interface TransactionalService {
                                ...
                                @AliasFor(annotation = Transactional.class,
                                    attribute = "propagation")
                                Propagation propagation() default Propagation.REQUIRED;
                            }
                        

https://github.com/sbrannen/spring-composed

Spring Lifecycle

Starting Lifecycle

Stopping Lifecycle

Lifecycle & SmartLifecycle


                           public interface Lifecycle {
                               void start();
                               void stop();
                               boolean isRunning();
                           }
                        

                           public interface Phased {
                               int getPhase();
                           }
                        

                            public interface SmartLifecycle extends Lifecycle, Phased {
                               boolean isAutoStartup();
                               void stop(Runnable callback);
                            }
                        

Bean Scopes

General Bean Scopes

Singleton

Prototype

Singleton Scope

Prototype Scope

Web Bean Scopes

Request

Session

Global Session

Application

Simplify Java (Kotlin) Development (Part 2)

Declarative programming

Eliminating boilerplate code

Great testing support

Declarative Programming

Declarative Cross-Cutting Concerns

Aspect-Oriented Programming (AOP)

Transaction Management

Security

Logging

Declarative Transaction & Authorization


                            @Service
                            public class TaskService {
                                ...
                                @Transactional(propagation = Propagation.REQUIRES_NEW)
                                @PreAuthorize("hasRole('USER')")
                                public Task createTask(
                                   ...
                                }
                                ...
                            }
                        

Aspect-Oriented Programming

Spring AOP vs. AspectJ

AspectJ Advice Annotations

@Before

@AfterReturning

@AfterThrowing

@After

@Around

Configure AspectJ Annotations Support


                            <dependency>
                               <groupId>org.aspectj</groupId>
                               <artifactId>aspectjweaver</artifactId>
                               <version>1.9.0</version>
                            </dependency>
                        

                            @SpringBootApplication
                            @EnableAspectJAutoProxy
                            public class SpringComponentsApplication {
                                public static void main(String[] args) {
                                    SpringApplication.run(
                                        SpringComponentsApplication.class, args);
                                }
                            }
                        

A Logging Aspect


                            @Component
                            @Aspect
                            public class LoggingAspect {
                            static final Logger LOG = LoggerFactory.getLogger(
                                                        LoggingAspect.class);
                               @Around("execution(* person.PersonService.*(..))")
                               public Object logAction (ProceedingJoinPoint pjp)
                                                        throws Throwable {
                                  LOG.info("Calling {}.{}",
                                    pjp.getTarget().getClass().getName(),
                                    pjp.getSignature().getName());
                                  return proceedingJoinPoint.proceed();
                               }
                            }
                        

Eliminate Boilerplate Code

Pure JDBC Code


                           public List<Person> findAll() {
                               List<Person> result = new ArrayList<>();
                               try (Connection conn = dataSource.getConnection()) {
                                  statement = conn.prepareStatement(
                                                "select * from person");
                                  rs = statement.executeQuery();
                                  while (rs.next()) {
                                     person = new Person();
                                     …
                                     result.add(person);
                                  }
                               } catch (SQLException e) {…} finally {}
                               return result;
                            }
                        

JDBC Template (Java 7)


                           public List<Person> findAll() {
                               return jdbcTemplate.query("select * from person",
                                 new RowMapper<Person>() {
                                    @Override
                                    public Person mapRow(ResultSet arg0, int arg1)
                                            throws SQLException {
                                       Person person = new Person();
                                       …
                                       return person;
                                    }
                                 });
                           }
                        

JDBC Template (Java 8)


                           public List<Person> findAll() {
                               return jdbcTemplate.query("select * from person",
                                      (rs, rowNum) ->  {
                                         Person person = new Person();
                                         …
                                         return person;
                               });
                           }
                        

Other Templates

TransactionTemplate

JmsTemplate

RestTemplate

OAuth2RestTemplate

...

Advanced Bean Wiring

What about multiple candidates?


                            public interface Storage {
                            }
                        

                            @Component
                            public class Harddisk implements Storage {
                            }
                        

                            @Component
                            public class CompactDisc implements Storage {
                            }
                        

                            @Service
                            public class BackupManager {
                                private Storage storage;

                                @Autowired
                                public void setStorage(Storage storage) {
                                    this.storage = storage;
                                }
                                ...
                            }
                        

Single Match expected!


                            NoUniqueBeanDefinitionException:
                                No qualifying bean of type 'com.example.beans.Storage'
                                    available: expected single matching bean but found 2:
                                        compactDisc,harddisk
                                at org.springframework.beans.factory.config.
                                        DependencyDescriptor.resolveNotUnique
                                at org.springframework.beans.factory.support.
                                        DefaultListableBeanFactory.doResolveDependency
                                ...
                        

Possible Solutions

@Primary

@Qualifier

@Profile

@Conditional

@Primary


                            public interface Storage {
                            }
                        

                            @Primary @Component
                            public class Harddisk implements Storage {
                            }
                        

                            @Component
                            public class CompactDisc implements Storage {
                            }
                        

                            @Service
                            public class BackupManager {
                                private Storage storage;

                                @Autowired
                                public void setStorage(Storage storage) {
                                    this.storage = storage;
                                }
                                ...
                            }
                        

@Qualifier


                            public interface Storage {
                            }
                        

                            @Qualifier("HD") @Component
                            public class Harddisk implements Storage {
                            }
                        

                            @Qualifier("CD") @Component
                            public class CompactDisc implements Storage {
                            }
                        

                            @Service
                            public class BackupManager {
                                private Storage storage;

                                @Qualifier("CD") @Autowired
                                public void setStorage(Storage storage) {
                                    this.storage = storage;
                                }
                                ...
                            }
                        

-Dspring.profiles.active="dev"


                            public interface Storage {
                            }
                        

                            @Profile("dev") @Component
                            public class Harddisk implements Storage {
                            }
                        

                            @Profile("prod") @Component
                            public class CompactDisc implements Storage {
                            }
                        

                            @Service
                            public class BackupManager {
                                private Storage storage;

                                @Autowired
                                public void setStorage(Storage storage) {
                                    this.storage = storage;
                                }
                                ...
                            }
                        

@Conditional


                            @Target({ElementType.TYPE, ElementType.METHOD})
                            @Retention(RetentionPolicy.RUNTIME)
                            @Documented
                            @Conditional(ProfileCondition.class)
                            public @interface Profile {...}
                        

                            @Target({ ElementType.TYPE, ElementType.METHOD })
                            @Retention(RetentionPolicy.RUNTIME)
                            @Documented
                            @Conditional(OnClassCondition.class)
                            public @interface ConditionalOnClass {...}
                        

                            package org.springframework.boot.autoconfigure.orm.jpa;

                            @Configuration
                            @ConditionalOnClass({ ..., EntityManager.class })
                            @Conditional(HibernateEntityManagerCondition.class)
                            public class HibernateJpaAutoConfiguration {...}
                        

Spring Expression Language (SpEL)


                            <bean id="numberGuess" class="com.example.NumberGuess">
                                <property
                                    name="randomNumber"
                                    value="#{T(java.lang.Math).random() * 100.0}"/>
                            </bean>
                            <bean id="shapeGuess" class="com.example.ShapeGuess">
                                <property
                                    name="initialShapeSeed"
                                    value="#{ numberGuess.randomNumber }"/>
                        

                            ExpressionParser parser = new SpelExpressionParser();
                            Expression expression = parser.parseExpression(
                               "T(java.lang.Math).random() * 100.0");
                            double value = (Double) expression.getValue();
                        

References

Spring In Action 4th Edition
(Manning, ISBN: 978-1617291203)

Microservices

“Agile SOA”

http://isa-principles.org

The Well Defined Monolith

“Big Ball Of Mud” Monolith

From Monolith to Microservices

Autonomic Microservices

CI Pipelines for Microservices

Size of Microservices (I)

Size of Microservices (II)

Size of Microservices (III)

Size of Microservices (IV)

References

Building Microservices
(O'Reilly, ISBN: 978-1491950357)

Cloud Native

Cloud Native (I)

“Cloud-native is an approach to building and running applications that fully exploits the advantages of the cloud computing delivery model.”

pivotal.io

Cloud Native (II)

The Twelve Factory App

https://12factor.net

Cloud Native (III)

On Premise

Infrastructure as a service (IaaS)

Platform as a service (PaaS)

Software as a service (SaaS)

Function as a service (FaaS)

Cloud Native (IV)

Spring Cloud Native Stack

References

Cloud Native Java
(O'Reilly, ISBN: 978-1449374648)

Spring Boot

https://start.spring.io

Spring CLI

https://start.spring.io/spring.zip


                            $ spring init -d=web,security,jpa --build=gradle my-dir
                            Using service at https://start.spring.io
                            Project extracted to '/home/my-user/my-dir'
                        

Spring Boot Components

Auto Configuration

Spring Boot Application


                            package org.springframework.boot.autoconfigure;

                            ...
                            @SpringBootConfiguration
                            @EnableAutoConfiguration
                            @ComponentScan
                            public @interface SpringBootApplication {
                                ...
                            }
                        

                            @SpringBootApplication
                            public class MyApplication {

                                public static void main(String[] args) {
                                    SpringApplication.run(
                                         MyApplication.class, args);
                                }
                            }
                        

Auto Configuration


                            @Configuration
                            @ConditionalOnClass(Flyway.class)
                            @ConditionalOnBean(DataSource.class)
                            @ConditionalOnProperty(prefix = "spring.flyway",
                                name = "enabled", matchIfMissing = true)
                            @AutoConfigureAfter({ DataSourceAutoConfiguration.class,
                            HibernateJpaAutoConfiguration.class })
                            public class FlywayAutoConfiguration {
                                ...
                            }
                        

Deactivate Auto Configuration


                            @SpringBootApplication (
                              exclude = DataSourceAutoConfiguration.class)
                            public class MyApplication {

                                public static void main(String[] args) {
                                    SpringApplication.run(
                                         MyApplication.class, args);
                                }
                            }
                        

Externalize Configuration

Application Properties


                            spring.application.name=My App
                            spring.main.show-banner=false
                            server.port=8080
                            spring.datasource.jdbc-url=jdbc:h2:mydb
                            spring.datasource.username=sa
                        

Application Configuration (YAML)


                            spring:
                              application:
                                name: My App
                              main:
                                show-banner: false
                              datasource:
                                jdbc-url: jdbc:h2:mydb
                                username: sa
                        

YAML=YAML Ain't Markup Language

Configuration Naming Conventions

application.properties or application.yml (default)

application-dev.properties (if “dev” profile is active)

application-cloud.yml (if “cloud” profile is active)

Configuration Properties


                            @ConfigurationProperties(prefix = "hosts")
                            @Validated
                            public class MyProperties {

                                private Host host;
                                ...
                                public static class Host {
                                    @NotNull
                                    private String ip;
                                    @Min(1)
                                    private int port;
                                    ...
                                }
                            }
                        

Configuration Properties


                            hosts:
                              host:
                                ip: 192.168.0.1
                                port: 8080
                        

Application Configuration

More Options

Configuration Server

Vault Cloud

DevOps

Deployment Options

Can be packaged as...

Executable JAR or as... (Executable) WAR

but...

Make JAR not WAR

Spring Boot Build Plugin

Maven


                            <plugin>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-maven-plugin</artifactId>
                                <version>2.0.2.RELEASE</version>
                                <executions>
                                    <execution>
                                        <goals>
                                            <goal>repackage</goal>
                                        </goals>
                                    </execution>
                                </executions>
                            </plugin>
                        

Gradle


                            plugins {
                                id 'org.springframework.boot' version '2.0.2.RELEASE'
                            }
                        

Actuators

Manage and monitor your application

Exposure via..

HTTP

JMX

Actuator Endpoints (Partly)

Endpoint Description Enabled
beans List of Spring beans Yes
conditions Evaluated auto-config Yes
configprops List of properties Yes
health Application health info Yes
metrics ‘Metrics’ information Yes
shutdown Gracefully shutdown app No
threaddump Performs a thread dump Yes

Health Actuator

http://localhost:8080/actuator/health


                            {
                              "status": "UP",
                              "details": {
                                "mongo": {
                                  "status": "UP",
                                  "details": {
                                    "version": "3.2.2"
                                  }
                                },
                                "diskSpace": {
                                  "status": "UP",
                                  "details": {
                                    ...
                            }}}}
                        

Custom Health Indicator


                            @Component
                            public class BlobStorageHealthEndpoint
                                    implements HealthIndicator {

                                private CloudBlobClient cloudBlobClient;
                                ...

                                @Override
                                public Health health() {
                                    Health.Builder builder = Health.up();
                                    ...
                                    return builder.build();
                                }
                            }
                        

References

Learning Spring Boot 2.0
(Packt, ISBN: 978-1786463784)

Spring Data

Data Access Abstraction


                            @Service
                            public class PersonServiceImpl implements PersonService {
                               @Autowired private PersonRepository personRepository;

                               @Override
                               public List<Person> findAll() {
                                  return personRepository.findAll();
                               }
                            }
                        

JPA Entity


                            @Entity
                            public class Person
                                    extends AbstractPersistable<Long> {

                               private String firstName;
                               private String lastName;
                               private String yearOfBirth;

                               public Person() {
                                  super();
                               }
                               …
                            }
                        

Auditing

Auditor


                            public class SpringSecurityAuditorAware
                               implements AuditorAware<User> {

                               @Override
                               public User getCurrentAuditor() {
                                  Authentication authentication =
                                     SecurityContextHolder
                                        .getContext ().getAuthentication ();
                                     …
                               }
                            }
                        

Audited JPA Entity


                            @Entity
                            public class Person
                                extends AbstractAuditable<User,Long>  {

                               private String firstName;
                               private String lastName;
                               private String yearOfBirth;
                               …

                            }
                        

CRUD Repository

Create/Read/Update/Delete


                            public interface CrudRepository<T, ID>
                                    extends Repository<T, ID> {
                                ...
                                <S extends T> S save(S entity);
                                Optional<T> findById(ID id);
                                Iterable<T> findAll();
                                long count();
                                boolean existsById(ID id);
                                void delete(T entity);
                                ...
                            }
                        

Autogenerated Simple Queries

findByLastName()

findByLastNameAndFirstName()

findByFirstNameIgnoreCaseOrderByFirstName()

Custom Queries


                            public interface PersonRepository extends
                               JpaRepository<Person, Long> {

                                ...

                               @Query("SELECT p FROM #{#entityName} p LEFT JOIN FETCH "
                                            + "p.addresses WHERE p.id = :id")
                                  Person findOneWithAddresses(@Param("id") Long id);
                            }
                        

Spring Web

Spring Web Stacks


Spring MVC

Model-View-Controller

Separation between presentation and model

Controller and view communicate through the model

Observer pattern to update views on model changes

https://martinfowler.com/eaaDev/uiArchs.html#ModelViewController

Front Controller

“A controller that handles all requests for a Web site”

https://martinfowler.com/eaaCatalog/frontController.html

Spring MVC Request Handling


Controller


                            @Controller
                            public class HomeController {
                                @RequestMapping(value="/", method=GET)
                                public String home() {
                                    return "home";
                                }
                            }
                        

Request Mapping


                            @RequestMapping(
                                path="/",
                                method = POST
                                consumes = MediaType.APPLICATION_JSON_VALUE,
                                produces = MediaType.APPLICATION_JSON_VALUE)

                            @PostMapping(
                                path="/",
                                consumes = MediaType.APPLICATION_JSON_VALUE,
                                produces = MediaType.APPLICATION_JSON_VALUE)

                            @GetMapping(
                                path="/",
                                produces = MediaType.APPLICATION_JSON_VALUE)

@ResponseBody

Mapping for REST services

Indicates a method return value should be bound to the web response body

@RestController =

@Controller + @ResponseBody


                            @Target(ElementType.TYPE)
                            @Retention(RetentionPolicy.RUNTIME)
                            @Documented
                            @Controller
                            @ResponseBody
                            public @interface RestController {
                                ...
                            }
                        

View Resolvers

View Technologies

Thymeleaf

JSP & JSTL

Jackson (JSON, XML)

Script Views (e.g. React)

PDF, Excel

...

Other Web Frameworks

JavaServer Faces (JSF)

Apache Struts

Tapestry

Spring Security

Spring Security Features

Authentication

Authorization

Password Encoders

Security Testing Support

New in Spring Security 5.0

Support for Reactive Web Applications

Support for OAuth 2.0 Client

Support for OpenID Connect 1.0, JWT and JOSE (JWS/JWE/JWK) Client

Spring Security

Secure By Default

Authentication required for all HTTP endpoints

Session Fixation Protection

Session Cookie (HttpOnly, Secure)

CSRF Protection

Security Response Headers

Spring Security Auto Configuration


                            <parent>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-starter-parent</artifactId>
                                <version>2.0.2.RELEASE</version>
                                <relativePath/>
                            </parent>
                            <dependency>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-starter-security</artifactId>
                            </dependency>
                        

Spring Boot 2.0 Reference Docs

Auto Generated Login Form & Credentials


                            2018-05-10 20:11:24.505  INFO 28867 ---
                                [main] .s.s.UserDetailsServiceAutoConfiguration :

                            Using generated security password:
                                4cb48dca-1c78-4dbb-85bc-a5200256105e
                        

Authentication

Who am I?

HTTP 401 - Unauthorized

Basic Authentication


                            GET / HTTP/1.1
                            Host: localhost:8080
                        

                            HTTP/1.1 401
                            WWW-Authenticate: Basic realm="hello"
                        

                            GET / HTTP/1.1
                            Host: localhost:8080
                            Authorization: Basic dXNlcjpzZWNyZXQ=
                        

Form Based Login


                            POST /login HTTP/1.1
                            Host: localhost:8080
                            Content-Type: application/x-www-form-urlencoded
                            Cookie: JSESSIONID=14965E3A995DA1973F42F308D59727D4

                            username=user&password=secret&submit=Login
                        

                            HTTP/1.1 302
                            Set-Cookie: JSESSIONID=49C632387800316021BE804AB2F27C15;
                                            Path=/; HttpOnly
                        

                            GET / HTTP/1.1
                            Host: localhost:8080
                            Cookie: JSESSIONID=49C632387800316021BE804AB2F27C15
                        

Configure Custom User Storage


                            public class UserDetailsConfig {
                                @Bean
                                public PasswordEncoder passwordEncoder() {
                                    return PasswordEncoderFactories
                                        .createDelegatingPasswordEncoder();
                                }
                                @Bean
                                public UserDetailsService userDetailsService() {
                                    return new InMemoryUserDetailsManager(
                                        User.builder().username("user@example.com")
                                            .password(passwordEncoder().encode("secret"))
                                                    .roles("USER").build()
                                    );
                            }}
                        

Configure Custom Authentication


                            class WebSecurityConfig extends WebSecurityConfigurerAdapter{
                                @Override
                                protected void configure(
                                        AuthenticationManagerBuilder auth) {
                                    auth.userDetailsService(userDetailsService)
                                            .passwordEncoder(passwordEncoder);
                                }
                                @Override
                                protected void configure(HttpSecurity http) {
                                    http.httpBasic().and().formLogin()
                                        .and().authorizeRequests()
                                            .antMatchers("/unrestricted").permitAll()
                                            .anyRequest().authenticated();
                            }}
                        

Secure Passwords

Password Encoder


                            package org.springframework.security.crypto.password;

                            public interface PasswordEncoder {

                                String encode(CharSequence rawPassword);

                                boolean matches(CharSequence rawPassword,
                                                    String encodedPassword);
                            }
                        

Delegating Password Encoder


                            public class PasswordEncoderFactories {
                              public static PasswordEncoder
                                      createDelegatingPasswordEncoder() {
                                String encodingId = "bcrypt";
                                Map<String, PasswordEncoder> encoders
                                  = new HashMap<>();
                                encoders.put(encodingId, new BCryptPasswordEncoder());
                                encoders.put("ldap", new LdapShaPasswordEncoder());
                                encoders.put("noop", NoOpPasswordEncoder.getInstance());
                                encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
                                encoders.put("scrypt", new SCryptPasswordEncoder());
                                return new DelegatingPasswordEncoder(
                                      encodingId, encoders);
                            }}
                        
Passwords are stored this way

                            {bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQ...
                        

Bearer Token

  • OAuth2
  • OpenID Connect

                            GET / HTTP/1.1
                            Host: localhost:8080
                            Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiI
                        

Other Authentication Mechanisms

  • X.509 Client Certificate
  • SAML 2
  • API Token
  • ...

Authentication

Stateful or Stateless?

Session Cookie Token (Bearer, JWT)
With each Request
(on same domain)
Manually as Header
Potential CSRF! No CSRF possible
One domain Cross domain (CORS)
Sensitive Info (HTTPS) Sensitive Info (HTTPS)

HTTPS (SSL/TLS) !!

Validation (Destination Host)

Data Confidentiality (Encryption)

Data Integrity (Hashing)

HTTPS (SSL/TLS) !!

Let's Encrypt
CloudFlare
HTTP/2

Enable SSL/TLS in Spring Boot

Using Java Keystore


                            server.port=8443
                            server.ssl.key-store=classpath:keystore.jks
                            server.ssl.key-store-password=secret
                            server.ssl.key-password=another-secret
                        

OAuth 2 = Authorization


https://tools.ietf.org/html/rfc6749

OpenID Connect = Authenticaton


https://openid.net

JSON Web token (JWT)

Base 64 Encoded JSON Formatted Value of...

...Header

...Payload

...Signature


                            GET / HTTP/1.1
                            Host: localhost:8080
                            Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1N...
                        

JSON Web Token (JWT)

Header


                            {
                              typ: "JWT",
                              alg: "RS256"
                            }
                        

Payload


                            {
                              iss: "https://identity.example.com",
                              aud: "my-client-id",
                              exp: 1495782385,
                              nonce: "N0.46824857243233511495739124749",
                              iat: 1495739185,
                              at_hash: "hC1NDSB8WZ9SnjXTid175A",
                              sub: "mysubject",
                              auth_time: 1495739185,
                              email: "test@gmail.com"
                            }
                        

Spring Security OAuth2 Module & Spring Boot 1.5


Spring Boot 1.5 Reference Docs

Spring Security 5.0 OAuth2/OIDC Client & Spring Boot 2.0


                            ...
                            <dependency>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-starter-security</artifactId>
                            </dependency>
                            <dependency>
                                <groupId>org.springframework.security</groupId>
                                <artifactId>spring-security-oauth2-client</artifactId>
                            </dependency>
                            <dependency>
                                <groupId>org.springframework.security</groupId>
                                <artifactId>spring-security-oauth2-jose</artifactId>
                            </dependency>
                        

Spring Boot 2.0 Reference Docs

Authorization

What can I access?

HTTP 403 - Forbidden

Method Security

JSR 250: e.g. @RolesAllowed

Spring Security: @Secured

Method Security Expressions: e.g. @PreAuthorize

Configure Method Security


                            @EnableGlobalMethodSecurity(prePostEnabled = true)
                            public class WebSecurityConfig
                                    extends WebSecurityConfigurerAdapter {
                                ...
                            }

                        

Authorization of REST API

Role based


                            public class UserBoundaryService {

                                @PreAuthorize("hasRole('ADMIN')")
                                public List<User> findAllUsers() {...}

                            }
				    	

Authorization of REST API

Permission based


                            public class TaskBoundaryService {

                                @PreAuthorize("hasPermission(#taskId, 'TASK', 'WRITE')")
                                public Task findTask(UUID taskId) {...}

                            }
					    

Authorization of REST API

Integration Test


                            public class AuthorizationIntegrationTest {

                                @WithMockUser(roles = "ADMIN")
                                @Test
                                public void verifyFindAllUsersAuthorized() {...}

                                @WithMockUser(roles = "USER")
                                @Test(expected = AccessDeniedException.class)
                                public void verifyFindAllUsersUnauthorized() {...}
                            }
					    

References

Iron-Clad Java: Building Secure Web Applications (Oracle Press, ISBN: 978-0071835886)

Spring Test

Test Pyramid

The Practical Test Pyramid (Martin Fowler)

Why Unit Tests?

What is a Unit Test?

White Box Test

Runs Fast (only some milliseconds)

Tests Public API methods in a single class

Uses Mocking

What is a good Unit Test?

Repeatable (with same results)

Isolated/Independent

May Run Parallelized

“AAA” Unit Test Structure


                            public class HelloWorldTest {
                                private HelloWorld cut;

                                @Before // --> Arrange
                                public void setUp() {
                                    cut = new HelloWorld();
                                }

                                @Test
                                public void verifySayHello() {
                                    String greeting = cut.sayHello("World"); // --> Act
                                    assertThat("Should have got expected greeting",
                                            greeting, is("Hallo World")); // --> Assert
                            } }
                        

Assertion Matchers

Hamcrest Matchers

AssertJ Matchers

Hamcrest Matching


                            import static org.hamcrest.Matchers.*;

                            assertThat(frodo.getName(), is(equalTo(myBiscuit)));
                            assertThat(frodo.getName(), is(not(equalTo(myBiscuit))));

                            assertThat(frodo.getName(), startsWith("Fro"));
                            assertThat(frodo.getName(), endsWith("do"));
                            assertThat(frodo.getName(),
                                            is(equalToIgnoringCase("frodo")));

                            assertThat(fellowshipOfTheRing.size()), is(equalTo(9));
                            assertThat(fellowshipOfTheRing), hasItems(frodo, sam));
                            assertThat(fellowshipOfTheRing), not(hasItem(sauron));
                        

AssertJ Matching


                            import static org.assertj.core.api.Assertions.*;

                            assertThat(frodo.getName()).isEqualTo("Frodo");
                            assertThat(frodo).isNotEqualTo(sauron);

                            assertThat(frodo.getName()).startsWith("Fro")
                                                       .endsWith("do")
                                                       .isEqualToIgnoringCase("frodo");

                            assertThat(fellowshipOfTheRing).hasSize(9)
                                                           .contains(frodo, sam)
                                                           .doesNotContain(sauron);
                        

Mocking

Mock Types

Dummy

Fake

Mock

Spy

Mockito

Simple API

Provides Mock and Spy

Supports Call Verification

Also mocks final/static methods (Mockito 2)


http://site.mockito.org

Mockito Sample


                            @RunWith(MockitoJUnitRunner.class)
                            public class PersonServiceMockTest {
                                @Mock
                                private PersonDao personDao;
                                @InjectMocks
                                private PersonService cut;
                                @Test
                                public void verifySomething() {
                                    when(personDao.findAll()).thenReturn(
                                        Collections.singletonList(
                                             new Person("firstName", "lastName")));
                                    ...
                                }
                            }
                        

Spring Unit Tests

Tests WITHOUT Spring-Container

Mocks for PropertySource, Servlets, Reactive Web, ...

ReflectionUtils

Spring Framework Reference Docs

What is a Integration Test?

Integrated test of multiple units

Medium runtime (minutes)

Tests using external systems

Partly uses mocking

Spring Integration Tests

Tests WITH Spring-Container

SpringJUnitRunner

Caching for Spring Contexts

Dependency Injection

Mocked Beans

Spring Framework Reference Docs

Sample Spring Integration Test


                            @RunWith(SpringJUnitRunner.class)
                            @SpringApplicationConfiguration(classes = Application.class)
                            @TestPropertySource(properties=
                                    {"timezone = GMT", "port: 8081"})
                            @Sql({"/test-schema.sql", "/test-user-data.sql"})
                            @Transactional
                            public class ApplicationTests {
                                @Autowired
                                private ShopManagementService cut;

                                @Test
                                public void verifySomething() { cut.doSomething(); }
                                …
                            }
                        

Spring (Boot) Test Slices

@WebMvcTest

@WebFluxTest

@DataJpaTest

@DataMongoTest

@RestClientTest

...

Spring Boot Reference Docs

Test Driven Development (TDD)

TDD Workflows (Martin Fowler)

Cleanup (“Boy Scout Rule”)

Code Comprehension

Preparation For New Feature

Planned (Long-Term) Refactoring

References

What's New

Spring Boot 2.0

Spring 5.0


What's New?

Infrastructure Updates

JUnit 5 Testing Support

Functional Container Extensions

Reactive Systems / WebFlux

Spring Infrastructure Updates

Java 8 Baseline

Java 9 Automatic Modules

Java EE 7 Baseline

Java EE 8 Support (Servlet 4, Bean Validation 2.0)

HTTP/2 Support (Servlet 4)

Spring Boot Infrastructure Updates

Jetty 9.4

Tomcat 8.5

Hibernate 5.2

Hikari Connection Pool

JUnit 5

Test Context Support for JUnit 4 and JUnit 5

@SpringJUnitConfig = @ExtendWith(SpringExtension.class) + @ContextConfiguration

Functional Container Extensions


                            GenericApplicationContext ctx
                                = new GenericApplicationContext();

                            // Default constructor via reflection
                            ctx.registerBean(First.class);

                            // Explicit constructor via Supplier
                            ctx.registerBean(Second.class,
                            () -> new Second(ctx.getBean(First.class)));

                            // Explicit constructor with BeanDefinition customization
                            ctx.registerBean(Third.class,
                            () -> new Third(ctx.getBean(First.class)),
                            bd -> bd.setLazyInit(true));
                        

Reactive Systems

“Systems that are Responsive, Resilient, Elastic and Message Driven. We call these Reactive Systems.”

The Reactive Manifesto

Reactive Streams & Backpressure

Reactive Systems Implementations

akka

Reactor

RxJava

Spring Web Stacks


References

Spring In Action 5th Edition
(Manning, ISBN: 9781617294945)

This is the End

Questions/Feedback

andreas.falk@novatec-gmbh.de
Follow me on Twitter (@andifalk)