feat: Spring Boot 学习脚手架 v2.0
- 新增 IoC 容器学习模块 - 新增 AOP 切面编程学习模块 - 新增 MyBatis 集成学习模块 - 新增事务管理学习模块 - 新增用户/产品/订单 CRUD - 新增 7 个交互式学习页面 - 集成性能监控切面
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
package com.example.scaffold.learning;
|
||||
|
||||
import com.example.scaffold.aop.PerformanceAspect;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* IoC 容器学习控制器
|
||||
*
|
||||
* 学习要点:
|
||||
* 1. Bean 的生命周期
|
||||
* 2. 依赖注入方式
|
||||
* 3. Bean 作用域
|
||||
* 4. 条件化配置
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/learning/ioc")
|
||||
@RequiredArgsConstructor
|
||||
public class IocLearningController {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
private final PerformanceAspect performanceAspect;
|
||||
|
||||
// 演示字段注入(不推荐,但可以用)
|
||||
@Autowired
|
||||
@Qualifier("learningBean")
|
||||
private LearningBean learningBean;
|
||||
|
||||
/**
|
||||
* 查看所有 Bean
|
||||
*/
|
||||
@GetMapping("/beans")
|
||||
public Map<String, Object> listBeans() {
|
||||
String[] beanNames = applicationContext.getBeanDefinitionNames();
|
||||
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("total", beanNames.length);
|
||||
result.put("userBeans", Arrays.stream(beanNames)
|
||||
.filter(name -> name.startsWith("user") || name.startsWith("learning") ||
|
||||
name.contains("Service") || name.contains("Controller") || name.contains("Mapper"))
|
||||
.sorted()
|
||||
.toList());
|
||||
result.put("allBeans", Arrays.stream(beanNames).sorted().toList());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看 Bean 详情
|
||||
*/
|
||||
@GetMapping("/beans/{name}")
|
||||
public Map<String, Object> getBeanDetail(@PathVariable String name) {
|
||||
try {
|
||||
Object bean = applicationContext.getBean(name);
|
||||
Class<?> clazz = bean.getClass();
|
||||
|
||||
return Map.of(
|
||||
"name", name,
|
||||
"type", clazz.getName(),
|
||||
"simpleName", clazz.getSimpleName(),
|
||||
"interfaces", Arrays.toString(clazz.getInterfaces()),
|
||||
"annotations", Arrays.toString(clazz.getAnnotations()),
|
||||
"scope", applicationContext.isSingleton(name) ? "singleton" : "prototype"
|
||||
);
|
||||
} catch (BeansException e) {
|
||||
return Map.of("error", "Bean not found: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 演示依赖注入方式
|
||||
*/
|
||||
@GetMapping("/injection-types")
|
||||
public Map<String, String> injectionTypes() {
|
||||
return Map.of(
|
||||
"构造器注入", "推荐!明确依赖,不可变,易于测试",
|
||||
"Setter注入", "可选依赖,灵活性高",
|
||||
"字段注入", "不推荐!隐藏依赖,难以测试",
|
||||
"本控制器使用", "构造器注入 (RequiredArgsConstructor) + 字段注入演示"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 演示 Bean 作用域
|
||||
*/
|
||||
@GetMapping("/scopes")
|
||||
public Map<String, Object> scopes() {
|
||||
return Map.of(
|
||||
"singleton", "单例 - 整个应用只有一个实例(默认)",
|
||||
"prototype", "原型 - 每次请求都创建新实例",
|
||||
"request", "请求 - 每个 HTTP 请求一个实例",
|
||||
"session", "会话 - 每个 HTTP 会话一个实例",
|
||||
"demo", learningBean.getInstanceInfo()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 性能统计
|
||||
*/
|
||||
@GetMapping("/performance")
|
||||
public Map<String, Object> getPerformance() {
|
||||
var stats = performanceAspect.getStats();
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
|
||||
stats.forEach((key, value) -> {
|
||||
long totalMs = value.totalTime.get() / 1_000_000;
|
||||
long avgMs = value.totalCount.get() > 0 ? totalMs / value.totalCount.get() : 0;
|
||||
|
||||
result.put(key, Map.of(
|
||||
"count", value.totalCount.get(),
|
||||
"errors", value.errorCount.get(),
|
||||
"totalMs", totalMs,
|
||||
"avgMs", avgMs,
|
||||
"maxMs", value.maxTime.get()
|
||||
));
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置性能统计
|
||||
*/
|
||||
@PostMapping("/performance/reset")
|
||||
public Map<String, String> resetPerformance() {
|
||||
performanceAspect.resetStats();
|
||||
return Map.of("status", "ok", "message", "性能统计已重置");
|
||||
}
|
||||
|
||||
/**
|
||||
* 学习 Bean - 演示作用域和生命周期
|
||||
*/
|
||||
@org.springframework.stereotype.Component("learningBean")
|
||||
@Scope(WebApplicationContext.SCOPE_SESSION)
|
||||
public static class LearningBean {
|
||||
private final String instanceId = UUID.randomUUID().toString().substring(0, 8);
|
||||
private int accessCount = 0;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
System.out.println("🟢 [LearningBean @PostConstruct] Bean 初始化: " + instanceId);
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void destroy() {
|
||||
System.out.println("🔴 [LearningBean @PreDestroy] Bean 销毁: " + instanceId);
|
||||
}
|
||||
|
||||
public String getInstanceInfo() {
|
||||
accessCount++;
|
||||
return String.format("实例ID: %s, 访问次数: %d, 作用域: session", instanceId, accessCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user