1.2. Cloud Framework#
Uygulamaları cloud yapısına uygun şekilde geliştirmek için hizmete sunulan altyapı bileşenidir. Temel teknoloji bileşenleri olarak OpenFeign, Spring Cloud kullanılmaktadır. Exception handling, tracing, registry integration vb. bileşenleri içermektedir. Bu altyapı bileşeni ihtiyaçlar doğrultusunda genişletilebilmektedir.
Configuration#
Mikro servis mimaride çok sayıda uygulama dağıtık mimaride bulunmaktadır. Bu durum uygulamalar ayağa kalkarken gerekli konfigurasyonu nasıl vereceğimiz problemini doğurmaktadır. EKSEN; config-server entegrasyonu ile konfigurasyonlar için tek kaynaktan beslenme sağlamaktadır.
config-server kullanılırken dikkat edilmesi gereken konular bulunmaktadır. Bunlar;
- config-server üzerinden gelen özellikler ve dosyalar baskınlık göstermektedir. Uygulamada resources altında bulunan .yml uzantılı dosyalar ve içerisindeki özellikler eğer config-server üzerinden gelmiyorsa kullanılabilir. Aksi takdirde **config-server**dan gelen ezecektir.
- Uygulama ayağa kaldırılırken enviroment olarak verilen özellikler config-server üzerinden gelen özellikleri ezmektedir.
- config-server üzerinden override edilmiş özellikler herhangi bir şekilde ezilemez. Özelliğin her uygulama için aynı olması isteniyorsa bu kullanım tavsiye edilmektedir. Bu yeteneğin kullanılması için config-server ayağa kaldırılırken environment'ların önüne 'SPRING_CLOUD_CONFIG_SERVER_OVERRIDES_' ön ekinin eklenmesi gerekmektedir. Örnek:
version: '2.1'
services:
config-server-service:
.
.
environment:
SPRING_CLOUD_CONFIG_SERVER_OVERRIDES_HVL_OAUTH_SESSION_SERVICE_URL: http://hvlsessionserver:9080
SPRING_CLOUD_CONFIG_SERVER_OVERRIDES_HVL_OAUTH_SESSION_SERVICE_PATH: /
Uygulamalarda config-server bağlantısı bootstrap.yml üzerinden sağlanmaktadır.
spring:
config:
import:
- optional:configserver:${spring.cloud.config.uri}
cloud:
config:
uri: ${SERVER_CONFIGURATION_REMOTE_URL:http://localhost:8888/config}
profile: ${SERVER_CONFIGURATION_CLOUD_PROFILE:cloud-eureka,cloud-tracing,hvl-context,hvl-data,hvl-logger,hvl-mail,hvl-security,hvl-service,hvl-session,database-datasource,instance,kafka,management,swagger,apm}
label: ${SERVER_CONFIGURATION_LABEL:framework(_)spring}
enabled: ${SERVER_CONFIGURATION_REMOTE_ENABLED:true}
username: ${CONFIG_AUTH_USERNAME:admin}
password: ${CONFIG_AUTH_PASSWORD:123456}
logging:
auth:
username: ${LOGGING_AUTH_USERNAME:${spring.cloud.config.username}}
password: ${LOGGING_AUTH_PASSWORD:${spring.cloud.config.password}}
config: ${LOGGING_CONFIG:${spring.cloud.config.uri}/${spring.application.name}/default/framework(_)log4j2(_)instance(_)oauth/log4j2.yml}
EKSEN olarak loglama ve genel bütün konfigürasyonları config-server üzerinden almaktayız. Burada profile mantığı kullanılarak parçalama yapılmıştır. Konfigürasyon dosyalarını ve config-server dosyalarını hvl-infra adresinden inceleyebilirsiniz.
Eureka Web Starter#
Mikro servis mimaride dağıtık servisler hakkında bilgi almak için service-registry olarak Eureka kullanılmasına destek sağlamaktadır. Eureka entegrasyonu için gerekli temel yapıları sağlamaktadır.
hvl-infra altında bulunan 'application-cloud-eureka.yml' dosyasıyla konfigure edilebilmektedir.
Kubernetes Web Starter#
Mikro servis mimaride dağıtık servisler hakkında bilgi almak için service-registry olarak Kubernetes kullanılmasına destek sağlamaktadır. Kubernetes entegrasyonu için gerekli temel yapıları sağlamaktadır.
hvl-infra altında bulunan 'application-cloud-kubernetes.yml' dosyasıyla konfigure edilebilmektedir.
Service#
Mikro servis yapılarda uygulamaların birbirlerine declarative yapıda istek (Http request) atabilmesini sağlamaktadır. Yani geliştirici istek atacağı interface'i tanımladıktan sonra java üzerinden implementasyon yapmadan istek atabilmektedir. Burada teknoloji olarak OpenFeign kullanılmaktadır.
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(name = "", url = "", path = "")
public interface SampleRestService {
@GetMapping(path = "/sample", produces = MediaType.APPLICATION_JSON_VALUE)
String sample();
}
Declarative yapıları injection yapmadan oluşturmak için HvlFeignClientBuilder
sınıfını kullanılabilir.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tr.com.havelsan.javarch.cloud.service.builder.HvlFeignClientBuilder;
import tr.com.havelsan.javarch.samples.jpa.data.logic.SampleRestService;
/**
* @author javarch
*/
@SpringBootApplication
public class HvlSampleApplication {
public static void main(String[] args) {
SpringApplication.run(new Class[]{HvlSampleApplication.class}, args);
final SampleRestService sampleRestService = HvlFeignClientBuilder.create().target(SampleRestService.class);
}
}
FeignClient sınıflarının decoder, encoder, interceptor, logger alanlarını da konfigure edebilirsiniz.
EKSEN, decoder işlemi için HvlDecoder
interface'inden türeyen HvlFeignClientDecoder, HvlFeignClientErrorDecoder, HvlFeignResponseDecoder
sınıfları ile destek sağlamaktadır.
EKSEN, encoder işlemi için HvlFeignEncoder
sınıfı ile destek sağlamaktadır.
EKSEN, interceptor işlemi için HvlCloudServiceRequestInterceptor
sınıfı ile destek sağlamaktadır.
EKSEN, logger işlemi için HvlFeignClientLogger
sınıfı ile destek sağlamaktadır.
NOT: Yukarıda sağlanan desteklerin kullanımı zorunlu değildir. Uygulamaya göre özelleştirilebilir hatta arttırılabilir. FeignClient özelinde bile yazılabilir. Fakat burada özelleştirme yapılırken altyapının sağladığı destekler incelenmeli ve isteğin yaşam döngüsü bozulmamalıdır.
Http isteği için FeignClient declarative yapısının kullanılmasının en büyük problemi, mikro servis mimaride uygulamalar dağıtık mimaride farklı JVM de çalıştığı için hatanın ele alınmasıdır.
EKSEN, FeignClient kullanımında istek sonucunda hatayı JVM'de ele alınmasını sağlanmıştır. Bunun için FeignClient uçlarında kullanılacak hataların @HvlFeignClientError
annotation'ı ile işaretlenmesi gerekmektedir.
EKSEN, Feign client uçları için @HvlPrivateFeignRestService
ve @HvlPublicFeignRestService
sağlamaktadır. Bu uçların şuan için bir işlevi yoktur ancak dışarıya açılmak istenen uçlar ve gizli kalması istenen uçların kod okunaklılığı açısından bu anotasyonlarla işaretlenmesi önerilir.
import org.springframework.http.HttpStatus;
import tr.com.havelsan.javarch.cloud.service.annotation.HvlFeignClientError;
import tr.com.havelsan.javarch.exception.HvlCheckedException;
import tr.com.havelsan.javarch.exception.model.HvlErrorDetail;
import tr.com.havelsan.javarch.service.annotation.HvlExceptionHttpStatus;
@HvlFeignClientError
@HvlExceptionHttpStatus(code = HttpStatus.BAD_REQUEST)
public class SampleInvalidRequestException extends HvlCheckedException {
public static final String ERROR_CODE = "code";
public static final String ERROR_MESSAGE = "message";
public SampleInvalidRequestException() {
super(ERROR_MESSAGE, new HvlErrorDetail(ERROR_CODE, ERROR_MESSAGE));
}
public SampleInvalidRequestException(HvlErrorDetail errorDetail) {
super(errorDetail);
}
}
NOT: FeignClient hatalarının sistem tarafından taranması gerekmektedir.
hvl.core.service.cloud.feign.client.exception.scan-path
özelliğine hatanın bulunduğu package verilmesi gerekmektedir.ÖNERİ: FeignClient kullanımlarında arayüz sınıflarında @Validated ve @Valid annotationları kullanılmalıdır. Arayüz içerisindeki metotlarada gerekli validasyon annotationları konulmalıdır. Böylece istek atılmadan validasyondan geri döner.
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import javax.validation.constraints.NotEmpty;
@FeignClient(name = "", url = "", path = "")
@Validated
public interface SampleRestService {
@GetMapping(path = "/sample", produces = MediaType.APPLICATION_JSON_VALUE)
String sample(@NotEmpty String plainText);
}
hvl-infra altında bulunan 'application-hvl-service.yml' dosyasıyla konfigure edilebilmektedir.