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 listBeans() { String[] beanNames = applicationContext.getBeanDefinitionNames(); Map 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 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 injectionTypes() { return Map.of( "构造器注入", "推荐!明确依赖,不可变,易于测试", "Setter注入", "可选依赖,灵活性高", "字段注入", "不推荐!隐藏依赖,难以测试", "本控制器使用", "构造器注入 (RequiredArgsConstructor) + 字段注入演示" ); } /** * 演示 Bean 作用域 */ @GetMapping("/scopes") public Map scopes() { return Map.of( "singleton", "单例 - 整个应用只有一个实例(默认)", "prototype", "原型 - 每次请求都创建新实例", "request", "请求 - 每个 HTTP 请求一个实例", "session", "会话 - 每个 HTTP 会话一个实例", "demo", learningBean.getInstanceInfo() ); } /** * 性能统计 */ @GetMapping("/performance") public Map getPerformance() { var stats = performanceAspect.getStats(); Map 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 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); } } }