Files
gc-plan/week2/src/main/java/com/learn/ioc/SimpleIocDemo.java
2026-04-29 23:45:17 +08:00

165 lines
6.0 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.learn.ioc;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
/**
* 第 1 天:手写简易 IoC 容器 —— 理解控制反转的本质
*
* 核心概念:
* IoCInversion of Control把"创建对象"的控制权从程序员手里
* 交给容器。以前是 new 一个对象,现在是容器帮我们创建并注入。
*
* DIDependency 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<String, Object> 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 的核心理念——控制反转!");
}
}