Guice একটি শক্তিশালী ডিপেনডেন্সি ইনজেকশন ফ্রেমওয়ার্ক, যা ডিপেনডেন্সি ম্যানেজমেন্টকে সহজ এবং মডুলার করে। Guice-এ মডিউল (Module) হলো একটি কনফিগারেশন ক্লাস, যেখানে ডিপেনডেন্সিগুলো বাউন্ড করা হয়। এটি AbstractModule ক্লাস থেকে ইনহেরিট করে এবং ডিপেনডেন্সি কনফিগারেশন সংজ্ঞায়িত করতে ব্যবহৃত হয়।
Guice Module Basics
১. মডিউল তৈরি করার ধাপসমূহ
AbstractModuleথেকে ইনহেরিট করুন: Guice-এর মডিউল তৈরি করতেAbstractModuleক্লাস এক্সটেন্ড করতে হবে।configure()মেথড ওভাররাইড করুন: এই মেথডে ডিপেনডেন্সি বাউন্ড করতে হবে।bind()মেথড ব্যবহার করুন: ইন্টারফেস এবং তার ইমপ্লিমেন্টেশনগুলোর মধ্যে সম্পর্ক সংজ্ঞায়িত করুন।
২. উদাহরণ: একটি বেসিক মডিউল
Step 1: একটি ইন্টারফেস তৈরি করুন
public interface GreetingService {
void greet(String name);
}
Step 2: ইন্টারফেসের একটি ইমপ্লিমেন্টেশন তৈরি করুন
public class GreetingServiceImpl implements GreetingService {
@Override
public void greet(String name) {
System.out.println("Hello, " + name + "!");
}
}
Step 3: মডিউল তৈরি করুন
import com.google.inject.AbstractModule;
public class AppModule extends AbstractModule {
@Override
protected void configure() {
// Binding the interface to its implementation
bind(GreetingService.class).to(GreetingServiceImpl.class);
}
}
Step 4: মডিউল ব্যবহার করুন
import com.google.inject.Guice;
import com.google.inject.Injector;
public class MainApp {
public static void main(String[] args) {
// Create an injector with the module
Injector injector = Guice.createInjector(new AppModule());
// Get an instance of the service
GreetingService service = injector.getInstance(GreetingService.class);
// Use the service
service.greet("World");
}
}
৩. Guice মডিউলের সুবিধা
- ইন্টারফেস এবং ইমপ্লিমেন্টেশন ড coupling কমায়।
- মাল্টিপল মডিউল ব্যবহার করে কোডকে আরও মডুলার এবং পুনঃব্যবহারযোগ্য করে তোলে।
- ডিফল্ট বা কাস্টম ডিপেনডেন্সি সহজে কনফিগার করা যায়।
Advanced Module Features
১. Constructor Bindings
কোনো ক্লাস সরাসরি বাউন্ড করতে চাইলে bind() ব্যবহার করুন:
@Override
protected void configure() {
bind(GreetingServiceImpl.class);
}
২. Named Bindings
একই ইন্টারফেসের একাধিক ইমপ্লিমেন্টেশন ব্যবহারের জন্য Guice @Named অ্যানোটেশন সাপোর্ট করে।
উদাহরণ:
import com.google.inject.name.Names;
@Override
protected void configure() {
bind(GreetingService.class).annotatedWith(Names.named("formal")).to(FormalGreetingService.class);
bind(GreetingService.class).annotatedWith(Names.named("informal")).to(InformalGreetingService.class);
}
Service Implementation Example
public class FormalGreetingService implements GreetingService {
@Override
public void greet(String name) {
System.out.println("Good day, " + name + ".");
}
}
public class InformalGreetingService implements GreetingService {
@Override
public void greet(String name) {
System.out.println("Hey, " + name + "!");
}
}
Main Application Example
import com.google.inject.Inject;
import com.google.inject.name.Named;
public class MainApp {
@Inject
@Named("formal")
private GreetingService formalService;
@Inject
@Named("informal")
private GreetingService informalService;
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AppModule());
MainApp app = injector.getInstance(MainApp.class);
app.formalService.greet("Alice");
app.informalService.greet("Bob");
}
}
৩. Provider Bindings
Provider ব্যবহার করে কাস্টম ডিপেনডেন্সি তৈরি করুন:
import com.google.inject.Provider;
public class CustomGreetingServiceProvider implements Provider<GreetingService> {
@Override
public GreetingService get() {
return new GreetingServiceImpl(); // Custom initialization logic
}
}
মডিউলে Provider Bindings যুক্ত করুন
@Override
protected void configure() {
bind(GreetingService.class).toProvider(CustomGreetingServiceProvider.class);
}
৪. Injecting Dependencies into Module
মডিউল নিজেই ডিপেনডেন্সি গ্রহণ করতে পারে:
public class AppModule extends AbstractModule {
private final String greetingPrefix;
public AppModule(String greetingPrefix) {
this.greetingPrefix = greetingPrefix;
}
@Override
protected void configure() {
bindConstant().annotatedWith(Names.named("GreetingPrefix")).to(greetingPrefix);
}
}
Main Application Example
public class MainApp {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AppModule("Hello"));
GreetingService service = injector.getInstance(GreetingService.class);
service.greet("World");
}
}
Best Practices for Guice Modules
- Single Responsibility Principle (SRP): প্রতিটি মডিউল একটি নির্দিষ্ট কাজের জন্য দায়িত্ব পালন করবে।
- উদাহরণ:
DatabaseModule,ServiceModule,APIModule।
- উদাহরণ:
- Use Named Bindings for Clarity: একই ইন্টারফেসের একাধিক ইমপ্লিমেন্টেশন ব্যবহারের ক্ষেত্রে
@Namedবা কাস্টম অ্যানোটেশন ব্যবহার করুন। - Avoid Over-Binding: সবকিছু বাউন্ড করার দরকার নেই। শুধু প্রয়োজনীয় ডিপেনডেন্সি বাউন্ড করুন।
- Split Modules for Modularity: বড় প্রকল্পে একাধিক মডিউলে কোড ভাগ করুন এবং
Modules.combine()ব্যবহার করুন।
Guice মডিউল তৈরি করা সহজ এবং কার্যকর। এটি ডিপেনডেন্সি ইনজেকশনকে মডুলার, পুনঃব্যবহারযোগ্য এবং সহজবোধ্য করে তোলে। মডিউল ব্যবহার করে Java অ্যাপ্লিকেশন ডেভেলপমেন্ট আরও ম্যানেজেবল এবং স্কেলেবল হয়ে ওঠে।
Guice Module হলো Google Guice-এর একটি কেন্দ্রীয় উপাদান যা Dependency Injection (DI) পদ্ধতিতে নির্দিষ্ট ডিপেনডেন্সি ম্যাপিং বা বাইন্ডিং সংজ্ঞায়িত করে। এটি মূলত Guice-কে জানায় যে, কিভাবে নির্দিষ্ট ইন্টারফেস বা অবজেক্ট গুলি তাদের বাস্তবায়নের (implementation) সাথে সংযুক্ত হতে হবে।
Guice Module কী?
- Guice Module হলো একটি ক্লাস যা
com.google.inject.AbstractModuleথেকে ইনহেরিট করে। - এটি Guice-এর
configure()মেথড ওভাররাইড করে প্রয়োজনীয় বাইন্ডিং বা ডিপেনডেন্সি ম্যাপিং তৈরি করে। - Module ব্যবহার করে আপনি সহজে ডিপেনডেন্সি ম্যানেজ করতে পারেন, যেমন কোন ইন্টারফেসের জন্য কোন ইমপ্লিমেন্টেশন ব্যবহার করা হবে।
Guice Module কীভাবে কাজ করে?
- ম্যাপিং তৈরি করা:
- Module এ বাইন্ডিং সংজ্ঞায়িত করা হয়। উদাহরণস্বরূপ, একটি ইন্টারফেস (Interface) এর জন্য একটি নির্দিষ্ট ইমপ্লিমেন্টেশন (Implementation) বাইন্ড করা হয়।
- Injector তৈরি করা:
- Guice একটি Injector তৈরি করে, যা মডিউলে সংজ্ঞায়িত বাইন্ডিং ব্যবহার করে নির্দিষ্ট ডিপেনডেন্সি সরবরাহ করে।
- ডিপেনডেন্সি রেজোলভ করা:
- Injector ক্লায়েন্ট কোডে ডিপেনডেন্সি ইনজেক্ট করে, যেখানে প্রয়োজনীয় অবজেক্ট সরবরাহ করা হয়।
Guice Module এর উদাহরণ
1. Module তৈরি করা
AbstractModule ক্লাস থেকে ইনহেরিট করে একটি Module তৈরি করা হয় এবং configure() মেথডে বাইন্ডিং সংজ্ঞায়িত করা হয়।
import com.google.inject.AbstractModule;
public class AppModule extends AbstractModule {
@Override
protected void configure() {
// Service ইন্টারফেসের জন্য ServiceImpl ইমপ্লিমেন্টেশন নির্ধারণ
bind(Service.class).to(ServiceImpl.class);
}
}
2. একটি Interface এবং Implementation তৈরি করা
Module এর বাইন্ডিং অনুযায়ী একটি ইন্টারফেস এবং তার ইমপ্লিমেন্টেশন তৈরি করা হয়।
// Interface
public interface Service {
void performTask();
}
// Implementation
public class ServiceImpl implements Service {
@Override
public void performTask() {
System.out.println("Task performed by ServiceImpl.");
}
}
3. Main Application এ Injector ব্যবহার
Injector তৈরি করে Module এর বাইন্ডিং অনুযায়ী ডিপেনডেন্সি রেজোলভ করা হয়।
import com.google.inject.Guice;
import com.google.inject.Injector;
public class MainApp {
public static void main(String[] args) {
// Injector তৈরি এবং Module লোড করা
Injector injector = Guice.createInjector(new AppModule());
// Service ডিপেনডেন্সি রেজোলভ করা
Service service = injector.getInstance(Service.class);
// মেথড কল করা
service.performTask();
}
}
Guice Module এর সুবিধা
- Decoupled Code:
- কোডের বিভিন্ন অংশের মধ্যে tight coupling কমিয়ে দেয়। ইন্টারফেস ব্যবহার করে আপনি সহজেই নতুন ইমপ্লিমেন্টেশন যুক্ত করতে পারেন।
- Reusable:
- একটি Module একাধিক প্রোজেক্ট বা পরিবেশে পুনরায় ব্যবহার করা যায়।
- Flexible Binding:
- Constructor Injection, Field Injection এবং Method Injection সহজেই সম্ভব।
- Testability:
- Unit Testing এর জন্য মক বা বিকল্প ইমপ্লিমেন্টেশন ব্যবহার করা যায়।
বাইন্ডিং এর অন্যান্য বৈশিষ্ট্য
1. নির্দিষ্ট Instance বাইন্ডিং
একটি নির্দিষ্ট অবজেক্টকে বাইন্ড করা যায়।
bind(String.class).toInstance("Hello, Guice!");
2. Constructor Binding
কোন ক্লাসের নির্দিষ্ট কনস্ট্রাক্টর ব্যবহার করতে বাধ্য করা যায়।
bind(Service.class).toConstructor(ServiceImpl.class.getConstructor(String.class));
3. Scoped Binding
Singleton বা Custom Scope নির্ধারণ করা যায়।
bind(Service.class).to(ServiceImpl.class).in(Singleton.class);
Module-এর Complex উদাহরণ
মাল্টিপল মডিউল ব্যবহার এবং চেইনিং করার সুবিধা।
import com.google.inject.Guice;
import com.google.inject.Injector;
public class MultiModuleApp {
public static void main(String[] args) {
// একাধিক Module লোড করা
Injector injector = Guice.createInjector(new AppModule(), new AnotherModule());
// Service ডিপেনডেন্সি রেজোলভ করা
Service service = injector.getInstance(Service.class);
service.performTask();
}
}
- Guice Module Dependency Injection-এর মাধ্যমে কোডের মডুলারিটি এবং রিইউসেবিলিটি বাড়ায়।
AbstractModuleক্লাস ব্যবহার করে বাইন্ডিং তৈরি করা হয় এবং Injector এর মাধ্যমে প্রয়োজনীয় ডিপেনডেন্সি সরবরাহ করা হয়।- Guice Module আপনার প্রোজেক্টকে আরও মেইনটেইনেবল ও স্কেলেবল করে তোলে।
Guice-এ AbstractModule হলো একটি প্রধান ক্লাস, যা ডিপেনডেন্সি ইনজেকশনের জন্য বেসিক কনফিগারেশন প্রদান করে। Guice-এর মাধ্যমে আপনি কোন ইন্টারফেস কোন ইমপ্লিমেন্টেশনের সাথে যুক্ত করবেন এবং কীভাবে ডিপেনডেন্সি তৈরি হবে তা AbstractModule ক্লাস ব্যবহার করে নির্ধারণ করেন।
AbstractModule কী?
AbstractModule হলো Guice ফ্রেমওয়ার্কের একটি অ্যাবস্ট্রাক্ট ক্লাস, যা ডিপেনডেন্সি কনফিগারেশনের জন্য configure() মেথড প্রদান করে। এই মেথডে আপনি ডিপেনডেন্সি ম্যানেজমেন্টের নিয়মাবলী (bindings) সংজ্ঞায়িত করেন।
AbstractModule-এর ভূমিকা এবং ব্যবহার
1. Bindings তৈরি করা
AbstractModule-এর configure() মেথডে ইন্টারফেস এবং তার ইমপ্লিমেন্টেশন ক্লাসের মধ্যে সম্পর্ক নির্ধারণ করা হয়।
import com.google.inject.AbstractModule;
public class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(MyService.class).to(MyServiceImpl.class);
}
}
এখানে:
bind(MyService.class).to(MyServiceImpl.class): এটি নির্দেশ করে যে, যখনMyServiceএর ডিপেনডেন্সি চাওয়া হবে, তখনMyServiceImplইনস্ট্যান্স তৈরি করা হবে।
2. Singleton Scope ব্যবহার করা
আপনার ক্লাসকে Singleton হিসাবে ব্যবহার করতে পারেন যাতে একবার মাত্র ইনস্ট্যান্স তৈরি হয়।
import com.google.inject.AbstractModule;
import com.google.inject.Singleton;
public class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(MyService.class).to(MyServiceImpl.class).in(Singleton.class);
}
}
3. Custom Providers ব্যবহার করা
আপনার যদি ডিপেনডেন্সি তৈরির প্রক্রিয়া কাস্টমাইজ করতে হয়, তাহলে @Provides ব্যবহার করতে পারেন।
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
public class MyModule extends AbstractModule {
@Override
protected void configure() {
// অন্যান্য bindings
}
@Provides
public MyService provideMyService() {
return new MyServiceImpl("Custom Initialization");
}
}
4. Constructor Binding ব্যবহার করা
ক্লাসের কনস্ট্রাক্টর যদি নির্দিষ্ট ডিপেনডেন্সি ইনজেক্ট করে, তাহলে কনস্ট্রাক্টর বাইন্ডিং করা যায়।
import com.google.inject.AbstractModule;
public class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(MyService.class).toInstance(new MyServiceImpl("Initialized with Constructor"));
}
}
5. Interface to Multiple Implementations
একটি ইন্টারফেসের জন্য ভিন্ন ভিন্ন ইমপ্লিমেন্টেশন প্রদান করতে চাইলে @Named বা Annotations ব্যবহার করা হয়।
import com.google.inject.AbstractModule;
import com.google.inject.name.Names;
public class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(MyService.class).annotatedWith(Names.named("ServiceA")).to(ServiceAImpl.class);
bind(MyService.class).annotatedWith(Names.named("ServiceB")).to(ServiceBImpl.class);
}
}
এরপর নির্দিষ্ট ইমপ্লিমেন্টেশন ইনজেক্ট করতে পারেন:
import com.google.inject.Inject;
import com.google.inject.name.Named;
public class Client {
private final MyService service;
@Inject
public Client(@Named("ServiceA") MyService service) {
this.service = service;
}
public void execute() {
service.execute();
}
}
6. Dependency Injection-এর Example
Step 1: ইন্টারফেস এবং ইমপ্লিমেন্টেশন তৈরি করুন
public interface MyService {
void execute();
}
public class MyServiceImpl implements MyService {
@Override
public void execute() {
System.out.println("Service is executed!");
}
}
Step 2: Module তৈরি করুন
import com.google.inject.AbstractModule;
public class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(MyService.class).to(MyServiceImpl.class);
}
}
Step 3: Main Application
import com.google.inject.Guice;
import com.google.inject.Injector;
public class MainApp {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new MyModule());
MyService myService = injector.getInstance(MyService.class);
myService.execute(); // Output: Service is executed!
}
}
উপকারিতা
- Flexible Configuration: AbstractModule ব্যবহার করে ডিপেনডেন্সি সম্পর্ক সহজেই কনফিগার করা যায়।
- Loose Coupling: ইন্টারফেস এবং ইমপ্লিমেন্টেশনের মধ্যে আলগা সংযোগ নিশ্চিত করে।
- Reusable Modules: একাধিক প্রজেক্টে একই Module ব্যবহার করা যায়।
- Scalability: বড় এবং জটিল অ্যাপ্লিকেশনেও সহজে পরিচালনা করা যায়।
AbstractModule Guice-এর মূল উপাদানগুলোর একটি, যা Dependency Injection বাস্তবায়নের সময় ডিপেনডেন্সি সম্পর্ক নির্ধারণে সহায়ক। এটি কোডকে আরো ক্লিন, মডুলার, এবং রিইউজেবল করতে সাহায্য করে।
Guice-এর Module একটি কাস্টম ক্লাস যা ডিপেনডেন্সি ইনজেকশন কনফিগার করতে ব্যবহৃত হয়। Guice-এ Binding এর মাধ্যমে নির্দিষ্ট ইন্টারফেস বা ক্লাসের জন্য নির্দিষ্ট ইমপ্লিমেন্টেশন মজুদ করা হয়। একে configure() মেথডের মাধ্যমে কনফিগার করা হয়, যেখানে আপনি বিভিন্ন সার্ভিস বা ডিপেনডেন্সির জন্য Binding নির্দেশ করেন।
নিচে Guice Module এ Binding কনফিগার করার কিছু উদাহরণ দেওয়া হলো:
Binding কনফিগার করার মূল ধারণা
1. Basic Binding:
এটি সর্বাধিক সাধারণ Binding, যেখানে আপনি একটি ইন্টারফেস বা ক্লাসকে তার ইমপ্লিমেন্টেশন কনফিগার করেন।
import com.google.inject.AbstractModule;
// Service ইন্টারফেস এবং তার ইমপ্লিমেন্টেশন
public interface Service {
void serve();
}
public class ServiceImpl implements Service {
@Override
public void serve() {
System.out.println("Service is being served!");
}
}
public class AppModule extends AbstractModule {
@Override
protected void configure() {
// Service ইন্টারফেসকে ServiceImpl ইমপ্লিমেন্টেশন দিয়ে bind করা
bind(Service.class).to(ServiceImpl.class);
}
}
2. Constructor Injection সহ Binding:
Guice Constructor Injection সাপোর্ট করে, যা অটোমেটিকভাবে নির্দিষ্ট ডিপেনডেন্সি ইনজেক্ট করে।
import com.google.inject.Inject;
// Client ক্লাস যেখানে Service ইনজেক্ট করা হবে
public class Client {
private final Service service;
@Inject
public Client(Service service) {
this.service = service;
}
public void doWork() {
service.serve();
}
}
public class AppModule extends AbstractModule {
@Override
protected void configure() {
// Service ইন্টারফেসকে ServiceImpl ইমপ্লিমেন্টেশন দিয়ে bind করা
bind(Service.class).to(ServiceImpl.class);
}
}
import com.google.inject.Guice;
import com.google.inject.Injector;
public class Main {
public static void main(String[] args) {
// Guice Injector তৈরি
Injector injector = Guice.createInjector(new AppModule());
// Client ইনস্ট্যান্স তৈরি এবং তার ডিপেনডেন্সি ইনজেক্ট করা
Client client = injector.getInstance(Client.class);
client.doWork(); // Output: Service is being served!
}
}
3. Named Binding:
Guice এ আপনি @Named অ্যানোটেশন ব্যবহার করে একই টাইপের একাধিক ডিপেনডেন্সি ইনজেক্ট করতে পারেন।
import com.google.inject.name.Named;
import com.google.inject.Inject;
public class ServiceA implements Service {
@Override
public void serve() {
System.out.println("Service A is being served!");
}
}
public class ServiceB implements Service {
@Override
public void serve() {
System.out.println("Service B is being served!");
}
}
public class AppModule extends AbstractModule {
@Override
protected void configure() {
// Named Binding কনফিগার করা
bind(Service.class).annotatedWith(Names.named("A")).to(ServiceA.class);
bind(Service.class).annotatedWith(Names.named("B")).to(ServiceB.class);
}
}
public class Client {
private final Service serviceA;
private final Service serviceB;
@Inject
public Client(@Named("A") Service serviceA, @Named("B") Service serviceB) {
this.serviceA = serviceA;
this.serviceB = serviceB;
}
public void doWork() {
serviceA.serve(); // Output: Service A is being served!
serviceB.serve(); // Output: Service B is being served!
}
}
public class Main {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AppModule());
Client client = injector.getInstance(Client.class);
client.doWork();
}
}
4. Provider Binding:
Guice-এ Provider ব্যবহার করে নির্দিষ্ট ডিপেনডেন্সি তৈরি করা সম্ভব। এটি সুবিধাজনক যখন ডিপেনডেন্সি জেনেরেটর ফাংশন তৈরি করতে চান।
import com.google.inject.Provider;
public class ServiceProvider implements Provider<Service> {
@Override
public Service get() {
return new ServiceImpl();
}
}
public class AppModule extends AbstractModule {
@Override
protected void configure() {
// Service ইন্টারফেসের জন্য Provider Binding
bind(Service.class).toProvider(ServiceProvider.class);
}
}
public class Main {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AppModule());
// Service ইন্টারফেসের ইনস্ট্যান্স তৈরি করা হচ্ছে ServiceProvider থেকে
Service service = injector.getInstance(Service.class);
service.serve(); // Output: Service is being served!
}
}
5. Scoped Binding:
Guice-এ সোকোপ (scope) ব্যবহার করা যেতে পারে, যেমন @Singleton অ্যানোটেশন দিয়ে সিঙ্গেলটন ইনস্ট্যান্স তৈরি করা।
import com.google.inject.Singleton;
@Singleton
public class SingletonService implements Service {
@Override
public void serve() {
System.out.println("Singleton Service is being served!");
}
}
public class AppModule extends AbstractModule {
@Override
protected void configure() {
bind(Service.class).to(SingletonService.class);
}
}
public class Main {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new AppModule());
// একই ইনস্ট্যান্স পুনরায় ব্যবহার করা হচ্ছে (সিঙ্গেলটন)
Service service1 = injector.getInstance(Service.class);
Service service2 = injector.getInstance(Service.class);
System.out.println(service1 == service2); // Output: true
}
}
Guice-এ Module ব্যবহার করে Binding কনফিগার করা একটি শক্তিশালী উপায় যা ডিপেনডেন্সি ইনজেকশন সহজ করে এবং অ্যাপ্লিকেশনের কোড আরো মডুলার এবং রিইউজেবল করে তোলে। Guice এর মাধ্যমে আপনি বিভিন্ন ধরনের Binding কনফিগার করতে পারেন যেমন:
- Basic Binding
- Constructor Injection
- Named Binding
- Provider Binding
- Scoped Binding
এগুলি প্রজেক্টের প্যাটার্ন অনুযায়ী ব্যবহার করে আপনি আপনার অ্যাপ্লিকেশন আরও কার্যকরী এবং maintainable করতে পারবেন।
Guice ব্যবহার করে Multiple Modules এর ব্যবস্থাপনা অনেক সহজ এবং কার্যকর। Guice আপনাকে Dependency Injection করতে সহায়তা করে, এবং যখন আপনার অ্যাপ্লিকেশনটি বড় হয় বা একাধিক মডিউল বা সেবা থাকে, তখন Guice এর মাধ্যমে মডুলার কোডিং সহজ হয়ে যায়।
নিচে Multiple Modules ব্যবস্থাপনা করার জন্য বিভিন্ন কৌশল এবং গাইডলাইন দেয়া হল।
Multiple Modules ব্যবস্থাপনা: প্রক্রিয়া ও কৌশল
1. Module Creation এবং Integration
Guice অ্যাপ্লিকেশন তৈরির জন্য আপনি একাধিক মডিউল তৈরি করতে পারেন। প্রতিটি মডিউল আলাদা দায়িত্ব পালন করবে এবং আপনি এসব মডিউলকে একত্রে ইঞ্জেক্ট করতে পারবেন।
মডিউল তৈরি:
প্রথমে, একটি মডিউল তৈরি করুন যা আপনার ডিপেন্ডেন্সি গুলি কনফিগার করবে।
import com.google.inject.AbstractModule;
// Module 1
public class ServiceModule1 extends AbstractModule {
@Override
protected void configure() {
bind(Service1.class).to(Service1Impl.class);
}
}
// Module 2
public class ServiceModule2 extends AbstractModule {
@Override
protected void configure() {
bind(Service2.class).to(Service2Impl.class);
}
}
এখানে, ServiceModule1 এবং ServiceModule2 দুটি আলাদা মডিউল। প্রতিটি মডিউল আলাদা সার্ভিস কনফিগার করবে, যেমন Service1 এবং Service2।
2. Multiple Modules ইঞ্জেক্ট করা
একাধিক মডিউলকে একত্রে ব্যবহার করতে হলে, Guice Injector এর মাধ্যমে এগুলো ইঞ্জেক্ট করা হয়। আপনাকে শুধু সব মডিউল গুলো createInjector() মেথডে পাস করতে হবে।
import com.google.inject.Guice;
import com.google.inject.Injector;
// Application class
public class Application {
private final Service1 service1;
private final Service2 service2;
// Constructor Injection
@Inject
public Application(Service1 service1, Service2 service2) {
this.service1 = service1;
this.service2 = service2;
}
public void start() {
service1.execute();
service2.execute();
}
public static void main(String[] args) {
// Multiple modules passed to the injector
Injector injector = Guice.createInjector(new ServiceModule1(), new ServiceModule2());
Application app = injector.getInstance(Application.class);
app.start();
}
}
এখানে, Guice.createInjector() মেথডে দুটি মডিউল পাস করা হয়েছে। এটি Guice কে নির্দেশ দেয় যে, দুইটি আলাদা মডিউল একসাথে কাজ করবে।
3. Circular Dependencies এর সমস্যা
Guice সাইক্লিক ডিপেন্ডেন্সি (যেমন, A depends on B, এবং B depends on A) ম্যানেজ করতে সহায়তা করে না। যদি আপনি একে ট্রাই করেন তবে Guice একটি CreationException প্রদান করবে।
যদি এমন ডিপেন্ডেন্সি থাকে, তবে আপনাকে সেই ডিপেন্ডেন্সি গুলি ম্যানেজ করতে Provider বা Constructor Injection ব্যবহার করতে হবে।
import com.google.inject.Inject;
import com.google.inject.Provider;
// Example of Circular Dependency
class A {
private final Provider<B> b;
@Inject
public A(Provider<B> b) {
this.b = b;
}
public void doSomething() {
System.out.println("Class A");
b.get().doSomething();
}
}
class B {
private final Provider<A> a;
@Inject
public B(Provider<A> a) {
this.a = a;
}
public void doSomething() {
System.out.println("Class B");
a.get().doSomething();
}
}
এখানে Provider ব্যবহার করা হয়েছে যাতে Guice সঠিক সময়ে নির্ভরতা প্রদান করতে পারে এবং সাইক্লিক ডিপেন্ডেন্সি ম্যানেজ করা যায়।
4. Module এর মধ্যে একে অপরের ডিপেন্ডেন্সি ম্যানেজ করা
এক মডিউলের কনফিগারেশন অন্য মডিউলের উপর নির্ভরশীল হলে, Guice এর Module Chaining ব্যবহার করতে পারেন। এটি আপনাকে একাধিক মডিউলকে একত্রে কনফিগার করার সুবিধা দেয়।
import com.google.inject.AbstractModule;
import com.google.inject.Module;
public class CombinedModule extends AbstractModule {
private final Module module1;
private final Module module2;
public CombinedModule(Module module1, Module module2) {
this.module1 = module1;
this.module2 = module2;
}
@Override
protected void configure() {
install(module1); // Install module1
install(module2); // Install module2
}
}
এখানে CombinedModule নামক একটি মডিউল তৈরি করা হয়েছে যা module1 এবং module2 কে একত্রে ইনস্টল করবে।
5. Scope Management
Guice এর সাথে Scope ম্যানেজমেন্ট অত্যন্ত গুরুত্বপূর্ণ। আপনি Singleton বা RequestScoped ডিপেন্ডেন্সি ব্যবহার করতে পারেন।
public class ServiceModule extends AbstractModule {
@Override
protected void configure() {
bind(Service.class).to(ServiceImpl.class).in(Singleton.class);
}
}
এখানে, Service এর ইনস্ট্যান্স একটি Singleton হিসেবে তৈরি হবে, মানে পুরো অ্যাপ্লিকেশন চলাকালীন একটাই ইনস্ট্যান্স থাকবে।
6. Multi-bindings (Multiple Bindings for the Same Type)
Guice এর মাধ্যমে একাধিক ডিপেন্ডেন্সি (একই টাইপের) বাইনড করা যেতে পারে। এ জন্য multibindings ব্যবহার করা হয়।
import com.google.inject.multibindings.MapBinder;
public class MultiBindingModule extends AbstractModule {
@Override
protected void configure() {
MapBinder<String, String> mapBinder = MapBinder.newMapBinder(binder(), String.class, String.class);
mapBinder.addBinding("key1").toInstance("value1");
mapBinder.addBinding("key2").toInstance("value2");
}
}
এখানে, MapBinder ব্যবহার করা হয়েছে যাতে একই টাইপের একাধিক বাইনডিং করা যায়।
Guice এর মাধ্যমে Multiple Modules ব্যবস্থাপনা করা অনেক সহজ। আপনি বিভিন্ন মডিউল তৈরি করে, তাদের আলাদা আলাদা কনফিগারেশন ম্যানেজ করতে পারেন এবং তারপর Injector ব্যবহার করে সব মডিউল একত্রে ব্যবহার করতে পারেন। Module Chaining, Scope Management, Circular Dependencies সহ বিভিন্ন কৌশল ব্যবহার করে Guice কে আরও শক্তিশালী এবং মডুলার অ্যাপ্লিকেশন তৈরি করতে পারেন।
Read more