Spring Boot Basics — DI, Controllers & Services
Spring Boot-এর ভিত্তি — DI, Controller ও Service
1. Spring in One Idea: Don't Call new. Ask.
Spring's greatest idea is inversion of control. Instead of your code creating its own
collaborators (new PaymentGateway()), you declare that you need one, and Spring's
application context hands you a ready-made instance. Your classes shrink to pure business
logic; wiring moves out of your code entirely.
new দিয়ে object তৈরি করেন না; ঘোষণা করেন যে আপনার কী দরকার, আর Spring-এর application context সেটি তৈরি করে হাতে দেয়। আপনার class-গুলোতে শুধু business logic থাকে, wiring কোডের বাইরে চলে যায়।
spring-boot-starter-web) to run these examples. The plain-Java DI demo in §4 below DOES run.
2. A Tiny Spring Boot App
A Spring Boot application is a normal Java main method annotated with
@SpringBootApplication. That single annotation turns on component scanning, auto-configuration,
and the embedded Tomcat server in one stroke.
main method, শুধু @SpringBootApplication annotation। এই একটিই annotation chalu করে dial — component scan, auto-configuration, এবং embedded Tomcat server।
package com.abcltech.hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
@SpringBootApplication
@RestController
class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
@GetMapping("/hello")
public String hello(@RequestParam(defaultValue = "World") String name) {
return "Hello, " + name + "!";
}
}
Expected (after mvn spring-boot:run): $ curl http://localhost:8080/hello?name=Bangladesh Hello, Bangladesh!
| Annotation | Role | বাংলায় |
|---|---|---|
@SpringBootApplication | Bootstrap — enables scan + autoconfig. | পুরো app চালু করে। |
@RestController | Class handles HTTP and returns JSON/text. | HTTP request handle করে। |
@Service | Business-logic bean. | Business logic bean। |
@Repository | Data-access bean. | Data access bean। |
@Component | Generic Spring-managed bean. | Generic Spring bean। |
@Autowired | Ask Spring for a dependency. | Spring-এর কাছে dependency চাওয়া। |
3. How DI Works — Picture It
4. DI Without Spring — The Idea in Plain Java
The best way to demystify Spring is to do a miniature version by hand. Below, OrderController
declares a constructor dependency on OrderService. A tiny "context" class new-s up
the graph in the right order and injects collaborators.
OrderController-এর constructor-এ OrderService-এর dependency, এবং একটি ছোট Context সঠিক ক্রমে object তৈরি করে wiring করছে।
class OrderRepository {
public int countOrders() { return 42; }
}
class OrderService {
private final OrderRepository repo;
OrderService(OrderRepository repo) { this.repo = repo; } // constructor injection
public String summary() { return "Orders so far: " + repo.countOrders(); }
}
class OrderController {
private final OrderService svc;
OrderController(OrderService svc) { this.svc = svc; }
public String handleGet() { return "HTTP 200 · " + svc.summary(); }
}
class MiniContext {
// Simulates a Spring container: build singletons in dependency order
OrderRepository repo = new OrderRepository();
OrderService svc = new OrderService(repo);
OrderController ctrl = new OrderController(svc);
}
class Main {
public static void main(String[] args) {
MiniContext ctx = new MiniContext();
System.out.println(ctx.ctrl.handleGet());
}
}
5. The Same Thing, With Spring
With Spring, you just add annotations. No MiniContext, no manual new.
MiniContext লাগে না, new লাগে না।
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;
@Repository
class OrderRepository {
public int countOrders() { return 42; }
}
@Service
class OrderService {
private final OrderRepository repo;
OrderService(OrderRepository repo) { this.repo = repo; }
public String summary() { return "Orders so far: " + repo.countOrders(); }
}
@RestController
class OrderController {
private final OrderService svc;
OrderController(OrderService svc) { this.svc = svc; }
@GetMapping("/orders/summary")
public String get() { return svc.summary(); }
}
Expected: $ curl http://localhost:8080/orders/summary Orders so far: 42
final, the object is
never in a half-initialized state, and unit tests can pass fakes directly — no Spring required.
সব সময় constructor injection বেছে নিন। Field
final হয়, object কখনো অর্ধ-initialised অবস্থায় থাকে না, এবং test-এ সরাসরি fake পাঠানো যায় — Spring ছাড়াই।
6. Configuration: application.properties
Spring Boot reads a plain properties file from src/main/resources/application.properties
(or the YAML equivalent). Any key is available via @Value or strongly-typed
@ConfigurationProperties classes.
src/main/resources/application.properties ফাইল থেকে configuration পড়ে (YAML-ও চলে)। যেকোনো key @Value বা typed @ConfigurationProperties দিয়ে ব্যবহার করা যায়।
server.port=8080
spring.application.name=abcltech-orders
# Business config
bkash.merchant=ABCL_MERCH_007
bkash.timeout.ms=2500
7. Vocabulary
| Term | Meaning | বাংলায় |
|---|---|---|
| Bean | An object managed by the Spring container. | Spring-পরিচালিত object। |
| Application context | The container that holds all beans. | সব bean ধরে রাখা container। |
| Component scan | Classpath scan for annotated classes. | Classpath-এ annotation-যুক্ত class খোঁজা। |
| Autoconfiguration | Sensible defaults based on what's on the classpath. | Classpath দেখে default চালু করা। |
| Scope | Bean lifetime: singleton, prototype, request… | Bean-এর জীবনকাল। |
| Profile | Named environment (dev, staging, prod). | Env-ভিত্তিক configuration। |
8. Practice Problems
-
Extend the hand-rolled DI demo with a
Loggerthat bothOrderServiceandOrderControllerdepend on. Verify the log line prints at each layer.হাতে-লেখা DI demo-তে একটিLoggerযোগ করুন যা Service ও Controller দুই জায়গায় dependency। প্রতিটি layer-এ log যায় কিনা যাচাই করুন।✨ Show Answer
Main.javaclass Logger { void log(String m){ System.out.println("[LOG] "+m); } } class OrderService { private final Logger log; OrderService(Logger log){ this.log = log; } String summary(){ log.log("service"); return "42"; } } class OrderController { private final OrderService svc; private final Logger log; OrderController(OrderService s, Logger l){ svc=s; log=l; } String handle(){ log.log("controller"); return svc.summary(); } } class Main { public static void main(String[] a) { Logger l = new Logger(); System.out.println(new OrderController(new OrderService(l), l).handle()); } } -
Why is constructor injection preferred over field injection (
@Autowiredon a field)?Constructor injection field injection-এর চেয়ে কেন ভালো?✨ Show Answer
Answer: (1) Dependencies become
finaland can never be forgotten — the compiler refuses to build an incomplete object. (2) The class is testable without Spring — you just call its constructor in a test. (3) Circular dependencies surface as clear compile/startup errors instead of mysterious runtime NPEs. (4) The class's required collaborators become visible at a glance from its signature. -
Write what a Spring Boot
@RestControllermethod forGET /healthreturning{"status":"UP"}looks like.Spring Boot-এGET /healthroute লিখুন যা{"status":"UP"}JSON ফেরাবে।✨ Show Answer
HealthController.javaimport org.springframework.web.bind.annotation.*; import java.util.Map; @RestController class HealthController { @GetMapping("/health") public Map<String,String> health() { return Map.of("status", "UP"); } } -
Build a hand-rolled "Spring profile" switcher: a
Configclass reads an env variableAPP_ENV(defaultdev) and prints a different greeting fordevvsprod.হাতে-লেখা Spring profile বানান — env variableAPP_ENVপড়ে dev/prod-এ ভিন্ন greeting প্রিন্ট করুন।✨ Show Answer
Main.javaclass Main { public static void main(String[] args) { String env = System.getenv("APP_ENV"); if (env == null) env = "dev"; System.out.println(switch (env) { case "prod" -> "Running in PRODUCTION — be careful."; case "dev" -> "DEV mode — debug logs ON."; default -> "Unknown env: " + env; }); } } -
Explain, in 3 sentences, what happens when you call
SpringApplication.run(App.class, args).তিন বাক্যে বলুন —SpringApplication.run(App.class, args)চালালে কী ঘটে।✨ Show Answer
Answer: (1) Spring bootstraps the
ApplicationContextand scans the classpath for@Component/@Service/@RestControllerbeans, instantiating and wiring them in dependency order. (2) Auto-configuration kicks in — Spring detects thatspring-boot-starter-webis on the classpath and starts the embedded Tomcat server on port 8080. (3) The app stays up, listens for HTTP traffic, and dispatches requests to your mapped handler methods until it is stopped.
Summary — Module 47
Spring Boot is the de-facto Java web framework, and its heart is dependency injection —
you declare what you need, the container wires it up. A few annotations (@RestController,
@Service, @Repository) replace hundreds of lines of glue code. Always prefer
constructor injection; it keeps your code testable and Spring-agnostic.