1.10. Support#
Uygulama mimarisinde ihtiyaç duyulan destek paketlerini içeren altyapı bileşenidir.
- Elasticsearch Apm Support
- Spring Batch
- File System
- Mail Sender
- Micrometer Prometheus
- Multitenancy
- Skywalking
- Tracing
- Blobstore
Apm Support#
EKSEN, bu bileşen ile APM agentlarını instance içerisine ekleyerek Elasticsearch - APM entegrasyonu desteği sağlamaktadır.
hvl:
elastic:
apm:
server-url: ${ELASTIC_APM_SERVER_URL:http://hvlapmserver:8200}
configuration-map:
enabled: ${ELASTIC_APM_ENABLED:false}
service_name: ${ELASTIC_APM_SERVICE_NAME:${spring.application.name}}
application_packages: ${ELASTIC_APM_PACKAGES:tr.com.havelsan}
environment: ${ELASTIC_APM_ENVIRONMENT:staging}
cloud_provider: ${ELASTIC_APM_CLOUD_PROVIDER:NONE}
transaction_ignore_urls: ${ELASTIC_APM_CLOUD_PROVIDER:/actuator/health,/actuator/info}
hvl-infra üzerinden Config Server kullanıldığı durumlarda bootstrap.yml dosyasındaki spring.cloud.config.profile pathine apm değerinin eklenmesi gerekmektedir. Böylece yukarıdaki özelliklerin ve daha fazlasının olduğu application-apm.yml dosyası projeye dahil olacaktır.
hvl.elastic.apm.configuration-map.enabled değeri true yapılarak apm tracing sistemi aktif hale getirilebilir. Sistemin düzgün bir şekilde çalışabilmesi için elastic-search uygulaması çalışıyor olmalıdır.
Loglanan metrikleri görüntülemek için Kibana uygulamasındaki APM ekranından konfigürasyonlarının yapılması gerekmektedir.
Batch Support#
Kurumsal sistemlerin günlük operasyonları için hayati önem taşıyan güçlü toplu uygulamaların geliştirilmesini sağlamak üzere tasarlanmış hafif ve kapsamlı bir altyapı bileşenidir.
Spring Batch, günlüğe kaydetme/izleme, işlem yönetimi, iş işleme istatistikleri, işi yeniden başlatma, atlama ve kaynak yönetimi dahil olmak üzere büyük hacimli kayıtların işlenmesinde gerekli olan yeniden kullanılabilir işlevler sağlar. Ayrıca, optimizasyon ve bölümleme teknikleri yoluyla son derece yüksek hacimli ve yüksek performanslı toplu işleri mümkün kılacak daha gelişmiş teknik hizmetler ve özellikler de sağlar. Basit ve aynı zamanda karmaşık, yüksek hacimli toplu işler, önemli miktarda bilgiyi işlemek için yüksek düzeyde ölçeklenebilir bir şekilde kullanabilir.
hvl-infra altında bulunan 'application-batch.yml' dosyasıyla konfigüre edilebilmektedir.
Tablo İlklendirme#
Spring batch, veritabanındaki kendine ait tablolar vasıtasıyla çalışmaktadır. Bu kapsamda hvl-batch-support kütüphanesinden liquibase desteği sağlanmaktadır. Aşağıdaki şekilde liquibase scripti basitçe liqubase yaml dosyalarına eklenebilir.
Temel olarak job, step, reader, processor ve writer beanleri tanımlanmalıdır. Yapılacak işleme göre farklı tanımlamalara ihtiyaç duyulabilir. Aşağıdaki örnekte veritabanından okunan verinin kafkaya yazılması örneği bulunmaktadır.
@Bean
public Job simpleJob(Step simpleStep) {
return new JobBuilder(JOB_NAME, jobRepository)
.start(simpleStep)
.build();
}
@Bean
public Step simpleStep(PlatformTransactionManager transactionManager,
ItemReader<HvlBatchSimplePersonEntity> simplePersonItemReader,
ItemProcessor<HvlBatchSimplePersonEntity, HvlBatchSimplePersonKafkaModel> simplePersonItemProcessor,
ObjectProvider<ItemWriter<HvlBatchSimplePersonKafkaModel>> kafkaItemWriter) {
return new StepBuilder("simple_step", jobRepository)
.<HvlBatchSimplePersonEntity, HvlBatchSimplePersonKafkaModel>chunk(10, transactionManager)
.reader(simplePersonItemReader) //read data
.processor(simplePersonItemProcessor) // process data
.writer(Objects.requireNonNull(kafkaItemWriter.getIfAvailable(), "Item writer bean cannot be null!")) //write to kafka
.allowStartIfComplete(true)
.build();
}
@Bean
public ItemReader<HvlBatchSimplePersonEntity> simplePersonItemReader(HvlBatchSimplePersonRepository simplePersonRepository) {
return new RepositoryItemReaderBuilder<HvlBatchSimplePersonEntity>()
.name("simple_person_item_reader")
.pageSize(100)
.repository(simplePersonRepository)
.methodName("findAll")
.sorts(Map.of("id", Sort.Direction.ASC))
.build();
}
@Bean
public ItemProcessor<HvlBatchSimplePersonEntity, HvlBatchSimplePersonKafkaModel> simplePersonItemProcessor() {
return item -> {
System.out.printf("Processing item %s", item);
final HvlBatchSimplePersonKafkaModel simplePersonKafkaModel = new HvlBatchSimplePersonKafkaModel();
simplePersonKafkaModel.setName(item.getName());
simplePersonKafkaModel.setSurname(item.getSurname());
return simplePersonKafkaModel;
};
}
@Bean
public ItemWriter<HvlBatchSimplePersonKafkaModel> kafkaItemWriter(
KafkaTemplate<String, HvlBatchSimplePersonKafkaModel> kafkaTemplate) {
kafkaTemplate.setDefaultTopic("my-simple-person-topic");
return new KafkaItemWriterBuilder<String, HvlBatchSimplePersonKafkaModel>()
.itemKeyMapper(source -> null)
.kafkaTemplate(kafkaTemplate)
.build();
}
Tanımlanan job'ı çalıştırmak için ise JobLauncher kullanılmaktadır. Aşağıda basit bir örnek verilmiştir.
final JobLauncher jobLauncher = applicationContext.getBean(JobLauncher.class);
final Job simpleJob = applicationContext.getBean(Job.class);
try {
jobLauncher.run(simpleJob, new JobParameters());
} catch (JobRestartException e) {
throw new RuntimeException(e);
} catch (JobInstanceAlreadyCompleteException e) {
throw new RuntimeException(e);
} catch (JobExecutionAlreadyRunningException e) {
throw new RuntimeException(e);
} catch (JobParametersInvalidException e) {
throw new RuntimeException(e);
}
Daha detaylı örneklere hvl-javalt-samples altindaki projelerden ulaşılabilir. Simple proje yukarıdaki örneğin detaylı halidir. Jdbc projesi ise csv uzantılı bir dosyadan veri okuyup veritabanına yazan bir örnek projedir.
File System Support#
Belirli bir path üzerinde dosya işlemleri yapmak için sağlanan bileşendir. HvlFileSystemResourceService sınıfı kullanılarak işlemler yapılmaktadır.
public interface HvlFileSystemResourceService {
void persistDocument(InputStream document, HvlFileSystemInfoModel resourcePersisterInfo) throws HvlFileSystemException;
void deleteDocument(HvlFileSystemInfoModel resourcePersisterInfo) throws HvlFileSystemException;
InputStream readDocument(HvlFileSystemInfoModel resourcePersisterInfo) throws HvlFileSystemException;
String getDocumentName(HvlFileSystemResourcePathStrategy hvlFileSystemResourcePathStrategy);
}
Yapılacak dosya işlemleri resourcePath'e verilen path üzerinde gerçekleştirilir.
Mail Support#
EKSEN, mail atmak için gerekli altyapıyı sağlamaktadır. Başlıca yetenekler:
- Fake mail: Geliştirme ortamları için tüm maillerin sahte bir adrese yönlendirilmesi yapılabilir. Böylece tek bir mail adresi hesabından tüm mailler kontrol edilebilir.
- Html mail desteği
- Takvim/Toplantı davetli mail desteği
- Ekli mail gönderme desteği
Ek olarak mail template'leri ile daha kompleks mailler atılmak isteniyorsa EKSEN tarafından sağlanan ve EKSEN altyapısını kullanan Notification ürünü incelenebilir.
hvl-infra altında bulunan 'application-hvl-mail.yml' dosyasıyla konfigüre edilebilmektedir.
Konfigürasyon sınıfına @HvlEnableMailSupport anotasyonu eklenerek aktif hale getirilmelidir.
@Configuration
@HvlEnableMailSupport
public class SampleConfiguration extends HvlBaseConfiguration {
}
Micrometer Prometheus Support#
EKSEN, micrometer kütüphanelerini kullanarak prometheus'a veri basılmasını sağlamaktadır. Böylece Grafana gibi monitoring uygulamaları kullanılarak uygulamalar hakkında detaylı bilgi edinilebilmektedir.
Multi Tenancy Support#
EKSEN, aynı uygulama üzerinden farklı müşterilere destek verilmesi durumları için multi tenancy support bileşenini sağlamaktadır. Bu bileşen ile aşağıdaki türlerde tenancy sağlanabilmektedir.
- Veritabanı
- Veritabanı Şeması
- Veritabanı Tablo Kolonu
- Gateway
Veritabanı düzeylerinden birinde multi tenancy yapılmak istendiğinde aşağıdaki entity sınıfları kullanılmalıdır:
- HvlHardDeleteTenantEntity
- HvlLookupTenantEntity
- HvlSimpleTenantEntity
- HvlSoftDeleteTenantEntity
hvl-infra altında bulunan 'application-hvl-multi-tenancy.yml' dosyasıyla konfigüre edilebilmektedir.
Skywalking Support#
EKSEN, bu bileşen ile Apache Skywalking için gerekli kütüphaneleri sisteme dahil eder.
- Apache Skywalking için sağlanan backend ve ui docker uygulamaları hvl-infra içerisinden çalıştırılmalıdır.
- Apache web sitesinden Java Agent 9.6.0 indirilir ve uygun bir path'e çıkartılır.
- Çalıştırılacak uygulamanın VM değişkenlerine aşağıdaki komut eklenir.
-javaagent:/AGENT-PATH/skywalking-agent/skywalking-agent.jar -Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector- log4j2.yml içerisine örnekteki gibi
GRPCLogClientAppenderappender'ı vegrpc-logreferansları eklenir. - Skywalking UI uygulaması üzerinde uygulama adının düzgün görünebilmesi için
SW_AGENT_NAMEortam değişkeni ile uygulama adı verilmelidir. Varsayılan olarak bu değerYour_ApplicationNamegelmektedir. - Ek olarak agent ile ilgili ayarlar için Java Agent Setup dokümanı incelenebilir.
Uyarı
Skywalking ve apm eşzamanlı olarak devreye alındığında agent'lar çakışma yaşamaktadır. Uygulamaya 2 kütüphane de dahil edilmiş olabilir ancak uygulama çalışırken yalnızca apm veya skywalking devrede olmalıdır.
Loglanan metrikleri görüntülemek için varsayılan olarak 8080 portundan çalışan Skywalking UI uygulaması kullanılmalıdır.
Tracing Support#
EKSEN, cloud ortamlar için tracing yapabilmek amacıyla Micrometer ve Brave desteği sağlamaktadır. Bu teknolojiler kullanılarak, instancelar arasındaki network izlenebilir ve requestlerin hangi uygulamalardan geçtiği gözlenebilir. Monitoring tool olarak Zipkin kullanılarak uygulamalar arası network izlenebilir.
Sağlanan @HvlTraceLog anotasyonu ile çalışan methodların da trace edilmesi sağlanmaktadır. Takip edilmek istenen methodların tepesine eklenmesi gerekmektedir.
Konsol log seviyesi trace yapılarak request ve response'lar detaylı olarak görülebilmektedir.
hvl:
tracing:
include-headers: ${TRACING_INCLUDE_HEADERS:true}
include-client-info: ${TRACING_INCLUDE_CLIENT_INFO:true}
include-query-string: ${TRACING_INCLUDE_QUERY_STRING:false}
include-payload: ${TRACING_INCLUDE_PAYLOAD:true}
max-payload: ${TRACING_MAX_PAYLOAD:5120}
method:
aspect:
enabled: ${TRACING_METHOD_ASPECT_ENABLED:false}
redis:
name: redis
ignoring-span-name-list:
- 'http get'
- 'http put'
- 'http get /actuator/health'
- 'http get /actuator/info'
- 'http get /actuator'
- 'security filterchain before'
- 'security filterchain after'
- 'authorize request'
- 'secured request'
- 'info'
- 'connection'
httpexchanges:
recording:
in-memory-trace:
capacity: ${IN_MEMORY_TRACE_CAPACITY:100}
reverse: ${IN_MEMORY_TRACE_REVERSE:true}
javamelody:
enabled: false
init-parameters:
log: true
management:
httpexchanges:
recording:
enabled: ${HTTP_TRACE_ENABLED:true}
tracing:
enabled: ${TRACING_ENABLED:false}
sampling:
probability: ${TRACING_PROBABILITY:1.0}
zipkin:
tracing:
endpoint: ${ZIPKIN_ENDPOINT:http://hvlzipkin:9411/api/v2/spans}
prometheus:
metrics:
export:
enabled: ${PROMETHEUS_EXPORTER_ENABLED:false}
hvl-infra üzerinden Config Server kullanıldığı durumlarda bootstrap.yml dosyasındaki spring.cloud.config.profile pathine cloud-tracing ve management değerinin eklenmesi gerekmektedir. Böylece yukarıdaki özelliklerin ve daha fazlasının olduğu application-cloud-tracing.yml ve application-management.yml dosyaları projeye dahil olacaktır.
Zipkin#
management.tracing.enabled değeri true yapıldığı durumlarda uygulama management.zipkin.tracing.endpoint değerini kullanarak zipkin uygulamasına metrik göndermeye başlar. Sistemin düzgün olarak çalışabilmesi için elastic-search uygulaması ve zipkin uygulaması çalışıyor olmalıdır.
Java Melody ile Performans İzleme#
JavaMelody'nin amacı QA ve üretim ortamlarında Java veya Java EE uygulamalarını izlemektir. Kullanıcılardan gelen istekleri simüle etmek için bir araç değildir, kullanıcıların uygulamayı kullanımına bağlı olarak uygulamanın gerçek zamanlı çalışmasıyla ilgili istatistikleri ölçmek ve hesaplamak için bir araçtır.
javamelody.enabled değeri varsayılan olarak false gelmektedir. Bu değer true yapıldıktan sonra uygulamanın /monitoring path'i üzerinden java melody sayfasına ulaşılabilir.
Dikkat
Bu uygulama gerçek zamanlı olarak sürekli veri toplama yapacağı için, canlı kurulum ortamlarında ihtiyaç dışında kapalı tutulması tavsiye edilir.
Blobstore Support#
Blobstore birden fazla content manager uygulamasıyla eş zamanlı ve esnek bir şekilde çalışabilen bir yapıdır. Bu sayede farklı content manager sistemleri tek bir uygulama üzerinden yönetilebilir, veri erişimi merkezi ve ölçeklenebilir bir hale getirilir.

Temel Özellikler:
- Aynı anda birden fazla content manager sunucusuyla entegre çalışabilme
- Her content manager için bağımsız yapılandırma imkânı
- Her yapılandırmaya özel bean alias tanımlayabilme
- Uygulama tarafında alias kullanarak dinamik blobstore oluşturma
- Blobstore üzerinden okuma, yazma ve silme işlemlerini gerçekleştirme
- Blocking (senkron) servis desteği
- Reactive (reaktif) servis desteği
- Asenkron (async) servis desteği
Bu yapı sayesinde sistem, yüksek esneklik, modülerlik ve farklı entegrasyon senaryolarına hızlı uyum sağlama avantajı sunar.
Konfigürasyon sınıfına @HvlEnableBlobstoreSupport anotasyonu eklenerek aktif hale getirilmelidir.
@Configuration
@HvlEnableBlobstoreSupport
public class SampleConfiguration extends HvlBaseConfiguration {}
hvl:
core:
blobstore:
data-adapters:
s3Blob-stores:
minio1:
bean-aliases: ${MINIO_BEAN_ALIASES:minio}
bean-name: ${MINIO_BEAN_NAME:minioContentLoader}
url: ${MINIO_URL:<minio-server-url>:<minio-server-port>}
username: ${MINIO_USERNAME:<username>}
password: ${MINIO_PASSWORD:<password>}
default-bucket-name: ${MINIO_BUCKET:miniobucket}
jdbc-blob-stores:
postgre-db:
bean-aliases: ${POSTGRE_JDBC_BEAN_ALIASES:postgredb}
url: ${POSTGRE_JDBC_URL:jdbc:postgresql://<db-host>:<postgredb-port>/<database-name>}
username: ${POSTGRE_JDBC_USERNAME:<username>}
password: ${POSTGRE_JDBC_PASSWORD:<password}
schema-name: ${POSTGRE_JDBC_SCHEMA:<schema-name}
table-name: ${POSTGRE_JDBC_TABLE:<table-name>}
oracle-db:
bean-aliases: ${ORACLE_BEAN_ALIASES:oracledb}
url: ${JDBC_URL:jdbc:postgresql://<db-host>:<oracle-port>/<database-name>}
username: ${ORACLE_JDBC_USERNAME:<username>}
password: ${ORACLE_JDBC_PASSWORD:<password}
schema-name: ${ORACLE_JDBC_SCHEMA:<schema-name}
table-name: ${ORACLE_JDBC_TABLE:<table-name>}
hcm-blob-stores:
hcm1:
bean-aliases: ${HCM_ALIASES:cm,cm1}
url: ${HCM_URL:http://<username>:<password>@<host>:<port>/cmapi}
default-repository-name: ${HCM_REPOSITORY:<repository-name>}
bean-aliases
Birden fazla veri kaynağının eşzamanlı olarak çalıştırılması gerektiğinde, nesnelere takma ad (alias) atamak amacıyla bean-aliases mekanizması kullanılabilir. Örneğin, üç farklı veritabanına veya üç ayrı HCM uygulamasına, bean-aliases aracılığıyla özel erişim sağlanabilir.
HvlIntegratedBlobStore Yönetimi#
Uygulama içerisinde farklı veri saklama alanlarına (HCM, S3, JDBC Veritabanı) veya aynı altyapıyı kullanan farklı mantıksal klasörlere (n farklı alias ile) dinamik olarak erişmek için HvlIntegratedBlobStoreSelector bileşeni kullanılır.
Dinamik Blob Store Seçimi#
Aşağıdaki kod bloğu, applicationContext üzerinden seçici sınıfı çağırır ve "cm" alias değeri ile ilişkilendirilmiş özel blob store kaynağını getirir.
final HvlIntegratedBlobStoreSelector selector =
applicationContext.getBean(HvlIntegratedBlobStoreSelector.class);
// "cm" alias'ına sahip kaynak seçilir. Bulunamazsa hata fırlatır.
final HvlIntegratedBlobStore blobStore = selector.selectBlobStoreOrElseThrow("cm");
Çoklu Kaynak (Multi-Alias) Yönetimi
Bu mimari sayesinde sistemde n sayıda farklı kaynak tanımlanabilir. Örneğin "cm", "crm", "finance" gibi farklı takma adlar (aliases) kullanarak, uygulamanın farklı modüllerinin kendilerine ait izole depolama alanlarına tek bir selector üzerinden erişmesini sağlayabilirsiniz.
Avantajları#
- Esneklik: Yeni bir depolama alanı eklemek için kodun değiştirilmesine gerek kalmaz, sadece yeni bir alias tanımlamak yeterlidir.
- Hata Yönetimi:
selectBlobStoreOrElseThrowmetodu, talep edilen alias sistemde kayıtlı değilse çalışma zamanında anlamlı bir exception fırlatarak hatalı yapılandırmaların önüne geçer. - Temiz Kod:
if-elseveyaswitch-caseblokları yerine Spring tabanlı dinamik strateji deseni (Strategy Pattern) kullanılmış olur.
HCM#
HCM Uygulaması Kullanımı
Aşağıda "cm" alias verilen bir bean üzerinden veri okuma,yazma ve silme işlemleri ile ilgili örnek bulunmaktadır.
final ConfigurableApplicationContext applicationContext = SpringApplication.run(HvlBlobstoreServerApplication.class, args);
final HvlIntegratedBlobStoreSelector selector =
applicationContext.getBean(HvlIntegratedBlobStoreSelector.class);
final HvlIntegratedBlobStore blobStore = selector.selectBlobStoreOrElseThrow("cm");
//read
final String id="1001";//Okunması istenen verinin blobOid bilgisi
final HvlBlobReadDescriptor blobReadDescriptor = HvlBlobReadDescriptor.builder()
.withBlobOid(id)
.build();
blobStore.read(blobReadDescriptor);
//write
String fileName = "hvl.png";
// Sadece veri akisini simule eden bos/mock kaynak
final InputStream source = new java.io.ByteArrayInputStream(new byte[0]);
HvlBlobWriteDescriptor.Builder builder = HvlBlobWriteDescriptor.builder()
.withStorableContentSource(source)
.withContentSourceName(fileName);
final HvlBlobWriteDescriptor writeDescriptor = builder.build();
final String writenId = blobStore.write(writeDescriptor);
//remove
final String removedIdentifier="1000";//Silinmesi istenen verinin blobOid bilgisi
final boolean result=blobStore.remove(HvlBlobRemoveDescriptor.builder()
.withBlobOid(removedIdentifier)
.build());
Minio#
Minio Uygulaması Kullanımı
Aşağıda "minio" alias verilen bir bean üzerinden veri okuma,yazma ve silme işlemleri ile ilgili örnek bulunmaktadır.
final ConfigurableApplicationContext applicationContext = SpringApplication.run(HvlBlobstoreServerApplication.class, args);
final HvlIntegratedBlobStoreSelector selector =
applicationContext.getBean(HvlIntegratedBlobStoreSelector.class);
final HvlIntegratedBlobStore blobStore = selector.selectBlobStoreOrElseThrow("minio");
//read
final String id="1001";//Okunması istenen verinin blobOid bilgisi
final HvlBlobReadDescriptor blobReadDescriptor = HvlBlobReadDescriptor.builder()
.withBlobOid(id)
.build();
blobStore.read(blobReadDescriptor);
//write
String fileName = "hvl.png";
// Sadece veri akisini simule eden bos/mock kaynak
final InputStream source = new java.io.ByteArrayInputStream(new byte[0]);
HvlBlobWriteDescriptor.Builder builder = HvlBlobWriteDescriptor.builder()
.withStorableContentSource(source)
.withBlobOid(UUID.randomUUID().toString())
.withContentSourceName(fileName);
final HvlBlobWriteDescriptor writeDescriptor = builder.build();
final String writenId = blobStore.write(writeDescriptor);
//remove
final String removedIdentifier="1000";//Silinmesi istenen verinin blobOid bilgisi
final boolean result=blobStore.remove(HvlBlobRemoveDescriptor.builder()
.withBlobOid(removedIdentifier)
.build());
JDBC#
JDBC Kaynağına Blobstore ile erişim
Herhangi bir veritabanı kullanarak blobstore desteği ile veri yazma okuma için veritabanı şema ve tablo ayarları yapılmaıdır (Bkz:Nasıl konfigüre edilir?)
Veri İlklendirme#
Blobstore aracılığıyla bir JDBC kaynağı üzerinde işlem gerçekleştirmek amacıyla, ilgili veritabanında parametrik olarak tanımlanmış şema kapsamında ve yine parametrik olarak belirtilen tablo adına göre aşağıdaki alanların yer alması gerekmektedir.
CREATE TABLE blobstore.stored_content (
stored_content_type varchar(255) NULL,
content_source_name varchar(255) NULL,
"uuid" varchar(36) NULL,
stored_content bytea NULL
);