Java_and_Spring

Spring @Value annotated methods

Spring supports @Value methods on:

  • class instance variables (i.e. they are not static)
  • on setter methods - which leads to a workaround for the above static limitation, for example:
static String someVariable

@Value("{someVar}")
public void setSomeVariable(String someVar){
    someVariable = someVar;
}

Java_and_Spring
0
From Executor to CompletableFuture to Webflux

  • Executor (plain threading): allows you to define multiple threads (a pool of threads) which run atomic units of work in parallel. Depending on resources, max number of threads is limited. If on thread is blocked, it will wait until it can continue. (i.e. we have parallelism but no asynchronicity)

  • CompleteableFuture: allows the same as above, however now if a thread is blocked it can switch to another task while waiting for the original work to become unblocked. (i.e. now we have parallelism and asynchronicity)

  • Webflux: allows the same as the above, but where CompleteableFuture is eagerly executed, webflux is designed to be lazily executed (i.e. executed only when required - on subsciption). This allows the design to implement backpressure and control upstream workloads

Java_and_Spring
0
Spring Simultaneous Reactive WebClient Requests

The Spring WebClient is a reactive webclient. In general the workflow with webclient is (in kotlin):

val webClient = WebClient.create("http://x.y.z.")
          .post()
          .uri("/events*/_search")
          .contentType(MediaType.APPLICATION_JSON)
          .accept(MediaType.APPLICATION_JSON)
          .body(BodyInserters.fromObject(someJSON))
          .exchange()
          .flatMap { clientResponse -> clientResponse.bodyToMono(String::class.java) }

In the above case, webClient will be a Mono<String>, which hasn't been executed yet (since there's no subscription). We can gather multiple such "webclients" into an array, and execute all simultaneously by using Flux.merge, for example:

val webClients = ArrayList<Mono<String>>()
webClients.add(webClient) // usually called multiple times

Flux.merge( webClients ).subscribe{ e -> println(e) } //web calls done simultaneously here

Java_and_Spring
0
Reactive Java: flatMapMany

flatMapMany can be used for converting a Mono containing an iterable into a flux.

For example (in kotlin):

val demoMono : Mono<ArrayList<String>> = ...
val demoFlux = demoMono.flatMapMany {
     stringArrayList -> Flux.fromIterable(stringArrayList)
}

//demoFlux will be of type Flux<String>

https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#flatMapMany

Java_and_Spring
0
Spring Postgres Generation Strategy

Best to use GenerationType.SEQUENCE since it is highly optimized for postgres, avoids unnecessary SELECT statements

Java_and_Spring
Postgres
0
Creating singletons without locking

Typically Java singletons are created using double-checked locking (i.e. check if the singleton instance is null, only if it is, go into synchronized code, check if null again and create instance). However, a more elegant way of doing this is to use static code blocks, which are also thread safe. For example:

public class ourSingleton{

    public static ourSingleton INSTANCE;
    private static String demo;

    private ourSingleton(){

        demo = "ourSingleton"; // an example of initializing a variable
        this.INSTANCE = this;
        System.out.println("init done");

    }

    static { // static code block
        new ourSingleton();
    }

    public void printDemo(){
        System.out.println(this); // show that same instance of class is used
        System.out.println(demo); // get access to the initialized variable
    }

}

// [...]

// note that now ourSingleton.INSTANCE can't be null due to the static code block, eliminating
// the need for the typical double-check locking
ourSingleton demo1 = ourSingleton.INSTANCE; 
ourSingleton demo2 = ourSingleton.INSTANCE;

demo1.printDemo();
demo2.printDemo();

/*
outputs:
"
init done               <---- init only called once
ourSingleton@5594a1b5   <---- same output for both instances of singleton
ourSingleton
ourSingleton@5594a1b5
ourSingleton
 "
 */

In kotlin this is even easier by using an object:

object ourSingleton{
    init{
        println("init done");
   }
}

Java_and_Spring
Kotlin
0
Common Spring Class Annotations

@Component @Service @Respository

Java_and_Spring
0
Spring Webflux HTTP request flow

(Incoming HTTP request) ===> Router ===> Handler ===>Response

The Handler can be a Spring component(@Component) / service (@Service)

Java_and_Spring
0
FlatMap use case

In a scenario where you're dealing with an object of type Mono<Mono<String>> (or some other similarly nested object), and you'd like to get access to the inner object, switch from using MAP to FLATMAP

Java_and_Spring
0
Java Atomic Variables

Atomic variables have special "transactional" or "atomic" operations such as getAndSet which allow you to do two operations (like checking the value of a variable, and then setting it), in a transactional/atomic fashion - i.e. the operations (plural) are guaranteed to all succeed or all fail. Atomic variables are usually used in multithreaded sections of code which for performance reasons are avoiding locks such as synchronized blocks

Java_and_Spring
0
Volatile vs Synchronized

  • Volatile

    • field modifier, eg: volatile int demo = 5;
    • Used since threads can have their own copy of memory, and "volatile" ensures there's only one copy of the variable, so all threads will see the same value
  • Synchronized

    • modifies code blocks or methods
    • use locks to ensure only one thread at a time can run the code
    • includes variables, i.e. there is no need for volatile on synchronized variables. (which results in more overhead)

Java_and_Spring
0
Convert Reactive stream to Non-Reactive

  • Convert Mono: [...] .block()
  • Convert Flux: [...] .toIterable()

Java_and_Spring
0
List Access Times (ArrayList vs LinkedList)

  • ArrayList: faster at read/write operations on existing elements due to random access capability
  • LinkedList: faster at adding or removing elements since only 2 pointers need to be updated (remember double linked list)

Java_and_Spring
0
Java Ordered vs Unordered streams

By default, all streams are ordered. That means that any ordered operations on both serial and parallel streams will have the same effect:

// note the use of a TreeSet - which imposes order by sorting
TreeSet<Integer> sequence = new TreeSet<>();
System.out.println("Building sequence");
for (int i=0; i < 1000000; i++) {
    sequence.add(i);
}

System.out.println("Serial stream");
sequence.stream().skip(10000).findFirst().ifPresent(System.out::println);
// output 10000

System.out.println("Ordered Parallel stream");
sequence.stream().parallel().skip(10000).findFirst().ifPresent(System.out::println);
// still outputs 10000 - even though parallel used

System.out.println("Unordered Parallel stream");
sequence.stream().unordered().parallel().skip(10000).findFirst().ifPresent(System.out::println);
// doesnt always output 10000

inserting the unordered() intermediate operation can have performance benefits for downstream parallel operators since they no longer are constrained by order

Java_and_Spring
0
Submitting tasks to Java's ExecutorService

sibmittingToExecutorService

Note that if we submit a lambda that does not return a value, the compiler assumes it impelents the Future interface, but if the lambda returns a value it assumes a Callable interface

Java_and_Spring
0