MS Lesson13: Proxy Design Pattern, ACID & Transaction
Proxy Design Pattern
Proxy - it provides an object that acts as substitute for a real service object used by a client. A proxy receives client requests, does some work and then passes the request to a original object.
package guru.springframework.cruddemo.proxy;
public interface DailySession {
void attendLesson();
}
package guru.springframework.cruddemo.proxy;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Attendance {
private Date date;
private boolean isPresent;
}
package guru.springframework.cruddemo.proxy;
import lombok.Data;
@Data
public class Student implements DailySession {
private final Attendance attendance;
public Student(Attendance attendance) {
this.attendance = attendance;
}
@Override
public void attendLesson() {
System.out.println("Attending the session...");
}
}
package guru.springframework.cruddemo.proxy;
public class StudentProxy extends Student {
public StudentProxy(Attendance attendance) {
super(attendance);
}
@Override
public void attendLesson() {
if (super.getAttendance().isPresent()) {
super.attendLesson();
} else {
throw new RuntimeException("Student is not present and can't attend session");
}
}
}
package guru.springframework.cruddemo.proxy;
import java.util.Date;
public class Teacher {
public static void main(String[] args) {
DailySession dailySession = new StudentProxy(new Attendance(new Date(), true));
dailySession.attendLesson();
}
}
bu daha cox CGLIB proxylemeye oxshayir
ve ya
package guru.springframework.cruddemo.proxy;
public class StudentProxy implements DailySession {
private final DailySession target;
private final Attendance attendance;
public StudentProxy(DailySession target, Attendance attendance) {
this.target = target;
this.attendance = attendance;
}
@Override
public void attendLesson() {
if (attendance.isPresent()) {
target.attendLesson();
} else {
throw new RuntimeException("Student is not present and can't attend session");
}
}
}
package guru.springframework.cruddemo.proxy;
import java.util.Date;
public class Teacher {
public static void main(String[] args) {
Attendance attendance = new Attendance(new Date(), true);
DailySession realStudent = new Student(attendance);
DailySession dailySession = new StudentProxy(realStudent, attendance);
dailySession.attendLesson();
}
}
bu ise klassik Static Proxy patterni "canonical" forma
Proxy bize ne qazandirdi:
* Biznes kodunu ayirdi:
Student.attendLesson() sadece oz ishini edir.
isPresent kimi qaydalar ayrica StudentProxy-dedir.
* Cross-cutting logic elave etdi
Elave davranishi (check, logging, security, transaction) esas klasa toxunmadan elave edildi.
* Single responsibility yaxshilashdi
Student = lesson logic
StudentProxy = access/control logic
* Deyishiklikde risk azaldi
Yeni qayda gelende real klasi dagitmiriq, proxy qatinda deyishirik
* Spring AOP ucun zehni model verdi
@Transactional, @Cashable, @PreAuthorize hamisi eyni fikir:
cagirish proxy-den kecir, evvel/sonra elave ish gorulur
1. Static proxy
Istifadesi:
2. Protection proxy
3. Virtual proxy
Spring @Transactional elaqesi
Spring de eyni pattern-den istifade edir:
* target bizim service class
* proxy: JDK ve ya CGLIB
* interceptor: TransactionInterceptor
* around logic: begin -> method call -> commit/rollback
===========================================================================
ACID - tranzaksiyalarin etibarli ishlemesi ucun 4 esas prinsip teqdim edir. ACID-i esasen DB engine temin edir.
A - Atomicity
Ya hamisi ya hec biri. Bir tranzaksiyanin icinde 5 addim varsa ya 5-de commit olur ya da 1 fail olursa rollback olur.
C - Consistency
Tranzaksiyadan evvel DB duzgun idise tranzaksiyada sonra da DB duzgun olmalidir.
Duzgun ne demekdir?
* DB constaint-ler: non null, unique, foreign key, check
* Biznes qaydalari: balans menfi olmasin, stok sifirdan ashagi dushmesin ve s.
Mes: email unique olmalidir, eyni email ikinci defe insert edilse DB reject versin
I - Isolation
Paralele tranzaksiyalar bir birini korlamasin. Eyni anda iki istifadeci eyni datani ishledende biri o birinin yarimciq veya qarishiq neticelerini gormeli/gormemelidir (biznes mentiqden asili olaraq). Yeni Isolation paralel ishlemenin riskini idare edir.
D - Durability
Tranzaksiya commit olduqdan sonra server restart olsada, proses cokse de, melumat itmir. Bu adeten WAL/log, disk flush ve DB recovery mexanizmleri ile temin olunur.
@Transactional - ACID-in tetbiqde istifade olunan duymesidir; duymeni Spring basir, ACID-i DB heyata kecirir.
* Atomicity
@Transactional metod daxilinde bir nece emeliyyati bir transaciton-a salir. Exception olarsa rollback edir ve yarimciq veziyyet qalmir.
* Consistency
Commit zamani DB constraint-lerini yoxlayir (FK, UNIQUE, CHECK). Qaydalar pozularsa commit olmur/rollback olur.
* Isolation
@Transactional(isolation = ...) ile paralel tranzaksiya davranishini teyin etmek olur (READ_COMMITTED, SERIALIZABLE ve s).
* Durability
Commit verildikden sonra neticenin qalici olmasini DB temin edir (WAL/log ve recovery mexanizmi ile).
@Transactional sadece commit emri verir.
WAL nedir?
Write-Ahead Logging
DB bir deyishiklik edende, evvelce hemin deyishikliyin "jurnalini" (log record) yazir, sonra esas data fayllarini yenileyir. Esas sebeb durability ve crash recovery. Server sondu, process oldu, elektrik kesildi ve s. DB restart olanda WAL-i oxuyub: commit olunmush deyishiklikleri berpa edir (redo), yarimciq tranzaksiyalari tetbiq etmir.
@Transactional
@Transactional birbasha DB-ye "Begin/Commit" gondermir. Arada bu zencirler var:
1. Cagirish bir Spring Proxy-den kecir (AOP)
2. Proxy TransactionInterceptor-u ishe salir
3. Interceptor PlatformTransactionManager ile transaction acir
4. Yazdigimiz metod ishleyir
5. Exception yoxdursa commit, uygun exception varsa rollback
PlatformTransactionManager Spring-in transaction ucun esas interface-dir. En cox rast gelinen implementasiyalari:
*DatasourceTransactionManager (JDBC)
*JpaTransactionManger (JPA/Hibernate)
*HibernateTransactionManager (pure Hibernate hallarinda)
Adeten default olaraq JpaTransactionManager ishleyir.
TransactionInterceptor
AOP interceptor-dur, @Transactional qaydalarini oxuyur:
*propagation nedir?
*isolation nedir?
*rollback qaydalari nedir?
sonra transaction manager-e deyir:
*"metoddan evvel transaction ac"
*"metod bitende commit/rollback ele"
Spring @Transactional olan bean-i birbasha yox, cox vaxt proxy kimi verir.
Proxy novleri:
* JDK Dynamic Proxy: interface uzerinden
* CGLIB Proxy: class-i subclass edib
CGLIB proxy:
package guru.springframework.cruddemo.service.impl;
import guru.springframework.cruddemo.service.PersonService;
import lombok.RequiredArgsConstructor;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
public class PersonServiceImpl implements PersonService {
private final ApplicationContext applicationContext;
@Override
@Transactional
public void inspectProxyType() {
Object bean = applicationContext.getBean(PersonService.class);
System.out.println("PersonService bean class = " + bean.getClass().getName());
System.out.println("isAopProxy = " + AopUtils.isAopProxy(bean));
System.out.println("isCglib = " + AopUtils.isCglibProxy(bean));
System.out.println("isJdk = " + AopUtils.isJdkDynamicProxy(bean));
System.out.println("targetClass = " + AopUtils.getTargetClass(bean).getName());
}
}
JDK Dynamic Proxy:
spring:
aop:
proxy-target-class: false
Bu tip proxy-de klasi kast etmek olmaz, bu ClassCastException verecek.
CGLIB-de bu cast cox vaxt ishleyir (proxy subclass olduguna gore).
Interface olmada JDK Dynamic Proxy yaratmaq olmur, avtomatik CGLIB Proxy yaranacaq.
JDK Dynamic Proxy vs CGLIB Proxy
1. Neyi proxyleyir?
* JDK Proxy: yalniz interface metodlarini
* CGLIB: class-i subclass edib, interface olmasa da metodlari intercept edir.
2. Final mehdudiyyetleri.
* JDK Proxy: final class/method problemi yoxdur (interfaceye baxir)
* CGLIB: final class ve final method proxylemir (override ede bilmir)
3. Performans.
* Muasir JVM lerde ferq adeten cox kicikdir. Real sistemde secimi performansdan cox dizayn ve mehdudiyyetler mueyyen edir.
4. Ustunlukler.
* JDK ustunluyu: sade, interface kontraktina sadiq, final metod problemi yoxdur.
* CGLIB ustunluyu: interface olmasa da ishleyir, class-based interception imkani verir.
5. Secim qaydasi.
* Interface-le ishleyirsense ve "contract-first" isteyirsense -> JDK
* Interface yoxdur ve ya klaslari proxy elemek lazimdirsa -> CGLIB
S (Shared) lock vs X (Exclusive) lock
S lock - sen oxuyanda bashqasi eyni anda deyishib "oxudugun melumati yari yolda deyishmesin".
S lock = tehlukesiz oxu. PESSIMISTIC_READ
X lock - iki tranzaksiya eyni setri eyni anda update edib neticeni pozmasin ("lost update").
X lock = tehlukesiz yazi. PERSSIMISTIC_WRITE
Комментарии
Отправить комментарий