手写Spring IoC:注解+反射打造轻量级容器
深入理解Spring IoC核心原理,通过注解和反射机制手写一个简易版IoC容器,掌握依赖注入的本质。
1. 引言:Spring IoC的魔力
在Spring框架中,IoC(控制反转)和DI(依赖注入)是最核心的概念。只需一个@Autowired注解,Spring就能自动帮我们注入依赖对象,这背后的原理是什么?
本文将通过注解+反射的方式,手写一个简易版Spring IoC容器,让你深入理解:
- 注解是如何被扫描和解析的
- Bean是如何被创建和管理的
- 依赖注入是如何实现的
- Spring容器的运行机制

1.1 为什么要手写IoC?
- 理解原理 - 知其然更知其所以然
- 面试必备 - Spring IoC是面试高频考点
- 提升能力 - 掌握反射、注解等核心技术
- 框架选型 - 理解框架设计思想
2. 核心概念:IoC、DI、注解、反射
2.1 控制反转(IoC)
传统方式:对象自己创建依赖
java
public class UserService {
private UserDao userDao = new UserDaoImpl(); // 主动创建
}
IoC方式:对象由容器创建和注入
java
public class UserService {
@Autowired
private UserDao userDao; // 被动接收
}
控制反转就是把对象创建和依赖管理的控制权,从应用代码转移到IoC容器。
2.2 依赖注入(DI)
依赖注入是IoC的实现方式,有三种注入方式:
① 构造器注入
java
@Component
public class UserService {
private final UserDao userDao;
@Autowired
public UserService(UserDao userDao) {
this.userDao = userDao;
}
}
② Setter注入
java
@Component
public class UserService {
private UserDao userDao;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
③ 字段注入(最常用)
java
@Component
public class UserService {
@Autowired
private UserDao userDao;
}
2.3 Java注解
注解是Java 5引入的元数据标记机制。
java
// 定义注解
@Retention(RetentionPolicy.RUNTIME) // 运行时保留
@Target(ElementType.TYPE) // 作用于类
public @interface Component {
String value() default "";
}
// 使用注解
@Component("userService")
public class UserService {
}
2.4 Java反射
反射允许程序在运行时动态获取类信息并操作对象。
java
// 加载类
Class<?> clazz = Class.forName("com.example.UserService");
// 检查注解
if (clazz.isAnnotationPresent(Component.class)) {
Component component = clazz.getAnnotation(Component.class);
String beanName = component.value();
}
// 创建实例
Object instance = clazz.getDeclaredConstructor().newInstance();
// 获取字段
Field[] fields = clazz.getDeclaredFields();
// 设置字段值
field.setAccessible(true);
field.set(instance, value);
3. 第一步:定义核心注解

首先定义我们自己的注解,模拟Spring的核心注解。
3.1 @Component注解
java
package com.myspring.annotation;
import java.lang.annotation.*;
/**
* 标记组件类,类似Spring的@Component
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
/**
* Bean名称,默认为类名首字母小写
*/
String value() default "";
}
3.2 @Autowired注解
java
package com.myspring.annotation;
import java.lang.annotation.*;
/**
* 自动注入依赖,类似Spring的@Autowired
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
public @interface Autowired {
/**
* 是否必须注入
*/
boolean required() default true;
}
3.3 @Qualifier注解
java
package com.myspring.annotation;
import java.lang.annotation.*;
/**
* 指定要注入的Bean名称
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
public @interface Qualifier {
String value();
}
3.4 @Scope注解
java
package com.myspring.annotation;
import java.lang.annotation.*;
/**
* 指定Bean的作用域
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
String value() default "singleton";
}
4. 第二步:实现包扫描器

包扫描器负责扫描指定包下的所有类,找出带有@Component注解的类。
4.1 ClassScanner类
java
package com.myspring.core;
import com.myspring.annotation.Component;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* 类扫描器:扫描指定包下的所有类
*/
public class ClassScanner {
/**
* 扫描指定包下带有@Component注解的类
*
* @param basePackage 基础包路径,如"com.example"
* @return 带有@Component注解的Class列表
*/
public static List<Class<?>> scanComponents(String basePackage) {
List<Class<?>> classList = new ArrayList<>();
try {
// 将包名转换为路径
String packagePath = basePackage.replace('.', '/');
// 获取包的URL路径
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL resource = classLoader.getResource(packagePath);
if (resource == null) {
System.out.println("包路径不存在: " + basePackage);
return classList;
}
// 获取包的文件路径
File packageDir = new File(resource.getFile());
// 递归扫描所有类文件
scanClasses(packageDir, basePackage, classList);
} catch (Exception e) {
e.printStackTrace();
}
return classList;
}
/**
* 递归扫描目录下的所有类文件
*/
private static void scanClasses(File dir, String packageName, List<Class<?>> classList) {
if (!dir.exists() || !dir.isDirectory()) {
return;
}
File[] files = dir.listFiles();
if (files == null) {
return;
}
for (File file : files) {
if (file.isDirectory()) {
// 递归扫描子目录
scanClasses(file, packageName + "." + file.getName(), classList);
} else if (file.getName().endsWith(".class")) {
try {
// 获取类名
String className = packageName + "." +
file.getName().replace(".class", "");
// 加载类
Class<?> clazz = Class.forName(className);
// 检查是否有@Component注解
if (clazz.isAnnotationPresent(Component.class)) {
classList.add(clazz);
System.out.println("扫描到组件: " + className);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
5. 第三步:创建Bean工厂
Bean工厂负责存储和管理所有的Bean实例。
5.1 BeanDefinition类
java
package com.myspring.core;
/**
* Bean定义信息
*/
public class BeanDefinition {
private String beanName;
private Class<?> beanClass;
private String scope;
private Object singletonInstance;
public BeanDefinition(String beanName, Class<?> beanClass, String scope) {
this.beanName = beanName;
this.beanClass = beanClass;
this.scope = scope;
}
// Getter和Setter方法
public String getBeanName() { return beanName; }
public Class<?> getBeanClass() { return beanClass; }
public String getScope() { return scope; }
public Object getSingletonInstance() { return singletonInstance; }
public void setSingletonInstance(Object instance) {
this.singletonInstance = instance;
}
}
5.2 BeanFactory类
java
package com.myspring.core;
import com.myspring.annotation.Component;
import com.myspring.annotation.Scope;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Bean工厂:创建和管理Bean实例
*/
public class BeanFactory {
// 存储Bean定义信息
private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
/**
* 注册Bean定义
*/
public void registerBeanDefinition(Class<?> clazz) {
// 获取Bean名称
Component component = clazz.getAnnotation(Component.class);
String beanName = component.value();
if (beanName.isEmpty()) {
// 默认使用类名首字母小写
beanName = toLowerFirstCase(clazz.getSimpleName());
}
// 获取作用域
String scope = "singleton";
if (clazz.isAnnotationPresent(Scope.class)) {
Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
scope = scopeAnnotation.value();
}
// 创建BeanDefinition并注册
BeanDefinition beanDefinition = new BeanDefinition(beanName, clazz, scope);
beanDefinitionMap.put(beanName, beanDefinition);
System.out.println("注册Bean: " + beanName + ", 作用域: " + scope);
}
/**
* 获取Bean实例
*/
public Object getBean(String beanName) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) {
throw new RuntimeException("Bean不存在: " + beanName);
}
// 单例模式
if ("singleton".equals(beanDefinition.getScope())) {
Object instance = beanDefinition.getSingletonInstance();
if (instance == null) {
instance = createBean(beanDefinition);
beanDefinition.setSingletonInstance(instance);
}
return instance;
}
// 原型模式:每次都创建新实例
return createBean(beanDefinition);
}
/**
* 根据类型获取Bean
*/
public Object getBean(Class<?> clazz) {
for (BeanDefinition bd : beanDefinitionMap.values()) {
if (clazz.isAssignableFrom(bd.getBeanClass())) {
return getBean(bd.getBeanName());
}
}
throw new RuntimeException("Bean不存在: " + clazz.getName());
}
/**
* 创建Bean实例
*/
private Object createBean(BeanDefinition beanDefinition) {
try {
Class<?> clazz = beanDefinition.getBeanClass();
Object instance = clazz.getDeclaredConstructor().newInstance();
System.out.println("创建Bean实例: " + beanDefinition.getBeanName());
return instance;
} catch (Exception e) {
throw new RuntimeException("创建Bean失败: " +
beanDefinition.getBeanName(), e);
}
}
/**
* 首字母小写
*/
private String toLowerFirstCase(String str) {
char[] chars = str.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
/**
* 获取所有Bean名称
*/
public Map<String, BeanDefinition> getBeanDefinitions() {
return beanDefinitionMap;
}
}
6. 第四步:实现依赖注入

依赖注入是IoC容器的核心功能,通过反射自动为Bean注入依赖。
6.1 DependencyInjector类
java
package com.myspring.core;
import com.myspring.annotation.Autowired;
import com.myspring.annotation.Qualifier;
import java.lang.reflect.Field;
/**
* 依赖注入器:为Bean注入依赖
*/
public class DependencyInjector {
private BeanFactory beanFactory;
public DependencyInjector(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
/**
* 为所有Bean执行依赖注入
*/
public void injectDependencies() {
for (BeanDefinition bd : beanFactory.getBeanDefinitions().values()) {
Object bean = beanFactory.getBean(bd.getBeanName());
injectBean(bean);
}
}
/**
* 为单个Bean注入依赖
*/
public void injectBean(Object bean) {
Class<?> clazz = bean.getClass();
// 获取所有字段
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 检查是否有@Autowired注解
if (!field.isAnnotationPresent(Autowired.class)) {
continue;
}
Autowired autowired = field.getAnnotation(Autowired.class);
try {
// 确定要注入的Bean
Object dependency = null;
// 检查是否有@Qualifier指定Bean名称
if (field.isAnnotationPresent(Qualifier.class)) {
Qualifier qualifier = field.getAnnotation(Qualifier.class);
String beanName = qualifier.value();
dependency = beanFactory.getBean(beanName);
} else {
// 根据类型查找Bean
dependency = beanFactory.getBean(field.getType());
}
// 反射设置字段值
field.setAccessible(true);
field.set(bean, dependency);
System.out.println("注入依赖: " + clazz.getSimpleName() +
"." + field.getName());
} catch (Exception e) {
if (autowired.required()) {
throw new RuntimeException("依赖注入失败: " +
clazz.getSimpleName() + "." + field.getName(), e);
}
}
}
}
}
7. 第五步:完善生命周期

7.1 生命周期注解
java
package com.myspring.annotation;
import java.lang.annotation.*;
/**
* Bean初始化后调用
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PostConstruct {
}
java
package com.myspring.annotation;
import java.lang.annotation.*;
/**
* Bean销毁前调用
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PreDestroy {
}
7.2 生命周期管理器
java
package com.myspring.core;
import com.myspring.annotation.PostConstruct;
import com.myspring.annotation.PreDestroy;
import java.lang.reflect.Method;
/**
* Bean生命周期管理器
*/
public class LifecycleManager {
/**
* 执行初始化方法
*/
public static void invokeInitMethod(Object bean) {
Class<?> clazz = bean.getClass();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(PostConstruct.class)) {
try {
method.setAccessible(true);
method.invoke(bean);
System.out.println("执行初始化方法: " +
clazz.getSimpleName() + "." + method.getName());
} catch (Exception e) {
throw new RuntimeException("初始化方法执行失败", e);
}
}
}
}
/**
* 执行销毁方法
*/
public static void invokeDestroyMethod(Object bean) {
Class<?> clazz = bean.getClass();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(PreDestroy.class)) {
try {
method.setAccessible(true);
method.invoke(bean);
System.out.println("执行销毁方法: " +
clazz.getSimpleName() + "." + method.getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
8. 完整示例:使用手写IoC

8.1 创建ApplicationContext
java
package com.myspring.core;
import java.util.List;
/**
* 应用上下文:整合所有功能
*/
public class ApplicationContext {
private BeanFactory beanFactory;
private DependencyInjector injector;
public ApplicationContext(String basePackage) {
// 1. 创建Bean工厂
beanFactory = new BeanFactory();
// 2. 扫描组件
System.out.println("========== 开始扫描组件 ==========");
List<Class<?>> componentClasses = ClassScanner.scanComponents(basePackage);
// 3. 注册Bean定义
System.out.println("\n========== 注册Bean定义 ==========");
for (Class<?> clazz : componentClasses) {
beanFactory.registerBeanDefinition(clazz);
}
// 4. 实例化所有单例Bean
System.out.println("\n========== 实例化单例Bean ==========");
for (BeanDefinition bd : beanFactory.getBeanDefinitions().values()) {
if ("singleton".equals(bd.getScope())) {
beanFactory.getBean(bd.getBeanName());
}
}
// 5. 依赖注入
System.out.println("\n========== 执行依赖注入 ==========");
injector = new DependencyInjector(beanFactory);
injector.injectDependencies();
// 6. 执行初始化方法
System.out.println("\n========== 执行初始化方法 ==========");
for (BeanDefinition bd : beanFactory.getBeanDefinitions().values()) {
Object bean = beanFactory.getBean(bd.getBeanName());
LifecycleManager.invokeInitMethod(bean);
}
System.out.println("\n========== IoC容器启动完成 ==========\n");
}
/**
* 获取Bean
*/
public Object getBean(String beanName) {
return beanFactory.getBean(beanName);
}
/**
* 根据类型获取Bean
*/
public <T> T getBean(Class<T> clazz) {
return (T) beanFactory.getBean(clazz);
}
/**
* 关闭容器
*/
public void close() {
System.out.println("\n========== 关闭IoC容器 ==========");
for (BeanDefinition bd : beanFactory.getBeanDefinitions().values()) {
Object bean = beanFactory.getBean(bd.getBeanName());
LifecycleManager.invokeDestroyMethod(bean);
}
}
}
8.2 编写测试类
java
package com.example.dao;
import com.myspring.annotation.Component;
@Component
public class UserDao {
public void save() {
System.out.println("UserDao: 保存用户数据");
}
}
java
package com.example.service;
import com.example.dao.UserDao;
import com.myspring.annotation.Autowired;
import com.myspring.annotation.Component;
import com.myspring.annotation.PostConstruct;
import com.myspring.annotation.PreDestroy;
@Component
public class UserService {
@Autowired
private UserDao userDao;
public void register(String username) {
System.out.println("UserService: 注册用户 " + username);
userDao.save();
}
@PostConstruct
public void init() {
System.out.println("UserService初始化完成");
}
@PreDestroy
public void destroy() {
System.out.println("UserService准备销毁");
}
}
java
package com.example;
import com.example.service.UserService;
import com.myspring.core.ApplicationContext;
/**
* 测试类
*/
public class Main {
public static void main(String[] args) {
// 创建IoC容器
ApplicationContext context = new ApplicationContext("com.example");
// 获取Bean并使用
UserService userService = context.getBean(UserService.class);
userService.register("张三");
// 关闭容器
context.close();
}
}
8.3 运行输出
makefile
========== 开始扫描组件 ==========
扫描到组件: com.example.dao.UserDao
扫描到组件: com.example.service.UserService
========== 注册Bean定义 ==========
注册Bean: userDao, 作用域: singleton
注册Bean: userService, 作用域: singleton
========== 实例化单例Bean ==========
创建Bean实例: userDao
创建Bean实例: userService
========== 执行依赖注入 ==========
注入依赖: UserService.userDao
========== 执行初始化方法 ==========
执行初始化方法: UserService.init
UserService初始化完成
========== IoC容器启动完成 ==========
UserService: 注册用户 张三
UserDao: 保存用户数据
========== 关闭IoC容器 ==========
执行销毁方法: UserService.destroy
UserService准备销毁
9. 总结
9.1 核心要点
通过手写IoC容器,我们深入理解了:
- 注解机制 - 使用
@Retention、@Target定义注解 - 反射技术 - 类加载、实例创建、字段注入
- 扫描解析 - 递归扫描包路径,解析注解信息
- Bean管理 - 单例/原型模式,Bean定义存储
- 依赖注入 - 自动查找和注入依赖对象
- 生命周期 - 初始化和销毁回调方法
9.2 与Spring IoC的对比
| 功能 | 手写版本 | Spring IoC |
|---|---|---|
| 注解扫描 | 简单递归 | 高性能ASM字节码扫描 |
| Bean管理 | Map存储 | 多级缓存+循环依赖处理 |
| 依赖注入 | 字段注入 | 字段+构造器+Setter |
| 作用域 | singleton/prototype | 更多作用域 |
| AOP支持 | 无 | 完整AOP框架 |
| 性能优化 | 基础 | 大量优化策略 |