ความหมายของ Ecosystem ในโลกซอฟต์แวร์
Ecosystem (ระบบนิเวศ) ในบริบทของภาษาโปรแกรม หมายถึง ชุมชน เครื่องมือ ไลบรารี่ framework และแพลตฟอร์มที่เกี่ยวข้องกับภาษานั้นๆ ซึ่งทำงานร่วมกันเพื่อสนับสนุนการพัฒนาซอฟต์แวร์
Java มี ecosystem ที่ใหญ่ที่สุดและสมบูรณ์ที่สุดในบรรดาภาษาโปรแกรมทั้งหมด ซึ่งเป็นหนึ่งในเหตุผลสำคัญที่ Java ยังคงเป็นภาษาอันดับต้นๆ ของโลกมากกว่า 30 ปี
- ความหมายของ Ecosystem ในโลกซอฟต์แวร์
- ส่วนประกอบหลักของ Java Ecosystem
- 2. Java Editions: Java สำหรับงานแต่ละประเภท
- 2.1 Java SE (Standard Edition)
- 2.2 Java EE (Enterprise Edition) → Jakarta EE
- 2.3 Java ME (Micro Edition)
- 2.4 Android
- 3. Java Frameworks: เครื่องมือเร่งการพัฒนา
- 3.1 Spring Framework: King of Java Frameworks
- 3.2 Hibernate: ORM Framework
- 3.3 Apache Kafka: Streaming & Event Processing
- 3.4 Elasticsearch: Search & Analytics
- 4. Build Tools & Dependency Management
- 4.1 Maven: Build Automation
- 4.2 Gradle: Modern Build Tool
- 5. Testing Frameworks
- 5.1 JUnit: Unit Testing
- 5.2 Mockito: Mocking Framework
- 5.3 Selenium: Integration Testing
- 6. Monitoring & Logging
- 6.1 SLF4J & Logback: Logging
- 6.2 Prometheus & Grafana: Metrics & Visualization
- 7. Version Control & DevOps
- 7.1 Git & GitHub: Version Control
- 7.2 Docker & Containerization
- 7.3 CI/CD Pipelines
- สรุป Java Ecosystem
ส่วนประกอบหลักของ Java Ecosystem
1. Java Platform: รากฐานของทุกอย่าง
1.1 JDK (Java Development Kit)
JDK คือชุดเครื่องมือสำหรับพัฒนาโปรแกรม Java ประกอบด้วย:
ส่วนประกอบของ JDK:
textJDK
├── JRE (Java Runtime Environment)
│ ├── JVM (Java Virtual Machine)
│ ├── Core Libraries (java.lang, java.util, java.io, etc.)
│ └── Runtime Support Files
│
├── Development Tools
│ ├── javac (Compiler - แปลง .java → .class)
│ ├── java (Launcher - รันโปรแกรม)
│ ├── jar (Archive tool - รวมไฟล์)
│ ├── javadoc (Documentation generator)
│ ├── jdb (Debugger)
│ └── jshell (Interactive shell - Java 9+)
│
└── Additional Libraries
├── JavaFX (GUI)
└── Tools API
ตัวอย่างการใช้งาน JDK Tools:
bash# 1. เขียนโปรแกรม (HelloWorld.java)
# สร้างไฟล์ HelloWorld.java
# 2. Compile - แปลงเป็น bytecode
javac HelloWorld.java
# สร้างไฟล์ HelloWorld.class
# 3. Run - รันด้วย JVM
java HelloWorld
# Output: Hello, World!
# 4. สร้าง JAR file (สำหรับ distribute)
jar cvf myapp.jar *.class
# สร้างไฟล์ myapp.jar
# 5. รัน JAR file
java -jar myapp.jar
# 6. Generate documentation
javadoc HelloWorld.java
# สร้าง HTML documentation
# 7. Interactive shell (Java 9+)
jshell
jshell> int x = 10;
jshell> System.out.println(x * 2);
20
1.2 JVM (Java Virtual Machine): หัวใจของ “Write Once, Run Anywhere”
JVM คือเครื่องเสมือนที่รันโค้ด Java โดยแปล bytecode เป็นคำสั่งเครื่องของแต่ละระบบปฏิบัติการ
สถาปัตยกรรม JVM:
textJava Source Code (.java)
↓
[javac Compiler]
↓
Bytecode (.class)
↓
[JVM - Platform Specific]
↓
┌─────────────────┐
│ Class Loader │ ← โหลด .class files
└─────────────────┘
↓
┌─────────────────┐
│ Bytecode │ ← ตรวจสอบความปลอดภัย
│ Verifier │
└─────────────────┘
↓
┌─────────────────┐
│ Interpreter/ │ ← แปลและรันโค้ด
│ JIT Compiler │
└─────────────────┘
↓
┌─────────────────┐
│ Runtime Data │ ← Memory Management
│ Areas │ (Heap, Stack, Method Area)
└─────────────────┘
↓
┌─────────────────┐
│ Garbage │ ← จัดการ memory อัตโนมัติ
│ Collector │
└─────────────────┘
↓
┌─────────────────┐
│ Native Method │ ← เชื่อมต่อกับ OS
│ Interface │
└─────────────────┘
ตัวอย่างการทำงานของ JVM:
java// Example.java
public class Example {
public static void main(String[] args) {
int x = 10;
int y = 20;
int result = add(x, y);
System.out.println("Result: " + result);
}
public static int add(int a, int b) {
return a + b;
}
}
สิ่งที่เกิดขึ้นใน JVM:
text1. Class Loading:
- JVM โหลด Example.class เข้า Memory
- ตรวจสอบ bytecode ว่าถูกต้องและปลอดภัย
2. Memory Allocation:
Stack Memory:
┌──────────────────┐
│ main() frame │
│ - x = 10 │
│ - y = 20 │
│ - result = ? │
└──────────────────┘
↓ เรียก add()
┌──────────────────┐
│ add() frame │
│ - a = 10 │
│ - b = 20 │
│ - return 30 │
└──────────────────┘
↓ return
┌──────────────────┐
│ main() frame │
│ - x = 10 │
│ - y = 20 │
│ - result = 30 │
└──────────────────┘
3. Execution:
- Interpreter แปล bytecode เป็นคำสั่งเครื่อง
- JIT Compiler คอมไพล์ hot code (โค้ดที่รันบ่อย) เป็น native code
4. Output:
- System.out.println() เรียก native method
- แสดงผล "Result: 30" บน console
ข้อดีของ JVM:
- Platform Independence (ความเป็นอิสระจากแพลตฟอร์ม)
java// โค้ดเดียวกันรันได้บนทุก OS
public class PlatformDemo {
public static void main(String[] args) {
System.out.println("OS: " + System.getProperty("os.name"));
System.out.println("Java Version: " + System.getProperty("java.version"));
// โค้ดนี้ทำงานเหมือนกันทุก platform
String filePath = "data/config.txt";
File file = new File(filePath);
// JVM จัดการ file separator อัตโนมัติ
// Windows: data\config.txt
// Linux/Mac: data/config.txt
}
}
- Automatic Memory Management (Garbage Collection)
java// ไม่ต้องจัดการ memory เอง (ต่างจาก C/C++)
public class MemoryDemo {
public static void main(String[] args) {
// สร้าง objects
for (int i = 0; i < 1000000; i++) {
String temp = "String " + i;
// ไม่ต้อง free memory เอง
// Garbage Collector ทำให้อัตโนมัติ
}
// JVM จะลบ objects ที่ไม่ใช้งานแล้วออกจาก memory
System.gc(); // แนะนำให้ GC ทำงาน (แต่ไม่บังคับ)
}
}
- Security (ความปลอดภัย)
java// JVM ตรวจสอบ bytecode ก่อนรัน
public class SecurityDemo {
public static void main(String[] args) {
int[] array = new int[5];
try {
// JVM จะตรวจสอบและป้องกัน buffer overflow
array[10] = 100; // ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Prevented memory access violation!");
}
// ใน C/C++ โค้ดแบบนี้จะ crash หรือเข้าถึง memory ผิด
}
}
1.3 JIT Compiler: เพิ่มความเร็วด้วย Just-In-Time Compilation
JIT (Just-In-Time) Compiler คือส่วนของ JVM ที่แปลง bytecode เป็น native machine code ขณะรันโปรแกรม
การทำงานของ JIT:
textFirst Execution (Cold Code):
┌──────────────┐
│ Bytecode │ → Interpreter → Slow Execution
└──────────────┘
After Multiple Executions (Hot Code):
┌──────────────┐
│ Bytecode │ → JIT Compiler → Native Code → Fast Execution
└──────────────┘ (Cached)
ตัวอย่างผลของ JIT:
javapublic class JITDemo {
// Method นี้จะถูกเรียกหลายครั้ง → Hot Code
public static long fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
public static void main(String[] args) {
// Warm-up: ให้ JIT compile
for (int i = 0; i < 10000; i++) {
fibonacci(20);
}
// Measure performance
long start = System.nanoTime();
for (int i = 0; i < 10000; i++) {
fibonacci(20);
}
long end = System.nanoTime();
double seconds = (end - start) / 1_000_000_000.0;
System.out.println("Time: " + seconds + " seconds");
// หลัง JIT compile จะเร็วกว่า interpreter หลายเท่า
}
}
ผลลัพธ์:
- Interpreted mode: ~2.5 seconds
- After JIT compilation: ~0.8 seconds (เร็วขึ้น 3 เท่า)
2. Java Editions: Java สำหรับงานแต่ละประเภท
Java แบ่งออกเป็น 4 editions หลักตามการใช้งาน:
2.1 Java SE (Standard Edition)
Java SE คือรากฐานของ Java สำหรับ Desktop Applications, Command-line tools, และพื้นฐานทั่วไป
ส่วนประกอบหลัก:
- Core libraries (Collections, I/O, Networking)
- GUI libraries (JavaFX, Swing)
- Database connectivity (JDBC)
- XML processing
- Security
ตัวอย่างการใช้งาน Java SE:
java// 1. Desktop Calculator Application
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class CalculatorApp extends Application {
private TextField display = new TextField();
@Override
public void start(Stage primaryStage) {
GridPane grid = new GridPane();
// Display
display.setEditable(false);
grid.add(display, 0, 0, 4, 1);
// Buttons
String[] buttons = {
"7", "8", "9", "/",
"4", "5", "6", "*",
"1", "2", "3", "-",
"0", ".", "=", "+"
};
int row = 1, col = 0;
for (String text : buttons) {
Button btn = new Button(text);
btn.setOnAction(e -> handleButton(text));
grid.add(btn, col, row);
col++;
if (col > 3) {
col = 0;
row++;
}
}
Scene scene = new Scene(grid, 300, 400);
primaryStage.setTitle("Calculator");
primaryStage.setScene(scene);
primaryStage.show();
}
private void handleButton(String text) {
// Calculator logic
}
}
// 2. File Processing Tool
import java.io.*;
import java.nio.file.*;
public class FileProcessor {
public static void processLogFiles(String directory) throws IOException {
// อ่านไฟล์ทั้งหมดใน directory
Files.walk(Paths.get(directory))
.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".log"))
.forEach(path -> {
try {
long lineCount = Files.lines(path).count();
System.out.println(path.getFileName() + ": " + lineCount + " lines");
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
// 3. Network Client
import java.net.*;
import java.io.*;
public class HTTPClient {
public static String fetchData(String urlString) throws IOException {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream())
);
StringBuilder response = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
response.append(line);
}
in.close();
return response.toString();
}
}
2.2 Java EE (Enterprise Edition) → Jakarta EE
Java EE (ปัจจุบันเปลี่ยนชื่อเป็น Jakarta EE) คือ Java สำหรับ Enterprise Applications ระดับองค์กรขนาดใหญ่
Technologies ใน Jakarta EE:
- Servlets & JSP – Web applications
- JPA (Java Persistence API) – Database ORM
- EJB (Enterprise JavaBeans) – Business logic
- JMS (Java Message Service) – Message queuing
- JAX-RS – RESTful web services
- CDI (Contexts and Dependency Injection) – Dependency injection
ตัวอย่าง: RESTful API สำหรับ E-Commerce
java// 1. Entity Class (JPA)
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false)
private Double price;
private Integer stock;
@Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
// Constructors, getters, setters
}
// 2. Repository (Data Access)
@Stateless
public class ProductRepository {
@PersistenceContext
private EntityManager em;
public Product findById(Long id) {
return em.find(Product.class, id);
}
public List<Product> findAll() {
return em.createQuery("SELECT p FROM Product p", Product.class)
.getResultList();
}
public Product save(Product product) {
if (product.getId() == null) {
em.persist(product);
return product;
} else {
return em.merge(product);
}
}
public void delete(Long id) {
Product product = findById(id);
if (product != null) {
em.remove(product);
}
}
}
// 3. REST API (JAX-RS)
@Path("/products")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ProductResource {
@Inject
private ProductRepository repository;
@GET
public List<Product> getAllProducts() {
return repository.findAll();
}
@GET
@Path("/{id}")
public Response getProduct(@PathParam("id") Long id) {
Product product = repository.findById(id);
if (product != null) {
return Response.ok(product).build();
}
return Response.status(Response.Status.NOT_FOUND).build();
}
@POST
public Response createProduct(Product product) {
Product saved = repository.save(product);
return Response.status(Response.Status.CREATED)
.entity(saved)
.build();
}
@PUT
@Path("/{id}")
public Response updateProduct(@PathParam("id") Long id, Product product) {
product.setId(id);
Product updated = repository.save(product);
return Response.ok(updated).build();
}
@DELETE
@Path("/{id}")
public Response deleteProduct(@PathParam("id") Long id) {
repository.delete(id);
return Response.noContent().build();
}
}
บริษัทไทยที่ใช้ Jakarta EE/Java EE:
- ธนาคารพาณิชย์ (SCB, Kbank, BBL) – Core Banking Systems
- ประกันภัย (AIA, FWD) – Policy Management
- โรงพยาบาล (Bumrungrad, BNH) – Hospital Information Systems
- สายการบิน (Thai Airways) – Reservation Systems
2.3 Java ME (Micro Edition)
Java ME คือ Java สำหรับ อุปกรณ์ embedded และ IoT devices ที่มี resource จำกัด
Use Cases:
- Smart Cards
- IoT Sensors
- Industrial Controllers
- Mobile Devices (เก่า – ก่อน Android)
ตัวอย่าง: IoT Temperature Sensor
java// Simplified Java ME code for IoT device
import javax.microedition.midlet.*;
import javax.microedition.io.*;
public class TemperatureSensor extends MIDlet {
private StreamConnection conn;
private OutputStream out;
public void startApp() {
try {
// Connect to server
conn = (StreamConnection) Connector.open("socket://server:8080");
out = conn.openOutputStream();
// Send sensor data every 5 seconds
while (true) {
double temperature = readSensor();
String data = "TEMP:" + temperature + "\n";
out.write(data.getBytes());
out.flush();
Thread.sleep(5000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private double readSensor() {
// Read from hardware sensor
return 25.5; // Simulated value
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {
try {
if (out != null) out.close();
if (conn != null) conn.close();
} catch (Exception e) {}
}
}
2.4 Android
Android ใช้ Java (และ Kotlin) เป็นภาษาหลักในการพัฒนา Mobile Apps
Android Components:
- Activities (UI screens)
- Services (background tasks)
- Broadcast Receivers (system events)
- Content Providers (data sharing)
ตัวอย่าง: Android Food Delivery App
java// 1. Main Activity
public class MainActivity extends AppCompatActivity {
private RecyclerView restaurantList;
private RestaurantAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
restaurantList = findViewById(R.id.restaurant_list);
restaurantList.setLayoutManager(new LinearLayoutManager(this));
// Load restaurants
loadRestaurants();
}
private void loadRestaurants() {
// API call
RestaurantAPI api = RetrofitClient.getInstance().create(RestaurantAPI.class);
api.getRestaurants().enqueue(new Callback<List<Restaurant>>() {
@Override
public void onResponse(Call<List<Restaurant>> call,
Response<List<Restaurant>> response) {
if (response.isSuccessful()) {
adapter = new RestaurantAdapter(response.body());
restaurantList.setAdapter(adapter);
}
}
@Override
public void onFailure(Call<List<Restaurant>> call, Throwable t) {
Toast.makeText(MainActivity.this,
"Failed to load restaurants",
Toast.LENGTH_SHORT).show();
}
});
}
}
// 2. Model
public class Restaurant {
private String id;
private String name;
private String cuisine;
private double rating;
private int deliveryTime;
private boolean isOpen;
// Getters and setters
}
// 3. API Interface (Retrofit)
public interface RestaurantAPI {
@GET("restaurants")
Call<List<Restaurant>> getRestaurants();
@GET("restaurants/{id}")
Call<Restaurant> getRestaurant(@Path("id") String id);
@POST("orders")
Call<Order> placeOrder(@Body Order order);
}
// 4. Background Service
public class OrderTrackingService extends Service {
private Handler handler = new Handler();
private Runnable updateTask = new Runnable() {
@Override
public void run() {
// Update order status
updateOrderStatus();
handler.postDelayed(this, 10000); // Every 10 seconds
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler.post(updateTask);
return START_STICKY;
}
private void updateOrderStatus() {
// Check order status from server
// Send notification if status changed
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Android Apps ที่ใช้ Java ในไทย:
- LINE – Messaging app
- SCB Easy – Mobile banking
- Shopee – E-commerce
- Grab – Ride hailing & delivery
- True ID – Streaming platform
3. Java Frameworks: เครื่องมือเร่งการพัฒนา
3.1 Spring Framework: King of Java Frameworks
Spring เป็น framework ที่ได้รับความนิยมสูงสุดสำหรับพัฒนา Enterprise Applications
Spring Ecosystem:
textSpring Framework
├── Spring Core (DI/IoC Container)
├── Spring Boot (Rapid Development)
├── Spring MVC (Web Applications)
├── Spring Data (Database Access)
├── Spring Security (Authentication/Authorization)
├── Spring Cloud (Microservices)
└── Spring Batch (Batch Processing)
ตัวอย่าง: Spring Boot REST API
java// 1. Main Application
@SpringBootApplication
public class ECommerceApplication {
public static void main(String[] args) {
SpringApplication.run(ECommerceApplication.class, args);
}
}
// 2. Entity
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String customerId;
private Double totalAmount;
@Enumerated(EnumType.STRING)
private OrderStatus status;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "order")
private List<OrderItem> items;
@CreationTimestamp
private LocalDateTime createdAt;
// Getters, setters
}
// 3. Repository (Spring Data JPA)
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByCustomerId(String customerId);
List<Order> findByStatus(OrderStatus status);
@Query("SELECT o FROM Order o WHERE o.totalAmount > :amount")
List<Order> findHighValueOrders(@Param("amount") Double amount);
}
// 4. Service
@Service
@Transactional
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private PaymentService paymentService;
@Autowired
private NotificationService notificationService;
public Order createOrder(OrderRequest request) {
Order order = new Order();
order.setCustomerId(request.getCustomerId());
order.setItems(request.getItems());
order.setTotalAmount(calculateTotal(request.getItems()));
order.setStatus(OrderStatus.PENDING);
order = orderRepository.save(order);
// Process payment
boolean paymentSuccess = paymentService.processPayment(order);
if (paymentSuccess) {
order.setStatus(OrderStatus.CONFIRMED);
notificationService.sendOrderConfirmation(order);
} else {
order.setStatus(OrderStatus.FAILED);
}
return orderRepository.save(order);
}
public Order getOrder(Long id) {
return orderRepository.findById(id)
.orElseThrow(() -> new OrderNotFoundException(id));
}
public List<Order> getCustomerOrders(String customerId) {
return orderRepository.findByCustomerId(customerId);
}
}
// 5. REST Controller
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping
public ResponseEntity<Order> createOrder(@RequestBody @Valid OrderRequest request) {
Order order = orderService.createOrder(request);
return ResponseEntity.status(HttpStatus.CREATED).body(order);
}
@GetMapping("/{id}")
public ResponseEntity<Order> getOrder(@PathVariable Long id) {
Order order = orderService.getOrder(id);
return ResponseEntity.ok(order);
}
@GetMapping
public ResponseEntity<List<Order>> getOrders(
@RequestParam(required = false) String customerId) {
if (customerId != null) {
return ResponseEntity.ok(orderService.getCustomerOrders(customerId));
}
return ResponseEntity.ok(orderService.getAllOrders());
}
}
// 6. Security Configuration
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/orders/**").authenticated()
.antMatchers("/api/public/**").permitAll()
.and()
.oauth2ResourceServer()
.jwt();
}
}
บริษัทไทยที่ใช้ Spring:
- SCB Tech – ระบบ Banking
- LINE MAN – Order Management
- Central Tech – E-Commerce Platform
- Agoda – Booking System
- Grab Thailand – Backend Services
3.2 Hibernate: ORM Framework
Hibernate ทำให้การทำงานกับ Database ง่ายขึ้นด้วยการแปลง Objects เป็น Tables
ตัวอย่าง: Hibernate ORM
java// 1. Entity with Relationships
@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
private List<Order> orders = new ArrayList<>();
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id")
private Address address;
// Methods
public void addOrder(Order order) {
orders.add(order);
order.setCustomer(this);
}
}
// 2. Query with HQL (Hibernate Query Language)
public class CustomerDAO {
@PersistenceContext
private EntityManager entityManager;
public List<Customer> findCustomersWithHighValueOrders(double minAmount) {
String hql = "SELECT DISTINCT c FROM Customer c " +
"JOIN c.orders o " +
"WHERE o.totalAmount > :minAmount";
return entityManager.createQuery(hql, Customer.class)
.setParameter("minAmount", minAmount)
.getResultList();
}
// Criteria API (Type-safe)
public List<Customer> findByEmailDomain(String domain) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Customer> cq = cb.createQuery(Customer.class);
Root<Customer> customer = cq.from(Customer.class);
cq.where(cb.like(customer.get("email"), "%" + domain));
return entityManager.createQuery(cq).getResultList();
}
}
3.3 Apache Kafka: Streaming & Event Processing
Kafka ใช้สำหรับ Real-time Data Streaming และ Event-Driven Architecture
Use Cases:
- Log aggregation
- Real-time analytics
- Event sourcing
- Message queue
ตัวอย่าง: Order Event Processing
java// 1. Producer - ส่ง events
@Configuration
public class KafkaProducerConfig {
@Bean
public ProducerFactory<String, OrderEvent> producerFactory() {
return new DefaultKafkaProducerFactory<>(
Map.of(
ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092",
ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class,
ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class
)
);
}
@Bean
public KafkaTemplate<String, OrderEvent> kafkaTemplate() {
return new KafkaTemplate<>(producerFactory());
}
}
// 2. Service - ส่ง order events
@Service
public class OrderEventPublisher {
@Autowired
private KafkaTemplate<String, OrderEvent> kafkaTemplate;
public void publishOrderCreated(Order order) {
OrderEvent event = new OrderEvent(
OrderEventType.CREATED,
order.getId(),
order.getCustomerId(),
order.getTotalAmount()
);
kafkaTemplate.send("order-events", String.valueOf(order.getId()), event);
}
public void publishOrderConfirmed(Order order) {
OrderEvent event = new OrderEvent(
OrderEventType.CONFIRMED,
order.getId(),
order.getCustomerId(),
order.getTotalAmount()
);
kafkaTemplate.send("order-events", String.valueOf(order.getId()), event);
}
public void publishOrderDelivered(Order order) {
OrderEvent event = new OrderEvent(
OrderEventType.DELIVERED,
order.getId(),
order.getCustomerId(),
order.getTotalAmount()
);
kafkaTemplate.send("order-events", String.valueOf(order.getId()), event);
}
}
// 3. Consumer - รับและประมวลผล events
@Service
public class OrderEventConsumer {
@KafkaListener(topics = "order-events", groupId = "order-notification-group")
public void handleOrderEvent(OrderEvent event) {
switch (event.getType()) {
case CREATED:
System.out.println("New order created: " + event.getOrderId());
sendNotification(event.getCustomerId(), "Order placed successfully");
break;
case CONFIRMED:
System.out.println("Order confirmed: " + event.getOrderId());
sendNotification(event.getCustomerId(), "Order confirmed by restaurant");
break;
case DELIVERED:
System.out.println("Order delivered: " + event.getOrderId());
sendNotification(event.getCustomerId(), "Your order has been delivered");
recordMetrics(event);
break;
}
}
private void sendNotification(String customerId, String message) {
// Send email, SMS, or push notification
}
private void recordMetrics(OrderEvent event) {
// Record delivery time, customer satisfaction, etc.
}
}
// 4. Analytics Consumer - สำหรับ real-time analytics
@Service
public class OrderAnalyticsConsumer {
@Autowired
private AnalyticsRepository analyticsRepository;
@KafkaListener(topics = "order-events", groupId = "analytics-group")
public void analyzeOrderEvents(OrderEvent event) {
// Update real-time dashboards
// Calculate KPIs: Average order value, delivery time, customer satisfaction
OrderMetrics metrics = new OrderMetrics();
metrics.setOrderId(event.getOrderId());
metrics.setAmount(event.getAmount());
metrics.setTimestamp(LocalDateTime.now());
analyticsRepository.save(metrics);
}
}
บริษัทไทยที่ใช้ Kafka:
- LINE MAN – Real-time order tracking
- Agoda – Booking stream processing
- Grab – Ride matching & analytics
3.4 Elasticsearch: Search & Analytics
Elasticsearch ใช้สำหรับ Full-text Search และ Real-time Analytics
ตัวอย่าง: Product Search Engine
java// 1. Product Index Document
@Document(indexName = "products")
public class ProductDocument {
@Id
private String id;
@Field(type = FieldType.Text)
private String name;
@Field(type = FieldType.Text)
private String description;
@Field(type = FieldType.Keyword)
private String category;
@Field(type = FieldType.Double)
private Double price;
@Field(type = FieldType.Integer)
private Integer rating;
@Field(type = FieldType.Date)
private LocalDateTime createdAt;
}
// 2. Repository
@Repository
public interface ProductSearchRepository
extends ElasticsearchRepository<ProductDocument, String> {
// Basic search
List<ProductDocument> findByName(String name);
// Category search
List<ProductDocument> findByCategory(String category);
// Price range search
List<ProductDocument> findByPriceBetween(Double minPrice, Double maxPrice);
}
// 3. Advanced Search Service
@Service
public class ProductSearchService {
@Autowired
private ProductSearchRepository repository;
@Autowired
private ElasticsearchOperations elasticsearchOperations;
// Full-text search with filters
public List<ProductDocument> searchProducts(
String keyword,
String category,
Double minPrice,
Double maxPrice,
Integer minRating) {
Query query = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.multiMatchQuery(keyword)
.field("name", 3.0) // name has weight 3
.field("description", 1.0))
.withFilter(QueryBuilders.termQuery("category", category))
.withFilter(QueryBuilders.rangeQuery("price")
.gte(minPrice)
.lte(maxPrice))
.withFilter(QueryBuilders.rangeQuery("rating")
.gte(minRating))
.withPageable(PageRequest.of(0, 20))
.build();
SearchHits<ProductDocument> results =
elasticsearchOperations.search(query, ProductDocument.class);
return results.getSearchHits()
.stream()
.map(SearchHit::getContent)
.collect(Collectors.toList());
}
// Autocomplete search
public List<String> autocomplete(String prefix) {
Query query = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchPhraseQuery("name.prefix", prefix))
.withPageable(PageRequest.of(0, 10))
.build();
SearchHits<ProductDocument> results =
elasticsearchOperations.search(query, ProductDocument.class);
return results.getSearchHits()
.stream()
.map(hit -> hit.getContent().getName())
.distinct()
.collect(Collectors.toList());
}
// Aggregation - Category statistics
public Map<String, Long> getCategoryStats() {
Query query = new NativeSearchQueryBuilder()
.addAggregation(AggregationBuilders
.terms("categories")
.field("category")
.size(100))
.build();
SearchHits<ProductDocument> results =
elasticsearchOperations.search(query, ProductDocument.class);
Aggregations aggregations = results.getAggregations();
Terms categoryAgg = aggregations.get("categories");
return categoryAgg.getBuckets()
.stream()
.collect(Collectors.toMap(
bucket -> bucket.getKeyAsString(),
bucket -> bucket.getDocCount()
));
}
}
// 4. Controller
@RestController
@RequestMapping("/api/search")
public class SearchController {
@Autowired
private ProductSearchService searchService;
@GetMapping("/products")
public ResponseEntity<List<ProductDocument>> search(
@RequestParam String keyword,
@RequestParam(required = false) String category,
@RequestParam(required = false) Double minPrice,
@RequestParam(required = false) Double maxPrice,
@RequestParam(defaultValue = "0") Integer minRating) {
List<ProductDocument> results = searchService.searchProducts(
keyword, category, minPrice, maxPrice, minRating
);
return ResponseEntity.ok(results);
}
@GetMapping("/autocomplete")
public ResponseEntity<List<String>> autocomplete(
@RequestParam String q) {
List<String> suggestions = searchService.autocomplete(q);
return ResponseEntity.ok(suggestions);
}
@GetMapping("/stats/categories")
public ResponseEntity<Map<String, Long>> getCategoryStats() {
Map<String, Long> stats = searchService.getCategoryStats();
return ResponseEntity.ok(stats);
}
}
บริษัทไทยที่ใช้ Elasticsearch:
- Shopee – Product search
- Lazada – Search & recommendations
- Central Online – Product discovery
4. Build Tools & Dependency Management
4.1 Maven: Build Automation
Maven ใช้สำหรับ Automated Build, Testing, Deployment
Structure:
textmy-java-project/
├── pom.xml ← Configuration file
├── src/
│ ├── main/
│ │ ├── java/ ← Source code
│ │ └── resources/ ← Properties files
│ └── test/
│ ├── java/ ← Test code
│ └── resources/ ← Test properties
└── target/ ← Build output
├── classes/
└── my-app-1.0.jar
pom.xml Example:
xml<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ecommerce</groupId>
<artifactId>order-service</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>Order Service</name>
<description>E-Commerce Order Management Service</description>
<!-- Parent Spring Boot POM -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
<!-- Dependencies -->
<dependencies>
<!-- Spring Boot Starters -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Database -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<!-- Kafka -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<!-- Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- Build plugins -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Maven Commands:
bash# Clean and compile
mvn clean compile
# Run tests
mvn test
# Build JAR
mvn clean package
# Run application
mvn spring-boot:run
# Install to local repository
mvn install
# Deploy to remote repository
mvn deploy
4.2 Gradle: Modern Build Tool
Gradle เป็นอีกตัวเลือกสำหรับ Build Automation ที่ใช้ Groovy/Kotlin
build.gradle.kts Example:
kotlinplugins {
id("java")
id("org.springframework.boot") version "2.7.0"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
}
group = "com.ecommerce"
version = "1.0.0"
java.sourceCompatibility = JavaVersion.VERSION_11
repositories {
mavenCentral()
}
dependencies {
// Spring Boot
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
// Database
runtimeOnly("mysql:mysql-connector-java:8.0.26")
// Kafka
implementation("org.springframework.kafka:spring-kafka")
// Security & JWT
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("io.jsonwebtoken:jjwt:0.9.1")
// Testing
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
tasks.withType<Test> {
useJUnitPlatform()
}
5. Testing Frameworks
5.1 JUnit: Unit Testing
JUnit เป็น Framework หลักสำหรับ Unit Testing
ตัวอย่าง:
java@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderServiceTest {
@MockBean
private OrderRepository orderRepository;
@MockBean
private PaymentService paymentService;
@InjectMocks
private OrderService orderService;
private Order mockOrder;
@Before
public void setUp() {
mockOrder = new Order();
mockOrder.setId(1L);
mockOrder.setCustomerId("CUST001");
mockOrder.setTotalAmount(1000.0);
mockOrder.setStatus(OrderStatus.PENDING);
}
@Test
public void testCreateOrderSuccess() {
// Arrange
OrderRequest request = new OrderRequest();
request.setCustomerId("CUST001");
request.setItems(Arrays.asList(
new OrderItem("PROD001", 2, 500.0)
));
when(orderRepository.save(any(Order.class))).thenReturn(mockOrder);
when(paymentService.processPayment(any(Order.class))).thenReturn(true);
// Act
Order result = orderService.createOrder(request);
// Assert
assertNotNull(result);
assertEquals(OrderStatus.CONFIRMED, result.getStatus());
verify(orderRepository, times(1)).save(any(Order.class));
verify(paymentService, times(1)).processPayment(any(Order.class));
}
@Test
public void testCreateOrderPaymentFailed() {
// Arrange
OrderRequest request = new OrderRequest();
request.setCustomerId("CUST001");
request.setItems(Arrays.asList());
when(orderRepository.save(any(Order.class))).thenReturn(mockOrder);
when(paymentService.processPayment(any(Order.class))).thenReturn(false);
// Act
Order result = orderService.createOrder(request);
// Assert
assertEquals(OrderStatus.FAILED, result.getStatus());
}
@Test
public void testGetOrderNotFound() {
// Arrange
when(orderRepository.findById(999L)).thenReturn(Optional.empty());
// Act & Assert
assertThrows(OrderNotFoundException.class, () -> {
orderService.getOrder(999L);
});
}
}
5.2 Mockito: Mocking Framework
Mockito ใช้สำหรับ Mock Objects ในการทดสอบ
ตัวอย่าง Advanced:
javapublic class PaymentServiceTest {
@Mock
private PaymentGateway paymentGateway;
@Mock
private EmailService emailService;
@InjectMocks
private PaymentService paymentService;
@Before
public void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
public void testProcessPaymentWithRetry() {
// Arrange - ครั้งแรก fail, ครั้งที่ 2 success
when(paymentGateway.charge(anyDouble()))
.thenThrow(new NetworkException("Connection timeout"))
.thenReturn(new PaymentResult(true, "TXN001"));
// Act
PaymentResult result = paymentService.processPaymentWithRetry(1000.0);
// Assert
assertTrue(result.isSuccess());
verify(paymentGateway, times(2)).charge(1000.0);
}
@Test
public void testPaymentNotificationOnSuccess() {
// Arrange
when(paymentGateway.charge(anyDouble()))
.thenReturn(new PaymentResult(true, "TXN001"));
// Act
paymentService.processPayment(1000.0);
// Assert - ตรวจสอบว่า email ถูกส่ง
ArgumentCaptor<String> emailCaptor = ArgumentCaptor.forClass(String.class);
verify(emailService, times(1)).sendSuccessNotification(emailCaptor.capture());
String email = emailCaptor.getValue();
assertEquals("[email protected]", email);
}
}
5.3 Selenium: Integration Testing
Selenium ใช้สำหรับ End-to-End Testing ของ Web Applications
ตัวอย่าง:
javapublic class CheckoutFlowTest {
private WebDriver driver;
@Before
public void setUp() {
// ใช้ Chrome WebDriver
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
driver = new ChromeDriver();
}
@Test
public void testCompleteCheckoutFlow() throws InterruptedException {
// 1. เปิด website
driver.get("http://localhost:8080");
// 2. ค้นหาสินค้า
WebElement searchBox = driver.findElement(By.id("search-input"));
searchBox.sendKeys("MacBook Pro");
searchBox.submit();
Thread.sleep(2000);
// 3. เลือกสินค้า
WebElement productLink = driver.findElement(By.className("product-item"));
productLink.click();
Thread.sleep(1000);
// 4. เพิ่มลงตะกร้า
WebElement addToCartBtn = driver.findElement(By.id("add-to-cart"));
addToCartBtn.click();
// 5. ไปที่ checkout
WebElement cartIcon = driver.findElement(By.className("cart-icon"));
cartIcon.click();
Thread.sleep(1000);
WebElement checkoutBtn = driver.findElement(By.id("checkout-button"));
checkoutBtn.click();
// 6. ป้อนข้อมูลจัดส่ง
WebElement nameInput = driver.findElement(By.id("delivery-name"));
nameInput.sendKeys("John Doe");
WebElement phoneInput = driver.findElement(By.id("delivery-phone"));
phoneInput.sendKeys("0812345678");
WebElement addressInput = driver.findElement(By.id("delivery-address"));
addressInput.sendKeys("123 Sukhumvit Road, Bangkok");
// 7. เลือก Payment Method
WebElement creditCardOption = driver.findElement(By.id("payment-credit-card"));
creditCardOption.click();
// 8. ยืนยันคำสั่ง
WebElement confirmBtn = driver.findElement(By.id("confirm-order"));
confirmBtn.click();
Thread.sleep(3000);
// 9. ตรวจสอบผลลัพธ์
WebElement successMessage = driver.findElement(By.className("success-message"));
assertTrue(successMessage.isDisplayed());
String confirmationNumber = driver.findElement(By.id("order-number")).getText();
assertTrue(confirmationNumber.startsWith("ORD"));
}
@After
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}
6. Monitoring & Logging
6.1 SLF4J & Logback: Logging
Logging สำคัญสำหรับ Debugging และ Monitoring Production Systems
ตัวอย่าง:
java// ใช้ SLF4J (Simple Logging Facade)
public class OrderService {
private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
public Order createOrder(OrderRequest request) {
logger.info("Creating order for customer: {}", request.getCustomerId());
try {
Order order = new Order();
order.setCustomerId(request.getCustomerId());
order.setItems(request.getItems());
logger.debug("Order object created: {}", order.getId());
Order saved = orderRepository.save(order);
logger.info("Order saved successfully: {}", saved.getId());
boolean paymentSuccess = paymentService.processPayment(saved);
if (paymentSuccess) {
logger.info("Payment processed for order: {}", saved.getId());
saved.setStatus(OrderStatus.CONFIRMED);
} else {
logger.warn("Payment failed for order: {}", saved.getId());
saved.setStatus(OrderStatus.FAILED);
}
return saved;
} catch (Exception e) {
logger.error("Error creating order for customer: {}",
request.getCustomerId(), e);
throw new OrderProcessingException("Failed to create order", e);
}
}
}
logback.xml Configuration:
xml<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- Console appender -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<!-- File appender -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>
<encoder>
<pattern>
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/application.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<!-- Logger configurations -->
<logger name="com.ecommerce" level="INFO"/>
<logger name="org.springframework" level="WARN"/>
<!-- Root logger -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
6.2 Prometheus & Grafana: Metrics & Visualization
Prometheus สำหรับ Collect Metrics, Grafana สำหรับ Visualization
ตัวอย่าง:
java// Spring Boot Actuator + Micrometer (Prometheus)
@Configuration
public class MetricsConfiguration {
@Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCustomizer() {
return registry -> {
// สร้าง custom metrics
registry.counter("orders.created.total");
registry.counter("orders.failed.total");
registry.timer("order.processing.time");
registry.gauge("active.orders", 0);
};
}
}
// ใช้ metrics ใน service
@Service
public class OrderMetricsService {
@Autowired
private MeterRegistry meterRegistry;
public void recordOrderCreation() {
meterRegistry.counter("orders.created.total").increment();
}
public void recordOrderFailure() {
meterRegistry.counter("orders.failed.total").increment();
}
public void recordProcessingTime(long durationMs) {
meterRegistry.timer("order.processing.time")
.record(Duration.ofMillis(durationMs));
}
public void updateActiveOrders(int count) {
meterRegistry.gauge("active.orders", count);
}
}
// Prometheus endpoint: http://localhost:8080/actuator/prometheus
// Grafana dashboard: http://localhost:3000
Grafana Dashboard Queries:
text# ยอดออเดอร์ที่สร้างต่อนาที
rate(orders_created_total[1m])
# ระดับความล้มเหลวของการชำระเงิน
orders_failed_total / orders_created_total
# ระยะเวลาการประมวลผล order
histogram_quantile(0.95, order_processing_time)
7. Version Control & DevOps
7.1 Git & GitHub: Version Control
Git ใช้สำหรับ Source Code Management
Workflow:
bash# Clone repository
git clone https://github.com/company/order-service.git
# สร้าง feature branch
git checkout -b feature/add-order-tracking
# ทำการแก้ไขและ commit
git add .
git commit -m "feat: add order real-time tracking"
# Push ไป remote
git push origin feature/add-order-tracking
# สร้าง Pull Request → Code Review → Merge
7.2 Docker & Containerization
Docker ใช้สำหรับ Package Application ให้ Portable
Dockerfile Example:
textFROM openjdk:11-jre-slim
WORKDIR /app
# Copy JAR file
COPY target/order-service-1.0.0.jar app.jar
# Expose port
EXPOSE 8080
# Run application
ENTRYPOINT ["java", "-jar", "app.jar"]
docker-compose.yml:
textversion: '3.8'
services:
app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/ecommerce
- SPRING_DATASOURCE_USERNAME=root
- SPRING_DATASOURCE_PASSWORD=password
depends_on:
- db
- kafka
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=ecommerce
ports:
- "3306:3306"
kafka:
image: confluentinc/cp-kafka:6.2.0
environment:
- KAFKA_BROKER_ID=1
- KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
depends_on:
- zookeeper
zookeeper:
image: confluentinc/cp-zookeeper:6.2.0
environment:
- ZOOKEEPER_CLIENT_PORT=2181
7.3 CI/CD Pipelines
GitHub Actions Example:
textname: Build and Deploy
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
- name: Run tests
run: mvn clean test
- name: Build JAR
run: mvn clean package -DskipTests
- name: Build Docker image
run: docker build -t order-service:latest .
- name: Push to Docker Registry
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker push order-service:latest
- name: Deploy to production
run: |
kubectl set image deployment/order-service \
order-service=order-service:latest
สรุป Java Ecosystem
Java ประสบความสำเร็จมานานเพราะมี Ecosystem ที่สมบูรณ์:
| ส่วนประกอบ | ตัวอย่าง | ประโยชน์ |
|---|---|---|
| Runtime | JVM, JIT | Platform independent, Auto memory management |
| Frameworks | Spring, Hibernate | Rapid development, Best practices |
| Data | Elasticsearch, Kafka | Real-time search & streaming |
| Build | Maven, Gradle | Automation, Dependency management |
| Testing | JUnit, Mockito | Code quality assurance |
| Monitoring | Prometheus, Grafana | Production visibility |
| DevOps | Docker, Kubernetes | Containerization, Orchestration |
บริษัทไทยใช้ Java Ecosystem ร่วมกัน:
textJava SE (Core Language)
↓
Spring Boot (Framework)
↓
PostgreSQL/MySQL (Database) + JPA (ORM)
↓
Kafka (Event Streaming)
↓
Elasticsearch (Search)
↓
Docker (Containerization)
↓
Kubernetes (Orchestration)
↓
Prometheus + Grafana (Monitoring)
↓
GitHub Actions (CI/CD)
↓
Production Cloud (AWS/GCP/Azure)
นักศึกษาเมื่อจบวิชา OOP ด้วย Java จะเข้าใจและสามารถใช้ Ecosystem นี้ได้ และพร้อมทำงานจริงในบริษัทซอฟต์แวร์ไทย
