手写极简Spring容器,深入理解IoC与AOP
2026/9/2 17:23:48 网站建设 项目流程

正文

一、前言

很多开发只会使用 Spring 框架,但完全搞不懂 IoC 控制反转、AOP 切面底层到底怎么运行。网上讲解源码门槛太高,今天我们从零手写极简版迷你 Spring 容器,只用 JDK 原生技术:自定义注解、反射、动态代理,实现核心功能:组件扫描、单例 Bean 管理、自动依赖注入、方法日志切面增强。

项目完全脱离 Spring 依赖,纯原生 Java 实现,看完就能彻底理解:

  1. Spring 如何通过注解自动创建对象(IoC 容器)
  2. @Autowired 自动注入的底层反射原理
  3. @Component 扫描包的实现逻辑
  4. JDK 动态代理实现 AOP 前置 / 后置通知
  5. 单例 Bean 缓存设计、容器启动完整流程

适合 Java 进阶、面试突击 Spring 底层原理、课程实训作业。

二、项目整体需求与架构

2.1 核心功能需求

  1. 注解驱动 Bean 管理:自定义 @Component 注解标记业务类,容器自动扫描实例化,无需手动 new;
  2. 单例全局缓存:容器启动统一创建单例对象,全局复用;
  3. 自动依赖注入:自定义 @Autowired,通过反射给成员变量赋值,解除硬编码耦合;
  4. AOP 切面增强:自定义 @Aspect 标记切面类,JDK 动态代理对目标方法前后添加日志,不修改原有业务代码;
  5. 容器统一上下文入口,一键启动扫描、创建 Bean、生成代理、获取实例。

2.2 整体包分层结构

com.example.ioc ├── annotation // 自定义注解 │ Component.java │ Autowired.java │ Aspect.java │ Scope.java ├── aop // AOP切面基础 │ BaseAspect.java │ AspectHandler.java ├── context // IoC容器核心 │ BeanDefinition.java │ BeanScanner.java │ BeanFactory.java │ AopProxyFactory.java │ MiniSpringContext.java ├── service // 业务接口&实现 │ UserService.java │ OrderService.java │ impl │ UserServiceImpl.java │ OrderServiceImpl.java └── TestContainer // 启动测试类

2.3 核心技术点梳理

  1. 注解 + 反射:运行时读取类上 @Component、@Autowired 注解,动态创建对象、赋值成员变量;
  2. 单例模式:BeanFactory 使用 ConcurrentHashMap 缓存单例,保证线程安全;
  3. 工厂模式:Bean 工厂负责对象创建,代理工厂统一生成 AOP 代理;
  4. JDK 动态代理:实现 InvocationHandler 拦截方法,完成切面增强;
  5. IO 文件遍历:包扫描器递归读取 class 文件,加载 Class 对象;
  6. 泛型、函数式编程简化容器获取 Bean 逻辑。

三、Maven 项目配置

pom.xml 核心依赖

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"> <modelVersion>4.0.0</modelVersion> <groupId>com.example.ioc</groupId> <artifactId>mini-spring-ioc</artifactId> <version>1.0-SNAPSHOT> <properties> maven.compiler.source>17</maven.compiler.source> maven.compiler.target>17</maven.compiler> encoding>UTF-8 </properties> <dependencies> <!-- Lombok简化实体代码 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.38</version> <scope>provided</scope> </dependency> <!-- 日志依赖 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.9</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.4.11</version> </dependency> <!-- JUnit测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> <scope>test</scope> </dependency> </dependencies> </project>

四、分层完整代码实现

4.1 自定义注解层 annotation

1. @Component 标记容器管理 Bean

package com.example.ioc.annotation; import java.lang.annotation.*; /** * 标记类为IoC容器管理组件 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Component { String value() default ""; }

2. @Autowired 自动注入注解

package com.example.ioc.annotation; import java.lang.annotation.*; /** * 字段自动依赖注入 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Autowired { }

3. @Scope 作用域注解

package com.example.ioc.annotation; import java.lang.annotation.*; /** * Bean作用域,默认singleton单例 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Scope { String value() default "singleton"; }

4. @Aspect 切面注解

package com.example.ioc.annotation; import java.lang.annotation.*; /** * 标记切面类,value指定要代理的目标类全限定名 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Aspect { String value() default ""; }

4.2 AOP 切面基础层 aop

1. 切面基类 BaseAspect

package com.example.ioc.aop; /** * 切面统一父类,定义前后置通知规范 */ public abstract class BaseAspect { // 方法执行前增强 public abstract void before(); // 方法执行后增强 public abstract void after(); }

2. 动态代理拦截器 AspectHandler

package com.example.ioc.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * JDK动态代理调用处理器,拦截目标方法执行切面逻辑 */ public class AspectHandler implements InvocationHandler { // 原始目标对象 private final Object target; // 切面增强类 private final BaseAspect aspect; public AspectHandler(Object target, BaseAspect aspect) { this.target = target; this.aspect = aspect; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 前置通知 aspect.before(); // 执行原始业务方法 Object result = method.invoke(target, args); // 后置通知 aspect.after(); return result; } /** 创建代理对象 */ public Object getProxy() { return java.lang.reflect.Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this ); } }

3. 日志切面实现类

package com.example.ioc.aop; import com.example.ioc.annotation.Aspect; import com.example.ioc.annotation.Component; import lombok.extern.slf4j.Slf4j; /** * 日志切面:拦截UserServiceImpl所有方法,打印前后日志 */ @Slf4j @Component @Aspect(value = "com.example.ioc.service.impl.UserServiceImpl") public class LogAspect extends BaseAspect{ @Override public void before() { log.info("【AOP前置通知】方法即将执行"); } @Override public void after() { log.info("【AOP后置通知】方法执行完成"); } }

4.3 IoC 容器核心层 context

1. BeanDefinition Bean 元数据模型

package com.example.ioc.context; import com.example.ioc.annotation.Scope; import lombok.Getter; import lombok.Setter; /** * Bean定义:存储类名、作用域、Bean标识名称 */ @Getter @Setter public class BeanDefinition { private String beanName; private Class<?> beanClass; private String scope = "singleton"; public BeanDefinition(String beanName, Class<?> beanClass) { this.beanName = beanClass; // 读取Scope注解 if (beanClass.isAnnotationPresent(Scope.class)) { this.scope = beanClass.getAnnotation(Scope.class).value(); } } public boolean isSingleton() { return "singleton".equals(scope); } }

2. 包扫描器 BeanScanner

package com.example.ioc.context; import com.example.ioc.annotation.Component; import java.io.File; import java.net.URL; import java.util.HashMap; import java.util.Map; /** * 包扫描工具:递归遍历包下class文件,识别@Component生成BeanDefinition */ public class BeanScanner { private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(); public void scan(String basePackage) throws Exception { // 包路径转文件路径 String path = basePackage.replace(".", "/"); URL resource = getClass().getClassLoader().getResource(path); if (resource == null) return; File root = new File(resource.toURI()); scanFile(root, basePackage); } // 递归扫描目录 private void scanFile(File file, String pkg) throws ClassNotFoundException { if (file.isDirectory()) { File[] files = file.listFiles(); if (files == null) return; for (File f : files) { if (f.isDirectory()) { scanFile(f, pkg + "." + f.getName()); } else { String className = pkg + "." + f.getName().replace(".class", ""); Class<?> clazz = Class.forName(className); // 标记@Component才注册 if (clazz.isAnnotationPresent(Component.class)) { registerBean(clazz); } } } } } // 注册Bean定义 private void registerBean(Class<?> clazz) { Component comp = clazz.getAnnotation(Component.class); String beanName; if (comp.value().isBlank()) { // 首字母小写作为beanName String simpleName = clazz.getSimpleName(); beanName = Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1); // 去除Impl后缀 if (beanName.endsWith("Impl")) { beanName = beanName.substring(0, beanName.length() - 4); } } else { beanName = comp.value(); } beanDefinitionMap.put(beanName, new BeanDefinition(beanName, clazz)); } public Map<String, BeanDefinition> getBeanDefinitionMap() { return beanDefinitionMap; } }

3. AOP 代理工厂 AopProxyFactory

package com.example.ioc.context; import com.example.ioc.aop.AspectHandler; import com.example.ioc.aop.BaseAspect; import com.example.ioc.annotation.Aspect; /** * AOP代理单例工厂,生成JDK动态代理对象 */ public class AopProxyFactory { private static final AopProxyFactory INSTANCE = new AopProxyFactory(); private AopProxyFactory(){} public static AopProxyFactory getInstance() { return INSTANCE; } public Object createProxy(Class<?> aspectCls) throws Exception { // 实例化切面 BaseAspect aspect = (BaseAspect) aspectCls.getDeclaredConstructor().newInstance(); // 获取切面指定的目标类 Aspect aspectAnno = aspectCls.getAnnotation(Aspect.class); Class<?> targetCls = Class.forName(aspectAnno.value()); Object target = targetCls.getDeclaredConstructor().newInstance(); // 创建代理 AspectHandler handler = new AspectHandler(target, aspect); return handler.getProxy(); } }

4. Bean 工厂 BeanFactory

package com.example.ioc.context; import com.example.ioc.annotation.Autowired; import java.lang.reflect.Field; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Bean工厂:负责实例化、依赖注入、单例缓存、代理替换 */ public class BeanFactory { private static final BeanFactory INSTANCE = new BeanFactory(); // 单例Bean缓存池,线程安全 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(); private Map<String, BeanDefinition> beanDefinitionMap; private BeanFactory(){} public static BeanFactory getInstance() { return INSTANCE; } public void init(Map<String, BeanDefinition> map) { this.beanDefinitionMap = map; } // 初始化所有单例原始Bean public void createSingletonBeans() throws Exception { for (BeanDefinition def : beanDefinitionMap.values()) { if (def.isSingleton() && !singletonObjects.containsKey(def.getBeanName())) { Object bean = def.getBeanClass().getDeclaredConstructor().newInstance(); singletonObjects.put(def.getBeanName(), bean); } } } // 自动依赖注入 public void injectBean() throws Exception { for (BeanDefinition def : beanDefinitionMap.values()) { Class<?> clazz = def.getBeanClass(); Object bean = clazz.getDeclaredConstructor().newInstance(); // 遍历所有字段,处理@Autowired Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Autowired.class)) { field.setAccessible(true); // 根据类型从缓存获取依赖Bean Object depBean = getBeanByType(field.getType()); field.set(bean, depBean); } } singletonObjects.put(def.getBeanName(), bean); } } // 替换切面目标Bean为代理对象 public void replaceAopProxy() throws Exception { AopProxyFactory proxyFactory = AopProxyFactory.getInstance(); for (BeanDefinition def : beanDefinitionMap.values()) { Class<?> clazz = def.getBeanClass(); if (clazz.isAnnotationPresent(com.example.ioc.annotation.Aspect.class)) { Object proxy = proxyFactory.createProxy(clazz); // 覆盖缓存中原对象 modifyBean(clazz, proxy); } } } // 根据类型获取Bean @SuppressWarnings("unchecked") public <T> T getBeanByType(Class<T> clazz) { for (Object bean : singletonObjects.values()) { if (clazz.isAssignableFrom(bean.getClass())) { return (T) bean; } } return null; } // 根据Bean名称获取实例 public Object getBean(String beanName) { return singletonObjects.get(beanName); } // 根据类型替换缓存中的Bean public void modifyBean(Class<?> targetCls, Object proxyBean) { for (Map.Entry<String, Object> entry : singletonObjects.entrySet()) { if (targetCls.isAssignableFrom(entry.getValue().getClass())) { singletonObjects.put(entry.getKey(), proxyBean); } } } public Map<String, Object> getSingletonObjects() { return singletonObjects; } }

5. 容器上下文 MiniSpringContext

package com.example.ioc.context; import lombok.extern.slf4j.Slf4j; /** * IoC容器统一入口,单例全局上下文 */ @Slf4j public class MiniSpringContext { private static MiniSpringContext INSTANCE; private final String basePackage; private final BeanScanner scanner; private final BeanFactory beanFactory; private MiniSpringContext(String basePackage) { this.basePackage = basePackage; this.scanner = new BeanScanner(); this.beanFactory = BeanFactory.getInstance(); refresh(); } // 容器刷新核心流程:扫描->创建Bean->注入依赖->生成AOP代理 private void refresh() { try { log.info("迷你IoC容器开始启动..."); // 1.包扫描 scanner.scan(basePackage); // 2.初始化工厂 beanFactory.init(scanner.getBeanDefinitionMap()); // 3.创建原始单例 beanFactory.createSingletonBeans(); // 4.自动依赖注入 beanFactory.injectBean(); // 5.替换AOP代理对象 beanFactory.replaceAopProxy(); log.info("IoC容器启动完成!"); } catch (Exception e) { log.error("容器启动失败", e); } } // 获取容器单例 public static MiniSpringContext getInstance(String basePackage) { if (INSTANCE == null) { synchronized (MiniSpringContext.class) { if (INSTANCE == null) { INSTANCE = new MiniSpringContext(basePackage); } } } return INSTANCE; } // 根据类型获取Bean public <T> T getBean(Class<T> clazz) { return beanFactory.getBeanByType(clazz); } // 根据Bean名称获取 public Object getBean(String beanName) { return beanFactory.getBean(beanName); } }

4.4 业务层 Service

1. UserService 接口

package com.example.ioc.service; public interface UserService { void sayHello(); }

2. UserServiceImpl 实现类(被 AOP 拦截)

package com.example.ioc.service.impl; import com.example.ioc.annotation.Component; import com.example.ioc.service.User; @Component public class UserServiceImpl implements UserService { @Override public void sayHello() { System.out.println("用户业务方法执行:Hello IoC&AOP"); } }

3. OrderService 接口

package com.example.ioc.service; public interface OrderService { void testOrder(); }

4. OrderServiceImpl(依赖注入 UserService)

package com.example.ioc.service.impl; import com.example.ioc.annotation.Autowired; import com.example.ioc.annotation.Component; import com.example.ioc.service.OrderService; import com.example.ioc.service.UserService; @Component public class OrderServiceImpl implements OrderService { @Autowired private UserService userService; @Override public void testOrder() { System.out.println("订单业务逻辑执行"); userService.sayHello(); } }

4.5 测试启动类

package com.example.ioc; import com.example.ioc.context.MiniSpringContext; import com.example.ioc.service.OrderService; import lombok.extern.slf4j.Slf4j; @Slf4j public class TestContainer { public static void main(String[] args) { // 扫描根包,启动容器 MiniSpringContext context = MiniSpringContext.getInstance("com.example.ioc"); // 根据类型获取Bean Order order1 = context.getBean(OrderService.class); // 根据名称获取Bean Order order2 = (OrderService) context.getBean("orderService"); log.info("order1和order2是否为同一个单例:{}", order1 == order2); log.info("执行业务方法,观察AOP日志"); order1.testOrder(); } }

五、运行结果解析

控制台输出流程:

  1. 容器启动日志,完成包扫描、Bean 实例化、依赖注入;
  2. 打印两个 OrderService 对象地址完全相同,证明单例缓存生效;
  3. 执行 testOrder () 方法: 先打印【AOP 前置通知】,再输出订单业务,调用 userService.sayHello 后打印【AOP 后置通知】;
  4. 自动注入成功:OrderServiceImpl 中无需手动 new UserService,容器自动装配。

六、底层核心原理拆解(面试高频)

1. IoC 控制反转

传统写法:业务代码主动 new 依赖对象(主动创建); IoC 容器:由容器统一创建所有 Bean,业务直接获取(控制权交给容器,反转); 本项目通过包扫描 + 反射动态创建对象,完全模拟 Spring 的 Bean 工厂。

2. @Autowired 注入原理

  1. 反射获取类所有 Field 字段;
  2. 判断字段标注 @Autowired;
  3. 根据字段类型去单例缓存池中匹配对应 Bean;
  4. setAccessible (true) 打破私有权限,反射赋值,实现自动装配。

3. AOP JDK 动态代理限制

JDK 动态代理只能代理实现接口的类,原理:运行时生成目标接口的代理类,拦截所有接口方法; 如果类没有实现接口,需要 CGLIB 字节码代理,本项目为简化使用 JDK 代理。

4. 单例线程安全设计

BeanFactory 使用 ConcurrentHashMap 存储单例,容器创建使用双重校验锁实现单例上下文,避免多线程启动容器创建多个上下文实例。

七、结尾

这份迷你 Spring 容器项目没有任何 Spring 框架依赖,全部基于 Java 基础:注解、反射、动态代理、单例、工厂模式手写实现,完美复刻 Spring 两大核心 IoC 和 AOP。

很多开发者只会调 @Autowired、@Aspect 注解,但完全不知道底层如何反射创建对象、如何拦截方法,跟着本项目逐行调试,就能打通 Spring 底层知识盲区,面试问到 IoC/AOP 手写实现也能流畅作答。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询