জাভা ডেভেলপারদের জন্য, স্প্রিং ফ্রেমওয়ার্কের মধ্যে বিন স্কোপ (Bean Scope) একটি অত্যন্ত গুরুত্বপূর্ণ ধারণা। এটি নির্ধারণ করে যে একটি বিন কতক্ষণ এবং কীভাবে অ্যাপ্লিকেশনের মধ্যে বিদ্যমান থাকবে। আপনি যদি স্প্রিং ব্যবহার করে একটি এপ্লিকেশন তৈরি করেন, তাহলে বিন স্কোপের সঠিক ব্যবহার আপনার কোডকে আরও কার্যকরী এবং মেমরি-ইফিশিয়েন্ট করতে পারে। এই টিউটোরিয়ালে আমরা স্প্রিং বিন স্কোপের বিভিন্ন প্রকার, তাদের ব্যবহার এবং কীভাবে সঠিক স্কোপ নির্বাচন করতে হয় তা শিখব।

ভূমিকা

স্প্রিং বিন স্কোপ হলো একটি কনফিগারেশন যা নির্ধারণ করে যে একটি বিনের লাইফসাইকেল কেমন হবে। অর্থাৎ, একটি বিন কখন তৈরি হবে, কখন ধ্বংস হবে এবং কতবার এটি ব্যবহার করা যাবে। স্প্রিং ফ্রেমওয়ার্কে পাঁচটি প্রধান স্কোপ রয়েছে: সিঙ্গেলটন (Singleton), প্রোটোটাইপ (Prototype), রিকুয়েস্ট (Request), সেশন (Session), এবং গ্লোবাল সেশন (Global Session)। এছাড়াও, ওয়েব-ভিত্তিক অ্যাপ্লিকেশনের জন্য আরও কিছু বিশেষ স্কোপ রয়েছে। এই টিউটোরিয়ালে আমরা প্রতিটি স্কোপের বিস্তারিত ব্যাখ্যা করব এবং তাদের ব্যবহারের উদাহরণ দেখাব।

পূর্বশর্ত

এই টিউটোরিয়ালটি সম্পূর্ণভাবে বুঝতে এবং অনুসরণ করতে আপনার নিম্নলিখিত বিষয়গুলির সাথে পরিচিত হওয়া উচিত:

  • জাভা প্রোগ্রামিং ভাষা: আপনার জাভা ভাষার মৌলিক ধারণা জানা থাকতে হবে।
  • স্প্রিং বুট: স্প্রিং বুটের মৌলিক ধারণা এবং কিভাবে একটি স্প্রিং বুট প্রজেক্ট তৈরি করতে হয় তা জানা থাকতে হবে।
  • আইডিই (IDE): আপনি IntelliJ IDEA, Eclipse, বা VS Code এর মতো একটি আইডিই ব্যবহার করতে পারেন।
  • ম্যাভেন বা গ্রেডল: আপনার প্রজেক্টে ডিপেন্ডেন্সি ম্যানেজমেন্টের জন্য ম্যাভেন বা গ্রেডল ব্যবহার করতে হবে।

ধাপে ধাপে বাস্তবায়ন

১. সিঙ্গেলটন স্কোপ (Singleton Scope)

সিঙ্গেলটন স্কোপ হলো স্প্রিংয়ের ডিফল্ট স্কোপ। যখন আপনি কোনো বিনকে সিঙ্গেলটন হিসেবে ডিফাইন করেন, তখন স্প্রিং কন্টেইনার সেই বিনের একটি মাত্র ইনস্ট্যান্স তৈরি করে এবং পুরো অ্যাপ্লিকেশন জুড়ে সেই একই ইনস্ট্যান্স ব্যবহার করে। এটি মেমরি সেভ করার জন্য এবং পারফরম্যান্স উন্নত করার জন্য খুবই কার্যকরী।

@Component
@Scope("singleton")
public class SingletonBean {
    public SingletonBean() {
        System.out.println("SingletonBean তৈরি হয়েছে!");
    }
}

উপরের কোডে, @Scope("singleton") অ্যানোটেশন ব্যবহার করে আমরা একটি বিনকে সিঙ্গেলটন স্কোপে ডিফাইন করেছি। যখনই এই বিনটি ব্যবহার করা হবে, স্প্রিং কন্টেইনার একই ইনস্ট্যান্স রিটার্ন করবে।

২. প্রোটোটাইপ স্কোপ (Prototype Scope)

প্রোটোটাইপ স্কোপে, প্রতিবার যখন আপনি একটি বিনের জন্য রিকুয়েস্ট করবেন, তখন স্প্রিং কন্টেইনার একটি নতুন ইনস্ট্যান্স তৈরি করে। এটি ব্যবহার করা হয় যখন আপনার প্রতিবার নতুন করে একটি অবজেক্টের প্রয়োজন হয়।

@Component
@Scope("prototype")
public class PrototypeBean {
    public PrototypeBean() {
        System.out.println("PrototypeBean তৈরি হয়েছে!");
    }
}

উপরের কোডে, @Scope("prototype") অ্যানোটেশন ব্যবহার করে আমরা একটি বিনকে প্রোটোটাইপ স্কোপে ডিফাইন করেছি। প্রতিবার যখনই এই বিনটি ইনজেক্ট করা হবে, স্প্রিং কন্টেইনার একটি নতুন ইনস্ট্যান্স তৈরি করবে।

৩. রিকুয়েস্ট স্কোপ (Request Scope)

রিকুয়েস্ট স্কোপ শুধুমাত্র ওয়েব-ভিত্তিক অ্যাপ্লিকেশনে ব্যবহার করা হয়। এটি একটি HTTP রিকুয়েস্টের জন্য একটি বিন তৈরি করে এবং রিকুয়েস্ট শেষ হলে বিনটি ধ্বংস হয়ে যায়।

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestBean {
    public RequestBean() {
        System.out.println("RequestBean তৈরি হয়েছে!");
    }
}

উপরের কোডে, @Scope অ্যানোটেশন এবং proxyMode ব্যবহার করে আমরা একটি বিনকে রিকুয়েস্ট স্কোপে ডিফাইন করেছি। এটি নিশ্চিত করে যে প্রতিটি HTTP রিকুয়েস্টের জন্য একটি নতুন বিন তৈরি হবে।

৪. সেশন স্কোপ (Session Scope)

সেশন স্কোপ একটি HTTP সেশনের জন্য একটি বিন তৈরি করে। এটি ব্যবহারকারীর সেশন জুড়ে একই বিন ব্যবহার করতে সাহায্য করে।

@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SessionBean {
    public SessionBean() {
        System.out.println("SessionBean তৈরি হয়েছে!");
    }
}

উপরের কোডে, @Scope অ্যানোটেশন এবং proxyMode ব্যবহার করে আমরা একটি বিনকে সেশন স্কোপে ডিফাইন করেছি। এটি নিশ্চিত করে যে প্রতিটি HTTP সেশনের জন্য একটি নতুন বিন তৈরি হবে।

৫. গ্লোবাল সেশন স্কোপ (Global Session Scope)

গ্লোবাল সেশন স্কোপ শুধুমাত্র পোর্টলেট-ভিত্তিক অ্যাপ্লিকেশনে ব্যবহার করা হয়। এটি একটি গ্লোবাল সেশনের জন্য একটি বিন তৈরি করে যা সমস্ত পোর্টলেট সেশনে ভাগ করা যায়।

@Component
@Scope(value = WebApplicationContext.SCOPE_GLOBAL_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class GlobalSessionBean {
    public GlobalSessionBean() {
        System.out.println("GlobalSessionBean তৈরি হয়েছে!");
    }
}

উপরের কোডে, @Scope অ্যানোটেশন এবং proxyMode ব্যবহার করে আমরা একটি বিনকে গ্লোবাল সেশন স্কোপে ডিফাইন করেছি। এটি শুধুমাত্র পোর্টলেট-ভিত্তিক অ্যাপ্লিকেশনে ব্যবহার করা হয়।

সম্পূর্ণ উদাহরণ

নিচে একটি সম্পূর্ণ স্প্রিং বুট অ্যাপ্লিকেশন দেওয়া হলো যা বিভিন্ন স্কোপের বিন ব্যবহার করে:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@SpringBootApplication
public class BeanScopeApplication {

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(BeanScopeApplication.class, args);
        
        SingletonBean singleton1 = context.getBean(SingletonBean.class);
        SingletonBean singleton2 = context.getBean(SingletonBean.class);
        System.out.println("সিঙ্গেলটন বিন একই? " + (singleton1 == singleton2));
        
        PrototypeBean prototype1 = context.getBean(PrototypeBean.class);
        PrototypeBean prototype2 = context.getBean(PrototypeBean.class);
        System.out.println("প্রোটোটাইপ বিন আলাদা? " + (prototype1 != prototype2));
    }

    @Component
    @Scope("singleton")
    public static class SingletonBean {
        public SingletonBean() {
            System.out.println("SingletonBean তৈরি হয়েছে!");
        }
    }

    @Component
    @Scope("prototype")
    public static class PrototypeBean {
        public PrototypeBean() {
            System.out.println("PrototypeBean তৈরি হয়েছে!");
        }
    }
}

উপরের উদাহরণে, আমরা একটি স্প্রিং বুট অ্যাপ্লিকেশন তৈরি করেছি যা সিঙ্গেলটন এবং প্রোটোটাইপ স্কোপের বিন ব্যবহার করে। main মেথডে আমরা দেখতে পাচ্ছি যে সিঙ্গেলটন বিনের জন্য একই ইনস্ট্যান্স ব্যবহার করা হয়, কিন্তু প্রোটোটাইপ বিনের জন্য প্রতিবার নতুন ইনস্ট্যান্স তৈরি হয়।

সাধারণ সমস্যা ও সমাধান

১. প্রোটোটাইপ বিনের লাইফসাইকেল ম্যানেজমেন্ট

প্রোটোটাইপ স্কোপের বিনের লাইফসাইকেল সম্পূর্ণভাবে স্প্রিং কন্টেইনার দ্বারা ম্যানেজ করা হয় না। অর্থাৎ, স্প্রিং কন্টেইনার প্রোটোটাইপ বিন তৈরি করে কিন্তু তার ডেস্ট্রয় মেথড কল করে না। এটি ম্যানুয়ালি করতে হবে।

@Component
@Scope("prototype")
public class PrototypeBean {
    @PostConstruct
    public void init() {
        System.out.println("PrototypeBean ইনিশিয়ালাইজড!");
    }
    
    @PreDestroy
    public void destroy() {
        System.out.println("PrototypeBean ধ্বংস!");
    }
}

উপরের কোডে, @PostConstruct এবং @PreDestroy অ্যানোটেশন ব্যবহার করে আমরা প্রোটোটাইপ বিনের লাইফসাইকেল ইভেন্টগুলি ম্যানেজ করতে পারি।

২. স্কোপ প্রোবলেম

যখন আপনি একটি সিঙ্গেলটন বিনের মধ্যে একটি প্রোটোটাইপ বিন ইনজেক্ট করেন, তখন প্রোটোটাইপ বিনটি শুধুমাত্র একবার তৈরি হয়। এটি সমাধান করতে আপনি @Lookup অ্যানোটেশন বা ObjectFactory ব্যবহার করতে পারেন।

@Component
public class SingletonBean {
    @Lookup
    public PrototypeBean getPrototypeBean() {
        return null; // স্প্রিং এই মেথডটি ওভাররাইড করবে
    }
}

উপরের কোডে, @Lookup অ্যানোটেশন ব্যবহার করে আমরা সিঙ্গেলটন বিনের মধ্যে প্রোটোটাইপ বিনের একটি নতুন ইনস্ট্যান্স তৈরি করতে পারি।

সারসংক্ষেপ

এই টিউটোরিয়ালে আমরা স্প্রিং বিন স্কোপের বিভিন্ন প্রকার সম্পর্কে শিখেছি। সিঙ্গেলটন স্কোপ সবচেয়ে বেশি ব্যবহৃত হয় এবং এটি মেমরি সেভ করে। প্রোটোটাইপ স্কোপ ব্যবহার করা হয় যখন প্রতিবার নতুন অবজেক্টের প্রয়োজন হয়। রিকুয়েস্ট, সেশন, এবং গ্লোবাল সেশন স্কোপ ওয়েব-ভিত্তিক অ্যাপ্লিকেশনে ব্যবহার করা হয়। সঠিক স্কোপ নির্বাচন আপনার অ্যাপ্লিকেশনের পারফরম্যান্স এবং মেমরি ব্যবহারকে উন্নত করতে পারে। মনে রাখবেন, প্রতিটি স্কোপের নিজস্ব ব্যবহার এবং সীমাবদ্ধতা রয়েছে, তাই আপনার প্রয়োজন অনুযায়ী স্কোপ নির্বাচন করুন।

Share