11 Mayıs 2022 Çarşamba

SpringCache Caffeine

Giriş
Açıklaması şöyle
The spring boot automatically configures the CaffeineCacheManager if Caffeine is found in the classpath.
Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>com.github.ben-manes.caffeine</groupId>
  <artifactId>caffeine</artifactId>
</dependency>
Bir örnek burada

25 Nisan 2022 Pazartesi

SpringMVC ResponseBodyAdvice Arayüzü - Response Nesnesi Değiştiren Interceptor

Giriş
Şu satırı dahil ederiz
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
Spring ile hazır gelen advice'lardan bir tanesi. Açıklaması şöyle
It helps us to modify the message i.e response object before it is written to the Response body.
supports metodu
İmzası şöyle
boolean supports(MethodParameter returnType,
                 Class<? extends HttpMessageConverter<?>> converterType)
Açıklaması şöyle
The MethodParameterargument helps us to check from which class and method the Request is coming and return the boolean value.  Based on it the BeforeBodyRead Method is Called.
beforeBodyWrite metodu
İmzası şöyle
T beforeBodyWrite(@Nullable T body,
                  MethodParameter returnType,
                  MediaType selectedContentType,
                  Class<? extends HttpMessageConverter<>> selectedConverterType,
                  ServerHttpRequest request,
                  ServerHttpResponse response)
Örnek
Şöyle yaparız
@RestControllerAdvice
public class DemoControllerAdvice implements 
  ResponseBodyAdvice<Map<String, String>> {

  @Override
  public boolean supports(
    MethodParameter returnType, 
    Class<? extends HttpMessageConverter<?>> converterType) {

    String className = returnType.getContainingClass().toString();
    String methodName = returnType.getMethod().toString();
    if (className.contains("DemoController_") && 
        methodName.contains("ResponseModification")) {
      return true;
    }
    return false;
  }

  @Override
  public Map<String, String> beforeBodyWrite(
    Map<String, String> body, 
    MethodParameter returnType,
    MediaType selectedContentType, 
    Class<? extends HttpMessageConverter<?>> selectedConverterType,
    ServerHttpRequest request, 
    ServerHttpResponse response) {

    body.put("body_data", "Age of the Person is 25 years");
    return body;
  }
}
Örnek
Şöyle yaparız. Burada @RestControllerAdvice yerine @ControllerAdvice kullanılıyor
@ControllerAdvice
public class ResponseBodyInterceptor implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { ... return body; } }

SpringMVC RequestBodyAdviceAdapter Sınıfı

Giriş
Spring ile hazır gelen advice'lardan bir tanesi

Örnek
Şöyle yaparız
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;

@ControllerAdvice
public class RequestBodyInterceptor extends RequestBodyAdviceAdapter {

  @Autowired
  HttpServletRequest request;

  @Override
  public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
    ...
    return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
  }

  @Override
  public boolean supports(MethodParameter methodParameter, Type targetType, 
    Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
  }
}

18 Nisan 2022 Pazartesi

SpringCloud Gateway GlobalFilter Arayüzü

Giriş
GlobalFilter ve GatewayFilter benziyorlar

Örnek
Şöyle yaparız
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

public class PostGlobalFilter implements GlobalFilter, Ordered {

  ...

  @Override
  public int getOrder() {
    return 0;
  }
}
Metodun içi şöyle
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  return chain.filter(exchange).then(Mono.fromRunnable(()->{
    ServerHttpResponse response = exchange.getResponse();
    HttpStatus responseStatus = response.getStatusCode();
    if(responseStatus.equals(HttpStatus.BAD_REQUEST)){
      String newResponseBody =
      "<body>\n" +
      "<h1 style=\"color:red;text-align:center\">Bad Request </h1>\n" +
      "<p>If you are seeing this page it means response body is modified.</p>\n" +
      "</body>";

      DataBuffer dataBuffer = response.bufferFactory()
        .wrap(newResponseBody.getBytes(StandardCharsets.UTF_8));
      response.getHeaders().setContentLength(newResponseBody.length());
      response.writeWith(Mono.just(dataBuffer)).subscribe();
      exchange.mutate().response(response).build();
    }
  }));
}


1 Nisan 2022 Cuma

Spring Profiles Kullanımı

Giriş
Açıklaması şöyle. Özellikle test kodlarında çok işe yarar.
Spring Boot provides profiles that help to create environment-specific configurations and stereotypes in the applications. 
Kullanılabilecek anotasyonlar şöyle

1. Spring boot 3.0.x ve Ötesi
Açıklaması şöyle
In spring boot 3.0.x onwards all the deprecated methods of 2.7.x have been removed. spring.profiles.include one of them that has been removed from spring boot. Instead of spring.profiles.include, spring boot has introduced spring.profiles.group in spring 2.4.x onwards. you have to make multiple groups based on profiles like spring.profiles.group.{env}={profile1},{profile2} in application.properties file.
Açıklaması şöyle
spring.profiles={env} is also removed, use spring.config.activate.on-profile={env}.
Örnek
Şöyle yaparız. Çalışılan ortam dev veya prod ise belirtilen profile dosyalar yüklenir
spring.profiles.group.dev=common
spring.profiles.group.prod=common
Yani ortam dev ise
application-common.properties
application-dev.properties
yüklenir

Örnek
Açıklaması şöyle
Profile Groups is another feature added in Boot 2.4. using this feature you can have multiple profiles activated under one group of profiles.

spring.profiles.group.development[0]=devdb 
spring.profiles.group.development[1]=devkafka

The application can now be started using --spring.profiles.active=development to active the development, devdb and devkafka profiles in one hit.
2. Spring boot 2.4.x - 2.7.x
Açıklaması şöyle. Yani eskisi gibi çalışabilmek mümkün
In spring boot 2.4.x spring.profiles.include marked as deprecated which will be removed in spring boot 3.0.0

To support the previous configuration, you can add the below line in application.properties.

spring.config.use-legacy-processing=true
3. Spring boot 2.3.x veya Öncesi
Active profile ismi verilir. Aktif profile isimleri birden fazla verilebilir ve virgül ile ayrılır. 4 yöntem var. 
1. Komut Satırı --spring.profiles.active kullanımı
2. Komut Satırı -D kullanımı
3. envrironment variables
4. application.properties dosyası

Örnek
Eğer active profile yanında ortak bir dosyayı daha yüklemek istersek spring.profiles.include kullanılır. Şöyle yaparız
spring.profiles.include=common
spring.profiles.active=dev
Böylece şu dosyalar yüklenebilir.
application-common.properties
application-dev.properties


1. Komut Satırı - --spring.profiles.active
--spring.profiles.active seçeneği kullanılır. 
Örnek
Şöyle yaparız.
start "Service 1" /B java.exe -jar service1.jar --spring.profiles.active=local
2. Komut satırı - java -Dspring.profiles.active
Aslında --spring.profiles.active ile -D--spring.profiles.active temelde aynı şeyler.
Örnek
Şöyle yaparız
java -jar -Dspring.profiles.active=dev application.jar
# or
java -jar application.jar --spring.profiles.active=dev
Örnek
Şöyle yaparız. Burada dev ve container isimli iki tane profile etkinleştiriliyor.
java -Dspring.profiles.active=dev,container -jar build/libs/dockeriser-0.0.1-SNAPSHOT.jar
3. environment variables
Örnek
Şöyle yaparız
export spring_profiles_active=dev
Örnek
environment variables koddan da verilebiliyor. Şöyle yaparız
@Autowired 
private ConfigurableEnvironment env; 
... 
env.setActiveProfiles("dev");

4. application.properties
Örnek
Profil vermek için şöyle yaparız.
spring.profiles.active=dev,local
Örnek - YAML Dosyası
Şöyle yaparız.
spring:
  profiles:
    active: dev
Açıklaması şöyle
If you prefer to have only one configuration (application.yml) file in your project, then you can separate each profile configuration using three dashes.

If you see in the above example, there are three sections, which are separated by three dashes. First section is for common properties which are enabled for all the spring profiles. Second section is for integration-test spring profile and third one is for prod profile.

28 Şubat 2022 Pazartesi

SpringData DataAccessException Hiyerarşisi

Giriş
Şu satırı dahil ederiz
import org.springframework.dao.DataAccessException;
DataAccessException soyut bir sınıf. Bu sınıftan kalıtan bir sürü alt sınıf daha var. Şeklen şöyle



Bunlardan en önemlisi NonTransientDataAccessException sınıfı. 

NonTransientDataAccessException Sınıfı
Bu da aslında soyut bir sınıfı. Veri tabanındaki işlemde geçici/uçucu olmayan yani non-transient bir hata olduğunu belirtir. Kalıtan en önemli sınıflar şöyle

DataIntegrityViolationException
Null olmaması gerek bir alan null ise fırlatılır

DuplicateKeyException
Primary key hatası varsa vs. fırlatılır

DataRetrievalFailureException
Sorguda erişilmeye çalışılan primary key yoksa fırlatılır

IncorrectResultSetColumnCountException
Açıklaması burada

IncorrectResultSizeDataAccessException
Örneğin tek satır sonuç yerine daha fazla satır dönerse fırlatılır

DataSourceLookupFailureException
InvalidDataAccessResourceUsageException
BadSqlGrammarException
CannotGetJdbcConnectionException
Açıklaması burada






24 Şubat 2022 Perşembe

SpringCloud Zipkin

Zipkin Nedir?
Açıklaması şöyle
Zipkin is a distributed instrumentation and monitoring tool that will allow us to collect service information and perform searches on it. With the aim of finding problems in the latency of them, mainly through evaluating how long it has taken the execution of those services.
application.properties
Açıklaması şöyle
By default, our services will try to send trace messages to localhost:9411. If OpenZipkin runs at a different address, you need to specify it in the settings of each service:
Örnek
Şöyle yaparız
spring: zipkin: base-url: http://<host>:<port>
Örnek
Zipkin'a RabbitMQ ile mesaj göndermek için şöyle yaparız
spring.zipkin.sender.type=rabbit
spring.zipkin.rabbitmq.queue=zipkin
....
Docker Zipkin Sunucusu
Zipkin sunucusu 9411 numaralı portu kullanır. GUI'ye erişmek için şöyle yaparız
http://localhost:9411/
Örnek
Şöyle yaparız
docker run -d -p 9411:9411 openzipkin/zipkin
Docker Compose
"docker-compose up" ile başlatırız
Örnek
Şöyle yaparız
version: "3.1" services: zipkin: image: openzipkin/zipkin:2 ports: - "9411:9411"
Örnek 
Şöyle yaparız
version: "3.9"

services:
  microservices_postgresql:
    image: postgres:latest
    container_name: microservices_postgresql
    expose:
      - "5432"
    ports:
      - "5432:5432"
    restart: always
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=bank_accounts
      - POSTGRES_HOST=5432
    command: -p 5432
    volumes:
      - ./docker_data/microservices_pgdata:/var/lib/postgresql/data
    networks: [ "microservices" ]

  redis:
    image: redis:latest
    container_name: microservices_redis
    ports:
      - "6379:6379"
    restart: always
    networks: [ "microservices" ]

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    command:
      - --config.file=/etc/prometheus/prometheus.yml
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
    networks: [ "microservices" ]

  node_exporter:
    container_name: microservices_node_exporter
    restart: always
    image: prom/node-exporter
    ports:
      - '9101:9100'
    networks: [ "microservices" ]

  grafana:
    container_name: microservices_grafana
    restart: always
    image: grafana/grafana
    ports:
      - '3000:3000'
    networks: [ "microservices" ]

  zipkin:
    image: openzipkin/zipkin:latest
    restart: always
    container_name: microservices_zipkin
    ports:
      - "9411:9411"
    networks: [ "microservices" ]


networks:
  microservices:
    name: microservices
Şeklen şöyle

Her hangi bir isteği genişletirsek şöyle