Spring Integration: සංකීර්ණ වැඩ පහසු කරමු - SC Guide

ආයුබෝවන් ඩෙවලොපර්ස්ලා! කොහොමද ඉතින් ඔයාලට? අද අපි කතා කරන්න යන්නේ සාමාන්යයෙන් අපිට දවසින් දවස මුණගැහෙන Software Engineering වල තියෙන ටිකක් සංකීර්ණ ප්රශ්නයක් ගැන. ඒ තමයි වෙනස් වෙනස් Software Systems කිහිපයක් එකිනෙකා එක්ක කතා කරන්නේ, වැඩ කරන්නේ කොහොමද කියන එක. හිතන්නකො, අපේ ලංකාවේ බැංකු පද්ධති ගැන. එක බැංකුවක පද්ධතියක් තව බැංකුවක පද්ධතියක් එක්ක, නැත්නම් ඒගොල්ලන්ගේම වෙනත් අංශයක පද්ධතියක් එක්ක, එහෙම නැත්නම් තුන්වෙනි පාර්ශවයක (Third-party) ගෙවීම් පද්ධතියක් එක්ක සම්බන්ධ වෙන්නේ කොහොමද? මේ වගේ තැන්වලදී අපිට Enterprise Integration Patterns (EIP) කියන Concepts Set එකක් ගොඩක් වැදගත් වෙනවා. මේ EIP Concepts එක practical විදිහට Implement කරන්න පුළුවන් Framework එකක් තමයි Spring Integration කියන්නේ.
සාමාන්යයෙන් අපේ Application එකක් කියන්නේ පොඩි පොඩි කොටස් ගොඩකින් හැදිලා තියෙන එකක්. මේ කොටස් (Components) අතරේ තියෙන Communication එක, ඒ කියන්නේ දත්ත හුවමාරුව සහ ඒවා Process කරන විදිය, ගොඩක් වෙලාවට සංකීර්ණ වෙන්න පුළුවන්. විශේෂයෙන්ම Microservices Architectures වගේ තැන්වලදී මේ ගැටලුව තවත් වැඩි වෙනවා. මේ වගේ තැනකදි අපිට අවශ්ය වෙනවා මේ කොටස් අතරේ තියෙන සම්බන්ධතාවය (Integration) ලේසි කරන්න, Manage කරන්න, ඒ වගේම හොඳට Scaling කරන්න පුළුවන් විදිහට හදාගන්න. Spring Integration කියන්නේ හරියට මේ වගේ අවස්ථාවලදී අපේ අතට ලැබෙන සුපිරි උපකරණයක් වගේ තමයි. අද අපි මේ ගැන මුල ඉඳලම කතා කරමු, ඒ වගේම පොඩි ප්රායෝගික උදාහරණයක් එක්ක කොහොමද මේක වැඩ කරන්නේ කියලත් බලමු.
Spring Integration කියන්නේ මොකක්ද?
සරලවම කියනවා නම්, Spring Integration කියන්නේ Enterprise Integration Patterns (EIP) Implementation කරන්න පහසුකම් සලසන, Spring Framework එකට සම්බන්ධ (Extension) Open-Source Framework එකක්. මේක පදනම් වෙලා තියෙන්නේ Message-Driven Architecture එක මත. ඒ කියන්නේ, Components අතරේ Communication එක වෙන්නේ සෘජුවම Functions Call කරනවා වෙනුවට Messages හරහා.
මේ Framework එකේ ප්රධාන Concepts කිහිපයක් තියෙනවා:
- Message (පණිවිඩය): Integration Flow එකකදී දත්ත හුවමාරු වෙන මූලිකම ඒකකය තමයි Message එකක් කියන්නේ. Message එකකට කොටස් දෙකක් තියෙනවා: Payload එක සහ Headers. Payload එක කියන්නේ අපිට යවන්න ඕන Actual Data එක (උදා: JSON Object එකක්, String එකක්, Java Object එකක්). Headers කියන්නේ ඒ Data එක ගැන Meta-Information, ඒ කියන්නේ Message ID එක, Timestamp එක, Reply-To Channel එක වගේ දේවල්.
- Message Channel (පණිවිඩ නාලිකාව): මේවා හරියට පණිවිඩ ගමන් කරන පාරවල් වගේ. Source එකකින් එන Message එකක් Destination එකකට යවන්නේ Channel එකක් හරහා. Message Channel එකකට එක Endpoint එකකින් Message එකක් යවන්න පුළුවන් වගේම, තව Endpoint එකකින් ඒක ගන්නත් පුළුවන්. Spring Integration වලදී ප්රධාන Message Channel වර්ග දෙකක් තියෙනවා:
- Point-to-Point Channel: මේ Channel එකකට එක Message එකක් යැව්වම, ඒක එක Consumer කෙනෙක්ට විතරයි යන්නේ. හරියට දුරකථන ඇමතුමක් වගේ.
- Publish-Subscribe Channel: මේ Channel එකකට Message එකක් යැව්වම, ඒක Subscribe කරලා තියෙන හැම Consumer කෙනෙක්ටම යවන්න පුළුවන්. හරියට Radio Broadcast එකක් වගේ.
- Message Endpoint (පණිවිඩ අවසාන ලක්ෂ්යය): මේවා තමයි Messages Convert කරන, Process කරන, Routing කරන Components. Endpoint එකක් Channel එකකින් Message එකක් අරගෙන, ඒක Process කරලා, තව Channel එකකට යවන්න පුළුවන්. Spring Integration වල තියෙන ප්රධාන Message Endpoint වර්ග කිහිපයක්:
- Channel Adapter: බාහිර System (Files, Databases, REST APIs, JMS Queues) එක්ක සම්බන්ධ වෙන්න මේවා පාවිච්චි කරනවා. උදාහරණයක් විදිහට, File System එකකින් File එකක් කියවන්න File Inbound Channel Adapter එකක් පාවිච්චි කරන්න පුළුවන්.
- Transformer: මේක Message එකක Payload එකේ Format එක වෙනස් කරනවා. උදා: XML එකක් JSON බවට පත් කරනවා.
- Filter: මේකෙන් Message එකක් Flow එකේ ඊළඟ පියවරට යවන්න ඕනෙද නැද්ද කියලා තීරණය කරනවා.
- Router: Message එකක Content එක මත පදනම් වෙලා, ඒක යවන්න ඕන Channel එක තීරණය කරනවා.
- Splitter: එක Message එකක් පොඩි පොඩි Message කීපයකට බෙදනවා.
- Aggregator: Split කරපු Message කීපයක් නැවත එක Message එකක් බවට එකතු කරනවා.
- Service Activator: Message එකක් ලැබුණම අපේ Business Logic එක ක්රියාත්මක කරනවා. මේක සාමාන්ය Java Class එකක Method එකක් වෙන්න පුළුවන්.
මේ Concepts ටික එකට එකතු වෙලා තමයි සංකීර්ණ Integration Flow එකක් හැදෙන්නේ. හරියට මොඩියුලර් බිල්ඩින් බ්ලොක්ස් වගේ, අපිට ඕන විදිහට මේවා එකතු කරලා සංකීර්ණ දේවල් හදන්න පුළුවන්.
ඇයි අපිට Spring Integration ඕනේ?
හරි, දැන් අපි දන්නවා Spring Integration කියන්නේ මොකක්ද කියලා. ඒත් ඇයි අපිට මේක ඕනේ? අපිට සාමාන්ය Functions Call කරලා, APIs Call කරලා වැඩ කරන්න බැරිද? පුළුවන්, හැබැයි මේ වගේ සංකීර්ණ Integration Flow එකක් Manage කරන්න යනකොට Spring Integration අපිට ගොඩක් ප්රයෝජනවත් වෙනවා.
- Loose Coupling (නොගැටෙන සම්බන්ධතාවය): Spring Integration වලදී Components එකිනෙකා එක්ක කෙලින්ම සම්බන්ධ වෙන්නේ නැහැ. ඒ වෙනුවට ඔවුන් Channel එකක් හරහා Messages යවනවා. මේ නිසා එක Component එකක් වෙනස් කළොත්, ඒක අනෙක් Components වලට බලපාන්නේ නැහැ. Microservices Architectures වලදී මේක ගොඩක් වැදගත් වෙනවා, මොකද අපිට එක Service එකක් Update කරන්න පුළුවන් අනෙක් Service වලට බලපෑමක් නැතුව.
- Reusability (නැවත භාවිතය): Enterprise Integration Patterns (EIP) මත පදනම් වෙලා තියෙන නිසා, පොදු Integration Logic එක නැවත නැවතත් පාවිච්චි කරන්න පුළුවන්. උදාහරණයක් විදිහට, File කියවන Component එකක්, වෙනත් ඕනෑම Application එකකට පාවිච්චි කරන්න පුළුවන්.
- Maintainability and Readability (පහසු නඩත්තු කිරීම සහ කියවීමේ පහසුව): Flow එක Message Channel හරහා දෘශ්යමාන (Visual) විදිහට හදාගන්න පුළුවන් නිසා, System එකේ Flow එක තේරුම් ගන්නත්, ඒක නඩත්තු කරන්නත් ලේසියි. නවක ඩෙවලොපර් කෙනෙක්ට වුණත් System එක කොහොමද වැඩ කරන්නේ කියලා ඉක්මනට තේරුම් ගන්න පුළුවන්.
- Error Handling (දෝෂ හැසිරවීම): Spring Integration වලට ගොඩක් දියුණු Error Handling Mechanisms තියෙනවා. Messages Fail වුණොත් ඒවා Recover කරන්න, නැවත යවන්න (Retry), Dead-Letter Channels වලට යවන්න වගේ දේවල් කරන්න පුළුවන්. මේක Enterprise Systems වලදී අනිවාර්යයි.
- Extensibility (විස්තීරණය කිරීමේ හැකියාව): අපිට ඕන නම් Custom Components ලියලා අපේ Flow එකට එකතු කරන්න පුළුවන්. ඒ වගේම Spring Framework එකත් එක්ක ගොඩක් හොඳට වැඩ කරන නිසා, Spring Data, Spring Security වගේ දේවල් එක්ක Integration කරන්නත් ලේසියි.
- Abstraction of underlying transport (පහළ ස්තරයේ ගමනාගමනයෙන් වියුක්ත වීම): අපිට Files, JMS, AMQP, REST, JDBC වගේ ඕනෑම Transport එකක් පාවිච්චි කරන්න පුළුවන්. Spring Integration මේ හැම එකක්ම Message Channels බවට Abstraction කරන නිසා, අපිට Transport එක ගැන වැඩිය හිතන්නේ නැතුව Business Logic එක ගැන අවධානය යොමු කරන්න පුළුවන්.
ඔය වගේ හේතු නිසා, විශේෂයෙන්ම සංකීර්ණ, distributed Systems ගොඩනගනකොට Spring Integration කියන්නේ නැතුවම බැරි උපකරණයක් වෙලා තියෙනවා.
Practical Example: සරල Integration Flow එකක් ගොඩනගමු
හරි, දැන් අපි මේ Spring Integration Concepts කොහොමද ප්රායෝගිකව පාවිච්චි කරන්නේ කියලා පොඩි උදාහරණයක් බලමු. අපි හිතමු අපිට ඕනේ සරල File Processing Application එකක් හදන්න කියලා. මේකෙන් කරන්නේ, අපි දෙන Folder එකක අලුතින් File එකක් දාපු ගමන්, ඒ File එකේ Content එක කියවලා, ඒක Console එකේ Print කරන එක. පස්සේ ඒ File එක Processed Folder එකකට Move කරන එක.
මේකට අවශ්ය වෙන්නේ ප්රධාන Components තුනක්:
- Input Folder එක Monitor කරන Channel Adapter එකක්.
- File එකේ Content එක Process කරන Service Activator එකක්.
- Processed File එක Move කරන Channel Adapter එකක්.
අපි මේක Spring Boot Application එකක් විදිහට හදමු, ඒ වගේම Spring Integration Java DSL (Domain Specific Language) එක පාවිච්චි කරමු. මේක XML වලට වඩා කියවන්න ලේසියි.
Dependencies (pom.xml
)
මුලින්ම, අපිට අවශ්ය Dependencies ටික pom.xml
එකට එකතු කරගමු:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-file</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
</dependency>
</dependencies>
Spring Integration Configuration (Java DSL)
ඊළඟට, අපේ Spring Integration Flow එක Configure කරමු. අපි මේක Configuration Class එකක් විදිහට ලියනවා.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.dsl.IntegrationFlow;
import org.springframework.integration.dsl.IntegrationFlows;
import org.springframework.integration.file.FileReadingMessageSource;
import org.springframework.integration.file.FileWritingMessageHandler;
import org.springframework.messaging.Message;
import java.io.File;
import java.nio.file.Files;
import java.util.Objects;
@Configuration
@EnableIntegration
public class FileIntegrationConfig {
private final String INPUT_DIR = "input";
private final String OUTPUT_DIR = "output";
// 1. File Reading Message Source (Inbound Channel Adapter)
// මේකෙන් 'input' ෆෝල්ඩරයේ අලුත් files කියවනවා.
@Bean
public FileReadingMessageSource fileReadingMessageSource() {
File inputDir = new File(INPUT_DIR);
if (!inputDir.exists()) {
inputDir.mkdirs(); // ෆෝල්ඩරය නැත්නම් හදනවා
}
return new FileReadingMessageSource();
}
// 2. File Writing Message Handler (Outbound Channel Adapter)
// Process කරපු files 'output' ෆෝල්ඩරයට move කරනවා.
@Bean
@ServiceActivator(inputChannel = "fileProcessChannel") // මේක 'fileProcessChannel' එකෙන් messages ගන්නවා
public FileWritingMessageHandler fileWritingMessageHandler() {
File outputDir = new File(OUTPUT_DIR);
if (!outputDir.exists()) {
outputDir.mkdirs(); // ෆෝල්ඩරය නැත්නම් හදනවා
}
FileWritingMessageHandler handler = new FileWritingMessageHandler(outputDir);
handler.setDeleteSourceFiles(true); // Source file එක delete කරනවා (move කරනවා)
handler.setExpectReply(false); // Reply එකක් බලාපොරොත්තු වෙන්නේ නැහැ
return handler;
}
// 3. The Integration Flow
// මේක තමයි අපේ File Processing Flow එක.
@Bean
public IntegrationFlow fileProcessingFlow() {
return IntegrationFlows.from(fileReadingMessageSource(),
c -> c.poller(p -> p.fixedDelay(1000))) // සෑම තත්පර 1 කට වරක් input ෆෝල්ඩරය check කරනවා
.filter(File.class, File::isFile) // files විතරක් process කරන්න filter කරනවා
.transform(File.class, file -> { // file එකේ content එක String එකක් බවට transform කරනවා
try {
return Files.readString(file.toPath());
} catch (Exception e) {
throw new RuntimeException("Error reading file: " + file.getName(), e);
}
})
.handle((payload, headers) -> { // Service Activator - content එක print කරනවා
System.out.println("------------------------------------");
System.out.println("Received and processed file content:");
System.out.println(payload);
System.out.println("------------------------------------");
// මේකෙන් original File object එක next step එකට යවනවා.
// Headers වලින් original File path එක ගන්නවා.
return headers.get("file_originalFile");
})
.channel("fileProcessChannel") // Process කරපු file එක 'fileProcessChannel' එකට යවනවා
.get(); // Flow එක build කරනවා
}
}
Application Main Class
සාමාන්ය Spring Boot Application එකක් විදිහට මේක Run කරන්න පුළුවන්.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringIntegrationDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringIntegrationDemoApplication.class, args);
System.out.println("Spring Integration Demo Application Started. Drop files into the 'input' folder.");
}
}
මෙය වැඩ කරන්නේ මෙහෙමයි:
fileReadingMessageSource()
: මේක තමයි අපේ Flow එක පටන් ගන්නේ. මේක File Inbound Channel Adapter එකක්. මේකෙන් "input" කියන Folder එක සෑම තත්පරයකටම වරක් Polling කරනවා (කියන්නේ check කරනවා). අලුත් File එකක් detect වුණොත්, ඒක Message එකක් විදිහට Flow එකට ඇතුල් කරනවා..filter(File.class, File::isFile)
: Folder එකේ directories තිබ්බොත් ඒවා skip කරලා, files විතරක් process කරන්න මේකෙන් filter කරනවා..transform(File.class, file -> ...)
: මේක Transformer එකක්. මේකෙන් File Object එකේ Payload එක, ඒ File එකේ Content එක (String විදිහට) බවට Convert කරනවා. ඒ කියන්නේ, Message එකේ Payload එක දැන් File එකේ නම නෙවෙයි, ඒක ඇතුලේ තියෙන දත්ත..handle((payload, headers) -> ...)
: මේක Service Activator එකක්. Message එකේ Payload එක (File Content එක) Console එකේ Print කරනවා. මෙතනදී අපි පොඩි උපක්රමයක් පාවිච්චි කරනවා: File Writing Message Handler එකට Original File එකේ Reference එක යවන්න ඕන නිසා, අපිට Headers වලින්file_originalFile
කියන Header එකෙන් Original File Object එක ගන්නවා. මේක Spring Integration Framework එකෙන් Auto Add කරන Header එකක්..channel("fileProcessChannel")
: Process කරපු Message එකfileProcessChannel
කියන Channel එකට යවනවා. මේ Channel එක Point-to-Point Channel එකක්.fileWritingMessageHandler()
: මේක තමයි අපේ Flow එකේ අන්තිම කොටස. මේක File Outbound Channel Adapter එකක්. මේකෙන්fileProcessChannel
එකෙන් එන Messages අරගෙන, ඒ Messages වල අඩංගු Original File Object එක (Payload එක) "output" කියන Folder එකට Move කරනවා.setDeleteSourceFiles(true)
කියන එකෙන් කියවෙන්නේ Source File එක, ඒ කියන්නේ "input" Folder එකේ තිබ්බ Original File එක, Move කළාට පස්සේ Delete කරන්න කියන එකයි.
මේ Application එක Run කරලා, "input" කියන Folder එක ඇතුළට .txt File එකක් (හෝ වෙනත් ඕනෑම File එකක්) දාලා බලන්න. ඒ File එකේ Content එක Console එකේ Print වෙලා, File එක "output" Folder එකට Move වෙනවා පෙනේවි. මේක සරල උදාහරණයක් වුණත්, මේකෙන් අපිට Spring Integration වල බලය හොඳට තේරෙනවා.
තව දුරටත් ඉගෙන ගමු
මේ අපි කතා කළේ Spring Integration වල මූලිකම දේවල් ගැන විතරයි. මේ Framework එක ගොඩක් දියුණුයි, ඒ වගේම ගොඩක් දේවල් කරන්න පුළුවන්. උදාහරණයක් විදිහට:
- Adapters: File Adapters වගේම, JMS, AMQP, Kafka, Web Services, JDBC, FTP/SFTP වගේ ගොඩක් System එක්ක Integrate වෙන්න පුළුවන් Adapters Spring Integration එකේ තියෙනවා.
- Transformers: XML to JSON, Object to XML වගේ විවිධ Data Transformations කරන්න පුළුවන්.
- Routers: Message එකක Content එක මත පදනම් වෙලා වෙනස් Channel වලට Messages යවන්න පුළුවන්.
- Splitters and Aggregators: Batch Processing, Scatter-Gather වගේ Patterns Implement කරන්න මේවා පාවිච්චි කරනවා.
- Error Handling: Dead-Letter Channels, Retry Advice වගේ දේවල් පාවිච්චි කරලා Robust Error Handling Implement කරන්න පුළුවන්.
- Monitoring: Actuator වගේ Spring Boot Features එක්ක Integration කරලා Flow එකේ Status එක, Performance එක Monitor කරන්න පුළුවන්.
මේ හැම එකක්ම Enterprise System එකකදී අතිශයින්ම වැදගත් වෙනවා. ඔබට තවත් සංකීර්ණ Integration Problems තියෙනවා නම්, Spring Integration ඔබට හොඳම විසඳුමක් වෙන්න පුළුවන්.
අවසාන වශයෙන්...
ඉතින් ඩෙවලොපර්ස්ලා, Spring Integration කියන්නේ සංකීර්ණ Application Integration ගැටළු විසඳන්න තියෙන සුපිරි උපකරණයක් කියලා දැන් ඔබට තේරෙනවා ඇති. විශේෂයෙන්ම Microservices Architectures වගේ තැන්වලදී මේකේ වටිනාකම තවත් වැඩි වෙනවා. මේ Framework එක හරහා ඔබට Scalable, Maintainable, සහ Robust Integration Solutions හදන්න පුළුවන්.
ඔබත් අදම මේක Try කරලා බලන්න. මම දීපු සරල උදාහරණයෙන් පටන් අරන්, පොඩ්ඩ පොඩ්ඩ වෙනස් කරලා, තව දේවල් එකතු කරලා බලන්න. Spring Integration official documentation එකත් ගොඩක් හොඳයි, ඒකෙන් තවත් ගොඩක් දේවල් ඉගෙන ගන්න පුළුවන්. මේ ගැන ඔයාලට තියෙන අදහස්, ප්රශ්න පහලින් comment කරන්න. අපි ඊළඟ ලිපියෙන් තවත් වටිනා දෙයක් ගැන කතා කරමු. ඔබට ජය!