Java Ecosystem: ระบบนิเวศที่ทำให้ Java แข็งแกร่ง

ความหมายของ Ecosystem ในโลกซอฟต์แวร์

Ecosystem (ระบบนิเวศ) ในบริบทของภาษาโปรแกรม หมายถึง ชุมชน เครื่องมือ ไลบรารี่ framework และแพลตฟอร์มที่เกี่ยวข้องกับภาษานั้นๆ ซึ่งทำงานร่วมกันเพื่อสนับสนุนการพัฒนาซอฟต์แวร์

Java มี ecosystem ที่ใหญ่ที่สุดและสมบูรณ์ที่สุดในบรรดาภาษาโปรแกรมทั้งหมด ซึ่งเป็นหนึ่งในเหตุผลสำคัญที่ Java ยังคงเป็นภาษาอันดับต้นๆ ของโลกมากกว่า 30 ปี


ส่วนประกอบหลักของ 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:

  1. 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
    }
}
  1. 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 ทำงาน (แต่ไม่บังคับ)
    }
}
  1. 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 ที่สมบูรณ์:

ส่วนประกอบตัวอย่างประโยชน์
RuntimeJVM, JITPlatform independent, Auto memory management
FrameworksSpring, HibernateRapid development, Best practices
DataElasticsearch, KafkaReal-time search & streaming
BuildMaven, GradleAutomation, Dependency management
TestingJUnit, MockitoCode quality assurance
MonitoringPrometheus, GrafanaProduction visibility
DevOpsDocker, KubernetesContainerization, 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 นี้ได้ และพร้อมทำงานจริงในบริษัทซอฟต์แวร์ไทย