1. 为什么要手写Spring容器很多Java开发者每天都在用Spring框架但可能很少有人真正思考过Spring容器到底是怎么工作的为什么我们只需要加个Service注解就能让一个类自动被管理依赖注入又是如何实现的记得我刚接触Spring时最大的困惑就是明明没有new对象这些对象是怎么来的后来花时间研究源码才发现原来Spring容器本质上就是个对象工厂关系管理器。它帮我们做了三件事创建对象不再需要手动new管理对象生命周期什么时候创建什么时候销毁维护对象间依赖关系自动把A需要的B注入进去手写一个简易Spring容器不仅能帮你彻底理解IoC控制反转和DI依赖注入的核心思想更重要的是当你再遇到Spring的诡异报错时能快速定位问题根源。我在实际项目中就遇到过因为不理解容器初始化顺序导致的循环依赖问题后来正是通过研究容器原理才找到解决方案。2. 基础准备定义核心组件2.1 自定义Bean注解任何Spring容器的起点都是Bean的定义。我们先创建一个简化版的MyBean注解Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) public interface MyBean { String value() default ; }这个注解和Spring原生的Component功能类似可以标记哪些类需要被容器管理。value()属性用来指定Bean的名称如果不指定默认使用类名首字母小写。2.2 Bean定义封装容器需要知道每个Bean的详细信息我们用一个BeanDefinition类来封装public class BeanDefinition { private Class? beanClass; private String beanName; private ListPropertyValue propertyValues new ArrayList(); // 构造方法、getter/setter省略 }其中PropertyValue用来描述Bean的属性依赖public class PropertyValue { private String name; private Object value; // 构造方法、getter/setter省略 }3. 实现容器核心功能3.1 注解解析器容器启动时首先要扫描所有带MyBean的类。我们写个注解解析器public class AnnotationBeanDefinitionParser { public ListBeanDefinition parse(String basePackage) { ListBeanDefinition definitions new ArrayList(); // 使用反射工具扫描包路径 Reflections reflections new Reflections(basePackage); SetClass? beanClasses reflections.getTypesAnnotatedWith(MyBean.class); for (Class? clazz : beanClasses) { MyBean annotation clazz.getAnnotation(MyBean.class); String beanName annotation.value().isEmpty() ? StringUtils.uncapitalize(clazz.getSimpleName()) : annotation.value(); BeanDefinition definition new BeanDefinition(clazz, beanName); definitions.add(definition); } return definitions; } }这里用到了Reflections库来简化类扫描你也可以自己实现文件遍历。3.2 Bean工厂实现接下来是最关键的BeanFactory它要负责创建和管理Bean实例public class BeanFactory { private MapString, BeanDefinition beanDefinitionMap new HashMap(); private MapString, Object singletonObjects new HashMap(); public void registerBeanDefinitions(ListBeanDefinition definitions) { definitions.forEach(def - beanDefinitionMap.put(def.getBeanName(), def)); } public Object getBean(String beanName) { Object bean singletonObjects.get(beanName); if (bean null) { bean createBean(beanName); singletonObjects.put(beanName, bean); } return bean; } private Object createBean(String beanName) { BeanDefinition definition beanDefinitionMap.get(beanName); try { Object instance definition.getBeanClass().newInstance(); applyPropertyValues(instance, definition.getPropertyValues()); return instance; } catch (Exception e) { throw new RuntimeException(创建Bean失败: beanName, e); } } private void applyPropertyValues(Object bean, ListPropertyValue pvs) { // 实现属性注入 } }这个简易工厂实现了单例管理singletonObjects和懒加载第一次getBean时才创建。4. 依赖注入的实现4.1 属性注入要让容器自动注入依赖我们需要扩展AnnotationBeanDefinitionParser// 在parse方法中添加 for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(Autowired.class)) { String refName field.getType().getSimpleName(); refName StringUtils.uncapitalize(refName); definition.getPropertyValues().add(new PropertyValue(field.getName(), refName)); } }然后在BeanFactory中实现注入private void applyPropertyValues(Object bean, ListPropertyValue pvs) { for (PropertyValue pv : pvs) { try { Field field bean.getClass().getDeclaredField(pv.getName()); field.setAccessible(true); Object value pv.getValue(); if (value instanceof String) { value getBean((String) value); } field.set(bean, value); } catch (Exception e) { throw new RuntimeException(注入属性失败: pv.getName(), e); } } }4.2 构造器注入更复杂的构造器注入可以通过解析构造器参数实现private Object createBean(String beanName) { BeanDefinition definition beanDefinitionMap.get(beanName); Constructor?[] constructors definition.getBeanClass().getConstructors(); if (constructors.length 1) { Constructor? constructor constructors[0]; Parameter[] parameters constructor.getParameters(); Object[] args new Object[parameters.length]; for (int i 0; i parameters.length; i) { String paramName StringUtils.uncapitalize(parameters[i].getType().getSimpleName()); args[i] getBean(paramName); } return constructor.newInstance(args); } // 其他情况处理... }5. 完整示例演示让我们用个完整例子测试这个容器MyBean public class UserService { Autowired private UserDao userDao; public void saveUser() { userDao.save(); } } MyBean public class UserDao { public void save() { System.out.println(用户数据已保存); } } public class Main { public static void main(String[] args) { // 1. 解析注解 AnnotationBeanDefinitionParser parser new AnnotationBeanDefinitionParser(); ListBeanDefinition definitions parser.parse(com.example); // 2. 注册Bean定义 BeanFactory factory new BeanFactory(); factory.registerBeanDefinitions(definitions); // 3. 获取Bean并使用 UserService userService (UserService) factory.getBean(userService); userService.saveUser(); // 输出: 用户数据已保存 } }6. 功能扩展思路虽然这个简易容器已经实现了核心功能但还有很多可以改进的地方循环依赖检测当A依赖BB又依赖A时目前实现会栈溢出生命周期回调实现类似PostConstruct的初始化方法调用作用域扩展目前只有单例可以增加原型(prototype)作用域AOP支持通过动态代理实现切面编程我在实际项目中遇到过这样一个案例因为不了解容器初始化顺序导致PostConstruct方法中调用其他Bean失败。后来通过给容器添加阶段初始化机制解决了这个问题——让某些Bean优先初始化。