手写代码模拟 Spring 底层原理
Spring 框架核心的 IOC(控制反转)和 AOP(面向切面编程)机制让开发者摆脱了繁琐的对象管理和重复的横切逻辑编写。本文将通过手写极简版 Spring 框架,用最浅显的代码拆解 IOC 容器的初始化流程和 AOP 动态代理的生成原理,让你彻底搞懂 Spring 底层核心逻辑。
一、核心需求与整体设计
我们要实现的核心功能:
IOC 容器:扫描指定包下的组件、解析注解、创建 Bean 实例、管理 Bean 的生命周期(依赖注入、Aware 接口回调);
AOP 代理:基于 CGLIB 实现事务切面(模拟 Spring 的 @Transactional 注解)。
先看整体架构,核心类只有这些:
注解类:@Component、@Autowired、@Transactional 等(模拟 Spring 注解);
核心接口:BeanNameAware、ApplicationContextAware(感知 Bean 名称和容器);
容器核心:HzApplicationContext(模拟 Spring 的 ApplicationContext);
辅助类:BeanDefinition(存储 Bean 的元信息)。
二、第一步:定义核心注解(模拟 Spring 注解)
首先复刻 Spring 的核心注解,这些注解是 IOC 和 AOP 的 “开关”:
1. 组件扫描与 Bean 定义注解
// 组件注解:标记需要被IOC容器管理的类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value() default ""; // 自定义Bean名称
}
// 组件扫描注解:指定IOC容器要扫描的包路径
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
String value(); // 扫描包路径
}
// 作用域注解:单例/原型
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
String value() default "singleton";
}
// 自动注入注解:依赖注入
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
boolean required() default true;
}
// 事务注解:AOP切面标记
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {
}
2. Aware 接口(感知容器 / Bean 信息)
模拟 Spring 的 Aware 接口,让 Bean 能感知自身的 Bean 名称、所属容器等信息:
// 感知Bean名称
public interface BeanNameAware {
void setBeanName(String name);
}
// 感知应用上下文
public interface ApplicationContextAware {
void setApplicationContext(HzApplicationContext applicationContext);
}
3. BeanDefinition(Bean 元信息存储)
Spring 会为每个 Bean 创建一个 “定义对象”,存储 Bean 的类型、作用域、是否懒加载等信息:
public class BeanDefinition {
private Class type; // Bean的类型
private String scope; // 作用域:singleton/prototype
private boolean isLazy; // 是否懒加载
// 省略get/set方法
}
三、第二步:实现 IOC 容器核心(HzApplicationContext)
IOC 容器是 Spring 的 “心脏”,核心流程分为 3 步:扫描包→解析 Bean 定义→创建 Bean 实例。
1. 容器初始化核心逻辑
public class HzApplicationContext {
private Class configClass; // 配置类(如AppConfig)
private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(); // Bean定义缓存
private Map<String, Object> singletonObjects = new HashMap<>(); // 单例Bean缓存
// 构造方法:初始化容器
public HzApplicationContext(Class configClass) {
this.configClass = configClass;
// 第一步:扫描指定包下的所有组件
scan(configClass);
// 第二步:初始化非懒加载的单例Bean
for (String beanName : beanDefinitionMap.keySet()) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
// 单例+非懒加载:立即创建Bean
if (beanDefinition.getScope().equals("singleton") && !beanDefinition.isLazy()) {
Object bean = createBean(beanName, beanDefinition);
singletonObjects.put(beanName, bean);
}
}
}
}2. 第一步:扫描包(解析 @ComponentScan 注解)
扫描指定包下的所有.class 文件,解析 @Component 注解,生成 BeanDefinition:
private void scan(Class configClass) {
// 1. 解析@ComponentScan注解,获取扫描路径
if (configClass.isAnnotationPresent(ComponentScan.class)) {
ComponentScan annotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
String scanPath = annotation.value(); // 如:com.vvhz.user
// 2. 包路径转文件路径(com.vvhz.user → com/vvhz/user)
scanPath = scanPath.replace(".", "/");
// 3. 类加载器加载资源
ClassLoader classLoader = this.getClass().getClassLoader();
URL resource = classLoader.getResource(scanPath);
File scanDir = new File(resource.getFile());
// 4. 遍历目录下的所有.class文件
List<File> classFiles = new ArrayList<>();
if (scanDir.isDirectory()) {
collectClassFiles(scanDir, classFiles); // 递归收集所有.class文件
}
// 5. 解析每个.class文件,生成BeanDefinition
for (File classFile : classFiles) {
// 文件路径转类名(如:com\vvhz\user\service\UserService → com.vvhz.user.service.UserService)
String absolutePath = classFile.getAbsolutePath();
String className = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"))
.replace("\\", ".");
try {
Class<?> clazz = classLoader.loadClass(className);
// 只有标记@Component的类才会被管理
if (clazz.isAnnotationPresent(Component.class)) {
// 生成BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType(clazz);
beanDefinition.setLazy(clazz.isAnnotationPresent(Lazy.class));
// 解析@Scope注解(默认单例)
if (clazz.isAnnotationPresent(Scope.class)) {
beanDefinition.setScope(clazz.getAnnotation(Scope.class).value());
} else {
beanDefinition.setScope("singleton");
}
// 生成Bean名称(自定义名称优先,否则类名首字母小写)
String beanName = clazz.getAnnotation(Component.class).value();
if (beanName.isEmpty()) {
beanName = Introspector.decapitalize(clazz.getSimpleName());
}
// 存入BeanDefinitionMap
beanDefinitionMap.put(beanName, beanDefinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
// 递归收集所有.class文件
private void collectClassFiles(File dir, List<File> classFiles) {
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
collectClassFiles(file, classFiles);
} else {
if (file.getName().endsWith(".class")) {
classFiles.add(file);
}
}
}
}
3. 第二步:创建 Bean 实例(核心!依赖注入 + Aware 回调 + AOP 代理)
createBean方法是 IOC 容器的核心,完成:实例化→依赖注入→Aware 接口回调→AOP 代理生成。
private Object createBean(String beanName, BeanDefinition beanDefinition) {
Class clazz = beanDefinition.getType();
try {
// 1. 实例化Bean(无参构造)
Object beanInstance = clazz.newInstance();
// 2. 依赖注入(解析@Autowired注解)
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
// 递归获取依赖的Bean(如UserService依赖OrderService)
Object dependentBean = getBean(field.getName());
field.setAccessible(true); // 突破private访问限制
field.set(beanInstance, dependentBean); // 注入
}
}
// 3. Aware接口回调(让Bean感知容器/自身名称)
if (beanInstance instanceof BeanNameAware) {
((BeanNameAware) beanInstance).setBeanName(beanName);
}
if (beanInstance instanceof ApplicationContextAware) {
((ApplicationContextAware) beanInstance).setApplicationContext(this);
}
// 4. AOP代理(基于CGLIB生成事务代理)
if (clazz.isAnnotationPresent(Transactional.class)) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz); // 设置父类(CGLIB基于继承)
Object target = beanInstance; // 原始Bean实例
// 方法拦截器(模拟事务逻辑)
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 前置增强:开启事务
System.out.println("开启数据库事务");
// 执行原始方法
Object result = method.invoke(target, args);
// 后置增强:提交事务
System.out.println("提交数据库事务");
return result;
}
});
// 生成代理对象(替换原始Bean)
beanInstance = enhancer.create();
}
return beanInstance;
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}4. 第三步:获取 Bean(getBean 方法)
对外提供获取 Bean 的接口,区分单例 / 原型 Bean:
public Object getBean(String beanName) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition == null) {
throw new NullPointerException("Bean不存在:" + beanName);
}
// 单例Bean:从缓存获取,缓存没有则创建
if ("singleton".equals(beanDefinition.getScope())) {
Object singletonBean = singletonObjects.get(beanName);
if (singletonBean == null) {
singletonBean = createBean(beanName, beanDefinition);
singletonObjects.put(beanName, singletonBean);
}
return singletonBean;
} else {
// 原型Bean:每次获取都创建新实例
return createBean(beanName, beanDefinition);
}
}
四、第三步:测试 IOC 容器与 AOP 代理
1. 编写业务类(模拟实际开发)
// 订单服务(被依赖)
@Component
public class OrderService {
}
// 用户服务(依赖OrderService,开启事务)
@Component
@Transactional
public class UserService implements BeanNameAware, ApplicationContextAware {
@Autowired
private OrderService orderService;
private HzApplicationContext applicationContext;
private String beanName;
public void test() {
System.out.println("OrderService实例:" + orderService);
System.out.println("容器实例:" + applicationContext);
System.out.println("Bean名称:" + beanName);
}
// 实现Aware接口的回调方法
@Override
public void setApplicationContext(HzApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
}
2. 编写配置类
@ComponentScan("com.vvhz.user") // 指定扫描包
public class AppConfig {
}
3. 启动容器测试
public class MyApplication {
public static void main(String[] args) {
// 初始化容器
HzApplicationContext context = new HzApplicationContext(AppConfig.class);
// 获取Bean
UserService userService = (UserService) context.getBean("userService");
// 调用方法(触发事务代理)
userService.test();
}
}4. 运行结果
开启数据库事务
OrderService实例:com.vvhz.user.service.OrderService@6d03e736
容器实例:com.vvhz.springframework.HzApplicationContext@568db2f2
Bean名称:userService
提交数据库事务从结果能看到:
IOC 容器完成了 OrderService 的自动注入;
BeanNameAware 和 ApplicationContextAware 回调成功;
@Transactional 触发了 AOP 代理,方法执行前后自动开启 / 提交事务。
四、核心原理总结
1. IOC 容器核心流程
扫描:解析 @ComponentScan 注解,递归扫描指定包下的 @Component 类,生成 BeanDefinition;
初始化:非懒加载的单例 Bean 在容器启动时创建,原型 Bean 在 getBean 时创建;
依赖注入:通过反射解析 @Autowired 注解,递归获取依赖 Bean 并注入;
生命周期回调:执行 Aware 接口的回调方法,让 Bean 感知容器 / 自身信息;
缓存管理:单例 Bean 存入 singletonObjects,原型 Bean 每次创建新实例。
2. AOP 代理核心原理(CGLIB)
识别 @Transactional 注解的类;
通过 CGLIB 的 Enhancer 创建代理类(继承原始类);
重写原始方法,在方法执行前后插入横切逻辑(事务);
代理对象替换原始 Bean 实例,对外提供服务。
五、与真实 Spring 的对比
本文的极简版 Spring 省略了很多细节(如循环依赖解决、BeanPostProcessor、注解属性解析、多切面排序等),但核心逻辑和真实 Spring 一致:
Spring 的 ApplicationContext 底层也是通过扫描→解析→创建 Bean 的流程;
Spring 的 AOP 默认使用 JDK 动态代理(接口)+ CGLIB(类),本文简化为仅 CGLIB;
Spring 的依赖注入支持构造器、setter、字段注入,本文仅实现字段注入。
六、总结
通过手写极简版 Spring,我们能清晰看到:
IOC 的本质:将对象的创建、依赖管理交给容器,开发者只需关注业务逻辑;
AOP 的本质:通过动态代理在不修改原始代码的情况下,为方法添加横切逻辑。
Spring 的源码虽然复杂,但核心原理并不难 —— 无非是 “注解解析 + 反射 + 设计模式(工厂、代理)” 的组合。掌握了这些核心逻辑,后续我们再去看 Spring 源码就会豁然开朗。
完整代码已放在示例中,也可以直接拉取gitee仓库的代码,可以直接运行,也可以尝试扩展(如添加 BeanPostProcessor、循环依赖解决、多切面支持等),进一步加深对 Spring 的理解。