> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pebchip.top/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Java Backend Reference: Spring Boot, JVM, and Concurrency

> Comprehensive Java guide covering Spring Boot, MyBatis-Plus, JVM internals, multithreading, Java 8 features, and production-ready patterns.

Java remains one of the most widely deployed backend languages in the industry, backed by a mature ecosystem and a battle-tested JVM. This page distills the core knowledge you need for building production-grade Java services: Spring Boot's auto-configuration model, JVM memory regions and class loading, multithreading primitives, Java 8+ language features, and data-access patterns with MyBatis-Plus.

## Spring Boot Essentials

Spring Boot eliminates the boilerplate of traditional Spring applications. It follows a "convention over configuration" philosophy: a handful of starter dependencies gives you an embedded Tomcat server, JSON serialization, database connectivity, and more—all wired together automatically.

### Auto-configuration and starters

Adding `spring-boot-starter-web` to your `pom.xml` pulls in Spring MVC, an embedded Tomcat, and Jackson without any XML configuration. Spring Boot scans your classpath and conditionally activates beans based on what it finds.

```xml theme={null}
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
```

Enable hot reload during development with the devtools starter:

```xml theme={null}
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>
```

Then configure it in `application.properties`:

```properties theme={null}
spring.devtools.restart.enabled=true
spring.devtools.restart.additional-paths=src/main/java
spring.devtools.restart.exclude=static/**
```

### Dependency injection

Spring Boot manages beans through its IoC container. Annotate classes with `@Service`, `@Repository`, or `@Component` to register them, and use `@Autowired` (or constructor injection) to receive dependencies:

```java theme={null}
@Service
public class OrderService {
    private final OrderRepository repo;

    public OrderService(OrderRepository repo) { // constructor injection
        this.repo = repo;
    }
}
```

### REST controllers

Use `@RestController` for APIs that return data (JSON by default). `@Controller` is for server-rendered pages. In a front-end/back-end separated architecture you will almost always use `@RestController`.

```java theme={null}
@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/users/{id}")
    public User getUser(@PathVariable int id) {
        return userService.findById(id);
    }

    @PostMapping("/users")
    public String createUser(@RequestBody User user) {
        userService.save(user);
        return "created";
    }
}
```

Spring Boot also supports request mapping shortcuts: `@GetMapping`, `@PostMapping`, `@PutMapping`, `@DeleteMapping`. Route paths should contain only nouns, not verbs (`/users`, not `/getUser`).

### Interceptors and filters

Interceptors handle Spring-managed resources; filters run before the Spring context and intercept every request including static files. Execution order: `Filter → Interceptor → Controller`.

```java theme={null}
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest req,
                             HttpServletResponse res,
                             Object handler) {
        // return false to abort the request
        return true;
    }
}
```

Register the interceptor in a `WebMvcConfigurer`:

```java theme={null}
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthInterceptor())
                .addPathPatterns("/api/**");
    }
}
```

## JVM Internals

The JVM manages memory in several distinct regions. Understanding them helps you tune heap sizes, diagnose `OutOfMemoryError`, and reason about object lifecycles.

### Memory regions

| Region                            | Thread scope                 | Purpose                                                               |
| --------------------------------- | ---------------------------- | --------------------------------------------------------------------- |
| Program Counter Register          | Per-thread                   | Tracks the current bytecode instruction                               |
| JVM Stack (virtual machine stack) | Per-thread                   | Stores stack frames with local variables and operand stacks           |
| Native Method Stack               | Per-thread                   | Services `native` (C/C++) calls via JNI                               |
| Heap                              | Shared                       | Stores almost all object instances; managed by the GC                 |
| Method Area                       | Shared                       | Stores class metadata, constants, static variables, JIT-compiled code |
| Runtime Constant Pool             | Shared (part of Method Area) | Literal values and symbolic references resolved at load time          |

The heap is the largest region and the primary GC target. You control its bounds with `-Xms` (initial size) and `-Xmx` (maximum size).

### Object lifecycle

When the JVM executes `new Foo()`:

1. **Class load check** — verifies that `Foo` is already loaded, linked, and initialized; triggers class loading if not.
2. **Memory allocation** — carves out a region of the heap. Uses CAS-based retry or per-thread TLAB (Thread-Local Allocation Buffer) to keep allocations thread-safe.
3. **Zero initialization** — sets all instance fields to their zero values so code can read fields before explicitly assigning them.
4. **Object header setup** — records the class pointer, identity hash code, GC generation age, and lock state in the header.
5. **Constructor** — runs `<init>()` to set user-defined initial values.

### Class loading

Class loading proceeds through five stages:

1. **Loading** — reads the `.class` bytecode and creates a `Class` object in the method area.
2. **Verification** — confirms the bytecode conforms to the JVM specification (no memory corruption, no type violations).
3. **Preparation** — allocates memory for static variables and sets them to zero (not their declared values yet).
4. **Resolution** — replaces symbolic references in the constant pool with direct memory pointers.
5. **Initialization** — executes the `<clinit>()` method, running static initializer blocks and assigning declared static values.

A class is unloaded only when its `Class` object is GC'd, which requires all instances to be collected and the class loader itself to be collected. JVM built-in class loaders never unload their classes.

### JIT compilation

The JVM interprets bytecode initially. The JIT compiler identifies hot methods and compiles them to native machine code at runtime. This means long-running Java processes typically outperform freshly started ones because the JIT has had time to optimize hot paths.

## Multithreading

### Thread and Runnable

There are two basic ways to define work for a thread. Extending `Thread` is simpler but wastes Java's single-inheritance slot:

```java theme={null}
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("running in thread");
    }
}
new MyThread().start();
```

Implementing `Runnable` is preferred because it keeps your class free to extend another class and makes it easy to share one `Runnable` across multiple threads:

```java theme={null}
public class MyTask implements Runnable {
    @Override
    public void run() {
        System.out.println("task running");
    }
}
new Thread(new MyTask()).start();
```

### ExecutorService and thread pools

Creating and destroying threads on demand is expensive. Use `ExecutorService` to maintain a pool of worker threads:

```java theme={null}
ExecutorService pool = Executors.newFixedThreadPool(10);

// submit a Runnable
pool.execute(new MyTask());

// submit a Callable (returns a Future)
Future<Integer> future = pool.submit(() -> {
    return 42;
});
System.out.println(future.get()); // blocks until done

pool.shutdown();
```

Thread pool parameters to know:

* `corePoolSize` — threads kept alive even when idle.
* `maximumPoolSize` — upper bound on thread count.
* `keepAliveTime` — how long idle threads above `corePoolSize` survive before being terminated.

### `synchronized` vs `ReentrantLock`

`synchronized` is an implicit lock tied to an object monitor. It releases automatically when the block exits, even on exception:

```java theme={null}
public synchronized void increment() {
    count++;
}

// or a block lock on an explicit object
synchronized (sharedList) {
    sharedList.add(item);
}
```

`ReentrantLock` is explicit and offers more control: try-lock, timed lock, and fairness settings. Always release in a `finally` block:

```java theme={null}
private final ReentrantLock lock = new ReentrantLock();

public void increment() {
    lock.lock();
    try {
        count++;
    } finally {
        lock.unlock();
    }
}
```

Priority ordering for choosing a lock: `ReentrantLock` > synchronized block > synchronized method.

### CompletableFuture

`CompletableFuture` enables non-blocking async pipelines without explicit thread management:

```java theme={null}
CompletableFuture<String> future = CompletableFuture
    .supplyAsync(() -> fetchData())        // runs on ForkJoinPool
    .thenApply(data -> transform(data))    // chained transformation
    .exceptionally(ex -> "fallback");      // error handling

String result = future.join(); // block until complete
```

### Producer-consumer with `wait` / `notifyAll`

The classic bounded-buffer pattern uses `wait` and `notifyAll` on a shared monitor to coordinate producers and consumers:

```java theme={null}
class BoundedBuffer {
    private final Object[] items = new Object[20];
    private int count = 0;

    public synchronized void put(Object item) throws InterruptedException {
        while (count == items.length) wait(); // buffer full
        items[count++] = item;
        notifyAll();
    }

    public synchronized Object take() throws InterruptedException {
        while (count == 0) wait(); // buffer empty
        Object item = items[--count];
        notifyAll();
        return item;
    }
}
```

## Java 8+ Features

### Optional

`Optional<T>` makes the possibility of a missing value explicit in the type system, eliminating entire classes of `NullPointerException`:

```java theme={null}
Optional<User> user = userRepo.findById(id);
String name = user.map(User::getName)
                  .orElse("anonymous");
```

### Stream API

Streams provide a declarative, functional-style pipeline for processing collections:

```java theme={null}
List<String> names = users.stream()
    .filter(u -> u.getAge() > 18)
    .sorted(Comparator.comparing(User::getName))
    .map(User::getName)
    .collect(Collectors.toList());
```

### Functional interfaces and lambdas

Any interface with exactly one abstract method is a functional interface and can be expressed as a lambda:

```java theme={null}
// Built-in functional interfaces
Function<Integer, Integer> square = x -> x * x;
Predicate<String>          isEmpty = s -> s.isEmpty();
Consumer<String>           printer = System.out::println;
Supplier<List<String>>     factory = ArrayList::new;

System.out.println(square.apply(5)); // 25
```

Lambda expressions eliminate the need for anonymous inner classes and integrate naturally with the Stream API.

### LocalDateTime

`java.time.LocalDateTime` replaces the problematic `Date` and `Calendar` APIs. It is immutable and thread-safe:

```java theme={null}
LocalDateTime now   = LocalDateTime.now();
LocalDateTime later = now.plusHours(2).plusDays(1);
String formatted    = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
LocalDateTime parsed = LocalDateTime.parse("2026-01-15T10:30:00");
```

## MyBatis-Plus

MyBatis-Plus enhances MyBatis with generic CRUD operations, a fluent query wrapper, and pagination—without requiring you to write SQL for common cases.

### Setup

Add the dependencies in `pom.xml`:

```xml theme={null}
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.32</version>
</dependency>
```

Configure your datasource in `application.properties`:

```properties theme={null}
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false
spring.datasource.username=root
spring.datasource.password=secret
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
```

Add `@MapperScan` to your main class:

```java theme={null}
@SpringBootApplication
@MapperScan("com.example.mapper")
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}
```

### Basic CRUD

Extend `BaseMapper<T>` to inherit full CRUD without writing SQL:

```java theme={null}
@Mapper
public interface UserMapper extends BaseMapper<User> {
    // selectById, insert, updateById, deleteById, selectList, etc.
    // are all inherited from BaseMapper
}
```

For custom queries, use annotations directly on the interface:

```java theme={null}
@Mapper
public interface UserMapper extends BaseMapper<User> {
    @Select("SELECT * FROM user WHERE name = #{name}")
    User findByName(String name);

    @Insert("INSERT INTO user VALUES (#{id}, #{name}, #{age})")
    int insert(User user);

    @Update("UPDATE user SET name=#{name}, age=#{age} WHERE id=#{id}")
    int update(User user);

    @Delete("DELETE FROM user WHERE id=#{id}")
    int delete(int id);
}
```

### Conditional queries

The `QueryWrapper` lets you build type-safe WHERE clauses without string concatenation:

```java theme={null}
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "alice")
       .gt("age", 18)
       .orderByAsc("age");
List<User> users = userMapper.selectList(wrapper);
```

### Pagination

Register the pagination interceptor once:

```java theme={null}
@Configuration
public class MybatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor paginationInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(
            new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
```

Then call `selectPage`:

```java theme={null}
@GetMapping("/users/page")
public IPage<User> page(int pageNum, int pageSize) {
    Page<User> config = new Page<>(pageNum, pageSize);
    return userMapper.selectPage(config, null);
}
```

### Dynamic SQL with XML mappers

For complex queries, pair an XML mapper with the Java interface. Place the XML file in the same package as the mapper with the same name:

```xml theme={null}
<!-- com/example/mapper/UserMapper.xml -->
<mapper namespace="com.example.mapper.UserMapper">
    <select id="searchList" resultType="com.example.entity.User">
        SELECT * FROM user
        <where>
            <if test="name != null">
                name LIKE CONCAT('%', #{name}, '%')
            </if>
            <if test="minAge != 0 and maxAge != 0">
                AND age BETWEEN #{minAge} AND #{maxAge}
            </if>
        </where>
        ORDER BY age DESC
    </select>
</mapper>
```

```java theme={null}
public List<User> searchList(@Param("name") String name,
                              @Param("minAge") int minAge,
                              @Param("maxAge") int maxAge);
```
