Spring Boot Custom Starter හදමු | ඔබේම Starter එකක් නිර්මාණය කරමු - Sinhala Developer Guide

Spring Boot Custom Starter හදමු | ඔබේම Starter එකක් නිර්මාණය කරමු - Sinhala Developer Guide

ආයුබෝවන් ඩෙවලොපර්ස්ලා හැමෝටම!

මේ දවස්වල Spring Boot ගැන කතා නොකර ඉන්න බෑනේ. පොඩි ඇප් එකක්ද, ලොකු මයික්‍රෝසර්විස් සිස්ටම් එකක්ද, හැම දේටම වගේ Spring Boot තමයි දැන් ගොඩක් අයගේ කැමැත්ත. ඒක එච්චරටම ලේසියි, වැඩ ගොඩක් අඩු කරනවා, අපේ කාලය ඉතුරු කරනවා. අද අපි කතා කරන්න යන්නේ Spring Boot එකේ තියෙන හරිම වැදගත් සහ ප්‍රයෝජනවත් සංකල්පයක් ගැන – ඒ තමයි Custom Spring Boot Starters!

අනේ මන්දා, සමහර වෙලාවට අපිට හිතෙනවා නේද, "අපෝ මේක ආයෙත් ආයෙත් ලියන්න එපැයි" කියලා? නැත්නම්, "මේ සෙටප් එක හැම ප්‍රොජෙක්ට් එකකම දාන්න ඕනෙද බන්?" කියලා. ඔන්න ඔය වගේ වෙලාවට තමයි මේ Custom Starters අපේ ජීවිතේට එන්නේ. අපි බලමු මේවා මොනවද, ඇයි අපිට මේවා ඕනෙ වෙන්නේ, සහ කොහොමද අපේම Starter එකක් හදාගන්නේ කියලා.

"Spring Boot Starter" කියන්නේ මොනවාද?

සරලවම කිව්වොත්, Spring Boot Starter එකක් කියන්නේ dependency set එකක්. ඒ කියන්නේ, එක තැනකට එකතු කරපු dependency ටිකක්. සාමාන්‍යයෙන් අපි මොකක් හරි ෆීචර් එකක් ඇප් එකකට දානකොට (උදාහරණයක් විදියට Web ඇප් එකක් නම්, data storage නම්, security නම්) එක dependency එකක් නෙවෙයි දාන්නේ. ඒකට අදාළ dependency ගොඩක් එකතු කරන්න වෙනවා. ඒවා එකිනෙකට ගැළපෙන්න ඕනේ, versions බලන්න ඕනේ, ඒවාට ඕන කරන තව dependency තියෙනවනම් ඒවාත් දාන්න ඕනේ... මේක හරිම කරදර වැඩක්!

Spring Boot Starters මේ වැඩේ හරිම ලේසි කරනවා. උදාහරණයක් විදියට, ඔයාට Web ඇප් එකක් හදන්න ඕන නම්, ඔයා කරන්නේ spring-boot-starter-web කියන dependency එක Project එකට add කරන එක විතරයි. එතකොට Spring Boot එකම ඒකට අවශ්‍ය Tomcat server එක, Spring MVC, REST support එක වගේ හැම දෙයක්ම අරන් එනවා. ඔයාට වෙන මුකුත් බලන්න දෙයක් නෑ.

මේවා Autoconfiguration කියන concept එකත් එක්ක වැඩ කරනවා. ඒ කියන්නේ, ඔයා Starter එකක් add කරාම, Spring Boot එක බලනවා "අප්පට සිරි, මේක දාලා නේ! එහෙනම් මේවට ඕන කරන බීන්ස් (beans) ටික මමම හදලා දෙන්නම්" කියලා. එතකොට ඔයාට මේවා manually configure කරන්න ඕනේ නෑ. එහෙමම පාවිච්චි කරන්න පුළුවන්.

Spring Boot එකේ ගොඩක් built-in starters තියෙනවා. ටිකක් බලමු නේද?

  • spring-boot-starter-web: Web applications, including RESTful applications.
  • spring-boot-starter-data-jpa: Using Spring Data JPA with Hibernate.
  • spring-boot-starter-security: Spring Security support.
  • spring-boot-starter-test: Testing Spring Boot applications.
  • spring-boot-starter-actuator: Production-ready features like monitoring and metrics.

දැන් තේරෙනවා නේද මේවා කොයිතරම් ප්‍රයෝජනවත්ද කියලා? අපේ dependency ගොඩක් අඩු කරනවා, version conflicts වළක්වනවා, boilerplate code ගොඩක් ලියන එක නවත්වනවා.

ඇයි අපිට Custom Starter එකක් ඕනෙ වෙන්නේ?

හරි, දැන් අපි දන්නවා built-in starters වලින් වැඩේ ලේසි වෙන හැටි. එතකොට ඇයි අපිට අපේම starter එකක් හදාගන්න ඕනෙ වෙන්නේ? මේවා ගොඩක් වෙලාවට useful වෙන්නේ මෙන්න මේ වගේ scenarios වලදී:

  1. Internal Libraries/Modules: ඔයාගේ කම්පැණි එකේ ඇතුළේ common service එකක් තියෙනවා කියමුකෝ. උදාහරණයක් විදියට, custom authentication service එකක්, පොදු payment gateway integration එකක්, නැත්නම් company එකේම standard logging mechanism එකක්. මේ වගේ දේවල් හැම ප්‍රොජෙක්ට් එකකම ආයෙත් ආයෙත් implement කරනවට වඩා, මේවටම starter එකක් හදලා තියෙනවනම්, අලුත් ප්‍රොජෙක්ට් එකකදී dependency එකක් විදියට add කරලා එහෙම්මම පාවිච්චි කරන්න පුළුවන්. හරිම ලේසියි නේද?
  2. Common Configurations: ඔයාගේ microservices ගොඩක එකම database configuration එකක්, message queue configuration එකක් නැත්නම් API Gateway configuration එකක් තියෙනවා කියමු. මේ හැම එකකටම වෙන වෙනම configure කරනවට වඩා, ඒවට පොදු starter එකක් හදලා, ඒකෙන් හැම service එකටම default configuration එකක් දෙන්න පුළුවන්. එතකොට code duplication අඩු වෙනවා, maintenance ලේසි වෙනවා.
  3. Third-party Library Integrations: සමහර වෙලාවට අපි third-party library එකක් පාවිච්චි කරනවා. ඒක Spring Boot එක්ක හරියට වැඩ කරන්න නම් ටිකක් configure කරන්න ඕන වෙනවා. ඒ වගේ වෙලාවට, ඒ library එකටම හරියන්න custom starter එකක් හැදුවොත්, ඒ library එක පාවිච්චි කරන අයට ලේසියෙන් ඒක Spring Boot Project එකකට add කරගන්න පුළුවන්.
  4. Boilerplate Code Reduction: නිතරම ලියන පොදු code block, utilities වගේ දේවල් starter එකක් ඇතුළට දාලා තියන්න පුළුවන්. එතකොට ඒවා අවශ්‍ය තැන්වලදී auto-configure වෙන්න සලස්වන්න පුළුවන්.

දැන් තේරෙනවා නේද, ඇයි මේ Custom Starters අපිට ගොඩක් වටින්නේ කියලා? මේවා අපේ productivity එක වැඩි කරනවා වගේම, code quality එකත් වැඩි කරනවා.

Custom Spring Boot Starter එකක් හදමු!

හරි, දැන් අපි කතා කරපු දේවල් ප්‍රායෝගිකව කරලා බලමු. Custom Spring Boot Starter එකක් හදනකොට සාමාන්‍යයෙන් modules දෙකක් හදනවා. ඒක හොඳ practice එකක්:

  1. [your-module]-spring-boot-starter: මේක තමයි අපේ "starter" module එක. මේකේ ඇතුළේ තියෙන්නේ වෙනත් dependency ටිකයි, අපේ Auto-configuration module එකේ dependency එකයි විතරයි. මේක තමයි අපේ usersලා dependency එකක් විදියට add කරගන්නේ.
  2. [your-module]-spring-boot-autoconfigure: මේක තමයි "auto-configuration" module එක. අපේ custom logic, configurations, properties වගේ හැම දෙයක්ම තියෙන්නේ මේකේ. මේකේ තමයි Spring Boot එක auto-configure කරන්න ඕන මොනවද කියලා අපි කියන්නේ.

අපි හදමු "Ayubowan" කියලා greetings දෙන පොඩි starter එකක්. ඒකේ message එක customize කරන්නත් පුළුවන් වෙන්න ඕනේ.

Project Structure

අපි Maven multi-module project එකක් විදියට හදමු.

my-ayubowan-starter
├── pom.xml (parent pom)
├── ayubowan-spring-boot-starter
│   └── pom.xml
│   └── src
│       └── main
│           └── java
│               └── ... (empty - just packaging)
├── ayubowan-spring-boot-autoconfigure
│   └── pom.xml
│   └── src
│       └── main
│           └── java
│               └── com
│                   └── example
│                       └── ayubowan
│                           ├── AyubowanService.java
│                           ├── AyubowanProperties.java
│                           └── AyubowanAutoConfiguration.java
│           └── resources
│               └── META-INF
│                   └── spring.factories

1. Parent pom.xml

පළමුවෙන් ම multi-module parent pom.xml එක හදමු.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>my-ayubowan-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>

    <name>Ayubowan Starter Parent</name>
    <description>Parent project for Ayubowan Spring Boot Starter</description>

    <properties>
        <java.version>17</java.version>
        <spring-boot.version>3.2.5</spring-boot.version>
    </properties>

    <modules>
        <module>ayubowan-spring-boot-starter</module>
        <module>ayubowan-spring-boot-autoconfigure</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

2. ayubowan-spring-boot-starter Module

මේක තමයි අපේ actual starter module එක. මේකේ ඇතුළේ තියෙන්නේ auto-configure module එකේ dependency එක විතරයි. එච්චරයි! නිකම්ම නිකම් wrapper එකක් වගේ.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>my-ayubowan-starter</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>ayubowan-spring-boot-starter</artifactId>
    <name>Ayubowan Spring Boot Starter</name>
    <description>Starter for Ayubowan service</description>

    <dependencies>
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>ayubowan-spring-boot-autoconfigure</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

</project>

3. ayubowan-spring-boot-autoconfigure Module

මේ තමයි වැඩේ සිද්ධ වෙන තැන! මේකේ තමයි අපේ custom logic එක, configuration properties, සහ auto-configuration class එක තියෙන්නේ.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.example</groupId>
        <artifactId>my-ayubowan-starter</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>ayubowan-spring-boot-autoconfigure</artifactId>
    <name>Ayubowan Spring Boot AutoConfigure</name>
    <description>Auto-configuration for Ayubowan service</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

AyubowanService.java

මෙන්න අපේ core service class එක. මේක තමයි අපේ custom logic එක තියෙන්නේ.

package com.example.ayubowan;

public class AyubowanService {

    private String greetingMessage;

    public AyubowanService(String greetingMessage) {
        this.greetingMessage = greetingMessage;
    }

    public String getAyubowanGreeting() {
        return greetingMessage + " Ayubowan!";
    }

    public void sayAyubowan() {
        System.out.println(getAyubowanGreeting());
    }
}

AyubowanProperties.java

මේ class එකෙන් තමයි අපිට application.properties (හෝ application.yml) ෆයිල් එකෙන් අපේ starter එකට values දෙන්න පුළුවන් වෙන්නේ. prefix එකෙන් කියන්නේ ayubowan.message වගේ properties හැදෙන විදිය.

package com.example.ayubowan;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "ayubowan")
public class AyubowanProperties {

    private String message = "Hello"; // Default message

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

AyubowanAutoConfiguration.java

මේක තමයි අපේ starter එකේ හදවත! මේකෙන් තමයි Spring Boot එකට කියන්නේ මොන class එකද autoconfigure කරන්න ඕන කියලා, සහ මොන conditions යටතේද ඒක කරන්න ඕන කියලා.

  • @Configuration: මේක configuration class එකක් කියලා Spring Boot එකට කියනවා.
  • @EnableConfigurationProperties(AyubowanProperties.class): මේකෙන් AyubowanProperties class එකට අපේ application.properties එකේ තියෙන values inject කරනවා.
  • @ConditionalOnClass(AyubowanService.class): මේකෙන් කියන්නේ AyubowanService class එක classpath එකේ තියෙනවා නම් විතරයි මේ configuration එක enable කරන්න කියලා.
  • @ConditionalOnMissingBean(AyubowanService.class): මේකෙන් කියන්නේ AyubowanService වර්ගයේ bean එකක් දැනටමත් Spring Context එකේ නැත්නම් විතරයි අලුතෙන් bean එකක් හදන්න කියලා. මේකෙන් වළක්වනවා අපේ user කෙනෙක්ට ඕන නම් තමන්ගේම AyubowanService bean එකක් හදන්න පුළුවන්කම.
  • @Bean: මේ method එකෙන් තමයි AyubowanService එක bean එකක් විදියට Spring Context එකට add කරන්නේ.
package com.example.ayubowan;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConditionalOnClass(AyubowanService.class)
@EnableConfigurationProperties(AyubowanProperties.class)
public class AyubowanAutoConfiguration {

    private final AyubowanProperties properties;

    public AyubowanAutoConfiguration(AyubowanProperties properties) {
        this.properties = properties;
    }

    @Bean
    @ConditionalOnMissingBean
    public AyubowanService ayubowanService() {
        return new AyubowanService(properties.getMessage());
    }
}

META-INF/spring.factories

මේක හරිම වැදගත් ෆයිල් එකක්! Spring Boot එකට කියන්නේ අපේ auto-configuration class එක කොහෙද තියෙන්නේ කියලා. මේක නැත්නම්, Spring Boot එකට අපේ starter එක හොයාගන්න බෑ.

src/main/resources/META-INF/spring.factories කියන path එකේ මේ ෆයිල් එක හදන්න.

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.ayubowan.AyubowanAutoConfiguration

දැන් අපේ starter එක ready! හැබැයි use කරන්න කලින්, අපි මේ module දෙකම install කරන්න ඕනෙ අපේ local Maven repository එකට. ඒකට, my-ayubowan-starter කියන parent directory එකට ගිහින් මේ command එක run කරන්න:

mvn clean install

මේකෙන් modules දෙකම build වෙලා, local Maven repo එකට (සාමාන්‍යයෙන් .m2 ෆෝල්ඩර් එකට) add වෙනවා. එතකොට අපිට පුළුවන් වෙන project එකකදී මේක dependency එකක් විදියට add කරගන්න.

Starter එක Use කරන්නේ කොහොමද?

හරි, දැන් අපි අපේ starter එක සාර්ථකව build කරලා install කරා. දැන් අපි අලුත් Spring Boot project එකක් හදලා මේ starter එක test කරලා බලමු.

1. New Spring Boot Project එකක් හදන්න

Spring Initializr (start.spring.io) එකට ගිහින් Maven Project එකක් හදන්න. Dependencies විදියට Spring Web වගේ මොනවා හරි පොඩි එකක් add කරගන්න. නැත්නම් මුකුත් නැතිව හිස් project එකක් හදාගන්නත් පුළුවන්.

2. Starter Dependency එක Add කරන්න

අලුතින් හදාගත්ත project එකේ pom.xml එකට අපේ custom starter එකේ dependency එක add කරන්න.

<dependency>
    <groupId>com.example</groupId>
    <artifactId>ayubowan-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version> <!-- Make sure this matches your starter's version -->
</dependency>

Maven එක refresh කරන්න, එතකොට අලුත් dependency එක download වෙයි.

3. Starter එක පාවිච්චි කරන්න

දැන් අපේ main application class එකට ගිහින් AyubowanService එක inject කරලා පාවිච්චි කරන්න පුළුවන්. Spring Boot එක auto-configure කරපු නිසා, අපිට මේකට වෙනම configuration එකක් ලියන්න ඕනේ නෑ.

package com.example.myayubowanapp;

import com.example.ayubowan.AyubowanService;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class MyAyubowanApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyAyubowanApplication.class, args);
    }

    @Bean
    public CommandLineRunner run(AyubowanService ayubowanService) {
        return args -> {
            ayubowanService.sayAyubowan();
        };
    }
}

මේ application එක run කරාම, console එකේ "Hello Ayubowan!" කියලා print වෙන්න ඕනේ.

4. Custom Property එකක් Set කරන්න

දැන් අපි බලමු application.properties ෆයිල් එකෙන් default message එක වෙනස් කරන්නේ කොහොමද කියලා.

src/main/resources/application.properties ෆයිල් එකට මේ line එක add කරන්න:

ayubowan.message=ආයුබෝවන් හැමෝටම!

දැන් ආයෙත් application එක run කරලා බලන්න. Console එකේ "ආයුබෝවන් හැමෝටම! Ayubowan!" කියලා print වෙන්න ඕනේ. දැක්කා නේද කොච්චර ලේසිද කියලා! අපේ starter එක දැන් configurable.

හරිම සරලයි නේද? මේක තමයි ඕනම Spring Boot Custom Starter එකක මූලික සංකල්පය. තව complex scenarios වලදී ConditionalOnProperty, ConditionalOnBean, ConditionalOnMissingBean, ConditionalOnExpression වගේ තව advanced annotations පාවිච්චි කරලා auto-configuration logic එක තව customize කරන්න පුළුවන්.

අවසාන වශයෙන්

දැන් ඔයාලට තේරෙන්න ඇති Spring Boot Starters කියන්නේ මොනවද, ඇයි මේවා අපිට වැදගත් වෙන්නේ, සහ කොහොමද අපේම Custom Starter එකක් හදාගෙන Project එකක් ඇතුළේ ඒක පාවිච්චි කරන්නේ කියලා. මේක ඔයාලගේ development process එකට ලොකු පහසුවක් ගේනවා, boilerplate code අඩු කරනවා, සහ project එකේ maintainability එක වැඩි කරනවා. විශේෂයෙන්ම Microservice architecture එකකදී මේ වගේ Custom Starters හරිම ප්‍රයෝජනවත්.

මතක තියාගන්න, Starter එකක් හැදුවට පස්සේ, ඒක publish කරන්න පුළුවන් Maven Central වගේ Public Repository එකකට. එතකොට ඕන කෙනෙක්ට dependency එකක් විදියට ඒක පාවිච්චි කරන්න පුළුවන්. නැත්නම් Private Repository එකක් පාවිච්චි කරලා company එක ඇතුළේ බෙදාහරින්නත් පුළුවන්.

ඉතින්, ඔයාලත් අදම උත්සාහ කරලා බලන්න මේ වගේ Custom Starter එකක් හදන්න. තමන්ගේම පොඩි starter එකක් හදලා ඒක වෙන project එකක use කරනකොට එන සතුට හරිම වෙනස්! මොනවා හරි ප්‍රශ්න තියෙනවා නම්, පහළින් comment එකක් දාන්න. අපි උදව් කරන්නම්. අලුත් දෙයක් ඉගෙන ගන්න හැමෝටම ජය වේවා!