- 新增 IoC 容器学习模块 - 新增 AOP 切面编程学习模块 - 新增 MyBatis 集成学习模块 - 新增事务管理学习模块 - 新增用户/产品/订单 CRUD - 新增 7 个交互式学习页面 - 集成性能监控切面
164 lines
5.5 KiB
Java
164 lines
5.5 KiB
Java
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);
|
|
}
|
|
}
|
|
} |