top of page
Yazarın fotoğrafıEnes İyidil

Spring State Machine Sihri: İş Akışlarınızı Dönüştürün


Giriş

Günümüz yazılım geliştirme dünyasında, karmaşık iş süreçlerini ve iş akışlarını yönetmek yaygın bir zorluk haline gelmiştir. Uygulamalar, sipariş işleme, kullanıcı kaydı veya iş akışı otomasyonu gibi çeşitli durumları ve geçişleri ele almak zorundadır. Bu durumları ve geçişlerini manuel olarak yönetmek zamanla zahmetli ve hata yapmaya açık hale gelebilir. İşte burada Spring State Machine devreye giriyor. Spring State Machine, Spring uygulamaları içinde durum makineleri tanımlamak ve yürütmek için kolay kullanımlı, genişletilebilir bir çözüm sunar. Geliştiricilere karmaşık durum geçişlerini modelleme ve durum odaklı iş mantığını temiz ve sürdürülebilir bir şekilde yönetme imkanı sağlar. Hiyerarşik durumlar, bölgeler ve olay tabanlı geçişler gibi özelliklerle Spring State Machine, karmaşık durum yönetimi senaryolarını ele almak için güçlü bir araç seti sunar. Bu yazıda, Spring State Machine’in yeteneklerini keşfedecek ve özelliklerini kullanarak durum makineleri oluşturma, yapılandırma ve yönetme konularında adım adım ilerleyeceğiz. Spring Boot ile entegrasyonunu, JPA persistansı ayarlamayı, durum geçişlerini özelleştirmeyi ve dinleyiciler ile monitörler kullanarak durum değişikliklerini izlemeyi ve hataları ayıklamayı öğreneceğiz. İster bir e-ticaret platformu, ister bir iş akışı motoru geliştiriyor olun, Spring State Machine uygulamanızın durum yönetim yeteneklerini basitleştirmenize ve geliştirmenize yardımcı olacak araçları sunar.

Spring State Machine

Spring State Machine, Java tabanlı uygulamalarda durum yönetimi (state management) sağlamak için kullanılan bir framework’tür. Bu framework, özellikle karmaşık durum ve geçişlerin yönetilmesi gereken uygulamalarda kullanılır.

İşlevsel olarak Spring State Machine, aşağıdaki konularda önemli rol oynar:

  1. Durum Yönetimi: Uygulamanın belirli bir anlık durumunu yönetir. Örneğin, bir ödeme işleminin durumu “Başlatıldı”, “Onay Bekliyor”, “Tamamlandı” gibi olabilir. Spring State Machine bu durumları tanımlar, takip eder ve yönetir.

  2. Durum Geçişleri: Belirli bir durumdan diğerine geçişlerin tanımlanması ve bu geçişlerin hangi koşullara bağlı olarak gerçekleşeceğinin belirlenmesi. Örneğin, bir ödeme işlemi “Onay Bekliyor” durumundaysa ve kullanıcı “Onayla” düğmesine bastıysa, durum “Tamamlandı” olabilir.

  3. Durum Takibi: Uygulamanın hangi durumda olduğunu anlamak için bir gözlem mekanizması sağlar. Bu, uygulamanın hangi adımları izlediğini ve hangi aşamada olduğunu anlamak için kullanışlıdır.

  4. Etkinlik Yönetimi: Durum geçişlerine bağlı olarak tetiklenebilecek olayların yönetimi. Örneğin, bir durum geçişinden sonra bir e-posta gönderme işlemi gerçekleştirmek gibi.

Spring State Machine’in kullanımı, genellikle iş akışı yönetimi gerektiren büyük ölçekli uygulamalarda yaygındır. Bu framework, durum ve geçişlerin karmaşıklığını yönetmeyi kolaylaştırır, kodun daha düzenli ve bakımı daha kolay hale getirir. Ayrıca, durum makinesi modellemesi ile uygulamanın iş mantığını daha açık bir şekilde ifade etmenizi sağlar.

Proje Oluşturma ve Bağımlılıkların Eklenmesi

Spring State Machine ve Spring Data JPA kullanarak bir proje oluşturmak için, yeni bir Spring Boot projesi oluşturmanız ve gerekli bağımlılıkları pom.xml dosyasına eklemeniz gerekmektedir. Aşağıda, adım adım bu süreci nasıl gerçekleştireceğinizi bulabilirsiniz.

1. Yeni Bir Spring Boot Projesi Oluşturma

Spring Initializr kullanarak yeni bir Spring Boot projesi oluşturabilirsiniz. Bunun için:

  1. Spring Initializr web sitesine gidin.

  2. Proje ayarlarını yapın (group, artifact, name, description vb.).

  3. Projeye eklemek istediğiniz bağımlılıkları seçin (Spring Web, Spring Data JPA, H2 Database vb.).

  4. Generate butonuna tıklayarak projeyi indirin ve geliştirme ortamınıza açın.

2. pom.xml Dosyasına Bağımlılıkların Eklenmesi

Oluşturulan projede, pom.xml dosyasına Spring State Machine ve Spring Data JPA için gerekli bağımlılıkları ekleyin.

<dependencies>    
	<!-- Spring Boot Starter Dependencies -->    
	<dependency>        
		<groupId>org.springframework.boot</groupId>        
		<artifactId>spring-boot-starter</artifactId>    
	</dependency>    
	<dependency>        
		<groupId>org.springframework.boot</groupId>        
		<artifactId>spring-boot-starter-web</artifactId>    
	</dependency>    
	<dependency>        
		<groupId>org.springframework.boot</groupId>        
		<artifactId>spring-boot-starter-data-jpa</artifactId>    
	</dependency>    
	<!-- PostgreSQL -->    
	<dependency>        
		<groupId>org.postgresql</groupId>        
		<artifactId>postgresql</artifactId>    
	</dependency>    
	<!-- Spring State Machine -->    
	<dependency>        
		<groupId>org.springframework.statemachine</groupId>        
		<artifactId>spring-statemachine-core</artifactId>        
		<version>${state-machine.version}</version>    
	</dependency>    
	<dependency>        
		<groupId>org.springframework.statemachine</groupId>        
		<artifactId>spring-statemachine-data-jpa</artifactId>        
		<version>${state-machine.version}</version>    
	</dependency>    
	<!-- Test Dependencies -->    
	<dependency>        
		<groupId>org.springframework.boot</groupId>        
		<artifactId>spring-boot-starter-test</artifactId>        
		<scope>test</scope>    
	</dependency>
</dependencies>
<properties>    
	<java.version>17</java.version>    
	<state-machine.version>3.2.0</state-machine.version> 
	<!-- Mevcut en son sürümü kontrol edin -->
</properties>

Spring State Machine Builder Kullanımı

Spring State Machine, statik olarak tanımlanan bir konfigürasyon dosyası üzerinden çalıştırılabildiği gibi, dinamik olarak Builder kullanılarak da çalıştırılabilir. Builder kullanılarak, birden fazla State Machine oluşturulup yönetilebilir. Bu yaklaşım, özellikle dinamik ve karmaşık iş akışlarının yönetiminde büyük kolaylık sağlar.

Bu başlıkta, Builder kullanarak bir Spring State Machine oluşturma sürecini adım adım ele alacağız. Örneklerle ve detaylı açıklamalarla konuyu daha anlaşılır hale getireceğiz.

1. Builder Kullanarak State Machine Oluşturma

Builder kullanarak bir State Machine oluşturmak oldukça esneklik sağlar. İlk olarak, Builder’ı başlatmamız gerekiyor:

Builder<String, String> machineBuilder = new Builder<>();

2. State’leri Ayarlamak

State’leri tanımlamak için configureStates metodunu kullanırız. Burada başlangıç ve bitiş durumlarını, ayrıca diğer durumları belirtiyoruz:

machineBuilder.configureStates()                
	.withStates()                
	.initial(initialState)                
	.end(endState)                
	.states(states)                
	.and();

3. Transition’ları Ayarlamak

Durumlar arası geçişleri tanımlamak için configureTransitions metodunu kullanırız. Her bir geçişin kaynağını, hedefini ve olayını belirtiyoruz:

machineBuilder.configureTransitions()                
	.withExternal()                
	.source(source)                
	.target(target)                
	.event(event)                
	.and();

4. Choice State Ekleme

Choice state, akışın birden fazla yöne doğru dallanmasını sağlar. Bu state’i eklemek için:

machineBuilder.configureStates()                
	.withStates()                
	.choice(choice);

Choice state için geçişleri tanımlamak ise şu şekildedir:

machineBuilder.configureTransitions()                
	.withChoice()                
	.source(source)                
	.first(firstTarget, ctx -> booleanCondition)                
	.last(lastTarget);

5. Custom Listener Ekleme

State Machine’in yaşam döngüsü olaylarını dinlemek için custom listener ekleyebiliriz:

machineBuilder.configureConfiguration()                
	.withConfiguration()                
	.listener(listener);

6. Custom Monitor Ekleme

State Machine’i izlemek için custom monitor ekleyebiliriz:

machineBuilder.configureConfiguration()                
	.withMonitoring()                
	.monitor(monitor);

7. State Machine Persister Ekleme

State Machine durumunu persist etmek için:

machineBuilder.configureConfiguration()                
	.withPersistence()                
	.runtimePersister(stateMachineRuntimePersister);

Builder ile Dinamik State Machine’ler

Builder ile verilen her değer -State, Transition, Choice, vb.- her durum için farklı olabilir ve bu sayede dinamik olarak değişen State Machine’ler oluşturulabilir. Bu esneklik, karmaşık iş akışlarını daha etkin bir şekilde modelleyip yönetmemizi sağlar.

Örnek Tamamlanmış Kod

Aşağıda, tüm bu adımları içeren tamamlanmış bir örnek bulabilirsiniz:

Builder<String, String> machineBuilder = new Builder<>();
machineBuilder.configureStates()                
	.withStates()                
	.initial("INITIAL")                
	.end("END")                
	.states(
		new HashSet<>(
			Arrays.asList("INITIAL", "STATE1", "STATE2", "END")
		)
	)                
	.and();
machineBuilder.configureTransitions()                
	.withExternal()                
	.source("INITIAL")                
	.target("STATE1")                
	.event("EVENT1")                
	.and()                
	.withExternal()                
	.source("STATE1")                
	.target("STATE2")                
	.event("EVENT2")                
	.and()                
	.withExternal()                
	.source("STATE2")                
	.target("END")                
	.event("EVENT3")                
	.and();
machineBuilder.configureStates()                
	.withStates()                
	.choice("CHOICE");
machineBuilder.configureTransitions()                
	.withChoice()                
	.source("STATE1")                
	.first("STATE2", ctx -> true)                
	.last("END");
machineBuilder.configureConfiguration()                
	.withConfiguration()                
	.listener(
		new StateMachineListenerAdapter<String, String>()
	 		{                    
				@Override                    
				public void stateChanged(
					State<String, String> from, 
					State<String, String> to
				) {                        
					System.out.println(
						"State changed from " + from + 
						" to " + to);                    
				}                
			}
	);
machineBuilder.configureConfiguration()                
	.withMonitoring()                
	.monitor(
		new StateMachineMonitor<String, String>() 
			{                    
				@Override                    
				public void monitor(
					StateMachine<String, String> stateMachine
				) {                        
					System.out.println(
						"Monitoring state machine: " + 						
						stateMachine.getId());                    
				}                
			}
	);
machineBuilder.configureConfiguration()                
	.withPersistence()                
	.runtimePersister(new DefaultStateMachineRuntimePersister<>());

Bu örnekle, dinamik olarak değişen ve kompleks iş akışlarını yönetebilen bir State Machine oluşturmuş olduk. Bu yöntemle, Spring State Machine’in sunduğu tüm esneklik ve gücü kullanarak iş süreçlerinizi daha etkin bir şekilde yönetebilirsiniz.

Spring State Machine Data JPA Kullanımı

Spring State Machine, durumların veritabanında kaydedilmesi ve gerektiğinde makinenin tekrardan çağrılabilmesi için dahili olarak persist edilebilir. Bu özellik, State Machine’in mevcut durumunun kaydedilmesini ve yeniden yüklenmesini sağlayarak uzun süreli işlemleri yönetmede büyük kolaylık sağlar. Bu başlıkta, Spring Data JPA kullanarak State Machine’i persist etme sürecini ele alacağız.

1. Konfigürasyon Dosyalarını Oluşturma

İlk olarak, gerekli konfigürasyon dosyalarını oluşturmalıyız. Bu dosyalar, JPA repository’lerini ve entity’leri tarayacak ve transaction yönetimini etkinleştirecektir.

SpringDataJpaConfig

Spring Data JPA konfigürasyonu için aşağıdaki sınıfı oluşturun:

@Configuration@EnableJpaRepositories(
	basePackages = {        
		"org.springframework.statemachine.data.jpa",        
		"your.repository.package"
	}
)
@EntityScan(
	basePackages = {        
		"org.springframework.statemachine.data.jpa",        
		"your.repository.package"
	}
)
@EnableTransactionManagement
public class SpringDataJpaConfig {}

Bu konfigürasyon, Spring Data JPA repository’lerini ve entity’lerini tanımlar ve transaction yönetimini etkinleştirir.

StateMachineJpaPersistedConfig

State Machine’i persist etmek için aşağıdaki konfigürasyon sınıfını oluşturun:

@Configuration
public class StateMachineJpsPersistedConfig {    
	@Bean    
	public StateMachineRuntimePersister<String, String, String> 	
		stateMachineRuntimePersister(            
			JpaStateMachineRepository jpaStateMachineRepository
	) {        
		return new JpaPersistingStateMachineInterceptor<>	
			(jpaStateMachineRepository);    
	}
}

Bu konfigürasyon, StateMachineRuntimePersister bean'ini tanımlar ve JPA repository'sini kullanarak State Machine'in persist edilmesini sağlar.

2. State Machine Service Yapısı

Her model için ayrı bir State Machine Service oluşturularak, aynı akışlarda doğrudan State Machine dönen bir yapı kurulabilir. Bu yapı, State Machine’leri yönetmek ve yeniden yüklemek için kullanılabilir.

Aşağıda, bu yapının nasıl oluşturulacağına dair bir örnek bulunmaktadır:

State Machine Service Yönetimi

Öncelikle, State Machine servislerini yönetmek için bir HashMap tanımlayın:

final HashMap<String, StateMachineService<String, String>> machineServices = new HashMap<>();

State Machine’i Alma ve Yükleme

State Machine’i almak ve yüklemek için aşağıdaki metodları kullanın:

public StateMachine<String, String> getStateMachine(Flow flow) {    
	logger.info("Get State Machine : Flow => {}", flow);    
	StateMachineService<String, String> stateMachineService = 		
		getStateMachineService(flow);    
	logger.info("Get State Machine Service : stateMachineService => {}", 	
		stateMachineService);    
	return stateMachineService.acquireStateMachine(flow.getMachineId());
}
StateMachineService<String, String> getStateMachineService(
	Flow flow
) {    
	logger.info("Get State Machine Service : Flow => {}", flow);    
	if (!machineServices.containsKey(flow.getFlowModelId())) {        
		try {            
			stateMachineServiceBuilder(flow);        
		} catch (Exception e) {            
			logger.error("Get State Machine Service : Flow => {1}, 	
				Exception => {}", flow, e);            
			throw new RuntimeException(e);        
		}    
	}    
	return machineServices.get(flow.getFlowModelId());
}

Bu kod parçası, bir Flow nesnesi için State Machine’i alır ve yönetir. Eğer belirtilen Flow modeline ait bir State Machine Service yoksa, stateMachineServiceBuilder metodunu çağırarak yeni bir servis oluşturur.

Spring State Machine Custom Listener ve Monitor Kullanımı

Spring State Machine, olayları dinleyebilmemiz ve sistemin nasıl davrandığını izleyebilmemiz için bir takım sınıflar sunar. Bu sınıflar sayesinde, State Machine’in durum değişikliklerini, geçişlerini ve hata durumlarını dinleyebilir ve izleyebiliriz. Bu başlıkta, Spring State Machine’de custom listener ve monitor nasıl oluşturulacağı ve kullanılacağı üzerinde duracağız.

Neden Custom Listener ve Monitor Kullanmalıyız?

  • Durum Takibi: State Machine’in hangi durumlarda olduğunu ve bu durumlar arasında nasıl geçiş yaptığını izlemek için.

  • Hata Yönetimi: State Machine’de oluşabilecek hataları tespit etmek ve loglamak için.

  • Performans İzleme: State Machine geçişlerinin ne kadar sürdüğünü izlemek ve performans analizleri yapmak için.

  • Olay Bazlı İşlem: Belirli olaylar gerçekleştiğinde özel işlemler gerçekleştirmek için (örneğin, bir geçiş tamamlandığında başka bir hizmeti tetiklemek gibi).

Custom Listener Sınıfı

Custom Listener, State Machine olaylarını dinleyebilmemizi sağlar. Aşağıda, bu sınıfın nasıl oluşturulacağı ve kullanılacağı gösterilmektedir.

@Service
public class CustomStateMachineListener 
	implements StateMachineListener<String, String> 
{    
	private final Logger logger = 
		LoggerFactory.getLogger(CustomStateMachineListener.class);    
	@Override    
	public void stateChanged(
		State<String, String> from, State<String, String> to
	) {        
		System.out.printf(                
			"\033[1;34m %s -> Listener Operation: stateChanged, From: 	
			%s, To: %s, Thread: %d%n \033[0m",                
			LocalDateTime.now(),                
			from != null ? from.getId() : "",                
			to != null ? to.getId() : "",                
			Thread.currentThread().getId()
		);        
		logger.info("State Changed : {} => {}", from, to);    
	}    
	@Override    
	public void stateEntered(State<String, String> state) {        
		System.out.printf(                
			"\033[1;34m %s -> Listener Operation: stateEntered, State: 
			%s, Thread: %d%n \033[0m",                
			LocalDateTime.now(),                
			state != null ? state.getId() : "",                
			Thread.currentThread().getId()
		);        
		logger.info("State Entered : {}", state);    
	}    
	@Override    
	public void stateExited(State<String, String> state) {        
		System.out.printf(                
			"\033[1;34m %s -> Listener Operation: stateExited, State: 
			%s, Thread: %d%n \033[0m",                
			LocalDateTime.now(),                
			state != null ? state.getId() : "",                
			Thread.currentThread().getId()
		);        
		logger.info("State Exited : {}", state);    
	}    
	@Override    
	public void eventNotAccepted(Message<String> event) {        
		System.err.printf(                
			"\033[1;34m %s -> Listener Operation Error: 
			eventNotAccepted, Event: %s, Thread: %d%n 	
			\033[0m",                
			LocalDateTime.now(),                
			event,                
			Thread.currentThread().getId()
		);        
		logger.error("Event Not Accepted : {}", event);    
	}    
	@Override    
	public void transition(
		Transition<String, String> transition
	) {        
		String source = transition.getSource() != null ? 
			transition.getSource().getId() : "";        
		String event = transition.getTrigger() != null ? 
			transition.getTrigger().getEvent() : "";        
		String target = transition.getTarget() != null ? 
			transition.getTarget().getId() : "";        
		System.out.printf(                
			"\033[1;34m %s -> Listener Operation: transition, 
			Transition: %s -- %s --> %s, Thread: %d%n 
			\033[0m",                
			LocalDateTime.now(),                
			source,                
			event,                
			target,                
			Thread.currentThread().getId()
		);        
		logger.info("Transition : {} -- {} --> {}", source, event, 	
			target);    
	}    
	@Override    
	public void transitionStarted(
		Transition<String, String> transition
	) {        
		String source = transition.getSource() != null ? 
			transition.getSource().getId() : "";        
		String event = transition.getTrigger() != null ? 
			transition.getTrigger().getEvent() : "";        
		String target = transition.getTarget() != null ? 
			transition.getTarget().getId() : "";        
		System.out.printf(                
			"\033[1;34m %s -> Listener Operation: transitionStarted, 
			Transition: %s -- %s --> %s, Thread: %d%n 
			\033[0m",                
			LocalDateTime.now(),                
			source,                
			event,                
			target,                
			Thread.currentThread().getId()
		);        
		logger.info("Transition Started : {} -- {} --> {}", source, 
			event, target);    
	}    
	@Override    
	public void transitionEnded(
		Transition<String, String> transition
	) {        
		String source = transition.getSource() != null ? 
			transition.getSource().getId() : "";        
		String event = transition.getTrigger() != null ? 
			transition.getTrigger().getEvent() : "";        
		String target = transition.getTarget() != null ? 
			transition.getTarget().getId() : "";        
		System.out.printf(                
			"\033[1;34m %s -> Listener Operation: transitionEnded, 
			Transition: %s -- %s --> %s, Thread: %d%n 
			\033[0m",                
			LocalDateTime.now(),                
			source,                
			event,                
			target,                
			Thread.currentThread().getId()
		);        
		logger.info("Transition Ended : {} -- {} --> {}", source, event, 
			target);    
	}    
	@Override    
	public void stateMachineStarted(
		StateMachine<String, String> stateMachine
	) {        
		System.out.printf(                
			"\033[1;34m %s -> Listener Operation: stateMachineStarted, 
			Machine Id: %s, Machine UUID: %s, Thread: %d%n 
			\033[0m",                
			LocalDateTime.now(),                
			stateMachine.getId(),                
			stateMachine.getUuid(),                
			Thread.currentThread().getId()
		);        
		logger.info("State Machine Started : {}", stateMachine);    
	}    
	@Override    
	public void stateMachineStopped(
		StateMachine<String, String> stateMachine
	) {        
		System.out.printf(                
			"\033[1;34m %s -> Listener Operation: stateMachineStopped, 
			Machine Id: %s, Machine UUID: %s, Thread: %d%n 
			\033[0m",                
			LocalDateTime.now(),                
			stateMachine.getId(),                
			stateMachine.getUuid(),                
			Thread.currentThread().getId()
		);        
		logger.info("State Machine Stopped : {}", stateMachine);    
	}    
	@Override    
	public void stateMachineError(
		StateMachine<String, String> stateMachine, Exception e
	) {        
		System.err.printf(                
			"\033[1;34m %s -> Listener Operation Error: 
			stateMachineError, Machine Id: %s, Machine UUID: %s, Error: 
			%s, Thread: %d%n \033[0m",                
			LocalDateTime.now(),                
			stateMachine.getId(),                
			stateMachine.getUuid(),                
			e.getClass().getSimpleName(),                
			Thread.currentThread().getId()
		);        
		logger.error("State Machine Error : State Machine => {}, 
			Exception => {}", stateMachine, e);    
	}    
	@Override    
	public void extendedStateChanged(Object o, Object o1) {        
		// Uygulama gereksinimlerine göre doldurulabilir    
	}    
	@Override    
	public void stateContext(
		StateContext<String, String> stateContext
	) {        
		System.out.printf(                
			"\033[1;34m %s -> Listener Operation: stateContext, Current 
			State: %s, Thread: %d%n \033[0m",                
			LocalDateTime.now(),                
			stateContext.getStateMachine().getState() != null ? 					
				stateContext.getStateMachine()
					.getState().getId() 
				: "",                
			Thread.currentThread().getId()
		);        
		logger.info("StateContext : {}", stateContext);    
	}
}

Bu sınıf, State Machine olaylarını dinleyerek loglama işlemleri yapar. Her bir olay için konsola renkli çıktılar verir ve olayları loglar.

Custom Monitor Sınıfı

Custom Monitor, State Machine geçişlerini ve aksiyonlarını izleyerek performans analizleri yapmamızı sağlar.

@Service
public class CustomStateMachineMonitor 
	extends AbstractStateMachineMonitor<String, String> 
{    
	private final Logger logger = 
		LoggerFactory.getLogger(CustomStateMachineMonitor.class);    
	@Override    
	public void transition(
		StateMachine<String, String> stateMachine, 
		Transition<String, String> transition, 
		long duration
	) {        
		String source = transition.getSource() != null ? 
			transition.getSource().getId() : "";        
		String event = transition.getTrigger() != null ? 
			transition.getTrigger().getEvent() : "";        
		String target = transition.getTarget() != null ? 
			transition.getTarget().getId() : "";        
		System.out.printf(                
			"\033[46m %s -> Monitor Operation: transition, State Machine 
			ID: %s, Transition: %s -- %s --> %s, Duration: %d%n 
			\033[0m",                
			LocalDateTime.now(),                
			stateMachine.getId(),                
			source,                
			event,                
			target,                
			duration
		);        
		logger.info("Transition : {} -- {} --> {} Duration => {}", 
			source, event, target, duration);    
	}    
	@Override    
	public void action(
		StateMachine<String, String> stateMachine, 
		Function<StateContext<String, String>, 
		Mono<Void>> action, 
		long duration
	) {        
		System.out.printf(                
			"\033[46m %s -> Monitor Operation: action, State Machine ID: 
			%s, Action: %s, Duration: %d%n \033[0m",                
			LocalDateTime.now(),                
			stateMachine.getId(),                
			action.toString(),                
			duration
		);        
		logger.info("Action : State Machine => {}, Action => {}, Duration 			
			=> {}", stateMachine, action, duration);    
	}
}

State Machine Transition Başlatma

Spring State Machine, karmaşık iş akışlarını ve geçiş durumlarını yönetmek için güçlü bir araçtır. Bu araç, belirli bir State Machine başlatılarak ve olay gönderimi yapılarak durumların dinamik olarak değiştirilmesini sağlar. Bu makalede, Spring State Machine Service kullanılarak bir State Machine’in nasıl başlatılacağı ve bir olayı nasıl göndereceğiniz anlatılacaktır.

State Machine’i Başlatma ve Olay Gönderme

Bir State Machine başlatmak ve bir olay göndermek için aşağıdaki adımları izleyebilirsiniz:

1. State Machine’i Alma:

İlk olarak, ilgili State Machine’i almak için gerekli işlemleri yapmalısınız. Aşağıda bir örnek verilmiştir:

StateMachine<String, String> stateMachine = getStateMachine(flow);

2. State Machine’i Başlatma:

State Machine’i başlatmak için startReactively metodunu kullanabilirsiniz. Bu metot, State Machine’in reaktif olarak başlatılmasını sağlar. block() metodu, işlemin tamamlanmasını beklemek için kullanılır.

stateMachine.startReactively().block();

3. Olay Gönderimi:

Bir olay göndermek için sendEvent metodunu kullanabilirsiniz. Bu metot, belirtilen olayı State Machine’e gönderir. Olayı göndermek için Mono.just ve MessageBuilder kullanarak bir mesaj oluşturabilirsiniz. blockLast() metodu, işlemin tamamlanmasını beklemek için kullanılır.

stateMachine.sendEvent(
	Mono.just(  
		MessageBuilder.withPayload(event).build()
	)
).blockLast();

Aşağıda, bir State Machine’i başlatmak ve bir olay göndermek için tam bir örnek verilmiştir:

public void initiateStateMachine(Flow flow, String event) {    
	// State Machine'i alma    
	StateMachine<String, String> stateMachine = 
		getStateMachine(flow);    
	// State Machine'i başlatma    
	stateMachine.startReactively().block();    
	// Olay gönderimi    
	stateMachine.sendEvent(
		Mono.just(      
			MessageBuilder.withPayload(event).build()
		)
	).blockLast();    
	// Durum güncellemeleri ve kontrol    
	if (stateMachine.getState().getId().equals("EXPECTED_STATE")) 	
	{        
		System.out.println("State transition was successful!");    
	} else {        
		System.out.println("State transition failed.");    
	}
}

Detaylı Açıklama

  1. State Machine’i Alma: getStateMachine(flow) metodu, ilgili State Machine’i döndürür. Bu metot, flow parametresine göre doğru State Machine’i seçer.

  2. State Machine’i Başlatma: stateMachine.startReactively().block(); komutu, State Machine’in reaktif olarak başlatılmasını sağlar. Bu, State Machine’in başlatıldığından emin olmak için kullanılır.

  3. Olay Gönderimi: stateMachine.sendEvent(Mono.just(MessageBuilder.withPayload(event).build())).blockLast(); komutu, belirtilen olayı State Machine’e gönderir. Mono.just ve MessageBuilder kullanarak bir mesaj oluşturulur ve sendEvent metodu ile gönderilir.

  4. Durum Güncellemeleri ve Kontrol: Son olarak, State Machine’in geçiş durumunu kontrol edebilirsiniz. stateMachine.getState().getId() metodu, State Machine’in mevcut durumunu döndürür. Bu durumu kontrol ederek geçişin başarılı olup olmadığını belirleyebilirsiniz.

State Machine için oluşturduğum demo projenin reposu;

3 görüntüleme0 yorum

Comments


bottom of page