package com.learn.ioc; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; /** * 第 1 天:手写简易 IoC 容器 —— 理解控制反转的本质 * * 核心概念: * IoC(Inversion of Control):把"创建对象"的控制权从程序员手里 * 交给容器。以前是 new 一个对象,现在是容器帮我们创建并注入。 * * DI(Dependency Injection):依赖注入,IoC 最常见的实现方式。 * 当 A 类需要 B 类时,不需要 A 自己 new B,而是由容器把 B 注入到 A 中。 * * 这个类是一个极简 IoC 容器实现,只依赖 JDK,用于理解 Spring 的核心思想。 * * 运行方式:IDEA 中右键此类 → Run 'SimpleIocDemo.main()' */ public class SimpleIocDemo { // ==================== 1. 定义两个简单的"业务类" ==================== /** 模拟一个"数据访问层"组件 */ static class UserRepository { public String findUser() { return "张三(来自数据库)"; } } /** 模拟一个"业务逻辑层"组件 —— 它依赖 UserRepository */ static class UserService { // UserService 需要 UserRepository,但自己不 new private UserRepository userRepository; // 通过 setter 方法接收依赖(这就是"注入") public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } public String getUserInfo() { return userRepository.findUser(); } } // ==================== 2. 极简 IoC 容器 ==================== /** * 一个玩具级 IoC 容器,实现两个能力: * 1. 注册 Bean(把对象放进容器) * 2. 注入依赖(帮对象建立关联关系) */ static class SimpleContainer { // 存储所有 Bean:名字 → 对象 private final Map beans = new HashMap<>(); /** 注册一个 Bean */ public void register(String name, Object bean) { beans.put(name, bean); } /** 获取一个 Bean */ public Object getBean(String name) { return beans.get(name); } /** * 自动注入:扫描每个 Bean 中带 @Autowired 注解的字段,自动赋值 * (这里用我们自定义的注解来模拟 Spring 的 @Autowired) */ public void autowire() { for (Object bean : beans.values()) { for (Field field : bean.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(MyAutowired.class)) { field.setAccessible(true); try { // 根据字段类型找到匹配的 Bean Object dependency = findBeanByType(field.getType()); if (dependency != null) { field.set(bean, dependency); } } catch (IllegalAccessException e) { throw new RuntimeException(e); } } } } } private Object findBeanByType(Class type) { for (Object bean : beans.values()) { if (type.isAssignableFrom(bean.getClass())) { return bean; } } return null; } } // ==================== 3. 自定义注解(模拟 Spring 的 @Autowired) ==================== @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @interface MyAutowired { } // ==================== 4. 使用注解版本测试自动注入 ==================== static class OrderRepository { public String getOrder() { return "订单 #12345"; } } static class OrderService { @MyAutowired // 告诉容器:帮我把 OrderRepository 注入进来 private OrderRepository orderRepository; public String getOrderInfo() { return orderRepository.getOrder(); } } // ==================== 5. 主方法——跑起来看效果 ==================== public static void main(String[] args) { System.out.println("========== IoC 容器原理演示 ==========\n"); // --- 方式一:手动注入(模拟 XML 配置时代的做法) --- System.out.println("--- 方式一:手动 setter 注入 ---"); SimpleContainer container1 = new SimpleContainer(); UserRepository userRepo = new UserRepository(); UserService userService = new UserService(); container1.register("userRepository", userRepo); container1.register("userService", userService); // 手动注入依赖 userService.setUserRepository(userRepo); UserService service1 = (UserService) container1.getBean("userService"); System.out.println("调用结果: " + service1.getUserInfo()); // --- 方式二:自动注入(模拟注解时代的做法) --- System.out.println("\n--- 方式二:注解自动注入 ---"); SimpleContainer container2 = new SimpleContainer(); container2.register("orderRepository", new OrderRepository()); container2.register("orderService", new OrderService()); // 一行代码,自动完成所有依赖注入 container2.autowire(); OrderService service2 = (OrderService) container2.getBean("orderService"); System.out.println("调用结果: " + service2.getOrderInfo()); // --- 对比总结 --- System.out.println("\n========== 总结 =========="); System.out.println("没有 IoC 容器时:A a = new A(); a.setB(new B()); // 自己控制一切"); System.out.println("有了 IoC 容器后:@Autowired B b; // 容器自动注入,你只管用"); System.out.println("\n这就是 Spring 的核心理念——控制反转!"); } }