স্প্রিং বুট হল 2026 সালে এন্টারপ্রাইজ ব্যাকএন্ডের জন্য প্রভাবশালী জাভা ফ্রেমওয়ার্ক। স্প্রিং বুট 3.3, গ্রালভিএম-এর মাধ্যমে নেটিভ কম্পাইলেশন, প্রজেক্ট লুমের মাধ্যমে ভার্চুয়াল থ্রেড এবং স্প্রিং এআই স্টার্টার, জাভা এপিআই তৈরির কাজ কখনোই দ্রুত হয়নি। এই নির্দেশিকা আপনাকে হ্যালো ওয়ার্ল্ড থেকে প্রোডাকশন-গ্রেড REST API-এ নিয়ে যায়।
📋 Table of Contents
কেন বসন্ত বুট?
- স্বয়ংক্রিয় কনফিগারেশন— সংবেদনশীল ডিফল্ট, সাধারণ প্যাটার্নের জন্য শূন্য বয়লারপ্লেট
- এমবেডেড সার্ভার— Tomcat/Netty অন্তর্ভুক্ত, কোন স্থাপনার WAR ফাইল নেই
- উৎপাদন-প্রস্তুত— অ্যাকচুয়েটর, মাইক্রোমিটার মেট্রিক্স, স্বাস্থ্য পরীক্ষা অন্তর্নির্মিত
- GraalVM নেটিভ— নেটিভ বাইনারিতে কম্পাইল করুন, <50ms এ শুরু হয়, 50% কম RAM ব্যবহার করে
- বিশাল ইকোসিস্টেম— স্প্রিং ডেটা, সিকিউরিটি, ক্লাউড, ব্যাচ, এআই
প্রকল্প সেটআপ
# Spring Initializr (start.spring.io)
# Or via curl:
curl https://start.spring.io/starter.zip -d dependencies=web,data-jpa,postgresql,security,actuator,validation,lombok -d type=maven-project -d language=java -d javaVersion=21 -d name=techpulse-api -d groupId=com.techpulse -d artifactId=api -o techpulse-api.zip
unzip techpulse-api.zip
cd techpulse-api
mvn spring-boot:run
application.yml কনফিগারেশন
spring:
datasource:
url: jdbc:postgresql://localhost:5432/techpulse_db
username: ${DB_USER}
password: ${DB_PASSWORD}
hikari:
maximum-pool-size: 20
minimum-idle: 5
jpa:
hibernate:
ddl-auto: validate # use Flyway/Liquibase for production
show-sql: false
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
flyway:
enabled: true
locations: classpath:db/migration
server:
port: 8080
compression:
enabled: true
management:
endpoints:
web:
exposure:
include: health,metrics,info,prometheus
endpoint:
health:
show-details: always
সত্তা এবং সংগ্রহস্থল
// User.java
@Entity
@Table(name = "users")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
@Size(min = 2, max = 50)
private String name;
@Column(unique = true, nullable = false)
@Email
private String email;
@Column(nullable = false)
@JsonIgnore
private String passwordHash;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Role role = Role.USER;
@Column(nullable = false)
private boolean active = true;
@CreationTimestamp
private LocalDateTime createdAt;
@UpdateTimestamp
private LocalDateTime updatedAt;
public enum Role { USER, ADMIN, MODERATOR }
}
// UserRepository.java
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
Page<User> findByActiveTrue(Pageable pageable);
List<User> findByRole(User.Role role);
boolean existsByEmail(String email);
@Query("SELECT u FROM User u WHERE u.name ILIKE %:name%")
List<User> searchByName(@Param("name") String name);
}
সার্ভিস লেয়ার
// UserService.java
@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class UserService {
private final UserRepository userRepo;
private final PasswordEncoder passwordEncoder;
@Transactional(readOnly = true)
public Page<UserDTO> listUsers(Pageable pageable) {
return userRepo.findByActiveTrue(pageable)
.map(UserDTO::from);
}
@Transactional(readOnly = true)
public UserDTO getUser(Long id) {
return userRepo.findById(id)
.map(UserDTO::from)
.orElseThrow(() -> new ResourceNotFoundException("User not found: " + id));
}
public UserDTO createUser(CreateUserRequest request) {
if (userRepo.existsByEmail(request.email())) {
throw new ConflictException("Email already exists: " + request.email());
}
User user = User.builder()
.name(request.name())
.email(request.email())
.passwordHash(passwordEncoder.encode(request.password()))
.build();
User saved = userRepo.save(user);
log.info("Created user: {} ({})", saved.getEmail(), saved.getId());
return UserDTO.from(saved);
}
public UserDTO updateUser(Long id, UpdateUserRequest request) {
User user = userRepo.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("User not found"));
if (request.name() != null) user.setName(request.name());
return UserDTO.from(userRepo.save(user));
}
public void deleteUser(Long id) {
User user = userRepo.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("User not found"));
user.setActive(false); // soft delete
userRepo.save(user);
}
}
REST কন্ট্রোলার
// UserController.java
@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
@Validated
@Slf4j
public class UserController {
private final UserService userService;
@GetMapping
public ResponseEntity<Page<UserDTO>> listUsers(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
@RequestParam(defaultValue = "createdAt") String sortBy,
@RequestParam(defaultValue = "DESC") Sort.Direction direction
) {
Pageable pageable = PageRequest.of(page, size, Sort.by(direction, sortBy));
return ResponseEntity.ok(userService.listUsers(pageable));
}
@GetMapping("/{id}")
public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.getUser(id));
}
@PostMapping
public ResponseEntity<UserDTO> createUser(
@Valid @RequestBody CreateUserRequest request
) {
UserDTO created = userService.createUser(request);
URI location = URI.create("/api/v1/users/" + created.id());
return ResponseEntity.created(location).body(created);
}
@PatchMapping("/{id}")
public ResponseEntity<UserDTO> updateUser(
@PathVariable Long id,
@Valid @RequestBody UpdateUserRequest request
) {
return ResponseEntity.ok(userService.updateUser(id, request));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
// DTOs (Java records)
public record UserDTO(Long id, String name, String email, User.Role role, LocalDateTime createdAt) {
public static UserDTO from(User user) {
return new UserDTO(user.getId(), user.getName(), user.getEmail(),
user.getRole(), user.getCreatedAt());
}
}
public record CreateUserRequest(
@NotBlank @Size(min=2, max=50) String name,
@NotBlank @Email String email,
@NotBlank @Size(min=8) String password
) {}
গ্লোবাল এক্সেপশন হ্যান্ডলার
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ProblemDetail handleNotFound(ResourceNotFoundException ex) {
ProblemDetail problem = ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND, ex.getMessage());
problem.setTitle("Resource Not Found");
return problem;
}
@ExceptionHandler(ConflictException.class)
public ProblemDetail handleConflict(ConflictException ex) {
return ProblemDetail.forStatusAndDetail(HttpStatus.CONFLICT, ex.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ProblemDetail handleValidation(MethodArgumentNotValidException ex) {
Map<String, String> errors = ex.getBindingResult().getFieldErrors().stream()
.collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
ProblemDetail problem = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "Validation failed");
problem.setProperty("errors", errors);
return problem;
}
}
JWT এর সাথে বসন্ত নিরাপত্তা
// JwtService.java
@Service
public class JwtService {
@Value("${app.jwt.secret}")
private String secret;
private static final long EXPIRY = 86400000L; // 24h
public String generateToken(UserDetails user) {
return Jwts.builder()
.subject(user.getUsername())
.issuedAt(new Date())
.expiration(new Date(System.currentTimeMillis() + EXPIRY))
.signWith(Keys.hmacShaKeyFor(secret.getBytes()))
.compact();
}
public String extractUsername(String token) {
return Jwts.parser()
.verifyWith(Keys.hmacShaKeyFor(secret.getBytes()))
.build()
.parseSignedClaims(token)
.getPayload()
.getSubject();
}
}
ভার্চুয়াল থ্রেড (জাভা 21 + স্প্রিং বুট 3.3)
# application.yml — enable virtual threads
spring:
threads:
virtual:
enabled: true # uses Project Loom virtual threads for Tomcat
ভার্চুয়াল থ্রেডের সাথে, প্রতিটি HTTP অনুরোধ একটি প্ল্যাটফর্ম থ্রেডের পরিবর্তে একটি হালকা ভার্চুয়াল থ্রেড পায়। এটি কোন কোড পরিবর্তন ছাড়াই I/O-বাউন্ড অ্যাপ্লিকেশনের (ডাটাবেস কোয়েরি, বাহ্যিক API কল) থ্রুপুটকে নাটকীয়ভাবে উন্নত করে।
GraalVM নেটিভ ইমেজ
# Add to pom.xml
# <plugin>spring-boot-maven-plugin with native goal</plugin>
# Build native image (requires GraalVM 22+)
mvn -Pnative native:compile
# Run (starts in ~50ms, uses ~60MB RAM vs 300MB JVM)
./target/techpulse-api
2026 সালে স্প্রিং বুট 3.3 উত্পাদন-প্রস্তুত, দ্রুত এবং বিকাশকারী-বান্ধব। ভার্চুয়াল থ্রেডগুলি বেশিরভাগ ব্যবহারের ক্ষেত্রে প্রতিক্রিয়াশীল প্রোগ্রামিংয়ের প্রয়োজনীয়তা দূর করে। GraalVM নেটিভ ইমেজ জাভাকে কনটেইনারাইজড মাইক্রোসার্ভিসের জন্য একটি গুরুতর প্রতিযোগী করে তোলে যেখানে শুরুর সময় এবং মেমরি গুরুত্বপূর্ণ।
🔗 Share this article
✍️ Leave a Comment