User Tools

Site Tools


programming:spring

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
programming:spring [2023/11/01 07:31] – removed - external edit (Unknown date) 127.0.0.1programming:spring [2024/07/14 19:36] (current) – [Docker] skipidar
Line 1: Line 1:
 +===== Spring Boot ======
  
 +Spring boot - is a Java framework, which claims to retrieve the default configurations from the libraries loaded to the path.
 +
 +==== Rest Controller ====
 +Logging the exposed endpoints.
 +To log the exposed endpoints the change in the application.properties is required:
 +
 +application.properties
 +<code>
 +logging.level.web=TRACE
 +logging.level.org.springframework.web=TRACE
 +</code>
 +
 +
 +Example output
 +<code>
 +12:14:48.398 [main] TRACE o.s.w.s.m.m.a.RequestMappingHandlerMapping  
 + i.d.l.d.g.RestGroupController:
 + {GET [/rest/, /rest/groups]}: index(String,Optional)
 + {POST /rest/groups, consumes [application/json]}: createGroup(Group)
 + {POST /rest/groups/{groupId}/member}: addUserToGroup(String,String)
 + {DELETE /rest/groups, consumes [application/json]}: deleteRole(String)
 + {GET [/rest/, /rest/groups/member/{memberId}]}: groupsByMember(String)
 + {GET [/rest/, /rest/groups/{id}]}: groupById(String)
 + {DELETE /rest/groups/{groupId}/member}: removeUserFromGroup(String,String)
 +12:14:48.418 [main] TRACE o.s.w.s.m.m.a.RequestMappingHandlerMapping  
 + i.d.l.d.r.RestRoleController:
 + {GET [/rest/, /rest/roles]}: index(String,Optional)
 + {POST /rest/roles/{roleId}/member}: addMemberToRole(String,String,String)
 + {DELETE /rest/roles, consumes [application/json]}: deleteRole(String)
 + {POST /rest/roles, consumes [application/json]}: createRole(Role)
 + {DELETE /rest/roles/{roleId}/member}: removeUserFromRole(String,String,String)
 +</code>
 +
 +===== New project =====
 +Use [[https://start.spring.io/|Spring Initializr]] to generate a new project.
 +
 +Import it to the Idea IDE via: 
 +{{https://lh3.googleusercontent.com/-eDxwVOJ3dzs/Wpp5XRC7hkI/AAAAAAAAADw/L4JVWKY-81gPOnyjZekGnsZt44ccnP6UgCHMYCw/s0/2018-03-03_11-30-52.png}}
 +
 +
 +===== Gradle =====
 +
 +Spring boot is normally either 
 +  * packaged to an executable jar, together with dependencies, or
 +  * packaged as a deployable war, so that it may be deployed to a Tomcat etc.
 +
 +== Running the app ==
 +
 +Running the app with gradle, choosing the port
 +<code>
 +./gradlew bootRun --args='--server.port=8888'
 +</code>
 +
 +
 +== Building a JAR ==
 +
 +To create a Jar with gradle - add the following to build.gradle
 +
 +to automagically resolve dependencies within the current spring boot version - you must apply a special plugin. \\
 +The dependencies will be resolved acording to the BOM - bill of materials. \\
 +Check https://docs.spring.io/spring-boot/docs/2.0.0.RELEASE/gradle-plugin/reference/html/#packaging-executable-jars
 +<code>
 +apply plugin: 'io.spring.dependency-management'
 +</code>
 +
 +Build the jar by using **gradlew**. \\ This will produce a JAR e.g. under **build\libs\PROJECTNAME\complete.jar**
 +<code>
 +../../gradlew BootJar
 +</code>
 +
 +Start the jar
 +<code>
 +java -jar complete.jar
 +</code>
 +
 +{{https://lh3.googleusercontent.com/-nSi9oHOqYxY/Wphe7hn3NKI/AAAAAAAAADY/Pc9ecqMiTpIkSgR9VfKIcDAft7SrIN8wQCHMYCw/s0/2018-03-01_21-13-31.png}}
 +
 +== Building a WAR ==
 +
 +build.gradle
 +<code>
 +apply plugin: 'io.spring.dependency-management'
 +apply plugin: 'war'
 +</code>
 +
 +Build the jar by using **gradlew**. \\ This will produce a JAR e.g. under **build\libs\PROJECTNAME\complete.war**
 +<code>
 +../../gradlew BootWar
 +</code>
 +
 +
 +===== Spring Profiles ======
 +
 +Spring profiles can be activated in multiple ways, e.g. 
 +
 +by setting the environment variable
 +
 +<code>
 +export spring_profiles_active=dev
 +</code>
 +
 +
 +by passing an argument to the java virtual machine
 +<code>
 +-Dspring.profiles.active=dev
 +</code>
 +
 +
 +When activated - you get the option to create a profile dependant properties files.
 +
 +
 +  * .properties files are located in  /resources/application-{profile}.properties
 +    * ./resources/application-dev.properties
 +    * ./resources/application-stage.properties
 +    * ./resources/application-prod.properties    * 
 +  * ./resources/application.properties - is the default file, which is active
 +  * .properties files are additive
 +
 +
 +To pick a default profile - you need to set in in applicaiton.properties
 +
 +application.properties
 +<sxh shell>
 +# the default profile which is used. Can be overridden by specifying the Spring profile as -Dspring.profiles.active or in another way.
 +# without that the "spring.profiles.active" will not fall back to the value "default"
 +spring.profiles.active=dev
 +</sxh>
 +
 +
 +==== Continous build ====
 +Spring boot applications - can be configured to 
 + - react on file changes
 + - rebuild the application e.g. to a jar
 + - redeploy the jar, e.g. to the ThomCat
 +
 +
 +
 +== Step 1 ==
 +
 +Add dev-tools to the dependencies,
 +so that the rebuilt app is hot-swaped on the app server.
 +
 +In **build.gradle**
 +<code>
 +dependencies {
 +
 + // makes Spring boot hot swap rebuilt jar to tomcat
 + developmentOnly 'org.springframework.boot:spring-boot-devtools'
 +}
 +</code>
 +
 +
 +== Step 2 ==
 +
 +In a separate terminal, start the continuous build of application.
 +
 +Do that in a separate terminal, because the command doesn't come back, but listens for file changes.
 +
 +It works in **Vagrant**, in a **Ubuntu guest-VM**,  on **host-Windows**, on a "shared-folder".<br>
 +But unfortunately, changes, originating form **vagrant-host-machine** - are NOT recognized.<br>
 +To trigger rebuild, hot-swap - one needs to change some file in the **vagrant-guest-machine**.
 +
 +Starts continuos build skipping the tests
 +<code>
 +./gradlew build -xtest --continuous
 +</code>
 +
 +To propagate a change triggering a rebuild - you need to modify the file on the guest-system
 +<code>
 +echo "" >> HelloController.java
 +</code>
 +
 +== Step3 Launch the app ==
 +
 +The app will be built and propagated 
 +<code>
 +./gradlew bootRun --args='--server.port=8888'
 +</code>
 +
 +
 +
 +====== Native Image ======
 +
 +# Prerequisites
 +
 +Install java 
 +
 +<code>
 +# java open GraalVM from liberica "native image kit"
 +sdk install java 22.3.r17-nik < /dev/null
 +
 +# switch
 +sdk use java 22.3.r17-nik
 +
 +# set the Java_home
 +source "~/.sdkman/bin/sdkman-init.sh"
 +</code>
 +
 +# Quickstart
 +
 +Build a native image
 +
 +<code>
 +./gradlew nativeCompile
 +</code>
 +
 +[native-image-plugin] Native Image written to: /PROJECTDIR/throttling-enforcer/build/native/nativeCompile
 +
 +Run
 +
 +<code>
 +/PROJECTDIR/throttling-enforcer/build/native/nativeCompile/demo
 +</code>
 +
 +
 +
 +===== Rest Controller ====
 +
 +CRUD repositories ''CrudRepository<Entity, Id>''
 +
 +can create queries by convention.
 +
 +Just name the methods according to the convention https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
 +and they will be mapped to queries.
 +
 +
 +===== API Versioning ====
 +
 +URI Versioning - Twitter
 +  * http://localhost:8080/vl/person
 +  * http://localhost:8080/v2/person
 +
 +
 +Request Parameter versioning - Amazon
 +  * http://localhost:8080/person?version=l
 +  * http://localhost:8080/pcrson?vcrsion=2
 +
 +
 +(Custom) headers versioning - Microsoft
 +  * SAME-URL headers=(X-API-VERSION=l]
 +  * SAME-URL headers=[X-API-VERSION=2]
 +
 +
 +Media type versioning - GitHub
 +  * SAME-URL produces=application/vnd.company.app-vl+json
 +  * SAME-URL produces=application/vnd.company.app-v2+json
 +
 +
 +===== Libs =====
 +
 +==== Hystrix - Circuit Breaker ====
 +https://www.baeldung.com/spring-cloud-netflix-hystrix
 +
 +==== Feign - declarative REST client ====
 +
 +Reduces the glue-code to the minimum.
 +Need only to express - what to call and receive the response DTO
 +
 +https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html
 +
 +
 +
 +
 +<sxh java>
 +package com.in28minutes.microservices.currencyconversionservice;
 +
 +import org.springframework.cloud.netflix.feign.FeignClient;
 +import org.springframework.web.bind.annotation.GetMapping;
 +import org.springframework.web.bind.annotation.PathVariable;
 +
 +@FeignClient(name = "currency-exchange-service", url = "localhost:8000")
 +public interface CurrencyExchangeServiceProxy {
 +
 +    @GetMapping("/currency-exchange/from/{from}/to/{to}")
 +    public CurrencyConversionBean retrieveExchangeValue
 +            (@PathVariable("from") String from, @PathVariable("to") String to);
 +}
 +
 +</sxh>
 +==== Ribbon - Client based load balancer ====
 +
 +Exposes multiple deployments under one URL
 +
 +{{https://s3.eu-central-1.amazonaws.com/alf-digital-wiki-pics/sharex/K9ELIqz2Uf.png}}
 +
 +{{https://s3.eu-central-1.amazonaws.com/alf-digital-wiki-pics/sharex/Od4LgsV7Ij.png}}
 +
 +
 +==== Zuul API Gateway ====
 +
 +API Gateway in SPring
 +
 +
 +
 +
 +==== EUreka Namingserver ====
 +
 +Allows to register / discover services on a naming server.
 +
 +Has a GUI to list available services.
 +
 +{{https://s3.eu-central-1.amazonaws.com/alf-digital-wiki-pics/sharex/qVkyO04yvD.png}}
 +
 +
 +
 +==== Cloud Sleuth - unique tracing id to requests ====
 +
 +adds a unique tracing id to requests
 +
 +
 +
 +==== Zipkin - Distributed Tracing Server ====
 +
 +
 +Central tracing server. 
 +
 +  * Like ELK.
 +  * and CloudWatch
 +
 +
 +{{https://s3.eu-central-1.amazonaws.com/alf-digital-wiki-pics/sharex/ce868zFAte.png}}
 +{{https://s3.eu-central-1.amazonaws.com/alf-digital-wiki-pics/sharex/EG0bVz0lrr.png}}
 +==== Spring Cloud Bus  ====
 +
 +Can use it to refresh the configs of all services,
 +by sending a message via the bus.
 +
 +
 +
 +
 +=====  Docker ===== 
 +
 +== Build manually without gradle ==
 +
 +<sxh java>
 +docker build --build-arg JAR_FILE=build/libs/\*.jar -t springio/demo-consume-api -f src/main/docker/Dockerfile  .
 +</sxh>
 +
 +== Build with Gradle ==
 +
 +You can build a tagged docker image with Gradle in one command:
 +
 +<sxh java>
 +sudo su
 +./gradlew bootBuildImage --imageName=springio/demo-consume-api
 +
 +
 +sudo docker images
 +
 +</sxh>
 +
 +== And run ==
 +
 +<sxh java>
 +sudo docker run -p 8080:8080 springio/demo-consume-api
 +</sxh>