Pages

Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

Thursday, March 7, 2019

Build a distributed system with Hardware and SpringBoot using Robo4J framework on Java 11

Img.0: Robo4J Application running on RaspberryPi with Java 11

Following post is specially dedicated to all Spring framework fans and others :). It looks nowadays that basic knowledge of spring framework is necessary in the Java field. 

I recently asked random attendee at the meetup a question: "... how good do you feel with Java language?". He started his answer with a long Spring story about how good he is in developing and "hacking" Spring using various libraries, streams, message queues etc. ... I don't even remember all technologies he listed.  
  In his answer is also one important point. People know and are able to develop some apps with the Spring framework. This also means that if any new framework wants to be used by a bit wider dev. community it should follow the main stream. 
The Spring Framework is inside such main stream. It provides quite easy way how to prototype and use the latest technologies. Companies are putting some effort here ! :)

1. Wiring up Robo4J and Spring Contexts 
Img.1: Spring Framework and Robo4J Framework runtimes

For quite a long Robo4J didn't have it's own spring-plugin. The upcoming version is coming up with "
robo4j-spring-configuration-starter" plugin. The plugin allows to expose the RoboContext to the spring ApplicationContext. 
It means Robo4J context can be easily injected into the appropriated Spring managed component ( @Component, @Service or @Configuration ). The both contexts Spring and Robo4J are separated from each other (see Img.1).
When the robo4j configuration starter plugin has been added to the application classpath it tries to search by default for the descriptor files "robo4jSystem.xml" and "robo4jContext.xml". 
The "robo4jContext.xml" file is mandatory by default
When the file is not present in resources directory the Robo4j exception will be thrown. 
It doesn't make sense to continue without having anything to wire. 

The starter plugin can be added to the build system descriptor file, for example Gradle: 

...
dependencies {
   implementation "com.robo4j:robo4j-spring-configuration-starter"
   implementation "com.robo4j:robo4j-core"
   implementation "com.robo4j:robo4j-hw-rpi"
   implementation "com.robo4j:robo4j-units-rpi"
   implementation "org.springframework.boot:spring-boot-starter"
   implementation "org.springframework.boot:spring-boot-starter-web"
    ...
}
...

2. Starting Robo4J and Spring together
Having a robo4j starter plugin present together with robo4j context descriptor file ("robo4jContext.xml") we are ready to start the Spring application. The plugin will automatically configure appropriate bean. Following output can be observed in the log file:

: Initializing Spring embedded WebApplicationContext
: Root WebApplicationContext: initialization completed in 1024 ms
: Robo4J context will be initiated
: Initializing ExecutorService 'applicationTaskExecutor'
: Tomcat started on port(s): 8080 (http) with context path ''

The log snippet shows that Robo4J context will be initiated, which means all relevant hardware units and units will be configured and started. 

3. Building up distributed system with hardware 
Following section describes how to build a simple distributed system. The distributed system consists from two parts: Robo4J Spring application and pure Robo4J application. The both applications are configured over Robo4J auto-discovery mechanism. The auto discovery mechanism allows automatic Robo4J units configuration but more details are over the scope of this article (see Img.2.)
Img.2.: Example distributed application using Robo4J & Spring with auto-discovery mechanism
3a. Robo4J Spring application 
The Img.2. shows how the spring application has the access to the Rob4J context. The Robo4J context is instantiated and configured by the starter plugin. The rest of spring application is just standard, we create one @RestController and @Service. 

@RestController
public class MessageRestController {

    private final LcdService lcdService;

    @Autowired
    public MessageRestController(LcdService lcdService) {
        this.lcdService = lcdService;
    }

    /**
     * Hello world get
     *
     * @return default message
     */
    @GetMapping("/")
    public String index() {
        return "Hello Robo4J Spring World!";
    }

    /**
     * POST end-point for sending message to the Robo4J context
     *
     * @param message simple DTO object
     * @return message content
     */
    @PostMapping("/lcd")
    public String sendMessage(@RequestBody SimpleMessage message) {
        return lcdService.displayMessage(message);
    }
}

The LcdService provides the access to the Robo4J context and propagates the message deeper to the Robo4J context. Inside the RoboContext is found the appropriate unit (example: RemoteLcdUnit). The unit contains the method that sends the message to the remote Robo4J system over the TCP/IP through the Robo4J Unit.

public class RemoteLcdUnit extends RoboUnit<LcdMessage> {
...
    @Override
    public void onMessage(LcdMessage message) {
        RoboContext discoveredContext = LookupServiceProvider
                    .getDefaultLookupService()
                    .getContext(remoteContext);
        if (discoveredContext != null) {
            discoveredContext
                .getReference(unitName)
                .sendMessage(message);
        }
    }
...
}

3b. Robo4J Application
The remote Robo4J application receives the message, deserializes it and sends it to the consumer unit (AdafruitLcdUnit). This unit is registered inside the Robo4J context. 
The application context descriptor ("robo4jContext.xml") looks very simple as the rest is managed by the framework itself.
See the descriptor file:

<robo4j>
    <roboUnit id="lcd">
        <class>com.robo4j.units.rpi.lcd.AdafruitLcdUnit</class>
        <config name="com.robo4j.root">
            <value name="bus" type="int">1</value>
            <value name="address" type="int">0x20</value>
        </config>
    </roboUnit>
</robo4j>

It uses the hardware abstraction provided by the "robo4J-units-rpi" module. 

4. Running both Applications
We have prepared both parts of our simple distributed system. Let's run them. 
Both of them are using OpenJDK 11! In case of RaspberryPi it's the Liberica JDK 11.0.2. 
The Img.2. shows that the communication with the LCD Hardware is possible through Spring @RestController. The RestController provides the POST method, that accepts JSON format of the SimpleMessage class. 

url: POST http://localhost:8080/lcd
body: {"content" : "Java 11, Robo4J \n SpringBoot"}

5. Conclusion
The described example shows how simple it is to build up and run the distributed system using the real hardware units on pure Java. 
The Robo4J Framework allows a simple connection with the Spring kind of applications. It is not necessary to write any line of code in other than JVM language (Java, Kotlin, Scala, JRuby ;). It is also not necessary to use some difficult data transformations written in C in order to put the sensors outputs on the various message queues. 
Robo4J allows to build an event driven systems that are communicating between them selves by passing messages. 
The example additionally shows that  the final system may be distributed over many different JVMs and Robo4J framework takes care about the communication under the hood. This allows to be fully concentrated on the system logic development. 

The following approach supports, nowadays often discussed, "evolutionary architecture" one, which goal is to propose the way how to utilize a different kind of design patterns and desired technologies. 

Happy Coding!

Saturday, December 1, 2018

Deep dive into distributed tracing with Spring Boot and Flight Recorder

Motivation
At Oracle CodeONE 2018 Marcus Hirt held very interesting presentation called "Diagnose Your Microservices: OpenTracing/Oracle Application Performance Monitoring Cloud [DEV5435]". This presentation gave an audience pretty intensive quick inside view to the large scale cloud application tracing.
Although his talk was not recorded, he has created pretty nice example, Robotshop, that he open-sourced.  You can find all information in his recently published blog posts (CLICK HERE). 
  His post also touched the Application Performance Management (APM) solutions that has been formed before OpenTracing standard has born.
  All intensive work crystallized into the previously mentioned OpenTracing standard, but what is it ?  As the web-site says It's a vendor-neutral APIs and instrumentation standard for distributed tracing (note: it's more about instrumentation). Companies like Datadog, Skywalking, Jaeger, LightStep are actively contributing into this standard, which is great news, it shows that the topic is pretty hot and we should probably think about it.
  Let's get back to my post topic. Many developers, world wide, are using spring-boot libraries stack to create a Spring based applications.

In this post you will learn how to connect some tracers (Jaeger, Zipkin) with your project. You will also learn how to connect Java Mission Control/Java Flight Recorder for very deep service analysis.

The post also stress the question how worthful it is to think about the application logging strategies. Why ? To be honest, who is reading couple of gigabytes big log files in order to spot the root case ;).  Who is writing continually very sophisticated regular expressions to get such information ?.

The source code is available on my GitHub account: [here] branch: [vehiclefactory-jfr-tracer]

Introduction
   In my previous post I've shown how to configure spring-boot project using opentracing [CLICK_HERE]. It was just  a simple producer consumer pattern based demo. In the following text we create a VehicleShop project with 4 independent micro-services : VehicleShopService, FactoryService, StorageService, CustomerService. All those services are spring-boot based ones.
The example project uses the Gradle build system. It does contain all services and you can start each of them separately, in docker or you can configure the docker-compose file.

  The monitoring is about to "extracting meaningful stories" from the defined Metrics (four golden signals, RED method etc.) or Logs (app events, stack-traces etc.), in other hand tracing is more about Spans, Spans analysis. Tracking gives the answer to individual request.
  What is such Span ? The Span is the primary building block of distributed trace. Such individual Span represents the work done within the distributed system. How we define such Span ?
By the opentracing standard Span has following properties:

  • an operation name
  • start and finish timestamp
  • key:value Span Tag
  • a SpanContext 
    • carries date across the process boundaries
Having defined Span we define the space from where such Span is coming from. Let's consider one individual Span,  we name it "Active Span". Such Span is responsible for the work accomplished by the surrounding code. Active Span has actually one very important property:
  • it can be only one Active Span inside the thread at time T.
Such property is managed by the Scope, which formalizes the activation and deactivation of a Span. 
OpenTracing standard defines the term Trace. Trace represents the interface which implementation creates the Spans.

The VehicleShop example 
Previously has been mentioned that VehicleShop project is the collection of micro-services. Those services are exchanging information between each other according to the schema (Img.1.)
Img.1.: VehicleShop project schema
The Customer service represents the set of the schedulers. Those schedulers generate a traffic that simulates the multiple customers behaviour like buying , searching or upgrading the car. The VehicleShop service sends requests to the vehicle elements storage (StorageService) in order to get information about available pieces. The VehicleShop sends requests to the FactoryService to check which cars are available to sell out.  The FactoryService before any car gets produces send the request to the StorageService whether the VehicleElement, necessary to build the car, are available (Img.2.)
Img.2.: example communication diagram
All services have enabled opentracing support by the following libraries:
opentracing-spring-jaeger-cloud-starter
opentracing-spring-zipkin-cloud-starter

when you add any of those libraries into the project class-path they will automatically configure the default tracer settings. You simple can start the tracer inside the docker container:
$docker run -d -p 6831:6831/udp -p 16686:16686 jaegertracing/all-in-one:latest
$docker run -d -p 9411:9411 openzipkin/zipkin:latest

Of course you can use the custom configuration of the tracer, but in such case you need properly re-configure spring @Configuration beans. The another alternative is to use the environment variables.
When the all services are up, you can open the Jaeger UI : http://localhost:16686/ (Img.3.)

Img.3.: JagerUI : VehicleShopService traces
The interface allows to analyze taken spans and observe a real application communication over the micro-services (Img.4.)

Img.4.: Tracing a specific request 
The Jaeger UI offers one very neat feature. It's ability to compare two spans by IDs. The span Id you can get from available traces (Img.5.)

Img.5.: Span comparison
As you can see the example architecture is very simple but it already shows the value of the tracing.

  Let's connect the example with Java Mission Control / Flight Recorder and see the traces from different perspectives.
  As the tracing provides you the ability to get the view into the application communication layer and here recognizing some potential issues, when the JFR is attached to the micro-service JVMs, you can directly analysize the potentially suspicious code.  It means that the trace may be very good initial signal to start the investigation.

Attaching Flight Recorder to the VehicleShop example
Marcus has recently published very neat library java-jfr-tracer . This library allows to record Scopes and Spans into the JDK Flight Recorder for very deep analysis.  To enable such feature it necessary to add following library into the project.

gradle.build:
implementation "se.hirt.jmc:jfr-tracer:0.0.3"

After having the library we need to register a new JFR Tracer, which is the wrap of the OpenTracing tracer, in following way:

@Autowired
public CustomTracerConfig(Tracer tracer) {
     GlobalTracer.register(new DelegatingJfrTracer(tracer));
}

Now information provided by tracers will be available also through the Flight Recorder interface through recorder Events (Img.6.)

Img.6.: Flight Recorder with recorded spans
The Flight Recorder gives you a chance to recognize a suspicious trace ids which may bring the significant value during the issue solving. The Spring framework is not just a one thread framework and using it may bring/open potential challenges (Img.7.)

Img.7.: VehicleShop threads view


Summary
Distributed Tracing is great and challenging.  As you can see from the image (Img.7.) there are bunch of threads and by adding new libraries to the project a new are coming. Distributed tracing is opening the way how to understand to what is really happening across the micro-services.
It means distributed tracing allows/supports:
  • distributed transaction monitoring
  • performance and latency optimization 
  • root cause analysis
  • service dependencies analysis
  • distributed context propagation
The only OpenTracing standard implementation may not be enough. Often you may need to know what is happening inside the specific one and the trace may forward you directly to the issue.

Using Flight Recorder for Distributed Tracing is like using "weapon" from different galaxy, it's not the silver bullet but it may be very close to it .

Enjoy the Demo and happy tracing!



Monday, November 26, 2018

How to configure distribute tracing for spring-boot apps on Java 11


One of the big challenges in micro-services world is ability to understand what the system really does and being able to spot the potentials issues before the get propagated into the production.  The performance of JVM is most probably not the case why the system does not respond properly or provides a scary results. Aside of it a micro-services can be a really messy to debug especially when certain number of them has been reached.

In following post you will get an idea how the tracing can implement for spring-boot based applications. The blog post uses two libraries Jaeger and Zipkin. Both libraries are according to OpenTracing standard. The OpenTracing standard provides vendor-neutral APISs and instrumentation. 

Example source code is available on my GitHub account, project: spring-profile-logging

Motivation
The example project consists from two application Consumer and Producer, micro-services. Those two micro-services are communicating between each other over the HTTP protocol. (see Img.1.)
Img.1.: Architecture overview 

The basic idea behind the demo is the specific vehicle type construction and the process can be traced. For the demo simplification has been used two micro-services interacting between each other. The Producer contains the set of the Schedulers that are producing different types of HTTP requests (GET, PUT, POST ...). The Consumer is processing those requests.  It's possible to participate on the running process by using the consumer API: 

GET: http://<tracing-consumer>:<port>/shop/models
GET: http://<tracing-consumer>:<port>/shop/vehicle?id=<vehicle_id>
POST: http://<tracing-consumer>:<port>/shop/models/vehicle
PUT: http://<tracing-consumer>:<port>/shop/models/vehicle

The JSON vehicle model is very simple: {"id": 33, "name" : "some care2"}, but you can find the the model definition in VehicleModel class. 

The example can be used for low-level profiling using Java Mission Control / Flight Recorder to deep dive into the caused latencies.  How to run locally the last version of JMC see my previous blog post.

Technologies
As was mentioned before the project is the collection of two different spring-applications running upon the Java 11 and above (you can use previous versions ;)

The gradle.libraries files contains used versions:

projectJavaVersion = "11"
springBootStarterVersion = "2.1.0.RELEASE"
openTracingSpringVersion = "0.2.1"
openTracingJaegerSpringVersion = "0.2.2"
openTracingZipkinSpringVersion = "0.2.0"

Understanding consumer and producer applications 
The relation between producer and consumer apps is obvious from  the schema (see: Img.1.). Both of them use @EnableAutoConfiguration feature provided by spring to configure the Tracers.  It means spring starter of the specific tracer configures it based on variables application provides. The applications are configured by using YAML file application.yml with properties, example. 

spring:
  application:
    name: ${APPLICATION_NAME}
server:
  port: ${DEMO_PORT}

tracing:
  consumer:
    url: ${DEMO_CONSUMER_URL}
opentracing:
  jaeger:
    udp-sender:
      host: ${OPENTRACING_HOST}
      port: ${OPENTRACING_PORT}

The variables can be configured on demand (local environment , docker).  The consumer application may look in following way: 

@SpringBootApplication
public class ConsumerApp {

    public static void main(String[] args) {
        new SpringApplicationBuilder(ConsumerApp.class)
                .web(WebApplicationType.SERVLET)
                .run(args);
    }
}

Aside of it Producer application may use lightly different approach of configuring spring-boot framework. 

@EnableAutoConfiguration
@EnableScheduling
@RestController
public class ProducerApp {
...
    @Scheduled(fixedRate = 10000)
    public void postNewVehicle() {
        VehicleModel vehicle = new VehicleModel();
        vehicle.setName("vehicle" + vehicleNumber.getAndIncrement());
        ResponseEntity<VehicleModel> response = restTemplate.postForEntity(consumerServiceUrl + "/shop/models/vehicle",    vehicle, VehicleModel.class);
    }
...
    public static void main(String[] args) {
        SpringApplication.run(ProducerApp.class,args);
    }
}

Running producer consumer demo
Now we have configured both applications. The project offers couple of option how it can be run. You can use your favorite IDE to run it locally, as separate docker images or use docker-compose. We decided to use the docker compose file which provide us better comfort and all three part run isolated.  The  docker-compose.yml may look in following way: 

version: "3.7"

services:

  jaeger:

    container_name: jaeger

    image: jaegertracing/all-in-one:latest

    ports:
     ...

    networks:

      - simulation

  tracing-consumer:
    container_name: tracing-consumer
    depends_on:
      - jaeger
    environment:
      APPLICATION_NAME: "docker_tracing_consumer"
      DEMO_PORT: 8091
      OPENTRACING_HOST: jaeger
      OPENTRACING_PORT: 6831
    ports:
      - "8091:8091"
      - "9999:9999"
    networks:
    - simulation
  tracing-producer:
    container_name: tracing-producer
    depends_on:
    - jaeger
    - tracing-consumer
    environment:
     ...
    ports:
      - "8092:8092"
    networks:
      - simulation

Getting some result from Jaeger Tracer
As you may have noticed the example code uses only Jaeger tracer. The Jaeger project has been open-source by Uber technologies. In order you want to use Zipkin inside the docker-compose file there are necessary small modifications, but Zipkin tracer can be run fully locally. 
Let's run the project: 
$docker-compose -f ./docker/docker-compose.yml up
by executing $docker ps command we can see 3 container are running.  
The producer schedulers already start sending requests to the consumer.  Inside the web browser we can access the Jaeger UI on configured port (see Img.2):
http://localhost:16686

Img.2.: Jaeger UI
On the left conner is possible to select  configured micro-service. As tracing is basically span analysis we can track down each span that is included inside the trace:
Img.3.: Jaeger Tracing spans
Final Thoughts
Following simple example has shown the power of instrumentation using spring-boot together with OpenTracing standard. The tracing technology opens the door to see your real micro-services architecture, not just guess. It allows you to spot some initial problems during the development. Those problems can be latter more investigated by using different technologies like Java Mission Control / Java Flight Recorder. 
The example also shows the importance of tracing in order to clearly understand the system behaviour. 

Enjoy The Demo (here)


Thursday, November 10, 2016

Template Engines at One : Spring-Boot and Engines setup review after Deprecated Velocity.


  Let’s dive for while into the Template engines problematics of MVC based frameworks. 

  In next minutes the text will brings you to the mystery of different templating possibilities supported by Spring Boot framework.   

  Spring Boot became to be very popular because of its configuration possibilities  and full support of spring based application. Spring Boot follows the simple moto “just run”, wait a sec, no, it’s not NIKE. In the age of “Micro-Services” and cutting monoliths this motto, in     Spring way, has quite nice impact on desired application prototyping.  

  I don’t think there is any necessity to go much deeper into the Model View Controller (MVC) design pattern issue because there is a mass of other articles which can be easily found. 
  The main intent of the following text is to review the setups of the different Java Template Engines for Spring based application. How can even such question come into the focus ?   
  Well, the reason is that Velocity Engine is deprecated for a while and a lot developers around the globe need to find well fitting alternative.
  Let’s begin and define the set for our test. We put into the comparison following engines:

  1. Apache Velocity
  2. Apache FreeMarker 
  3. Thymeleaf
  4. Pebble
  I’ve not included JSP Engine because JSPs are mature technology and has been around since the early days, which means that thousands and more articles has been already written around. The fact that JSPs are really hard to beat in case of raw speed stays but this is not in the focus now.

  By having prepared MvcConfiguration class which extends WebMvcConfigurerAdapter:
@Configuration
@EnableWebMvc
public class MvcConfiguration extends WebMvcConfigurerAdapter {
...
  The mentioned MvcConfiguration class must define @Bean ViewResolver that can negotiate about the proper request ViewResolver.
@Bean(name = "viewResolver")
public ViewResolver contentNegotiatingViewResolver( ContentNegotiationManager manager) {
        List resolvers = ...
  Each of mentioned template engines has under the folder webapp its own directory dedicated only to it. Such directory (velocity, freemarker, thymeleaf and pebble) contains only engine related files.
  And here is the Deprecated engine that has been widely used over last several years: 

Apache Velocity 
   Apache Velocity Template Engine is used for the comparison and also to make testing other three alternatives (FreeMarker, Thymeleaf and Pebble) little bit simpler. Apache Velocity is one of Jakarta project. Each of Velocity templates is processed but not compiled to Java which supports better code separation.
Following code snippets configures Spring Boot ViewResolver and enables the Velocity usage:
...
@Bean(name = "velocityViewResolver")
public ViewResolver getVelocityViewResolver() {
   VelocityViewResolver resolver = new VelocityViewResolver();
   resolver.setSuffix(".vm");
   resolver.setCache(true);
   return resolver;
}
...
  Having configured ViewResolver we need to add it to the contentNegotiatingViewResolver @Bean which  gives us the access to the ContentNegotiationManager. The ContentNegotiationManager provides look up methods to the file extensions based on MediaType. In the example case will be 
used based for specific engine file suffix search
...
@Bean(name = "viewResolver")
public ViewResolver contentNegotiatingViewResolver( ContentNegotiationManager manager) {
   List resolvers =
      Arrays.asList(getVelocityViewResolver(),
      ...
  Inside the directory webapp we create directory velocity and simple velocity template. We call the file test.vm and it will contain following content:
<html lang="en">
<head>
    <title>Test Velocity</title>
</head>
<body>
<h2>This is $test</h2>
</body>

</html>
  We are almost done. There is only one more important thing. For setting up specific Spring Boot application properties has been used configuration file called application.properties located inside the project resources folder. 
In velocity case it will contain loader path setup (ps: you can customise it)
spring.velocity.resourceLoaderPath=/velocity/
  Congratulation!  Deprecated Template Engine Velocity us UP and Running, but this is not all what we want to achieve so we continue with the next alternative:

Apache FreeMarker
  The 1st considered candidate as the replacement to Velocity is the FreeMarker. FreeMarker is currently coming from the Apache projects incubator supporeted by Apache Software Foundation (ASF). ASF puts its effort to support FreeMarker development, which is very good sign, for long life. The one more reason may be that FreeMarker is widely used across the Apache family projects, good example is newly accepted NetBeans one!
Let’s add FM support to sample project by configuring ViewResolver in the following way:
@Bean(name = "freeMarkerViewResolver")
public ViewResolver getFreeMakerViewResolver() {
   FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
   resolver.setSuffix(".ftl");
   resolver.setCache(true);
   return resolver;
}
  We need to add also properly FreeMarker ViewResolver to the ContentNegotiationManager inside the MvcConfiguration @Bean:
@Bean(name = "viewResolver")
public ViewResolver contentNegotiatingViewResolver( ContentNegotiationManager manager) {
   List resolvers =
      Arrays.asList(getVelocityViewResolver(),
                    getFreeMakerViewResolver(),
                    ...
  Now is the sample application ready for the simple FreeMarker templates. Inside the webapp folder we create new folder called freemarker and we add following two files:
index.ftl
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Test applicaiton</title>
</head>
<body>
<h2>This is test application Main sample site</h2>
</body>

</html>
and magic.ftl file which will contains simple FM tags
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Magic Spell: ${word}!</title>
</head>
<body>
<h2>MagicHappens by word: ${word}!</h2>
</body>

</html>
but hold on it’s not enough in case of FreeMarker we can not forget to properly add configuration inside the application.properties file:
spring.freemarker.templateLoaderPath=/freemarker/
  Now it’s done we have FreeMarker up and running inside our sample project!
Well done and we can move to the next one which is:

Pebble Template Engine
  It’s quite new player on the market. It promises quite useful inheritance features and easy to read syntax but comment this is out of the scope of this article. This article is focused on ViewResolver Configuration and having it up and running as the motto of Spring Boot. As the first step we need to again configure ViewResolver properly. In case of Pebble, all is slightly more complicated because the result of the configuration is extremely closely connected with the Servlet config it self. Let’s see, we go back again in the @Bean  MvcConfiguration and we add: 
@Bean(name="pebbleViewResolver")
public ViewResolver getPebbleViewResolver(){
   PebbleViewResolver resolver = new PebbleViewResolver();
   resolver.setPrefix("/pebble/");
   resolver.setSuffix(".html");
   resolver.setPebbleEngine(pebbleEngine());
   return resolver;
}
  Previous has been mentioned that Template may support configuration by application.properties file, this is currently not the case of Pebble. We need to configure all manually and we need to define more Pebble related @Bean
@Bean
public PebbleEngine pebbleEngine() {
  return new PebbleEngine.Builder()
                .loader(this.templatePebbleLoader())
                .extension(pebbleSpringExtension())
                .build();
}

@Bean
public Loader templatePebbleLoader(){
   return new ServletLoader(servletContext);
}

@Bean
public SpringExtension pebbleSpringExtension() {
  return new SpringExtension();
}
  As you can see the templatePebbleLoader @Bean requires direct access to the ServletContext which needs to be injected into the configuration @Bean
@Autowired
private ServletContext servletContext;
...
  It also means that by doing this Pebble takes over the any created servlet and will play default choice when any other exists. This may not be bad but when you want to use Pebble and for example Thymeleaf together, you need to do slightly more Spring hacking.

Now we have prepared Pebble configuration so let’s create new pebble folder under the webapp and add a new template file pebble.html
<html>
<head>
    <title>{{ pebble }}</title>
</head>
<body>
{{ pebble }}
</body>

</html>
Now we are ready, Pebble is up and running and we can go directly to the last option: 

Thymeleaf Template Engine
  Thymeleaf present itself as the ideal choice for HTML5 JVM web development, it may be true but it’s over the scope of this article and you can try this claim by using the example project over my GitHub account. Thymeleaf has better Spring support  than Pebble. This allows us to use for its configuration application.properties file and add Thymeleaf setup options there:
spring.thymeleaf.prefix=/thymeleaf/
spring.thymeleaf.suffix=.html
but the rest is very similar to Pebble,
@Bean(name = "thymeleafViewResolver")
public ViewResolver getThymeleafViewResolver() {
  ThymeleafViewResolver resolver = new ThymeleafViewResolver();
  resolver.setTemplateEngine(getThymeleafTemplateEngine());
  resolver.setCache(true);
  return resolver;
}
  Thymeleaf takes similarly control over the any new Servlet creation as you can see in MvcConfiguration @Bean
@Bean(name ="thymeleafTemplateEngine")
public SpringTemplateEngine getThymeleafTemplateEngine() {
  SpringTemplateEngine templateEngine = new SpringTemplateEngine();
  templateEngine.setTemplateResolver(getThymeleafTemplateResolver());
  return templateEngine;
}

@Bean(name ="thymeleafTemplateResolver")
public ServletContextTemplateResolver getThymeleafTemplateResolver() {
  ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
  templateResolver.setPrefix("/thymeleaf/");
  templateResolver.setSuffix(".htm");
  return templateResolver;
}
  Now it’s time to add ViewResolver into the content negotiation configuration: 
@Bean(name = "viewResolver")
public ViewResolver contentNegotiatingViewResolver( ContentNegotiationManager manager) {
   List resolvers =
      Arrays.asList(getVelocityViewResolver(),
                    getFreeMakerViewResolver(),
//                  getPebbleViewResolver()
                    getThymeleafViewResolver()
                );
      ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
      resolver.setViewResolvers(resolvers);
      resolver.setContentNegotiationManager(manager);
      return resolver;
}
...
  As the last step we create again under what webapp folder new folder called thymeleaf and we add thyme.htm file there: 
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Getting Started: Thymeleaf</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'HERE IS, ' + ${thyme} + '!'" />
</body>

</htm>
  And big applause you have successfully configured all four Spring Boot Supported Template Engines. 
At the end of the configuration section, it is important to point out that each of engines has assigned its own @Controller which is responsible for proper output generation: 

1.Velocity Controller 
@Controller
public class VelocityHelloController {

    @RequestMapping(value = "/velocity")
    public String test(Model model){
        System.out.println("Test");
        model.addAttribute("test", "Here is Velocity");
        return "test";
    }

}
2. FrameMarker
@Controller
public class FMHelloController {


    @RequestMapping("/")
    public String index(){
        System.out.println("INDEX");
        return "index";
    }

    @RequestMapping("/magic")
    public String magic(Model model, @RequestParam(value = "word", required=false, defaultValue="MagicHappens") String word) {
        System.out.println("MAGIC");
        model.addAttribute("word", word);
        return "magic";
    }

}
3. Pebble
@Controller
public class PebbleHelloController {

    @RequestMapping(value = "/pebble")
    public String something(Model model){
        System.out.println("Pebble");
        model.addAttribute("pebble", "The Pebble");
        return "pebble";
    }
}
4.Thymeleaf
@Controller
public class TLHelloController {


    @RequestMapping(value = "/thyme")
    public String something(Model model){
        System.out.println("Thymeleaf");
        model.addAttribute("thyme", "The Thymeleaf");
        return "thyme";
    }

}

Configuration experience Summary
  Now is the right time to write few last words about the general feeling from all mentioned possibilities. I don’t want to highlight any of those tested choices as the best replacement to the Deprecated Velocity Template Engine but from the configuration experiences and Spring framework support, I’d choose FrameMarker. By Choosing FreeMarker I won’t be limited in using Velocity and any other option in parallel, but as has been mentioned before doing right choice is out of the scope of this article. 
I've created sample gradle project which imports all Temple engines starter. This setup can be find inside the configuration file build.gradle


dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
    compile("org.springframework.boot:spring-boot-starter-freemarker:$springBootVersion")
    compile("org.springframework.boot:spring-boot-starter-velocity:$springBootVersion")
    compile("org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion")
    compile("com.mitchellbosecke:pebble-spring-boot-starter:$pebbleVersion")
    testCompile "junit:junit:${junitVersion}"
}

Enjoy the sample project in testing yours choice !!!


used versions:
Java JDK: 1.8.111
Spring-Boot:  1.4.1.RELEASE

Pebble: 2.2.3